Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/handle", "fix/shell" ]
members = [ "common", "vmm", "kernel", "macros" , "user", "arca" , "arcane", "fix", "fix/handle", "fix/shell", "fix/parser" ]
default-members = [ "common", "vmm", "macros", "arca", "fix/handle" ]

resolver = "2"
Expand Down
4 changes: 2 additions & 2 deletions addblob.fix
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
(let ((add @"./target/x86_64-unknown-none/addblob"))
!*(add !*(add 2 3) 1))
(let ((add @"./target/x86_64-unknown-none/debug/addblob"))
*#(add *#(add 2u64 3u64) 1u64))
39 changes: 19 additions & 20 deletions addblob_extended.fix
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
(let ((add @"./target/x86_64-unknown-none/addblob")
(a 1) (b 2) (c 3) (d 4) (e 5) (f 6) (g 7)
(h 8) (i 9) (j 10) (k 11) (l 12) (m 13)
(n 14) (o 15) (p 16))
!*(add
!*(add
!*(add
!*(add a b)
!*(add c d)
(let ((add @"./target/x86_64-unknown-none/debug/addblob")
(a 1u64) (b 2u64) (c 3u64) (d 4u64) (e 5u64) (f 6u64) (g 7u64) (h 8u64)
(i 9u64) (j 10u64) (k 11u64) (l 12u64) (m 13u64) (n 14u64) (o 15u64) (p 16u64))
*#(add
*#(add
*#(add
*#(add a b)
*#(add c d)
)
!*(add
!*(add e f)
!*(add g h)
*#(add
*#(add e f)
*#(add g h)
)
)
!*(add
!*(add
!*(add i j)
!*(add k l)
*#(add
*#(add
*#(add i j)
*#(add k l)
)
!*(add
!*(add m n)
!*(add o p)
*#(add
*#(add m n)
*#(add o p)
)
)
)
)
)
23 changes: 15 additions & 8 deletions demo.fix
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,40 @@
-- The whole file is interpreted as a single expression. Expressions can be comprised of:

-- Integer Literals
42
42u8

-- String Literals
"hello"

-- Trees
(1 2 3)
(1u8 2u8 3u8)

-- References
&"hello"

-- Identification Thunks
^&4
'&4u8

-- Application Thunks
*(1 2)
#(1u8 2u8)

-- Selection Thunks
["hello" 2u8] -- Zero-indexed
["hello" 1u8 3u8] -- Inclusive start and exclusive end

-- Strict Encodes
!^&2
*'&2u8

-- Shallow Encodes
+'&2u8

-- Let bindings that tie expressions to variables
(let ((x 42)) x)
(let ((x 42u8)) x)

-- @ path executables
@"./target/x86_64-unknown-none/addblob"

-- Primitives (To be implemented)
$interpret
-- Primitives
*#($identity 2u8)

-}
2 changes: 1 addition & 1 deletion fix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ crossbeam-queue = {
[build-dependencies]
fixshell = { path = "shell", artifact="staticlib", target = "x86_64-unknown-none" }
fixpostprocessor = { path = "postprocessor" }
fixprocedure = { path = "procedure", artifact = "cdylib", target = "wasm32-unknown-unknown" }
fixparser = { path = "parser", artifact = "cdylib", target = "wasm32-unknown-unknown" }
anyhow = "1.0.98"
bindgen = "0.72.1"
cc = "1.2.30"
Expand Down
4 changes: 4 additions & 0 deletions fix/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ fn main() -> Result<()> {
symlink(dst, link)?;
}
}
let parser = PathBuf::from(env::var_os("CARGO_CDYLIB_FILE_FIXPARSER").unwrap());
let wasm = fixpostprocessor::process(&std::fs::read(&parser)?)?;
let (c, h) = wasm2c(&wasm)?;
std::fs::write(Path::new(&out_dir).join("fixparser"), c2elf(&c, &h)?)?;

let cwd = std::env::var("CARGO_MANIFEST_DIR").unwrap();

Expand Down
2 changes: 1 addition & 1 deletion fix/etc/memmap.ld
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ENTRY(_start)

MEMORY {
cls (rwx) : ORIGIN = 0x0000000000000000, LENGTH = 2M
upper (rw) : ORIGIN = 0xFFFF800100100000, LENGTH = 8M
upper (rw) : ORIGIN = 0xFFFF800100100000, LENGTH = 32M
}

