Experiment with context scopes
This commit is contained in:
parent
0e52ed7a49
commit
e84e022eed
@ -12,7 +12,7 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
|
use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, TypeConstructor};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct As {
|
pub struct As {
|
||||||
@ -34,9 +34,10 @@ impl AbstractNode for As {
|
|||||||
&self,
|
&self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
self.expression
|
self.expression
|
||||||
.define_and_validate(_context, _manage_memory)?;
|
.define_and_validate(_context, _manage_memory, scope)?;
|
||||||
|
|
||||||
match self.constructor {
|
match self.constructor {
|
||||||
TypeConstructor::Raw(_) => {}
|
TypeConstructor::Raw(_) => {}
|
||||||
@ -50,9 +51,10 @@ impl AbstractNode for As {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let expression_position = self.expression.position();
|
let expression_position = self.expression.position();
|
||||||
let evaluation = self.expression.evaluate(context, _manage_memory)?;
|
let evaluation = self.expression.evaluate(context, _manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,7 +9,9 @@ use crate::{
|
|||||||
Context, Value,
|
Context, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Statement, Type, TypeConstructor, WithPosition};
|
use super::{
|
||||||
|
AbstractNode, Evaluation, SourcePosition, Statement, Type, TypeConstructor, WithPosition,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
@ -47,20 +49,21 @@ impl AbstractNode for Assignment {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
if let Some(constructor) = &self.constructor {
|
let r#type = if let Some(constructor) = &self.constructor {
|
||||||
let r#type = constructor.construct(&context)?;
|
constructor.construct(&context)?
|
||||||
|
|
||||||
context.set_type(self.identifier.node.clone(), r#type.clone())?;
|
|
||||||
} else if let Some(r#type) = self.statement.expected_type(context)? {
|
} else if let Some(r#type) = self.statement.expected_type(context)? {
|
||||||
context.set_type(self.identifier.node.clone(), r#type)?;
|
r#type
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::CannotAssignToNone(
|
return Err(ValidationError::CannotAssignToNone(
|
||||||
self.statement.last_evaluated_statement().position(),
|
self.statement.last_evaluated_statement().position(),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
self.statement.define_and_validate(context, manage_memory)?;
|
context.set_type(self.identifier.node.clone(), r#type, scope)?;
|
||||||
|
self.statement
|
||||||
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
|
|
||||||
let statement_type = self.statement.expected_type(context)?;
|
let statement_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
@ -91,8 +94,9 @@ impl AbstractNode for Assignment {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let evaluation = self.statement.evaluate(context, manage_memory)?;
|
let evaluation = self.statement.evaluate(context, manage_memory, scope)?;
|
||||||
let right = match evaluation {
|
let right = match evaluation {
|
||||||
Some(Evaluation::Return(value)) => value,
|
Some(Evaluation::Return(value)) => value,
|
||||||
evaluation => return Ok(evaluation),
|
evaluation => return Ok(evaluation),
|
||||||
@ -100,7 +104,7 @@ impl AbstractNode for Assignment {
|
|||||||
|
|
||||||
match self.operator {
|
match self.operator {
|
||||||
AssignmentOperator::Assign => {
|
AssignmentOperator::Assign => {
|
||||||
context.set_value(self.identifier.node, right)?;
|
context.set_value(self.identifier.node, right, scope)?;
|
||||||
}
|
}
|
||||||
AssignmentOperator::AddAssign => {
|
AssignmentOperator::AddAssign => {
|
||||||
let left_option = if manage_memory {
|
let left_option = if manage_memory {
|
||||||
@ -137,7 +141,7 @@ impl AbstractNode for Assignment {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
context.set_value(self.identifier.node, new_value)?;
|
context.set_value(self.identifier.node, new_value, scope)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableNotFound {
|
ValidationError::VariableNotFound {
|
||||||
@ -182,7 +186,7 @@ impl AbstractNode for Assignment {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
context.set_value(self.identifier.node, new_value)?;
|
context.set_value(self.identifier.node, new_value, scope)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableNotFound {
|
ValidationError::VariableNotFound {
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Statement, Type};
|
use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct AsyncBlock {
|
pub struct AsyncBlock {
|
||||||
@ -29,20 +29,26 @@ impl AbstractNode for AsyncBlock {
|
|||||||
&self,
|
&self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.define_and_validate(_context, manage_memory)?;
|
statement.define_and_validate(_context, manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate(self, _context: &Context, _: bool) -> Result<Option<Evaluation>, RuntimeError> {
|
fn evaluate(
|
||||||
|
self,
|
||||||
|
_context: &Context,
|
||||||
|
_: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let final_result = Mutex::new(Ok(None));
|
let final_result = Mutex::new(Ok(None));
|
||||||
let statement_count = self.statements.len();
|
let statement_count = self.statements.len();
|
||||||
let error_option = self.statements.into_par_iter().enumerate().find_map_any(
|
let error_option = self.statements.into_par_iter().enumerate().find_map_any(
|
||||||
|(index, statement)| -> Option<RuntimeError> {
|
|(index, statement)| -> Option<RuntimeError> {
|
||||||
let result = statement.evaluate(&_context, false);
|
let result = statement.evaluate(&_context, false, scope);
|
||||||
|
|
||||||
if let Err(error) = result {
|
if let Err(error) = result {
|
||||||
return Some(error);
|
return Some(error);
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Statement, Type};
|
use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
@ -33,9 +33,10 @@ impl AbstractNode for Block {
|
|||||||
&self,
|
&self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.define_and_validate(_context, _manage_memory)?;
|
statement.define_and_validate(_context, _manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -45,11 +46,12 @@ impl AbstractNode for Block {
|
|||||||
self,
|
self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let mut previous = None;
|
let mut previous = None;
|
||||||
|
|
||||||
for statement in self.statements {
|
for statement in self.statements {
|
||||||
previous = statement.evaluate(_context, _manage_memory)?;
|
previous = statement.evaluate(_context, _manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(previous)
|
Ok(previous)
|
||||||
@ -96,7 +98,9 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
block.evaluate(&Context::new(None), true).unwrap(),
|
block
|
||||||
|
.evaluate(&Context::new(), true, SourcePosition(0, 0))
|
||||||
|
.unwrap(),
|
||||||
Some(Evaluation::Return(Value::integer(42)))
|
Some(Evaluation::Return(Value::integer(42)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -113,7 +117,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
block.expected_type(&Context::new(None)),
|
block.expected_type(&Context::new()),
|
||||||
Ok(Some(Type::Integer))
|
Ok(Some(Type::Integer))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ impl FunctionLogic for Length {
|
|||||||
Type::Function {
|
Type::Function {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
value_parameters: Some(vec![(
|
value_parameters: Some(vec![(
|
||||||
Identifier::new("list"),
|
Identifier::from("list"),
|
||||||
Type::ListOf(Box::new(Type::Any)),
|
Type::ListOf(Box::new(Type::Any)),
|
||||||
)]),
|
)]),
|
||||||
return_type: Some(Box::new(Type::Integer)),
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
@ -93,7 +93,7 @@ impl FunctionLogic for Length {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
||||||
let value = if let Some(value) = context.get_value(&Identifier::new("input"))? {
|
let value = if let Some(value) = context.get_value(&Identifier::from("input"))? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
@ -119,13 +119,13 @@ impl FunctionLogic for ReadFile {
|
|||||||
fn r#type() -> Type {
|
fn r#type() -> Type {
|
||||||
Type::Function {
|
Type::Function {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
value_parameters: Some(vec![(Identifier::new("path"), Type::String)]),
|
value_parameters: Some(vec![(Identifier::from("path"), Type::String)]),
|
||||||
return_type: Some(Box::new(Type::String)),
|
return_type: Some(Box::new(Type::String)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
||||||
let value = if let Some(value) = context.get_value(&Identifier::new("path"))? {
|
let value = if let Some(value) = context.get_value(&Identifier::from("path"))? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
@ -173,13 +173,13 @@ impl FunctionLogic for Sleep {
|
|||||||
fn r#type() -> Type {
|
fn r#type() -> Type {
|
||||||
Type::Function {
|
Type::Function {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
value_parameters: Some(vec![(Identifier::new("milliseconds"), Type::Integer)]),
|
value_parameters: Some(vec![(Identifier::from("milliseconds"), Type::Integer)]),
|
||||||
return_type: None,
|
return_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
||||||
let value = if let Some(value) = context.get_value(&Identifier::new("milliseconds"))? {
|
let value = if let Some(value) = context.get_value(&Identifier::from("milliseconds"))? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
@ -207,13 +207,13 @@ impl FunctionLogic for WriteLine {
|
|||||||
fn r#type() -> Type {
|
fn r#type() -> Type {
|
||||||
Type::Function {
|
Type::Function {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
value_parameters: Some(vec![(Identifier::new("output"), Type::String)]),
|
value_parameters: Some(vec![(Identifier::from("output"), Type::String)]),
|
||||||
return_type: None,
|
return_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
||||||
let value = if let Some(value) = context.get_value(&Identifier::new("output"))? {
|
let value = if let Some(value) = context.get_value(&Identifier::from("output"))? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
@ -240,26 +240,26 @@ struct JsonParse;
|
|||||||
impl FunctionLogic for JsonParse {
|
impl FunctionLogic for JsonParse {
|
||||||
fn r#type() -> Type {
|
fn r#type() -> Type {
|
||||||
let type_t = Type::Generic {
|
let type_t = Type::Generic {
|
||||||
identifier: Identifier::new("T"),
|
identifier: Identifier::from("T"),
|
||||||
concrete_type: None,
|
concrete_type: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type::Function {
|
Type::Function {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
value_parameters: Some(vec![(Identifier::new("input"), type_t.clone())]),
|
value_parameters: Some(vec![(Identifier::from("input"), type_t.clone())]),
|
||||||
return_type: Some(Box::new(type_t)),
|
return_type: Some(Box::new(type_t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
fn call(context: &Context, _: bool) -> Result<Option<Value>, RuntimeError> {
|
||||||
let target_type = if let Some(r#type) = context.get_type(&Identifier::new("T"))? {
|
let target_type = if let Some(r#type) = context.get_type(&Identifier::from("T"))? {
|
||||||
r#type
|
r#type
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::BuiltInFunctionFailure("T does not exist"),
|
ValidationError::BuiltInFunctionFailure("T does not exist"),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let value = if let Some(value) = context.get_value(&Identifier::new("input"))? {
|
let value = if let Some(value) = context.get_value(&Identifier::from("input"))? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
identifier::Identifier,
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Type, TypeConstructor, WithPosition};
|
use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct EnumDeclaration {
|
pub struct EnumDeclaration {
|
||||||
@ -32,7 +32,12 @@ impl EnumDeclaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for EnumDeclaration {
|
impl AbstractNode for EnumDeclaration {
|
||||||
fn define_and_validate(&self, context: &Context, _: bool) -> Result<(), ValidationError> {
|
fn define_and_validate(
|
||||||
|
&self,
|
||||||
|
context: &Context,
|
||||||
|
_: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
let EnumDeclaration {
|
let EnumDeclaration {
|
||||||
name,
|
name,
|
||||||
type_parameters,
|
type_parameters,
|
||||||
@ -73,13 +78,25 @@ impl AbstractNode for EnumDeclaration {
|
|||||||
type_parameters,
|
type_parameters,
|
||||||
variants: type_variants,
|
variants: type_variants,
|
||||||
};
|
};
|
||||||
|
let final_node_position = if let Some(constructors) = &self.variants.last().unwrap().content
|
||||||
|
{
|
||||||
|
constructors.last().unwrap().position()
|
||||||
|
} else {
|
||||||
|
self.variants.last().unwrap().name.position
|
||||||
|
};
|
||||||
|
let scope = SourcePosition(self.name.position.0, final_node_position.1);
|
||||||
|
|
||||||
context.set_type(name.node.clone(), r#type)?;
|
context.set_type(name.node.clone(), r#type, scope)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate(self, _: &Context, _: bool) -> Result<Option<Evaluation>, RuntimeError> {
|
fn evaluate(
|
||||||
|
self,
|
||||||
|
_: &Context,
|
||||||
|
_: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +45,15 @@ impl AbstractNode for Expression {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::As(r#as) => r#as.node.define_and_validate(context, manage_memory),
|
Expression::As(r#as) => r#as.node.define_and_validate(context, manage_memory, scope),
|
||||||
Expression::FunctionCall(function_call) => function_call
|
Expression::FunctionCall(function_call) => {
|
||||||
|
function_call
|
||||||
.node
|
.node
|
||||||
.define_and_validate(context, manage_memory),
|
.define_and_validate(context, manage_memory, scope)
|
||||||
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let found = context.add_expected_use(&identifier.node)?;
|
let found = context.add_expected_use(&identifier.node)?;
|
||||||
|
|
||||||
@ -64,15 +67,25 @@ impl AbstractNode for Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::MapIndex(map_index) => {
|
Expression::MapIndex(map_index) => {
|
||||||
map_index.node.define_and_validate(context, manage_memory)
|
map_index
|
||||||
|
.node
|
||||||
|
.define_and_validate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
Expression::ListIndex(list_index) => {
|
Expression::ListIndex(list_index) => {
|
||||||
list_index.node.define_and_validate(context, manage_memory)
|
list_index
|
||||||
|
.node
|
||||||
|
.define_and_validate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
Expression::Logic(logic) => logic.node.define_and_validate(context, manage_memory),
|
Expression::Logic(logic) => {
|
||||||
Expression::Math(math) => math.node.define_and_validate(context, manage_memory),
|
logic
|
||||||
|
.node
|
||||||
|
.define_and_validate(context, manage_memory, scope)
|
||||||
|
}
|
||||||
|
Expression::Math(math) => math.node.define_and_validate(context, manage_memory, scope),
|
||||||
Expression::Value(value_node) => {
|
Expression::Value(value_node) => {
|
||||||
value_node.node.define_and_validate(context, manage_memory)
|
value_node
|
||||||
|
.node
|
||||||
|
.define_and_validate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,11 +94,12 @@ impl AbstractNode for Expression {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::As(r#as) => r#as.node.evaluate(context, manage_memory),
|
Expression::As(r#as) => r#as.node.evaluate(context, manage_memory, scope),
|
||||||
Expression::FunctionCall(function_call) => {
|
Expression::FunctionCall(function_call) => {
|
||||||
function_call.node.evaluate(context, manage_memory)
|
function_call.node.evaluate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let value_option = if manage_memory {
|
let value_option = if manage_memory {
|
||||||
@ -105,11 +119,17 @@ impl AbstractNode for Expression {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::MapIndex(map_index) => map_index.node.evaluate(context, manage_memory),
|
Expression::MapIndex(map_index) => {
|
||||||
Expression::ListIndex(list_index) => list_index.node.evaluate(context, manage_memory),
|
map_index.node.evaluate(context, manage_memory, scope)
|
||||||
Expression::Logic(logic) => logic.node.evaluate(context, manage_memory),
|
}
|
||||||
Expression::Math(math) => math.node.evaluate(context, manage_memory),
|
Expression::ListIndex(list_index) => {
|
||||||
Expression::Value(value_node) => value_node.node.evaluate(context, manage_memory),
|
list_index.node.evaluate(context, manage_memory, scope)
|
||||||
|
}
|
||||||
|
Expression::Logic(logic) => logic.node.evaluate(context, manage_memory, scope),
|
||||||
|
Expression::Math(math) => math.node.evaluate(context, manage_memory, scope),
|
||||||
|
Expression::Value(value_node) => {
|
||||||
|
value_node.node.evaluate(context, manage_memory, scope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,16 +11,13 @@ use crate::{
|
|||||||
value::ValueInner,
|
value::ValueInner,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
|
use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, TypeConstructor};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall {
|
||||||
function_expression: Box<Expression>,
|
function_expression: Box<Expression>,
|
||||||
type_arguments: Option<Vec<TypeConstructor>>,
|
type_arguments: Option<Vec<TypeConstructor>>,
|
||||||
value_arguments: Option<Vec<Expression>>,
|
value_arguments: Option<Vec<Expression>>,
|
||||||
|
|
||||||
#[serde(skip)]
|
|
||||||
context: Context,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionCall {
|
impl FunctionCall {
|
||||||
@ -33,7 +30,6 @@ impl FunctionCall {
|
|||||||
function_expression: Box::new(function_expression),
|
function_expression: Box::new(function_expression),
|
||||||
type_arguments,
|
type_arguments,
|
||||||
value_arguments,
|
value_arguments,
|
||||||
context: Context::new(None),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,21 +37,21 @@ impl FunctionCall {
|
|||||||
impl AbstractNode for FunctionCall {
|
impl AbstractNode for FunctionCall {
|
||||||
fn define_and_validate(
|
fn define_and_validate(
|
||||||
&self,
|
&self,
|
||||||
outer_context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
self.context.set_parent(outer_context.clone())?;
|
|
||||||
self.function_expression
|
self.function_expression
|
||||||
.define_and_validate(outer_context, manage_memory)?;
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
|
|
||||||
if let Some(value_arguments) = &self.value_arguments {
|
if let Some(value_arguments) = &self.value_arguments {
|
||||||
for expression in value_arguments {
|
for expression in value_arguments {
|
||||||
expression.define_and_validate(outer_context, manage_memory)?;
|
expression.define_and_validate(context, manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_node_type =
|
let function_node_type =
|
||||||
if let Some(r#type) = self.function_expression.expected_type(outer_context)? {
|
if let Some(r#type) = self.function_expression.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::ExpectedValueStatement(
|
return Err(ValidationError::ExpectedValueStatement(
|
||||||
@ -78,9 +74,9 @@ impl AbstractNode for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (identifier, constructor) in parameters.into_iter().zip(arguments.into_iter()) {
|
for (identifier, constructor) in parameters.into_iter().zip(arguments.into_iter()) {
|
||||||
let r#type = constructor.construct(outer_context)?;
|
let r#type = constructor.construct(context)?;
|
||||||
|
|
||||||
self.context.set_type(identifier, r#type)?;
|
context.set_type(identifier, r#type, self.function_expression.position())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,8 +85,7 @@ impl AbstractNode for FunctionCall {
|
|||||||
for ((identifier, _), expression) in
|
for ((identifier, _), expression) in
|
||||||
parameters.iter().zip(arguments.into_iter())
|
parameters.iter().zip(arguments.into_iter())
|
||||||
{
|
{
|
||||||
let r#type =
|
let r#type = if let Some(r#type) = expression.expected_type(context)? {
|
||||||
if let Some(r#type) = expression.expected_type(outer_context)? {
|
|
||||||
r#type
|
r#type
|
||||||
} else {
|
} else {
|
||||||
return Err(ValidationError::ExpectedValueStatement(
|
return Err(ValidationError::ExpectedValueStatement(
|
||||||
@ -98,7 +93,11 @@ impl AbstractNode for FunctionCall {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context.set_type(identifier.clone(), r#type)?;
|
context.set_type(
|
||||||
|
identifier.clone(),
|
||||||
|
r#type,
|
||||||
|
self.function_expression.position(),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if parameters.len() != arguments.len() {
|
if parameters.len() != arguments.len() {
|
||||||
@ -134,13 +133,14 @@ impl AbstractNode for FunctionCall {
|
|||||||
|
|
||||||
fn evaluate(
|
fn evaluate(
|
||||||
self,
|
self,
|
||||||
outer_context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let function_position = self.function_expression.position();
|
let function_position = self.function_expression.position();
|
||||||
let evaluation = self
|
let evaluation = self
|
||||||
.function_expression
|
.function_expression
|
||||||
.evaluate(outer_context, manage_memory)?;
|
.evaluate(context, manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -156,9 +156,9 @@ impl AbstractNode for FunctionCall {
|
|||||||
for (identifier, constructor) in
|
for (identifier, constructor) in
|
||||||
type_parameters.into_iter().zip(type_arguments.into_iter())
|
type_parameters.into_iter().zip(type_arguments.into_iter())
|
||||||
{
|
{
|
||||||
let r#type = constructor.construct(outer_context)?;
|
let r#type = constructor.construct(context)?;
|
||||||
|
|
||||||
self.context.set_type(identifier.clone(), r#type)?;
|
context.set_type(identifier.clone(), r#type, function_position)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ impl AbstractNode for FunctionCall {
|
|||||||
parameters.into_iter().zip(arguments.into_iter())
|
parameters.into_iter().zip(arguments.into_iter())
|
||||||
{
|
{
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation = expression.evaluate(outer_context, manage_memory)?;
|
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -178,11 +178,11 @@ impl AbstractNode for FunctionCall {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context.set_value(identifier.clone(), value)?;
|
context.set_value(identifier.clone(), value, function_position)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return function.clone().call(&self.context, manage_memory);
|
return function.clone().call(context, manage_memory, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() {
|
if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() {
|
||||||
@ -208,9 +208,9 @@ impl AbstractNode for FunctionCall {
|
|||||||
for (identifier, constructor) in
|
for (identifier, constructor) in
|
||||||
type_parameters.into_iter().zip(type_arguments.into_iter())
|
type_parameters.into_iter().zip(type_arguments.into_iter())
|
||||||
{
|
{
|
||||||
let r#type = constructor.construct(outer_context)?;
|
let r#type = constructor.construct(context)?;
|
||||||
|
|
||||||
self.context.set_type(identifier.clone(), r#type)?;
|
context.set_type(identifier.clone(), r#type, function_position)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ impl AbstractNode for FunctionCall {
|
|||||||
parameters.into_iter().zip(arguments.into_iter())
|
parameters.into_iter().zip(arguments.into_iter())
|
||||||
{
|
{
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation = expression.evaluate(outer_context, manage_memory)?;
|
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -228,18 +228,18 @@ impl AbstractNode for FunctionCall {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context.set_value(identifier.clone(), value)?;
|
context.set_value(identifier.clone(), value, function_position)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return function
|
return function
|
||||||
.call(&self.context, manage_memory)
|
.call(context, manage_memory)
|
||||||
.map(|option| option.map(|value| Evaluation::Return(value)));
|
.map(|option| option.map(|value| Evaluation::Return(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedFunction {
|
ValidationError::ExpectedFunction {
|
||||||
actual: value.r#type(outer_context)?,
|
actual: value.r#type(context)?,
|
||||||
position: function_position,
|
position: function_position,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
value::ValueInner,
|
value::ValueInner,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Block, Evaluation, Expression, Type, WithPosition};
|
use super::{AbstractNode, Block, Evaluation, Expression, SourcePosition, Type, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct IfElse {
|
pub struct IfElse {
|
||||||
@ -39,12 +39,13 @@ impl AbstractNode for IfElse {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
self.if_expression
|
self.if_expression
|
||||||
.define_and_validate(context, manage_memory)?;
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
self.if_block
|
self.if_block
|
||||||
.node
|
.node
|
||||||
.define_and_validate(context, manage_memory)?;
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
|
|
||||||
let if_expression_type = if let Some(r#type) = self.if_expression.expected_type(context)? {
|
let if_expression_type = if let Some(r#type) = self.if_expression.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -60,7 +61,9 @@ impl AbstractNode for IfElse {
|
|||||||
let expression_type = expression.expected_type(context)?;
|
let expression_type = expression.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(Type::Boolean) = expression_type {
|
if let Some(Type::Boolean) = expression_type {
|
||||||
block.node.define_and_validate(context, manage_memory)?;
|
block
|
||||||
|
.node
|
||||||
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
|
|
||||||
let else_if_block_type = block.node.expected_type(context)?;
|
let else_if_block_type = block.node.expected_type(context)?;
|
||||||
|
|
||||||
@ -83,7 +86,9 @@ impl AbstractNode for IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(block) = &self.else_block {
|
if let Some(block) = &self.else_block {
|
||||||
block.node.define_and_validate(context, manage_memory)?;
|
block
|
||||||
|
.node
|
||||||
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
|
|
||||||
let else_if_block_type = block.node.expected_type(context)?;
|
let else_if_block_type = block.node.expected_type(context)?;
|
||||||
|
|
||||||
@ -105,9 +110,12 @@ impl AbstractNode for IfElse {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let if_position = self.if_expression.position();
|
let if_position = self.if_expression.position();
|
||||||
let evaluation = self.if_expression.evaluate(context, _manage_memory)?;
|
let evaluation = self
|
||||||
|
.if_expression
|
||||||
|
.evaluate(context, _manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -118,13 +126,13 @@ impl AbstractNode for IfElse {
|
|||||||
|
|
||||||
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
|
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
|
||||||
if *if_boolean {
|
if *if_boolean {
|
||||||
return self.if_block.node.evaluate(context, _manage_memory);
|
return self.if_block.node.evaluate(context, _manage_memory, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(else_ifs) = self.else_ifs {
|
if let Some(else_ifs) = self.else_ifs {
|
||||||
for (expression, block) in else_ifs {
|
for (expression, block) in else_ifs {
|
||||||
let expression_position = expression.position();
|
let expression_position = expression.position();
|
||||||
let evaluation = expression.evaluate(context, _manage_memory)?;
|
let evaluation = expression.evaluate(context, _manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -135,7 +143,7 @@ impl AbstractNode for IfElse {
|
|||||||
|
|
||||||
if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
|
if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
|
||||||
if *else_if_boolean {
|
if *else_if_boolean {
|
||||||
return block.node.evaluate(context, _manage_memory);
|
return block.node.evaluate(context, _manage_memory, scope);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
@ -149,7 +157,7 @@ impl AbstractNode for IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(else_statement) = self.else_block {
|
if let Some(else_statement) = self.else_block {
|
||||||
else_statement.node.evaluate(context, _manage_memory)
|
else_statement.node.evaluate(context, _manage_memory, scope)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -214,7 +222,7 @@ mod tests {
|
|||||||
Some(Vec::with_capacity(0)),
|
Some(Vec::with_capacity(0)),
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
.evaluate(&Context::new(None), true)
|
.evaluate(&Context::new(), true, SourcePosition(0, 0))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Some(Evaluation::Return(Value::string("foo".to_string())))
|
Some(Evaluation::Return(Value::string("foo".to_string())))
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Expression, Type, ValueNode, WithPosition};
|
use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, ValueNode, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct ListIndex {
|
pub struct ListIndex {
|
||||||
@ -29,10 +29,12 @@ impl AbstractNode for ListIndex {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
self.collection
|
self.collection
|
||||||
.define_and_validate(context, _manage_memory)?;
|
.define_and_validate(context, _manage_memory, scope)?;
|
||||||
self.index.define_and_validate(context, _manage_memory)?;
|
self.index
|
||||||
|
.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let collection_type = if let Some(r#type) = self.collection.expected_type(context)? {
|
let collection_type = if let Some(r#type) = self.collection.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -77,9 +79,10 @@ impl AbstractNode for ListIndex {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_clear_variables: bool,
|
_clear_variables: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let left_position = self.collection.position();
|
let left_position = self.collection.position();
|
||||||
let left_evaluation = self.collection.evaluate(context, _clear_variables)?;
|
let left_evaluation = self.collection.evaluate(context, _clear_variables, scope)?;
|
||||||
let left_value = if let Some(Evaluation::Return(value)) = left_evaluation {
|
let left_value = if let Some(Evaluation::Return(value)) = left_evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -88,7 +91,7 @@ impl AbstractNode for ListIndex {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
let right_position = self.index.position();
|
let right_position = self.index.position();
|
||||||
let right_evaluation = self.index.evaluate(context, _clear_variables)?;
|
let right_evaluation = self.index.evaluate(context, _clear_variables, scope)?;
|
||||||
let right_value = if let Some(Evaluation::Return(value)) = right_evaluation {
|
let right_value = if let Some(Evaluation::Return(value)) = right_evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Expression, Type};
|
use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Logic {
|
pub enum Logic {
|
||||||
@ -29,6 +29,7 @@ impl AbstractNode for Logic {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Logic::Equal(left, right)
|
Logic::Equal(left, right)
|
||||||
@ -37,8 +38,8 @@ impl AbstractNode for Logic {
|
|||||||
| Logic::Less(left, right)
|
| Logic::Less(left, right)
|
||||||
| Logic::GreaterOrEqual(left, right)
|
| Logic::GreaterOrEqual(left, right)
|
||||||
| Logic::LessOrEqual(left, right) => {
|
| Logic::LessOrEqual(left, right) => {
|
||||||
left.define_and_validate(context, _manage_memory)?;
|
left.define_and_validate(context, _manage_memory, scope)?;
|
||||||
right.define_and_validate(context, _manage_memory)?;
|
right.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let left_type = if let Some(r#type) = left.expected_type(context)? {
|
let left_type = if let Some(r#type) = left.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -62,8 +63,8 @@ impl AbstractNode for Logic {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Logic::And(left, right) | Logic::Or(left, right) => {
|
Logic::And(left, right) | Logic::Or(left, right) => {
|
||||||
left.define_and_validate(context, _manage_memory)?;
|
left.define_and_validate(context, _manage_memory, scope)?;
|
||||||
right.define_and_validate(context, _manage_memory)?;
|
right.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let left_type = if let Some(r#type) = left.expected_type(context)? {
|
let left_type = if let Some(r#type) = left.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -95,7 +96,7 @@ impl AbstractNode for Logic {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Logic::Not(expression) => {
|
Logic::Not(expression) => {
|
||||||
expression.define_and_validate(context, _manage_memory)?;
|
expression.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let expression_type = if let Some(r#type) = expression.expected_type(context)? {
|
let expression_type = if let Some(r#type) = expression.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -121,10 +122,11 @@ impl AbstractNode for Logic {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let run_and_expect_value = |expression: Expression| -> Result<Value, RuntimeError> {
|
let run_and_expect_value = |expression: Expression| -> Result<Value, RuntimeError> {
|
||||||
let expression_position = expression.position();
|
let expression_position = expression.position();
|
||||||
let evaluation = expression.evaluate(&mut context.clone(), _manage_memory)?;
|
let evaluation = expression.evaluate(&mut context.clone(), _manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -138,7 +140,7 @@ impl AbstractNode for Logic {
|
|||||||
|
|
||||||
let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
|
let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
|
||||||
let expression_position = expression.position();
|
let expression_position = expression.position();
|
||||||
let evaluation = expression.evaluate(&mut context.clone(), _manage_memory)?;
|
let evaluation = expression.evaluate(&mut context.clone(), _manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -256,7 +258,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -268,7 +270,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -280,7 +282,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -292,7 +294,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -304,7 +306,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -313,7 +315,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -325,7 +327,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -334,7 +336,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -346,7 +348,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -358,7 +360,7 @@ mod tests {
|
|||||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||||
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
||||||
)
|
)
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -369,7 +371,7 @@ mod tests {
|
|||||||
Logic::Not(Expression::Value(
|
Logic::Not(Expression::Value(
|
||||||
ValueNode::Boolean(false).with_position((0, 0))
|
ValueNode::Boolean(false).with_position((0, 0))
|
||||||
))
|
))
|
||||||
.evaluate(&mut Context::new(None), true),
|
.evaluate(&mut Context::new(), true, SourcePosition(0, 0)),
|
||||||
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
Ok(Some(Evaluation::Return(Value::boolean(true))))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Statement, Type};
|
use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Loop {
|
pub struct Loop {
|
||||||
@ -29,9 +29,10 @@ impl AbstractNode for Loop {
|
|||||||
&self,
|
&self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.define_and_validate(_context, false)?;
|
statement.define_and_validate(_context, false, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -41,10 +42,11 @@ impl AbstractNode for Loop {
|
|||||||
self,
|
self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
loop {
|
loop {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
let run = statement.clone().evaluate(_context, false)?;
|
let run = statement.clone().evaluate(_context, false, scope)?;
|
||||||
|
|
||||||
if let Some(Evaluation::Break) = run {
|
if let Some(Evaluation::Break) = run {
|
||||||
return Ok(run);
|
return Ok(run);
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
value::ValueInner,
|
value::ValueInner,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Expression, Type, ValueNode, WithPosition};
|
use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, ValueNode, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct MapIndex {
|
pub struct MapIndex {
|
||||||
@ -30,9 +30,10 @@ impl AbstractNode for MapIndex {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
self.collection
|
self.collection
|
||||||
.define_and_validate(context, _manage_memory)?;
|
.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let collection_type = if let Some(r#type) = self.collection.expected_type(context)? {
|
let collection_type = if let Some(r#type) = self.collection.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -56,7 +57,8 @@ impl AbstractNode for MapIndex {
|
|||||||
if let Expression::Identifier(_) = &self.index {
|
if let Expression::Identifier(_) = &self.index {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
self.index.define_and_validate(context, _manage_memory)
|
self.index
|
||||||
|
.define_and_validate(context, _manage_memory, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,9 +66,10 @@ impl AbstractNode for MapIndex {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let collection_position = self.collection.position();
|
let collection_position = self.collection.position();
|
||||||
let evaluation = self.collection.evaluate(context, _manage_memory)?;
|
let evaluation = self.collection.evaluate(context, _manage_memory, scope)?;
|
||||||
let collection = if let Some(Evaluation::Return(value)) = evaluation {
|
let collection = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,6 +25,7 @@ impl AbstractNode for Math {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Math::Add(left, right) => {
|
Math::Add(left, right) => {
|
||||||
@ -86,11 +87,13 @@ impl AbstractNode for Math {
|
|||||||
fn evaluate(
|
fn evaluate(
|
||||||
self,
|
self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_clear_variables: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let run_and_expect_value =
|
let run_and_expect_value = |position: SourcePosition,
|
||||||
|position: SourcePosition, expression: Expression| -> Result<Value, RuntimeError> {
|
expression: Expression|
|
||||||
let evaluation = expression.evaluate(&mut _context.clone(), _clear_variables)?;
|
-> Result<Value, RuntimeError> {
|
||||||
|
let evaluation = expression.evaluate(&mut _context.clone(), _manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,9 +126,11 @@ impl AbstractTree {
|
|||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
) -> Result<Option<Value>, Vec<DustError>> {
|
) -> Result<Option<Value>, Vec<DustError>> {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
|
let global_scope = SourcePosition(0, usize::MAX);
|
||||||
|
|
||||||
for statement in &self.0 {
|
for statement in &self.0 {
|
||||||
let validation_result = statement.define_and_validate(context, manage_memory);
|
let validation_result =
|
||||||
|
statement.define_and_validate(context, manage_memory, global_scope);
|
||||||
|
|
||||||
if let Err(error) = validation_result {
|
if let Err(error) = validation_result {
|
||||||
errors.push(DustError::Validation {
|
errors.push(DustError::Validation {
|
||||||
@ -146,7 +148,7 @@ impl AbstractTree {
|
|||||||
|
|
||||||
for statement in self.0 {
|
for statement in self.0 {
|
||||||
let position = statement.position();
|
let position = statement.position();
|
||||||
let run = statement.evaluate(context, manage_memory);
|
let run = statement.evaluate(context, manage_memory, global_scope);
|
||||||
|
|
||||||
match run {
|
match run {
|
||||||
Ok(evaluation) => match evaluation {
|
Ok(evaluation) => match evaluation {
|
||||||
@ -180,9 +182,10 @@ impl AbstractNode for AbstractTree {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
for statement in &self.0 {
|
for statement in &self.0 {
|
||||||
statement.define_and_validate(context, manage_memory)?;
|
statement.define_and_validate(context, manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -192,11 +195,12 @@ impl AbstractNode for AbstractTree {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let mut previous = None;
|
let mut previous = None;
|
||||||
|
|
||||||
for statement in self.0 {
|
for statement in self.0 {
|
||||||
previous = statement.evaluate(context, manage_memory)?;
|
previous = statement.evaluate(context, manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(previous)
|
Ok(previous)
|
||||||
@ -212,12 +216,14 @@ pub trait AbstractNode {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError>;
|
) -> Result<(), ValidationError>;
|
||||||
|
|
||||||
fn evaluate(
|
fn evaluate(
|
||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError>;
|
) -> Result<Option<Evaluation>, RuntimeError>;
|
||||||
|
|
||||||
fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError>;
|
fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError>;
|
||||||
|
@ -62,35 +62,60 @@ impl AbstractNode for Statement {
|
|||||||
&self,
|
&self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
log::trace!("Validating statement at {}", self.position());
|
log::trace!("Validating statement at {}", self.position());
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment
|
Statement::Assignment(assignment) => {
|
||||||
|
assignment
|
||||||
.node
|
.node
|
||||||
.define_and_validate(_context, _manage_memory),
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
Statement::AsyncBlock(async_block) => async_block
|
}
|
||||||
|
Statement::AsyncBlock(async_block) => {
|
||||||
|
async_block
|
||||||
.node
|
.node
|
||||||
.define_and_validate(_context, _manage_memory),
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
Statement::Block(block) => block.node.define_and_validate(_context, _manage_memory),
|
}
|
||||||
|
Statement::Block(block) => {
|
||||||
|
block
|
||||||
|
.node
|
||||||
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
|
}
|
||||||
Statement::EnumDeclaration(enum_declaration) => enum_declaration
|
Statement::EnumDeclaration(enum_declaration) => enum_declaration
|
||||||
.node
|
.node
|
||||||
.define_and_validate(_context, _manage_memory),
|
.define_and_validate(_context, _manage_memory, scope),
|
||||||
Statement::Expression(expression) => {
|
Statement::Expression(expression) => {
|
||||||
expression.define_and_validate(_context, _manage_memory)
|
expression.define_and_validate(_context, _manage_memory, scope)
|
||||||
}
|
}
|
||||||
Statement::IfElse(if_else) => {
|
Statement::IfElse(if_else) => {
|
||||||
if_else.node.define_and_validate(_context, _manage_memory)
|
if_else
|
||||||
|
.node
|
||||||
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
|
}
|
||||||
|
Statement::Loop(r#loop) => {
|
||||||
|
r#loop
|
||||||
|
.node
|
||||||
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
}
|
}
|
||||||
Statement::Loop(r#loop) => r#loop.node.define_and_validate(_context, _manage_memory),
|
|
||||||
Statement::StructureDefinition(struct_definition) => struct_definition
|
Statement::StructureDefinition(struct_definition) => struct_definition
|
||||||
.node
|
.node
|
||||||
.define_and_validate(_context, _manage_memory),
|
.define_and_validate(_context, _manage_memory, scope),
|
||||||
Statement::TypeAlias(type_alias) => type_alias
|
Statement::TypeAlias(type_alias) => {
|
||||||
|
type_alias
|
||||||
.node
|
.node
|
||||||
.define_and_validate(_context, _manage_memory),
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
Statement::While(r#while) => r#while.node.define_and_validate(_context, _manage_memory),
|
}
|
||||||
Statement::Use(r#use) => r#use.node.define_and_validate(_context, _manage_memory),
|
Statement::While(r#while) => {
|
||||||
|
r#while
|
||||||
|
.node
|
||||||
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
|
}
|
||||||
|
Statement::Use(r#use) => {
|
||||||
|
r#use
|
||||||
|
.node
|
||||||
|
.define_and_validate(_context, _manage_memory, scope)
|
||||||
|
}
|
||||||
Statement::Break(_) | Statement::Null(_) => Ok(()),
|
Statement::Break(_) | Statement::Null(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,27 +124,34 @@ impl AbstractNode for Statement {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
log::trace!("Evaluating statement at {}", self.position());
|
log::trace!("Evaluating statement at {}", self.position());
|
||||||
|
|
||||||
let result = match self {
|
let result = match self {
|
||||||
Statement::Assignment(assignment) => assignment.node.evaluate(context, manage_memory),
|
Statement::Assignment(assignment) => {
|
||||||
Statement::AsyncBlock(async_block) => async_block.node.evaluate(context, manage_memory),
|
assignment.node.evaluate(context, manage_memory, scope)
|
||||||
Statement::Block(block) => block.node.evaluate(context, manage_memory),
|
}
|
||||||
|
Statement::AsyncBlock(async_block) => {
|
||||||
|
async_block.node.evaluate(context, manage_memory, scope)
|
||||||
|
}
|
||||||
|
Statement::Block(block) => block.node.evaluate(context, manage_memory, scope),
|
||||||
Statement::Break(_) => Ok(Some(Evaluation::Break)),
|
Statement::Break(_) => Ok(Some(Evaluation::Break)),
|
||||||
Statement::Expression(expression) => expression.evaluate(context, manage_memory),
|
Statement::Expression(expression) => expression.evaluate(context, manage_memory, scope),
|
||||||
Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory),
|
Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory, scope),
|
||||||
Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory),
|
Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory, scope),
|
||||||
Statement::Null(_) => Ok(None),
|
Statement::Null(_) => Ok(None),
|
||||||
Statement::StructureDefinition(structure_definition) => {
|
Statement::StructureDefinition(structure_definition) => structure_definition
|
||||||
structure_definition.node.evaluate(context, manage_memory)
|
.node
|
||||||
|
.evaluate(context, manage_memory, scope),
|
||||||
|
Statement::TypeAlias(type_alias) => {
|
||||||
|
type_alias.node.evaluate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
Statement::TypeAlias(type_alias) => type_alias.node.evaluate(context, manage_memory),
|
|
||||||
Statement::EnumDeclaration(type_alias) => {
|
Statement::EnumDeclaration(type_alias) => {
|
||||||
type_alias.node.evaluate(context, manage_memory)
|
type_alias.node.evaluate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
Statement::While(r#while) => r#while.node.evaluate(context, manage_memory),
|
Statement::While(r#while) => r#while.node.evaluate(context, manage_memory, scope),
|
||||||
Statement::Use(r#use) => r#use.node.evaluate(context, manage_memory),
|
Statement::Use(r#use) => r#use.node.evaluate(context, manage_memory, scope),
|
||||||
};
|
};
|
||||||
|
|
||||||
if manage_memory {
|
if manage_memory {
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
identifier::Identifier,
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Type, TypeConstructor};
|
use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct StructureDefinition {
|
pub struct StructureDefinition {
|
||||||
@ -23,7 +23,12 @@ impl StructureDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for StructureDefinition {
|
impl AbstractNode for StructureDefinition {
|
||||||
fn define_and_validate(&self, context: &Context, _: bool) -> Result<(), ValidationError> {
|
fn define_and_validate(
|
||||||
|
&self,
|
||||||
|
context: &Context,
|
||||||
|
_: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
let mut fields = Vec::with_capacity(self.fields.len());
|
let mut fields = Vec::with_capacity(self.fields.len());
|
||||||
|
|
||||||
for (identifier, constructor) in &self.fields {
|
for (identifier, constructor) in &self.fields {
|
||||||
@ -37,7 +42,7 @@ impl AbstractNode for StructureDefinition {
|
|||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_type(self.name.clone(), struct_type)?;
|
context.set_type(self.name.clone(), struct_type, scope)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -46,6 +51,7 @@ impl AbstractNode for StructureDefinition {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let mut fields = Vec::with_capacity(self.fields.len());
|
let mut fields = Vec::with_capacity(self.fields.len());
|
||||||
|
|
||||||
@ -60,7 +66,7 @@ impl AbstractNode for StructureDefinition {
|
|||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_type(self.name, struct_type)?;
|
context.set_type(self.name, struct_type, scope)?;
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -325,9 +325,9 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = BTreeMap::new();
|
let mut map = BTreeMap::new();
|
||||||
|
|
||||||
map.insert(Identifier::new("x"), Type::Integer);
|
map.insert(Identifier::from("x"), Type::Integer);
|
||||||
map.insert(Identifier::new("y"), Type::String);
|
map.insert(Identifier::from("y"), Type::String);
|
||||||
map.insert(Identifier::new("z"), Type::Map(map.clone()));
|
map.insert(Identifier::from("z"), Type::Map(map.clone()));
|
||||||
|
|
||||||
assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(()));
|
assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(()));
|
||||||
assert_eq!(Type::Range.check(&Type::Range), Ok(()));
|
assert_eq!(Type::Range.check(&Type::Range), Ok(()));
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
identifier::Identifier,
|
identifier::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Type, TypeConstructor, WithPosition};
|
use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct TypeAlias {
|
pub struct TypeAlias {
|
||||||
@ -26,15 +26,25 @@ impl TypeAlias {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for TypeAlias {
|
impl AbstractNode for TypeAlias {
|
||||||
fn define_and_validate(&self, context: &Context, _: bool) -> Result<(), ValidationError> {
|
fn define_and_validate(
|
||||||
|
&self,
|
||||||
|
context: &Context,
|
||||||
|
_: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
let r#type = self.constructor.construct(&context)?;
|
let r#type = self.constructor.construct(&context)?;
|
||||||
|
|
||||||
context.set_type(self.identifier.node.clone(), r#type)?;
|
context.set_type(self.identifier.node.clone(), r#type, scope)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate(self, _: &Context, _: bool) -> Result<Option<Evaluation>, RuntimeError> {
|
fn evaluate(
|
||||||
|
self,
|
||||||
|
_: &Context,
|
||||||
|
_: bool,
|
||||||
|
_: SourcePosition,
|
||||||
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use crate::{
|
|||||||
Type,
|
Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, AbstractTree, Evaluation};
|
use super::{AbstractNode, AbstractTree, Evaluation, SourcePosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Use {
|
pub struct Use {
|
||||||
@ -41,6 +41,7 @@ impl AbstractNode for Use {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
let abstract_tree = match self.path.as_str() {
|
let abstract_tree = match self.path.as_str() {
|
||||||
"std.fs" => std_fs_compiled().clone(),
|
"std.fs" => std_fs_compiled().clone(),
|
||||||
@ -59,7 +60,7 @@ impl AbstractNode for Use {
|
|||||||
*self.abstract_tree.write()? = Some(abstract_tree);
|
*self.abstract_tree.write()? = Some(abstract_tree);
|
||||||
|
|
||||||
if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() {
|
if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() {
|
||||||
abstract_tree.define_and_validate(context, manage_memory)
|
abstract_tree.define_and_validate(context, manage_memory, scope)
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::Uninitialized)
|
Err(ValidationError::Uninitialized)
|
||||||
}
|
}
|
||||||
@ -69,9 +70,12 @@ impl AbstractNode for Use {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() {
|
if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() {
|
||||||
abstract_tree.clone().evaluate(context, manage_memory)
|
abstract_tree
|
||||||
|
.clone()
|
||||||
|
.evaluate(context, manage_memory, scope)
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::Uninitialized,
|
ValidationError::Uninitialized,
|
||||||
|
@ -15,8 +15,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AbstractNode, Block, BuiltInFunction, Evaluation, Expression, Type, TypeConstructor, WithPos,
|
AbstractNode, Block, BuiltInFunction, Evaluation, Expression, SourcePosition, Type,
|
||||||
WithPosition,
|
TypeConstructor, WithPos, WithPosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -53,7 +53,6 @@ impl ValueNode {
|
|||||||
value_parameters,
|
value_parameters,
|
||||||
return_type,
|
return_type,
|
||||||
body,
|
body,
|
||||||
validation_context: Context::new(None),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,6 +62,7 @@ impl AbstractNode for ValueNode {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
if let ValueNode::List(list) = self {
|
if let ValueNode::List(list) = self {
|
||||||
let mut items = list.into_iter();
|
let mut items = list.into_iter();
|
||||||
@ -76,7 +76,7 @@ impl AbstractNode for ValueNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
item.define_and_validate(context, _manage_memory)?;
|
item.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let item_type = if let Some(r#type) = item.expected_type(context)? {
|
let item_type = if let Some(r#type) = item.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -102,7 +102,7 @@ impl AbstractNode for ValueNode {
|
|||||||
{
|
{
|
||||||
if let Some(expressions) = content {
|
if let Some(expressions) = content {
|
||||||
for expression in expressions {
|
for expression in expressions {
|
||||||
expression.define_and_validate(context, _manage_memory)?;
|
expression.define_and_validate(context, _manage_memory, scope)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ impl AbstractNode for ValueNode {
|
|||||||
|
|
||||||
if let ValueNode::Map(map_assignments) = self {
|
if let ValueNode::Map(map_assignments) = self {
|
||||||
for (_identifier, constructor_option, expression) in map_assignments {
|
for (_identifier, constructor_option, expression) in map_assignments {
|
||||||
expression.define_and_validate(context, _manage_memory)?;
|
expression.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
if let Some(constructor) = constructor_option {
|
if let Some(constructor) = constructor_option {
|
||||||
let actual_type = if let Some(r#type) = expression.expected_type(context)? {
|
let actual_type = if let Some(r#type) = expression.expected_type(context)? {
|
||||||
@ -155,45 +155,38 @@ impl AbstractNode for ValueNode {
|
|||||||
if let ValueNode::Function(FunctionNode {
|
if let ValueNode::Function(FunctionNode {
|
||||||
return_type,
|
return_type,
|
||||||
body,
|
body,
|
||||||
validation_context,
|
|
||||||
type_parameters,
|
type_parameters,
|
||||||
value_parameters,
|
value_parameters,
|
||||||
}) = self
|
}) = self
|
||||||
{
|
{
|
||||||
let outer_context = context;
|
|
||||||
|
|
||||||
validation_context.set_parent(outer_context.clone())?;
|
|
||||||
|
|
||||||
if let Some(type_parameters) = type_parameters {
|
if let Some(type_parameters) = type_parameters {
|
||||||
for identifier in type_parameters {
|
for identifier in type_parameters {
|
||||||
validation_context.set_type(
|
context.set_type(
|
||||||
identifier.clone(),
|
identifier.clone(),
|
||||||
Type::Generic {
|
Type::Generic {
|
||||||
identifier: identifier.clone(),
|
identifier: identifier.clone(),
|
||||||
concrete_type: None,
|
concrete_type: None,
|
||||||
},
|
},
|
||||||
|
body.position,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value_parameters) = value_parameters {
|
if let Some(value_parameters) = value_parameters {
|
||||||
for (identifier, type_constructor) in value_parameters {
|
for (identifier, type_constructor) in value_parameters {
|
||||||
let r#type = type_constructor.clone().construct(outer_context)?;
|
let r#type = type_constructor.clone().construct(context)?;
|
||||||
|
|
||||||
validation_context.set_type(identifier.clone(), r#type)?;
|
context.set_type(identifier.clone(), r#type, body.position)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.node
|
body.node
|
||||||
.define_and_validate(&validation_context, _manage_memory)?;
|
.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let ((expected_return, expected_position), actual_return) =
|
let ((expected_return, expected_position), actual_return) =
|
||||||
match (return_type, body.node.expected_type(&validation_context)?) {
|
match (return_type, body.node.expected_type(context)?) {
|
||||||
(Some(constructor), Some(r#type)) => (
|
(Some(constructor), Some(r#type)) => (
|
||||||
(
|
(constructor.construct(context)?, constructor.position()),
|
||||||
constructor.construct(validation_context)?,
|
|
||||||
constructor.position(),
|
|
||||||
),
|
|
||||||
r#type,
|
r#type,
|
||||||
),
|
),
|
||||||
(None, Some(_)) => {
|
(None, Some(_)) => {
|
||||||
@ -238,7 +231,7 @@ impl AbstractNode for ValueNode {
|
|||||||
}) = context.get_type(&name.node)?
|
}) = context.get_type(&name.node)?
|
||||||
{
|
{
|
||||||
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
|
for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) {
|
||||||
expression.define_and_validate(context, _manage_memory)?;
|
expression.define_and_validate(context, _manage_memory, scope)?;
|
||||||
|
|
||||||
let actual_type = if let Some(r#type) = expression.expected_type(context)? {
|
let actual_type = if let Some(r#type) = expression.expected_type(context)? {
|
||||||
r#type
|
r#type
|
||||||
@ -266,6 +259,7 @@ impl AbstractNode for ValueNode {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||||
@ -279,7 +273,7 @@ impl AbstractNode for ValueNode {
|
|||||||
|
|
||||||
for expression in expressions {
|
for expression in expressions {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation = expression.evaluate(context, manage_memory)?;
|
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||||
|
|
||||||
if let Some(Evaluation::Return(value)) = evaluation {
|
if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
values.push(value);
|
values.push(value);
|
||||||
@ -303,7 +297,7 @@ impl AbstractNode for ValueNode {
|
|||||||
|
|
||||||
for expression in expression_list {
|
for expression in expression_list {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation = expression.evaluate(context, manage_memory)?;
|
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -322,7 +316,7 @@ impl AbstractNode for ValueNode {
|
|||||||
|
|
||||||
for (identifier, _type, expression) in property_list {
|
for (identifier, _type, expression) in property_list {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation = expression.evaluate(context, manage_memory)?;
|
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -375,7 +369,7 @@ impl AbstractNode for ValueNode {
|
|||||||
|
|
||||||
for (identifier, expression) in expressions {
|
for (identifier, expression) in expressions {
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation = expression.evaluate(context, manage_memory)?;
|
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
@ -703,7 +697,6 @@ impl Display for ValueNode {
|
|||||||
value_parameters,
|
value_parameters,
|
||||||
return_type,
|
return_type,
|
||||||
body,
|
body,
|
||||||
validation_context: _,
|
|
||||||
}) => {
|
}) => {
|
||||||
write!(f, "fn ")?;
|
write!(f, "fn ")?;
|
||||||
|
|
||||||
@ -743,8 +736,6 @@ pub struct FunctionNode {
|
|||||||
value_parameters: Option<Vec<(Identifier, TypeConstructor)>>,
|
value_parameters: Option<Vec<(Identifier, TypeConstructor)>>,
|
||||||
return_type: Option<TypeConstructor>,
|
return_type: Option<TypeConstructor>,
|
||||||
body: WithPosition<Block>,
|
body: WithPosition<Block>,
|
||||||
#[serde(skip)]
|
|
||||||
validation_context: Context,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for FunctionNode {
|
impl PartialEq for FunctionNode {
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractNode, Evaluation, Expression, Statement, Type};
|
use super::{AbstractNode, Evaluation, Expression, SourcePosition, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct While {
|
pub struct While {
|
||||||
@ -31,11 +31,13 @@ impl AbstractNode for While {
|
|||||||
&self,
|
&self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
self.expression.define_and_validate(_context, false)?;
|
self.expression
|
||||||
|
.define_and_validate(_context, false, scope)?;
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.define_and_validate(_context, false)?;
|
statement.define_and_validate(_context, false, scope)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -45,13 +47,14 @@ impl AbstractNode for While {
|
|||||||
self,
|
self,
|
||||||
_context: &Context,
|
_context: &Context,
|
||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let get_boolean = || -> Result<Value, RuntimeError> {
|
let get_boolean = || -> Result<Value, RuntimeError> {
|
||||||
let expression_position = self.expression.position();
|
let expression_position = self.expression.position();
|
||||||
let evaluation = self
|
let evaluation =
|
||||||
.expression
|
self.expression
|
||||||
.clone()
|
.clone()
|
||||||
.evaluate(&mut _context.clone(), false)?;
|
.evaluate(&mut _context.clone(), false, scope)?;
|
||||||
|
|
||||||
if let Some(Evaluation::Return(value)) = evaluation {
|
if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
@ -64,7 +67,9 @@ impl AbstractNode for While {
|
|||||||
|
|
||||||
while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() {
|
while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() {
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
let evaluation = statement.clone().evaluate(&mut _context.clone(), false)?;
|
let evaluation = statement
|
||||||
|
.clone()
|
||||||
|
.evaluate(&mut _context.clone(), false, scope)?;
|
||||||
|
|
||||||
if let Some(Evaluation::Break) = evaluation {
|
if let Some(Evaluation::Break) = evaluation {
|
||||||
return Ok(evaluation);
|
return Ok(evaluation);
|
||||||
|
@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::Type,
|
abstract_tree::{SourcePosition, Type},
|
||||||
error::{PoisonError, ValidationError},
|
error::{PoisonError, ValidationError},
|
||||||
identifier::Identifier,
|
identifier::Identifier,
|
||||||
standard_library::core_context,
|
standard_library::core_context,
|
||||||
@ -15,132 +15,63 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
data: Arc<RwLock<ContextData>>,
|
variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData, SourcePosition)>>>,
|
||||||
is_clean: Arc<RwLock<bool>>,
|
is_clean: Arc<RwLock<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct ContextData {
|
|
||||||
variables: HashMap<Identifier, (VariableData, UsageData)>,
|
|
||||||
parent: Option<Context>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new(parent: Option<Context>) -> Self {
|
pub fn new() -> Self {
|
||||||
Context {
|
Context {
|
||||||
data: Arc::new(RwLock::new(ContextData {
|
variables: Arc::new(RwLock::new(HashMap::new())),
|
||||||
variables: HashMap::new(),
|
|
||||||
parent,
|
|
||||||
})),
|
|
||||||
is_clean: Arc::new(RwLock::new(true)),
|
is_clean: Arc::new(RwLock::new(true)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_std_core(parent: Option<Context>) -> Result<Self, PoisonError> {
|
pub fn new_with_std_core() -> Result<Self, PoisonError> {
|
||||||
let new = Context::with_variables_from(core_context())?;
|
let new = Context::with_variables_from(core_context())?;
|
||||||
|
|
||||||
if let Some(context) = parent {
|
|
||||||
new.set_parent(context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(new)
|
Ok(new)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_variables_from(other: &Context) -> Result<Self, PoisonError> {
|
pub fn with_variables_from(other: &Context) -> Result<Self, PoisonError> {
|
||||||
let variables = other.data.read()?.variables.clone();
|
let variables = other.variables.read()?.clone();
|
||||||
|
|
||||||
Ok(Context {
|
Ok(Context {
|
||||||
data: Arc::new(RwLock::new(ContextData {
|
variables: Arc::new(RwLock::new(variables)),
|
||||||
variables,
|
|
||||||
parent: None,
|
|
||||||
})),
|
|
||||||
is_clean: Arc::new(RwLock::new(true)),
|
is_clean: Arc::new(RwLock::new(true)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_child(&self) -> Context {
|
pub fn contains(
|
||||||
Context::new(Some(self.clone()))
|
&self,
|
||||||
}
|
identifier: &Identifier,
|
||||||
|
scope: SourcePosition,
|
||||||
pub fn set_parent(&self, parent: Context) -> Result<(), PoisonError> {
|
) -> Result<bool, ValidationError> {
|
||||||
self.data.write()?.parent = Some(parent);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn contains(&self, identifier: &Identifier) -> Result<bool, ValidationError> {
|
|
||||||
log::trace!("Checking that {identifier} exists");
|
log::trace!("Checking that {identifier} exists");
|
||||||
|
|
||||||
let data = self.data.read()?;
|
let variables = self.variables.read()?;
|
||||||
|
|
||||||
|
if let Some((_, _, variable_scope)) = variables.get(identifier) {
|
||||||
|
if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(_) = data.variables.get(identifier) {
|
|
||||||
Ok(true)
|
|
||||||
} else if let Some(parent) = &data.parent {
|
|
||||||
parent.contains_inheritable(identifier)
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_inheritable(&self, identifier: &Identifier) -> Result<bool, ValidationError> {
|
|
||||||
let data = self.data.read()?;
|
|
||||||
|
|
||||||
if let Some((variable_data, _)) = data.variables.get(identifier) {
|
|
||||||
match variable_data {
|
|
||||||
VariableData::Type(Type::Enum { .. })
|
|
||||||
| VariableData::Type(Type::Function { .. })
|
|
||||||
| VariableData::Type(Type::Structure { .. }) => return Ok(true),
|
|
||||||
VariableData::Value(value) => match value.inner().as_ref() {
|
|
||||||
ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => return Ok(true),
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = &data.parent {
|
|
||||||
parent.contains_inheritable(identifier)
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
|
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
|
||||||
log::trace!("Getting {identifier}'s type");
|
log::trace!("Getting {identifier}'s type");
|
||||||
|
|
||||||
let data = self.data.read()?;
|
let variables = self.variables.read()?;
|
||||||
|
|
||||||
if let Some((data, _)) = data.variables.get(identifier) {
|
if let Some((data, _, _)) = variables.get(identifier) {
|
||||||
let r#type = match data {
|
let r#type = match data {
|
||||||
VariableData::Type(r#type) => r#type.clone(),
|
VariableData::Type(r#type) => r#type.clone(),
|
||||||
VariableData::Value(value) => value.r#type(self)?,
|
VariableData::Value(value) => value.r#type(self)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(r#type.clone()))
|
Ok(Some(r#type.clone()))
|
||||||
} else if let Some(parent) = &data.parent {
|
|
||||||
parent.get_inheritable_type(identifier)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_inheritable_type(
|
|
||||||
&self,
|
|
||||||
identifier: &Identifier,
|
|
||||||
) -> Result<Option<Type>, ValidationError> {
|
|
||||||
let data = self.data.read()?;
|
|
||||||
|
|
||||||
if let Some(r#type) = self.get_type(identifier)? {
|
|
||||||
match r#type {
|
|
||||||
Type::Enum { .. } | Type::Function { .. } | Type::Structure { .. } => {
|
|
||||||
return Ok(Some(r#type))
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = &data.parent {
|
|
||||||
parent.get_inheritable_type(identifier)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -149,37 +80,13 @@ impl Context {
|
|||||||
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
|
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
|
||||||
log::trace!("Using {identifier}'s value");
|
log::trace!("Using {identifier}'s value");
|
||||||
|
|
||||||
let data = self.data.read()?;
|
let variables = self.variables.read()?;
|
||||||
|
|
||||||
if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) {
|
if let Some((VariableData::Value(value), usage_data, _)) = variables.get(identifier) {
|
||||||
usage_data.inner().write()?.actual += 1;
|
usage_data.inner().write()?.actual += 1;
|
||||||
*self.is_clean.write()? = false;
|
*self.is_clean.write()? = false;
|
||||||
|
|
||||||
return Ok(Some(value.clone()));
|
return Ok(Some(value.clone()));
|
||||||
} else if let Some(parent) = &data.parent {
|
|
||||||
parent.use_inheritable_value(identifier)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn use_inheritable_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
|
|
||||||
let data = self.data.read()?;
|
|
||||||
|
|
||||||
if let Some((VariableData::Value(value), usage_data)) = data.variables.get(identifier) {
|
|
||||||
match value.inner().as_ref() {
|
|
||||||
ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => {
|
|
||||||
usage_data.inner().write()?.actual += 1;
|
|
||||||
*self.is_clean.write()? = false;
|
|
||||||
|
|
||||||
return Ok(Some(value.clone()));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = &data.parent {
|
|
||||||
parent.use_inheritable_value(identifier)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -188,62 +95,49 @@ impl Context {
|
|||||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
|
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
|
||||||
log::trace!("Getting {identifier}'s value");
|
log::trace!("Getting {identifier}'s value");
|
||||||
|
|
||||||
let data = self.data.read()?;
|
let variables = self.variables.read()?;
|
||||||
|
|
||||||
if let Some((VariableData::Value(value), _)) = data.variables.get(identifier) {
|
if let Some((VariableData::Value(value), _, _)) = variables.get(identifier) {
|
||||||
Ok(Some(value.clone()))
|
Ok(Some(value.clone()))
|
||||||
} else if let Some(parent) = &data.parent {
|
|
||||||
parent.get_inheritable_value(identifier)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_inheritable_value(&self, identifier: &Identifier) -> Result<Option<Value>, PoisonError> {
|
pub fn set_type(
|
||||||
if let Some(value) = self.get_value(identifier)? {
|
&self,
|
||||||
match value.inner().as_ref() {
|
identifier: Identifier,
|
||||||
ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => return Ok(Some(value)),
|
r#type: Type,
|
||||||
_ => {}
|
scope: SourcePosition,
|
||||||
}
|
) -> Result<(), PoisonError> {
|
||||||
}
|
|
||||||
|
|
||||||
let data = self.data.read()?;
|
|
||||||
|
|
||||||
if let Some(parent) = &data.parent {
|
|
||||||
parent.get_inheritable_value(identifier)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), PoisonError> {
|
|
||||||
log::debug!("Setting {identifier} to type {}", r#type);
|
log::debug!("Setting {identifier} to type {}", r#type);
|
||||||
|
|
||||||
let mut data = self.data.write()?;
|
let mut variables = self.variables.write()?;
|
||||||
let usage_data = data
|
let (usage_data, scope) = variables
|
||||||
.variables
|
|
||||||
.remove(&identifier)
|
.remove(&identifier)
|
||||||
.map(|(_, usage_data)| usage_data)
|
.map(|(_, old_usage_data, old_scope)| (old_usage_data, old_scope))
|
||||||
.unwrap_or_else(|| UsageData::new());
|
.unwrap_or_else(|| (UsageData::new(), scope));
|
||||||
|
|
||||||
data.variables
|
variables.insert(identifier, (VariableData::Type(r#type), usage_data, scope));
|
||||||
.insert(identifier, (VariableData::Type(r#type), usage_data));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), PoisonError> {
|
pub fn set_value(
|
||||||
|
&self,
|
||||||
|
identifier: Identifier,
|
||||||
|
value: Value,
|
||||||
|
scope: SourcePosition,
|
||||||
|
) -> Result<(), PoisonError> {
|
||||||
log::debug!("Setting {identifier} to value {value}");
|
log::debug!("Setting {identifier} to value {value}");
|
||||||
|
|
||||||
let mut data = self.data.write()?;
|
let mut variables = self.variables.write()?;
|
||||||
let usage_data = data
|
let (usage_data, scope) = variables
|
||||||
.variables
|
|
||||||
.remove(&identifier)
|
.remove(&identifier)
|
||||||
.map(|(_, usage_data)| usage_data)
|
.map(|(_, old_usage_data, old_scope)| (old_usage_data, old_scope))
|
||||||
.unwrap_or_else(|| UsageData::new());
|
.unwrap_or_else(|| (UsageData::new(), scope));
|
||||||
|
|
||||||
data.variables
|
variables.insert(identifier, (VariableData::Value(value), usage_data, scope));
|
||||||
.insert(identifier, (VariableData::Value(value), usage_data));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -251,48 +145,12 @@ impl Context {
|
|||||||
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, PoisonError> {
|
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, PoisonError> {
|
||||||
log::trace!("Adding expected use for variable {identifier}");
|
log::trace!("Adding expected use for variable {identifier}");
|
||||||
|
|
||||||
let data = self.data.read()?;
|
let variables = self.variables.read()?;
|
||||||
|
|
||||||
if let Some((_, usage_data)) = data.variables.get(identifier) {
|
if let Some((_, usage_data, _)) = variables.get(identifier) {
|
||||||
usage_data.inner().write()?.expected += 1;
|
usage_data.inner().write()?.expected += 1;
|
||||||
|
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else if let Some(parent) = &data.parent {
|
|
||||||
parent.add_expected_use_for_inheritable(identifier)
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_expected_use_for_inheritable(
|
|
||||||
&self,
|
|
||||||
identifier: &Identifier,
|
|
||||||
) -> Result<bool, PoisonError> {
|
|
||||||
let data = self.data.read()?;
|
|
||||||
|
|
||||||
if let Some((variable_data, usage_data)) = data.variables.get(identifier) {
|
|
||||||
match variable_data {
|
|
||||||
VariableData::Type(Type::Enum { .. })
|
|
||||||
| VariableData::Type(Type::Function { .. })
|
|
||||||
| VariableData::Type(Type::Structure { .. }) => {
|
|
||||||
usage_data.inner().write()?.expected += 1;
|
|
||||||
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
VariableData::Value(value) => match value.inner().as_ref() {
|
|
||||||
ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => {
|
|
||||||
usage_data.inner().write()?.expected += 1;
|
|
||||||
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = &data.parent {
|
|
||||||
parent.add_expected_use_for_inheritable(identifier)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
@ -303,8 +161,8 @@ impl Context {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.data.write()?.variables.retain(
|
self.variables.write()?.retain(
|
||||||
|identifier, (value_data, usage_data)| match value_data {
|
|identifier, (value_data, usage_data, _)| match value_data {
|
||||||
VariableData::Type(_) => true,
|
VariableData::Type(_) => true,
|
||||||
VariableData::Value(_) => {
|
VariableData::Value(_) => {
|
||||||
let usage = usage_data.inner().read().unwrap();
|
let usage = usage_data.inner().read().unwrap();
|
||||||
@ -332,7 +190,7 @@ impl Context {
|
|||||||
|
|
||||||
impl Default for Context {
|
impl Default for Context {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Context::new(None)
|
Context::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,40 +1,46 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
|
hash::{Hash, Hasher},
|
||||||
sync::{Arc, OnceLock, RwLock},
|
sync::{Arc, OnceLock, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{de::Visitor, Deserialize, Serialize};
|
use serde::{de::Visitor, Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::abstract_tree::SourcePosition;
|
||||||
|
|
||||||
static IDENTIFIER_CACHE: OnceLock<RwLock<HashMap<String, Identifier>>> = OnceLock::new();
|
static IDENTIFIER_CACHE: OnceLock<RwLock<HashMap<String, Identifier>>> = OnceLock::new();
|
||||||
|
|
||||||
fn identifier_cache<'a>() -> &'a RwLock<HashMap<String, Identifier>> {
|
fn identifier_cache<'a>() -> &'a RwLock<HashMap<String, Identifier>> {
|
||||||
IDENTIFIER_CACHE.get_or_init(|| RwLock::new(HashMap::new()))
|
IDENTIFIER_CACHE.get_or_init(|| RwLock::new(HashMap::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Identifier(Arc<String>);
|
pub struct Identifier(Arc<String>);
|
||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
pub fn new(text: &str) -> Self {
|
pub fn new(text: &str, scope: Option<SourcePosition>) -> Self {
|
||||||
let cache = identifier_cache();
|
let cache = identifier_cache();
|
||||||
|
|
||||||
if let Some(identifier) = cache.read().unwrap().get(text) {
|
if let Some(identifier) = cache.read().unwrap().get(text).cloned() {
|
||||||
return identifier.clone();
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
let identifier = Identifier(Arc::new(text.to_string()));
|
let new = Identifier(Arc::new(text.to_string()));
|
||||||
|
|
||||||
cache
|
cache.write().unwrap().insert(text.to_string(), new.clone());
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(text.to_string(), identifier.clone());
|
|
||||||
|
|
||||||
identifier
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
self.0.as_str()
|
&self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Identifier {
|
||||||
|
fn from(text: &str) -> Self {
|
||||||
|
Identifier::new(text, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +88,7 @@ impl<'de> Visitor<'de> for IdentifierVisitor {
|
|||||||
where
|
where
|
||||||
E: serde::de::Error,
|
E: serde::de::Error,
|
||||||
{
|
{
|
||||||
Ok(Identifier::new(v))
|
Ok(Identifier::new(v, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
||||||
|
@ -24,7 +24,7 @@ use lexer::{lex, Token};
|
|||||||
use parser::{parse, parser};
|
use parser::{parse, parser};
|
||||||
|
|
||||||
pub fn interpret(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
|
pub fn interpret(source_id: &str, source: &str) -> Result<Option<Value>, InterpreterError> {
|
||||||
let interpreter = Interpreter::new(Context::new(None));
|
let interpreter = Interpreter::new(Context::new());
|
||||||
|
|
||||||
interpreter.run(Arc::from(source_id), Arc::from(source))
|
interpreter.run(Arc::from(source_id), Arc::from(source))
|
||||||
}
|
}
|
||||||
@ -448,7 +448,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_standard_library() {
|
fn load_standard_library() {
|
||||||
let context = Context::new(None);
|
let context = Context::new();
|
||||||
|
|
||||||
for abstract_tree in std_full_compiled() {
|
for abstract_tree in std_full_compiled() {
|
||||||
abstract_tree.run(&context, true).unwrap();
|
abstract_tree.run(&context, true).unwrap();
|
||||||
|
@ -42,7 +42,7 @@ pub fn parser<'src>(
|
|||||||
Token::Comment(_) => {}
|
Token::Comment(_) => {}
|
||||||
};
|
};
|
||||||
let identifier = select! {
|
let identifier = select! {
|
||||||
Token::Identifier(text) => Identifier::new(text),
|
Token::Identifier(text) => Identifier::from(text),
|
||||||
};
|
};
|
||||||
|
|
||||||
let positioned_identifier = identifier
|
let positioned_identifier = identifier
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{AbstractNode, AbstractTree},
|
abstract_tree::{AbstractNode, AbstractTree, SourcePosition},
|
||||||
context::Context,
|
context::Context,
|
||||||
lexer::lex,
|
lexer::lex,
|
||||||
parser,
|
parser,
|
||||||
@ -28,14 +28,15 @@ static CORE_CONTEXT: OnceLock<Context> = OnceLock::new();
|
|||||||
|
|
||||||
pub fn core_context<'a>() -> &'a Context {
|
pub fn core_context<'a>() -> &'a Context {
|
||||||
CORE_CONTEXT.get_or_init(|| {
|
CORE_CONTEXT.get_or_init(|| {
|
||||||
let context = Context::new(None);
|
let context = Context::new();
|
||||||
let std_core = std_core_compiled().clone();
|
let std_core = std_core_compiled().clone();
|
||||||
|
let global_scope = SourcePosition(0, usize::MAX);
|
||||||
|
|
||||||
std_core
|
std_core
|
||||||
.define_and_validate(&context, true)
|
.define_and_validate(&context, true, global_scope)
|
||||||
.expect("Failed to validate std.core");
|
.expect("Failed to validate std.core");
|
||||||
std_core
|
std_core
|
||||||
.evaluate(&context, true)
|
.evaluate(&context, true, global_scope)
|
||||||
.expect("Failed to evaluate std.core");
|
.expect("Failed to evaluate std.core");
|
||||||
|
|
||||||
context
|
context
|
||||||
|
@ -14,7 +14,9 @@ use serde::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{AbstractNode, Block, BuiltInFunction, Evaluation, Type, WithPosition},
|
abstract_tree::{
|
||||||
|
AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition, Type, WithPosition,
|
||||||
|
},
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
identifier::Identifier,
|
identifier::Identifier,
|
||||||
@ -778,7 +780,10 @@ impl Function {
|
|||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
manage_memory: bool,
|
manage_memory: bool,
|
||||||
|
scope: SourcePosition,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
self.body.evaluate(context, manage_memory)
|
self.body
|
||||||
|
.define_and_validate(context, manage_memory, scope)?;
|
||||||
|
self.body.evaluate(context, manage_memory, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ fn main() {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let context = Context::new_with_std_core(None).unwrap();
|
let context = Context::new_with_std_core().unwrap();
|
||||||
let interpreter = Interpreter::new(context.clone());
|
let interpreter = Interpreter::new(context.clone());
|
||||||
|
|
||||||
let (source_id, source): (Arc<str>, Arc<str>) = if let Some(path) = args.path {
|
let (source_id, source): (Arc<str>, Arc<str>) = if let Some(path) = args.path {
|
||||||
|
Loading…
Reference in New Issue
Block a user