1
0

Continue AST overhaul

This commit is contained in:
Jeff 2024-08-14 15:52:04 -04:00
parent 43b2393d8a
commit fdf324c866
6 changed files with 328 additions and 2171 deletions

View File

@ -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) {

View File

@ -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(),

View File

@ -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!());
}
}

View File

@ -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

View File

@ -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!()
}
}