SECTIONS {
Expand Down
12 changes: 12 additions & 0 deletions fix/parser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "fixparser"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
fixutils = { path = "../utils" }
dlmalloc = { version = "0.2.14", features = ["global"] }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
47 changes: 47 additions & 0 deletions fix/parser/src/grammar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
### Text Format

```
A ::= O | K | E Any
| name Identifier
| $name Stdlib primitive
| @"/path/" Executable path

binding ::= name = A Binds identifier to a value

int ::= num_u8 Integer
| num_u16
| num_u32
| num_u64
| num_u128

B ::= int Blob
| string

T ::= (A*) Tree

R ::= &B | &T Ref

O ::= B | T | R Data

K ::= 'O Thunk (Identify)
| #T Thunk (Apply)
| [A*] Thunk (Select)
| [O int] Thunk (Select 1)
| [O int int] Thunk (Select N)

E ::= *K Encode (Strict)
| +K Encode (Shallow)

comment ::= -- Single line
| {- -} Multi-line
```

### Example

```
compiler = @"/path/"

*#(*#(compiler $def_limits
"int f(int x, int y) {return x + y;}")
$def_limits 19u32 4u32)
```
37 changes: 26 additions & 11 deletions fix/src/parser/lexer.rs → fix/parser/src/lexer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use super::token::Token;
use crate::token::Token;
use alloc::{
format,
string::{String, ToString},
vec::Vec,
};
use core::{iter::Peekable, str::Chars};
use kernel::prelude::*;

pub struct Lexer<'a> {
characters: Peekable<Chars<'a>>,
Expand Down Expand Up @@ -36,10 +40,14 @@ impl<'a> Lexer<'a> {
let token = match character {
'(' => Token::LParen,
')' => Token::RParen,
'[' => Token::LBracket,
']' => Token::RBracket,
'&' => Token::Ampersand,
'*' => Token::Asterisk,
'^' => Token::Caret,
'!' => Token::Bang,
'+' => Token::Plus,
'\'' => Token::Apostrophe,
'#' => Token::Pound,
'$' => Token::Primitive(self.take(String::new(), Self::is_identifier)),
'"' => {
let text = self.take(String::new(), |ch| ch != '"');
if self.characters.next() != Some('"') {
Expand All @@ -52,14 +60,21 @@ impl<'a> Lexer<'a> {
let digits = self.take(String::new(), |ch| ch.is_ascii_hexdigit());
Token::Bytes(hex::decode(&digits).map_err(|error| error.to_string())?)
}
// Negative numbers
'-' if self.peek(|character| character.is_ascii_digit()) => {
let number = self.take(String::new(), |ch| ch.is_ascii_digit());
Token::Number(-number.parse::<i64>().map_err(|error| error.to_string())?)
}
character if character.is_ascii_digit() => {
let number = self.take(String::from(character), |ch| ch.is_ascii_digit());
Token::Number(number.parse::<i64>().map_err(|error| error.to_string())?)
let digits = self.take(String::from(character), |ch| {
ch.is_ascii_digit() || ch == '_'
});
let suffix = self.take(String::new(), |ch| ch.is_ascii_alphanumeric());
let bytes = match suffix.as_str() {
"u8" => digits.parse::<u8>().map(|n| n.to_le_bytes().to_vec()),
"u16" => digits.parse::<u16>().map(|n| n.to_le_bytes().to_vec()),
"u32" => digits.parse::<u32>().map(|n| n.to_le_bytes().to_vec()),
"u64" => digits.parse::<u64>().map(|n| n.to_le_bytes().to_vec()),
"u128" => digits.parse::<u128>().map(|n| n.to_le_bytes().to_vec()),
"" => return Err(format!("integer literal {digits} missing suffix")),
other => return Err(format!("unknown integer suffix: {other}")),
};
Token::Bytes(bytes.map_err(|error| error.to_string())?)
}
character if Self::is_identifier(character) => {
Token::Identifier(self.take(String::from(character), Self::is_identifier))
Expand Down
30 changes: 30 additions & 0 deletions fix/parser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#![cfg_attr(target_arch = "wasm32", no_std, feature(asm_experimental_arch))]
extern crate alloc;

use dlmalloc::GlobalDlmalloc;
#[global_allocator]
static ALLOCATOR: GlobalDlmalloc = GlobalDlmalloc;

mod lexer;
mod parser;
mod token;

use fixutils::*;
use lexer::Lexer;
use parser::Parser;

num_memories!(48);
num_tables!(24);

#[fix_entrypoint]
pub fn _fixpoint_apply(combination: RustHandle<'static>) -> Result<RustHandle<'static>, FixError> {
let arguments = combination.to_entries()?;

let source_handle = arguments.get(1).expect("expected source");
let source = source_handle.to_bytes()?;
let source = core::str::from_utf8(&source).expect("source should be valid UTF-8");

let tokens = Lexer::new(source).tokenize().expect("failed to tokenize");
let mut parser = Parser::new(tokens, arguments.get(2).expect("expected environment"))?;
parser.parse_program()
}
Loading
Loading