Skip to content

Commit

Permalink
fire: Fix call logic and transfer of return value
Browse files Browse the repository at this point in the history
  • Loading branch information
CohenArthur committed Oct 15, 2023
1 parent f64d70f commit c43c79a
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 42 deletions.
89 changes: 52 additions & 37 deletions fire/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ impl Fire {
// these two functions should probalby be part of a gc struct, which should be contained within the Fire
fn allocate(&mut self, key: OriginIdx, value: Instance) {
// if we allocate the same value twice, this is an interpreter error
assert!(self.values.insert(key, value).is_none());
// FIXME: this is not specifically true - e.g. calling a function twice will allocate twice to the function's bindings, which is fine?
self.values.insert(key, value);
}

fn copy(&mut self, to_copy: &RefIdx, key: OriginIdx) {
if let Some(instance) = self.values.get(&to_copy.unwrap()) {
if let Some(instance) = self.values.get(&to_copy.expect_resolved()) {
self.allocate(key, instance.clone())
}
}
Expand All @@ -59,7 +60,7 @@ impl Fire {
_fir: &Fir<FlattenData<'_>>,
node: &Node<FlattenData<'_>>, // allocate a value for this node's origin
args: &[RefIdx],
) {
) -> Option<Instance> {
let ast = node.data.ast.node();
let name = match &ast.node {
ast::Node::Function {
Expand All @@ -74,17 +75,15 @@ impl Fire {

if name.access() == "println" {
args.iter().for_each(|arg| {
let value = self.values.get(&arg.unwrap()).unwrap();
let value = self.values.get(&arg.expect_resolved()).unwrap();
// FIXME: Ugly as SIN
println!("{}", unsafe {
String::from_utf8_unchecked(value.data().into())
});
})
}

// this should allocate data

// None
None
}

fn fire_block(
Expand All @@ -95,12 +94,12 @@ impl Fire {
) {
// How do we deal with returns in this system?
stmts.iter().for_each(|node| {
let node = &fir.nodes[&node.unwrap()];
let node = &fir.nodes[&node.expect_resolved()];
self.fire_node(fir, node);
});

if let Some(last_stmt) = stmts.last() {
if let Kind::Return(_) = &fir.nodes[&last_stmt.unwrap()].kind {
if let Kind::Return(_) = &fir.nodes[&last_stmt.expect_resolved()].kind {
self.transfer(last_stmt, node.origin)
}
}
Expand All @@ -122,25 +121,33 @@ impl Fire {
fn fire_call(
&mut self,
fir: &Fir<FlattenData<'_>>,
_node: &Node<FlattenData<'_>>,
node: &Node<FlattenData<'_>>,
to: &RefIdx,
args: &[RefIdx],
) {
let def = &fir.nodes[&to.unwrap()];
let def = &fir.nodes[&to.expect_resolved()];
let (block, def_args) = match &def.kind {
Kind::Function { block, args, .. } => (block, args),
_ => unreachable!(),
};

args.iter().enumerate().for_each(|(i, arg)| {
self.fire_node(fir, &fir.nodes[&arg.unwrap()]);
self.transfer(arg, def_args[i].unwrap());
self.fire_node(fir, &fir.nodes[&arg.expect_resolved()]);
self.transfer(arg, def_args[i].expect_resolved());
});

// FIXME: We need to add bindings here between the function's variables and the arguments given to the call
match block {
None => self.perform_extern_call(fir, def, args),
Some(block) => self.fire_node_ref(fir, block), // what to do here?
None => {
let result = self.perform_extern_call(fir, def, args);
if let Some(instance) = result {
self.allocate(node.origin, instance)
}
}
Some(block) => {
self.fire_node_ref(fir, block); // what to do here?
self.transfer(block, node.origin);
}
}
}

Expand All @@ -159,30 +166,38 @@ impl Fire {
&mut self,
fir: &Fir<FlattenData<'_>>,
node: &Node<FlattenData<'_>>,
_value: &RefIdx,
value: &RefIdx,
ty: &RefIdx,
) {
let tyref = &fir.nodes[&ty.unwrap()];
let fields = match &tyref.kind {
Kind::Type { fields, .. } => fields,
// FIXME: here we need to decide part of our copy/move semantics
Kind::TypeReference(_) => return,
other => {
dbg!(other);
unreachable!()
// what do we do here when we have a `value` but no `ty`?
match ty {
// this is a transfer
RefIdx::Unresolved => self.transfer(value, node.origin),
// this is an allocate?
RefIdx::Resolved(ty) => {
let tyref = &fir.nodes[ty];
let fields = match &tyref.kind {
Kind::Type { fields, .. } => fields,
// FIXME: here we need to decide part of our copy/move semantics
Kind::TypeReference(_) => return,
other => {
dbg!(other);
unreachable!()
}
};

// TODO: can we just check if value == ty?
let instance = if fields.is_empty() {
Instance::empty()
} else {
unreachable!()
};

// FIXME: Handle result here
// FIXME: Should this be a transfer?
self.allocate(node.origin, instance);
}
};

// TODO: can we just check if value == ty?
let instance = if fields.is_empty() {
Instance::empty()
} else {
unreachable!()
};

// FIXME: Handle result here
// FIXME: Should this be a transfer?
self.allocate(node.origin, instance);
}
}

fn fire_return(
Expand All @@ -199,7 +214,7 @@ impl Fire {
}

fn fire_node_ref(&mut self, fir: &Fir<FlattenData<'_>>, node_ref: &RefIdx) {
let node = &fir.nodes[&node_ref.unwrap()];
let node = &fir.nodes[&node_ref.expect_resolved()];

self.fire_node(fir, node)
}
Expand Down
4 changes: 3 additions & 1 deletion interpreter/jinko.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ fn experimental_pipeline(input: &str, file: &Path) -> InteractResult {
.display(&fir);

let fir = x_try!(fir.type_check());
let _result = fir.interpret();
let result = fir.interpret();

dbg!(result);

todo!("unfinished experimental pipeline: use result as exit code and display it")
}
Expand Down
7 changes: 7 additions & 0 deletions typecheck/src/actual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ fn innermost_type(fir: &Fir<FlattenData>, linked_node: RefIdx) -> Option<Type> {
// these are the *only* terminal branches
Kind::Type { .. } => Some(Type::One(RefIdx::Resolved(linked_node.origin))),
Kind::Assignment { .. } => None,
// if a typed value has no specific type, but points to a value, use this as the source of the type
Kind::TypedValue {
ty: RefIdx::Unresolved,
value,
// can we set `ty` here or not? probably not
// we need to :(
} => innermost_type(fir, *value),
Kind::Constant(ty)
| Kind::TypeReference(ty)
| Kind::TypedValue { ty, .. }
Expand Down
30 changes: 26 additions & 4 deletions typecheck/src/typer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ use crate::{Type, TypeCtx};
pub(crate) struct Typer<'ctx>(pub(crate) &'ctx mut TypeCtx);

impl<'ctx> Typer<'ctx> {
fn assign_type(&mut self, node: OriginIdx, ty: Option<Type>) {
// Having non-unique ids in the Fir is an interpreter error
// Or should we return an error here?
assert!(self.0.types.insert(node, ty).is_none());
}

/// Assign a type to a node. This type can either be void ([`None`]) in the case of a declaration or void
/// statement, or may be a "type linked list": a reference to a type defined elsewhere in the [`Fir`].
/// Let's consider a block of multiple statements, the last of which being a function call. The type of a
Expand All @@ -25,9 +31,7 @@ impl<'ctx> Typer<'ctx> {
) -> Result<Node<FlattenData<'ast>>, Error> {
let ty = ty.map(Type::One);

// Having non-unique ids in the Fir is an interpreter error
// Or should we return an error here?
assert!(self.0.types.insert(node.origin, ty).is_none());
self.assign_type(node.origin, ty);

Ok(node)
}
Expand Down Expand Up @@ -80,10 +84,28 @@ impl<'ast> Mapper<FlattenData<'ast>, FlattenData<'ast>, Error> for Typer<'_> {
| fir::Kind::Function { .. }
| fir::Kind::Binding { .. }
| fir::Kind::Assignment { .. } => self.ty(node, None),
// // FIXME: This might be the wrong way to go about this
// // special case where we want to change the `ty` of a `TypedValue`
// fir::Kind::TypedValue {
// ty: RefIdx::Unresolved,
// value,
// } => {
// self.assign_type(node.origin, Some(Type::One(value)));

// Ok(Node {
// // this seems dodgy at best
// kind: fir::Kind::TypedValue { value, ty: value },
// ..node
// })
// }
// These nodes all refer to other nodes, type references or typed values. They will need
// to be flattened later on.
fir::Kind::TypeReference(ty)
| fir::Kind::TypedValue { value: ty, .. }
| fir::Kind::TypedValue {
ty: RefIdx::Unresolved,
value: ty,
}
| fir::Kind::TypedValue { ty, .. }
| fir::Kind::Instantiation { to: ty, .. }
| fir::Kind::Call { to: ty, .. }
| fir::Kind::Conditional { true_block: ty, .. } => self.ty(node, Some(ty)),
Expand Down

0 comments on commit c43c79a

Please sign in to comment.