diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index 512919cd..fc817c65 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -658,7 +658,8 @@ fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C } // Fetch the correct constructor. - let type_reference = tree.child_tree_of_kind(c.syntax, TreeKind::TypeExpression)?; + // 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)?; let environment = c.semantics.environment_of(t); match environment.bind(identifier)? { diff --git a/fine/src/parser.rs b/fine/src/parser.rs index b2f5e460..8a906de0 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -120,6 +120,7 @@ impl<'a> std::ops::IndexMut for SyntaxTree<'a> { pub enum TreeKind { Error, + AlternateType, Argument, ArgumentList, BinaryExpression, @@ -150,6 +151,7 @@ pub enum TreeKind { SelfParameter, SelfReference, TypeExpression, + TypeIdentifier, TypeParameter, TypeParameterList, UnaryExpression, @@ -688,14 +690,27 @@ fn return_type(p: &mut CParser) { fn type_expr(p: &mut CParser) { let m = p.start(); - // TODO: Other kinds of type expressions probably! - p.expect(TokenKind::Identifier, "expected the identifier of a type"); + alternate_type(p); + p.end(m, TreeKind::TypeExpression); +} + +fn alternate_type(p: &mut CParser) { + let mut result = type_identifier(p); + while p.eat(TokenKind::Or) { + let m = p.start_before(result); + type_identifier(p); + result = p.end(m, TreeKind::AlternateType); + } +} + +fn type_identifier(p: &mut CParser) -> MarkClosed { + let m = p.start(); + p.expect(TokenKind::Identifier, "expected the identifier of a type"); if p.at(TokenKind::Less) { type_parameter_list(p); } - - p.end(m, TreeKind::TypeExpression); + p.end(m, TreeKind::TypeIdentifier) } fn type_parameter_list(p: &mut CParser) { @@ -1095,7 +1110,7 @@ fn object_constructor(p: &mut CParser) -> MarkClosed { let m = p.start(); p.expect_start(TokenKind::New); - type_expr(p); + type_identifier(p); if p.at(TokenKind::LeftBrace) { field_list(p); } else { diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index c447ec57..f09d1521 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -143,6 +143,9 @@ pub enum Type { // class need to be fetched explicitly from the semantics via the // TreeRef and `Semantics::class_of`; they are computed lazily. Object(TreeRef, Rc), + + // An alternate is one or another type. + Alternate(Box, Box), } impl Type { @@ -204,6 +207,7 @@ impl fmt::Display for Type { List(t) => write!(f, "list<{t}>"), Object(_, name) => write!(f, "{} instance", name), Class(_, name) => write!(f, "class {}", name), + Alternate(l, r) => write!(f, "{l} or {r}"), } } } @@ -592,7 +596,7 @@ impl<'a> Semantics<'a> { } let tree = &self.syntax_tree[t]; - eprintln!(">>> environment_of => {tree:?}"); + // eprintln!(">>> environment_of => {tree:?}"); let parent = match self.logical_parents[t.index()] { Some(t) => self.environment_of(t), @@ -613,7 +617,7 @@ impl<'a> Semantics<'a> { }; self.environments.borrow_mut()[t.index()] = Incremental::Complete(result.clone()); - eprintln!("<<< environment_of => {tree:?}"); + // eprintln!("<<< environment_of => {tree:?}"); result } @@ -986,11 +990,12 @@ impl<'a> Semantics<'a> { } let tree = &self.syntax_tree[t]; - eprintln!(">>> type_of => {tree:?}"); + // eprintln!(">>> type_of => {tree:?}"); let result = match tree.kind { TreeKind::Error => Some(Type::Error), + TreeKind::AlternateType => self.type_of_alternate_type(tree), TreeKind::Argument => self.type_of_argument(tree), TreeKind::BinaryExpression => self.type_of_binary(tree), TreeKind::Block => self.type_of_block(tree), @@ -1016,7 +1021,8 @@ impl<'a> Semantics<'a> { 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::TypeExpression => self.type_of_type_expr(tree), + TreeKind::TypeIdentifier => self.type_of_type_identifier(t, tree), TreeKind::TypeParameter => self.type_of_type_parameter(tree), TreeKind::UnaryExpression => self.type_of_unary(tree), @@ -1026,7 +1032,7 @@ impl<'a> Semantics<'a> { // NOTE: These return `None` if they encounter some problem. let result = result.unwrap_or(Type::Error); self.types.borrow_mut()[t.index()] = Incremental::Complete(result.clone()); - eprintln!("<<< type_of => {tree:?}"); + // eprintln!("<<< type_of => {tree:?}"); result } @@ -1190,8 +1196,13 @@ impl<'a> Semantics<'a> { } } - fn type_of_type_expr(&self, t: TreeRef, tree: &Tree) -> Option { + fn type_of_type_expr(&self, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::TypeExpression); + Some(self.type_of(tree.nth_tree(0)?)) + } + + fn type_of_type_identifier(&self, t: TreeRef, tree: &Tree) -> Option { + assert_eq!(tree.kind, TreeKind::TypeIdentifier); // TODO: This will *clearly* need to get better. let token = tree.nth_token(0)?; @@ -1711,6 +1722,13 @@ impl<'a> Semantics<'a> { Some(self.type_of(tree.nth_tree(0)?)) } + fn type_of_alternate_type(&self, tree: &Tree) -> Option { + // TODO: IDEA: nth_tree returns a bogus tree if not a tree, stop returning Option? + let left = self.type_of(tree.nth_tree(0)?); + let right = self.type_of(tree.nth_tree(2)?); + Some(Type::Alternate(Box::new(left), Box::new(right))) + } + pub fn dump_compiler_state(&self, tr: Option) { eprintln!("Parsed the tree as:"); eprintln!("\n{}", self.syntax_tree.dump(true)); @@ -1789,7 +1807,7 @@ pub fn check(s: &Semantics) { TreeKind::Parameter => { let _ = s.type_of(t); } - TreeKind::TypeExpression => { + TreeKind::TypeExpression | TreeKind::AlternateType | TreeKind::TypeIdentifier => { let _ = s.type_of(t); } TreeKind::Block => { diff --git a/fine/tests/errors/resilience/function_extra_comma.fine b/fine/tests/errors/resilience/function_extra_comma.fine index a8d571b9..2be131ee 100644 --- a/fine/tests/errors/resilience/function_extra_comma.fine +++ b/fine/tests/errors/resilience/function_extra_comma.fine @@ -15,7 +15,8 @@ fun f3() {} // | Identifier:'"x"' // | Colon:'":"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Comma:'","' // | Error:'"Error at 'fun': expect ')' to end a parameter list"' // | FunctionDecl @@ -27,7 +28,8 @@ fun f3() {} // | Identifier:'"x"' // | Colon:'":"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Comma:'","' // | Error // | Error:'"Error at ',': expected parameter"' @@ -36,7 +38,8 @@ fun f3() {} // | Identifier:'"z"' // | Colon:'":"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | RightParen:'")"' // | Block // | LeftBrace:'"{"' diff --git a/fine/tests/errors/resilience/incomplete_function.fine b/fine/tests/errors/resilience/incomplete_function.fine index 2a627c13..20531986 100644 --- a/fine/tests/errors/resilience/incomplete_function.fine +++ b/fine/tests/errors/resilience/incomplete_function.fine @@ -15,7 +15,8 @@ fun fib(n: f64) -> f64 { // | Identifier:'"f1"' // | Colon:'":"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Comma:'","' // | Error:'"Error at 'fun': expect ')' to end a parameter list"' // | FunctionDecl @@ -27,12 +28,14 @@ fun fib(n: f64) -> f64 { // | Identifier:'"n"' // | Colon:'":"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | RightParen:'")"' // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Block // | LeftBrace:'"{"' // | ExpressionStatement diff --git a/fine/tests/expression/argument.fine b/fine/tests/expression/argument.fine index 2c8164a6..a432d24e 100644 --- a/fine/tests/expression/argument.fine +++ b/fine/tests/expression/argument.fine @@ -20,12 +20,14 @@ fun test() -> f64 { // | Identifier:'"x"' // | Colon:'":"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | RightParen:'")"' // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Block // | LeftBrace:'"{"' // | ExpressionStatement @@ -45,7 +47,8 @@ fun test() -> f64 { // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Block // | LeftBrace:'"{"' // | ExpressionStatement diff --git a/fine/tests/expression/arithmetic.fine b/fine/tests/expression/arithmetic.fine index 395ba11b..03639511 100644 --- a/fine/tests/expression/arithmetic.fine +++ b/fine/tests/expression/arithmetic.fine @@ -16,7 +16,8 @@ fun test() -> f64 { // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Block // | LeftBrace:'"{"' // | ExpressionStatement diff --git a/fine/tests/expression/boolean.fine b/fine/tests/expression/boolean.fine index 5ed756f0..98a991a1 100644 --- a/fine/tests/expression/boolean.fine +++ b/fine/tests/expression/boolean.fine @@ -41,7 +41,8 @@ fun test() -> bool { // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"bool"' +// | TypeIdentifier +// | Identifier:'"bool"' // | Block // | LeftBrace:'"{"' // | ExpressionStatement diff --git a/fine/tests/expression/conditional.fine b/fine/tests/expression/conditional.fine index 425f6684..cad9fa10 100644 --- a/fine/tests/expression/conditional.fine +++ b/fine/tests/expression/conditional.fine @@ -29,7 +29,8 @@ fun test() -> f64 { // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Block // | LeftBrace:'"{"' // | IfStatement diff --git a/fine/tests/expression/variable.fine b/fine/tests/expression/variable.fine index 6c3ee1c8..e7335ac8 100644 --- a/fine/tests/expression/variable.fine +++ b/fine/tests/expression/variable.fine @@ -50,7 +50,8 @@ fun test() -> f64 { // | ReturnType // | Arrow:'"->"' // | TypeExpression -// | Identifier:'"f64"' +// | TypeIdentifier +// | Identifier:'"f64"' // | Block // | LeftBrace:'"{"' // | ExpressionStatement