[fine] Tracking cleanups: HashMap->Vec, and record complete

This commit is contained in:
John Doty 2024-01-07 08:29:02 -08:00
parent efd0685f41
commit 3877c6e547

View file

@ -222,7 +222,9 @@ fn set_logical_parents(
}
}
#[derive(Clone, Copy, Debug)]
enum Incremental<T> {
None,
InProgress,
Complete(T),
}
@ -239,15 +241,14 @@ pub struct Semantics<'a> {
// TODO: State should be externalized instead of this refcell nonsense.
errors: RefCell<Vec<Error>>,
types: RefCell<HashMap<TreeRef, Incremental<Type>>>,
environments: RefCell<HashMap<TreeRef, Incremental<EnvironmentRef>>>,
types: RefCell<Vec<Incremental<Type>>>,
environments: RefCell<Vec<Incremental<EnvironmentRef>>>,
empty_environment: EnvironmentRef,
}
impl<'a> Semantics<'a> {
pub fn new(tree: &'a SyntaxTree<'a>, lines: &'a Lines) -> Self {
let mut logical_parents = Vec::with_capacity(tree.len());
logical_parents.resize(tree.len(), None);
let mut logical_parents = vec![None; tree.len()];
if let Some(root) = tree.root() {
set_logical_parents(&mut logical_parents, tree, root, None);
}
@ -257,8 +258,8 @@ impl<'a> Semantics<'a> {
lines,
logical_parents,
errors: RefCell::new(vec![]),
types: RefCell::new(HashMap::new()),
environments: RefCell::new(HashMap::new()),
types: RefCell::new(vec![Incremental::None; tree.len()]),
environments: RefCell::new(vec![Incremental::None; tree.len()]),
empty_environment: EnvironmentRef::new(Environment::new(None)),
};
@ -342,22 +343,23 @@ impl<'a> Semantics<'a> {
}
pub fn environment_of(&self, t: TreeRef) -> EnvironmentRef {
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();
{
let state = &mut self.environments.borrow_mut()[t.index()];
match state {
Incremental::None => (),
Incremental::Complete(e) => return e.clone(),
Incremental::InProgress => {
// eprintln!("environment_of circular => {t:?}");
self.report_error_tree_ref(
t,
"INTERNAL COMPILER ERROR: Circular dependency detected: environment",
);
*state = Incremental::Complete(self.empty_environment.clone());
return self.empty_environment.clone();
}
}
*state = Incremental::InProgress;
}
self.environments
.borrow_mut()
.insert(t, Incremental::InProgress);
let tree = &self.syntax_tree[t];
// eprintln!("environment_of => {tree:?}");
@ -375,9 +377,7 @@ impl<'a> Semantics<'a> {
_ => parent,
};
self.environments
.borrow_mut()
.insert(t, Incremental::Complete(result.clone()));
self.environments.borrow_mut()[t.index()] = Incremental::Complete(result.clone());
result
}
@ -444,20 +444,20 @@ impl<'a> Semantics<'a> {
}
pub fn type_of(&self, t: TreeRef) -> Option<Type> {
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);
{
let state = &mut self.types.borrow_mut()[t.index()];
match state {
Incremental::None => (),
Incremental::Complete(existing) => return Some(existing.clone()),
Incremental::InProgress => {
// eprintln!("type_of circular => {t:?}");
self.report_error_tree_ref(t, "The type of this expression depends on itself");
*state = Incremental::Complete(Type::Error);
return Some(Type::Error);
}
}
*state = Incremental::InProgress;
}
self.types.borrow_mut().insert(t, Incremental::InProgress);
let tree = &self.syntax_tree[t];
// eprintln!("type_of => {tree:?}");
@ -479,21 +479,13 @@ impl<'a> Semantics<'a> {
TreeKind::ExpressionStatement => self.type_of_expression_statement(tree),
TreeKind::Identifier => self.type_of_identifier(tree),
// 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, Incremental::Complete(result.clone()));
self.types.borrow_mut()[t.index()] = Incremental::Complete(result.clone());
Some(result)
}