[fine] Tracking cleanups: HashMap->Vec, and record complete
This commit is contained in:
parent
efd0685f41
commit
3877c6e547
1 changed files with 36 additions and 44 deletions
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue