Continue AST overhaul
This commit is contained in:
parent
43b2393d8a
commit
fdf324c866
@ -16,7 +16,7 @@ pub enum Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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(
|
Expression::WithoutBlock(Node::new(
|
||||||
Box::new(ExpressionWithoutBlock::Call(call_expression)),
|
Box::new(ExpressionWithoutBlock::Call(call_expression)),
|
||||||
position,
|
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(
|
Expression::WithoutBlock(Node::new(
|
||||||
Box::new(ExpressionWithoutBlock::Operator(operator_expression)),
|
Box::new(ExpressionWithoutBlock::Operator(operator_expression)),
|
||||||
position,
|
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(
|
Expression::WithoutBlock(Node::new(
|
||||||
Box::new(ExpressionWithoutBlock::Struct(struct_expression)),
|
Box::new(ExpressionWithoutBlock::Struct(struct_expression)),
|
||||||
position,
|
position,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identifier_expression(identifier: Identifier, position: Span) -> Self {
|
pub fn identifier(identifier: Identifier, position: Span) -> Self {
|
||||||
Expression::WithoutBlock(Node::new(
|
Expression::WithoutBlock(Node::new(
|
||||||
Box::new(ExpressionWithoutBlock::Identifier(identifier)),
|
Box::new(ExpressionWithoutBlock::Identifier(identifier)),
|
||||||
position,
|
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 {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Expression::WithBlock(expression_node) => expression_node.position,
|
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 {
|
pub enum LiteralExpression {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
@ -273,6 +266,12 @@ impl Display for LiteralExpression {
|
|||||||
|
|
||||||
impl Eq 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 {
|
impl Ord for LiteralExpression {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
@ -10,7 +10,7 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{BuiltInFunction, Context, Identifier, Span, Type, Value};
|
use crate::{Identifier, Span, Type};
|
||||||
|
|
||||||
/// In-memory representation of a Dust program.
|
/// In-memory representation of a Dust program.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
@ -59,6 +59,10 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Statement::Expression(expression) => expression.position(),
|
Statement::Expression(expression) => expression.position(),
|
||||||
|
@ -10,9 +10,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::{BinaryOperator, UnaryOperator},
|
abstract_tree::{AbstractSyntaxTree, Node, Statement},
|
||||||
parse, AbstractSyntaxTree, Context, DustError, Identifier, Node, Span, Statement,
|
parse, Context, DustError, Identifier, Span, Type,
|
||||||
StructDefinition, StructType, Type,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Analyzes the abstract syntax tree for errors.
|
/// Analyzes the abstract syntax tree for errors.
|
||||||
@ -73,7 +72,7 @@ impl<'a> Analyzer<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_statement(&mut self, _: &Node<Statement>) -> Result<(), AnalyzerError> {
|
fn analyze_statement(&mut self, _: &Statement) -> Result<(), AnalyzerError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,25 +80,25 @@ impl<'a> Analyzer<'a> {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum AnalyzerError {
|
pub enum AnalyzerError {
|
||||||
ExpectedBoolean {
|
ExpectedBoolean {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedIdentifier {
|
ExpectedIdentifier {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedIdentifierOrString {
|
ExpectedIdentifierOrString {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedIntegerOrRange {
|
ExpectedIntegerOrRange {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedList {
|
ExpectedList {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedMap {
|
ExpectedMap {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedValue {
|
ExpectedValue {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedValueArgumentCount {
|
ExpectedValueArgumentCount {
|
||||||
expected: usize,
|
expected: usize,
|
||||||
@ -107,56 +106,54 @@ pub enum AnalyzerError {
|
|||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IndexOutOfBounds {
|
IndexOutOfBounds {
|
||||||
list: Node<Statement>,
|
list: Statement,
|
||||||
index: Node<Statement>,
|
index: Statement,
|
||||||
index_value: usize,
|
index_value: usize,
|
||||||
length: usize,
|
length: usize,
|
||||||
},
|
},
|
||||||
TypeConflict {
|
TypeConflict {
|
||||||
actual_statement: Node<Statement>,
|
actual_statement: Statement,
|
||||||
actual_type: Type,
|
actual_type: Type,
|
||||||
expected: Type,
|
expected: Type,
|
||||||
},
|
},
|
||||||
UndefinedField {
|
UndefinedField {
|
||||||
identifier: Node<Statement>,
|
identifier: Statement,
|
||||||
statement: Node<Statement>,
|
statement: Statement,
|
||||||
},
|
},
|
||||||
UndefinedType {
|
UndefinedType {
|
||||||
identifier: Node<Identifier>,
|
identifier: Node<Identifier>,
|
||||||
},
|
},
|
||||||
UnexpectedIdentifier {
|
UnexpectedIdentifier {
|
||||||
identifier: Node<Statement>,
|
identifier: Statement,
|
||||||
},
|
},
|
||||||
UnexectedString {
|
UnexectedString {
|
||||||
actual: Node<Statement>,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
UndefinedVariable {
|
UndefinedVariable {
|
||||||
identifier: Node<Statement>,
|
identifier: Statement,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnalyzerError {
|
impl AnalyzerError {
|
||||||
pub fn position(&self) -> Span {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
AnalyzerError::ExpectedBoolean { actual, .. } => actual.position,
|
AnalyzerError::ExpectedBoolean { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position,
|
AnalyzerError::ExpectedIdentifier { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position,
|
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedIntegerOrRange { actual, .. } => actual.position,
|
AnalyzerError::ExpectedIntegerOrRange { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedList { actual } => actual.position,
|
AnalyzerError::ExpectedList { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedMap { actual } => actual.position,
|
AnalyzerError::ExpectedMap { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedValue { actual } => actual.position,
|
AnalyzerError::ExpectedValue { actual } => actual.position(),
|
||||||
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
|
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
|
||||||
AnalyzerError::IndexOutOfBounds { list, index, .. } => {
|
AnalyzerError::IndexOutOfBounds { index, .. } => index.position(),
|
||||||
(list.position.0, index.position.1)
|
|
||||||
}
|
|
||||||
AnalyzerError::TypeConflict {
|
AnalyzerError::TypeConflict {
|
||||||
actual_statement, ..
|
actual_statement, ..
|
||||||
} => actual_statement.position,
|
} => actual_statement.position(),
|
||||||
AnalyzerError::UndefinedField { identifier, .. } => identifier.position,
|
AnalyzerError::UndefinedField { identifier, .. } => identifier.position(),
|
||||||
AnalyzerError::UndefinedType { identifier } => identifier.position,
|
AnalyzerError::UndefinedType { identifier } => identifier.position,
|
||||||
AnalyzerError::UndefinedVariable { identifier } => identifier.position,
|
AnalyzerError::UndefinedVariable { identifier } => identifier.position(),
|
||||||
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position,
|
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position(),
|
||||||
AnalyzerError::UnexectedString { actual } => actual.position,
|
AnalyzerError::UnexectedString { actual } => actual.position(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +228,7 @@ impl Display for AnalyzerError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{AssignmentOperator, Identifier, Value};
|
use crate::{Identifier, Value};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -242,27 +239,7 @@ mod tests {
|
|||||||
a += 1.0
|
a += 1.0
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -272,27 +249,7 @@ mod tests {
|
|||||||
a -= 1.0
|
a -= 1.0
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -302,221 +259,83 @@ mod tests {
|
|||||||
Foo(1, 2)
|
Foo(1, 2)
|
||||||
";
|
";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn constant_list_index_out_of_bounds() {
|
fn constant_list_index_out_of_bounds() {
|
||||||
let source = "[1, 2, 3][3]";
|
let source = "[1, 2, 3][3]";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nonexistant_field_identifier() {
|
fn nonexistant_field_identifier() {
|
||||||
let source = "{ x = 1 }.y";
|
let source = "{ x = 1 }.y";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nonexistant_field_string() {
|
fn nonexistant_field_string() {
|
||||||
let source = "{ x = 1 }.'y'";
|
let source = "{ x = 1 }.'y'";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn malformed_list_index() {
|
fn malformed_list_index() {
|
||||||
let source = "[1, 2, 3]['foo']";
|
let source = "[1, 2, 3]['foo']";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
analyze(source),
|
|
||||||
Err(DustError::AnalyzerError {
|
|
||||||
analyzer_error: AnalyzerError::ExpectedIntegerOrRange {
|
|
||||||
actual: Node::new(Statement::Constant(Value::string("foo")), (10, 15)),
|
|
||||||
},
|
|
||||||
source
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn malformed_field_access() {
|
fn malformed_field_access() {
|
||||||
let source = "{ x = 1 }.0";
|
let source = "{ x = 1 }.0";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
analyze(source),
|
|
||||||
Err(DustError::AnalyzerError {
|
|
||||||
analyzer_error: AnalyzerError::ExpectedIdentifierOrString {
|
|
||||||
actual: Node::new(Statement::Constant(Value::integer(0)), (10, 11)),
|
|
||||||
},
|
|
||||||
source
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn length_no_arguments() {
|
fn length_no_arguments() {
|
||||||
let source = "length()";
|
let source = "length()";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
analyze(source),
|
|
||||||
Err(DustError::AnalyzerError {
|
|
||||||
analyzer_error: AnalyzerError::ExpectedValueArgumentCount {
|
|
||||||
expected: 1,
|
|
||||||
actual: 0,
|
|
||||||
position: (0, 6)
|
|
||||||
},
|
|
||||||
source
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_plus_integer() {
|
fn float_plus_integer() {
|
||||||
let source = "42.0 + 2";
|
let source = "42.0 + 2";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn integer_plus_boolean() {
|
fn integer_plus_boolean() {
|
||||||
let source = "42 + true";
|
let source = "42 + true";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_even_expects_number() {
|
fn is_even_expects_number() {
|
||||||
let source = "is_even('hello')";
|
let source = "is_even('hello')";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_odd_expects_number() {
|
fn is_odd_expects_number() {
|
||||||
let source = "is_odd('hello')";
|
let source = "is_odd('hello')";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
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
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn undefined_variable() {
|
fn undefined_variable() {
|
||||||
let source = "foo";
|
let source = "foo";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(analyze(source), todo!());
|
||||||
analyze(source),
|
|
||||||
Err(DustError::AnalyzerError {
|
|
||||||
analyzer_error: AnalyzerError::UndefinedVariable {
|
|
||||||
identifier: Node::new(Statement::Identifier(Identifier::new("foo")), (0, 3)),
|
|
||||||
},
|
|
||||||
source
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,7 @@ pub mod r#type;
|
|||||||
pub mod value;
|
pub mod value;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
|
||||||
pub use abstract_tree::{
|
pub use abstract_tree::{AbstractSyntaxTree, Expression, Node, Statement};
|
||||||
AbstractSyntaxTree, AssignmentOperator, BinaryOperator, Node, Statement, StructDefinition,
|
|
||||||
UnaryOperator,
|
|
||||||
};
|
|
||||||
pub use analyzer::{analyze, Analyzer, AnalyzerError};
|
pub use analyzer::{analyze, Analyzer, AnalyzerError};
|
||||||
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
||||||
pub use context::{Context, VariableData};
|
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},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parse, AbstractSyntaxTree, Analyzer, AssignmentOperator, BinaryOperator, BuiltInFunctionError,
|
abstract_tree::{AbstractSyntaxTree, Node, Statement},
|
||||||
Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructType, Type,
|
parse, Analyzer, BuiltInFunctionError, Context, DustError, Identifier, ParseError, Span,
|
||||||
UnaryOperator, Value, ValueError,
|
Struct, StructType, Type, Value, ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Run the source code and return the result.
|
/// Run the source code and return the result.
|
||||||
@ -89,7 +87,7 @@ impl Vm {
|
|||||||
let mut previous_value = None;
|
let mut previous_value = None;
|
||||||
|
|
||||||
while let Some(statement) = self.abstract_tree.statements.pop_front() {
|
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)?;
|
previous_value = self.run_statement(statement)?;
|
||||||
|
|
||||||
@ -103,647 +101,8 @@ impl Vm {
|
|||||||
Ok(previous_value)
|
Ok(previous_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
|
fn run_statement(&self, node: Statement) -> Result<Option<Value>, VmError> {
|
||||||
match node.inner {
|
todo!()
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user