diff --git a/fine/src/parser.rs b/fine/src/parser.rs index a0f519f7..802657ad 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -66,6 +66,10 @@ impl<'a> SyntaxTree<'a> { self[t].end_pos } + pub fn len(&self) -> usize { + self.trees.len() + } + pub fn trees(&self) -> impl Iterator { (0..self.trees.len()).map(|i| TreeRef::from_index(i)) } @@ -164,6 +168,23 @@ impl<'a> Tree<'a> { }) .flatten() } + + pub fn dump(&self, tree: &SyntaxTree<'a>, with_positions: bool, output: &mut String) { + let _ = write!(output, "{:?}", self.kind); + if with_positions { + let _ = write!(output, " [{}, {})", self.start_pos, self.end_pos); + } + let _ = write!(output, "\n"); + for child in self.children.iter() { + child.dump_rec(2, tree, with_positions, output); + } + } +} + +impl<'a> std::fmt::Debug for Tree<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?} [{}-{})", self.kind, self.start_pos, self.end_pos) + } } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] @@ -181,19 +202,6 @@ impl TreeRef { } } -impl<'a> Tree<'a> { - pub fn dump(&self, tree: &SyntaxTree<'a>, with_positions: bool, output: &mut String) { - let _ = write!(output, "{:?}", self.kind); - if with_positions { - let _ = write!(output, " [{}, {})", self.start_pos, self.end_pos); - } - let _ = write!(output, "\n"); - for child in self.children.iter() { - child.dump_rec(2, tree, with_positions, output); - } - } -} - pub enum Child<'a> { Token(Token<'a>), Tree(TreeRef), diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 9bf484ea..40138628 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -172,22 +172,16 @@ impl std::ops::Deref for EnvironmentRef { } } -fn set_logical_parents(parents: &mut Vec>, syntax_tree: &SyntaxTree, t: TreeRef) { +fn set_logical_parents( + parents: &mut Vec>, + syntax_tree: &SyntaxTree, + t: TreeRef, + parent: Option, +) { + parents[t.index()] = parent.clone(); + let tree = &syntax_tree[t]; - - // The default logical parent is the physical parent. - if parents.len() <= t.index() { - parents.resize(t.index() + 1, None); - } - parents[t.index()] = tree.parent.clone(); - - for child in &tree.children { - match child { - Child::Token(_) => (), - Child::Tree(ct) => set_logical_parents(parents, syntax_tree, *ct), - } - } - + // eprintln!("SET PARENT {parent:?} => CHILD {tree:?} ({t:?})"); match tree.kind { TreeKind::Block | TreeKind::File => { // In a block (or at the top level), each child actually points @@ -199,16 +193,40 @@ fn set_logical_parents(parents: &mut Vec>, syntax_tree: &SyntaxT match child { Child::Token(_) => (), Child::Tree(ct) => { - parents[ct.index()] = parent; + set_logical_parents(parents, syntax_tree, *ct, parent); parent = Some(*ct); } } } } - _ => {} + TreeKind::LetStatement => { + // In a let statement, the logical parent of the children is + // actually the logical parent of the let statement, so that the + // variable doesn't have itself in scope. :P + for child in &tree.children { + match child { + Child::Token(_) => (), + Child::Tree(ct) => set_logical_parents(parents, syntax_tree, *ct, parent), + } + } + } + _ => { + // By default, the parent for each child is current tree. + for child in &tree.children { + match child { + Child::Token(_) => (), + Child::Tree(ct) => set_logical_parents(parents, syntax_tree, *ct, Some(t)), + } + } + } } } +enum Incremental { + InProgress, + Complete(T), +} + pub struct Semantics<'a> { // TODO: Do I really want my own copy here? Should we standardize on Arc // or Rc or some other nice sharing mechanism? @@ -221,16 +239,17 @@ pub struct Semantics<'a> { // TODO: State should be externalized instead of this refcell nonsense. errors: RefCell>, - types: RefCell>, - environments: RefCell>, + types: RefCell>>, + environments: RefCell>>, empty_environment: EnvironmentRef, } impl<'a> Semantics<'a> { pub fn new(tree: &'a SyntaxTree<'a>, lines: &'a Lines) -> Self { - let mut logical_parents = Vec::new(); + let mut logical_parents = Vec::with_capacity(tree.len()); + logical_parents.resize(tree.len(), None); if let Some(root) = tree.root() { - set_logical_parents(&mut logical_parents, tree, root); + set_logical_parents(&mut logical_parents, tree, root, None); } let mut semantics = Semantics { @@ -323,11 +342,26 @@ impl<'a> Semantics<'a> { } pub fn environment_of(&self, t: TreeRef) -> EnvironmentRef { - if let Some(existing) = self.environments.borrow().get(&t) { - return existing.clone(); + match self.environments.borrow().get(&t) { + None => (), + Some(Incremental::Complete(e)) => return e.clone(), + Some(Incremental::InProgress) => { + // TODO: Rewrite as complete with empty after reporting error. + // eprintln!("environment_of circular => {t:?}"); + self.report_error_tree_ref( + t, + "INTERNAL COMPILER ERROR: Circular dependency detected: environment", + ); + return self.empty_environment.clone(); + } } + self.environments + .borrow_mut() + .insert(t, Incremental::InProgress); let tree = &self.syntax_tree[t]; + // eprintln!("environment_of => {tree:?}"); + let parent = match self.logical_parents[t.index()] { Some(t) => self.environment_of(t), None => self.empty_environment.clone(), @@ -340,12 +374,13 @@ impl<'a> Semantics<'a> { _ => parent, }; - self.environments.borrow_mut().insert(t, result.clone()); + self.environments + .borrow_mut() + .insert(t, Incremental::Complete(result.clone())); result } fn environment_of_let(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef { - // 0 is the ... let keyword let Some(name) = tree.nth_token(1) else { return parent; // Error is already reported? }; @@ -370,11 +405,24 @@ impl<'a> Semantics<'a> { } pub fn type_of(&self, t: TreeRef) -> Option { - if let Some(existing) = self.types.borrow().get(&t) { - return Some(existing.clone()); + match self.types.borrow().get(&t) { + None => (), + Some(Incremental::Complete(existing)) => return Some(existing.clone()), + Some(Incremental::InProgress) => { + // TODO: Rewrite as complete with error after reporting error. + // eprintln!("type_of circular => {t:?}"); + self.report_error_tree_ref( + t, + "INTERNAL COMPILER ERROR: Circular dependency detected: type", + ); + return Some(Type::Error); + } } + self.types.borrow_mut().insert(t, Incremental::InProgress); let tree = &self.syntax_tree[t]; + // eprintln!("type_of => {tree:?}"); + let result = match tree.kind { TreeKind::Error => Some(Type::Error), TreeKind::UnaryExpression => self.type_of_unary(tree), @@ -391,13 +439,22 @@ impl<'a> Semantics<'a> { TreeKind::ReturnStatement => Some(Type::Unreachable), TreeKind::ExpressionStatement => self.type_of_expression_statement(tree), TreeKind::Identifier => self.type_of_identifier(tree), - _ => return None, + + // TODO: Previously I had short-circuited here and not put anything + // in the table if this node isn't the kind that I would + // normally compute a type for. I should keep doing that to + // detect nonsense without blowing out the hash table. If + // we're going to be computing a type for every node it + // should just be an array instead of a hash table. + _ => None, }; // NOTE: These return `None` if they encounter some problem. let result = result.unwrap_or(Type::Error); - self.types.borrow_mut().insert(t, result.clone()); + self.types + .borrow_mut() + .insert(t, Incremental::Complete(result.clone())); Some(result) } diff --git a/fine/tests/example_tests.rs b/fine/tests/example_tests.rs index 30a5eb5a..d41900e8 100644 --- a/fine/tests/example_tests.rs +++ b/fine/tests/example_tests.rs @@ -107,6 +107,7 @@ fn report_semantic_error(semantics: &Semantics, tr: Option, message: &s } if let Some(tr) = tr { + println!("About the tree: {:?}", &tree[tr]); println!("The logical parent chain of the tree was:\n"); let mut current = Some(tr); while let Some(c) = current { diff --git a/fine/tests/expression/variable.fine b/fine/tests/expression/variable.fine index efffbca4..455da6e6 100644 --- a/fine/tests/expression/variable.fine +++ b/fine/tests/expression/variable.fine @@ -7,7 +7,10 @@ // | LiteralExpression // | Number:'"23"' // | Semicolon:'";"' -// | ExpressionStatement +// | LetStatement +// | Let:'"let"' +// | Identifier:'"y"' +// | Equal:'"="' // | BinaryExpression // | Identifier // | Identifier:'"x"' @@ -15,9 +18,14 @@ // | LiteralExpression // | Number:'"2"' // | Semicolon:'";"' +// | ExpressionStatement +// | Identifier +// | Identifier:'"y"' +// | Semicolon:'";"' // | let x = 23; -x * 2; +let y = x * 2; +y; -// @type: 416 f64 +// @type: 590 f64