diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index 32d7f0aa..731d8aee 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -291,7 +291,6 @@ fn compile_expression(c: &mut Compiler, t: TreeRef) { TreeKind::NewObjectExpression => compile_new_object_expression(c, t, tree), TreeKind::FieldValue => compile_field_value(c, t, tree), TreeKind::MemberAccess => compile_member_access(c, tree), - TreeKind::SelfReference => compile_self_reference(c), _ => ice!(c, t, "{tree:?} is not an expression, cannot compile"), }; if matches!(cr, None) { @@ -554,19 +553,11 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat let tree = &c.syntax[*declaration]; compiler_assert_eq!(c, t, tree.kind, TreeKind::FunctionDecl); - compile_function_declaration(c, *declaration, tree, false)?; + compile_function_declaration(c, t, tree, false)?; - match c.function_bindings.get(&key) { - Some(index) => *index, - None => { - ice!( - c, - t, - "did not compile the function with key {:?}!", - declaration - ) - } - } + *c.function_bindings + .get(&key) + .expect("did not compile the function!") } }; Instruction::LoadFunction(index) @@ -593,12 +584,6 @@ fn compile_call_expression(c: &mut Compiler, tree: &Tree) -> CR { } let func = tree.nth_tree(0)?; - let func_type = c.semantics.type_of(func); - let arg_count = match func_type { - // TODO: Consider being guided by syntax here? - Type::Method(..) => arg_count + 1, - _ => arg_count, - }; compile_expression(c, func); c.push(Instruction::Call(arg_count)); @@ -697,21 +682,11 @@ fn compile_field_value(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR { fn compile_member_access(c: &mut Compiler, 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)?); - - // 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_expression(c, tree.nth_tree(2)?); OK } -fn compile_self_reference(c: &mut Compiler) -> CR { - c.push(Instruction::LoadArgument(0)); - OK -} - fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) { let tree = &c.semantics.tree()[t]; let cr = match tree.kind { @@ -802,7 +777,6 @@ fn compile_function_declaration(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_v // if we have no unbound type variables. 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)?; let param_list = tree.child_tree_of_kind(c.syntax, TreeKind::ParamList)?; diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 87c23214..dd9837c3 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -62,19 +62,10 @@ pub struct FieldDecl { pub field_type: Type, } -pub struct MethodDecl { - pub name: Rc, - pub decl_type: Type, - pub declaration: TreeRef, -} - pub struct ClassDecl { pub name: Rc, pub fields: Vec, - pub methods: Vec, pub decl_tree: TreeRef, - - pub env: EnvironmentRef, } #[derive(Clone)] @@ -124,12 +115,6 @@ pub enum Type { Bool, Function(Vec>, Box), - - // A method is like a function except that it takes a self parameter. - // This is how we signal the difference. We do *not* count them as the - // same. - Method(Box, Vec>, Box), - List(Box), // Classes need to be fetched explicitly from the semantics; they are @@ -176,30 +161,15 @@ impl fmt::Display for Type { write!(f, ") -> {ret}") } - Method(self_type, args, ret) => { - write!(f, "method of {self_type} (")?; - let mut first = true; - for arg in args.iter() { - if !first { - write!(f, ", ")?; - } - write!(f, "{arg}")?; - first = false; - } - write!(f, ") -> {ret}") - } - - TypeVariable(_) => { - // TODO: Better names for type variable - write!(f, "$_") - } + // TODO: Better names + TypeVariable(_) => write!(f, "$_"), List(t) => write!(f, "list<{t}>"), Class(_, name) => write!(f, "class {}", name), } } } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug)] pub enum Location { Argument, Local, @@ -243,7 +213,6 @@ pub struct Environment { pub location: Location, pub next_index: usize, pub declarations: HashMap, Declaration>, - pub is_error: bool, } impl Environment { @@ -269,21 +238,9 @@ impl Environment { location, next_index, declarations: HashMap::new(), - is_error: false, } } - pub fn error() -> EnvironmentRef { - // TODO: Exactly once? - EnvironmentRef::new(Environment { - parent: None, - location: Location::Local, - next_index: 0, - declarations: HashMap::new(), - is_error: true, - }) - } - pub fn insert(&mut self, token: &Token, t: Type) -> Option { self.insert_name(token.as_str().into(), t) } @@ -600,7 +557,7 @@ impl<'a> Semantics<'a> { TreeKind::ForStatement => self.environment_of_for(parent, tree), - TreeKind::MemberAccess => self.environment_of_member_access(tree), + TreeKind::MemberAccess => self.environment_of_member_access(parent, tree), _ => parent, }; @@ -708,22 +665,16 @@ impl<'a> Semantics<'a> { None => Type::Error, }; - let declaration_type = match declaration_type { - Type::Method(..) => { - let start = name.start; - let end = name.start + name.as_str().len(); - self.report_error_span(start, end, "methods cannot be assigned to variables"); - Type::Error - } - _ => declaration_type, - }; - - eprintln!("{} => {}", name, declaration_type); - let location = match parent.location { Location::Local => Location::Local, Location::Module => Location::Module, Location::Argument => Location::Local, + + // TODO: Wait can I... do wild stuff? e.g.: + // + // foo.{let y = 23; bar} + // + // ??? Location::Slot => Location::Local, }; @@ -737,41 +688,25 @@ impl<'a> Semantics<'a> { assert!(tree.kind == TreeKind::ParamList); let mut environment = Environment::new(Some(parent), Location::Argument); - for (i, child) in tree.children.iter().enumerate() { + for child in tree.children.iter() { let Child::Tree(ct) = child else { continue; }; let param = &self.syntax_tree[*ct]; - match param.kind { - TreeKind::SelfParameter => { - let param_name = param.nth_token(0).unwrap(); - let declaration_type = self.type_of(*ct); - if environment.insert(param_name, declaration_type).is_some() { - self.report_error_tree( - param, - format!("duplicate definition of self parameter"), - ); - } else if i != 1 { - self.report_error_tree( - param, - "self parameter must be the first parameter in the list", - ); - } - } - TreeKind::Parameter => { - let Some(param_name) = param.nth_token(0) else { - continue; - }; + if param.kind != TreeKind::Parameter { + continue; + } - let declaration_type = self.type_of(*ct); - if environment.insert(param_name, declaration_type).is_some() { - self.report_error_tree( - param, - format!("duplicate definition of parameter '{param_name}'"), - ); - } - } - _ => (), + let Some(param_name) = param.nth_token(0) else { + continue; + }; + + let declaration_type = self.type_of(*ct); + if environment.insert(param_name, declaration_type).is_some() { + self.report_error_tree( + param, + format!("duplicate definition of parameter '{param_name}'"), + ); } } @@ -801,27 +736,41 @@ impl<'a> Semantics<'a> { EnvironmentRef::new(environment) } - fn environment_of_member_access(&self, tree: &Tree) -> EnvironmentRef { + fn environment_of_member_access(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { + // TODO: Build an "error environment" and then anything that tried to + // bind in it would know to give up and not report a new error. + assert_eq!(tree.kind, TreeKind::MemberAccess); // Build environment out of members of type of lhs let Some(lhs) = tree.nth_tree(0) else { - return Environment::error(); + return parent; }; let Some(op) = tree.nth_token(1) else { - return Environment::error(); + return parent; }; let typ = self.type_of(lhs); match &typ { Type::Class(ct, _) => { + // NOTE: The parent here is None! environment search after a dot + // is constrained to the scope of the type, obviously! let class = self.class_of(*ct); - class.env.clone() + let mut env = Environment::new(None, Location::Slot); + + // TODO: Cache environment of type. + // NOTE: It is important that this go in order! The location + // index is the slot index! + for field in class.fields.iter() { + env.insert_name((&*field.name).into(), field.field_type.clone()); + } + + EnvironmentRef::new(env) } - Type::Error => Environment::error(), + Type::Error => parent, // TODO: WRONG _ => { // TODO: This is probably wrong, yeah? self.report_error(op.start, format!("cannot access members of '{typ}'")); - Environment::error() + parent } } } @@ -847,8 +796,6 @@ impl<'a> Semantics<'a> { assert_eq!(tree.kind, TreeKind::ClassDecl); let name = tree.nth_token(1).map(|t| t.as_str()).unwrap_or(""); - - // Fields let mut fields = Vec::new(); for field in tree.children_of_kind(self.syntax_tree, TreeKind::FieldDecl) { let f = &self.syntax_tree[field]; @@ -864,53 +811,10 @@ impl<'a> Semantics<'a> { } } - // Methods - let mut methods = Vec::new(); - for method in tree.children_of_kind(self.syntax_tree, TreeKind::FunctionDecl) { - let m = &self.syntax_tree[method]; - if let Some(method_name) = m.nth_token(1) { - methods.push(MethodDecl { - name: method_name.as_str().into(), - decl_type: self.type_of(method), - declaration: method, - }); - } - } - - // Build into an environment - let mut env = Environment::new(None, Location::Slot); - for (index, field) in fields.iter().enumerate() { - env.declarations.insert( - (&*field.name).into(), - Declaration::Variable { - index, - declaration_type: field.field_type.clone(), - location: Location::Slot, - }, - ); - } - for method in methods.iter() { - let existing = env.declarations.insert( - (&*method.name).into(), - Declaration::Function { - declaration_type: method.decl_type.clone(), - declaration: method.declaration, - }, - ); - if existing.is_some() { - self.report_error_tree_ref( - method.declaration, - format!("duplicate definition of method '{}'", method.name), - ); - } - } - let result = ClassRef::new(ClassDecl { name: name.into(), fields: fields.into(), - methods: methods.into(), decl_tree: t, - env: EnvironmentRef::new(env), }); self.classes.borrow_mut()[t.index()] = Incremental::Complete(result.clone()); @@ -977,34 +881,35 @@ impl<'a> Semantics<'a> { let result = match tree.kind { TreeKind::Error => Some(Type::Error), - - TreeKind::Argument => self.type_of_argument(tree), + TreeKind::UnaryExpression => self.type_of_unary(tree), TreeKind::BinaryExpression => self.type_of_binary(tree), - TreeKind::Block => self.type_of_block(tree), - TreeKind::CallExpression => self.type_of_call(tree), - TreeKind::ClassDecl => self.type_of_class_decl(t, tree), - TreeKind::ConditionalExpression => self.type_of_conditional(tree), - TreeKind::ExpressionStatement => self.type_of_expression_statement(tree), - TreeKind::FieldValue => self.type_of_field_value(t, tree), - TreeKind::ForStatement => Some(Type::Nothing), - TreeKind::FunctionDecl => self.type_of_function_decl(tree), - TreeKind::GroupingExpression => self.type_of_grouping(tree), - TreeKind::Identifier => self.type_of_identifier(t, tree), - TreeKind::IfStatement => self.type_of_if_statement(tree), - TreeKind::LetStatement => Some(Type::Nothing), - TreeKind::ListConstructor => self.type_of_list_constructor(t, tree), - TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree), - TreeKind::LiteralExpression => self.type_of_literal(tree), - TreeKind::MemberAccess => self.type_of_member_access(tree), - TreeKind::NewObjectExpression => self.type_of_new_object_expression(tree), - TreeKind::Parameter => self.type_of_parameter(tree), - TreeKind::ReturnStatement => Some(Type::Unreachable), - TreeKind::ReturnType => self.type_of_return_type(tree), - TreeKind::SelfParameter => self.type_of_self_parameter(tree), - TreeKind::SelfReference => self.type_of_self_reference(t, tree), TreeKind::TypeExpression => self.type_of_type_expr(t, tree), TreeKind::TypeParameter => self.type_of_type_parameter(tree), - TreeKind::UnaryExpression => self.type_of_unary(tree), + TreeKind::Block => self.type_of_block(tree), + TreeKind::LiteralExpression => self.type_of_literal(tree), + TreeKind::GroupingExpression => self.type_of_grouping(tree), + TreeKind::ConditionalExpression => self.type_of_conditional(tree), + TreeKind::CallExpression => self.type_of_call(tree), + TreeKind::Argument => self.type_of_argument(tree), + TreeKind::MemberAccess => self.type_of_member_access(tree), + + TreeKind::LetStatement => Some(Type::Nothing), + TreeKind::ReturnStatement => Some(Type::Unreachable), + TreeKind::ForStatement => Some(Type::Nothing), + TreeKind::ExpressionStatement => self.type_of_expression_statement(tree), + TreeKind::IfStatement => self.type_of_if_statement(tree), + TreeKind::Identifier => self.type_of_identifier(t, tree), + + TreeKind::FunctionDecl => self.type_of_function_decl(tree), + TreeKind::ReturnType => self.type_of_return_type(tree), + TreeKind::Parameter => self.type_of_parameter(tree), + + TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree), + TreeKind::ListConstructor => self.type_of_list_constructor(t, tree), + + TreeKind::NewObjectExpression => self.type_of_new_object_expression(tree), + TreeKind::FieldValue => self.type_of_field_value(t, tree), + TreeKind::ClassDecl => self.type_of_class_decl(t, tree), _ => self.internal_compiler_error(Some(t), "asking for a nonsense type"), }; @@ -1217,9 +1122,7 @@ impl<'a> Semantics<'a> { Some(Type::Error) } None => { - if !environment.is_error { - self.report_error_tree(tree, format!("Unrecognized type: '{token}'")); - } + self.report_error_tree(tree, format!("Unrecognized type: '{token}'")); Some(Type::Error) } } @@ -1394,37 +1297,6 @@ impl<'a> Semantics<'a> { Some(*ret.clone()) } - - Type::Method(_, params, ret) => { - let mut any_errors = false; - - // For the purposes of type checking ignore the self type. - if params.len() != arg_types.len() { - // TODO: Augment with function name if known - self.report_error_tree(tree, format!("expected {} parameters", params.len())); - any_errors = true; - } - - for (i, ((t, a), p)) in arg_types.iter().zip(params.iter()).enumerate() { - if !self.type_compat(&a, p) { - self.report_error_tree_ref( - *t, - format!( - "parameter {i} has an incompatible type: expected {} but got {}", - p, a - ), - ); - any_errors = true; - } - } - - if any_errors { - return Some(Type::Error); - } - - Some(*ret.clone()) - } - _ => { self.report_error_tree_ref(f_ref, format!("expected a function type, got: {f}")); Some(Type::Error) @@ -1492,71 +1364,15 @@ impl<'a> Semantics<'a> { }); } - if !environment.is_error { - self.report_error_tree(tree, format!("cannot find value {id} here")); - } - Some(Type::Error) - } - - fn type_of_self_parameter(&self, tree: &Tree) -> Option { - let pl = tree.parent?; - let param_list = &self.syntax_tree[pl]; - - let fd = param_list.parent?; - let function_decl = &self.syntax_tree[fd]; - - let cd = function_decl.parent?; - let class_decl = &self.syntax_tree[cd]; - - if class_decl.kind != TreeKind::ClassDecl { - self.report_error_tree(tree, "self parameter only allowed in methods"); - Some(Type::Error) - } else { - Some(self.type_of(cd)) - } - } - - fn type_of_self_reference(&self, t: TreeRef, tree: &Tree) -> Option { - assert_eq!(tree.kind, TreeKind::SelfReference); - - let id = tree.nth_token(0)?; - let environment = self.environment_of(t); - if let Some(declaration) = environment.bind(id) { - return Some(match declaration { - Declaration::Variable { - declaration_type, .. - } => declaration_type.clone(), - _ => self.internal_compiler_error( - Some(t), - "how did I bind something other than a variable to self?", - ), - }); - } - - if !environment.is_error { - self.report_error_tree(tree, "`self` is only valid in methods"); - } + self.report_error_tree(tree, format!("cannot find value {id} here")); Some(Type::Error) } fn type_of_function_decl(&self, tree: &Tree) -> Option { let param_list = tree.child_tree_of_kind(self.syntax_tree, TreeKind::ParamList)?; - - // NOTE: The methodness here is determined by the presence of a self - // parameter, even if that parameter is incorrect (e.g., this - // declaration is not nested in a class, or it is not the first - // parameter.) We could have also chosen to signal it by our - // nesting but we want to extract the self parameter to a - // distinguished place in the function type. - let mut self_type = None; let mut parameter_types = Vec::new(); for p in param_list.child_trees() { - let p_type = Box::new(self.type_of(p)); - if self.syntax_tree[p].kind == TreeKind::SelfParameter { - self_type = Some(p_type); - } else { - parameter_types.push(p_type); - } + parameter_types.push(Box::new(self.type_of(p))); } let return_type = match tree.child_of_kind(self.syntax_tree, TreeKind::ReturnType) { @@ -1564,11 +1380,7 @@ impl<'a> Semantics<'a> { None => Type::Nothing, }; let return_type = Box::new(return_type); - - Some(match self_type { - Some(self_type) => Type::Method(self_type, parameter_types, return_type), - None => Type::Function(parameter_types, return_type), - }) + Some(Type::Function(parameter_types, return_type)) } fn type_of_parameter(&self, tree: &Tree) -> Option { @@ -1640,9 +1452,7 @@ impl<'a> Semantics<'a> { let declaration = match environment.bind(id) { Some(d) => d, None => { - if !environment.is_error { - self.report_error_tree(tree, format!("cannot find value {id} here")); - } + self.report_error_tree(tree, format!("cannot find value {id} here")); return Some(Type::Error); } }; diff --git a/fine/src/vm.rs b/fine/src/vm.rs index 3a09687b..cf778e0e 100644 --- a/fine/src/vm.rs +++ b/fine/src/vm.rs @@ -102,18 +102,6 @@ impl Frame { } } - pub fn func(&self) -> Rc { - self.func.clone() - } - - pub fn args(&self) -> &[StackValue] { - &self.args - } - - pub fn pc(&self) -> usize { - self.pc - } - fn pop_value(&mut self) -> Result { self.stack.pop().ok_or_else(|| VMErrorCode::StackUnderflow) } diff --git a/fine/tests/example_tests.rs b/fine/tests/example_tests.rs index f8e1117e..461e6387 100644 --- a/fine/tests/example_tests.rs +++ b/fine/tests/example_tests.rs @@ -263,7 +263,7 @@ fn assert_eval_ok(tree: &SyntaxTree, lines: &Lines, expected: &str) { let semantics = Semantics::new(tree, lines); let module = compile(&semantics); - let mut context = Context::new(module.clone()); + let mut context = Context::new(module); context.init().expect("Unable to initialize module"); match eval_export_fn(&mut context, "test", &[]) { @@ -278,24 +278,7 @@ fn assert_eval_ok(tree: &SyntaxTree, lines: &Lines, expected: &str) { ); } Err(e) => { - semantics.dump_compiler_state(None); - - let mut actual = String::new(); - let _ = dump_module(&mut actual, &module); - - eprintln!("{actual}"); - - for frame in e.stack.iter() { - eprintln!("{:?}", frame.func()); - eprint!(" ("); - for arg in frame.args().iter() { - eprint!("{:?},", arg); - } - eprintln!(") @ {}", frame.pc()); - } - eprintln!(); - - panic!("error occurred while running: {:?}", e.code); + semantic_panic!(&semantics, None, "error occurred while running: {:?}", e); } } } diff --git a/fine/tests/expression/class.fine b/fine/tests/expression/class.fine index 4a1eb8c2..e9c7d7b9 100644 --- a/fine/tests/expression/class.fine +++ b/fine/tests/expression/class.fine @@ -6,9 +6,9 @@ class Point { // 12 // } - fun square_length(self) -> f64 { - self.x * self.x + self.y * self.y - } + // fun square_length(self) -> f64 { + // self.x * self.x + self.y * self.y + // } } class Line { @@ -18,24 +18,24 @@ class Line { fun test() -> f64 { let line = new Line { - start: new Point { y: 23, x: 7 }, + start: new Point { x: 7, y: 23 }, end: new Point { x: 999, y: 99 }, }; - let pt = line.start; - let z = line.start.x + pt.square_length();// + Point::something_static(); + let z = line.start.x;// + pt.square_length() + Point::something_static(); z } +/// @ignore WIP: Methods // @no-errors -// @eval: Float(585.0) +// @eval: Float(7.0) // @compiles-to: // | function << module >> (0 args, 0 locals): // | strings (0): // | code (2): // | 0: PushNothing // | 1: Return -// | function Point (5 args, 0 locals): +// | function Point (4 args, 0 locals): // | strings (1): // | 0: Point // | code (5): @@ -53,9 +53,9 @@ fun test() -> f64 { // | 2: PushString(0) // | 3: NewObject(2) // | 4: Return -// | function test (0 args, 3 locals): +// | function test (0 args, 2 locals): // | strings (0): -// | code (24): +// | code (17): // | 0: PushFloat(99.0) // | 1: PushFloat(999.0) // | 2: LoadFunction(1) @@ -69,30 +69,8 @@ fun test() -> f64 { // | 10: StoreLocal(0) // | 11: LoadLocal(0) // | 12: LoadSlot(0) -// | 13: StoreLocal(1) -// | 14: LoadLocal(0) -// | 15: LoadSlot(0) -// | 16: LoadSlot(0) -// | 17: LoadLocal(1) -// | 18: LoadFunction(4) -// | 19: Call(1) -// | 20: FloatAdd -// | 21: StoreLocal(2) -// | 22: LoadLocal(2) -// | 23: Return -// | function square_length (1 args, 0 locals): -// | strings (0): -// | code (12): -// | 0: LoadArgument(0) -// | 1: LoadSlot(0) -// | 2: LoadArgument(0) -// | 3: LoadSlot(0) -// | 4: FloatMultiply -// | 5: LoadArgument(0) -// | 6: LoadSlot(1) -// | 7: LoadArgument(0) -// | 8: LoadSlot(1) -// | 9: FloatMultiply -// | 10: FloatAdd -// | 11: Return +// | 13: LoadSlot(0) +// | 14: StoreLocal(1) +// | 15: LoadLocal(1) +// | 16: Return // | diff --git a/fine/tests/expression/errors/no_method_variables.fine b/fine/tests/expression/errors/no_method_variables.fine deleted file mode 100644 index a2a85579..00000000 --- a/fine/tests/expression/errors/no_method_variables.fine +++ /dev/null @@ -1,11 +0,0 @@ -class Foo { - fun bar(self) {} -} - -fun test() { - let obj = new Foo {}; - let f = obj.bar; -} - -// @expect-errors: -// | 7:6: methods cannot be assigned to variables