diff --git a/fine/src/parser.rs b/fine/src/parser.rs index 7b30b65a..4527ebd5 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -139,6 +139,7 @@ pub enum TreeKind { Identifier, IfStatement, IsExpression, + IteratorVariable, LetStatement, ListConstructor, ListConstructorElement, @@ -889,10 +890,7 @@ fn statement_for(p: &mut CParser) { let m = p.start(); p.expect_start(TokenKind::For); - p.expect( - TokenKind::Identifier, - "expected an identifier for the loop variable", - ); + iterator_variable(p); p.expect(TokenKind::In, "expect an 'in' after the loop variable"); if p.at_any(EXPRESSION_FIRST) { expression(p); @@ -904,6 +902,17 @@ fn statement_for(p: &mut CParser) { p.end(m, TreeKind::ForStatement); } +fn iterator_variable(p: &mut CParser) { + let m = p.start(); + + p.expect( + TokenKind::Identifier, + "expected an identifier for the iterator variable", + ); + + p.end(m, TreeKind::IteratorVariable); +} + fn statement_expression(p: &mut CParser) { let m = p.start(); diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 4942a2f3..b51a56db 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -908,31 +908,19 @@ impl<'a> Semantics<'a> { EnvironmentRef::new(environment) } - fn environment_of_for(&self, parent: EnvironmentRef, _tree: &Tree) -> EnvironmentRef { - // let Some(id) = tree.nth_token(1) else { - // return parent; - // }; + fn environment_of_for(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { + let Some(it) = tree.nth_tree(1) else { + return parent; + }; - // let Some(enumerable) = tree.nth_tree(3) else { - // return parent; - // }; + let iterator = &self.syntax_tree[it]; + let Some(id) = iterator.nth_token(0) else { + return parent; + }; - // let item_type = match self.type_of(enumerable) { - // Type::Error => Type::Error, - // Type::List(x) => (&*x).clone(), - // _ => { - // self.report_error_tree_ref(enumerable, "this expression is not enumerable"); - // Type::Error - // } - // }; - - // TODO: This is broken, need a sub-tree to point the decl at that - // has the right type. - // - // let mut environment = Environment::new(Some(parent), Location::Local); - // environment.insert(id, item_type); - // EnvironmentRef::new(environment) - parent + let mut environment = Environment::new(Some(parent), Location::Local); + environment.insert(id, it); + EnvironmentRef::new(environment) } fn environment_of_is_expression(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { @@ -1277,6 +1265,7 @@ impl<'a> Semantics<'a> { TreeKind::Identifier => self.type_of_identifier(t, tree), TreeKind::IfStatement => self.type_of_if_statement(tree), TreeKind::IsExpression => Some(Type::Bool), + TreeKind::IteratorVariable => self.type_of_iterator_variable(tree), TreeKind::LetStatement => Some(Type::Nothing), TreeKind::ListConstructor => self.type_of_list_constructor(t, tree), TreeKind::ListConstructorElement => self.type_of_list_constructor_element(tree), @@ -1938,6 +1927,24 @@ impl<'a> Semantics<'a> { } } + fn type_of_iterator_variable(&self, tree: &Tree) -> Option { + assert_eq!(tree.kind, TreeKind::IteratorVariable); + let parent = &self.syntax_tree[tree.parent?]; + assert_eq!(parent.kind, TreeKind::ForStatement); + + let enumerable = parent.nth_tree(3)?; + let item_type = match self.type_of(enumerable) { + Type::Error => Type::Error, + Type::List(x) => (&*x).clone(), + _ => { + self.report_error_tree_ref(enumerable, "this expression is not enumerable"); + Type::Error + } + }; + + Some(item_type) + } + fn type_of_list_constructor(&self, t: TreeRef, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::ListConstructor); let mut element_type = None; @@ -2346,7 +2353,9 @@ pub fn check(s: &Semantics) { TreeKind::ListConstructorElement => { let _ = s.type_of(t); } + TreeKind::ForStatement => check_for_statement(s, t), + TreeKind::IteratorVariable => {} TreeKind::ClassDecl => check_class_declaration(s, tree), TreeKind::FieldDecl => {} diff --git a/fine/tests/expression/lists.fine b/fine/tests/expression/lists.fine index c2bdccf4..7e6159bc 100644 --- a/fine/tests/expression/lists.fine +++ b/fine/tests/expression/lists.fine @@ -13,4 +13,4 @@ fun test() -> f64 { // @ignore WIP // @no-errors -// @type: 88 list \ No newline at end of file +// @type: 155 list \ No newline at end of file