diff --git a/fine/src/parser.rs b/fine/src/parser.rs index d6bc089a..8a906de0 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -155,9 +155,6 @@ pub enum TreeKind { TypeParameter, TypeParameterList, UnaryExpression, - - IsExpression, - VariableBinding, } pub struct Tree<'a> { @@ -321,7 +318,6 @@ struct MarkClosed { struct CParser<'a> { tokens: Tokens<'a>, current: Token<'a>, - next: Token<'a>, fuel: Cell, events: Vec>, panic: bool, @@ -332,13 +328,11 @@ impl<'a> CParser<'a> { let mut parser = CParser { tokens, current: Token::new(TokenKind::EOF, 0, ""), - next: Token::new(TokenKind::EOF, 0, ""), fuel: Cell::new(256), events: Vec::new(), panic: false, }; parser.current = parser.tokens.next(); - parser.next = parser.tokens.next(); parser.skip_ephemera(); parser } @@ -377,18 +371,14 @@ impl<'a> CParser<'a> { self.events.push(ParseEvent::Advance { token: self.current.clone(), }); - // Move next into current (and current into next but who cares, thanks rust.) - std::mem::swap(&mut self.current, &mut self.next); - self.next = self.tokens.next(); + self.current = self.tokens.next(); self.skip_ephemera(); } fn skip_ephemera(&mut self) { while self.current.kind == TokenKind::Whitespace || self.current.kind == TokenKind::Comment { - // Move next into current (and current into next but who cares, thanks rust.) - std::mem::swap(&mut self.current, &mut self.next); - self.next = self.tokens.next(); + self.current = self.tokens.next(); } } @@ -407,17 +397,6 @@ impl<'a> CParser<'a> { self.current.kind } - fn peek_next(&self) -> TokenKind { - if self.fuel.get() == 0 { - panic!( - "parser is stuck at '{}' ({})!", - self.current, self.current.start - ); - } - self.fuel.set(self.fuel.get() - 1); - self.next.kind - } - // fn trace(&self, msg: &str) { // eprintln!("{}: {}: {}", self.current.start, self.current, msg); // } @@ -908,7 +887,7 @@ fn expression(p: &mut CParser) { expression_with_power(p, 0) } -const UNARY_POWER: u8 = 16; +const UNARY_POWER: u8 = 14; fn infix_power(token: TokenKind) -> Option<(u8, u8)> { // A dumb thing: the pair controls associativity. @@ -918,18 +897,17 @@ fn infix_power(token: TokenKind) -> Option<(u8, u8)> { match token { TokenKind::Equal => Some((1, 0)), TokenKind::Or => Some((2, 3)), - TokenKind::Is => Some((4, 5)), - TokenKind::And => Some((6, 7)), - TokenKind::EqualEqual | TokenKind::BangEqual => Some((8, 9)), + TokenKind::And => Some((4, 5)), + TokenKind::EqualEqual | TokenKind::BangEqual => Some((6, 7)), TokenKind::Less | TokenKind::Greater | TokenKind::GreaterEqual | TokenKind::LessEqual => { - Some((10, 11)) + Some((8, 9)) } - TokenKind::Plus | TokenKind::Minus => Some((12, 13)), - TokenKind::Star | TokenKind::Slash => Some((14, 15)), + TokenKind::Plus | TokenKind::Minus => Some((10, 11)), + TokenKind::Star | TokenKind::Slash => Some((12, 13)), // // UNARY_POWER goes here. // - TokenKind::Dot => Some((18, 19)), + TokenKind::Dot => Some((16, 17)), _ => None, } } @@ -953,58 +931,22 @@ fn expression_with_power(p: &mut CParser, minimum_power: u8) { break; } - expr = match token { - TokenKind::Dot => member_access(p, expr, rp), - TokenKind::Is => is_expression(p, expr, rp), - _ => binary_expression(p, expr, rp), - }; + // TODO: I don't think this works for other "infix" types, but we'll + // see won't we. + let m = p.start_before(expr); + p.advance(); // Consume the operator + expression_with_power(p, rp); + expr = p.end( + m, + if token == TokenKind::Dot { + TreeKind::MemberAccess + } else { + TreeKind::BinaryExpression + }, + ); } } -fn member_access(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClosed { - let m = p.start_before(left); - p.advance(); // Consume the operator - expression_with_power(p, right_power); - p.end(m, TreeKind::MemberAccess) -} - -fn binary_expression(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClosed { - let m = p.start_before(left); - p.advance(); // Consume the operator - expression_with_power(p, right_power); - p.end(m, TreeKind::BinaryExpression) -} - -fn is_expression(p: &mut CParser, left: MarkClosed, right_power: u8) -> MarkClosed { - let m = p.start_before(left); - p.advance(); // Consume the operator - - // This is hard to do with just, like, no lookahead. - if p.peek() == TokenKind::Identifier && p.peek_next() == TokenKind::Colon { - // This is a variable binding. - variable_binding(p); - } else { - type_expr(p); - } - - // Additional predicates go into the right-hand-side. - if p.eat(TokenKind::And) { - expression_with_power(p, right_power); - } - - p.end(m, TreeKind::IsExpression) -} - -fn variable_binding(p: &mut CParser) { - let m = p.start(); - - p.expect_start(TokenKind::Identifier); - p.expect_start(TokenKind::Colon); - type_expr(p); - - p.end(m, TreeKind::VariableBinding); -} - fn argument_list(p: &mut CParser) { let m = p.start(); @@ -1183,14 +1125,7 @@ fn field_list(p: &mut CParser) { p.expect_start(TokenKind::LeftBrace); while !p.at(TokenKind::RightBrace) && !p.eof() { - 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"); - } + field_value(p); } p.expect( TokenKind::RightBrace, @@ -1203,7 +1138,7 @@ fn field_list(p: &mut CParser) { fn field_value(p: &mut CParser) { let m = p.start(); - p.expect_start(TokenKind::Identifier); + p.expect(TokenKind::Identifier, "expected a field name"); if p.eat(TokenKind::Colon) { expression(p); } diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index f104a7ea..f09d1521 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -604,13 +604,14 @@ impl<'a> Semantics<'a> { }; let result = match tree.kind { - 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), + TreeKind::File => self.environment_of_file(parent, tree), + TreeKind::Block => self.environment_of_block(parent, tree), + + TreeKind::ForStatement => self.environment_of_for(parent, tree), + + TreeKind::MemberAccess => self.environment_of_member_access(tree), _ => parent, }; @@ -818,24 +819,6 @@ 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. @@ -985,9 +968,6 @@ 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, } @@ -1030,7 +1010,6 @@ 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), @@ -1875,9 +1854,6 @@ pub fn check(s: &Semantics) { TreeKind::FieldValue => {} TreeKind::SelfParameter => {} TreeKind::SelfReference => {} - - TreeKind::IsExpression => check_is_expression(s, tree), - TreeKind::VariableBinding => check_variable_binding(s, tree), } } } @@ -2053,14 +2029,6 @@ fn check_class_declaration(s: &Semantics, tree: &Tree) { } } -fn check_is_expression(_s: &Semantics, _tree: &Tree) { - // TODO -} - -fn check_variable_binding(_s: &Semantics, _tree: &Tree) { - // TODO -} - #[cfg(test)] mod tests { use super::*; diff --git a/fine/src/tokens.rs b/fine/src/tokens.rs index 36a9ec65..67140c88 100644 --- a/fine/src/tokens.rs +++ b/fine/src/tokens.rs @@ -48,7 +48,6 @@ pub enum TokenKind { If, Import, In, - Is, Let, New, Or, @@ -298,9 +297,6 @@ impl<'a> Tokens<'a> { if ident == "in" { return TokenKind::In; } - if ident == "is" { - return TokenKind::Is; - } } 'l' => { if ident == "let" { @@ -597,8 +593,6 @@ mod tests { (58, New, "new") ); - test_tokens!(more_more_keywords, "in is", (0, In, "in"), (3, Is, "is")); - test_tokens!( strings, r#"'this is a string that\'s great!\r\n' "foo's" 'bar"s' "#, diff --git a/fine/tests/expression/alternates.fine b/fine/tests/expression/alternates.fine index 97bb3007..45dcb868 100644 --- a/fine/tests/expression/alternates.fine +++ b/fine/tests/expression/alternates.fine @@ -33,7 +33,7 @@ class Monster { fun print(x:string) {} fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) { - match weapon { + weapon match { w:RangedWeapon -> distance >= w.minRange and distance <= w.maxRange, _ -> distance == 1 } diff --git a/fine/tests/expression/is.fine b/fine/tests/expression/is.fine deleted file mode 100644 index 0f645743..00000000 --- a/fine/tests/expression/is.fine +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 8d559820..00000000 --- a/fine/tests/expression/return_expression.fine +++ /dev/null @@ -1,6 +0,0 @@ -fun explicit_return() -> f64 { - return 10.0; - // No error: after this point code is unreachable. -} - -// @no-errors \ No newline at end of file