Add context stacks
This commit is contained in:
parent
d032334635
commit
21b63b5942
@ -17,7 +17,7 @@ use crate::{
|
|||||||
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
|
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
|
||||||
StructExpression, TupleAccessExpression,
|
StructExpression, TupleAccessExpression,
|
||||||
},
|
},
|
||||||
core_library, parse, Context, ContextError, DustError, Expression, Identifier, RangeableType,
|
parse, ContextError, ContextStack, DustError, Expression, Identifier, RangeableType,
|
||||||
StructType, Type, TypeConflict, TypeEvaluation,
|
StructType, Type, TypeConflict, TypeEvaluation,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,8 +34,8 @@ 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 = core_library().create_child();
|
let context_stack = ContextStack::with_core_library();
|
||||||
let mut analyzer = Analyzer::new(&abstract_tree, context);
|
let mut analyzer = Analyzer::new(&abstract_tree, context_stack);
|
||||||
|
|
||||||
analyzer.analyze();
|
analyzer.analyze();
|
||||||
|
|
||||||
@ -54,22 +54,22 @@ pub fn analyze(source: &str) -> Result<(), DustError> {
|
|||||||
/// # use dust_lang::*;
|
/// # use dust_lang::*;
|
||||||
/// let input = "x = 1 + false";
|
/// let input = "x = 1 + false";
|
||||||
/// let abstract_tree = parse(input).unwrap();
|
/// let abstract_tree = parse(input).unwrap();
|
||||||
/// let context = Context::new();
|
/// let context_stack = ContextStack::new();
|
||||||
/// let mut analyzer = Analyzer::new(&abstract_tree, context);
|
/// 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: Context,
|
context_stack: 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: Context) -> Self {
|
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context_stack: ContextStack) -> Self {
|
||||||
Self {
|
Self {
|
||||||
abstract_tree,
|
abstract_tree,
|
||||||
context,
|
context_stack,
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,6 +81,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_statement(&mut self, statement: &Statement) {
|
fn analyze_statement(&mut self, statement: &Statement) {
|
||||||
|
let context = self.context_stack.top();
|
||||||
|
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Expression(expression) => {
|
Statement::Expression(expression) => {
|
||||||
self.analyze_expression(expression, statement.position())
|
self.analyze_expression(expression, statement.position())
|
||||||
@ -91,14 +93,14 @@ impl<'a> Analyzer<'a> {
|
|||||||
Statement::Let(let_statement) => match &let_statement.inner {
|
Statement::Let(let_statement) => match &let_statement.inner {
|
||||||
LetStatement::Let { identifier, value }
|
LetStatement::Let { identifier, value }
|
||||||
| LetStatement::LetMut { identifier, value } => {
|
| LetStatement::LetMut { identifier, value } => {
|
||||||
let r#type = match value.type_evaluation(&self.context) {
|
let r#type = match value.type_evaluation(&context) {
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => {
|
Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => {
|
||||||
let set_type = self.context.set_variable_type(
|
let set_type = context.set_variable_type(
|
||||||
identifier.inner.clone(),
|
identifier.inner.clone(),
|
||||||
Type::Struct(StructType::Unit { name }),
|
Type::Struct(StructType::Unit { name }),
|
||||||
statement.position(),
|
statement.position(),
|
||||||
@ -119,7 +121,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(r#type) = r#type {
|
if let Some(r#type) = r#type {
|
||||||
let set_type = self.context.set_variable_type(
|
let set_type = context.set_variable_type(
|
||||||
identifier.inner.clone(),
|
identifier.inner.clone(),
|
||||||
r#type.clone(),
|
r#type.clone(),
|
||||||
statement.position(),
|
statement.position(),
|
||||||
@ -145,7 +147,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
},
|
},
|
||||||
Statement::StructDefinition(struct_definition) => {
|
Statement::StructDefinition(struct_definition) => {
|
||||||
let set_constructor_type = match &struct_definition.inner {
|
let set_constructor_type = match &struct_definition.inner {
|
||||||
StructDefinition::Unit { name } => self.context.set_constructor_type(
|
StructDefinition::Unit { name } => context.set_constructor_type(
|
||||||
name.inner.clone(),
|
name.inner.clone(),
|
||||||
StructType::Unit {
|
StructType::Unit {
|
||||||
name: name.inner.clone(),
|
name: name.inner.clone(),
|
||||||
@ -155,7 +157,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
StructDefinition::Tuple { name, items } => {
|
StructDefinition::Tuple { name, items } => {
|
||||||
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
||||||
|
|
||||||
self.context.set_constructor_type(
|
context.set_constructor_type(
|
||||||
name.inner.clone(),
|
name.inner.clone(),
|
||||||
StructType::Tuple {
|
StructType::Tuple {
|
||||||
name: name.inner.clone(),
|
name: name.inner.clone(),
|
||||||
@ -172,7 +174,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.context.set_constructor_type(
|
context.set_constructor_type(
|
||||||
name.inner.clone(),
|
name.inner.clone(),
|
||||||
StructType::Fields {
|
StructType::Fields {
|
||||||
name: name.inner.clone(),
|
name: name.inner.clone(),
|
||||||
@ -194,6 +196,8 @@ 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();
|
||||||
|
|
||||||
match expression {
|
match expression {
|
||||||
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner),
|
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner),
|
||||||
Expression::Break(break_node) => {
|
Expression::Break(break_node) => {
|
||||||
@ -206,7 +210,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
|
|
||||||
self.analyze_expression(invoker, statement_position);
|
self.analyze_expression(invoker, statement_position);
|
||||||
|
|
||||||
let invoker_evaluation = match invoker.type_evaluation(&self.context) {
|
let invoker_evaluation = match invoker.type_evaluation(&context) {
|
||||||
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));
|
||||||
@ -219,7 +223,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
invoker_evaluation
|
invoker_evaluation
|
||||||
{
|
{
|
||||||
for (expected_type, argument) in fields.iter().zip(arguments.iter()) {
|
for (expected_type, argument) in fields.iter().zip(arguments.iter()) {
|
||||||
let actual_type = match argument.type_evaluation(&self.context) {
|
let actual_type = match argument.type_evaluation(&context) {
|
||||||
Ok(evaluation) => evaluation.r#type(),
|
Ok(evaluation) => evaluation.r#type(),
|
||||||
Err(ast_error) => {
|
Err(ast_error) => {
|
||||||
self.errors.push(AnalysisError::AstError(ast_error));
|
self.errors.push(AnalysisError::AstError(ast_error));
|
||||||
@ -282,7 +286,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) {
|
for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) {
|
||||||
self.analyze_expression(argument, statement_position);
|
self.analyze_expression(argument, statement_position);
|
||||||
|
|
||||||
let argument_evaluation = match argument.type_evaluation(&self.context) {
|
let argument_evaluation = match argument.type_evaluation(&context) {
|
||||||
Ok(evaluation) => evaluation,
|
Ok(evaluation) => evaluation,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
self.errors.push(AnalysisError::AstError(error));
|
self.errors.push(AnalysisError::AstError(error));
|
||||||
@ -321,7 +325,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
let FieldAccessExpression { container, field } =
|
let FieldAccessExpression { container, field } =
|
||||||
field_access_expression.inner.as_ref();
|
field_access_expression.inner.as_ref();
|
||||||
|
|
||||||
let evaluation = match container.type_evaluation(&self.context) {
|
let evaluation = match container.type_evaluation(&context) {
|
||||||
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));
|
||||||
@ -355,7 +359,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let find_identifier = self
|
let find_identifier = self
|
||||||
.context
|
.context_stack
|
||||||
|
.top()
|
||||||
.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 {
|
||||||
@ -394,7 +399,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_expression(list, statement_position);
|
self.analyze_expression(list, statement_position);
|
||||||
self.analyze_expression(index, statement_position);
|
self.analyze_expression(index, statement_position);
|
||||||
|
|
||||||
let list_type_evaluation = match list.type_evaluation(&self.context) {
|
let list_type_evaluation = match list.type_evaluation(&context) {
|
||||||
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));
|
||||||
@ -413,7 +418,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let index_type_evaluation = match index.type_evaluation(&self.context) {
|
let index_type_evaluation = match index.type_evaluation(&context) {
|
||||||
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));
|
||||||
@ -540,7 +545,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_expression(assignee, statement_position);
|
self.analyze_expression(assignee, statement_position);
|
||||||
self.analyze_expression(modifier, statement_position);
|
self.analyze_expression(modifier, statement_position);
|
||||||
|
|
||||||
let assignee_type_evaluation = match assignee.type_evaluation(&self.context) {
|
let assignee_type_evaluation =
|
||||||
|
match assignee.type_evaluation(&self.context_stack.top()) {
|
||||||
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));
|
||||||
@ -548,7 +554,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let modifier_type_evaluation = match modifier.type_evaluation(&self.context) {
|
let modifier_type_evaluation =
|
||||||
|
match modifier.type_evaluation(&self.context_stack.top()) {
|
||||||
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));
|
||||||
@ -608,7 +615,8 @@ 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) {
|
let left_type_evaluation = match left.type_evaluation(&self.context_stack.top())
|
||||||
|
{
|
||||||
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));
|
||||||
@ -616,7 +624,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let right_type_evaluation = match right.type_evaluation(&self.context) {
|
let right_type_evaluation =
|
||||||
|
match right.type_evaluation(&self.context_stack.top()) {
|
||||||
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));
|
||||||
@ -704,7 +713,8 @@ 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) {
|
let left_type_evaluation = match left.type_evaluation(&self.context_stack.top())
|
||||||
|
{
|
||||||
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));
|
||||||
@ -712,7 +722,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let right_type_evaluation = match right.type_evaluation(&self.context) {
|
let right_type_evaluation =
|
||||||
|
match right.type_evaluation(&self.context_stack.top()) {
|
||||||
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));
|
||||||
@ -775,7 +786,8 @@ impl<'a> Analyzer<'a> {
|
|||||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
||||||
StructExpression::Fields { name, fields } => {
|
StructExpression::Fields { name, fields } => {
|
||||||
let update_position = self
|
let update_position = self
|
||||||
.context
|
.context_stack
|
||||||
|
.top()
|
||||||
.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 {
|
||||||
@ -795,7 +807,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
Expression::TupleAccess(tuple_access) => {
|
Expression::TupleAccess(tuple_access) => {
|
||||||
let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref();
|
let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref();
|
||||||
|
|
||||||
let type_evaluation = match tuple.type_evaluation(&self.context) {
|
let type_evaluation = match tuple.type_evaluation(&context) {
|
||||||
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));
|
||||||
|
@ -5,7 +5,57 @@ use std::{
|
|||||||
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ast::Span, Constructor, Identifier, StructType, Type, Value};
|
use crate::{ast::Span, core_library, Constructor, Identifier, StructType, Type, Value};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ContextStack {
|
||||||
|
stack: Arc<RwLock<Vec<Context>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextStack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
stack: Arc::new(RwLock::new(vec![Context::new()])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_context(context: Context) -> Self {
|
||||||
|
Self {
|
||||||
|
stack: Arc::new(RwLock::new(vec![context])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_core_library() -> Self {
|
||||||
|
Self::with_context(core_library().create_child())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&self) {
|
||||||
|
let mut stack = self.stack.write().unwrap();
|
||||||
|
let top = stack.last().unwrap().clone();
|
||||||
|
|
||||||
|
stack.push(top.create_child());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&self) {
|
||||||
|
let removed = self.stack.write().unwrap().pop();
|
||||||
|
|
||||||
|
if let Some(removed) = removed {
|
||||||
|
for (identifier, _) in removed.associations.read().unwrap().iter() {
|
||||||
|
log::trace!("Dropping context with: {}", identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top(&self) -> Context {
|
||||||
|
self.stack.read().unwrap().last().unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ContextStack {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type Associations = HashMap<Identifier, (ContextData, Span)>;
|
pub type Associations = HashMap<Identifier, (ContextData, Span)>;
|
||||||
|
|
||||||
@ -372,10 +422,33 @@ impl Display for ContextError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::vm::run_with_context;
|
use crate::{parse, Analyzer, DustError, Vm};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
analyzer.analyze();
|
||||||
|
|
||||||
|
if !analyzer.errors.is_empty() {
|
||||||
|
return Err(DustError::Analysis {
|
||||||
|
analysis_errors: analyzer.errors,
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let vm = Vm::new(context_stack);
|
||||||
|
|
||||||
|
vm.run(abstract_syntax_tree)
|
||||||
|
.map_err(|runtime_error| DustError::Runtime {
|
||||||
|
runtime_error,
|
||||||
|
source,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn context_removes_variables() {
|
fn context_removes_variables() {
|
||||||
let source = "
|
let source = "
|
||||||
@ -387,7 +460,7 @@ mod tests {
|
|||||||
let context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run_with_context(source, context.clone()),
|
run_vm_with_context(source, context.clone()),
|
||||||
Ok(Some(Value::integer(15)))
|
Ok(Some(Value::integer(15)))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -405,7 +478,7 @@ mod tests {
|
|||||||
";
|
";
|
||||||
let context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
run_with_context(source, context.clone()).unwrap();
|
run_vm_with_context(source, context.clone()).unwrap();
|
||||||
|
|
||||||
assert_eq!(context.association_count().unwrap(), 0);
|
assert_eq!(context.association_count().unwrap(), 0);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ pub use analyzer::{analyze, AnalysisError, Analyzer};
|
|||||||
pub use ast::{AbstractSyntaxTree, AstError, Expression, Node, Span, Statement};
|
pub use ast::{AbstractSyntaxTree, AstError, Expression, Node, Span, Statement};
|
||||||
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
||||||
pub use constructor::Constructor;
|
pub use constructor::Constructor;
|
||||||
pub use context::{Context, ContextData, ContextError};
|
pub use context::{Context, ContextData, ContextError, ContextStack};
|
||||||
pub use core_library::core_library;
|
pub use core_library::core_library;
|
||||||
pub use dust_error::DustError;
|
pub use dust_error::DustError;
|
||||||
pub use evaluation::{Evaluation, TypeEvaluation};
|
pub use evaluation::{Evaluation, TypeEvaluation};
|
||||||
@ -45,4 +45,4 @@ pub use parser::{parse, ParseError, Parser};
|
|||||||
pub use r#type::*;
|
pub use r#type::*;
|
||||||
pub use token::{Token, TokenKind, TokenOwned};
|
pub use token::{Token, TokenKind, TokenOwned};
|
||||||
pub use value::*;
|
pub use value::*;
|
||||||
pub use vm::{run, run_with_context, RuntimeError, Vm};
|
pub use vm::{run, RuntimeError, Vm};
|
||||||
|
@ -15,8 +15,8 @@ use serde::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractSyntaxTree, BuiltInFunction, BuiltInFunctionError, Context, ContextError, EnumType,
|
AbstractSyntaxTree, BuiltInFunction, BuiltInFunctionError, Context, ContextError, ContextStack,
|
||||||
FunctionType, Identifier, RangeableType, RuntimeError, StructType, Type, Vm,
|
EnumType, FunctionType, Identifier, RangeableType, RuntimeError, StructType, Type, Vm,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Dust value representation
|
/// Dust value representation
|
||||||
@ -1405,20 +1405,22 @@ impl Function {
|
|||||||
.call(_type_arguments, value_arguments)
|
.call(_type_arguments, value_arguments)
|
||||||
.map_err(FunctionCallError::BuiltInFunction),
|
.map_err(FunctionCallError::BuiltInFunction),
|
||||||
Function::Parsed { r#type, body, .. } => {
|
Function::Parsed { r#type, body, .. } => {
|
||||||
let new_context =
|
let base_context = context.create_child();
|
||||||
Context::with_data_from(context).map_err(FunctionCallError::Context)?;
|
let new_context_stack = ContextStack::with_context(base_context.clone());
|
||||||
|
|
||||||
if let (Some(value_parameters), Some(value_arguments)) =
|
if let (Some(value_parameters), Some(value_arguments)) =
|
||||||
(&r#type.value_parameters, value_arguments)
|
(&r#type.value_parameters, value_arguments)
|
||||||
{
|
{
|
||||||
for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) {
|
for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) {
|
||||||
new_context
|
base_context
|
||||||
.set_variable_value(identifier.clone(), value)
|
.set_variable_value(identifier.clone(), value)
|
||||||
.map_err(FunctionCallError::Context)?;
|
.map_err(FunctionCallError::Context)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let vm = Vm::new(new_context);
|
drop(base_context);
|
||||||
|
|
||||||
|
let vm = Vm::new(new_context_stack);
|
||||||
|
|
||||||
vm.run(body)
|
vm.run(body)
|
||||||
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))
|
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))
|
||||||
|
@ -21,9 +21,10 @@ use crate::{
|
|||||||
StructDefinition, StructExpression,
|
StructDefinition, StructExpression,
|
||||||
},
|
},
|
||||||
constructor::ConstructError,
|
constructor::ConstructError,
|
||||||
core_library, parse, Analyzer, BuiltInFunctionError, Context, ContextData, ContextError,
|
context::ContextStack,
|
||||||
DustError, Evaluation, Expression, Function, FunctionCallError, Identifier, ParseError,
|
parse, Analyzer, BuiltInFunctionError, Context, ContextData, ContextError, DustError,
|
||||||
StructType, Type, Value, ValueData, ValueError,
|
Evaluation, Expression, Function, FunctionCallError, Identifier, ParseError, StructType, Type,
|
||||||
|
Value, ValueData, ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Run the source code and return the result.
|
/// Run the source code and return the result.
|
||||||
@ -37,28 +38,9 @@ use crate::{
|
|||||||
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||||
let context = core_library().create_child();
|
let context_stack = ContextStack::with_core_library();
|
||||||
|
|
||||||
run_with_context(source, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the source code with a context and return the result.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// # use dust_lang::*;
|
|
||||||
/// let context = Context::new();
|
|
||||||
///
|
|
||||||
/// context.set_variable_value(Identifier::new("foo"), Value::integer(40));
|
|
||||||
/// context.update_last_position(&Identifier::new("foo"), (100, 100));
|
|
||||||
///
|
|
||||||
/// let result = run_with_context("foo + 2", context);
|
|
||||||
///
|
|
||||||
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
/// ```
|
|
||||||
pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>, DustError> {
|
|
||||||
let abstract_syntax_tree = parse(source)?;
|
let abstract_syntax_tree = parse(source)?;
|
||||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree, context.clone());
|
let mut analyzer = Analyzer::new(&abstract_syntax_tree, context_stack.clone());
|
||||||
|
|
||||||
analyzer.analyze();
|
analyzer.analyze();
|
||||||
|
|
||||||
@ -69,7 +51,7 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let vm = Vm::new(context);
|
let vm = Vm::new(context_stack);
|
||||||
|
|
||||||
vm.run(abstract_syntax_tree)
|
vm.run(abstract_syntax_tree)
|
||||||
.map_err(|runtime_error| DustError::Runtime {
|
.map_err(|runtime_error| DustError::Runtime {
|
||||||
@ -86,12 +68,12 @@ pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>,
|
|||||||
///
|
///
|
||||||
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
|
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
context: Context,
|
context_stack: ContextStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn new(context: Context) -> Self {
|
pub fn new(context_stack: ContextStack) -> Self {
|
||||||
Self { context }
|
Self { context_stack }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
|
pub fn run(&self, mut tree: AbstractSyntaxTree) -> Result<Option<Value>, RuntimeError> {
|
||||||
@ -209,7 +191,8 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
let constructor = struct_type.constructor();
|
let constructor = struct_type.constructor();
|
||||||
|
|
||||||
self.context
|
self.context_stack
|
||||||
|
.top()
|
||||||
.set_constructor(name, constructor)
|
.set_constructor(name, constructor)
|
||||||
.map_err(|error| RuntimeError::ContextError {
|
.map_err(|error| RuntimeError::ContextError {
|
||||||
error,
|
error,
|
||||||
@ -221,7 +204,8 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if collect_garbage {
|
if collect_garbage {
|
||||||
self.context
|
self.context_stack
|
||||||
|
.top()
|
||||||
.collect_garbage(position.1)
|
.collect_garbage(position.1)
|
||||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||||
}
|
}
|
||||||
@ -250,7 +234,8 @@ impl Vm {
|
|||||||
_ => value,
|
_ => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context
|
self.context_stack
|
||||||
|
.top()
|
||||||
.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 })?;
|
||||||
|
|
||||||
@ -263,7 +248,8 @@ impl Vm {
|
|||||||
.expect_value(position)?
|
.expect_value(position)?
|
||||||
.into_mutable();
|
.into_mutable();
|
||||||
|
|
||||||
self.context
|
self.context_stack
|
||||||
|
.top()
|
||||||
.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 })?;
|
||||||
|
|
||||||
@ -364,11 +350,13 @@ 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.context.get_data(&identifier.inner).map_err(|error| {
|
let get_data = self
|
||||||
RuntimeError::ContextError {
|
.context_stack
|
||||||
|
.top()
|
||||||
|
.get_data(&identifier.inner)
|
||||||
|
.map_err(|error| RuntimeError::ContextError {
|
||||||
error,
|
error,
|
||||||
position: identifier.position,
|
position: identifier.position,
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(ContextData::VariableValue(value)) = get_data {
|
if let Some(ContextData::VariableValue(value)) = get_data {
|
||||||
@ -403,7 +391,8 @@ impl Vm {
|
|||||||
|
|
||||||
let position = name.position;
|
let position = name.position;
|
||||||
let constructor = self
|
let constructor = self
|
||||||
.context
|
.context_stack
|
||||||
|
.top()
|
||||||
.get_constructor(&name.inner)
|
.get_constructor(&name.inner)
|
||||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||||
|
|
||||||
@ -1020,18 +1009,17 @@ impl Vm {
|
|||||||
block: BlockExpression,
|
block: BlockExpression,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
let block_context = self.context.create_child();
|
self.context_stack.push();
|
||||||
let vm = Vm::new(block_context);
|
|
||||||
|
|
||||||
match block {
|
let evaluation = match block {
|
||||||
BlockExpression::Async(statements) => vm
|
BlockExpression::Async(statements) => self
|
||||||
.run_async(AbstractSyntaxTree::with_statements(statements))
|
.run_async(AbstractSyntaxTree::with_statements(statements))
|
||||||
.map(Evaluation::Return),
|
.map(Evaluation::Return),
|
||||||
BlockExpression::Sync(statements) => {
|
BlockExpression::Sync(statements) => {
|
||||||
let mut evaluation = Evaluation::Return(None);
|
let mut evaluation = Evaluation::Return(None);
|
||||||
|
|
||||||
for statement in statements {
|
for statement in statements {
|
||||||
evaluation = vm.run_statement(statement, collect_garbage)?;
|
evaluation = self.run_statement(statement, collect_garbage)?;
|
||||||
|
|
||||||
if let Evaluation::Break(_) = evaluation {
|
if let Evaluation::Break(_) = evaluation {
|
||||||
return Ok(evaluation);
|
return Ok(evaluation);
|
||||||
@ -1040,7 +1028,11 @@ impl Vm {
|
|||||||
|
|
||||||
Ok(evaluation)
|
Ok(evaluation)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
self.context_stack.pop();
|
||||||
|
|
||||||
|
evaluation
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_if(
|
fn run_if(
|
||||||
|
Loading…
Reference in New Issue
Block a user