2024-08-09 01:59:09 +00:00
|
|
|
//! Virtual machine for running the abstract syntax tree.
|
2024-08-12 12:54:21 +00:00
|
|
|
//!
|
|
|
|
//! This module provides three running option:
|
|
|
|
//! - `run` convenience function that takes a source code string and runs it
|
|
|
|
//! - `run_with_context` convenience function that takes a source code string and a context
|
|
|
|
//! - `Vm` struct that can be used to run an abstract syntax tree
|
2024-08-09 00:58:56 +00:00
|
|
|
use std::{
|
2024-08-17 14:07:38 +00:00
|
|
|
collections::HashMap,
|
2024-08-09 00:58:56 +00:00
|
|
|
fmt::{self, Display, Formatter},
|
2024-08-16 09:14:00 +00:00
|
|
|
sync::{Arc, Mutex},
|
2024-08-09 00:58:56 +00:00
|
|
|
};
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-05 19:54:48 +00:00
|
|
|
use crate::{
|
2024-08-16 09:24:55 +00:00
|
|
|
ast::{
|
2024-08-16 10:43:29 +00:00
|
|
|
AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression,
|
2024-08-16 13:22:36 +00:00
|
|
|
FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression,
|
2024-08-17 14:07:38 +00:00
|
|
|
LiteralExpression, LogicOperator, LoopExpression, MapExpression, MathOperator, Node,
|
2024-08-20 08:12:43 +00:00
|
|
|
OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement,
|
|
|
|
StructDefinition, StructExpression,
|
2024-08-16 04:41:52 +00:00
|
|
|
},
|
2024-08-20 15:40:37 +00:00
|
|
|
core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData,
|
2024-08-20 21:01:30 +00:00
|
|
|
ContextError, DustError, Expression, Function, FunctionCallError, Identifier, ParseError,
|
2024-08-23 05:12:20 +00:00
|
|
|
StructType, Type, Value, ValueData, ValueError,
|
2024-08-05 19:54:48 +00:00
|
|
|
};
|
2024-08-05 04:40:51 +00:00
|
|
|
|
2024-08-13 16:23:25 +00:00
|
|
|
/// Run the source code and return the result.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use dust_lang::vm::run;
|
|
|
|
/// # use dust_lang::value::Value;
|
|
|
|
/// let result = run("40 + 2");
|
|
|
|
///
|
2024-08-17 02:43:29 +00:00
|
|
|
/// assert_eq!(result, Ok(Some(Value::Integer(42))));
|
2024-08-13 16:23:25 +00:00
|
|
|
/// ```
|
2024-08-12 01:42:16 +00:00
|
|
|
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
2024-08-20 15:40:37 +00:00
|
|
|
let context = core_library().create_child();
|
2024-08-07 15:38:08 +00:00
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
run_with_context(source, context)
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-13 16:23:25 +00:00
|
|
|
/// Run the source code with a context and return the result.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use dust_lang::{Context, Identifier, Value, run_with_context};
|
|
|
|
/// let context = Context::new();
|
|
|
|
///
|
2024-08-17 02:43:29 +00:00
|
|
|
/// context.set_value(Identifier::new("foo"), Value::Integer(40));
|
2024-08-13 16:23:25 +00:00
|
|
|
/// context.update_last_position(&Identifier::new("foo"), (100, 100));
|
|
|
|
///
|
|
|
|
/// let result = run_with_context("foo + 2", context);
|
|
|
|
///
|
2024-08-17 02:43:29 +00:00
|
|
|
/// assert_eq!(result, Ok(Some(Value::Integer(42))));
|
2024-08-13 16:23:25 +00:00
|
|
|
/// ```
|
2024-08-12 12:54:21 +00:00
|
|
|
pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>, DustError> {
|
2024-08-12 02:41:40 +00:00
|
|
|
let abstract_syntax_tree = parse(source)?;
|
2024-08-20 16:09:17 +00:00
|
|
|
let analyzer = Analyzer::new(&abstract_syntax_tree, context.clone());
|
2024-08-12 02:41:40 +00:00
|
|
|
|
|
|
|
analyzer
|
|
|
|
.analyze()
|
2024-08-20 08:38:15 +00:00
|
|
|
.map_err(|analysis_error| DustError::Analysis {
|
2024-08-17 09:32:18 +00:00
|
|
|
analysis_error,
|
2024-08-12 02:41:40 +00:00
|
|
|
source,
|
|
|
|
})?;
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
let mut vm = Vm::new(abstract_syntax_tree, context);
|
2024-08-12 02:41:40 +00:00
|
|
|
|
2024-08-20 08:38:15 +00:00
|
|
|
vm.run().map_err(|runtime_error| DustError::Runtime {
|
2024-08-17 09:32:18 +00:00
|
|
|
runtime_error,
|
|
|
|
source,
|
|
|
|
})
|
2024-08-12 02:41:40 +00:00
|
|
|
}
|
|
|
|
|
2024-08-13 22:27:03 +00:00
|
|
|
/// Dust virtual machine.
|
|
|
|
///
|
2024-08-13 23:41:36 +00:00
|
|
|
/// **Warning**: Do not run an AbstractSyntaxTree that has not been analyzed *with the same
|
|
|
|
/// context*. Use the `run` or `run_with_context` functions to make sure the program is analyzed
|
|
|
|
/// before running it.
|
2024-08-13 22:27:03 +00:00
|
|
|
///
|
|
|
|
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
|
2024-08-07 23:03:50 +00:00
|
|
|
pub struct Vm {
|
|
|
|
abstract_tree: AbstractSyntaxTree,
|
2024-08-12 12:54:21 +00:00
|
|
|
context: Context,
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 23:03:50 +00:00
|
|
|
impl Vm {
|
2024-08-12 12:54:21 +00:00
|
|
|
pub fn new(abstract_tree: AbstractSyntaxTree, context: Context) -> Self {
|
|
|
|
Self {
|
|
|
|
abstract_tree,
|
|
|
|
context,
|
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
pub fn run(&mut self) -> Result<Option<Value>, RuntimeError> {
|
2024-08-20 18:45:43 +00:00
|
|
|
let mut previous_evaluation = None;
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
while let Some(statement) = self.abstract_tree.statements.pop_front() {
|
2024-08-20 18:45:43 +00:00
|
|
|
previous_evaluation = self.run_statement(statement, true)?;
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-20 18:45:43 +00:00
|
|
|
match previous_evaluation {
|
|
|
|
Some(Evaluation::Break(value_option)) => Ok(value_option),
|
|
|
|
Some(Evaluation::Return(value_option)) => Ok(value_option),
|
|
|
|
_ => Ok(None),
|
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_statement(
|
|
|
|
&self,
|
|
|
|
statement: Statement,
|
|
|
|
collect_garbage: bool,
|
2024-08-20 18:45:43 +00:00
|
|
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
2024-08-20 07:28:13 +00:00
|
|
|
log::debug!("Running statement: {}", statement);
|
|
|
|
|
2024-08-16 04:41:52 +00:00
|
|
|
let position = statement.position();
|
|
|
|
let result = match statement {
|
2024-08-20 18:45:43 +00:00
|
|
|
Statement::Expression(expression) => {
|
|
|
|
Ok(Some(self.run_expression(expression, collect_garbage)?))
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
Statement::ExpressionNullified(expression) => {
|
2024-08-20 18:45:43 +00:00
|
|
|
let evaluation = self.run_expression(expression.inner, collect_garbage)?;
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-20 18:45:43 +00:00
|
|
|
if let Evaluation::Break(_) = evaluation {
|
|
|
|
Ok(Some(evaluation))
|
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
}
|
2024-08-16 13:22:36 +00:00
|
|
|
Statement::Let(let_statement) => {
|
2024-08-16 15:21:20 +00:00
|
|
|
self.run_let_statement(let_statement.inner, collect_garbage)?;
|
2024-08-16 13:22:36 +00:00
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-08-17 02:43:29 +00:00
|
|
|
Statement::StructDefinition(struct_definition) => {
|
|
|
|
let (name, struct_type) = match struct_definition.inner {
|
2024-08-20 04:15:19 +00:00
|
|
|
StructDefinition::Unit { name } => {
|
|
|
|
(name.inner.clone(), StructType::Unit { name: name.inner })
|
|
|
|
}
|
2024-08-17 08:06:13 +00:00
|
|
|
StructDefinition::Tuple { name, items } => {
|
|
|
|
let fields = items.into_iter().map(|item| item.inner).collect();
|
|
|
|
|
2024-08-20 04:15:19 +00:00
|
|
|
(
|
|
|
|
name.inner.clone(),
|
|
|
|
StructType::Tuple {
|
|
|
|
name: name.inner,
|
|
|
|
fields,
|
|
|
|
},
|
|
|
|
)
|
2024-08-17 02:43:29 +00:00
|
|
|
}
|
2024-08-17 14:07:38 +00:00
|
|
|
StructDefinition::Fields { name, fields } => {
|
|
|
|
let fields = fields
|
|
|
|
.into_iter()
|
|
|
|
.map(|(identifier, r#type)| (identifier.inner, r#type.inner))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
(
|
|
|
|
name.inner.clone(),
|
2024-08-20 04:15:19 +00:00
|
|
|
StructType::Fields {
|
|
|
|
name: name.inner,
|
|
|
|
fields,
|
|
|
|
},
|
2024-08-17 14:07:38 +00:00
|
|
|
)
|
|
|
|
}
|
2024-08-17 02:43:29 +00:00
|
|
|
};
|
2024-08-20 06:25:22 +00:00
|
|
|
let constructor = struct_type.constructor();
|
2024-08-17 02:43:29 +00:00
|
|
|
|
2024-08-20 21:01:30 +00:00
|
|
|
self.context
|
|
|
|
.set_constructor(name, constructor)
|
|
|
|
.map_err(|error| RuntimeError::ContextError {
|
|
|
|
error,
|
|
|
|
position: struct_definition.position,
|
|
|
|
})?;
|
2024-08-17 02:43:29 +00:00
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-08-16 04:41:52 +00:00
|
|
|
};
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
if collect_garbage {
|
2024-08-20 21:01:30 +00:00
|
|
|
self.context
|
|
|
|
.collect_garbage(position.1)
|
|
|
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
2024-08-16 15:21:20 +00:00
|
|
|
}
|
2024-08-16 13:22:36 +00:00
|
|
|
|
2024-08-20 04:15:19 +00:00
|
|
|
result.map_err(|error| RuntimeError::Statement {
|
2024-08-16 04:41:52 +00:00
|
|
|
error: Box::new(error),
|
|
|
|
position,
|
|
|
|
})
|
2024-08-16 03:17:49 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_let_statement(
|
|
|
|
&self,
|
|
|
|
let_statement: LetStatement,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<(), RuntimeError> {
|
2024-08-16 13:22:36 +00:00
|
|
|
match let_statement {
|
|
|
|
LetStatement::Let { identifier, value } => {
|
2024-08-20 21:01:30 +00:00
|
|
|
let position = value.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let value = self
|
|
|
|
.run_expression(value, collect_garbage)?
|
2024-08-23 05:12:20 +00:00
|
|
|
.expect_value(position)?
|
|
|
|
.into_reference();
|
2024-08-16 13:22:36 +00:00
|
|
|
|
2024-08-20 21:01:30 +00:00
|
|
|
self.context
|
|
|
|
.set_variable_value(identifier.inner, value)
|
|
|
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
2024-08-16 13:22:36 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
LetStatement::LetMut { identifier, value } => {
|
2024-08-20 21:01:30 +00:00
|
|
|
let position = value.position();
|
2024-08-16 21:07:49 +00:00
|
|
|
let mutable_value = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(value, collect_garbage)?
|
2024-08-20 21:01:30 +00:00
|
|
|
.expect_value(position)?
|
2024-08-16 21:07:49 +00:00
|
|
|
.into_mutable();
|
2024-08-16 13:22:36 +00:00
|
|
|
|
2024-08-20 04:15:19 +00:00
|
|
|
self.context
|
2024-08-20 21:01:30 +00:00
|
|
|
.set_variable_value(identifier.inner, mutable_value)
|
|
|
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
2024-08-16 13:22:36 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
LetStatement::LetType { .. } => todo!(),
|
|
|
|
LetStatement::LetMutType { .. } => todo!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_expression(
|
|
|
|
&self,
|
|
|
|
expression: Expression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-20 07:28:13 +00:00
|
|
|
log::debug!("Running expression: {}", expression);
|
|
|
|
|
2024-08-16 04:41:52 +00:00
|
|
|
let position = expression.position();
|
2024-08-16 09:14:00 +00:00
|
|
|
let evaluation_result = match expression {
|
2024-08-16 15:21:20 +00:00
|
|
|
Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage),
|
2024-08-20 18:45:43 +00:00
|
|
|
Expression::Break(Node { inner, .. }) => {
|
|
|
|
let break_expression = if let Some(expression) = inner {
|
|
|
|
*expression
|
|
|
|
} else {
|
|
|
|
return Ok(Evaluation::Break(None));
|
|
|
|
};
|
|
|
|
let run_break = self.run_expression(break_expression, collect_garbage)?;
|
|
|
|
let evaluation = match run_break {
|
|
|
|
Evaluation::Break(value_option) => Evaluation::Break(value_option),
|
|
|
|
Evaluation::Return(value_option) => Evaluation::Break(value_option),
|
|
|
|
Evaluation::Constructor(_) => {
|
|
|
|
return Err(RuntimeError::ExpectedValue { position })
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(evaluation)
|
|
|
|
}
|
2024-08-16 15:21:20 +00:00
|
|
|
Expression::Call(call) => self.run_call(*call.inner, collect_garbage),
|
|
|
|
Expression::FieldAccess(field_access) => {
|
|
|
|
self.run_field_access(*field_access.inner, collect_garbage)
|
|
|
|
}
|
|
|
|
Expression::Grouped(expression) => {
|
|
|
|
self.run_expression(*expression.inner, collect_garbage)
|
|
|
|
}
|
2024-08-20 21:01:30 +00:00
|
|
|
Expression::Identifier(identifier) => self.run_identifier(identifier),
|
2024-08-16 15:21:20 +00:00
|
|
|
Expression::If(if_expression) => self.run_if(*if_expression.inner, collect_garbage),
|
|
|
|
Expression::List(list_expression) => {
|
|
|
|
self.run_list(*list_expression.inner, collect_garbage)
|
|
|
|
}
|
|
|
|
Expression::ListIndex(list_index) => {
|
|
|
|
self.run_list_index(*list_index.inner, collect_garbage)
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
Expression::Literal(literal) => self.run_literal(*literal.inner),
|
|
|
|
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner),
|
2024-08-17 14:07:38 +00:00
|
|
|
Expression::Map(map_expression) => self.run_map(*map_expression.inner, collect_garbage),
|
2024-08-16 10:43:29 +00:00
|
|
|
Expression::Operator(operator_expression) => {
|
2024-08-16 15:21:20 +00:00
|
|
|
self.run_operator(*operator_expression.inner, collect_garbage)
|
2024-08-16 10:43:29 +00:00
|
|
|
}
|
2024-08-17 14:07:38 +00:00
|
|
|
Expression::Range(range_expression) => {
|
|
|
|
self.run_range(*range_expression.inner, collect_garbage)
|
|
|
|
}
|
|
|
|
Expression::Struct(struct_expression) => {
|
|
|
|
self.run_struct(*struct_expression.inner, collect_garbage)
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
Expression::TupleAccess(_) => todo!(),
|
|
|
|
};
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-20 04:15:19 +00:00
|
|
|
evaluation_result.map_err(|error| RuntimeError::Expression {
|
2024-08-16 09:14:00 +00:00
|
|
|
error: Box::new(error),
|
|
|
|
position,
|
|
|
|
})
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-20 21:01:30 +00:00
|
|
|
fn run_identifier(&self, identifier: Node<Identifier>) -> Result<Evaluation, RuntimeError> {
|
2024-08-20 15:07:13 +00:00
|
|
|
log::debug!("Running identifier: {}", identifier);
|
|
|
|
|
2024-08-20 21:01:30 +00:00
|
|
|
let get_data = self.context.get_data(&identifier.inner).map_err(|error| {
|
|
|
|
RuntimeError::ContextError {
|
|
|
|
error,
|
|
|
|
position: identifier.position,
|
|
|
|
}
|
|
|
|
})?;
|
2024-08-20 15:07:13 +00:00
|
|
|
|
|
|
|
if let Some(ContextData::VariableValue(value)) = get_data {
|
|
|
|
return Ok(Evaluation::Return(Some(value)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(ContextData::Constructor(constructor)) = get_data {
|
|
|
|
if let Constructor::Unit(unit_constructor) = constructor {
|
|
|
|
return Ok(Evaluation::Return(Some(unit_constructor.construct())));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ok(Evaluation::Constructor(constructor));
|
|
|
|
}
|
|
|
|
|
2024-08-20 21:01:30 +00:00
|
|
|
Err(RuntimeError::UnassociatedIdentifier {
|
|
|
|
identifier: identifier.inner,
|
|
|
|
position: identifier.position,
|
|
|
|
})
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
|
|
|
|
2024-08-17 14:07:38 +00:00
|
|
|
fn run_struct(
|
|
|
|
&self,
|
|
|
|
struct_expression: StructExpression,
|
|
|
|
collect_garbage: bool,
|
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-20 07:28:13 +00:00
|
|
|
log::debug!("Running struct expression: {struct_expression}");
|
|
|
|
|
2024-08-20 08:12:43 +00:00
|
|
|
let StructExpression::Fields { name, fields } = struct_expression;
|
2024-08-17 14:07:38 +00:00
|
|
|
|
2024-08-20 08:12:43 +00:00
|
|
|
let position = name.position;
|
2024-08-20 21:01:30 +00:00
|
|
|
let constructor = self
|
|
|
|
.context
|
|
|
|
.get_constructor(&name.inner)
|
|
|
|
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
2024-08-17 14:07:38 +00:00
|
|
|
|
2024-08-20 08:12:43 +00:00
|
|
|
if let Some(constructor) = constructor {
|
|
|
|
if let Constructor::Fields(fields_constructor) = constructor {
|
|
|
|
let mut arguments = HashMap::with_capacity(fields.len());
|
2024-08-17 14:07:38 +00:00
|
|
|
|
2024-08-20 08:12:43 +00:00
|
|
|
for (identifier, expression) in fields {
|
|
|
|
let position = expression.position();
|
|
|
|
let value = self
|
|
|
|
.run_expression(expression, collect_garbage)?
|
|
|
|
.expect_value(position)?;
|
2024-08-17 14:07:38 +00:00
|
|
|
|
2024-08-20 08:12:43 +00:00
|
|
|
arguments.insert(identifier.inner, value);
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
2024-08-20 08:12:43 +00:00
|
|
|
|
|
|
|
Ok(Evaluation::Return(Some(
|
|
|
|
fields_constructor.construct(arguments),
|
|
|
|
)))
|
|
|
|
} else {
|
|
|
|
Err(RuntimeError::ExpectedFieldsConstructor { position })
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
2024-08-20 08:12:43 +00:00
|
|
|
} else {
|
|
|
|
Err(RuntimeError::ExpectedConstructor { position })
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_range(
|
|
|
|
&self,
|
|
|
|
range: RangeExpression,
|
|
|
|
collect_garbage: bool,
|
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
|
|
|
match range {
|
|
|
|
RangeExpression::Exclusive { start, end } => {
|
|
|
|
let start_position = start.position();
|
|
|
|
let start = self
|
|
|
|
.run_expression(start, collect_garbage)?
|
|
|
|
.expect_value(start_position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
|
|
|
|
let start_data = match start {
|
|
|
|
Value::Raw(data) => data,
|
|
|
|
Value::Reference(reference) => reference.as_ref().clone(),
|
|
|
|
Value::Mutable(locked) => locked.read().unwrap().clone(),
|
|
|
|
};
|
2024-08-17 14:07:38 +00:00
|
|
|
let end_position = end.position();
|
|
|
|
let end = self
|
|
|
|
.run_expression(end, collect_garbage)?
|
|
|
|
.expect_value(end_position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
let end_data = match end {
|
|
|
|
Value::Raw(data) => data,
|
|
|
|
Value::Reference(reference) => reference.as_ref().clone(),
|
|
|
|
Value::Mutable(locked) => locked.read().unwrap().clone(),
|
|
|
|
};
|
2024-08-17 14:07:38 +00:00
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
match (start_data, end_data) {
|
|
|
|
(ValueData::Byte(start), ValueData::Byte(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..end))))
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
(ValueData::Character(start), ValueData::Character(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..end))))
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
(ValueData::Float(start), ValueData::Float(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..end))))
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
(ValueData::Integer(start), ValueData::Integer(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..end))))
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
|
|
|
_ => Err(RuntimeError::InvalidRange {
|
|
|
|
start_position,
|
|
|
|
end_position,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RangeExpression::Inclusive { start, end } => {
|
|
|
|
let start_position = start.position();
|
|
|
|
let start = self
|
|
|
|
.run_expression(start, collect_garbage)?
|
|
|
|
.expect_value(start_position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
|
|
|
|
let start_data = match start {
|
|
|
|
Value::Raw(data) => data,
|
|
|
|
Value::Reference(reference) => reference.as_ref().clone(),
|
|
|
|
Value::Mutable(locked) => locked.read().unwrap().clone(),
|
|
|
|
};
|
2024-08-17 14:07:38 +00:00
|
|
|
let end_position = end.position();
|
|
|
|
let end = self
|
|
|
|
.run_expression(end, collect_garbage)?
|
|
|
|
.expect_value(end_position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
let end_data = match end {
|
|
|
|
Value::Raw(data) => data,
|
|
|
|
Value::Reference(reference) => reference.as_ref().clone(),
|
|
|
|
Value::Mutable(locked) => locked.read().unwrap().clone(),
|
|
|
|
};
|
2024-08-17 14:07:38 +00:00
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
match (start_data, end_data) {
|
|
|
|
(ValueData::Byte(start), ValueData::Byte(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..=end))))
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
(ValueData::Character(start), ValueData::Character(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..=end))))
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
(ValueData::Float(start), ValueData::Float(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..=end))))
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
(ValueData::Integer(start), ValueData::Integer(end)) => {
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::range(start..=end))))
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
2024-08-17 14:07:38 +00:00
|
|
|
_ => Err(RuntimeError::InvalidRange {
|
|
|
|
start_position,
|
|
|
|
end_position,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_map(
|
|
|
|
&self,
|
|
|
|
map: MapExpression,
|
|
|
|
collect_garbage: bool,
|
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
|
|
|
let MapExpression { pairs } = map;
|
|
|
|
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
|
|
|
|
for (identifier, expression) in pairs {
|
|
|
|
let expression_position = expression.position();
|
|
|
|
let value = self
|
|
|
|
.run_expression(expression, collect_garbage)?
|
|
|
|
.expect_value(expression_position)?;
|
|
|
|
|
|
|
|
map.insert(identifier.inner, value);
|
|
|
|
}
|
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::map(map))))
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_operator(
|
|
|
|
&self,
|
|
|
|
operator: OperatorExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 09:14:00 +00:00
|
|
|
match operator {
|
2024-08-16 10:43:29 +00:00
|
|
|
OperatorExpression::Assignment { assignee, value } => {
|
|
|
|
let assignee_position = assignee.position();
|
|
|
|
let assignee = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(assignee, collect_garbage)?
|
2024-08-16 10:43:29 +00:00
|
|
|
.expect_value(assignee_position)?;
|
|
|
|
let value_position = value.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let value = self
|
|
|
|
.run_expression(value, collect_garbage)?
|
|
|
|
.expect_value(value_position)?;
|
2024-08-16 10:43:29 +00:00
|
|
|
|
2024-08-16 13:22:36 +00:00
|
|
|
assignee
|
|
|
|
.mutate(value)
|
2024-08-17 09:32:18 +00:00
|
|
|
.map_err(|error| RuntimeError::ValueError {
|
2024-08-16 13:22:36 +00:00
|
|
|
error,
|
|
|
|
left_position: assignee_position,
|
|
|
|
right_position: value_position,
|
|
|
|
})?;
|
2024-08-16 10:43:29 +00:00
|
|
|
|
|
|
|
Ok(Evaluation::Return(None))
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
OperatorExpression::Comparison {
|
|
|
|
left,
|
|
|
|
operator,
|
|
|
|
right,
|
2024-08-16 10:43:29 +00:00
|
|
|
} => {
|
|
|
|
let left_position = left.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let left_value = self
|
|
|
|
.run_expression(left, collect_garbage)?
|
|
|
|
.expect_value(left_position)?;
|
2024-08-16 10:43:29 +00:00
|
|
|
let right_position = right.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let right_value = self
|
|
|
|
.run_expression(right, collect_garbage)?
|
|
|
|
.expect_value(right_position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
let result = match operator.inner {
|
|
|
|
ComparisonOperator::Equal => left_value.equal(&right_value),
|
|
|
|
ComparisonOperator::NotEqual => left_value.not_equal(&right_value),
|
|
|
|
ComparisonOperator::GreaterThan => left_value.greater_than(&right_value),
|
|
|
|
ComparisonOperator::GreaterThanOrEqual => {
|
|
|
|
left_value.greater_than_or_equal(&right_value)
|
|
|
|
}
|
|
|
|
ComparisonOperator::LessThan => left_value.less_than(&right_value),
|
|
|
|
ComparisonOperator::LessThanOrEqual => {
|
|
|
|
left_value.less_than_or_equal(&right_value)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let value = result.map_err(|error| RuntimeError::ValueError {
|
|
|
|
error,
|
|
|
|
left_position,
|
|
|
|
right_position,
|
|
|
|
})?;
|
2024-08-16 10:43:29 +00:00
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
Ok(Evaluation::Return(Some(value)))
|
2024-08-16 10:43:29 +00:00
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
OperatorExpression::CompoundAssignment {
|
|
|
|
assignee,
|
|
|
|
operator,
|
|
|
|
modifier,
|
2024-08-16 13:22:36 +00:00
|
|
|
} => {
|
|
|
|
let assignee_position = assignee.position();
|
|
|
|
let assignee = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(assignee, collect_garbage)?
|
2024-08-16 13:22:36 +00:00
|
|
|
.expect_value(assignee_position)?;
|
|
|
|
let modifier_position = modifier.position();
|
|
|
|
let modifier = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(modifier, collect_garbage)?
|
2024-08-16 13:22:36 +00:00
|
|
|
.expect_value(modifier_position)?;
|
|
|
|
|
|
|
|
match operator.inner {
|
|
|
|
MathOperator::Add => assignee.add_assign(&modifier),
|
|
|
|
MathOperator::Subtract => assignee.subtract_assign(&modifier),
|
|
|
|
MathOperator::Multiply => assignee.multiply_assign(&modifier),
|
|
|
|
MathOperator::Divide => assignee.divide_assign(&modifier),
|
|
|
|
MathOperator::Modulo => assignee.modulo_assign(&modifier),
|
|
|
|
}
|
2024-08-17 09:32:18 +00:00
|
|
|
.map_err(|error| RuntimeError::ValueError {
|
2024-08-16 13:22:36 +00:00
|
|
|
error,
|
|
|
|
left_position: assignee_position,
|
|
|
|
right_position: modifier_position,
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(Evaluation::Return(None))
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
OperatorExpression::ErrorPropagation(_) => todo!(),
|
2024-08-16 15:21:20 +00:00
|
|
|
OperatorExpression::Negation(expression) => {
|
|
|
|
let position = expression.position();
|
|
|
|
let value = self
|
|
|
|
.run_expression(expression, collect_garbage)?
|
|
|
|
.expect_value(position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
let negated = value.negate().map_err(|error| RuntimeError::ValueError {
|
|
|
|
error,
|
|
|
|
left_position: position,
|
|
|
|
right_position: position,
|
|
|
|
})?;
|
2024-08-16 15:21:20 +00:00
|
|
|
|
|
|
|
Ok(Evaluation::Return(Some(negated)))
|
|
|
|
}
|
|
|
|
OperatorExpression::Not(expression) => {
|
|
|
|
let position = expression.position();
|
|
|
|
let value = self
|
|
|
|
.run_expression(expression, collect_garbage)?
|
|
|
|
.expect_value(position)?;
|
2024-08-23 05:12:20 +00:00
|
|
|
let not = value.not().map_err(|error| RuntimeError::ValueError {
|
|
|
|
error,
|
|
|
|
left_position: position,
|
|
|
|
right_position: position,
|
|
|
|
})?;
|
2024-08-16 15:21:20 +00:00
|
|
|
|
|
|
|
Ok(Evaluation::Return(Some(not)))
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
OperatorExpression::Math {
|
|
|
|
left,
|
|
|
|
operator,
|
|
|
|
right,
|
2024-08-16 10:43:29 +00:00
|
|
|
} => {
|
|
|
|
let left_position = left.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let left_value = self
|
|
|
|
.run_expression(left, collect_garbage)?
|
|
|
|
.expect_value(left_position)?;
|
2024-08-16 10:43:29 +00:00
|
|
|
let right_position = right.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let right_value = self
|
|
|
|
.run_expression(right, collect_garbage)?
|
|
|
|
.expect_value(right_position)?;
|
2024-08-16 10:43:29 +00:00
|
|
|
let outcome = match operator.inner {
|
|
|
|
MathOperator::Add => left_value.add(&right_value),
|
|
|
|
MathOperator::Subtract => left_value.subtract(&right_value),
|
|
|
|
MathOperator::Multiply => left_value.multiply(&right_value),
|
|
|
|
MathOperator::Divide => left_value.divide(&right_value),
|
|
|
|
MathOperator::Modulo => left_value.modulo(&right_value),
|
|
|
|
}
|
2024-08-17 09:32:18 +00:00
|
|
|
.map_err(|value_error| RuntimeError::ValueError {
|
2024-08-16 10:43:29 +00:00
|
|
|
error: value_error,
|
|
|
|
left_position,
|
|
|
|
right_position,
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(Evaluation::Return(Some(outcome)))
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
OperatorExpression::Logic {
|
|
|
|
left,
|
|
|
|
operator,
|
|
|
|
right,
|
2024-08-16 10:43:29 +00:00
|
|
|
} => {
|
|
|
|
let left_position = left.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let left_value = self
|
|
|
|
.run_expression(left, collect_garbage)?
|
|
|
|
.expect_value(left_position)?;
|
2024-08-16 10:43:29 +00:00
|
|
|
let right_position = right.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let right_value = self
|
|
|
|
.run_expression(right, collect_garbage)?
|
|
|
|
.expect_value(right_position)?;
|
2024-08-16 10:43:29 +00:00
|
|
|
let outcome = match operator.inner {
|
|
|
|
LogicOperator::And => left_value.and(&right_value),
|
|
|
|
LogicOperator::Or => left_value.or(&right_value),
|
|
|
|
}
|
2024-08-17 09:32:18 +00:00
|
|
|
.map_err(|value_error| RuntimeError::ValueError {
|
2024-08-16 10:43:29 +00:00
|
|
|
error: value_error,
|
|
|
|
left_position,
|
|
|
|
right_position,
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(Evaluation::Return(Some(outcome)))
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
fn run_loop(&self, loop_expression: LoopExpression) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 09:14:00 +00:00
|
|
|
match loop_expression {
|
2024-08-20 18:45:43 +00:00
|
|
|
LoopExpression::Infinite {
|
|
|
|
block: Node { inner, .. },
|
|
|
|
} => match inner {
|
|
|
|
BlockExpression::Sync(statements) => 'outer: loop {
|
|
|
|
for statement in statements.clone() {
|
|
|
|
let evaluation = self.run_statement(statement, false)?;
|
|
|
|
|
|
|
|
if let Some(Evaluation::Break(value_option)) = evaluation {
|
|
|
|
break 'outer Ok(Evaluation::Return(value_option));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
BlockExpression::Async(_) => todo!(),
|
2024-08-16 09:14:00 +00:00
|
|
|
},
|
2024-08-16 15:21:20 +00:00
|
|
|
LoopExpression::While { condition, block } => {
|
|
|
|
while self
|
|
|
|
.run_expression(condition.clone(), false)?
|
|
|
|
.expect_value(condition.position())?
|
|
|
|
.as_boolean()
|
2024-08-17 09:32:18 +00:00
|
|
|
.ok_or_else(|| RuntimeError::ExpectedBoolean {
|
2024-08-16 15:21:20 +00:00
|
|
|
position: condition.position(),
|
|
|
|
})?
|
|
|
|
{
|
|
|
|
self.run_block(block.inner.clone(), false)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Evaluation::Return(None))
|
|
|
|
}
|
2024-08-20 04:15:19 +00:00
|
|
|
LoopExpression::For { .. } => todo!(),
|
2024-08-16 09:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 09:14:00 +00:00
|
|
|
let value = match literal {
|
2024-08-20 11:20:44 +00:00
|
|
|
LiteralExpression::BuiltInFunction(built_in_function) => {
|
2024-08-23 05:12:20 +00:00
|
|
|
Value::function(Function::BuiltIn(built_in_function))
|
2024-08-20 11:20:44 +00:00
|
|
|
}
|
2024-08-23 05:12:20 +00:00
|
|
|
LiteralExpression::String(string) => Value::string(string),
|
2024-08-17 16:15:47 +00:00
|
|
|
LiteralExpression::Primitive(primitive_expression) => match primitive_expression {
|
2024-08-23 05:12:20 +00:00
|
|
|
PrimitiveValueExpression::Boolean(boolean) => Value::boolean(boolean),
|
|
|
|
PrimitiveValueExpression::Character(character) => Value::character(character),
|
|
|
|
PrimitiveValueExpression::Integer(integer) => Value::integer(integer),
|
|
|
|
PrimitiveValueExpression::Float(float) => Value::float(float),
|
2024-08-17 16:15:47 +00:00
|
|
|
},
|
2024-08-16 09:14:00 +00:00
|
|
|
};
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
Ok(Evaluation::Return(Some(value)))
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_list_index(
|
|
|
|
&self,
|
|
|
|
list_index: ListIndexExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 09:14:00 +00:00
|
|
|
let ListIndexExpression { list, index } = list_index;
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
let list_position = list.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let list_value = self
|
|
|
|
.run_expression(list, collect_garbage)?
|
|
|
|
.expect_value(list_position)?;
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
let index_position = index.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let index_value = self
|
|
|
|
.run_expression(index, collect_garbage)?
|
|
|
|
.expect_value(index_position)?;
|
2024-08-16 03:17:49 +00:00
|
|
|
|
2024-08-17 14:07:38 +00:00
|
|
|
let get_index =
|
|
|
|
list_value
|
2024-08-23 05:12:20 +00:00
|
|
|
.index(&index_value)
|
2024-08-17 14:07:38 +00:00
|
|
|
.map_err(|error| RuntimeError::ValueError {
|
|
|
|
error,
|
|
|
|
left_position: list_position,
|
|
|
|
right_position: index_position,
|
|
|
|
})?;
|
2024-08-16 09:14:00 +00:00
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
Ok(Evaluation::Return(Some(get_index)))
|
2024-08-16 09:14:00 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_call(
|
|
|
|
&self,
|
|
|
|
call_expression: CallExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-20 07:28:13 +00:00
|
|
|
log::debug!("Running call expression: {call_expression}");
|
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
let CallExpression { invoker, arguments } = call_expression;
|
2024-08-20 21:01:30 +00:00
|
|
|
let invoker_position = invoker.position();
|
2024-08-16 09:14:00 +00:00
|
|
|
|
2024-08-20 15:07:13 +00:00
|
|
|
if let Expression::FieldAccess(field_access) = invoker {
|
|
|
|
let FieldAccessExpression { container, field } = *field_access.inner;
|
|
|
|
|
|
|
|
let container_position = container.position();
|
|
|
|
let container_value = self
|
|
|
|
.run_expression(container, collect_garbage)?
|
|
|
|
.expect_value(container_position)?;
|
|
|
|
|
|
|
|
let function = if let Some(value) = container_value.get_field(&field.inner) {
|
2024-08-23 05:12:20 +00:00
|
|
|
match value {
|
|
|
|
Value::Raw(ValueData::Function(function)) => function,
|
|
|
|
Value::Reference(arc) => match arc.as_ref().clone() {
|
|
|
|
ValueData::Function(function) => function,
|
|
|
|
_ => {
|
|
|
|
return Err(RuntimeError::ExpectedFunction {
|
|
|
|
position: container_position,
|
|
|
|
actual: container_value,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Value::Mutable(locked) => match locked.read().unwrap().clone() {
|
|
|
|
ValueData::Function(function) => function,
|
|
|
|
_ => {
|
|
|
|
return Err(RuntimeError::ExpectedFunction {
|
|
|
|
position: container_position,
|
|
|
|
actual: container_value,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
return Err(RuntimeError::ExpectedFunction {
|
|
|
|
position: container_position,
|
|
|
|
actual: container_value,
|
|
|
|
});
|
|
|
|
}
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
2024-08-20 23:44:22 +00:00
|
|
|
return Err(RuntimeError::UndefinedField {
|
2024-08-20 15:07:13 +00:00
|
|
|
value: container_value,
|
|
|
|
value_position: container_position,
|
|
|
|
property: field.inner,
|
|
|
|
property_position: field.position,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut value_arguments = vec![container_value];
|
|
|
|
|
|
|
|
for argument in arguments {
|
|
|
|
let position = argument.position();
|
|
|
|
let value = self
|
|
|
|
.run_expression(argument, collect_garbage)?
|
|
|
|
.expect_value(position)?;
|
|
|
|
|
|
|
|
value_arguments.push(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
let context = Context::new();
|
|
|
|
|
|
|
|
return function
|
|
|
|
.call(None, Some(value_arguments), &context)
|
2024-08-20 21:01:30 +00:00
|
|
|
.map(Evaluation::Return)
|
|
|
|
.map_err(|error| RuntimeError::FunctionCall {
|
|
|
|
error,
|
|
|
|
position: invoker_position,
|
|
|
|
});
|
2024-08-20 15:07:13 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
let invoker_position = invoker.position();
|
2024-08-20 04:15:19 +00:00
|
|
|
let run_invoker = self.run_expression(invoker, collect_garbage)?;
|
|
|
|
|
2024-08-20 06:25:22 +00:00
|
|
|
match run_invoker {
|
2024-08-20 07:28:13 +00:00
|
|
|
Evaluation::Constructor(constructor) => match constructor {
|
|
|
|
Constructor::Unit(unit_constructor) => {
|
|
|
|
Ok(Evaluation::Return(Some(unit_constructor.construct())))
|
|
|
|
}
|
|
|
|
Constructor::Tuple(tuple_constructor) => {
|
2024-08-20 06:25:22 +00:00
|
|
|
let mut fields = Vec::new();
|
2024-08-20 04:15:19 +00:00
|
|
|
|
2024-08-20 06:25:22 +00:00
|
|
|
for argument in arguments {
|
|
|
|
let position = argument.position();
|
2024-08-20 04:15:19 +00:00
|
|
|
|
2024-08-20 06:25:22 +00:00
|
|
|
if let Some(value) = self.run_expression(argument, collect_garbage)?.value()
|
|
|
|
{
|
|
|
|
fields.push(value);
|
|
|
|
} else {
|
|
|
|
return Err(RuntimeError::ExpectedValue { position });
|
|
|
|
}
|
|
|
|
}
|
2024-08-20 04:15:19 +00:00
|
|
|
|
2024-08-20 06:25:22 +00:00
|
|
|
let tuple = tuple_constructor.construct(fields);
|
2024-08-20 04:15:19 +00:00
|
|
|
|
2024-08-20 07:28:13 +00:00
|
|
|
Ok(Evaluation::Return(Some(tuple)))
|
2024-08-20 06:25:22 +00:00
|
|
|
}
|
2024-08-20 07:28:13 +00:00
|
|
|
Constructor::Fields(_) => {
|
|
|
|
todo!("Return an error")
|
|
|
|
}
|
|
|
|
},
|
2024-08-20 06:25:22 +00:00
|
|
|
Evaluation::Return(Some(value)) => {
|
2024-08-23 05:12:20 +00:00
|
|
|
let function = match value {
|
|
|
|
Value::Raw(ValueData::Function(function)) => function,
|
|
|
|
Value::Reference(arc) => match arc.as_ref() {
|
|
|
|
ValueData::Function(function) => function.clone(),
|
|
|
|
_ => {
|
|
|
|
return Err(RuntimeError::ExpectedFunction {
|
|
|
|
position: invoker_position,
|
|
|
|
actual: Value::Reference(arc.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Value::Mutable(locked) => match locked.read().unwrap().clone() {
|
|
|
|
ValueData::Function(function) => function,
|
|
|
|
_ => {
|
|
|
|
return Err(RuntimeError::ExpectedFunction {
|
|
|
|
position: invoker_position,
|
|
|
|
actual: Value::Mutable(locked.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
return Err(RuntimeError::ExpectedFunction {
|
|
|
|
position: invoker_position,
|
|
|
|
actual: value,
|
|
|
|
});
|
|
|
|
}
|
2024-08-20 06:25:22 +00:00
|
|
|
};
|
2024-08-20 04:15:19 +00:00
|
|
|
|
2024-08-20 19:43:50 +00:00
|
|
|
let mut value_arguments: Option<Vec<Value>> = None;
|
2024-08-16 09:14:00 +00:00
|
|
|
|
2024-08-20 06:25:22 +00:00
|
|
|
for argument in arguments {
|
|
|
|
let position = argument.position();
|
2024-08-20 07:28:13 +00:00
|
|
|
let value = self
|
|
|
|
.run_expression(argument, collect_garbage)?
|
|
|
|
.expect_value(position)?;
|
2024-08-16 09:14:00 +00:00
|
|
|
|
2024-08-20 19:43:50 +00:00
|
|
|
if let Some(value_arguments) = &mut value_arguments {
|
|
|
|
value_arguments.push(value);
|
|
|
|
} else {
|
|
|
|
value_arguments = Some(vec![value]);
|
|
|
|
}
|
2024-08-20 06:25:22 +00:00
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
|
2024-08-20 06:25:22 +00:00
|
|
|
let context = Context::new();
|
2024-08-16 09:14:00 +00:00
|
|
|
|
2024-08-20 07:28:13 +00:00
|
|
|
function
|
2024-08-20 19:43:50 +00:00
|
|
|
.call(None, value_arguments, &context)
|
2024-08-20 07:28:13 +00:00
|
|
|
.map(Evaluation::Return)
|
2024-08-20 21:01:30 +00:00
|
|
|
.map_err(|error| RuntimeError::FunctionCall {
|
|
|
|
error,
|
|
|
|
position: invoker_position,
|
|
|
|
})
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
2024-08-20 07:28:13 +00:00
|
|
|
_ => Err(RuntimeError::ExpectedValueOrConstructor {
|
|
|
|
position: invoker_position,
|
|
|
|
}),
|
2024-08-16 09:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_field_access(
|
|
|
|
&self,
|
|
|
|
field_access: FieldAccessExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 09:14:00 +00:00
|
|
|
let FieldAccessExpression { container, field } = field_access;
|
|
|
|
|
|
|
|
let container_position = container.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let container_value =
|
|
|
|
if let Some(value) = self.run_expression(container, collect_garbage)?.value() {
|
|
|
|
value
|
|
|
|
} else {
|
2024-08-17 09:32:18 +00:00
|
|
|
return Err(RuntimeError::ExpectedValue {
|
2024-08-16 15:21:20 +00:00
|
|
|
position: container_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-16 04:41:52 +00:00
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
Ok(Evaluation::Return(container_value.get_field(&field.inner)))
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_list(
|
|
|
|
&self,
|
|
|
|
list_expression: ListExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 04:41:52 +00:00
|
|
|
match list_expression {
|
|
|
|
ListExpression::AutoFill {
|
|
|
|
repeat_operand,
|
|
|
|
length_operand,
|
|
|
|
} => {
|
|
|
|
let position = length_operand.position();
|
2024-08-16 09:14:00 +00:00
|
|
|
let length = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(length_operand, collect_garbage)?
|
2024-08-16 09:14:00 +00:00
|
|
|
.expect_value(position)?
|
|
|
|
.as_integer()
|
2024-08-17 09:32:18 +00:00
|
|
|
.ok_or(RuntimeError::ExpectedInteger { position })?;
|
2024-08-16 04:41:52 +00:00
|
|
|
|
|
|
|
let position = repeat_operand.position();
|
2024-08-16 09:14:00 +00:00
|
|
|
let value = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(repeat_operand, collect_garbage)?
|
2024-08-16 09:14:00 +00:00
|
|
|
.expect_value(position)?;
|
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::list(vec![
|
2024-08-16 09:14:00 +00:00
|
|
|
value;
|
|
|
|
length as usize
|
|
|
|
]))))
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
ListExpression::Ordered(expressions) => {
|
2024-08-23 05:12:20 +00:00
|
|
|
let mut values = Vec::with_capacity(expressions.len());
|
2024-08-16 04:41:52 +00:00
|
|
|
|
|
|
|
for expression in expressions {
|
|
|
|
let position = expression.position();
|
2024-08-16 15:21:20 +00:00
|
|
|
let value = self
|
|
|
|
.run_expression(expression, collect_garbage)?
|
|
|
|
.expect_value(position)?;
|
2024-08-16 04:41:52 +00:00
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
values.push(value);
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-23 05:12:20 +00:00
|
|
|
Ok(Evaluation::Return(Some(Value::list(values))))
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_block(
|
|
|
|
&self,
|
|
|
|
block: BlockExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 04:41:52 +00:00
|
|
|
match block {
|
2024-08-16 09:14:00 +00:00
|
|
|
BlockExpression::Async(statements) => {
|
|
|
|
let final_result = Arc::new(Mutex::new(None));
|
2024-08-16 10:43:29 +00:00
|
|
|
let statements_length = statements.len();
|
|
|
|
let error_option =
|
|
|
|
statements
|
|
|
|
.into_par_iter()
|
|
|
|
.enumerate()
|
|
|
|
.find_map_any(|(i, statement)| {
|
2024-08-16 15:21:20 +00:00
|
|
|
let evaluation_result = self.run_statement(statement, false);
|
2024-08-16 10:43:29 +00:00
|
|
|
|
|
|
|
match evaluation_result {
|
2024-08-20 18:45:43 +00:00
|
|
|
Ok(evaluation_option) => {
|
2024-08-16 10:43:29 +00:00
|
|
|
if i == statements_length - 1 {
|
|
|
|
let mut final_result = final_result.lock().unwrap();
|
|
|
|
|
2024-08-20 18:45:43 +00:00
|
|
|
*final_result = evaluation_option;
|
2024-08-16 10:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
Err(error) => Some(error),
|
|
|
|
}
|
|
|
|
});
|
2024-08-16 04:41:52 +00:00
|
|
|
|
|
|
|
if let Some(error) = error_option {
|
|
|
|
Err(error)
|
2024-08-20 18:45:43 +00:00
|
|
|
} else if let Some(evaluation) = final_result.lock().unwrap().take() {
|
|
|
|
Ok(evaluation)
|
2024-08-16 04:41:52 +00:00
|
|
|
} else {
|
2024-08-20 18:45:43 +00:00
|
|
|
Ok(Evaluation::Return(None))
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-16 09:14:00 +00:00
|
|
|
BlockExpression::Sync(statements) => {
|
2024-08-20 18:45:43 +00:00
|
|
|
let mut previous_evaluation = None;
|
2024-08-16 04:41:52 +00:00
|
|
|
|
|
|
|
for statement in statements {
|
2024-08-20 18:45:43 +00:00
|
|
|
previous_evaluation = self.run_statement(statement, collect_garbage)?;
|
|
|
|
|
|
|
|
if let Some(Evaluation::Break(value_option)) = previous_evaluation {
|
|
|
|
return Ok(Evaluation::Break(value_option));
|
|
|
|
}
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-20 18:45:43 +00:00
|
|
|
match previous_evaluation {
|
|
|
|
Some(evaluation) => Ok(evaluation),
|
|
|
|
None => Ok(Evaluation::Return(None)),
|
|
|
|
}
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 15:21:20 +00:00
|
|
|
fn run_if(
|
|
|
|
&self,
|
|
|
|
if_expression: IfExpression,
|
|
|
|
collect_garbage: bool,
|
2024-08-17 09:32:18 +00:00
|
|
|
) -> Result<Evaluation, RuntimeError> {
|
2024-08-16 04:41:52 +00:00
|
|
|
match if_expression {
|
|
|
|
IfExpression::If {
|
|
|
|
condition,
|
|
|
|
if_block,
|
|
|
|
} => {
|
2024-08-16 09:14:00 +00:00
|
|
|
let position = condition.position();
|
|
|
|
let boolean = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(condition, collect_garbage)?
|
2024-08-16 09:14:00 +00:00
|
|
|
.expect_value(position)?
|
|
|
|
.as_boolean()
|
2024-08-17 09:32:18 +00:00
|
|
|
.ok_or(RuntimeError::ExpectedBoolean { position })?;
|
2024-08-16 09:14:00 +00:00
|
|
|
|
|
|
|
if boolean {
|
2024-08-20 18:45:43 +00:00
|
|
|
let evaluation = self.run_block(if_block.inner, collect_garbage)?;
|
|
|
|
|
|
|
|
if let Evaluation::Break(_) = evaluation {
|
|
|
|
return Ok(evaluation);
|
|
|
|
}
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
Ok(Evaluation::Return(None))
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
IfExpression::IfElse {
|
|
|
|
condition,
|
|
|
|
if_block,
|
|
|
|
r#else,
|
|
|
|
} => {
|
2024-08-16 09:14:00 +00:00
|
|
|
let position = condition.position();
|
|
|
|
let boolean = self
|
2024-08-16 15:21:20 +00:00
|
|
|
.run_expression(condition, collect_garbage)?
|
2024-08-16 09:14:00 +00:00
|
|
|
.expect_value(position)?
|
|
|
|
.as_boolean()
|
2024-08-17 09:32:18 +00:00
|
|
|
.ok_or(RuntimeError::ExpectedBoolean { position })?;
|
2024-08-16 09:14:00 +00:00
|
|
|
|
|
|
|
if boolean {
|
2024-08-20 19:16:06 +00:00
|
|
|
self.run_block(if_block.inner, collect_garbage)
|
|
|
|
} else {
|
|
|
|
match r#else {
|
|
|
|
ElseExpression::If(if_expression) => {
|
|
|
|
self.run_if(*if_expression.inner, collect_garbage)
|
|
|
|
}
|
|
|
|
ElseExpression::Block(block) => {
|
|
|
|
self.run_block(block.inner, collect_garbage)
|
|
|
|
}
|
2024-08-16 04:41:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-08-16 03:17:49 +00:00
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 09:14:00 +00:00
|
|
|
enum Evaluation {
|
2024-08-20 18:45:43 +00:00
|
|
|
Break(Option<Value>),
|
2024-08-20 06:25:22 +00:00
|
|
|
Constructor(Constructor),
|
2024-08-16 09:14:00 +00:00
|
|
|
Return(Option<Value>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Evaluation {
|
|
|
|
pub fn value(self) -> Option<Value> {
|
|
|
|
match self {
|
|
|
|
Evaluation::Return(value_option) => value_option,
|
2024-08-20 04:15:19 +00:00
|
|
|
_ => None,
|
2024-08-16 09:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
pub fn expect_value(self, position: Span) -> Result<Value, RuntimeError> {
|
2024-08-16 09:14:00 +00:00
|
|
|
if let Evaluation::Return(Some(value)) = self {
|
|
|
|
Ok(value)
|
|
|
|
} else {
|
2024-08-17 09:32:18 +00:00
|
|
|
Err(RuntimeError::ExpectedValue { position })
|
2024-08-16 09:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2024-08-17 09:32:18 +00:00
|
|
|
pub enum RuntimeError {
|
2024-08-20 21:01:30 +00:00
|
|
|
ContextError {
|
|
|
|
error: ContextError,
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
FunctionCall {
|
|
|
|
error: FunctionCallError,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-05 02:15:31 +00:00
|
|
|
ParseError(ParseError),
|
2024-08-20 04:15:19 +00:00
|
|
|
Expression {
|
|
|
|
error: Box<RuntimeError>,
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
Statement {
|
2024-08-17 09:32:18 +00:00
|
|
|
error: Box<RuntimeError>,
|
2024-08-16 04:41:52 +00:00
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 04:49:17 +00:00
|
|
|
ValueError {
|
|
|
|
error: ValueError,
|
2024-08-16 10:43:29 +00:00
|
|
|
left_position: Span,
|
|
|
|
right_position: Span,
|
2024-08-09 04:49:17 +00:00
|
|
|
},
|
2024-08-05 04:40:51 +00:00
|
|
|
|
|
|
|
// Anaylsis Failures
|
|
|
|
// These should be prevented by running the analyzer before the VM
|
2024-08-09 05:43:58 +00:00
|
|
|
BuiltInFunctionError {
|
|
|
|
error: BuiltInFunctionError,
|
2024-08-20 21:01:30 +00:00
|
|
|
position: Span,
|
2024-08-09 05:43:58 +00:00
|
|
|
},
|
2024-08-20 04:15:19 +00:00
|
|
|
EnumVariantNotFound {
|
|
|
|
identifier: Identifier,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-10 09:23:43 +00:00
|
|
|
ExpectedBoolean {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-20 04:15:19 +00:00
|
|
|
ExpectedConstructor {
|
2024-08-20 08:12:43 +00:00
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedFieldsConstructor {
|
2024-08-20 04:15:19 +00:00
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 04:49:17 +00:00
|
|
|
ExpectedIdentifier {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-12 20:57:10 +00:00
|
|
|
ExpectedIntegerOrRange {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedIdentifierOrString {
|
2024-08-09 04:49:17 +00:00
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedInteger {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-12 09:44:05 +00:00
|
|
|
ExpectedNumber {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-12 20:57:10 +00:00
|
|
|
ExpectedMap {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-17 14:07:38 +00:00
|
|
|
ExpectedType {
|
|
|
|
expected: Type,
|
|
|
|
actual: Type,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 04:49:17 +00:00
|
|
|
ExpectedFunction {
|
|
|
|
actual: Value,
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedList {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedValue {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-20 07:28:13 +00:00
|
|
|
ExpectedValueOrConstructor {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-17 02:43:29 +00:00
|
|
|
InvalidRange {
|
|
|
|
start_position: Span,
|
|
|
|
end_position: Span,
|
|
|
|
},
|
2024-08-20 15:07:13 +00:00
|
|
|
UnassociatedIdentifier {
|
2024-08-17 14:07:38 +00:00
|
|
|
identifier: Identifier,
|
2024-08-20 21:01:30 +00:00
|
|
|
position: Span,
|
2024-08-17 14:07:38 +00:00
|
|
|
},
|
2024-08-20 15:07:13 +00:00
|
|
|
UndefinedType {
|
2024-08-16 09:14:00 +00:00
|
|
|
identifier: Identifier,
|
2024-08-16 10:43:29 +00:00
|
|
|
position: Span,
|
2024-08-09 04:49:17 +00:00
|
|
|
},
|
2024-08-20 23:44:22 +00:00
|
|
|
UndefinedField {
|
2024-08-12 01:37:44 +00:00
|
|
|
value: Value,
|
|
|
|
value_position: Span,
|
|
|
|
property: Identifier,
|
|
|
|
property_position: Span,
|
|
|
|
},
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
impl RuntimeError {
|
2024-08-20 21:01:30 +00:00
|
|
|
pub fn position(&self) -> Span {
|
|
|
|
match self {
|
|
|
|
Self::ContextError { position, .. } => *position,
|
|
|
|
Self::BuiltInFunctionError { position, .. } => *position,
|
|
|
|
Self::FunctionCall { position, .. } => *position,
|
|
|
|
Self::UnassociatedIdentifier { position, .. } => *position,
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ParseError(parse_error) => parse_error.position(),
|
2024-08-20 04:15:19 +00:00
|
|
|
Self::Expression { position, .. } => *position,
|
|
|
|
Self::Statement { position, .. } => *position,
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ValueError {
|
|
|
|
left_position,
|
|
|
|
right_position,
|
|
|
|
..
|
|
|
|
} => (left_position.0, right_position.1),
|
2024-08-20 04:15:19 +00:00
|
|
|
Self::EnumVariantNotFound { position, .. } => *position,
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ExpectedBoolean { position } => *position,
|
2024-08-20 04:15:19 +00:00
|
|
|
Self::ExpectedConstructor { position, .. } => *position,
|
2024-08-20 08:12:43 +00:00
|
|
|
Self::ExpectedFieldsConstructor { position } => *position,
|
2024-08-17 14:07:38 +00:00
|
|
|
Self::ExpectedFunction { position, .. } => *position,
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ExpectedIdentifier { position } => *position,
|
|
|
|
Self::ExpectedIdentifierOrString { position } => *position,
|
|
|
|
Self::ExpectedInteger { position } => *position,
|
2024-08-17 14:07:38 +00:00
|
|
|
Self::ExpectedIntegerOrRange { position } => *position,
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ExpectedList { position } => *position,
|
2024-08-17 14:07:38 +00:00
|
|
|
Self::ExpectedMap { position } => *position,
|
|
|
|
Self::ExpectedNumber { position } => *position,
|
|
|
|
Self::ExpectedType { position, .. } => *position,
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ExpectedValue { position } => *position,
|
2024-08-20 15:07:13 +00:00
|
|
|
Self::ExpectedValueOrConstructor { position } => *position,
|
2024-08-17 02:43:29 +00:00
|
|
|
Self::InvalidRange {
|
|
|
|
start_position,
|
|
|
|
end_position,
|
|
|
|
..
|
|
|
|
} => (start_position.0, end_position.1),
|
2024-08-20 15:07:13 +00:00
|
|
|
|
2024-08-17 14:07:38 +00:00
|
|
|
Self::UndefinedType { position, .. } => *position,
|
2024-08-20 23:44:22 +00:00
|
|
|
Self::UndefinedField {
|
2024-08-16 10:43:29 +00:00
|
|
|
property_position, ..
|
|
|
|
} => *property_position,
|
2024-08-20 21:01:30 +00:00
|
|
|
}
|
2024-08-16 10:43:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
impl From<ParseError> for RuntimeError {
|
2024-08-05 04:40:51 +00:00
|
|
|
fn from(error: ParseError) -> Self {
|
|
|
|
Self::ParseError(error)
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-17 09:32:18 +00:00
|
|
|
impl Display for RuntimeError {
|
2024-08-09 00:58:56 +00:00
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2024-08-20 21:01:30 +00:00
|
|
|
Self::ContextError { error, position } => {
|
|
|
|
write!(f, "Context error at {:?}: {}", position, error)
|
|
|
|
}
|
|
|
|
Self::FunctionCall { error, position } => {
|
|
|
|
write!(f, "Function call error at {:?}: {}", position, error)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
Self::ParseError(parse_error) => write!(f, "{}", parse_error),
|
2024-08-20 04:15:19 +00:00
|
|
|
Self::Expression { error, position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Error while running expression at {:?}: {}",
|
|
|
|
position, error
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Self::Statement { error, position } => {
|
2024-08-16 04:41:52 +00:00
|
|
|
write!(
|
|
|
|
f,
|
2024-08-20 04:15:19 +00:00
|
|
|
"Error while running statement at {:?}: {}",
|
2024-08-16 04:41:52 +00:00
|
|
|
position, error
|
|
|
|
)
|
|
|
|
}
|
2024-08-16 10:43:29 +00:00
|
|
|
Self::ValueError {
|
|
|
|
error,
|
|
|
|
left_position,
|
|
|
|
right_position,
|
|
|
|
} => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Value error with values at positions: {:?} and {:?} {}",
|
|
|
|
left_position, right_position, error
|
|
|
|
)
|
|
|
|
}
|
2024-08-09 05:43:58 +00:00
|
|
|
Self::BuiltInFunctionError { error, .. } => {
|
|
|
|
write!(f, "{}", error)
|
2024-08-09 00:58:56 +00:00
|
|
|
}
|
2024-08-20 04:15:19 +00:00
|
|
|
Self::EnumVariantNotFound {
|
|
|
|
identifier,
|
|
|
|
position,
|
|
|
|
} => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Enum variant not found: {} at position: {:?}",
|
|
|
|
identifier, position
|
|
|
|
)
|
|
|
|
}
|
2024-08-10 09:23:43 +00:00
|
|
|
Self::ExpectedBoolean { position } => {
|
|
|
|
write!(f, "Expected a boolean at position: {:?}", position)
|
|
|
|
}
|
2024-08-20 08:12:43 +00:00
|
|
|
Self::ExpectedConstructor { position } => {
|
|
|
|
write!(f, "Expected a constructor at position: {:?}", position)
|
|
|
|
}
|
|
|
|
Self::ExpectedFieldsConstructor { position } => {
|
2024-08-20 04:15:19 +00:00
|
|
|
write!(
|
|
|
|
f,
|
2024-08-20 08:12:43 +00:00
|
|
|
"Expected a fields constructor at position: {:?}",
|
|
|
|
position
|
2024-08-20 04:15:19 +00:00
|
|
|
)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
Self::ExpectedFunction { actual, position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
2024-08-14 18:28:39 +00:00
|
|
|
"Expected a function, but got {} at position: {:?}",
|
2024-08-09 00:58:56 +00:00
|
|
|
actual, position
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Self::ExpectedIdentifier { position } => {
|
|
|
|
write!(f, "Expected an identifier at position: {:?}", position)
|
|
|
|
}
|
2024-08-12 20:57:10 +00:00
|
|
|
Self::ExpectedIdentifierOrString { position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Expected an identifier or string at position: {:?}",
|
|
|
|
position
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Self::ExpectedIntegerOrRange { position } => {
|
2024-08-09 00:58:56 +00:00
|
|
|
write!(
|
|
|
|
f,
|
2024-08-12 14:43:18 +00:00
|
|
|
"Expected an identifier, integer, or range at position: {:?}",
|
2024-08-09 00:58:56 +00:00
|
|
|
position
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Self::ExpectedInteger { position } => {
|
|
|
|
write!(f, "Expected an integer at position: {:?}", position)
|
|
|
|
}
|
|
|
|
Self::ExpectedList { position } => {
|
|
|
|
write!(f, "Expected a list at position: {:?}", position)
|
|
|
|
}
|
2024-08-17 14:07:38 +00:00
|
|
|
Self::ExpectedType {
|
|
|
|
expected,
|
|
|
|
actual,
|
|
|
|
position,
|
|
|
|
} => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Expected type {}, but got {} at position: {:?}",
|
|
|
|
expected, actual, position
|
|
|
|
)
|
|
|
|
}
|
2024-08-12 20:57:10 +00:00
|
|
|
Self::ExpectedMap { position } => {
|
|
|
|
write!(f, "Expected a map at position: {:?}", position)
|
|
|
|
}
|
2024-08-12 09:44:05 +00:00
|
|
|
Self::ExpectedNumber { position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Expected an integer or float at position: {:?}",
|
|
|
|
position
|
|
|
|
)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
Self::ExpectedValue { position } => {
|
|
|
|
write!(f, "Expected a value at position: {:?}", position)
|
|
|
|
}
|
2024-08-20 07:28:13 +00:00
|
|
|
Self::ExpectedValueOrConstructor { position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Expected a value or constructor at position: {:?}",
|
|
|
|
position
|
|
|
|
)
|
|
|
|
}
|
2024-08-17 02:43:29 +00:00
|
|
|
Self::InvalidRange {
|
|
|
|
start_position,
|
|
|
|
end_position,
|
|
|
|
} => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Invalid range with start position: {:?} and end position: {:?}",
|
|
|
|
start_position, end_position
|
|
|
|
)
|
|
|
|
}
|
2024-08-20 21:01:30 +00:00
|
|
|
Self::UnassociatedIdentifier { identifier, .. } => {
|
2024-08-16 10:43:29 +00:00
|
|
|
write!(
|
|
|
|
f,
|
2024-08-20 15:07:13 +00:00
|
|
|
"Identifier \"{identifier}\" is not associated with a value or constructor"
|
2024-08-16 10:43:29 +00:00
|
|
|
)
|
2024-08-09 04:49:17 +00:00
|
|
|
}
|
2024-08-20 23:44:22 +00:00
|
|
|
Self::UndefinedField {
|
2024-08-12 01:37:44 +00:00
|
|
|
value, property, ..
|
|
|
|
} => {
|
|
|
|
write!(f, "Value {} does not have the property {}", value, property)
|
|
|
|
}
|
2024-08-17 14:07:38 +00:00
|
|
|
Self::UndefinedType {
|
|
|
|
identifier,
|
|
|
|
position,
|
|
|
|
} => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Undefined type {} at position: {:?}",
|
|
|
|
identifier, position
|
|
|
|
)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2024-08-17 08:06:13 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use crate::Struct;
|
2024-08-13 18:21:31 +00:00
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
use super::*;
|
|
|
|
|
2024-08-20 18:45:43 +00:00
|
|
|
#[test]
|
|
|
|
fn break_loop() {
|
|
|
|
let input = "let mut x = 0; loop { x += 1; if x == 10 { break; } } x";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::mutable(Value::integer(10)))));
|
2024-08-20 18:45:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-17 14:07:38 +00:00
|
|
|
#[test]
|
|
|
|
fn string_index() {
|
|
|
|
let input = "'foo'[0]";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::character('f'))));
|
2024-08-17 14:07:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_expression() {
|
|
|
|
let input = "let x = map { foo = 42, bar = 4.2 }; x";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
|
|
|
Ok(Some(Value::map([
|
2024-08-23 07:04:11 +00:00
|
|
|
(Identifier::new("foo"), Value::integer(42)),
|
|
|
|
(Identifier::new("bar"), Value::float(4.2))
|
2024-08-17 14:07:38 +00:00
|
|
|
])))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-14 03:45:17 +00:00
|
|
|
#[test]
|
|
|
|
fn async_block() {
|
2024-08-17 14:07:38 +00:00
|
|
|
let input = "let mut x = 1; async { x += 1; x -= 1; } x";
|
2024-08-14 03:45:17 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::mutable(Value::integer(1)))));
|
2024-08-14 03:45:17 +00:00
|
|
|
}
|
|
|
|
|
2024-08-13 23:41:36 +00:00
|
|
|
#[test]
|
|
|
|
fn define_and_instantiate_fields_struct() {
|
2024-08-16 13:22:36 +00:00
|
|
|
let input = "struct Foo { bar: int, baz: float } Foo { bar: 42, baz: 4.0 }";
|
2024-08-13 23:41:36 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Some(Value::r#struct(Struct::Fields {
|
2024-08-17 08:06:13 +00:00
|
|
|
name: Identifier::new("Foo"),
|
|
|
|
fields: HashMap::from([
|
2024-08-23 07:04:11 +00:00
|
|
|
(Identifier::new("bar"), Value::integer(42)),
|
|
|
|
(Identifier::new("baz"), Value::float(4.0))
|
2024-08-17 08:06:13 +00:00
|
|
|
])
|
2024-08-13 23:41:36 +00:00
|
|
|
})))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 20:46:54 +00:00
|
|
|
#[test]
|
|
|
|
fn assign_tuple_struct_variable() {
|
|
|
|
let input = "
|
2024-08-20 04:15:19 +00:00
|
|
|
struct Foo(int);
|
|
|
|
let x = Foo(42);
|
2024-08-13 20:46:54 +00:00
|
|
|
x
|
|
|
|
";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Some(Value::r#struct(Struct::Tuple {
|
2024-08-17 08:06:13 +00:00
|
|
|
name: Identifier::new("Foo"),
|
2024-08-23 07:04:11 +00:00
|
|
|
fields: vec![Value::integer(42)]
|
2024-08-13 20:46:54 +00:00
|
|
|
})))
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
#[test]
|
|
|
|
fn define_and_instantiate_tuple_struct() {
|
2024-08-20 04:15:19 +00:00
|
|
|
let input = "struct Foo(int); Foo(42)";
|
2024-08-13 20:21:44 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Some(Value::r#struct(Struct::Tuple {
|
2024-08-17 08:06:13 +00:00
|
|
|
name: Identifier::new("Foo"),
|
2024-08-23 07:04:11 +00:00
|
|
|
fields: vec![Value::integer(42)]
|
2024-08-13 20:21:44 +00:00
|
|
|
})))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
#[test]
|
|
|
|
fn assign_unit_struct_variable() {
|
|
|
|
let input = "
|
2024-08-17 14:07:38 +00:00
|
|
|
struct Foo;
|
|
|
|
let x = Foo;
|
2024-08-13 19:12:32 +00:00
|
|
|
x
|
|
|
|
";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Some(Value::r#struct(Struct::Unit {
|
2024-08-17 08:06:13 +00:00
|
|
|
name: Identifier::new("Foo")
|
2024-08-13 19:12:32 +00:00
|
|
|
})))
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-08-13 18:21:31 +00:00
|
|
|
#[test]
|
|
|
|
fn define_and_instantiate_unit_struct() {
|
2024-08-20 04:15:19 +00:00
|
|
|
let input = "struct Foo; Foo";
|
2024-08-13 18:21:31 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Some(Value::r#struct(Struct::Unit {
|
2024-08-17 08:06:13 +00:00
|
|
|
name: Identifier::new("Foo")
|
2024-08-13 18:21:31 +00:00
|
|
|
})))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:57:10 +00:00
|
|
|
#[test]
|
|
|
|
fn list_index_nested() {
|
|
|
|
let input = "[[1, 2], [42, 4], [5, 6]][1][0]";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
2024-08-12 20:57:10 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 14:43:18 +00:00
|
|
|
#[test]
|
|
|
|
fn list_index_range() {
|
2024-08-12 20:57:10 +00:00
|
|
|
let input = "[1, 2, 3, 4, 5][1..3]";
|
2024-08-12 14:43:18 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
2024-08-23 07:04:11 +00:00
|
|
|
Ok(Some(Value::list(vec![
|
|
|
|
Value::integer(2),
|
|
|
|
Value::integer(3)
|
2024-08-12 14:43:18 +00:00
|
|
|
])))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 14:29:06 +00:00
|
|
|
#[test]
|
|
|
|
fn range() {
|
|
|
|
let input = "1..5";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::range(1..5))));
|
2024-08-12 14:29:06 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 09:44:05 +00:00
|
|
|
#[test]
|
|
|
|
fn negate_expression() {
|
2024-08-16 15:21:20 +00:00
|
|
|
let input = "let x = -42; -x";
|
2024-08-12 09:44:05 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
2024-08-12 09:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn not_expression() {
|
|
|
|
let input = "!(1 == 2 || 3 == 4 || 5 == 6)";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-12 09:44:05 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 02:02:17 +00:00
|
|
|
#[test]
|
|
|
|
fn list_index() {
|
2024-08-12 20:57:10 +00:00
|
|
|
let input = "[1, 42, 3][1]";
|
2024-08-12 02:02:17 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
2024-08-12 02:02:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_property_access() {
|
2024-08-20 04:15:19 +00:00
|
|
|
let input = "map { a = 42 }.a";
|
2024-08-12 02:02:17 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
2024-08-12 02:02:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn built_in_function_dot_notation() {
|
|
|
|
let input = "42.to_string()";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::string("42"))));
|
|
|
|
}
|
|
|
|
|
2024-08-11 19:12:19 +00:00
|
|
|
#[test]
|
|
|
|
fn to_string() {
|
2024-08-11 23:18:13 +00:00
|
|
|
let input = "to_string(42)";
|
2024-08-11 19:12:19 +00:00
|
|
|
|
2024-08-17 02:43:29 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::string("42"))));
|
2024-08-11 19:12:19 +00:00
|
|
|
}
|
|
|
|
|
2024-08-11 19:03:26 +00:00
|
|
|
#[test]
|
|
|
|
fn r#if() {
|
|
|
|
let input = "if true { 1 }";
|
|
|
|
|
2024-08-12 01:42:16 +00:00
|
|
|
assert_eq!(run(input), Ok(None));
|
2024-08-11 19:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn if_else() {
|
2024-08-17 08:06:13 +00:00
|
|
|
let input = "let x = if false { 1 } else { 2 }; x";
|
2024-08-11 19:03:26 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(2))));
|
2024-08-11 19:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn if_else_if() {
|
|
|
|
let input = "if false { 1 } else if true { 2 }";
|
|
|
|
|
2024-08-12 01:42:16 +00:00
|
|
|
assert_eq!(run(input), Ok(None));
|
2024-08-11 19:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn if_else_if_else() {
|
|
|
|
let input = "if false { 1 } else if false { 2 } else { 3 }";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
2024-08-11 19:03:26 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 09:23:43 +00:00
|
|
|
#[test]
|
|
|
|
fn while_loop() {
|
2024-08-17 08:06:13 +00:00
|
|
|
let input = "let mut x = 0; while x < 5 { x += 1 } x";
|
2024-08-10 09:23:43 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(5))));
|
2024-08-10 09:23:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 01:24:56 +00:00
|
|
|
#[test]
|
|
|
|
fn subtract_assign() {
|
2024-08-16 13:22:36 +00:00
|
|
|
let input = "let mut x = 1; x -= 1; x";
|
2024-08-14 01:24:56 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(0))));
|
2024-08-14 01:24:56 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
#[test]
|
|
|
|
fn add_assign() {
|
2024-08-16 13:22:36 +00:00
|
|
|
let input = "let mut x = 1; x += 1; x";
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(2))));
|
2024-08-09 22:14:46 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 10:43:29 +00:00
|
|
|
#[test]
|
|
|
|
fn and() {
|
|
|
|
let input = "true && true";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-16 10:43:29 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
#[test]
|
|
|
|
fn or() {
|
|
|
|
let input = "true || false";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-09 18:01:01 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 11:15:09 +00:00
|
|
|
#[test]
|
|
|
|
fn integer_equal() {
|
|
|
|
let input = "42 == 42";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-09 11:15:09 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 11:02:55 +00:00
|
|
|
#[test]
|
|
|
|
fn modulo() {
|
|
|
|
let input = "42 % 2";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(0))));
|
2024-08-09 11:02:55 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 10:46:24 +00:00
|
|
|
#[test]
|
|
|
|
fn divide() {
|
|
|
|
let input = "42 / 2";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(21))));
|
2024-08-09 10:46:24 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 07:00:48 +00:00
|
|
|
#[test]
|
|
|
|
fn less_than() {
|
|
|
|
let input = "2 < 3";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-09 07:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn less_than_or_equal() {
|
|
|
|
let input = "42 <= 42";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-09 07:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn greater_than() {
|
|
|
|
let input = "2 > 3";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(false))));
|
2024-08-09 07:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn greater_than_or_equal() {
|
|
|
|
let input = "42 >= 42";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-09 07:00:48 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 03:28:47 +00:00
|
|
|
#[test]
|
|
|
|
fn integer_saturating_add() {
|
|
|
|
let input = "9223372036854775807 + 1";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(i64::MAX))));
|
2024-08-09 03:28:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn integer_saturating_sub() {
|
|
|
|
let input = "-9223372036854775808 - 1";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(i64::MIN))));
|
2024-08-09 03:28:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiply() {
|
|
|
|
let input = "2 * 3";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
2024-08-09 03:28:47 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 14:50:19 +00:00
|
|
|
#[test]
|
|
|
|
fn boolean() {
|
|
|
|
let input = "true";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-07 14:50:19 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 19:54:48 +00:00
|
|
|
#[test]
|
|
|
|
fn is_even() {
|
2024-08-20 23:44:22 +00:00
|
|
|
let input = "42.is_even";
|
2024-08-05 19:54:48 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-05 19:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn is_odd() {
|
2024-08-20 23:44:22 +00:00
|
|
|
let input = "42.is_odd";
|
2024-08-05 19:54:48 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(false))));
|
2024-08-05 19:54:48 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
#[test]
|
2024-08-20 22:48:25 +00:00
|
|
|
fn list_length() {
|
|
|
|
let input = "[1, 2, 3].length";
|
2024-08-05 18:58:58 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
2024-08-05 18:58:58 +00:00
|
|
|
}
|
|
|
|
|
2024-08-20 22:48:25 +00:00
|
|
|
#[test]
|
|
|
|
fn string_length() {
|
|
|
|
let input = "\"hello\".length";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(5))));
|
2024-08-20 22:48:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_length() {
|
|
|
|
let input = "map { a = 42, b = 4.0 }.length";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(2))));
|
2024-08-20 22:48:25 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[test]
|
|
|
|
fn add() {
|
|
|
|
let input = "1 + 2";
|
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
2024-08-05 03:11:04 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_multiple() {
|
2024-08-05 04:40:51 +00:00
|
|
|
let input = "1 + 2 + 3";
|
2024-08-05 03:11:04 +00:00
|
|
|
|
2024-08-23 07:04:11 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
2024-08-05 03:11:04 +00:00
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|