Compare commits

...

2 commits

Author SHA1 Message Date
1199646e29 [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.
2024-02-15 06:36:14 -08:00
a21f18da6e [fine] export, dump source map, lookup fix 2024-02-15 06:29:56 -08:00
18 changed files with 117 additions and 50 deletions

View file

@ -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
}
@ -112,7 +105,8 @@ impl Runtime {
ModuleSource::SourceText(source) => {
let source: Rc<str> = 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() {

View file

@ -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();

View file

@ -23,28 +23,36 @@ use std::{
// that will have to wait for now
#[derive(Clone, PartialEq, Eq)]
pub struct Error {
pub file: Rc<str>,
pub start: (usize, usize),
pub end: (usize, usize),
pub message: String,
}
impl Error {
pub fn new<T>(line: usize, column: usize, message: T) -> Self
pub fn new<T>(file: Rc<str>, 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<T>(start: (usize, usize), end: (usize, usize), message: T) -> Self
pub fn new_spanned<T>(
file: Rc<str>,
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
)
}
}
@ -163,7 +175,7 @@ pub enum Type {
Alternate(Box<[Type]>),
// A module of some kind. What module?
Module(ImportRecord),
Module(Rc<str>, ImportRecord),
}
impl Type {
@ -258,7 +270,7 @@ impl fmt::Display for Type {
}
Ok(())
}
Module(name) => write!(f, "module {}", name.name),
Module(name, _) => write!(f, "module {}", name),
}
}
}
@ -622,6 +634,7 @@ enum Incremental<T> {
}
pub struct Semantics {
file: Rc<str>,
source: Rc<str>,
syntax_tree: Rc<SyntaxTree>,
lines: Rc<Lines>,
@ -641,7 +654,7 @@ pub struct Semantics {
}
impl Semantics {
pub fn new(source: Rc<str>, tree: Rc<SyntaxTree>, lines: Rc<Lines>) -> Self {
pub fn new(file: Rc<str>, source: Rc<str>, tree: Rc<SyntaxTree>, lines: Rc<Lines>) -> 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<T>(&self, tree: &Tree, error: T)
@ -2245,9 +2262,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 +2422,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 +2561,9 @@ pub fn check(s: &Semantics) {
TreeKind::Import => {
let _ = s.type_of(t);
}
TreeKind::Export => {}
TreeKind::ExportList => {}
}
}
}
@ -2783,7 +2818,7 @@ mod tests {
pub fn ice() {
let source: Rc<str> = "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");
}
}

View file

@ -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!(

View file

@ -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

View file

@ -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`

View file

@ -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)
// | __test__:4:6: cannot apply binary operator '+' to expressions of type 'class Foo' (on the left) and 'f64' (on the right)

View file

@ -4,4 +4,4 @@ class Foo {
}
// @expect-errors:
// | 3:2: duplicate definition of field 'x'
// | __test__:3:2: duplicate definition of field 'x'

View file

@ -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

View file

@ -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'

View file

@ -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'
// | __test__:3:2: duplicate definition of function 'foo'
// | __test__:8:0: duplicate definition of function 'nested'
// | __test__:11:0: duplicate definition of class 'Bar'

View file

@ -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

View file

@ -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

View file

@ -9,4 +9,4 @@ fun foo() -> f64 {
}
// @expect-errors:
// | 8:2: cannot find value y here
// | __test__:8:2: cannot find value y here

View file

@ -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

View file

@ -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'
// | __test__:3:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string'

View file

@ -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

View file

@ -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