Continue AST overhaul
This commit is contained in:
parent
43b2393d8a
commit
fdf324c866
@ -16,7 +16,7 @@ pub enum Expression {
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn call_expression(call_expression: CallExpression, position: Span) -> Self {
|
||||
pub fn call(call_expression: CallExpression, position: Span) -> Self {
|
||||
Expression::WithoutBlock(Node::new(
|
||||
Box::new(ExpressionWithoutBlock::Call(call_expression)),
|
||||
position,
|
||||
@ -30,7 +30,7 @@ impl Expression {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn operator_expression(operator_expression: OperatorExpression, position: Span) -> Self {
|
||||
pub fn operator(operator_expression: OperatorExpression, position: Span) -> Self {
|
||||
Expression::WithoutBlock(Node::new(
|
||||
Box::new(ExpressionWithoutBlock::Operator(operator_expression)),
|
||||
position,
|
||||
@ -58,14 +58,14 @@ impl Expression {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn struct_expression(struct_expression: StructExpression, position: Span) -> Self {
|
||||
pub fn r#struct(struct_expression: StructExpression, position: Span) -> Self {
|
||||
Expression::WithoutBlock(Node::new(
|
||||
Box::new(ExpressionWithoutBlock::Struct(struct_expression)),
|
||||
position,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn identifier_expression(identifier: Identifier, position: Span) -> Self {
|
||||
pub fn identifier(identifier: Identifier, position: Span) -> Self {
|
||||
Expression::WithoutBlock(Node::new(
|
||||
Box::new(ExpressionWithoutBlock::Identifier(identifier)),
|
||||
position,
|
||||
@ -97,13 +97,6 @@ impl Expression {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn identifier(identifier: Identifier, position: Span) -> Self {
|
||||
Expression::WithoutBlock(Node::new(
|
||||
Box::new(ExpressionWithoutBlock::Identifier(identifier)),
|
||||
position,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
Expression::WithBlock(expression_node) => expression_node.position,
|
||||
@ -248,7 +241,7 @@ impl Display for ListExpression {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LiteralExpression {
|
||||
Boolean(bool),
|
||||
Float(f64),
|
||||
@ -273,6 +266,12 @@ impl Display for LiteralExpression {
|
||||
|
||||
impl Eq for LiteralExpression {}
|
||||
|
||||
impl PartialOrd for LiteralExpression {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for LiteralExpression {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
|
@ -10,7 +10,7 @@ use std::{
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{BuiltInFunction, Context, Identifier, Span, Type, Value};
|
||||
use crate::{Identifier, Span, Type};
|
||||
|
||||
/// In-memory representation of a Dust program.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
@ -59,6 +59,10 @@ pub enum Statement {
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
pub fn struct_definition(struct_definition: StructDefinition, position: Span) -> Self {
|
||||
Statement::StructDefinition(Node::new(struct_definition, position))
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
Statement::Expression(expression) => expression.position(),
|
||||
|
@ -10,9 +10,8 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{BinaryOperator, UnaryOperator},
|
||||
parse, AbstractSyntaxTree, Context, DustError, Identifier, Node, Span, Statement,
|
||||
StructDefinition, StructType, Type,
|
||||
abstract_tree::{AbstractSyntaxTree, Node, Statement},
|
||||
parse, Context, DustError, Identifier, Span, Type,
|
||||
};
|
||||
|
||||
/// Analyzes the abstract syntax tree for errors.
|
||||
@ -73,7 +72,7 @@ impl<'a> Analyzer<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn analyze_statement(&mut self, _: &Node<Statement>) -> Result<(), AnalyzerError> {
|
||||
fn analyze_statement(&mut self, _: &Statement) -> Result<(), AnalyzerError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -81,25 +80,25 @@ impl<'a> Analyzer<'a> {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum AnalyzerError {
|
||||
ExpectedBoolean {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedIdentifier {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedIdentifierOrString {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedIntegerOrRange {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedList {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedMap {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedValue {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedValueArgumentCount {
|
||||
expected: usize,
|
||||
@ -107,56 +106,54 @@ pub enum AnalyzerError {
|
||||
position: Span,
|
||||
},
|
||||
IndexOutOfBounds {
|
||||
list: Node<Statement>,
|
||||
index: Node<Statement>,
|
||||
list: Statement,
|
||||
index: Statement,
|
||||
index_value: usize,
|
||||
length: usize,
|
||||
},
|
||||
TypeConflict {
|
||||
actual_statement: Node<Statement>,
|
||||
actual_statement: Statement,
|
||||
actual_type: Type,
|
||||
expected: Type,
|
||||
},
|
||||
UndefinedField {
|
||||
identifier: Node<Statement>,
|
||||
statement: Node<Statement>,
|
||||
identifier: Statement,
|
||||
statement: Statement,
|
||||
},
|
||||
UndefinedType {
|
||||
identifier: Node<Identifier>,
|
||||
},
|
||||
UnexpectedIdentifier {
|
||||
identifier: Node<Statement>,
|
||||
identifier: Statement,
|
||||
},
|
||||
UnexectedString {
|
||||
actual: Node<Statement>,
|
||||
actual: Statement,
|
||||
},
|
||||
UndefinedVariable {
|
||||
identifier: Node<Statement>,
|
||||
identifier: Statement,
|
||||
},
|
||||
}
|
||||
|
||||
impl AnalyzerError {
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
AnalyzerError::ExpectedBoolean { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position,
|
||||
AnalyzerError::ExpectedIntegerOrRange { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedList { actual } => actual.position,
|
||||
AnalyzerError::ExpectedMap { actual } => actual.position,
|
||||
AnalyzerError::ExpectedValue { actual } => actual.position,
|
||||
AnalyzerError::ExpectedBoolean { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedIdentifier { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedIntegerOrRange { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedList { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedMap { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedValue { actual } => actual.position(),
|
||||
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
|
||||
AnalyzerError::IndexOutOfBounds { list, index, .. } => {
|
||||
(list.position.0, index.position.1)
|
||||
}
|
||||
AnalyzerError::IndexOutOfBounds { index, .. } => index.position(),
|
||||
AnalyzerError::TypeConflict {
|
||||
actual_statement, ..
|
||||
} => actual_statement.position,
|
||||
AnalyzerError::UndefinedField { identifier, .. } => identifier.position,
|
||||
} => actual_statement.position(),
|
||||
AnalyzerError::UndefinedField { identifier, .. } => identifier.position(),
|
||||
AnalyzerError::UndefinedType { identifier } => identifier.position,
|
||||
AnalyzerError::UndefinedVariable { identifier } => identifier.position,
|
||||
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position,
|
||||
AnalyzerError::UnexectedString { actual } => actual.position,
|
||||
AnalyzerError::UndefinedVariable { identifier } => identifier.position(),
|
||||
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position(),
|
||||
AnalyzerError::UnexectedString { actual } => actual.position(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,7 +228,7 @@ impl Display for AnalyzerError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{AssignmentOperator, Identifier, Value};
|
||||
use crate::{Identifier, Value};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -242,27 +239,7 @@ mod tests {
|
||||
a += 1.0
|
||||
";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("a"), (31, 32)),
|
||||
operator: Node::new(AssignmentOperator::AddAssign, (33, 35)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::float(1.0)),
|
||||
(38, 41)
|
||||
))
|
||||
},
|
||||
(31, 32)
|
||||
),
|
||||
actual_type: Type::Integer,
|
||||
expected: Type::Float
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -272,27 +249,7 @@ mod tests {
|
||||
a -= 1.0
|
||||
";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("a"), (31, 32)),
|
||||
operator: Node::new(AssignmentOperator::SubtractAssign, (33, 37)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::float(1.0)),
|
||||
(40, 43)
|
||||
))
|
||||
},
|
||||
(31, 32)
|
||||
),
|
||||
actual_type: Type::Integer,
|
||||
expected: Type::Float
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -302,221 +259,83 @@ mod tests {
|
||||
Foo(1, 2)
|
||||
";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(Statement::Constant(Value::integer(2)), (55, 56)),
|
||||
actual_type: Type::Integer,
|
||||
expected: Type::Float
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constant_list_index_out_of_bounds() {
|
||||
let source = "[1, 2, 3][3]";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::IndexOutOfBounds {
|
||||
list: Node::new(
|
||||
Statement::List(vec![
|
||||
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
|
||||
Node::new(Statement::Constant(Value::integer(2)), (4, 5)),
|
||||
Node::new(Statement::Constant(Value::integer(3)), (7, 8)),
|
||||
]),
|
||||
(0, 9)
|
||||
),
|
||||
index: Node::new(Statement::Constant(Value::integer(3)), (10, 11)),
|
||||
index_value: 3,
|
||||
length: 3
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonexistant_field_identifier() {
|
||||
let source = "{ x = 1 }.y";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::UndefinedField {
|
||||
identifier: Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)),
|
||||
statement: Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(Statement::Constant(Value::integer(1)), (6, 7))
|
||||
)]),
|
||||
(0, 9)
|
||||
)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonexistant_field_string() {
|
||||
let source = "{ x = 1 }.'y'";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::UndefinedField {
|
||||
identifier: Node::new(Statement::Constant(Value::string("y")), (10, 13)),
|
||||
statement: Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(Statement::Constant(Value::integer(1)), (6, 7))
|
||||
)]),
|
||||
(0, 9)
|
||||
)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn malformed_list_index() {
|
||||
let source = "[1, 2, 3]['foo']";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::ExpectedIntegerOrRange {
|
||||
actual: Node::new(Statement::Constant(Value::string("foo")), (10, 15)),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn malformed_field_access() {
|
||||
let source = "{ x = 1 }.0";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::ExpectedIdentifierOrString {
|
||||
actual: Node::new(Statement::Constant(Value::integer(0)), (10, 11)),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length_no_arguments() {
|
||||
let source = "length()";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::ExpectedValueArgumentCount {
|
||||
expected: 1,
|
||||
actual: 0,
|
||||
position: (0, 6)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_plus_integer() {
|
||||
let source = "42.0 + 2";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(Statement::Constant(Value::integer(2)), (7, 8)),
|
||||
actual_type: Type::Integer,
|
||||
expected: Type::Float,
|
||||
},
|
||||
source
|
||||
})
|
||||
)
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_plus_boolean() {
|
||||
let source = "42 + true";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(Statement::Constant(Value::boolean(true)), (5, 9)),
|
||||
actual_type: Type::Boolean,
|
||||
expected: Type::Integer,
|
||||
},
|
||||
source
|
||||
})
|
||||
)
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_even_expects_number() {
|
||||
let source = "is_even('hello')";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(
|
||||
Statement::Constant(Value::string("hello")),
|
||||
(8, 15)
|
||||
),
|
||||
actual_type: Type::String,
|
||||
expected: Type::Number,
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_odd_expects_number() {
|
||||
let source = "is_odd('hello')";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::TypeConflict {
|
||||
actual_statement: Node::new(
|
||||
Statement::Constant(Value::string("hello")),
|
||||
(7, 14)
|
||||
),
|
||||
actual_type: Type::String,
|
||||
expected: Type::Number,
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn undefined_variable() {
|
||||
let source = "foo";
|
||||
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::AnalyzerError {
|
||||
analyzer_error: AnalyzerError::UndefinedVariable {
|
||||
identifier: Node::new(Statement::Identifier(Identifier::new("foo")), (0, 3)),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
assert_eq!(analyze(source), todo!());
|
||||
}
|
||||
}
|
||||
|
@ -28,10 +28,7 @@ pub mod r#type;
|
||||
pub mod value;
|
||||
pub mod vm;
|
||||
|
||||
pub use abstract_tree::{
|
||||
AbstractSyntaxTree, AssignmentOperator, BinaryOperator, Node, Statement, StructDefinition,
|
||||
UnaryOperator,
|
||||
};
|
||||
pub use abstract_tree::{AbstractSyntaxTree, Expression, Node, Statement};
|
||||
pub use analyzer::{analyze, Analyzer, AnalyzerError};
|
||||
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
||||
pub use context::{Context, VariableData};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,12 +9,10 @@ use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
};
|
||||
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use crate::{
|
||||
parse, AbstractSyntaxTree, Analyzer, AssignmentOperator, BinaryOperator, BuiltInFunctionError,
|
||||
Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructType, Type,
|
||||
UnaryOperator, Value, ValueError,
|
||||
abstract_tree::{AbstractSyntaxTree, Node, Statement},
|
||||
parse, Analyzer, BuiltInFunctionError, Context, DustError, Identifier, ParseError, Span,
|
||||
Struct, StructType, Type, Value, ValueError,
|
||||
};
|
||||
|
||||
/// Run the source code and return the result.
|
||||
@ -89,7 +87,7 @@ impl Vm {
|
||||
let mut previous_value = None;
|
||||
|
||||
while let Some(statement) = self.abstract_tree.statements.pop_front() {
|
||||
let new_position = statement.position;
|
||||
let new_position = statement.position();
|
||||
|
||||
previous_value = self.run_statement(statement)?;
|
||||
|
||||
@ -103,647 +101,8 @@ impl Vm {
|
||||
Ok(previous_value)
|
||||
}
|
||||
|
||||
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
|
||||
match node.inner {
|
||||
Statement::Assignment {
|
||||
identifier,
|
||||
operator,
|
||||
value,
|
||||
} => match operator.inner {
|
||||
AssignmentOperator::Assign => {
|
||||
let position = value.position;
|
||||
let value = if let Some(value) = self.run_statement(*value)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
if let Some(existing_value) = self.context.get_value(&identifier.inner) {
|
||||
if existing_value.is_mutable() {
|
||||
existing_value.mutate(&value);
|
||||
} else {
|
||||
return Err(VmError::CannotMutate {
|
||||
value: existing_value,
|
||||
position: identifier.position,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.context.set_value(identifier.inner, value);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
AssignmentOperator::AddAssign => {
|
||||
let left_value = if let Some(value) = self.context.get_value(&identifier.inner)
|
||||
{
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::UndefinedVariable { identifier });
|
||||
};
|
||||
let value_position = value.position;
|
||||
let right_value = if let Some(value) = self.run_statement(*value)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: value_position,
|
||||
});
|
||||
};
|
||||
|
||||
if left_value.is_mutable() {
|
||||
left_value.add_mut(&right_value).map_err(|value_error| {
|
||||
VmError::ValueError {
|
||||
error: value_error,
|
||||
position: (identifier.position.0, value_position.1),
|
||||
}
|
||||
})?;
|
||||
} else {
|
||||
return Err(VmError::CannotMutate {
|
||||
value: left_value,
|
||||
position: identifier.position,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
AssignmentOperator::SubtractAssign => {
|
||||
let left_value = if let Some(value) = self.context.get_value(&identifier.inner)
|
||||
{
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::UndefinedVariable { identifier });
|
||||
};
|
||||
let value_position = value.position;
|
||||
let right_value = if let Some(value) = self.run_statement(*value)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: value_position,
|
||||
});
|
||||
};
|
||||
|
||||
if left_value.is_mutable() {
|
||||
left_value
|
||||
.subtract_mut(&right_value)
|
||||
.map_err(|value_error| VmError::ValueError {
|
||||
error: value_error,
|
||||
position: (identifier.position.0, value_position.1),
|
||||
})?;
|
||||
} else {
|
||||
return Err(VmError::CannotMutate {
|
||||
value: left_value,
|
||||
position: identifier.position,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
},
|
||||
Statement::AsyncBlock(statements) => {
|
||||
let error_option = statements
|
||||
.into_par_iter()
|
||||
.find_map_any(|statement| self.run_statement(statement).err());
|
||||
|
||||
if let Some(error) = error_option {
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Statement::BinaryOperation {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => {
|
||||
let right_position = right.position;
|
||||
|
||||
if let BinaryOperator::FieldAccess = operator.inner {
|
||||
let left_span = left.position;
|
||||
let left_value = if let Some(value) = self.run_statement(*left)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: left_span,
|
||||
});
|
||||
};
|
||||
let right_span = right.position;
|
||||
|
||||
if let Some(map) = left_value.as_map() {
|
||||
if let Statement::Identifier(identifier) = right.inner {
|
||||
let value = map.get(&identifier).cloned();
|
||||
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
if let Some(value) = self.run_statement(*right)? {
|
||||
if let Some(string) = value.as_string() {
|
||||
let identifier = Identifier::new(string);
|
||||
|
||||
let value = map.get(&identifier).cloned();
|
||||
|
||||
return Ok(value);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(VmError::ExpectedIdentifierOrString {
|
||||
position: right_span,
|
||||
});
|
||||
} else {
|
||||
return Err(VmError::ExpectedMap {
|
||||
position: left_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let BinaryOperator::ListIndex = operator.inner {
|
||||
let list_position = left.position;
|
||||
let list_value = if let Some(value) = self.run_statement(*left)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: list_position,
|
||||
});
|
||||
};
|
||||
let list = if let Some(list) = list_value.as_list() {
|
||||
list
|
||||
} else {
|
||||
return Err(VmError::ExpectedList {
|
||||
position: list_position,
|
||||
});
|
||||
};
|
||||
let index_position = right.position;
|
||||
let index_value = if let Some(value) = self.run_statement(*right)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: index_position,
|
||||
});
|
||||
};
|
||||
|
||||
if let Some(index) = index_value.as_integer() {
|
||||
return if let Some(value) = list.get(index as usize) {
|
||||
Ok(Some(value.clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(range) = index_value.as_range() {
|
||||
let range = range.start as usize..range.end as usize;
|
||||
|
||||
return if let Some(list) = list.get(range) {
|
||||
Ok(Some(Value::list(list.to_vec())))
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
}
|
||||
|
||||
return Err(VmError::ExpectedIntegerOrRange {
|
||||
position: index_position,
|
||||
});
|
||||
}
|
||||
|
||||
let left_position = left.position;
|
||||
let left_value = if let Some(value) = self.run_statement(*left)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: left_position,
|
||||
});
|
||||
};
|
||||
let right_value = if let Some(value) = self.run_statement(*right)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: right_position,
|
||||
});
|
||||
};
|
||||
|
||||
match operator.inner {
|
||||
BinaryOperator::Add => left_value.add(&right_value),
|
||||
BinaryOperator::And => left_value.and(&right_value),
|
||||
BinaryOperator::Divide => left_value.divide(&right_value),
|
||||
BinaryOperator::Equal => Ok(Value::boolean(left_value == right_value)),
|
||||
BinaryOperator::Greater => left_value.greater_than(&right_value),
|
||||
BinaryOperator::GreaterOrEqual => {
|
||||
left_value.greater_than_or_equal(&right_value)
|
||||
}
|
||||
BinaryOperator::Less => left_value.less_than(&right_value),
|
||||
BinaryOperator::LessOrEqual => left_value.less_than_or_equal(&right_value),
|
||||
BinaryOperator::Modulo => left_value.modulo(&right_value),
|
||||
BinaryOperator::Multiply => left_value.multiply(&right_value),
|
||||
BinaryOperator::Or => left_value.or(&right_value),
|
||||
BinaryOperator::Subtract => left_value.subtract(&right_value),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.map(Some)
|
||||
.map_err(|value_error| VmError::ValueError {
|
||||
error: value_error,
|
||||
position: node.position,
|
||||
})
|
||||
}
|
||||
Statement::Block(statements) => {
|
||||
let mut previous_value = None;
|
||||
|
||||
for statement in statements {
|
||||
previous_value = self.run_statement(statement)?;
|
||||
}
|
||||
|
||||
Ok(previous_value)
|
||||
}
|
||||
Statement::BuiltInFunctionCall {
|
||||
function,
|
||||
type_arguments: _,
|
||||
value_arguments: value_nodes,
|
||||
} => {
|
||||
let values = if let Some(nodes) = value_nodes {
|
||||
let mut values = Vec::new();
|
||||
|
||||
for node in nodes {
|
||||
let position = node.position;
|
||||
let value = if let Some(value) = self.run_statement(node)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Some(values)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let function_call_return =
|
||||
function
|
||||
.call(None, values)
|
||||
.map_err(|built_in_function_error| VmError::BuiltInFunctionError {
|
||||
error: built_in_function_error,
|
||||
position: node.position,
|
||||
})?;
|
||||
|
||||
Ok(function_call_return)
|
||||
}
|
||||
Statement::Constant(value) => Ok(Some(value)),
|
||||
Statement::FieldsStructInstantiation { name, fields } => {
|
||||
let mut values = Vec::new();
|
||||
|
||||
for (identifier, value_node) in fields {
|
||||
let position = value_node.position;
|
||||
let value = if let Some(value) = self.run_statement(value_node)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
values.push((identifier.inner, value));
|
||||
}
|
||||
|
||||
Ok(Some(Value::r#struct(Struct::Fields {
|
||||
name: name.inner,
|
||||
fields: values,
|
||||
})))
|
||||
}
|
||||
Statement::Invokation {
|
||||
invokee,
|
||||
type_arguments: _,
|
||||
value_arguments: value_parameter_nodes,
|
||||
} => {
|
||||
let invokee_position = invokee.position;
|
||||
let invokee_type = invokee.inner.expected_type(&self.context);
|
||||
|
||||
if let Some(Type::Struct(StructType::Tuple { name, .. })) = invokee_type {
|
||||
let mut fields = Vec::new();
|
||||
|
||||
if let Some(value_parameter_nodes) = value_parameter_nodes {
|
||||
for statement in value_parameter_nodes {
|
||||
let position = statement.position;
|
||||
let value = if let Some(value) = self.run_statement(statement)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
fields.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
let struct_value = Value::r#struct(Struct::Tuple {
|
||||
name: name.clone(),
|
||||
fields,
|
||||
});
|
||||
|
||||
return Ok(Some(struct_value));
|
||||
}
|
||||
|
||||
let function_value = if let Some(value) = self.run_statement(*invokee)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: invokee_position,
|
||||
});
|
||||
};
|
||||
let function = if let Some(function) = function_value.as_function() {
|
||||
function
|
||||
} else {
|
||||
return Err(VmError::ExpectedFunction {
|
||||
actual: function_value,
|
||||
position: invokee_position,
|
||||
});
|
||||
};
|
||||
|
||||
let value_parameters = if let Some(value_nodes) = value_parameter_nodes {
|
||||
let mut value_parameters = Vec::new();
|
||||
|
||||
for node in value_nodes {
|
||||
let position = node.position;
|
||||
let value = if let Some(value) = self.run_statement(node)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
value_parameters.push(value);
|
||||
}
|
||||
|
||||
Some(value_parameters)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(function
|
||||
.clone()
|
||||
.call(None, value_parameters, &self.context)?)
|
||||
}
|
||||
Statement::Identifier(identifier) => {
|
||||
let value_option = self.context.get_value(&identifier);
|
||||
|
||||
if let Some(value) = value_option {
|
||||
return Ok(Some(value.clone()));
|
||||
}
|
||||
|
||||
let type_option = self.context.get_type(&identifier);
|
||||
|
||||
println!("{type_option:?}");
|
||||
|
||||
if let Some(Type::Struct(StructType::Unit { name })) = type_option {
|
||||
return Ok(Some(Value::r#struct(Struct::Unit { name })));
|
||||
}
|
||||
|
||||
Err(VmError::UndefinedVariable {
|
||||
identifier: Node::new(identifier, node.position),
|
||||
})
|
||||
}
|
||||
Statement::If { condition, body } => {
|
||||
let condition_position = condition.position;
|
||||
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
let condition = if let Some(condition) = condition_value.as_boolean() {
|
||||
condition
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
|
||||
if condition {
|
||||
self.run_statement(*body)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Statement::IfElse {
|
||||
condition,
|
||||
if_body,
|
||||
else_body,
|
||||
} => {
|
||||
let condition_position = condition.position;
|
||||
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
|
||||
if let Some(condition) = condition_value.as_boolean() {
|
||||
if condition {
|
||||
self.run_statement(*if_body)
|
||||
} else {
|
||||
self.run_statement(*else_body)
|
||||
}
|
||||
} else {
|
||||
Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
})
|
||||
}
|
||||
}
|
||||
Statement::IfElseIf {
|
||||
condition,
|
||||
if_body,
|
||||
else_ifs,
|
||||
} => {
|
||||
let condition_position = condition.position;
|
||||
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
|
||||
if let Some(condition) = condition_value.as_boolean() {
|
||||
if condition {
|
||||
self.run_statement(*if_body)
|
||||
} else {
|
||||
for (condition, body) in else_ifs {
|
||||
let condition_position = condition.position;
|
||||
let condition_value =
|
||||
if let Some(value) = self.run_statement(condition)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
let condition = if let Some(condition) = condition_value.as_boolean() {
|
||||
condition
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
|
||||
if condition {
|
||||
self.run_statement(body)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
})
|
||||
}
|
||||
}
|
||||
Statement::IfElseIfElse {
|
||||
condition,
|
||||
if_body,
|
||||
else_ifs,
|
||||
else_body,
|
||||
} => {
|
||||
let condition_position = condition.position;
|
||||
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
|
||||
if let Some(condition) = condition_value.as_boolean() {
|
||||
if condition {
|
||||
self.run_statement(*if_body)
|
||||
} else {
|
||||
for (condition, body) in else_ifs {
|
||||
let condition_position = condition.position;
|
||||
let condition_value =
|
||||
if let Some(value) = self.run_statement(condition)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
let condition = if let Some(condition) = condition_value.as_boolean() {
|
||||
condition
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
});
|
||||
};
|
||||
|
||||
if condition {
|
||||
return self.run_statement(body);
|
||||
}
|
||||
}
|
||||
|
||||
self.run_statement(*else_body)
|
||||
}
|
||||
} else {
|
||||
Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
})
|
||||
}
|
||||
}
|
||||
Statement::List(nodes) => {
|
||||
let values = nodes
|
||||
.into_iter()
|
||||
.map(|node| {
|
||||
let span = node.position;
|
||||
if let Some(value) = self.run_statement(node)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(VmError::ExpectedValue { position: span })
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<Value>, VmError>>()?;
|
||||
|
||||
Ok(Some(Value::list(values)))
|
||||
}
|
||||
Statement::Map(nodes) => {
|
||||
let mut values = BTreeMap::new();
|
||||
|
||||
for (identifier, value_node) in nodes {
|
||||
let position = value_node.position;
|
||||
let value = if let Some(value) = self.run_statement(value_node)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
values.insert(identifier.inner, value);
|
||||
}
|
||||
|
||||
Ok(Some(Value::map(values)))
|
||||
}
|
||||
Statement::AssignmentMut { identifier, value } => {
|
||||
let position = value.position;
|
||||
let value = if let Some(value) = self.run_statement(*value)? {
|
||||
value.to_mut()
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
self.context.set_value(identifier.inner, value);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Statement::ConstantMut(value) => Ok(Some(value)),
|
||||
Statement::Nil(node) => {
|
||||
let _return = self.run_statement(*node)?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Statement::StructDefinition(_) => Ok(None),
|
||||
Statement::UnaryOperation { operator, operand } => {
|
||||
let position = operand.position;
|
||||
let value = if let Some(value) = self.run_statement(*operand)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
match operator.inner {
|
||||
UnaryOperator::Negate => {
|
||||
if let Some(value) = value.as_integer() {
|
||||
Ok(Some(Value::integer(-value)))
|
||||
} else if let Some(value) = value.as_float() {
|
||||
Ok(Some(Value::float(-value)))
|
||||
} else {
|
||||
Err(VmError::ExpectedNumber { position })
|
||||
}
|
||||
}
|
||||
UnaryOperator::Not => {
|
||||
if let Some(value) = value.as_boolean() {
|
||||
Ok(Some(Value::boolean(!value)))
|
||||
} else {
|
||||
Err(VmError::ExpectedBoolean { position })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::While { condition, body } => {
|
||||
let mut return_value = None;
|
||||
|
||||
let condition_position = condition.position;
|
||||
|
||||
while let Some(condition_value) = self.run_statement(*condition.clone())? {
|
||||
if let Some(condition) = condition_value.as_boolean() {
|
||||
if !condition {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
position: condition_position,
|
||||
});
|
||||
}
|
||||
|
||||
return_value = self.run_statement(*body.clone())?;
|
||||
|
||||
if return_value.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(return_value)
|
||||
}
|
||||
}
|
||||
fn run_statement(&self, node: Statement) -> Result<Option<Value>, VmError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user