Compare commits
No commits in common. "1199646e29ded4d14212576918932a0bce35ab4e" and "a3ae4339cffe03f760efd193801d61da7e3126c8" have entirely different histories.
1199646e29
...
a3ae4339cf
18 changed files with 50 additions and 117 deletions
|
|
@ -41,10 +41,17 @@ impl ModuleLoader for StandardModuleLoader {
|
||||||
let result = match std::fs::canonicalize(&p) {
|
let result = match std::fs::canonicalize(&p) {
|
||||||
Ok(p) => match p.into_os_string().into_string() {
|
Ok(p) => match p.into_os_string().into_string() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_e) => name.clone(),
|
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()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
eprintln!("**** {source} {name} => {result}");
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,8 +112,7 @@ impl Runtime {
|
||||||
ModuleSource::SourceText(source) => {
|
ModuleSource::SourceText(source) => {
|
||||||
let source: Rc<str> = source.into();
|
let source: Rc<str> = source.into();
|
||||||
let (tree, lines) = parse(&source);
|
let (tree, lines) = parse(&source);
|
||||||
let semantics =
|
let semantics = Rc::new(Semantics::new(source, tree, lines));
|
||||||
Rc::new(Semantics::new(name.clone().into(), source, tree, lines));
|
|
||||||
|
|
||||||
let mut normalized_imports = Vec::new();
|
let mut normalized_imports = Vec::new();
|
||||||
for import in semantics.imports() {
|
for import in semantics.imports() {
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,6 @@ pub enum TreeKind {
|
||||||
WildcardPattern,
|
WildcardPattern,
|
||||||
|
|
||||||
Import,
|
Import,
|
||||||
Export,
|
|
||||||
ExportList,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tree {
|
pub struct Tree {
|
||||||
|
|
@ -578,7 +576,6 @@ fn file(p: &mut CParser) {
|
||||||
match p.peek() {
|
match p.peek() {
|
||||||
TokenKind::Import => import(p),
|
TokenKind::Import => import(p),
|
||||||
TokenKind::Class => class(p),
|
TokenKind::Class => class(p),
|
||||||
TokenKind::Export => export(p),
|
|
||||||
TokenKind::RightBrace => {
|
TokenKind::RightBrace => {
|
||||||
// An error parsing mismatched braces can leave me at an
|
// An error parsing mismatched braces can leave me at an
|
||||||
// un-balanced right brace, which unfortunately will not be
|
// un-balanced right brace, which unfortunately will not be
|
||||||
|
|
@ -639,36 +636,6 @@ fn import(p: &mut CParser) {
|
||||||
p.end(m, TreeKind::Import);
|
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) {
|
fn class(p: &mut CParser) {
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,36 +23,28 @@ use std::{
|
||||||
// that will have to wait for now
|
// that will have to wait for now
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
pub file: Rc<str>,
|
|
||||||
pub start: (usize, usize),
|
pub start: (usize, usize),
|
||||||
pub end: (usize, usize),
|
pub end: (usize, usize),
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
pub fn new<T>(file: Rc<str>, line: usize, column: usize, message: T) -> Self
|
pub fn new<T>(line: usize, column: usize, message: T) -> Self
|
||||||
where
|
where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
Error {
|
Error {
|
||||||
file,
|
|
||||||
start: (line, column),
|
start: (line, column),
|
||||||
end: (line, column),
|
end: (line, column),
|
||||||
message: message.to_string(),
|
message: message.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_spanned<T>(
|
pub fn new_spanned<T>(start: (usize, usize), end: (usize, usize), message: T) -> Self
|
||||||
file: Rc<str>,
|
|
||||||
start: (usize, usize),
|
|
||||||
end: (usize, usize),
|
|
||||||
message: T,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
Error {
|
Error {
|
||||||
file,
|
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
message: message.to_string(),
|
message: message.to_string(),
|
||||||
|
|
@ -68,11 +60,7 @@ impl fmt::Debug for Error {
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(f, "{}:{}: {}", self.start.0, self.start.1, self.message)
|
||||||
f,
|
|
||||||
"{}:{}:{}: {}",
|
|
||||||
self.file, self.start.0, self.start.1, self.message
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,7 +163,7 @@ pub enum Type {
|
||||||
Alternate(Box<[Type]>),
|
Alternate(Box<[Type]>),
|
||||||
|
|
||||||
// A module of some kind. What module?
|
// A module of some kind. What module?
|
||||||
Module(Rc<str>, ImportRecord),
|
Module(ImportRecord),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
|
|
@ -270,7 +258,7 @@ impl fmt::Display for Type {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Module(name, _) => write!(f, "module {}", name),
|
Module(name) => write!(f, "module {}", name.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -634,7 +622,6 @@ enum Incremental<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Semantics {
|
pub struct Semantics {
|
||||||
file: Rc<str>,
|
|
||||||
source: Rc<str>,
|
source: Rc<str>,
|
||||||
syntax_tree: Rc<SyntaxTree>,
|
syntax_tree: Rc<SyntaxTree>,
|
||||||
lines: Rc<Lines>,
|
lines: Rc<Lines>,
|
||||||
|
|
@ -654,7 +641,7 @@ pub struct Semantics {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Semantics {
|
impl Semantics {
|
||||||
pub fn new(file: Rc<str>, source: Rc<str>, tree: Rc<SyntaxTree>, lines: Rc<Lines>) -> Self {
|
pub fn new(source: Rc<str>, tree: Rc<SyntaxTree>, lines: Rc<Lines>) -> Self {
|
||||||
let mut logical_parents = vec![None; tree.len()];
|
let mut logical_parents = vec![None; tree.len()];
|
||||||
if let Some(root) = tree.root() {
|
if let Some(root) = tree.root() {
|
||||||
set_logical_parents(&mut logical_parents, &tree, root, None);
|
set_logical_parents(&mut logical_parents, &tree, root, None);
|
||||||
|
|
@ -663,7 +650,6 @@ impl Semantics {
|
||||||
let root_environment = Environment::new(None, Location::Module);
|
let root_environment = Environment::new(None, Location::Module);
|
||||||
|
|
||||||
let mut semantics = Semantics {
|
let mut semantics = Semantics {
|
||||||
file,
|
|
||||||
source,
|
source,
|
||||||
syntax_tree: tree.clone(),
|
syntax_tree: tree.clone(),
|
||||||
lines,
|
lines,
|
||||||
|
|
@ -744,12 +730,9 @@ impl Semantics {
|
||||||
{
|
{
|
||||||
let start = self.lines.position(start);
|
let start = self.lines.position(start);
|
||||||
let end = self.lines.position(end);
|
let end = self.lines.position(end);
|
||||||
self.errors.borrow_mut().push(Error::new_spanned(
|
self.errors
|
||||||
self.file.clone(),
|
.borrow_mut()
|
||||||
start,
|
.push(Error::new_spanned(start, end, error.to_string()));
|
||||||
end,
|
|
||||||
error.to_string(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_error_tree<T>(&self, tree: &Tree, error: T)
|
fn report_error_tree<T>(&self, tree: &Tree, error: T)
|
||||||
|
|
@ -2262,9 +2245,9 @@ impl Semantics {
|
||||||
self.internal_compiler_error(None, "import map not initialized");
|
self.internal_compiler_error(None, "import map not initialized");
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = string_constant_to_string(tok.as_str(&self.source));
|
let name = tok.as_str(&self.source);
|
||||||
match import_map.get(&name) {
|
match import_map.get(name) {
|
||||||
Some(import) => Some(Type::Module(name.into(), import.clone())),
|
Some(import) => Some(Type::Module(import.clone())),
|
||||||
None => {
|
None => {
|
||||||
self.report_error_tree(tree, format!("unable to resolve module import {name}"));
|
self.report_error_tree(tree, format!("unable to resolve module import {name}"));
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
|
|
@ -2422,21 +2405,6 @@ 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 {
|
if let Some(tr) = tr {
|
||||||
eprintln!("This is about the tree: {:?}", &self.syntax_tree[tr]);
|
eprintln!("This is about the tree: {:?}", &self.syntax_tree[tr]);
|
||||||
eprintln!("The logical parent chain of the tree was:\n");
|
eprintln!("The logical parent chain of the tree was:\n");
|
||||||
|
|
@ -2561,9 +2529,6 @@ pub fn check(s: &Semantics) {
|
||||||
TreeKind::Import => {
|
TreeKind::Import => {
|
||||||
let _ = s.type_of(t);
|
let _ = s.type_of(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeKind::Export => {}
|
|
||||||
TreeKind::ExportList => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2818,7 +2783,7 @@ mod tests {
|
||||||
pub fn ice() {
|
pub fn ice() {
|
||||||
let source: Rc<str> = "1+1".into();
|
let source: Rc<str> = "1+1".into();
|
||||||
let (tree, lines) = parse(&source);
|
let (tree, lines) = parse(&source);
|
||||||
let semantics = Semantics::new("__test__".into(), source, tree.clone(), lines);
|
let semantics = Semantics::new(source, tree.clone(), lines);
|
||||||
semantics.internal_compiler_error(tree.root(), "oh no");
|
semantics.internal_compiler_error(tree.root(), "oh no");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ pub enum TokenKind {
|
||||||
Await,
|
Await,
|
||||||
Class,
|
Class,
|
||||||
Else,
|
Else,
|
||||||
Export,
|
|
||||||
False,
|
False,
|
||||||
For,
|
For,
|
||||||
From,
|
From,
|
||||||
|
|
@ -295,9 +294,6 @@ impl<'a> Tokens<'a> {
|
||||||
if ident == "else" {
|
if ident == "else" {
|
||||||
return TokenKind::Else;
|
return TokenKind::Else;
|
||||||
}
|
}
|
||||||
if ident == "export" {
|
|
||||||
return TokenKind::Export;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
'f' => {
|
'f' => {
|
||||||
if ident == "false" {
|
if ident == "false" {
|
||||||
|
|
@ -643,13 +639,12 @@ mod tests {
|
||||||
|
|
||||||
test_tokens!(
|
test_tokens!(
|
||||||
more_more_keywords,
|
more_more_keywords,
|
||||||
"in is match _ as export",
|
"in is match _ as",
|
||||||
(0, In, "in"),
|
(0, In, "in"),
|
||||||
(3, Is, "is"),
|
(3, Is, "is"),
|
||||||
(6, Match, "match"),
|
(6, Match, "match"),
|
||||||
(12, Underscore, "_"),
|
(12, Underscore, "_"),
|
||||||
(14, As, "as"),
|
(14, As, "as")
|
||||||
(17, Export, "export")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test_tokens!(
|
test_tokens!(
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ fun wrong() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:7:4: cannot assign a value of type 'string' to type 'f64'
|
// | 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'
|
// | 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'
|
// | 11:4: cannot assign a value of type 'f64' to type 'string'
|
||||||
// | __test__:13:2: cannot assign a new value to a function declaration
|
// | 13:2: cannot assign a new value to a function declaration
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ fun test() {
|
||||||
|
|
||||||
// NOTE: These errors should be better
|
// NOTE: These errors should be better
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:2:10: Error at 'true': expected a block after `if`
|
// | 2:10: Error at 'true': expected a block after `if`
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ fun test() -> f64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:4:6: cannot apply binary operator '+' to expressions of type 'class Foo' (on the left) and 'f64' (on the right)
|
// | 4:6: cannot apply binary operator '+' to expressions of type 'class Foo' (on the left) and 'f64' (on the right)
|
||||||
|
|
@ -4,4 +4,4 @@ class Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:3:2: duplicate definition of field 'x'
|
// | 3:2: duplicate definition of field 'x'
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@ fun test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:7:12: missing an initializer for field y
|
// | 7:12: missing an initializer for field y
|
||||||
// | __test__:8:12: missing an initializer for field x
|
// | 8:12: missing an initializer for field x
|
||||||
// | __test__:9:41: Point instance does not have a field named z
|
// | 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
|
// | 10:32: field x is of type f64, but this expression generates a string
|
||||||
// | __test__:12:32: cannot find value x here
|
// | 12:32: cannot find value x here
|
||||||
// | __test__:15:31: field x is of type f64, but this expression generates a string
|
// | 15:31: field x is of type f64, but this expression generates a string
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
fun something(x: f64, x: f64) {}
|
fun something(x: f64, x: f64) {}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:1:22: duplicate definition of parameter 'x'
|
// | 1:22: duplicate definition of parameter 'x'
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ class Bar {}
|
||||||
class Bar {}
|
class Bar {}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:3:2: duplicate definition of function 'foo'
|
// | 3:2: duplicate definition of function 'foo'
|
||||||
// | __test__:8:0: duplicate definition of function 'nested'
|
// | 8:0: duplicate definition of function 'nested'
|
||||||
// | __test__:11:0: duplicate definition of class 'Bar'
|
// | 11:0: duplicate definition of class 'Bar'
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if 23 { "what" } else { "the" }
|
if 23 { "what" } else { "the" }
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:1:3: this condition produces 'f64', but must produce bool
|
// | 1:3: this condition produces 'f64', but must produce bool
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if (if false { true }) { 32 } else { 23 }
|
if (if false { true }) { 32 } else { 23 }
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:1:3: this condition produces 'nothing or bool', but must produce bool
|
// | 1:3: this condition produces 'nothing or bool', but must produce bool
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,4 @@ fun foo() -> f64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:8:2: cannot find value y here
|
// | 8:2: cannot find value y here
|
||||||
|
|
@ -8,4 +8,4 @@ fun test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:7:6: methods cannot be assigned to variables
|
// | 7:6: methods cannot be assigned to variables
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,4 @@ fun test() -> f64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:3:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string'
|
// | 3:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string'
|
||||||
|
|
@ -3,4 +3,4 @@ fun test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:2:8: this condition produces 'f64', but must produce bool
|
// | 2:8: this condition produces 'f64', but must produce bool
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,5 @@ fun test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | __test__:7:12: Error at '{': expected an identifier after a '.' in member access
|
// | 7:12: Error at '{': expected an identifier after a '.' in member access
|
||||||
// | __test__:7:26: cannot find value foo here
|
// | 7:26: cannot find value foo here
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue