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