[fine] Compiler flows error descriptions on tree errors

Like, even when the tree is malformed lets try to talk about what we
found. This is still not right, but it's better maybe.
This commit is contained in:
John Doty 2024-03-24 07:45:34 -07:00
parent 9ce5794c30
commit c4b4273115

View file

@ -282,7 +282,7 @@ pub fn compile(semantics: &Semantics) -> Rc<Module> {
compiler.temp_functions.resize(idx + 1, None);
}
compiler.function = func;
compile_function(&mut compiler, fk.tree);
let _ = compile_function(&mut compiler, fk.tree);
compiler.temp_functions[idx] = Some(Rc::new(compiler.function));
}
@ -310,13 +310,13 @@ fn file(c: &mut Compiler, t: TreeRef) {
c.push(Instruction::Return);
}
type CR = Option<()>;
const OK: CR = CR::Some(());
type CR = Result<(), &'static str>;
const OK: CR = CR::Ok(());
fn compile_expression(c: &mut Compiler, t: TreeRef) {
let tree = &c.syntax[t];
let cr = match tree.kind {
TreeKind::Error => None,
TreeKind::Error => Err("error tree"),
TreeKind::Argument => compile_argument(c, tree),
TreeKind::BinaryExpression => compile_binary_expression(c, t, tree),
@ -338,13 +338,13 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) {
_ => ice!(c, t, "{tree:?} is not an expression, cannot compile"),
};
if matches!(cr, None) {
c.push_panic(format!("panic compiling expression {:?}", tree));
if let Err(m) = cr {
c.push_panic(format!("panic compiling expression {:?}: {m}", tree));
}
}
fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
let tok = tr.nth_token(0)?;
let tok = tr.nth_token(0).ok_or("no token")?;
match c.semantics.type_of(t) {
Type::F64 => c.push(Instruction::PushFloat(
tok.as_str(c.source).parse().unwrap(),
@ -366,14 +366,14 @@ fn compile_literal(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
}
fn compile_grouping(c: &mut Compiler, t: &Tree) -> CR {
compile_expression(c, t.nth_tree(1)?);
compile_expression(c, t.nth_tree(1).ok_or("unexpected tree")?);
OK
}
fn compile_unary_operator(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
compile_expression(c, tr.nth_tree(1)?);
compile_expression(c, tr.nth_tree(1).ok_or("no arg")?);
let tok = tr.nth_token(0)?;
let tok = tr.nth_token(0).ok_or("no op")?;
match tok.kind {
TokenKind::Minus => {
c.push(Instruction::PushFloat(-1.0));
@ -388,12 +388,12 @@ fn compile_unary_operator(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
}
fn compile_condition_expression(c: &mut Compiler, t: &Tree) -> CR {
let condition = t.nth_tree(1)?;
let condition = t.nth_tree(1).ok_or("no cond")?;
compile_expression(c, condition);
let jump_else_index = c.push(Instruction::JumpFalse(0));
let then_branch = t.nth_tree(2)?;
let then_branch = t.nth_tree(2).ok_or("no then")?;
compile_expression(c, then_branch);
let jump_end_index = c.push(Instruction::Jump(0));
@ -413,9 +413,9 @@ fn compile_simple_binary_expression<T>(c: &mut Compiler, tr: &Tree, f: T) -> CR
where
T: FnOnce(&mut Compiler, &Type) -> Instruction,
{
compile_expression(c, tr.nth_tree(0)?);
compile_expression(c, tr.nth_tree(0).ok_or("no lhs")?);
let arg_tree = tr.nth_tree(2)?;
let arg_tree = tr.nth_tree(2).ok_or("no rhs")?;
let arg_type = c.semantics.type_of(arg_tree);
compile_expression(c, arg_tree);
@ -427,7 +427,7 @@ where
}
fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
let op = tr.nth_token(1)?;
let op = tr.nth_token(1).ok_or("no op")?;
match op.kind {
TokenKind::Plus => compile_simple_binary_expression(c, tr, |c, t| match t {
Type::F64 => Instruction::FloatAdd,
@ -454,7 +454,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
Type::F64 => Instruction::GreaterFloat,
Type::String => Instruction::GreaterString,
_ => c.inst_panic(format!("panic less equal {}", t)),
});
})?;
c.push(Instruction::BoolNot);
OK
}
@ -468,14 +468,14 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
Type::F64 => Instruction::LessFloat,
Type::String => Instruction::LessString,
_ => c.inst_panic(format!("panic greater equal {}", t)),
});
})?;
c.push(Instruction::BoolNot);
OK
}
TokenKind::And => {
// Compile the left hand side, it leaves a bool on the stack
compile_expression(c, tr.nth_tree(0)?);
compile_expression(c, tr.nth_tree(0).ok_or("no lhs")?);
// If the first part is true (hooray!) then we need to evaluate
// the right hand side, so jump around the short circuit...
@ -493,7 +493,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
// The right hand side leaves true or false on the stack, it's
// the result of the expression.
compile_expression(c, tr.nth_tree(2)?);
compile_expression(c, tr.nth_tree(2).ok_or("no rhs")?);
// (here's where you go after you leave the "false" on the stack.)
c.patch(jump_end_index, |i| Instruction::Jump(i));
@ -501,7 +501,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
}
TokenKind::Or => {
// Compile the left hand side, it leaves a bool on the stack
compile_expression(c, tr.nth_tree(0)?);
compile_expression(c, tr.nth_tree(0).ok_or("no lhs")?);
// If the first part is false (boo!) then we need to evaluate the
// right hand side, so jump around the short circuit...
@ -519,7 +519,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
// The right hand side leaves true or false on the stack, it's
// the result of the expression.
compile_expression(c, tr.nth_tree(2)?);
compile_expression(c, tr.nth_tree(2).ok_or("no rhs")?);
// (here's where you go after you leave "true" on the stack.)
c.patch(jump_end_index, |i| Instruction::Jump(i));
@ -542,10 +542,10 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
})
}
TokenKind::Equal => {
compile_expression(c, tr.nth_tree(2)?);
compile_expression(c, tr.nth_tree(2).ok_or("no value")?);
c.push(Instruction::Dup);
let lvalue = tr.nth_tree(0)?;
let lvalue = tr.nth_tree(0).ok_or("no lvalue")?;
let ltree = &c.syntax[lvalue];
#[allow(unused_assignments)]
@ -554,19 +554,19 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
let declaration = match ltree.kind {
// TODO: Assign to list access
TreeKind::Identifier => {
let id = ltree.nth_token(0)?.as_str(&c.source);
let id = ltree.nth_token(0).ok_or("no id")?.as_str(&c.source);
environment = c.semantics.environment_of(lvalue);
environment.bind(id)?
environment.bind(id).ok_or("cannot bind destination")?
}
TreeKind::MemberAccess => {
let id = ltree.nth_token(2)?.as_str(&c.source);
let id = ltree.nth_token(2).ok_or("no member")?.as_str(&c.source);
let t = ltree.nth_tree(0)?;
let t = ltree.nth_tree(0).ok_or("no lhs exp")?;
let typ = c.semantics.type_of(t);
environment = c.semantics.member_environment(t, &typ);
environment.bind(id)?
environment.bind(id).ok_or("cannot bind field")?
}
_ => return None,
_ => return Err("unsupported lval expression"),
};
let instruction = match declaration {
@ -590,7 +590,7 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
Instruction::StoreModule(index)
}
Location::Slot => {
compile_expression(c, ltree.nth_tree(0)?);
compile_expression(c, ltree.nth_tree(0).ok_or("no obj lhs")?);
Instruction::StoreSlot(index)
}
}
@ -614,10 +614,10 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
}
}
fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> Option<()> {
let ident = tree.nth_token(0)?.as_str(&c.source);
fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
let ident = tree.nth_token(0).ok_or("no ident")?.as_str(&c.source);
let environment = c.semantics.environment_of(t);
let declaration = environment.bind(ident)?;
let declaration = environment.bind(ident).ok_or("not found")?;
compile_load_declaration(c, t, declaration)
}
@ -689,22 +689,24 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
OK
}
fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
compile_expression(c, tree.nth_tree(1)?);
fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> CR {
compile_expression(c, tree.nth_tree(1).ok_or("no val")?);
let mut patches = Vec::new();
let match_body = tree.child_tree_of_kind(c.syntax, TreeKind::MatchBody)?;
let match_body = tree
.child_tree_of_kind(c.syntax, TreeKind::MatchBody)
.ok_or("no body")?;
for arm in match_body.children_of_kind(c.syntax, TreeKind::MatchArm) {
let arm = &c.syntax[arm];
// Evaluate pattern...
compile_pattern(c, arm.nth_tree(0)?)?;
compile_pattern(c, arm.nth_tree(0).ok_or("no arm pat")?)?;
// ...If false jump to next arm.
let jump_next_index = c.push(Instruction::JumpFalse(0));
// ...If true run expression and jump out.
compile_expression(c, arm.nth_tree(2)?);
compile_expression(c, arm.nth_tree(2).ok_or("no arm expr")?);
patches.push(c.push(Instruction::Jump(0)));
c.patch(jump_next_index, |i| Instruction::JumpFalse(i));
@ -719,13 +721,13 @@ fn compile_match_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
OK
}
fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
compile_expression(c, tree.nth_tree(0)?);
fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> CR {
compile_expression(c, tree.nth_tree(0).ok_or("no val")?);
compile_pattern(c, tree.nth_tree(2)?)
compile_pattern(c, tree.nth_tree(2).ok_or("no pat")?)
}
fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
fn compile_pattern(c: &mut Compiler, t: TreeRef) -> CR {
let tree = &c.syntax[t];
// Let's *try* to generate good code in the presence of a wildcard pattern....
@ -744,7 +746,9 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
if let Some(binding) = tree.child_tree_of_kind(&c.syntax, TreeKind::VariableBinding) {
if let Some(variable) = binding.nth_token(0) {
let environment = c.semantics.environment_of(t);
let declaration = environment.bind(variable.as_str(&c.source))?;
let declaration = environment
.bind(variable.as_str(&c.source))
.ok_or("not bound")?;
let Declaration::Variable {
location: Location::Local,
@ -766,8 +770,8 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
}
if !is_wildcard {
let type_expr = type_expr?;
compile_type_expr_eq(c, type_expr.nth_tree(0)?);
let type_expr = type_expr.ok_or("wild but no type")?;
compile_type_expr_eq(c, type_expr.nth_tree(0).ok_or("no type expr")?);
}
if let Some(and_index) = and_index {
@ -789,7 +793,7 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
Some(jump_end_index)
};
compile_expression(c, tree.nth_tree(and_index + 1)?);
compile_expression(c, tree.nth_tree(and_index + 1).ok_or("no condition")?);
// If we wound up with a jump what needs patching, patch it.
if let Some(jump_end_index) = jump_end_index {
@ -812,13 +816,16 @@ fn compile_type_expr_eq(c: &mut Compiler, t: TreeRef) {
_ => ice!(c, t, "tree is not a type expression"),
};
if result.is_none() {
c.push_panic(format!("panic compiling type expression eq {:?}", tree));
if let Err(m) = result {
c.push_panic(format!(
"internal error compiling type expression eq {:?}: {m}",
tree
));
}
}
fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
let identifier = tree.nth_token(0)?.as_str(&c.source);
let identifier = tree.nth_token(0).ok_or("no id")?.as_str(&c.source);
match identifier {
"f64" => {
c.push(Instruction::IsFloat);
@ -834,7 +841,7 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
}
_ => {
let environment = c.semantics.environment_of(t);
match environment.bind(identifier)? {
match environment.bind(identifier).ok_or("cannot bind")? {
Declaration::Class { declaration, .. } => {
// The runtime identifier of the class is the tree index of the
// class declaration sure why not.
@ -842,7 +849,7 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
c.push(Instruction::IsClass(index.try_into().unwrap()));
}
_ => return None,
_ => return Err("unsupported type decl"),
}
}
};
@ -852,7 +859,7 @@ fn compile_type_identifier_eq(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
// Compile the left hand side, it leaves a bool on the stack
compile_type_expr_eq(c, tree.nth_tree(0)?);
compile_type_expr_eq(c, tree.nth_tree(0).ok_or("no lhs")?);
// If the first part is false (boo!) then we need to evaluate the
// right hand side, so jump around the short circuit...
@ -870,7 +877,7 @@ fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
// The right hand side leaves true or false on the stack, it's
// the result of the expression.
compile_type_expr_eq(c, tree.nth_tree(2)?);
compile_type_expr_eq(c, tree.nth_tree(2).ok_or("no rhs")?);
// (here's where you go after you leave "true" on the stack.)
c.patch(jump_end_index, |i| Instruction::Jump(i));
@ -878,7 +885,9 @@ fn compile_type_alternate_eq(c: &mut Compiler, tree: &Tree) -> CR {
}
fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
let arg_list = tree.child_tree_of_kind(&c.syntax, TreeKind::ArgumentList)?;
let arg_list = tree
.child_tree_of_kind(&c.syntax, TreeKind::ArgumentList)
.ok_or("no arglist")?;
let mut args: Vec<_> = arg_list.child_trees().collect();
let arg_count = args.len();
@ -887,7 +896,7 @@ fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR {
compile_expression(c, arg);
}
let func = tree.nth_tree(0)?;
let func = tree.nth_tree(0).ok_or("no func")?;
let func_type = c.semantics.type_of(func);
let arg_count = match func_type {
// TODO: Consider being guided by syntax here?
@ -910,14 +919,14 @@ fn compile_block_expression(c: &mut Compiler, tree: &Tree) -> CR {
let last_index = tree.children.len() - if last_is_brace { 2 } else { 1 };
for i in 1..last_index {
compile_statement(c, tree.nth_tree(i)?, false);
compile_statement(c, tree.nth_tree(i).ok_or("no stat")?, false);
}
compile_statement(c, tree.nth_tree(last_index)?, true);
compile_statement(c, tree.nth_tree(last_index).ok_or("no last")?, true);
OK
}
fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
compile_expression(c, tree.nth_tree(0)?);
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
OK
}
@ -930,11 +939,13 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
let class = c.semantics.class_of(mid, ct);
let field_list = tree.child_tree_of_kind(&c.syntax, TreeKind::FieldList)?;
let field_list = tree
.child_tree_of_kind(&c.syntax, TreeKind::FieldList)
.ok_or("no field list")?;
let mut field_bindings = HashMap::new();
for field in field_list.children_of_kind(&c.syntax, TreeKind::FieldValue) {
let f = &c.syntax[field];
let name = f.nth_token(0)?;
let name = f.nth_token(0).ok_or("no field name")?;
field_bindings.insert(name.as_str(&c.source), field);
}
@ -942,16 +953,23 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
// (stack!) we compile them in reverse order. Missing fields panic,
// obviously.
for field in class.fields.iter().rev() {
let binding = field_bindings.get(&*field.name)?;
let binding = field_bindings
.get(&*field.name)
.ok_or("cannot bind field")?;
compile_expression(c, *binding);
}
// Fetch the correct constructor.
// TODO: Binding this type should be done by semantics, and we should borrow it.
let type_reference = tree.child_tree_of_kind(&c.syntax, TreeKind::TypeIdentifier)?;
let identifier = type_reference.nth_token(0)?.as_str(&c.source);
let type_reference = tree
.child_tree_of_kind(&c.syntax, TreeKind::TypeIdentifier)
.ok_or("no type ref")?;
let identifier = type_reference
.nth_token(0)
.ok_or("no type id")?
.as_str(&c.source);
let environment = c.semantics.environment_of(t);
match environment.bind(identifier)? {
match environment.bind(identifier).ok_or("cannot bind type")? {
Declaration::Class { declaration, .. } => {
let key = FunctionKey { tree: *declaration };
let index = match c.function_bindings.get(&key) {
@ -969,7 +987,7 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
};
c.push(Instruction::LoadFunction(index));
}
_ => return None,
_ => return Err("unsupported type for construction"),
}
c.push(Instruction::Call(class.fields.len()));
OK
@ -978,15 +996,15 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
if let Some(colon) = tree.nth_token(1) {
if colon.kind == TokenKind::Colon {
compile_expression(c, tree.nth_tree(2)?);
compile_expression(c, tree.nth_tree(2).ok_or("no val")?);
return OK;
}
}
// Form 2: { x, ... }
let environment = c.semantics.environment_of(t);
let id = tree.nth_token(0)?.as_str(&c.source);
let declaration = environment.bind(id)?;
let id = tree.nth_token(0).ok_or("no id")?.as_str(&c.source);
let declaration = environment.bind(id).ok_or("cannot bind")?;
compile_load_declaration(c, t, declaration)
}
@ -995,10 +1013,11 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
// In member access; the lhs sets up the object and in theory the rhs
// binds against it. ::shrug::
//
compile_expression(c, tree.nth_tree(0)?);
let lhs = tree.nth_tree(0).ok_or("no lhs")?;
compile_expression(c, lhs);
let typ = c.semantics.type_of(tree.nth_tree(0)?);
let ident = tree.nth_token(2)?.as_str(&c.source);
let typ = c.semantics.type_of(lhs);
let ident = tree.nth_token(2).ok_or("no ident")?.as_str(&c.source);
let environment = match &typ {
Type::Object(mid, ct, _) => {
@ -1011,15 +1030,15 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
}
_ => {
c.push_panic("cannot get environment of {typ}");
return None;
return Err("cannot get environment");
}
};
let declaration = environment.bind(ident)?;
let declaration = environment.bind(ident).ok_or("cannot bind")?;
// NOTE: If this is a method call we still don't have to do anything
// special here, since the load of the member function will *not*
// consume the self pointer from the stack.
compile_load_declaration(c, t, declaration);
compile_load_declaration(c, t, declaration)?;
OK
}
@ -1042,14 +1061,14 @@ fn compile_list_constructor(c: &mut Compiler, tree: &Tree) -> CR {
}
fn compile_list_constructor_element(c: &mut Compiler, tree: &Tree) -> CR {
compile_expression(c, tree.nth_tree(0)?);
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
OK
}
fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
let tree = &c.semantics.tree()[t];
let cr = match tree.kind {
TreeKind::Error => None,
TreeKind::Error => Err("parse error"),
TreeKind::Import => compile_import_statement(c, gen_value),
TreeKind::Block => compile_block_statement(c, t, gen_value),
@ -1064,13 +1083,17 @@ fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
};
if matches!(cr, None) {
c.push_panic(format!("stat {:?}", tree));
if let Err(e) = cr {
c.push_panic(format!(
"internal error compiling statement {:?}: {e}",
tree
));
}
}
fn compile_if_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
compile_expression(c, tree.nth_tree(0)?);
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
if !gen_value {
c.push(Instruction::Discard);
}
@ -1101,9 +1124,11 @@ fn compile_expression_statement(c: &mut Compiler, tree: &Tree, gen_value: bool)
}
fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: bool) -> CR {
compile_expression(c, tree.nth_tree(3)?);
compile_expression(c, tree.nth_tree(3).ok_or("no val")?);
let environment = c.semantics.environment_of(t);
let declaration = environment.bind(tree.nth_token(1)?.as_str(&c.source))?;
let declaration = environment
.bind(tree.nth_token(1).ok_or("no id")?.as_str(&c.source))
.ok_or("cannot bind")?;
let Declaration::Variable {
location, index, ..
@ -1144,9 +1169,11 @@ fn compile_function_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_v
let fk = FunctionKey { tree: t };
if !c.function_bindings.contains_key(&fk) {
// TODO: If this is a method the name should be different.
let name = tree.nth_token(1)?.as_str(&c.source);
let name = tree.nth_token(1).ok_or("no id")?.as_str(&c.source);
let param_list = tree.child_tree_of_kind(&c.syntax, TreeKind::ParamList)?;
let param_list = tree
.child_tree_of_kind(&c.syntax, TreeKind::ParamList)
.ok_or("no paramlist")?;
let param_count = param_list.children.len() - 2;
let function_index = c.temp_functions.len();
@ -1172,7 +1199,7 @@ fn compile_class_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_valu
// Classes get compiled as constructor functions which get called.
let fk = FunctionKey { tree: t };
if !c.function_bindings.contains_key(&fk) {
let name = tree.nth_token(1)?.as_str(&c.source);
let name = tree.nth_token(1).ok_or("no name")?.as_str(&c.source);
let field_count = tree.children.len() - 2;
@ -1198,7 +1225,9 @@ fn compile_function(c: &mut Compiler, t: TreeRef) -> CR {
let tree = &c.syntax[t];
match tree.kind {
TreeKind::FunctionDecl => {
let block = tree.child_of_kind(&c.syntax, TreeKind::Block)?;
let block = tree
.child_of_kind(&c.syntax, TreeKind::Block)
.ok_or("no body")?;
compile_expression(c, block);
}
TreeKind::ClassDecl => {
@ -1209,7 +1238,7 @@ fn compile_function(c: &mut Compiler, t: TreeRef) -> CR {
c.push(Instruction::LoadArgument(count - 1 - i));
}
let name = tree.nth_token(1)?.as_str(&c.source);
let name = tree.nth_token(1).ok_or("no name")?.as_str(&c.source);
let name_index = c.add_string(name.to_string());
c.push(Instruction::PushString(name_index));
c.push(Instruction::PushInt(t.index().try_into().unwrap()));
@ -1233,11 +1262,11 @@ fn compile_block_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) -> CR
fn compile_while_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
let start_index = c.function.instructions.len();
compile_expression(c, tree.nth_tree(1)?);
compile_expression(c, tree.nth_tree(1).ok_or("no cond")?);
let jump_end_index = c.push(Instruction::JumpFalse(0));
compile_block_statement(c, tree.nth_tree(2)?, false);
compile_block_statement(c, tree.nth_tree(2).ok_or("no body")?, false)?;
c.push(Instruction::Jump(start_index));
c.patch(jump_end_index, |i| Instruction::JumpFalse(i));
@ -1260,11 +1289,11 @@ fn compile_return_statement(c: &mut Compiler, tree: &Tree) -> CR {
fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
// Figure out the variable.
let vt = tree.nth_tree(1)?;
let vt = tree.nth_tree(1).ok_or("no var")?;
let var = &c.syntax[vt];
let id = var.nth_token(0)?.as_str(&c.source);
let id = var.nth_token(0).ok_or("no id")?.as_str(&c.source);
let body = tree.nth_tree(4)?;
let body = tree.nth_tree(4).ok_or("no body")?;
let env = c.semantics.environment_of(body);
let Some(variable_decl) = env.bind(id) else {
ice!(c, body, "Unable to bind {id} in loop body");
@ -1287,7 +1316,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
};
// Figure out the generator.
let iterable = tree.nth_tree(3)?;
let iterable = tree.nth_tree(3).ok_or("no generator")?;
compile_expression(c, iterable);
// call 'get_iterator'
@ -1299,7 +1328,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
));
c.push(Instruction::Call(1));
}
_ => return None, // TODO: Bind and call get_iterator() on type of iterable
_ => return Err("unsupported collection"), // TODO: Bind and call get_iterator() on type of iterable
}
// iterate
@ -1312,7 +1341,7 @@ fn compile_for_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
EXTERN_BUILTIN_LIST_ITERATOR_NEXT,
));
}
_ => return None, // TODO: Bind and call next() on type of iterator
_ => return Err("unsupported iterator"), // TODO: Bind and call next() on type of iterator
}
c.push(Instruction::Call(1)); // Call 'next'