diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index 05fb34e7..c72a4f53 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -282,7 +282,7 @@ pub fn compile(semantics: &Semantics) -> Rc { 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(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'