diff --git a/fine/src/parser.rs b/fine/src/parser.rs index 6fd7b36b..a0f519f7 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -138,7 +138,7 @@ pub enum TreeKind { pub struct Tree<'a> { pub kind: TreeKind, - pub parent: Option, + pub parent: Option, // TODO: Do we actually need this? pub start_pos: usize, pub end_pos: usize, pub children: Vec>, diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 38075f79..53dc1346 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -1,8 +1,8 @@ use crate::{ parser::{Child, SyntaxTree, Tree, TreeKind, TreeRef}, - tokens::{Lines, TokenKind}, + tokens::{Lines, Token, TokenKind}, }; -use std::{cell::RefCell, collections::HashMap, fmt}; +use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc}; // TODO: An error should have: // @@ -121,22 +121,126 @@ impl fmt::Display for Type { } } +pub struct Declaration { + declaration_type: Type, +} + +pub struct Environment { + parent: Option, + declarations: HashMap, Declaration>, +} + +impl Environment { + pub fn new(parent: Option) -> Self { + Environment { + parent, + declarations: HashMap::new(), + } + } + + pub fn bind(&self, token: &Token) -> Option<&Declaration> { + if let Some(decl) = self.declarations.get(token.as_str()) { + return Some(decl); + } + + let mut current = &self.parent; + while let Some(env) = current { + if let Some(decl) = env.declarations.get(token.as_str()) { + return Some(decl); + } + current = &env.parent; + } + + None + } +} + +#[derive(Clone)] +pub struct EnvironmentRef(Rc); + +impl EnvironmentRef { + pub fn new(environment: Environment) -> Self { + EnvironmentRef(Rc::new(environment)) + } +} + +impl std::ops::Deref for EnvironmentRef { + type Target = Environment; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn set_logical_parents(parents: &mut Vec>, syntax_tree: &SyntaxTree, t: TreeRef) { + 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), + } + } + + match tree.kind { + TreeKind::Block => { + // In a block, each child actually points to the previous child + // as the logical parent, so that variable declarations that + // occur as part of statements in the block are available to + // statements later in the block. + let mut parent = Some(t); + for child in &tree.children { + match child { + Child::Token(_) => (), + Child::Tree(ct) => { + parents[t.index()] = parent; + parent = Some(*ct); + } + } + } + } + _ => {} + } +} + 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? syntax_tree: &'a SyntaxTree<'a>, lines: &'a Lines, + + // Instead of physical parents, this is the set of *logical* parents. + // This is what is used for binding. + logical_parents: Vec>, + + // TODO: State should be externalized instead of this refcell nonsense. errors: 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(); + if let Some(root) = tree.root() { + set_logical_parents(&mut logical_parents, tree, root); + } + let mut semantics = Semantics { syntax_tree: tree, lines, + logical_parents, errors: RefCell::new(vec![]), types: RefCell::new(HashMap::new()), + environments: RefCell::new(HashMap::new()), + empty_environment: EnvironmentRef::new(Environment::new(None)), }; // NOTE: We ensure all the known errors are reported before we move @@ -210,6 +314,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(); + } + + let tree = &self.syntax_tree[t]; + let parent = match self.logical_parents[t.index()] { + Some(t) => self.environment_of(t), + None => self.empty_environment.clone(), + }; + + let result = match tree.kind { + // TODO: Things that introduce an environment! + _ => parent, + }; + + self.environments.borrow_mut().insert(t, result.clone()); + result + } + pub fn type_of(&self, t: TreeRef) -> Option { if let Some(existing) = self.types.borrow().get(&t) { return Some(existing.clone()); @@ -491,6 +615,16 @@ impl<'a> Semantics<'a> { fn type_of_identifier(&self, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::Identifier); + + let id = tree.nth_token(0)?; + if let Some(parent) = tree.parent { + let environment = self.environment_of(parent); + if let Some(declaration) = environment.bind(id) { + return Some(declaration.declaration_type); + } + } + + self.report_error_tree(tree, format!("cannot find value {id} here")); Some(Type::Error) } }