[fine] Starting to bind

This commit is contained in:
John Doty 2024-01-06 11:00:40 -08:00
parent 56e4be9a5b
commit 3d4538c0df
2 changed files with 137 additions and 3 deletions

View file

@ -138,7 +138,7 @@ pub enum TreeKind {
pub struct Tree<'a> {
pub kind: TreeKind,
pub parent: Option<TreeRef>,
pub parent: Option<TreeRef>, // TODO: Do we actually need this?
pub start_pos: usize,
pub end_pos: usize,
pub children: Vec<Child<'a>>,

View file

@ -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<EnvironmentRef>,
declarations: HashMap<Box<str>, Declaration>,
}
impl Environment {
pub fn new(parent: Option<EnvironmentRef>) -> 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<Environment>);
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<Option<TreeRef>>, 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<Option<TreeRef>>,
// TODO: State should be externalized instead of this refcell nonsense.
errors: RefCell<Vec<Error>>,
types: RefCell<HashMap<TreeRef, Type>>,
environments: RefCell<HashMap<TreeRef, EnvironmentRef>>,
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<Type> {
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<Type> {
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)
}
}