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