Improve context stacks
This commit is contained in:
parent
21b63b5942
commit
bbb45aa97e
@ -35,7 +35,7 @@ use crate::{
|
||||
pub fn analyze(source: &str) -> Result<(), DustError> {
|
||||
let abstract_tree = parse(source)?;
|
||||
let context_stack = ContextStack::with_core_library();
|
||||
let mut analyzer = Analyzer::new(&abstract_tree, context_stack);
|
||||
let mut analyzer = Analyzer::new(&abstract_tree, &context_stack);
|
||||
|
||||
analyzer.analyze();
|
||||
|
||||
@ -55,18 +55,18 @@ pub fn analyze(source: &str) -> Result<(), DustError> {
|
||||
/// let input = "x = 1 + false";
|
||||
/// let abstract_tree = parse(input).unwrap();
|
||||
/// let context_stack = ContextStack::new();
|
||||
/// let mut analyzer = Analyzer::new(&abstract_tree, context_stack);
|
||||
/// let mut analyzer = Analyzer::new(&abstract_tree, &context_stack);
|
||||
/// let result = analyzer.analyze();
|
||||
///
|
||||
/// assert!(!analyzer.errors.is_empty());
|
||||
pub struct Analyzer<'a> {
|
||||
abstract_tree: &'a AbstractSyntaxTree,
|
||||
context_stack: ContextStack,
|
||||
context_stack: &'a ContextStack,
|
||||
pub errors: Vec<AnalysisError>,
|
||||
}
|
||||
|
||||
impl<'a> Analyzer<'a> {
|
||||
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context_stack: ContextStack) -> Self {
|
||||
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context_stack: &'a ContextStack) -> Self {
|
||||
Self {
|
||||
abstract_tree,
|
||||
context_stack,
|
||||
@ -81,7 +81,7 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
|
||||
fn analyze_statement(&mut self, statement: &Statement) {
|
||||
let context = self.context_stack.top();
|
||||
let context = self.context_stack.current();
|
||||
|
||||
match statement {
|
||||
Statement::Expression(expression) => {
|
||||
@ -196,7 +196,7 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
|
||||
fn analyze_expression(&mut self, expression: &Expression, statement_position: Span) {
|
||||
let context = self.context_stack.top();
|
||||
let context = self.context_stack.current();
|
||||
|
||||
match expression {
|
||||
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner),
|
||||
@ -360,7 +360,7 @@ impl<'a> Analyzer<'a> {
|
||||
Expression::Identifier(identifier) => {
|
||||
let find_identifier = self
|
||||
.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.update_last_position(&identifier.inner, statement_position);
|
||||
|
||||
if let Ok(false) = find_identifier {
|
||||
@ -546,7 +546,7 @@ impl<'a> Analyzer<'a> {
|
||||
self.analyze_expression(modifier, statement_position);
|
||||
|
||||
let assignee_type_evaluation =
|
||||
match assignee.type_evaluation(&self.context_stack.top()) {
|
||||
match assignee.type_evaluation(&self.context_stack.current()) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
@ -555,7 +555,7 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
};
|
||||
let modifier_type_evaluation =
|
||||
match modifier.type_evaluation(&self.context_stack.top()) {
|
||||
match modifier.type_evaluation(&self.context_stack.current()) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
@ -615,8 +615,8 @@ impl<'a> Analyzer<'a> {
|
||||
self.analyze_expression(left, statement_position);
|
||||
self.analyze_expression(right, statement_position);
|
||||
|
||||
let left_type_evaluation = match left.type_evaluation(&self.context_stack.top())
|
||||
{
|
||||
let left_type_evaluation =
|
||||
match left.type_evaluation(&self.context_stack.current()) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
@ -625,7 +625,7 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
};
|
||||
let right_type_evaluation =
|
||||
match right.type_evaluation(&self.context_stack.top()) {
|
||||
match right.type_evaluation(&self.context_stack.current()) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
@ -713,8 +713,8 @@ impl<'a> Analyzer<'a> {
|
||||
self.analyze_expression(left, statement_position);
|
||||
self.analyze_expression(right, statement_position);
|
||||
|
||||
let left_type_evaluation = match left.type_evaluation(&self.context_stack.top())
|
||||
{
|
||||
let left_type_evaluation =
|
||||
match left.type_evaluation(&self.context_stack.current()) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
@ -723,7 +723,7 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
};
|
||||
let right_type_evaluation =
|
||||
match right.type_evaluation(&self.context_stack.top()) {
|
||||
match right.type_evaluation(&self.context_stack.current()) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
@ -787,7 +787,7 @@ impl<'a> Analyzer<'a> {
|
||||
StructExpression::Fields { name, fields } => {
|
||||
let update_position = self
|
||||
.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.update_last_position(&name.inner, statement_position);
|
||||
|
||||
if let Err(error) = update_position {
|
||||
|
@ -2,26 +2,29 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{ast::Span, core_library, Constructor, Identifier, StructType, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct ContextStack {
|
||||
stack: Arc<RwLock<Vec<Context>>>,
|
||||
current: AtomicUsize,
|
||||
}
|
||||
|
||||
impl ContextStack {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stack: Arc::new(RwLock::new(vec![Context::new()])),
|
||||
}
|
||||
Self::with_context(Context::new())
|
||||
}
|
||||
|
||||
pub fn with_context(context: Context) -> Self {
|
||||
Self {
|
||||
stack: Arc::new(RwLock::new(vec![context])),
|
||||
current: AtomicUsize::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,16 +32,44 @@ impl ContextStack {
|
||||
Self::with_context(core_library().create_child())
|
||||
}
|
||||
|
||||
pub fn push(&self) {
|
||||
pub fn move_up(&self) {
|
||||
let current = self.current.load(Ordering::Relaxed);
|
||||
let next = current + 1;
|
||||
let stack_len = self.stack.read().unwrap().len();
|
||||
|
||||
if next > stack_len {
|
||||
self.push();
|
||||
}
|
||||
|
||||
self.current.store(next, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn push(&self) {
|
||||
let mut stack = self.stack.write().unwrap();
|
||||
let top = stack.last().unwrap().clone();
|
||||
|
||||
stack.push(top.create_child());
|
||||
}
|
||||
|
||||
pub fn move_down(&self) {
|
||||
let current = self.current.load(Ordering::Relaxed);
|
||||
|
||||
if current == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.current.store(current - 1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn pop(&self) {
|
||||
if self.current.load(Ordering::Relaxed) == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let removed = self.stack.write().unwrap().pop();
|
||||
|
||||
self.move_down();
|
||||
|
||||
if let Some(removed) = removed {
|
||||
for (identifier, _) in removed.associations.read().unwrap().iter() {
|
||||
log::trace!("Dropping context with: {}", identifier);
|
||||
@ -46,8 +77,10 @@ impl ContextStack {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn top(&self) -> Context {
|
||||
self.stack.read().unwrap().last().unwrap().clone()
|
||||
pub fn current(&self) -> Context {
|
||||
let current_index = self.current.load(Ordering::Relaxed).saturating_sub(1);
|
||||
|
||||
self.stack.read().unwrap()[current_index].clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +462,7 @@ mod tests {
|
||||
fn run_vm_with_context(source: &str, context: Context) -> Result<Option<Value>, DustError> {
|
||||
let context_stack = ContextStack::with_context(context);
|
||||
let abstract_syntax_tree = parse(source)?;
|
||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree, context_stack.clone());
|
||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree, &context_stack);
|
||||
|
||||
analyzer.analyze();
|
||||
|
||||
|
@ -40,7 +40,7 @@ use crate::{
|
||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
let context_stack = ContextStack::with_core_library();
|
||||
let abstract_syntax_tree = parse(source)?;
|
||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree, context_stack.clone());
|
||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree, &context_stack);
|
||||
|
||||
analyzer.analyze();
|
||||
|
||||
@ -192,7 +192,7 @@ impl Vm {
|
||||
let constructor = struct_type.constructor();
|
||||
|
||||
self.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.set_constructor(name, constructor)
|
||||
.map_err(|error| RuntimeError::ContextError {
|
||||
error,
|
||||
@ -205,7 +205,7 @@ impl Vm {
|
||||
|
||||
if collect_garbage {
|
||||
self.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.collect_garbage(position.1)
|
||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||
}
|
||||
@ -235,7 +235,7 @@ impl Vm {
|
||||
};
|
||||
|
||||
self.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.set_variable_value(identifier.inner, new_value)
|
||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||
|
||||
@ -249,7 +249,7 @@ impl Vm {
|
||||
.into_mutable();
|
||||
|
||||
self.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.set_variable_value(identifier.inner, mutable_value)
|
||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||
|
||||
@ -352,7 +352,7 @@ impl Vm {
|
||||
fn run_identifier(&self, identifier: Node<Identifier>) -> Result<Evaluation, RuntimeError> {
|
||||
let get_data = self
|
||||
.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.get_data(&identifier.inner)
|
||||
.map_err(|error| RuntimeError::ContextError {
|
||||
error,
|
||||
@ -392,7 +392,7 @@ impl Vm {
|
||||
let position = name.position;
|
||||
let constructor = self
|
||||
.context_stack
|
||||
.top()
|
||||
.current()
|
||||
.get_constructor(&name.inner)
|
||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||
|
||||
@ -1009,7 +1009,7 @@ impl Vm {
|
||||
block: BlockExpression,
|
||||
collect_garbage: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
self.context_stack.push();
|
||||
self.context_stack.move_up();
|
||||
|
||||
let evaluation = match block {
|
||||
BlockExpression::Async(statements) => self
|
||||
|
Loading…
Reference in New Issue
Block a user