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-10 01:12:36 +00:00
|
|
|
collections::BTreeMap,
|
2024-08-09 00:58:56 +00:00
|
|
|
fmt::{self, Display, Formatter},
|
|
|
|
};
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-14 03:45:17 +00:00
|
|
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
|
|
|
|
2024-08-05 19:54:48 +00:00
|
|
|
use crate::{
|
2024-08-14 05:03:46 +00:00
|
|
|
parse, AbstractSyntaxTree, Analyzer, AssignmentOperator, BinaryOperator, BuiltInFunctionError,
|
|
|
|
Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructType, Type,
|
|
|
|
UnaryOperator, Value, 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");
|
|
|
|
///
|
|
|
|
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
|
|
/// ```
|
2024-08-12 01:42:16 +00:00
|
|
|
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
2024-08-12 12:54:21 +00:00
|
|
|
let context = Context::new();
|
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();
|
|
|
|
///
|
|
|
|
/// context.set_value(Identifier::new("foo"), Value::integer(40));
|
|
|
|
/// context.update_last_position(&Identifier::new("foo"), (100, 100));
|
|
|
|
///
|
|
|
|
/// let result = run_with_context("foo + 2", context);
|
|
|
|
///
|
|
|
|
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
|
|
/// ```
|
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-12 12:54:21 +00:00
|
|
|
let mut analyzer = Analyzer::new(&abstract_syntax_tree, &context);
|
2024-08-12 02:41:40 +00:00
|
|
|
|
|
|
|
analyzer
|
|
|
|
.analyze()
|
|
|
|
.map_err(|analyzer_error| DustError::AnalyzerError {
|
|
|
|
analyzer_error,
|
|
|
|
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-12 12:54:21 +00:00
|
|
|
vm.run()
|
2024-08-12 02:41:40 +00:00
|
|
|
.map_err(|vm_error| DustError::VmError { vm_error, source })
|
|
|
|
}
|
|
|
|
|
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-12 12:54:21 +00:00
|
|
|
pub fn run(&mut self) -> Result<Option<Value>, VmError> {
|
2024-08-12 08:10:07 +00:00
|
|
|
let mut previous_position = (0, 0);
|
2024-08-05 02:15:31 +00:00
|
|
|
let mut previous_value = None;
|
|
|
|
|
2024-08-12 02:41:40 +00:00
|
|
|
while let Some(statement) = self.abstract_tree.nodes.pop_front() {
|
2024-08-12 08:10:07 +00:00
|
|
|
let new_position = statement.position;
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
previous_value = self.run_statement(statement)?;
|
2024-08-12 08:10:07 +00:00
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
self.context.collect_garbage(previous_position.1);
|
2024-08-12 02:41:40 +00:00
|
|
|
|
2024-08-12 08:10:07 +00:00
|
|
|
previous_position = new_position;
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
self.context.collect_garbage(previous_position.1);
|
2024-08-12 08:10:07 +00:00
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
Ok(previous_value)
|
|
|
|
}
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
|
2024-08-09 07:00:48 +00:00
|
|
|
match node.inner {
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier,
|
2024-08-09 08:23:02 +00:00
|
|
|
operator,
|
2024-08-13 21:34:45 +00:00
|
|
|
value,
|
|
|
|
} => match operator.inner {
|
|
|
|
AssignmentOperator::Assign => {
|
|
|
|
let position = value.position;
|
|
|
|
let value = if let Some(value) = self.run_statement(*value)? {
|
2024-08-09 22:14:46 +00:00
|
|
|
value
|
|
|
|
} else {
|
2024-08-13 21:34:45 +00:00
|
|
|
return Err(VmError::ExpectedValue { position });
|
2024-08-09 22:14:46 +00:00
|
|
|
};
|
|
|
|
|
2024-08-13 21:34:45 +00:00
|
|
|
self.context.set_value(identifier.inner, value);
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-13 21:34:45 +00:00
|
|
|
Ok(None)
|
2024-08-09 22:14:46 +00:00
|
|
|
}
|
2024-08-13 21:34:45 +00:00
|
|
|
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)? {
|
2024-08-09 22:14:46 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
2024-08-13 21:34:45 +00:00
|
|
|
position: value_position,
|
2024-08-09 22:14:46 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
let new_value = left_value.add(&right_value).map_err(|value_error| {
|
|
|
|
VmError::ValueError {
|
|
|
|
error: value_error,
|
2024-08-13 21:34:45 +00:00
|
|
|
position: (identifier.position.0, value_position.1),
|
2024-08-09 22:14:46 +00:00
|
|
|
}
|
|
|
|
})?;
|
|
|
|
|
2024-08-13 21:34:45 +00:00
|
|
|
self.context.set_value(identifier.inner, new_value);
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-13 21:34:45 +00:00
|
|
|
Ok(None)
|
2024-08-09 22:14:46 +00:00
|
|
|
}
|
2024-08-13 21:34:45 +00:00
|
|
|
AssignmentOperator::SubtractAssign => {
|
2024-08-14 01:24:56 +00:00
|
|
|
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,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let new_value = left_value.subtract(&right_value).map_err(|value_error| {
|
|
|
|
VmError::ValueError {
|
|
|
|
error: value_error,
|
|
|
|
position: (identifier.position.0, value_position.1),
|
|
|
|
}
|
|
|
|
})?;
|
|
|
|
|
|
|
|
self.context.set_value(identifier.inner, new_value);
|
|
|
|
|
|
|
|
Ok(None)
|
2024-08-13 21:34:45 +00:00
|
|
|
}
|
|
|
|
},
|
2024-08-14 03:45:17 +00:00
|
|
|
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)
|
|
|
|
}
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left,
|
|
|
|
operator,
|
|
|
|
right,
|
|
|
|
} => {
|
|
|
|
let right_position = right.position;
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-12 19:02:04 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2024-08-12 20:57:10 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
};
|
2024-08-12 19:02:04 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 20:57:10 +00:00
|
|
|
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,
|
2024-08-12 19:02:04 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-09 08:23:02 +00:00
|
|
|
let left_position = left.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let left_value = if let Some(value) = self.run_statement(*left)? {
|
2024-08-12 08:10:07 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-12 12:54:21 +00:00
|
|
|
let right_value = if let Some(value) = self.run_statement(*right)? {
|
2024-08-12 08:10:07 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-05 04:40:51 +00:00
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
match operator.inner {
|
2024-08-09 08:23:02 +00:00
|
|
|
BinaryOperator::Add => left_value.add(&right_value),
|
2024-08-09 08:56:24 +00:00
|
|
|
BinaryOperator::And => left_value.and(&right_value),
|
2024-08-09 10:46:24 +00:00
|
|
|
BinaryOperator::Divide => left_value.divide(&right_value),
|
2024-08-09 11:15:09 +00:00
|
|
|
BinaryOperator::Equal => Ok(Value::boolean(left_value == right_value)),
|
2024-08-09 08:23:02 +00:00
|
|
|
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),
|
2024-08-09 11:02:55 +00:00
|
|
|
BinaryOperator::Modulo => left_value.modulo(&right_value),
|
2024-08-09 08:23:02 +00:00
|
|
|
BinaryOperator::Multiply => left_value.multiply(&right_value),
|
2024-08-09 08:56:24 +00:00
|
|
|
BinaryOperator::Or => left_value.or(&right_value),
|
2024-08-09 08:23:02 +00:00
|
|
|
BinaryOperator::Subtract => left_value.subtract(&right_value),
|
2024-08-09 22:14:46 +00:00
|
|
|
_ => unreachable!(),
|
2024-08-09 08:23:02 +00:00
|
|
|
}
|
2024-08-09 22:14:46 +00:00
|
|
|
.map(Some)
|
2024-08-09 08:23:02 +00:00
|
|
|
.map_err(|value_error| VmError::ValueError {
|
|
|
|
error: value_error,
|
|
|
|
position: node.position,
|
2024-08-09 22:14:46 +00:00
|
|
|
})
|
2024-08-05 04:40:51 +00:00
|
|
|
}
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Block(statements) => {
|
|
|
|
let mut previous_value = None;
|
|
|
|
|
|
|
|
for statement in statements {
|
2024-08-12 12:54:21 +00:00
|
|
|
previous_value = self.run_statement(statement)?;
|
2024-08-09 15:41:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(previous_value)
|
|
|
|
}
|
2024-08-07 22:24:25 +00:00
|
|
|
Statement::BuiltInFunctionCall {
|
|
|
|
function,
|
|
|
|
type_arguments: _,
|
|
|
|
value_arguments: value_nodes,
|
|
|
|
} => {
|
2024-08-07 22:46:40 +00:00
|
|
|
let values = if let Some(nodes) = value_nodes {
|
2024-08-07 22:24:25 +00:00
|
|
|
let mut values = Vec::new();
|
|
|
|
|
|
|
|
for node in nodes {
|
|
|
|
let position = node.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let value = if let Some(value) = self.run_statement(node)? {
|
2024-08-07 22:24:25 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue { position });
|
|
|
|
};
|
|
|
|
|
|
|
|
values.push(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(values)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2024-08-09 05:43:58 +00:00
|
|
|
let function_call_return =
|
|
|
|
function
|
|
|
|
.call(None, values)
|
|
|
|
.map_err(|built_in_function_error| VmError::BuiltInFunctionError {
|
|
|
|
error: built_in_function_error,
|
|
|
|
position: node.position,
|
|
|
|
})?;
|
2024-08-07 22:24:25 +00:00
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
Ok(function_call_return)
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
|
|
|
Statement::Constant(value) => Ok(Some(value.clone())),
|
2024-08-13 23:41:36 +00:00
|
|
|
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,
|
|
|
|
})))
|
|
|
|
}
|
2024-08-13 20:21:44 +00:00
|
|
|
Statement::Invokation {
|
|
|
|
invokee,
|
2024-08-07 22:46:40 +00:00
|
|
|
type_arguments: _,
|
2024-08-07 22:24:25 +00:00
|
|
|
value_arguments: value_parameter_nodes,
|
|
|
|
} => {
|
2024-08-13 20:21:44 +00:00
|
|
|
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)? {
|
2024-08-12 12:54:21 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
2024-08-13 20:21:44 +00:00
|
|
|
position: invokee_position,
|
2024-08-12 12:54:21 +00:00
|
|
|
});
|
|
|
|
};
|
2024-08-07 22:24:25 +00:00
|
|
|
let function = if let Some(function) = function_value.as_function() {
|
|
|
|
function
|
|
|
|
} else {
|
2024-08-09 00:58:56 +00:00
|
|
|
return Err(VmError::ExpectedFunction {
|
|
|
|
actual: function_value,
|
2024-08-13 20:21:44 +00:00
|
|
|
position: invokee_position,
|
2024-08-09 00:58:56 +00:00
|
|
|
});
|
2024-08-07 22:24:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2024-08-12 12:54:21 +00:00
|
|
|
let value = if let Some(value) = self.run_statement(node)? {
|
2024-08-07 22:24:25 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue { position });
|
|
|
|
};
|
|
|
|
|
|
|
|
value_parameters.push(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(value_parameters)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
Ok(function
|
|
|
|
.clone()
|
|
|
|
.call(None, value_parameters, &self.context)?)
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
2024-08-09 04:49:17 +00:00
|
|
|
Statement::Identifier(identifier) => {
|
2024-08-12 12:54:21 +00:00
|
|
|
let value_option = self.context.get_value(&identifier);
|
2024-08-12 02:41:40 +00:00
|
|
|
|
|
|
|
if let Some(value) = value_option {
|
2024-08-13 18:21:31 +00:00
|
|
|
return Ok(Some(value.clone()));
|
2024-08-09 04:49:17 +00:00
|
|
|
}
|
2024-08-13 18:21:31 +00:00
|
|
|
|
|
|
|
let type_option = self.context.get_type(&identifier);
|
|
|
|
|
|
|
|
println!("{type_option:?}");
|
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
if let Some(Type::Struct(StructType::Unit { name })) = type_option {
|
|
|
|
return Ok(Some(Value::r#struct(Struct::Unit { name })));
|
2024-08-13 18:21:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Err(VmError::UndefinedVariable {
|
2024-08-13 21:34:45 +00:00
|
|
|
identifier: Node::new(identifier, node.position),
|
2024-08-13 18:21:31 +00:00
|
|
|
})
|
2024-08-09 04:49:17 +00:00
|
|
|
}
|
2024-08-11 18:35:33 +00:00
|
|
|
Statement::If { condition, body } => {
|
|
|
|
let condition_position = condition.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-11 19:03:26 +00:00
|
|
|
let condition = if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
condition
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
2024-08-11 19:03:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if condition {
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(*body)?;
|
2024-08-11 18:35:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
Statement::IfElse {
|
|
|
|
condition,
|
|
|
|
if_body,
|
|
|
|
else_body,
|
|
|
|
} => {
|
|
|
|
let condition_position = condition.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-11 18:35:33 +00:00
|
|
|
|
|
|
|
if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
if condition {
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(*if_body)
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(*else_body)
|
2024-08-11 18:35:33 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Statement::IfElseIf {
|
|
|
|
condition,
|
|
|
|
if_body,
|
|
|
|
else_ifs,
|
|
|
|
} => {
|
|
|
|
let condition_position = condition.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-11 18:35:33 +00:00
|
|
|
|
|
|
|
if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
if condition {
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(*if_body)
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
|
|
|
for (condition, body) in else_ifs {
|
|
|
|
let condition_position = condition.position;
|
2024-08-12 08:10:07 +00:00
|
|
|
let condition_value =
|
2024-08-12 12:54:21 +00:00
|
|
|
if let Some(value) = self.run_statement(condition)? {
|
2024-08-12 08:10:07 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-11 19:03:26 +00:00
|
|
|
let condition = if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
condition
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
2024-08-11 19:03:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if condition {
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(body)?;
|
2024-08-11 18:35:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Statement::IfElseIfElse {
|
|
|
|
condition,
|
|
|
|
if_body,
|
|
|
|
else_ifs,
|
|
|
|
else_body,
|
|
|
|
} => {
|
|
|
|
let condition_position = condition.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-11 18:35:33 +00:00
|
|
|
|
|
|
|
if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
if condition {
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(*if_body)
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
|
|
|
for (condition, body) in else_ifs {
|
|
|
|
let condition_position = condition.position;
|
2024-08-12 08:10:07 +00:00
|
|
|
let condition_value =
|
2024-08-12 12:54:21 +00:00
|
|
|
if let Some(value) = self.run_statement(condition)? {
|
2024-08-12 08:10:07 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
};
|
2024-08-11 19:03:26 +00:00
|
|
|
let condition = if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
condition
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
2024-08-11 19:03:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if condition {
|
2024-08-12 12:54:21 +00:00
|
|
|
return self.run_statement(body);
|
2024-08-11 18:35:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
self.run_statement(*else_body)
|
2024-08-11 18:35:33 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2024-08-05 04:40:51 +00:00
|
|
|
Statement::List(nodes) => {
|
|
|
|
let values = nodes
|
|
|
|
.into_iter()
|
|
|
|
.map(|node| {
|
2024-08-07 19:47:37 +00:00
|
|
|
let span = node.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
if let Some(value) = self.run_statement(node)? {
|
2024-08-05 04:40:51 +00:00
|
|
|
Ok(value)
|
|
|
|
} else {
|
|
|
|
Err(VmError::ExpectedValue { position: span })
|
|
|
|
}
|
|
|
|
})
|
2024-08-07 23:03:50 +00:00
|
|
|
.collect::<Result<Vec<Value>, VmError>>()?;
|
2024-08-05 04:40:51 +00:00
|
|
|
|
|
|
|
Ok(Some(Value::list(values)))
|
|
|
|
}
|
2024-08-09 10:09:59 +00:00
|
|
|
Statement::Map(nodes) => {
|
|
|
|
let mut values = BTreeMap::new();
|
|
|
|
|
|
|
|
for (identifier, value_node) in nodes {
|
|
|
|
let position = value_node.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let value = if let Some(value) = self.run_statement(value_node)? {
|
2024-08-09 10:09:59 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue { position });
|
|
|
|
};
|
|
|
|
|
2024-08-13 21:34:45 +00:00
|
|
|
values.insert(identifier.inner, value);
|
2024-08-09 10:09:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Some(Value::map(values)))
|
|
|
|
}
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Nil(node) => {
|
2024-08-12 12:54:21 +00:00
|
|
|
let _return = self.run_statement(*node)?;
|
2024-08-09 15:41:23 +00:00
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-08-13 22:48:02 +00:00
|
|
|
Statement::StructDefinition(_) => Ok(None),
|
2024-08-12 09:44:05 +00:00
|
|
|
Statement::UnaryOperation { operator, operand } => {
|
|
|
|
let position = operand.position;
|
2024-08-12 12:54:21 +00:00
|
|
|
let value = if let Some(value) = self.run_statement(*operand)? {
|
2024-08-12 09:44:05 +00:00
|
|
|
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 })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-08-10 09:23:43 +00:00
|
|
|
Statement::While { condition, body } => {
|
|
|
|
let mut return_value = None;
|
|
|
|
|
|
|
|
let condition_position = condition.position;
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
while let Some(condition_value) = self.run_statement(*condition.clone())? {
|
2024-08-14 05:03:46 +00:00
|
|
|
if let Some(condition) = condition_value.as_boolean() {
|
|
|
|
if !condition {
|
2024-08-10 09:23:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedBoolean {
|
|
|
|
position: condition_position,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-12 12:54:21 +00:00
|
|
|
return_value = self.run_statement(*body.clone())?;
|
2024-08-10 09:23:43 +00:00
|
|
|
|
|
|
|
if return_value.is_some() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(return_value)
|
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2024-08-07 23:03:50 +00:00
|
|
|
pub enum VmError {
|
2024-08-05 02:15:31 +00:00
|
|
|
ParseError(ParseError),
|
2024-08-09 04:49:17 +00:00
|
|
|
ValueError {
|
|
|
|
error: ValueError,
|
|
|
|
position: Span,
|
|
|
|
},
|
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,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-10 09:23:43 +00:00
|
|
|
ExpectedBoolean {
|
|
|
|
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-09 04:49:17 +00:00
|
|
|
ExpectedFunction {
|
|
|
|
actual: Value,
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedList {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedValue {
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 22:14:46 +00:00
|
|
|
UndefinedVariable {
|
2024-08-13 21:34:45 +00:00
|
|
|
identifier: Node<Identifier>,
|
2024-08-09 04:49:17 +00:00
|
|
|
},
|
2024-08-12 01:37:44 +00:00
|
|
|
UndefinedProperty {
|
|
|
|
value: Value,
|
|
|
|
value_position: Span,
|
|
|
|
property: Identifier,
|
|
|
|
property_position: Span,
|
|
|
|
},
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 05:43:58 +00:00
|
|
|
impl VmError {
|
|
|
|
pub fn position(&self) -> Span {
|
|
|
|
match self {
|
|
|
|
Self::ParseError(parse_error) => parse_error.position(),
|
|
|
|
Self::ValueError { position, .. } => *position,
|
|
|
|
Self::BuiltInFunctionError { position, .. } => *position,
|
2024-08-10 09:23:43 +00:00
|
|
|
Self::ExpectedBoolean { position } => *position,
|
2024-08-09 05:43:58 +00:00
|
|
|
Self::ExpectedIdentifier { position } => *position,
|
2024-08-12 20:57:10 +00:00
|
|
|
Self::ExpectedIdentifierOrString { position } => *position,
|
|
|
|
Self::ExpectedIntegerOrRange { position } => *position,
|
2024-08-09 05:43:58 +00:00
|
|
|
Self::ExpectedInteger { position } => *position,
|
|
|
|
Self::ExpectedFunction { position, .. } => *position,
|
|
|
|
Self::ExpectedList { position } => *position,
|
2024-08-12 20:57:10 +00:00
|
|
|
Self::ExpectedMap { position } => *position,
|
2024-08-12 09:44:05 +00:00
|
|
|
Self::ExpectedNumber { position } => *position,
|
2024-08-09 05:43:58 +00:00
|
|
|
Self::ExpectedValue { position } => *position,
|
2024-08-09 22:14:46 +00:00
|
|
|
Self::UndefinedVariable { identifier } => identifier.position,
|
2024-08-12 01:37:44 +00:00
|
|
|
Self::UndefinedProperty {
|
|
|
|
property_position, ..
|
|
|
|
} => *property_position,
|
2024-08-09 05:43:58 +00:00
|
|
|
}
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 23:03:50 +00:00
|
|
|
impl From<ParseError> for VmError {
|
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-09 00:58:56 +00:00
|
|
|
impl Display for VmError {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
Self::ParseError(parse_error) => write!(f, "{}", parse_error),
|
2024-08-09 04:31:38 +00:00
|
|
|
Self::ValueError { error, .. } => write!(f, "{}", 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-10 09:23:43 +00:00
|
|
|
Self::ExpectedBoolean { position } => {
|
|
|
|
write!(f, "Expected a boolean at position: {:?}", position)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
Self::ExpectedFunction { actual, position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Expected a function, but got: {} at position: {:?}",
|
|
|
|
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-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-09 22:14:46 +00:00
|
|
|
Self::UndefinedVariable { identifier } => {
|
|
|
|
write!(f, "Undefined identifier: {}", identifier)
|
2024-08-09 04:49:17 +00:00
|
|
|
}
|
2024-08-12 01:37:44 +00:00
|
|
|
Self::UndefinedProperty {
|
|
|
|
value, property, ..
|
|
|
|
} => {
|
|
|
|
write!(f, "Value {} does not have the property {}", value, property)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2024-08-13 18:21:31 +00:00
|
|
|
use crate::Struct;
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
use super::*;
|
|
|
|
|
2024-08-14 03:45:17 +00:00
|
|
|
#[test]
|
|
|
|
fn async_block() {
|
|
|
|
let input = "x = 1; async { x += 1; x -= 1; } x";
|
|
|
|
|
|
|
|
assert!(run(input).unwrap().unwrap().as_integer().is_some());
|
|
|
|
}
|
|
|
|
|
2024-08-13 23:41:36 +00:00
|
|
|
#[test]
|
|
|
|
fn define_and_instantiate_fields_struct() {
|
|
|
|
let input = "struct Foo { bar: int, baz: float } Foo { bar = 42, baz = 4.0 }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
|
|
|
Ok(Some(Value::r#struct(Struct::Fields {
|
|
|
|
name: Identifier::new("Foo"),
|
|
|
|
fields: vec![
|
|
|
|
(Identifier::new("bar"), Value::integer(42)),
|
|
|
|
(Identifier::new("baz"), Value::float(4.0))
|
|
|
|
]
|
|
|
|
})))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 20:46:54 +00:00
|
|
|
#[test]
|
|
|
|
fn assign_tuple_struct_variable() {
|
|
|
|
let input = "
|
|
|
|
struct Foo(int)
|
|
|
|
x = Foo(42)
|
|
|
|
x
|
|
|
|
";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
|
|
|
Ok(Some(Value::r#struct(Struct::Tuple {
|
|
|
|
name: Identifier::new("Foo"),
|
|
|
|
fields: vec![Value::integer(42)]
|
|
|
|
})))
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
#[test]
|
|
|
|
fn define_and_instantiate_tuple_struct() {
|
|
|
|
let input = "struct Foo(int) Foo(42)";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
|
|
|
Ok(Some(Value::r#struct(Struct::Tuple {
|
|
|
|
name: Identifier::new("Foo"),
|
|
|
|
fields: vec![Value::integer(42)]
|
|
|
|
})))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
#[test]
|
|
|
|
fn assign_unit_struct_variable() {
|
|
|
|
let input = "
|
|
|
|
struct Foo
|
|
|
|
x = Foo
|
|
|
|
x
|
|
|
|
";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
|
|
|
Ok(Some(Value::r#struct(Struct::Unit {
|
|
|
|
name: Identifier::new("Foo")
|
|
|
|
})))
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-08-13 18:21:31 +00:00
|
|
|
#[test]
|
|
|
|
fn define_and_instantiate_unit_struct() {
|
|
|
|
let input = "struct Foo Foo";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input),
|
|
|
|
Ok(Some(Value::r#struct(Struct::Unit {
|
|
|
|
name: Identifier::new("Foo")
|
|
|
|
})))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:57:10 +00:00
|
|
|
#[test]
|
|
|
|
fn list_index_nested() {
|
|
|
|
let input = "[[1, 2], [42, 4], [5, 6]][1][0]";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
2024-08-12 15:24:24 +00:00
|
|
|
#[test]
|
|
|
|
fn map_property() {
|
|
|
|
let input = "{ x = 42 }.x";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_property_nested() {
|
|
|
|
let input = "{ x = { y = 42 } }.x.y";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_property_access_expression() {
|
|
|
|
let input = "{ foobar = 42 }.('foo' + 'bar')";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
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),
|
|
|
|
Ok(Some(Value::list(vec![
|
|
|
|
Value::integer(2),
|
|
|
|
Value::integer(3)
|
|
|
|
])))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 14:29:06 +00:00
|
|
|
#[test]
|
|
|
|
fn range() {
|
|
|
|
let input = "1..5";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::range(1..5))));
|
|
|
|
}
|
|
|
|
|
2024-08-12 09:44:05 +00:00
|
|
|
#[test]
|
|
|
|
fn negate_expression() {
|
|
|
|
let input = "x = -42; -x";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn not_expression() {
|
|
|
|
let input = "!(1 == 2 || 3 == 4 || 5 == 6)";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_property_access() {
|
|
|
|
let input = "{ a = 42 }.a";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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-12 01:42:16 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::string("42".to_string()))));
|
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() {
|
|
|
|
let input = "if false { 1 } else { 2 }";
|
|
|
|
|
2024-08-12 01:42:16 +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-12 01:42:16 +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() {
|
|
|
|
let input = "x = 0; while x < 5 { x += 1; } x";
|
|
|
|
|
2024-08-12 01:42:16 +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() {
|
|
|
|
let input = "x = 1; x -= 1; x";
|
|
|
|
|
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(0))));
|
|
|
|
}
|
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
#[test]
|
|
|
|
fn add_assign() {
|
|
|
|
let input = "x = 1; x += 1; x";
|
|
|
|
|
2024-08-12 01:42:16 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(2))));
|
2024-08-09 22:14:46 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
#[test]
|
|
|
|
fn or() {
|
|
|
|
let input = "true || false";
|
|
|
|
|
2024-08-12 01:42:16 +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 map_equal() {
|
2024-08-11 20:57:52 +00:00
|
|
|
let input = "{ y = 'foo' } == { y = 'foo' }";
|
2024-08-09 11:15:09 +00:00
|
|
|
|
2024-08-12 01:42:16 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
2024-08-09 11:15:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn integer_equal() {
|
|
|
|
let input = "42 == 42";
|
|
|
|
|
2024-08-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-12 01:42:16 +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-11 23:18:13 +00:00
|
|
|
let input = "is_even(42)";
|
2024-08-05 19:54:48 +00:00
|
|
|
|
2024-08-12 01:42:16 +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-11 23:18:13 +00:00
|
|
|
let input = "is_odd(42)";
|
2024-08-05 19:54:48 +00:00
|
|
|
|
2024-08-12 01:42:16 +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-07 22:24:25 +00:00
|
|
|
fn length() {
|
2024-08-11 23:18:13 +00:00
|
|
|
let input = "length([1, 2, 3])";
|
2024-08-05 18:58:58 +00:00
|
|
|
|
2024-08-12 01:42:16 +00:00
|
|
|
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
2024-08-05 18:58:58 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[test]
|
|
|
|
fn add() {
|
|
|
|
let input = "1 + 2";
|
|
|
|
|
2024-08-12 01:42:16 +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-12 01:42:16 +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
|
|
|
}
|