[fine] Imports maybe
Feels a little sketchy
This commit is contained in:
parent
1199646e29
commit
60e8f64c01
4 changed files with 299 additions and 85 deletions
|
|
@ -582,7 +582,8 @@ fn compile_binary_expression(c: &mut Compiler, t: TreeRef, tr: &Tree) -> CR {
|
||||||
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
|
Declaration::ExternFunction { .. } => inst_panic!("store ext"),
|
||||||
Declaration::Function { .. } => inst_panic!("store func"),
|
Declaration::Function { .. } => inst_panic!("store func"),
|
||||||
Declaration::Class { .. } => inst_panic!("store class"),
|
Declaration::Class { .. } => inst_panic!("store class"),
|
||||||
Declaration::Import { .. } => inst_panic!("store import"),
|
Declaration::ImportedModule { .. } => inst_panic!("store import"),
|
||||||
|
Declaration::ImportedDeclaration { .. } => inst_panic!("store import decl"),
|
||||||
};
|
};
|
||||||
c.push(instruction);
|
c.push(instruction);
|
||||||
OK
|
OK
|
||||||
|
|
@ -662,7 +663,8 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
|
||||||
Declaration::Class { .. } => return OK,
|
Declaration::Class { .. } => return OK,
|
||||||
|
|
||||||
// fix later
|
// fix later
|
||||||
Declaration::Import { .. } => ice!(c, t, "import compile not supported"),
|
Declaration::ImportedModule { .. } => ice!(c, t, "import compile not supported"),
|
||||||
|
Declaration::ImportedDeclaration { .. } => ice!(c, t, "import decl not supported"),
|
||||||
};
|
};
|
||||||
|
|
||||||
c.push(instruction);
|
c.push(instruction);
|
||||||
|
|
@ -874,11 +876,12 @@ fn compile_argument(c: &mut Compiler, tree: &Tree) -> CR {
|
||||||
|
|
||||||
fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
fn compile_new_object_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
// We pass in the arguments.... by... field order?
|
// We pass in the arguments.... by... field order?
|
||||||
let Type::Object(ct, _) = c.semantics.type_of(t) else {
|
let Type::Object(mid, ct, _) = c.semantics.type_of(t) else {
|
||||||
c.push(inst_panic!("new obj not ob"));
|
c.push(inst_panic!("new obj not ob"));
|
||||||
return OK;
|
return OK;
|
||||||
};
|
};
|
||||||
let class = c.semantics.class_of(ct);
|
|
||||||
|
let class = c.semantics.class_of(mid, ct);
|
||||||
|
|
||||||
let field_list = tree.child_tree_of_kind(&c.syntax, TreeKind::FieldList)?;
|
let field_list = tree.child_tree_of_kind(&c.syntax, TreeKind::FieldList)?;
|
||||||
let mut field_bindings = HashMap::new();
|
let mut field_bindings = HashMap::new();
|
||||||
|
|
@ -951,12 +954,12 @@ fn compile_member_access(c: &mut Compiler, t: TreeRef, tree: &Tree) -> CR {
|
||||||
let ident = tree.nth_token(2)?.as_str(&c.source);
|
let ident = tree.nth_token(2)?.as_str(&c.source);
|
||||||
|
|
||||||
let environment = match &typ {
|
let environment = match &typ {
|
||||||
Type::Object(ct, _) => {
|
Type::Object(mid, ct, _) => {
|
||||||
let class = c.semantics.class_of(*ct);
|
let class = c.semantics.class_of(*mid, *ct);
|
||||||
class.env.clone()
|
class.env.clone()
|
||||||
}
|
}
|
||||||
Type::Class(ct, _) => {
|
Type::Class(mid, ct, _) => {
|
||||||
let class = c.semantics.class_of(*ct);
|
let class = c.semantics.class_of(*mid, *ct);
|
||||||
class.static_env.clone()
|
class.static_env.clone()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, fs, path::PathBuf, rc::Rc};
|
||||||
|
|
||||||
use compiler::compile;
|
use compiler::compile;
|
||||||
use parser::parse;
|
use parser::parse;
|
||||||
use semantics::{check, Error, ImportRecord, Semantics};
|
use semantics::{check, Error, ImportRecord, ModuleId, Semantics};
|
||||||
use vm::{eval, Context};
|
use vm::{eval, Context};
|
||||||
|
|
||||||
pub mod compiler;
|
pub mod compiler;
|
||||||
|
|
@ -57,12 +57,12 @@ impl ModuleLoader for StandardModuleLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
id: u64,
|
id: ModuleId,
|
||||||
semantics: Rc<Semantics>,
|
semantics: Rc<Semantics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn id(&self) -> u64 {
|
pub fn id(&self) -> ModuleId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,10 +103,18 @@ impl Runtime {
|
||||||
// TODO: Errors here are bad! Remember, run everything!
|
// TODO: Errors here are bad! Remember, run everything!
|
||||||
match self.loader.load_module(&name)? {
|
match self.loader.load_module(&name)? {
|
||||||
ModuleSource::SourceText(source) => {
|
ModuleSource::SourceText(source) => {
|
||||||
|
let mid = ModuleId::from(id_assign);
|
||||||
|
id_assign += 1;
|
||||||
|
|
||||||
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(
|
||||||
Rc::new(Semantics::new(name.clone().into(), source, tree, lines));
|
mid,
|
||||||
|
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() {
|
||||||
|
|
@ -116,8 +124,7 @@ impl Runtime {
|
||||||
normalized_imports.push((import, normalized));
|
normalized_imports.push((import, normalized));
|
||||||
}
|
}
|
||||||
|
|
||||||
init_pending.insert(name, (id_assign, normalized_imports, semantics));
|
init_pending.insert(name, (mid, normalized_imports, semantics));
|
||||||
id_assign += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,10 +116,19 @@ impl std::ops::Deref for ClassRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub struct ModuleId(u64);
|
||||||
|
|
||||||
|
impl From<u64> for ModuleId {
|
||||||
|
fn from(value: u64) -> Self {
|
||||||
|
ModuleId(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ImportRecord {
|
pub struct ImportRecord {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub module_id: u64,
|
pub module_id: ModuleId,
|
||||||
pub semantics: Weak<Semantics>,
|
pub semantics: Weak<Semantics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,12 +173,12 @@ pub enum Type {
|
||||||
|
|
||||||
// A class is the static type of a class; when the class is referred to
|
// A class is the static type of a class; when the class is referred to
|
||||||
// by name it has this type. (Distinct from an instance!)
|
// by name it has this type. (Distinct from an instance!)
|
||||||
Class(TreeRef, Rc<str>),
|
Class(ModuleId, TreeRef, Rc<str>),
|
||||||
|
|
||||||
// An object is the type of an allocated object instance. Details of its
|
// An object is the type of an allocated object instance. Details of its
|
||||||
// class need to be fetched explicitly from the semantics via the
|
// class need to be fetched explicitly from the semantics via the
|
||||||
// TreeRef and `Semantics::class_of`; they are computed lazily.
|
// TreeRef and `Semantics::class_of`; they are computed lazily.
|
||||||
Object(TreeRef, Rc<str>),
|
Object(ModuleId, TreeRef, Rc<str>),
|
||||||
|
|
||||||
// An alternate is one or another type.
|
// An alternate is one or another type.
|
||||||
Alternate(Box<[Type]>),
|
Alternate(Box<[Type]>),
|
||||||
|
|
@ -257,8 +266,8 @@ impl fmt::Display for Type {
|
||||||
write!(f, "$_")
|
write!(f, "$_")
|
||||||
}
|
}
|
||||||
List(t) => write!(f, "list<{t}>"),
|
List(t) => write!(f, "list<{t}>"),
|
||||||
Object(_, name) => write!(f, "{} instance", name),
|
Object(_, _, name) => write!(f, "{} instance", name),
|
||||||
Class(_, name) => write!(f, "class {}", name),
|
Class(_, _, name) => write!(f, "class {}", name),
|
||||||
Alternate(ts) => {
|
Alternate(ts) => {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for t in ts.iter() {
|
for t in ts.iter() {
|
||||||
|
|
@ -318,8 +327,12 @@ impl std::cmp::Ord for Type {
|
||||||
lv.cmp(&rv)
|
lv.cmp(&rv)
|
||||||
}
|
}
|
||||||
(Type::List(x), Type::List(y)) => x.cmp(y),
|
(Type::List(x), Type::List(y)) => x.cmp(y),
|
||||||
(Type::Class(lt, _), Type::Class(rt, _)) => lt.index().cmp(&rt.index()),
|
(Type::Class(lm, lt, _), Type::Class(rm, rt, _)) => {
|
||||||
(Type::Object(lt, _), Type::Object(rt, _)) => lt.index().cmp(&rt.index()),
|
(lm.0, lt.index()).cmp(&(rm.0, rt.index()))
|
||||||
|
}
|
||||||
|
(Type::Object(lm, lt, _), Type::Object(rm, rt, _)) => {
|
||||||
|
(lm.0, lt.index()).cmp(&(rm.0, rt.index()))
|
||||||
|
}
|
||||||
(Type::Alternate(ll), Type::Alternate(rr)) => ll.cmp(rr),
|
(Type::Alternate(ll), Type::Alternate(rr)) => ll.cmp(rr),
|
||||||
|
|
||||||
_ => Ordering::Equal,
|
_ => Ordering::Equal,
|
||||||
|
|
@ -353,9 +366,11 @@ pub enum Declaration {
|
||||||
declaration: TreeRef,
|
declaration: TreeRef,
|
||||||
location: Location,
|
location: Location,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
exported: bool,
|
||||||
},
|
},
|
||||||
Function {
|
Function {
|
||||||
declaration: TreeRef, //?
|
declaration: TreeRef, //?
|
||||||
|
exported: bool,
|
||||||
},
|
},
|
||||||
ExternFunction {
|
ExternFunction {
|
||||||
declaration_type: Type,
|
declaration_type: Type,
|
||||||
|
|
@ -363,10 +378,52 @@ pub enum Declaration {
|
||||||
},
|
},
|
||||||
Class {
|
Class {
|
||||||
declaration: TreeRef, //?
|
declaration: TreeRef, //?
|
||||||
|
exported: bool,
|
||||||
},
|
},
|
||||||
Import {
|
ImportedModule {
|
||||||
declaration: TreeRef,
|
declaration: TreeRef,
|
||||||
|
exported: bool,
|
||||||
},
|
},
|
||||||
|
ImportedDeclaration {
|
||||||
|
semantics: Weak<Semantics>,
|
||||||
|
tree: Option<TreeRef>,
|
||||||
|
declaration: Box<Declaration>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Declaration {
|
||||||
|
pub fn is_exported(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Declaration::Variable { exported, .. } => *exported,
|
||||||
|
Declaration::Function { exported, .. } => *exported,
|
||||||
|
Declaration::ExternFunction { .. } => true,
|
||||||
|
Declaration::Class { exported, .. } => *exported,
|
||||||
|
Declaration::ImportedModule { exported, .. } => *exported,
|
||||||
|
Declaration::ImportedDeclaration { .. } => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tree(&self) -> Option<TreeRef> {
|
||||||
|
match self {
|
||||||
|
Declaration::Variable { declaration, .. } => Some(*declaration),
|
||||||
|
Declaration::Function { declaration, .. } => Some(*declaration),
|
||||||
|
Declaration::ExternFunction { .. } => None,
|
||||||
|
Declaration::Class { declaration, .. } => Some(*declaration),
|
||||||
|
Declaration::ImportedModule { declaration, .. } => Some(*declaration),
|
||||||
|
Declaration::ImportedDeclaration { tree, .. } => *tree,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_exported(&mut self) {
|
||||||
|
match self {
|
||||||
|
Declaration::Variable { exported, .. } => *exported = true,
|
||||||
|
Declaration::Function { exported, .. } => *exported = true,
|
||||||
|
Declaration::ExternFunction { .. } => (),
|
||||||
|
Declaration::Class { exported, .. } => *exported = true,
|
||||||
|
Declaration::ImportedModule { exported, .. } => *exported = true,
|
||||||
|
Declaration::ImportedDeclaration { .. } => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
|
|
@ -426,6 +483,7 @@ impl Environment {
|
||||||
declaration: t,
|
declaration: t,
|
||||||
location: self.location,
|
location: self.location,
|
||||||
index: self.next_index,
|
index: self.next_index,
|
||||||
|
exported: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.next_index += 1;
|
self.next_index += 1;
|
||||||
|
|
@ -634,6 +692,7 @@ enum Incremental<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Semantics {
|
pub struct Semantics {
|
||||||
|
mid: ModuleId,
|
||||||
file: Rc<str>,
|
file: Rc<str>,
|
||||||
source: Rc<str>,
|
source: Rc<str>,
|
||||||
syntax_tree: Rc<SyntaxTree>,
|
syntax_tree: Rc<SyntaxTree>,
|
||||||
|
|
@ -654,7 +713,13 @@ 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(
|
||||||
|
mid: ModuleId,
|
||||||
|
file: Rc<str>,
|
||||||
|
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,6 +728,7 @@ 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 {
|
||||||
|
mid,
|
||||||
file,
|
file,
|
||||||
source,
|
source,
|
||||||
syntax_tree: tree.clone(),
|
syntax_tree: tree.clone(),
|
||||||
|
|
@ -842,7 +908,10 @@ impl Semantics {
|
||||||
|
|
||||||
let existing = environment.declarations.insert(
|
let existing = environment.declarations.insert(
|
||||||
name.as_str(&self.source).into(),
|
name.as_str(&self.source).into(),
|
||||||
Declaration::Function { declaration: *t },
|
Declaration::Function {
|
||||||
|
declaration: *t,
|
||||||
|
exported: false,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
if existing.is_some() {
|
if existing.is_some() {
|
||||||
self.report_error_tree(
|
self.report_error_tree(
|
||||||
|
|
@ -865,49 +934,89 @@ impl Semantics {
|
||||||
fn environment_of_file(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
|
fn environment_of_file(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
|
||||||
let mut environment = Environment::new(Some(parent), Location::Module);
|
let mut environment = Environment::new(Some(parent), Location::Module);
|
||||||
|
|
||||||
|
let mut explicit_exports = Vec::new();
|
||||||
|
|
||||||
for child in tree.children.iter() {
|
for child in tree.children.iter() {
|
||||||
let Child::Tree(t) = child else {
|
let Child::Tree(t) = child else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let ct = &self.syntax_tree[*t];
|
let binding = {
|
||||||
let binding = match ct.kind {
|
// Redeclare t to be mutable (and a copy)
|
||||||
|
let mut t = *t;
|
||||||
|
let mut exported = false;
|
||||||
|
|
||||||
|
// Loop here in order to dereference TreeKind::Export;
|
||||||
|
// children of an export tree still go in the local
|
||||||
|
// environment.
|
||||||
|
loop {
|
||||||
|
let ct = &self.syntax_tree[t];
|
||||||
|
match ct.kind {
|
||||||
TreeKind::FunctionDecl => {
|
TreeKind::FunctionDecl => {
|
||||||
let Some(name) = ct.nth_token(1) else {
|
let Some(name) = ct.nth_token(1) else {
|
||||||
continue;
|
break None;
|
||||||
};
|
};
|
||||||
if name.kind != TokenKind::Identifier {
|
if name.kind != TokenKind::Identifier {
|
||||||
continue;
|
break None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let declaration = Declaration::Function { declaration: *t };
|
let declaration = Declaration::Function {
|
||||||
Some(("function", name, declaration))
|
declaration: t,
|
||||||
|
exported,
|
||||||
|
};
|
||||||
|
break Some(("function", name, declaration));
|
||||||
}
|
}
|
||||||
TreeKind::ClassDecl => {
|
TreeKind::ClassDecl => {
|
||||||
let Some(name) = ct.nth_token(1) else {
|
let Some(name) = ct.nth_token(1) else {
|
||||||
continue;
|
break None;
|
||||||
};
|
};
|
||||||
if name.kind != TokenKind::Identifier {
|
if name.kind != TokenKind::Identifier {
|
||||||
continue;
|
break None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let declaration = Declaration::Class { declaration: *t };
|
let declaration = Declaration::Class {
|
||||||
Some(("class", name, declaration))
|
declaration: t,
|
||||||
|
exported,
|
||||||
|
};
|
||||||
|
break Some(("class", name, declaration));
|
||||||
}
|
}
|
||||||
TreeKind::Import => {
|
TreeKind::Import => {
|
||||||
let Some(name) = ct.nth_token(3) else {
|
let Some(name) = ct.nth_token(3) else {
|
||||||
continue;
|
break None;
|
||||||
};
|
};
|
||||||
if name.kind != TokenKind::Identifier {
|
if name.kind != TokenKind::Identifier {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let declaration = Declaration::ImportedModule {
|
||||||
|
declaration: t,
|
||||||
|
exported,
|
||||||
|
};
|
||||||
|
break Some(("import", name, declaration));
|
||||||
|
}
|
||||||
|
TreeKind::Export => {
|
||||||
|
let Some(inner) = ct.nth_tree(1) else {
|
||||||
|
break None;
|
||||||
|
};
|
||||||
|
t = inner;
|
||||||
|
exported = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
TreeKind::ExportList => {
|
||||||
let declaration = Declaration::Import { declaration: *t };
|
for child in &ct.children {
|
||||||
Some(("import", name, declaration))
|
if let Child::Token(tok) = child {
|
||||||
|
if tok.kind == TokenKind::Identifier {
|
||||||
|
explicit_exports.push(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => break None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ct = &self.syntax_tree[*t];
|
||||||
if let Some((what, name, declaration)) = binding {
|
if let Some((what, name, declaration)) = binding {
|
||||||
let existing = environment
|
let existing = environment
|
||||||
.declarations
|
.declarations
|
||||||
|
|
@ -924,6 +1033,14 @@ impl Semantics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for tok in explicit_exports {
|
||||||
|
environment
|
||||||
|
.declarations
|
||||||
|
.get_mut(tok.as_str(&self.source))
|
||||||
|
// NOTE: If not present, we report the error elsewhere.
|
||||||
|
.map(|decl| decl.set_exported());
|
||||||
|
}
|
||||||
|
|
||||||
EnvironmentRef::new(environment)
|
EnvironmentRef::new(environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1113,7 +1230,23 @@ impl Semantics {
|
||||||
EnvironmentRef::new(env)
|
EnvironmentRef::new(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_of(&self, t: TreeRef) -> ClassRef {
|
pub fn class_of(&self, mid: ModuleId, t: TreeRef) -> ClassRef {
|
||||||
|
if mid != self.mid {
|
||||||
|
let weak_semantics = self
|
||||||
|
.import_map
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|(_, v)| v.module_id == mid)
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.semantics
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let other_semantics = weak_semantics.upgrade().unwrap();
|
||||||
|
return other_semantics.class_of(mid, t);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// I want to make sure that this borrow is dropped after this block.
|
// I want to make sure that this borrow is dropped after this block.
|
||||||
let mut borrow = self.classes.borrow_mut();
|
let mut borrow = self.classes.borrow_mut();
|
||||||
|
|
@ -1194,6 +1327,7 @@ impl Semantics {
|
||||||
index,
|
index,
|
||||||
declaration: field.declaration,
|
declaration: field.declaration,
|
||||||
location: Location::Slot,
|
location: Location::Slot,
|
||||||
|
exported: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1203,6 +1337,7 @@ impl Semantics {
|
||||||
(&*method.name).into(),
|
(&*method.name).into(),
|
||||||
Declaration::Function {
|
Declaration::Function {
|
||||||
declaration: method.declaration,
|
declaration: method.declaration,
|
||||||
|
exported: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1210,6 +1345,7 @@ impl Semantics {
|
||||||
(&*method.name).into(),
|
(&*method.name).into(),
|
||||||
Declaration::Function {
|
Declaration::Function {
|
||||||
declaration: method.declaration,
|
declaration: method.declaration,
|
||||||
|
exported: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
@ -1281,12 +1417,12 @@ impl Semantics {
|
||||||
.all(|(from, to)| self.can_convert(from, to))
|
.all(|(from, to)| self.can_convert(from, to))
|
||||||
}
|
}
|
||||||
|
|
||||||
(Type::Object(c_from, _), Type::Object(c_to, _)) => {
|
(Type::Object(m_from, c_from, _), Type::Object(m_to, c_to, _)) => {
|
||||||
// TODO: Structural comparisons. All that matters is that
|
// TODO: Structural comparisons. All that matters is that
|
||||||
// c_to has a subset of fields and methods, and the
|
// c_to has a subset of fields and methods, and the
|
||||||
// fields and methods are all compatible.
|
// fields and methods are all compatible.
|
||||||
//
|
//
|
||||||
c_from == c_to
|
m_from == m_to && c_from == c_to
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid introducing more errors
|
// Avoid introducing more errors
|
||||||
|
|
@ -1578,13 +1714,20 @@ impl Semantics {
|
||||||
);
|
);
|
||||||
return Some(Type::Error);
|
return Some(Type::Error);
|
||||||
}
|
}
|
||||||
Declaration::Import { .. } => {
|
Declaration::ImportedModule { .. } => {
|
||||||
self.report_error_tree_ref(
|
self.report_error_tree_ref(
|
||||||
left_tree,
|
left_tree,
|
||||||
"cannot assign a new value to an imported module",
|
"cannot assign a new value to an imported module",
|
||||||
);
|
);
|
||||||
return Some(Type::Error);
|
return Some(Type::Error);
|
||||||
}
|
}
|
||||||
|
Declaration::ImportedDeclaration { .. } => {
|
||||||
|
self.report_error_tree_ref(
|
||||||
|
left_tree,
|
||||||
|
"cannot assign a new value to a member of an imported module",
|
||||||
|
);
|
||||||
|
return Some(Type::Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = environment;
|
let _ = environment;
|
||||||
|
|
@ -1659,13 +1802,23 @@ impl Semantics {
|
||||||
);
|
);
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
}
|
}
|
||||||
Some(Declaration::Import { .. }) => {
|
Some(Declaration::ImportedModule { .. }) => {
|
||||||
self.report_error_tree(
|
self.report_error_tree(
|
||||||
tree,
|
tree,
|
||||||
format!("'{token}' is an imported module and cannot be used as a type"),
|
format!("'{token}' is an imported module and cannot be used as a type"),
|
||||||
);
|
);
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
}
|
}
|
||||||
|
Some(Declaration::ImportedDeclaration {
|
||||||
|
semantics,
|
||||||
|
tree,
|
||||||
|
declaration,
|
||||||
|
}) => Some(
|
||||||
|
semantics
|
||||||
|
.upgrade()
|
||||||
|
.unwrap()
|
||||||
|
.type_of_declaration(*tree, declaration),
|
||||||
|
),
|
||||||
None => {
|
None => {
|
||||||
if !environment.is_error {
|
if !environment.is_error {
|
||||||
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
|
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
|
||||||
|
|
@ -1903,23 +2056,50 @@ impl Semantics {
|
||||||
return Some(Type::Error);
|
return Some(Type::Error);
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(self.type_of_declaration(t, declaration))
|
Some(self.type_of_declaration(Some(t), declaration))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn member_environment(&self, t: TreeRef, typ: &Type) -> EnvironmentRef {
|
pub fn member_environment(&self, t: TreeRef, typ: &Type) -> EnvironmentRef {
|
||||||
match &typ {
|
match &typ {
|
||||||
Type::Object(ct, _) => {
|
Type::Object(mid, ct, _) => {
|
||||||
let class = self.class_of(*ct);
|
let class = self.class_of(*mid, *ct);
|
||||||
class.env.clone()
|
class.env.clone()
|
||||||
}
|
}
|
||||||
Type::Class(ct, _) => {
|
Type::Class(mid, ct, _) => {
|
||||||
let class = self.class_of(*ct);
|
let class = self.class_of(*mid, *ct);
|
||||||
class.static_env.clone()
|
class.static_env.clone()
|
||||||
}
|
}
|
||||||
// Type::Module(_name) => {
|
Type::Module(_, import) => {
|
||||||
// // Woof. Would like to bind this now.
|
// TODO: Cache this somehow, man.
|
||||||
// todo!();
|
let Some(other) = import.semantics.upgrade() else {
|
||||||
// }
|
self.internal_compiler_error(Some(t), "Unable to bind module");
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(root) = other.syntax_tree.root() else {
|
||||||
|
self.internal_compiler_error(Some(t), "Other syntax tree has no root");
|
||||||
|
};
|
||||||
|
let rt = &other.syntax_tree[root];
|
||||||
|
assert_eq!(rt.kind, TreeKind::File);
|
||||||
|
|
||||||
|
let mut result = Environment::new(None, Location::Module);
|
||||||
|
let other_env = other.environment_of(root);
|
||||||
|
for (name, decl) in other_env.declarations.iter() {
|
||||||
|
if decl.is_exported() {
|
||||||
|
eprintln!("******* {} is exported!", name);
|
||||||
|
result.declarations.insert(
|
||||||
|
name.clone(),
|
||||||
|
Declaration::ImportedDeclaration {
|
||||||
|
semantics: import.semantics.clone(),
|
||||||
|
tree: decl.tree(),
|
||||||
|
declaration: Box::new(decl.clone()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
eprintln!("******* {} is NOT exported!", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EnvironmentRef::new(result)
|
||||||
|
}
|
||||||
Type::Error => return Environment::error(),
|
Type::Error => return Environment::error(),
|
||||||
_ => {
|
_ => {
|
||||||
self.report_error_tree_ref(t, format!("cannot access members of '{typ}'"));
|
self.report_error_tree_ref(t, format!("cannot access members of '{typ}'"));
|
||||||
|
|
@ -1957,7 +2137,7 @@ impl Semantics {
|
||||||
let id = tree.nth_token(0)?.as_str(&self.source);
|
let id = tree.nth_token(0)?.as_str(&self.source);
|
||||||
let environment = self.environment_of(t);
|
let environment = self.environment_of(t);
|
||||||
if let Some(declaration) = environment.bind(id) {
|
if let Some(declaration) = environment.bind(id) {
|
||||||
return Some(self.type_of_declaration(t, declaration));
|
return Some(self.type_of_declaration(Some(t), declaration));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !environment.is_error {
|
if !environment.is_error {
|
||||||
|
|
@ -1966,18 +2146,26 @@ impl Semantics {
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_of_declaration(&self, t: TreeRef, declaration: &Declaration) -> Type {
|
fn type_of_declaration(&self, t: Option<TreeRef>, declaration: &Declaration) -> Type {
|
||||||
match declaration {
|
match declaration {
|
||||||
Declaration::Variable { declaration, .. } => self.type_of(*declaration),
|
Declaration::Variable { declaration, .. } => self.type_of(*declaration),
|
||||||
Declaration::Function { declaration, .. } => self.type_of(*declaration),
|
Declaration::Function { declaration, .. } => self.type_of(*declaration),
|
||||||
Declaration::Import { declaration, .. } => self.type_of(*declaration),
|
Declaration::ImportedModule { declaration, .. } => self.type_of(*declaration),
|
||||||
Declaration::ExternFunction {
|
Declaration::ExternFunction {
|
||||||
declaration_type, ..
|
declaration_type, ..
|
||||||
} => declaration_type.clone(),
|
} => declaration_type.clone(),
|
||||||
Declaration::Class { declaration, .. } => match self.type_of(*declaration) {
|
Declaration::Class { declaration, .. } => match self.type_of(*declaration) {
|
||||||
Type::Object(cd, name) => Type::Class(cd, name.clone()),
|
Type::Object(mid, cd, name) => Type::Class(mid, cd, name.clone()),
|
||||||
_ => self.internal_compiler_error(Some(t), "bound to a class not understood"),
|
_ => self.internal_compiler_error(t, "bound to a class not understood"),
|
||||||
},
|
},
|
||||||
|
Declaration::ImportedDeclaration {
|
||||||
|
semantics,
|
||||||
|
tree,
|
||||||
|
declaration,
|
||||||
|
} => semantics
|
||||||
|
.upgrade()
|
||||||
|
.unwrap()
|
||||||
|
.type_of_declaration(*tree, declaration),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2126,7 +2314,7 @@ impl Semantics {
|
||||||
// The details of a class are computed lazily, but this is enough of
|
// The details of a class are computed lazily, but this is enough of
|
||||||
// a belly-button.
|
// a belly-button.
|
||||||
let name = tree.nth_token(1)?;
|
let name = tree.nth_token(1)?;
|
||||||
Some(Type::Object(t, name.as_str(&self.source).into()))
|
Some(Type::Object(self.mid, t, name.as_str(&self.source).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_of_field_decl(&self, tree: &Tree) -> Option<Type> {
|
fn type_of_field_decl(&self, tree: &Tree) -> Option<Type> {
|
||||||
|
|
@ -2173,13 +2361,23 @@ impl Semantics {
|
||||||
);
|
);
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
}
|
}
|
||||||
Declaration::Import { .. } => {
|
Declaration::ImportedModule { .. } => {
|
||||||
self.report_error_tree(
|
self.report_error_tree(
|
||||||
tree,
|
tree,
|
||||||
format!("'{id}' is an imported module, and cannot be the value of a field"),
|
format!("'{id}' is an imported module, and cannot be the value of a field"),
|
||||||
);
|
);
|
||||||
Some(Type::Error)
|
Some(Type::Error)
|
||||||
}
|
}
|
||||||
|
Declaration::ImportedDeclaration {
|
||||||
|
semantics,
|
||||||
|
tree,
|
||||||
|
declaration,
|
||||||
|
} => Some(
|
||||||
|
semantics
|
||||||
|
.upgrade()
|
||||||
|
.unwrap()
|
||||||
|
.type_of_declaration(*tree, declaration),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2427,7 +2625,7 @@ impl Semantics {
|
||||||
Some(m) => {
|
Some(m) => {
|
||||||
eprintln!("Import map:");
|
eprintln!("Import map:");
|
||||||
for (k, b) in m.iter() {
|
for (k, b) in m.iter() {
|
||||||
eprintln!(" {k} => {} ({})", b.name, b.module_id);
|
eprintln!(" {k} => {} ({:?})", b.name, b.module_id);
|
||||||
}
|
}
|
||||||
eprintln!();
|
eprintln!();
|
||||||
}
|
}
|
||||||
|
|
@ -2466,9 +2664,12 @@ impl Semantics {
|
||||||
Declaration::Class { declaration, .. } => {
|
Declaration::Class { declaration, .. } => {
|
||||||
eprintln!(" (class {declaration:?})");
|
eprintln!(" (class {declaration:?})");
|
||||||
}
|
}
|
||||||
Declaration::Import { declaration, .. } => {
|
Declaration::ImportedModule { declaration, .. } => {
|
||||||
eprintln!(" (imported module {declaration:?})");
|
eprintln!(" (imported module {declaration:?})");
|
||||||
}
|
}
|
||||||
|
Declaration::ImportedDeclaration { .. } => {
|
||||||
|
eprintln!(" (imported member)");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
environment = env.parent.clone();
|
environment = env.parent.clone();
|
||||||
|
|
@ -2563,7 +2764,9 @@ pub fn check(s: &Semantics) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeKind::Export => {}
|
TreeKind::Export => {}
|
||||||
TreeKind::ExportList => {}
|
TreeKind::ExportList => {
|
||||||
|
// TODO: Check that each name in the list is in the environment
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2686,8 +2889,9 @@ fn check_new_object_expression(s: &Semantics, tree: &Tree) {
|
||||||
|
|
||||||
let class_type = s.type_of(type_expression); // TODO: Should yield a ClassType not an ObjectType?
|
let class_type = s.type_of(type_expression); // TODO: Should yield a ClassType not an ObjectType?
|
||||||
match &class_type {
|
match &class_type {
|
||||||
Type::Object(c, _) => {
|
Type::Object(mid, c, _) => {
|
||||||
let class = s.class_of(*c);
|
// Get the class def from ... place.
|
||||||
|
let class = s.class_of(*mid, *c);
|
||||||
|
|
||||||
let mut any_errors = false;
|
let mut any_errors = false;
|
||||||
let mut field_bindings = HashMap::new();
|
let mut field_bindings = HashMap::new();
|
||||||
|
|
@ -2818,7 +3022,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(ModuleId(0), "__test__".into(), source, tree.clone(), lines);
|
||||||
semantics.internal_compiler_error(tree.root(), "oh no");
|
semantics.internal_compiler_error(tree.root(), "oh no");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ fun test() -> string {
|
||||||
foo.hello() + " world"
|
foo.hello() + " world"
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ignore WIP
|
// TODO: Obviously run the code duh
|
||||||
// @no-errors
|
// @no-errors
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue