Skip to content
Merged
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
10 changes: 2 additions & 8 deletions addblob.fix
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
x = 2;
y = 3;
add = create_blob("./target/x86_64-unknown-none/addblob");
add_x_y = create_application_thunk(create_tree(add, x, y));
z = 1;
sum_x_y = create_strict_encode(add_x_y)
add_xy_z = create_application_thunk(create_tree(add, sum_x_y, z));
eval(create_strict_encode(add_xy_z));
(let ((add @"./target/x86_64-unknown-none/addblob"))
!*(add !*(add 2 3) 1))
84 changes: 27 additions & 57 deletions addblob_extended.fix
Original file line number Diff line number Diff line change
@@ -1,57 +1,27 @@
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 = create_blob("./target/x86_64-unknown-none/addblob");

ab = create_application_thunk(create_tree(add, a, b));
cd = create_application_thunk(create_tree(add, c, d));
ef = create_application_thunk(create_tree(add, e, f));
gh = create_application_thunk(create_tree(add, g, h));
ij = create_application_thunk(create_tree(add, i, j));
kl = create_application_thunk(create_tree(add, k, l));
mn = create_application_thunk(create_tree(add, m, n));
op = create_application_thunk(create_tree(add, o, p));

sum_ab = create_strict_encode(ab);
sum_cd = create_strict_encode(cd);
sum_ef = create_strict_encode(ef);
sum_gh = create_strict_encode(gh);
sum_ij = create_strict_encode(ij);
sum_kl = create_strict_encode(kl);
sum_mn = create_strict_encode(mn);
sum_op = create_strict_encode(op);

lefti = create_application_thunk(create_tree(add, sum_ab, sum_cd));
righti = create_application_thunk(create_tree(add, sum_ef, sum_gh));
leftr= create_application_thunk(create_tree(add, sum_ij, sum_kl));
rightr = create_application_thunk(create_tree(add, sum_mn, sum_op));

sum_lefti = create_strict_encode(lefti);
sum_righti = create_strict_encode(righti);
sum_leftr = create_strict_encode(leftr);
sum_rightr = create_strict_encode(rightr);

left = create_application_thunk(create_tree(add, sum_lefti, sum_leftr));
right = create_application_thunk(create_tree(add, sum_righti, sum_rightr));

sum_left = create_strict_encode(left);
sum_right = create_strict_encode(right);

final = create_application_thunk(create_tree(add, sum_left, sum_right));

eval(create_strict_encode(final));

(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)
)
!*(add
!*(add e f)
!*(add g h)
)
)
!*(add
!*(add
!*(add i j)
!*(add k l)
)
!*(add
!*(add m n)
!*(add o p)
)
)
)
)
4 changes: 0 additions & 4 deletions blobref.fix

This file was deleted.

34 changes: 34 additions & 0 deletions demo.fix
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{-
-- The whole file is interpreted as a single expression. Expressions can be comprised of:

-- Integer Literals
42

-- String Literals
"hello"

-- Trees
(1 2 3)

-- References
&"hello"

-- Identification Thunks
^&4

-- Application Thunks
*(1 2)

-- Strict Encodes
!^&2

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

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

-- Primitives (To be implemented)
$interpret

-}
2 changes: 1 addition & 1 deletion fix/src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl<R: Runtime> Evaluator<R> {
println!("evaluating {handle}");
match handle {
Handle::Ref(reference) => self.eval(self.lift(Handle::Ref(reference))),
Handle::Thunk(_) => todo!(),
Handle::Thunk(_) => handle,
Handle::Object(obj) => match obj {
Object::Blob(blob) => blob.into(),
Object::Tree(tree) => self.eval_tree(tree).into(),
Expand Down
17 changes: 17 additions & 0 deletions fix/src/interpreter/fixshell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use kernel::prelude::Box;

pub trait FixShell: Sized {
type Handle;

fn create_blob(&self, data: &[u8]) -> Self::Handle;
fn create_tree(&self, data: &[Self::Handle]) -> Self::Handle;
fn create_ref(handle: Self::Handle) -> Self::Handle;

fn get_blob_data(&self, handle: Self::Handle) -> Box<[u8]>;
fn get_tree_data(&self, handle: Self::Handle) -> Box<[Self::Handle]>;

fn create_application_thunk(handle: Self::Handle) -> Self::Handle;
fn create_identification_thunk(handle: Self::Handle) -> Self::Handle;

fn create_strict_encode(handle: Self::Handle) -> Self::Handle;
}
27 changes: 27 additions & 0 deletions fix/src/interpreter/grammar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
```
A ::= O | K | E | L Any
| $atom Special/Primitive
| @path Executable path

B ::= int literal Blob
| string literal Blob

T ::= (A*) Tree

R ::= &B | &T Ref

O ::= B | T | R Data

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if this grammar were actually used directly by the code, rather than being a documentation file that will inevitably get out of date. Some Rust parsing crates support this, I'm not sure of any of them work in no_std but it's possible. I know chumsky supports no_std but it uses parser combinators instead of an external BNF grammar.

Also I'm not sure handles should be a thing at this level? This seems more like you're using it to mean "any value", which is semantically different than a "handle"; Handles are a concrete 32-byte in-memory "pointer" in the implementation, while values are abstract objects in Fix. (although the meaning of "value" vs. "object" vs. "expression" vs. whatever else has changed a lot over time...)

K ::= ^O Thunk (Identify)
| *T Thunk (Apply)
| #T Thunk (Digest)
| ~T Thunk (Select)
| O[B] Thunk (Select 1)
| O[B:B] Thunk (Select N)

E ::= !K Encode (Strict)
| ?K Encode (Shallow)

L ::= (let ((name A)*) A) Let
```

109 changes: 109 additions & 0 deletions fix/src/interpreter/interpreter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
extern crate alloc;
use alloc::collections::BTreeMap;

use crate::{FixShell, Storage, parser::Expr};
use fixhandle::*;
use kernel::prelude::*;

pub struct Interpreter<'a> {
storage: &'a dyn Storage,
context: BTreeMap<String, Handle>,
}

impl<'a> Interpreter<'a> {
pub fn new(storage: &'a dyn Storage) -> Self {
Self {
storage,
context: BTreeMap::new(),
}
}

pub fn interpret(&mut self, expression: &Expr) -> Handle {
match expression {
Expr::String(str) => self.create_blob(str.as_bytes()),
Expr::Number(num) => self.create_blob(&i64::to_le_bytes(*num)),
Expr::Bytes(bytes) => self.create_blob(bytes),
Expr::Identifier(name) => *self.context.get(name).expect("undefined identifier"),
Expr::Ref(object) => Self::create_ref(self.interpret(object)),
Expr::Tree(handles) => {
let handles: Vec<Handle> = handles.iter().map(|x| self.interpret(x)).collect();
self.create_tree(&handles)
}
Expr::Application(tree) => Self::create_application_thunk(self.interpret(tree)),
Expr::Identification(tree) => Self::create_identification_thunk(self.interpret(tree)),
Expr::StrictEncode(thunk) => Self::create_strict_encode(self.interpret(thunk)),
Expr::Let { bindings, body } => {
let outer_context = self.context.clone();
for (name, expr) in bindings {
let handle = self.interpret(expr);
self.context.insert(name.clone(), handle);
}
let handle = self.interpret(body);
self.context = outer_context;
handle
}
}
}
}

impl FixShell for Interpreter<'_> {
type Handle = Handle;

fn create_blob(&self, data: &[u8]) -> Self::Handle {
self.storage.add_blob(data).into()
}

fn create_tree(&self, data: &[Self::Handle]) -> Self::Handle {
self.storage.add_tree(data).into()
}

fn create_ref(handle: Self::Handle) -> Self::Handle {
match handle {
Handle::Object(Object::Blob(blob)) => Handle::Ref(Ref::Blob(blob)),
Handle::Object(Object::Tree(tree)) => Handle::Ref(Ref::Tree(tree)),
_ => panic!("expected blob or tree handle"),
}
}

fn get_blob_data(&self, handle: Self::Handle) -> Box<[u8]> {
let Handle::Object(Object::Blob(blob)) = handle else {
panic!("expected blob handle")
};
self.storage
.get_blob(blob)
.expect("blob data exists for handle")
}

fn get_tree_data(&self, handle: Self::Handle) -> Box<[Self::Handle]> {
let Handle::Object(Object::Tree(tree)) = handle else {
panic!("expected tree handle")
};
self.storage
.get_tree(tree)
.expect("tree data exists for handle")
}

fn create_application_thunk(handle: Self::Handle) -> Self::Handle {
let Handle::Object(Object::Tree(tree)) = handle else {
panic!("expected tree handle for applicaiton")
};
Thunk::Application(tree).into()
}

fn create_identification_thunk(handle: Self::Handle) -> Self::Handle {
Thunk::Identification(match handle {
Handle::Object(Object::Blob(blob)) => Ref::Blob(blob),
Handle::Object(Object::Tree(tree)) => Ref::Tree(tree),
Handle::Ref(reference) => reference,
_ => panic!("expected blob or tree handle"),
})
.into()
}

fn create_strict_encode(handle: Self::Handle) -> Self::Handle {
let Handle::Thunk(thunk) = handle else {
panic!("expected thunk for strict encode")
};
Encode::Strict(thunk).into()
}
}
5 changes: 5 additions & 0 deletions fix/src/interpreter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod fixshell;
mod interpreter;

pub use fixshell::*;
pub use interpreter::*;
2 changes: 2 additions & 0 deletions fix/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![no_std]

pub mod evaluator;
pub mod interpreter;
pub mod parser;
pub mod runtime;
pub mod storage;
Expand All @@ -11,5 +12,6 @@ pub mod handle {

pub use evaluator::*;
pub use handle::*;
pub use interpreter::*;
pub use runtime::*;
pub use storage::*;
Loading
Loading