From b5b56b49a90a1a605a959935144912e9eecee98c Mon Sep 17 00:00:00 2001 From: John Doty Date: Sat, 3 Feb 2024 07:59:49 -0800 Subject: [PATCH] [fine] fix some bugs, semantics for is --- fine/src/parser.rs | 11 +++++-- fine/src/semantics.rs | 31 ++++++++++++++++---- fine/tests/expression/is.fine | 18 ++++++++++++ fine/tests/expression/return_expression.fine | 6 ++++ 4 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 fine/tests/expression/is.fine create mode 100644 fine/tests/expression/return_expression.fine diff --git a/fine/src/parser.rs b/fine/src/parser.rs index cfc40545..d6bc089a 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -1183,7 +1183,14 @@ fn field_list(p: &mut CParser) { p.expect_start(TokenKind::LeftBrace); while !p.at(TokenKind::RightBrace) && !p.eof() { - field_value(p); + if p.at(TokenKind::Identifier) { + field_value(p); + } else { + if p.at_any(STATEMENT_RECOVERY) { + break; + } + p.advance_with_error("expected an identifier in a field list"); + } } p.expect( TokenKind::RightBrace, @@ -1196,7 +1203,7 @@ fn field_list(p: &mut CParser) { fn field_value(p: &mut CParser) { let m = p.start(); - p.expect(TokenKind::Identifier, "expected a field name"); + p.expect_start(TokenKind::Identifier); if p.eat(TokenKind::Colon) { expression(p); } diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 536715b3..f104a7ea 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -604,14 +604,13 @@ impl<'a> Semantics<'a> { }; let result = match tree.kind { - TreeKind::LetStatement => self.environment_of_let(parent, tree), - TreeKind::ParamList => self.environment_of_paramlist(parent, tree), - TreeKind::File => self.environment_of_file(parent, tree), + TreeKind::IsExpression => self.environment_of_is_expression(parent, tree), TreeKind::Block => self.environment_of_block(parent, tree), - + TreeKind::File => self.environment_of_file(parent, tree), TreeKind::ForStatement => self.environment_of_for(parent, tree), - + TreeKind::LetStatement => self.environment_of_let(parent, tree), TreeKind::MemberAccess => self.environment_of_member_access(tree), + TreeKind::ParamList => self.environment_of_paramlist(parent, tree), _ => parent, }; @@ -819,6 +818,24 @@ impl<'a> Semantics<'a> { } } + fn environment_of_is_expression(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { + assert_eq!(tree.kind, TreeKind::IsExpression); + let Some(binding) = tree.child_tree_of_kind(self.syntax_tree, TreeKind::VariableBinding) + else { + return parent; + }; + let Some(variable) = binding.nth_token(0) else { + return Environment::error(); + }; + let Some(type_expr) = binding.nth_tree(2) else { + return Environment::error(); + }; + + let mut env = Environment::new(Some(parent), Location::Local); + env.insert(variable, type_expr); + return EnvironmentRef::new(env); + } + pub fn class_of(&self, t: TreeRef) -> ClassRef { { // I want to make sure that this borrow is dropped after this block. @@ -968,6 +985,9 @@ impl<'a> Semantics<'a> { (Type::Error, _) => true, (_, Type::Error) => true, + // Can... I... convert unreachable always? Is this sound? + (Type::Unreachable, _) => true, + // TODO: Unification on type variables! :D (_, _) => false, } @@ -1010,6 +1030,7 @@ impl<'a> Semantics<'a> { TreeKind::GroupingExpression => self.type_of_grouping(tree), TreeKind::Identifier => self.type_of_identifier(t, tree), TreeKind::IfStatement => self.type_of_if_statement(tree), + TreeKind::IsExpression => Some(Type::Bool), TreeKind::LetStatement => Some(Type::Nothing), TreeKind::ListConstructor => self.type_of_list_constructor(t, tree), TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree), diff --git a/fine/tests/expression/is.fine b/fine/tests/expression/is.fine new file mode 100644 index 00000000..0f645743 --- /dev/null +++ b/fine/tests/expression/is.fine @@ -0,0 +1,18 @@ +class Foo { + a: f64; +} + +fun test() -> f64 { + let b = new Foo { a : 23 }; + + let result = 0; + if b is c:Foo and c.a == 23 { + result = result + 1; + } + if b is c:Foo and c.a == 24 { + result = result + 1; + } + result +} + +// @no-errors diff --git a/fine/tests/expression/return_expression.fine b/fine/tests/expression/return_expression.fine new file mode 100644 index 00000000..8d559820 --- /dev/null +++ b/fine/tests/expression/return_expression.fine @@ -0,0 +1,6 @@ +fun explicit_return() -> f64 { + return 10.0; + // No error: after this point code is unreachable. +} + +// @no-errors \ No newline at end of file