From a21f18da6efd55dc9d24faf65868cbe5417827da Mon Sep 17 00:00:00 2001 From: John Doty Date: Thu, 15 Feb 2024 06:29:56 -0800 Subject: [PATCH 1/2] [fine] export, dump source map, lookup fix --- fine/src/lib.rs | 11 ++--------- fine/src/parser.rs | 33 +++++++++++++++++++++++++++++++++ fine/src/semantics.rs | 28 +++++++++++++++++++++++----- fine/src/tokens.rs | 9 +++++++-- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/fine/src/lib.rs b/fine/src/lib.rs index 51dfaec4..a9ba0872 100644 --- a/fine/src/lib.rs +++ b/fine/src/lib.rs @@ -41,17 +41,10 @@ impl ModuleLoader for StandardModuleLoader { let result = match std::fs::canonicalize(&p) { Ok(p) => match p.into_os_string().into_string() { Ok(s) => s, - Err(_e) => { - eprintln!("ERROR INTO OS STRING: {}", _e.to_string_lossy()); - name.clone() - } + Err(_e) => name.clone(), }, - Err(_e) => { - eprintln!("ERROR CANONICAL {}: {_e}", p.display()); - name.clone() - } + Err(_e) => name.clone(), }; - eprintln!("**** {source} {name} => {result}"); result } diff --git a/fine/src/parser.rs b/fine/src/parser.rs index 313ad0dd..df006d3c 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -167,6 +167,8 @@ pub enum TreeKind { WildcardPattern, Import, + Export, + ExportList, } pub struct Tree { @@ -576,6 +578,7 @@ fn file(p: &mut CParser) { match p.peek() { TokenKind::Import => import(p), TokenKind::Class => class(p), + TokenKind::Export => export(p), TokenKind::RightBrace => { // An error parsing mismatched braces can leave me at an // un-balanced right brace, which unfortunately will not be @@ -636,6 +639,36 @@ fn import(p: &mut CParser) { p.end(m, TreeKind::Import); } +fn export(p: &mut CParser) { + let m = p.start(); + + p.expect_start(TokenKind::Export); + match p.peek() { + TokenKind::Fun => function(p), + TokenKind::Let => statement_let(p), + TokenKind::Identifier => export_list(p), + TokenKind::Semicolon => (), + _ => p.error("expected something to export"), + } + + p.end(m, TreeKind::Export); +} + +fn export_list(p: &mut CParser) { + let m = p.start(); + + p.expect_start(TokenKind::Identifier); + while p.eat(TokenKind::Comma) { + p.expect( + TokenKind::Identifier, + "expected an identifier to export in this export list", + ); + } + p.expect(TokenKind::Semicolon, "expected a ; to end the export list"); + + p.end(m, TreeKind::ExportList); +} + fn class(p: &mut CParser) { let m = p.start(); diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 4ed8009b..d8b21734 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -163,7 +163,7 @@ pub enum Type { Alternate(Box<[Type]>), // A module of some kind. What module? - Module(ImportRecord), + Module(Rc, ImportRecord), } impl Type { @@ -258,7 +258,7 @@ impl fmt::Display for Type { } Ok(()) } - Module(name) => write!(f, "module {}", name.name), + Module(name, _) => write!(f, "module {}", name), } } } @@ -2245,9 +2245,9 @@ impl Semantics { self.internal_compiler_error(None, "import map not initialized"); }; - let name = tok.as_str(&self.source); - match import_map.get(name) { - Some(import) => Some(Type::Module(import.clone())), + let name = string_constant_to_string(tok.as_str(&self.source)); + match import_map.get(&name) { + Some(import) => Some(Type::Module(name.into(), import.clone())), None => { self.report_error_tree(tree, format!("unable to resolve module import {name}")); Some(Type::Error) @@ -2405,6 +2405,21 @@ impl Semantics { } } + { + match self.import_map.get() { + Some(m) => { + eprintln!("Import map:"); + for (k, b) in m.iter() { + eprintln!(" {k} => {} ({})", b.name, b.module_id); + } + eprintln!(); + } + None => { + eprintln!("The import map is not set.\n") + } + } + } + if let Some(tr) = tr { eprintln!("This is about the tree: {:?}", &self.syntax_tree[tr]); eprintln!("The logical parent chain of the tree was:\n"); @@ -2529,6 +2544,9 @@ pub fn check(s: &Semantics) { TreeKind::Import => { let _ = s.type_of(t); } + + TreeKind::Export => {} + TreeKind::ExportList => {} } } } diff --git a/fine/src/tokens.rs b/fine/src/tokens.rs index b4e84e69..e9d1230a 100644 --- a/fine/src/tokens.rs +++ b/fine/src/tokens.rs @@ -42,6 +42,7 @@ pub enum TokenKind { Await, Class, Else, + Export, False, For, From, @@ -294,6 +295,9 @@ impl<'a> Tokens<'a> { if ident == "else" { return TokenKind::Else; } + if ident == "export" { + return TokenKind::Export; + } } 'f' => { if ident == "false" { @@ -639,12 +643,13 @@ mod tests { test_tokens!( more_more_keywords, - "in is match _ as", + "in is match _ as export", (0, In, "in"), (3, Is, "is"), (6, Match, "match"), (12, Underscore, "_"), - (14, As, "as") + (14, As, "as"), + (17, Export, "export") ); test_tokens!( From 1199646e29ded4d14212576918932a0bce35ab4e Mon Sep 17 00:00:00 2001 From: John Doty Date: Thu, 15 Feb 2024 06:36:14 -0800 Subject: [PATCH 2/2] [fine] File name in error messages Going to need to normalize that name though, because right now it really *really* sucks to have a big \\?\ kinda name. Probably normalize it relative to the base directory. --- fine/src/lib.rs | 3 +- fine/src/semantics.rs | 33 ++++++++++++++----- .../expression/errors/assignment_errors.fine | 8 ++--- .../expression/errors/broken_conditional.fine | 2 +- .../errors/class_as_a_variable.fine | 2 +- .../errors/class_duplicate_fields.fine | 2 +- .../tests/expression/errors/class_errors.fine | 12 +++---- .../errors/duplicate_arguments.fine | 2 +- fine/tests/expression/errors/duplicates.fine | 6 ++-- fine/tests/expression/errors/if_not_bool.fine | 2 +- .../expression/errors/if_requires_else.fine | 2 +- .../expression/errors/locals_in_globals.fine | 2 +- .../errors/no_method_variables.fine | 2 +- .../errors/return_statement_mismatch.fine | 2 +- .../expression/errors/while_not_bool.fine | 2 +- .../expression/errors/wild_member_access.fine | 4 +-- 16 files changed, 52 insertions(+), 34 deletions(-) diff --git a/fine/src/lib.rs b/fine/src/lib.rs index a9ba0872..b340968e 100644 --- a/fine/src/lib.rs +++ b/fine/src/lib.rs @@ -105,7 +105,8 @@ impl Runtime { ModuleSource::SourceText(source) => { let source: Rc = source.into(); let (tree, lines) = parse(&source); - let semantics = Rc::new(Semantics::new(source, tree, lines)); + let semantics = + Rc::new(Semantics::new(name.clone().into(), source, tree, lines)); let mut normalized_imports = Vec::new(); for import in semantics.imports() { diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index d8b21734..16e9ce5c 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -23,28 +23,36 @@ use std::{ // that will have to wait for now #[derive(Clone, PartialEq, Eq)] pub struct Error { + pub file: Rc, pub start: (usize, usize), pub end: (usize, usize), pub message: String, } impl Error { - pub fn new(line: usize, column: usize, message: T) -> Self + pub fn new(file: Rc, line: usize, column: usize, message: T) -> Self where T: ToString, { Error { + file, start: (line, column), end: (line, column), message: message.to_string(), } } - pub fn new_spanned(start: (usize, usize), end: (usize, usize), message: T) -> Self + pub fn new_spanned( + file: Rc, + start: (usize, usize), + end: (usize, usize), + message: T, + ) -> Self where T: ToString, { Error { + file, start, end, message: message.to_string(), @@ -60,7 +68,11 @@ impl fmt::Debug for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}: {}", self.start.0, self.start.1, self.message) + write!( + f, + "{}:{}:{}: {}", + self.file, self.start.0, self.start.1, self.message + ) } } @@ -622,6 +634,7 @@ enum Incremental { } pub struct Semantics { + file: Rc, source: Rc, syntax_tree: Rc, lines: Rc, @@ -641,7 +654,7 @@ pub struct Semantics { } impl Semantics { - pub fn new(source: Rc, tree: Rc, lines: Rc) -> Self { + pub fn new(file: Rc, source: Rc, tree: Rc, lines: Rc) -> Self { let mut logical_parents = vec![None; tree.len()]; if let Some(root) = tree.root() { set_logical_parents(&mut logical_parents, &tree, root, None); @@ -650,6 +663,7 @@ impl Semantics { let root_environment = Environment::new(None, Location::Module); let mut semantics = Semantics { + file, source, syntax_tree: tree.clone(), lines, @@ -730,9 +744,12 @@ impl Semantics { { let start = self.lines.position(start); let end = self.lines.position(end); - self.errors - .borrow_mut() - .push(Error::new_spanned(start, end, error.to_string())); + self.errors.borrow_mut().push(Error::new_spanned( + self.file.clone(), + start, + end, + error.to_string(), + )); } fn report_error_tree(&self, tree: &Tree, error: T) @@ -2801,7 +2818,7 @@ mod tests { pub fn ice() { let source: Rc = "1+1".into(); let (tree, lines) = parse(&source); - let semantics = Semantics::new(source, tree.clone(), lines); + let semantics = Semantics::new("__test__".into(), source, tree.clone(), lines); semantics.internal_compiler_error(tree.root(), "oh no"); } } diff --git a/fine/tests/expression/errors/assignment_errors.fine b/fine/tests/expression/errors/assignment_errors.fine index 0f6782cf..bba8eb9c 100644 --- a/fine/tests/expression/errors/assignment_errors.fine +++ b/fine/tests/expression/errors/assignment_errors.fine @@ -14,7 +14,7 @@ fun wrong() { } // @expect-errors: -// | 7:4: cannot assign a value of type 'string' to type 'f64' -// | 8:4: cannot assign a value of type 'f64' to type 'string' -// | 11:4: cannot assign a value of type 'f64' to type 'string' -// | 13:2: cannot assign a new value to a function declaration +// | __test__:7:4: cannot assign a value of type 'string' to type 'f64' +// | __test__:8:4: cannot assign a value of type 'f64' to type 'string' +// | __test__:11:4: cannot assign a value of type 'f64' to type 'string' +// | __test__:13:2: cannot assign a new value to a function declaration diff --git a/fine/tests/expression/errors/broken_conditional.fine b/fine/tests/expression/errors/broken_conditional.fine index dbcfe35c..e4a9508a 100644 --- a/fine/tests/expression/errors/broken_conditional.fine +++ b/fine/tests/expression/errors/broken_conditional.fine @@ -4,4 +4,4 @@ fun test() { // NOTE: These errors should be better // @expect-errors: -// | 2:10: Error at 'true': expected a block after `if` +// | __test__:2:10: Error at 'true': expected a block after `if` diff --git a/fine/tests/expression/errors/class_as_a_variable.fine b/fine/tests/expression/errors/class_as_a_variable.fine index 83540878..e7bad9f8 100644 --- a/fine/tests/expression/errors/class_as_a_variable.fine +++ b/fine/tests/expression/errors/class_as_a_variable.fine @@ -5,4 +5,4 @@ fun test() -> f64 { } // @expect-errors: -// | 4:6: cannot apply binary operator '+' to expressions of type 'class Foo' (on the left) and 'f64' (on the right) \ No newline at end of file +// | __test__:4:6: cannot apply binary operator '+' to expressions of type 'class Foo' (on the left) and 'f64' (on the right) \ No newline at end of file diff --git a/fine/tests/expression/errors/class_duplicate_fields.fine b/fine/tests/expression/errors/class_duplicate_fields.fine index d8d59f60..051412c7 100644 --- a/fine/tests/expression/errors/class_duplicate_fields.fine +++ b/fine/tests/expression/errors/class_duplicate_fields.fine @@ -4,4 +4,4 @@ class Foo { } // @expect-errors: -// | 3:2: duplicate definition of field 'x' +// | __test__:3:2: duplicate definition of field 'x' diff --git a/fine/tests/expression/errors/class_errors.fine b/fine/tests/expression/errors/class_errors.fine index 678cca7b..25e26048 100644 --- a/fine/tests/expression/errors/class_errors.fine +++ b/fine/tests/expression/errors/class_errors.fine @@ -16,9 +16,9 @@ fun test() { } // @expect-errors: -// | 7:12: missing an initializer for field y -// | 8:12: missing an initializer for field x -// | 9:41: Point instance does not have a field named z -// | 10:32: field x is of type f64, but this expression generates a string -// | 12:32: cannot find value x here -// | 15:31: field x is of type f64, but this expression generates a string +// | __test__:7:12: missing an initializer for field y +// | __test__:8:12: missing an initializer for field x +// | __test__:9:41: Point instance does not have a field named z +// | __test__:10:32: field x is of type f64, but this expression generates a string +// | __test__:12:32: cannot find value x here +// | __test__:15:31: field x is of type f64, but this expression generates a string diff --git a/fine/tests/expression/errors/duplicate_arguments.fine b/fine/tests/expression/errors/duplicate_arguments.fine index 071d59b4..73d32c47 100644 --- a/fine/tests/expression/errors/duplicate_arguments.fine +++ b/fine/tests/expression/errors/duplicate_arguments.fine @@ -1,4 +1,4 @@ fun something(x: f64, x: f64) {} // @expect-errors: -// | 1:22: duplicate definition of parameter 'x' +// | __test__:1:22: duplicate definition of parameter 'x' diff --git a/fine/tests/expression/errors/duplicates.fine b/fine/tests/expression/errors/duplicates.fine index f9d1f975..5d780ff1 100644 --- a/fine/tests/expression/errors/duplicates.fine +++ b/fine/tests/expression/errors/duplicates.fine @@ -11,6 +11,6 @@ class Bar {} class Bar {} // @expect-errors: -// | 3:2: duplicate definition of function 'foo' -// | 8:0: duplicate definition of function 'nested' -// | 11:0: duplicate definition of class 'Bar' \ No newline at end of file +// | __test__:3:2: duplicate definition of function 'foo' +// | __test__:8:0: duplicate definition of function 'nested' +// | __test__:11:0: duplicate definition of class 'Bar' \ No newline at end of file diff --git a/fine/tests/expression/errors/if_not_bool.fine b/fine/tests/expression/errors/if_not_bool.fine index c72335be..43aadb5f 100644 --- a/fine/tests/expression/errors/if_not_bool.fine +++ b/fine/tests/expression/errors/if_not_bool.fine @@ -1,4 +1,4 @@ if 23 { "what" } else { "the" } // @expect-errors: -// | 1:3: this condition produces 'f64', but must produce bool +// | __test__:1:3: this condition produces 'f64', but must produce bool diff --git a/fine/tests/expression/errors/if_requires_else.fine b/fine/tests/expression/errors/if_requires_else.fine index 8f60f676..47d93660 100644 --- a/fine/tests/expression/errors/if_requires_else.fine +++ b/fine/tests/expression/errors/if_requires_else.fine @@ -1,4 +1,4 @@ if (if false { true }) { 32 } else { 23 } // @expect-errors: -// | 1:3: this condition produces 'nothing or bool', but must produce bool +// | __test__:1:3: this condition produces 'nothing or bool', but must produce bool diff --git a/fine/tests/expression/errors/locals_in_globals.fine b/fine/tests/expression/errors/locals_in_globals.fine index 0d975d6d..344e27c2 100644 --- a/fine/tests/expression/errors/locals_in_globals.fine +++ b/fine/tests/expression/errors/locals_in_globals.fine @@ -9,4 +9,4 @@ fun foo() -> f64 { } // @expect-errors: -// | 8:2: cannot find value y here \ No newline at end of file +// | __test__:8:2: cannot find value y here \ No newline at end of file diff --git a/fine/tests/expression/errors/no_method_variables.fine b/fine/tests/expression/errors/no_method_variables.fine index a2a85579..d2141fa6 100644 --- a/fine/tests/expression/errors/no_method_variables.fine +++ b/fine/tests/expression/errors/no_method_variables.fine @@ -8,4 +8,4 @@ fun test() { } // @expect-errors: -// | 7:6: methods cannot be assigned to variables +// | __test__:7:6: methods cannot be assigned to variables diff --git a/fine/tests/expression/errors/return_statement_mismatch.fine b/fine/tests/expression/errors/return_statement_mismatch.fine index 521d2772..5cbf9a67 100644 --- a/fine/tests/expression/errors/return_statement_mismatch.fine +++ b/fine/tests/expression/errors/return_statement_mismatch.fine @@ -6,4 +6,4 @@ fun test() -> f64 { } // @expect-errors: -// | 3:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string' \ No newline at end of file +// | __test__:3:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string' \ No newline at end of file diff --git a/fine/tests/expression/errors/while_not_bool.fine b/fine/tests/expression/errors/while_not_bool.fine index f0d19504..19c89f4c 100644 --- a/fine/tests/expression/errors/while_not_bool.fine +++ b/fine/tests/expression/errors/while_not_bool.fine @@ -3,4 +3,4 @@ fun test() { } // @expect-errors: -// | 2:8: this condition produces 'f64', but must produce bool +// | __test__:2:8: this condition produces 'f64', but must produce bool diff --git a/fine/tests/expression/errors/wild_member_access.fine b/fine/tests/expression/errors/wild_member_access.fine index ae5600f5..c76ed1d5 100644 --- a/fine/tests/expression/errors/wild_member_access.fine +++ b/fine/tests/expression/errors/wild_member_access.fine @@ -8,5 +8,5 @@ fun test() { } // @expect-errors: -// | 7:12: Error at '{': expected an identifier after a '.' in member access -// | 7:26: cannot find value foo here +// | __test__:7:12: Error at '{': expected an identifier after a '.' in member access +// | __test__:7:26: cannot find value foo here