dust/dust-lang/src/vm.rs

1105 lines
33 KiB
Rust
Raw Normal View History

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::{
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
use crate::{
2024-08-16 09:24:55 +00:00
ast::{
AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression,
FieldAccessExpression, IfExpression, ListExpression, ListIndexExpression,
LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression,
Statement,
2024-08-16 04:41:52 +00:00
},
2024-08-16 03:17:49 +00:00
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError,
2024-08-16 09:14:00 +00:00
Span, Type, Value, ValueError,
};
2024-08-05 04:40:51 +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
}
/// 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> {
let abstract_syntax_tree = parse(source)?;
2024-08-12 12:54:21 +00:00
let mut analyzer = Analyzer::new(&abstract_syntax_tree, &context);
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 12:54:21 +00:00
vm.run()
.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.
pub struct Vm {
abstract_tree: AbstractSyntaxTree,
2024-08-12 12:54:21 +00:00
context: Context,
2024-08-05 02:15:31 +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> {
let mut previous_position = (0, 0);
2024-08-05 02:15:31 +00:00
let mut previous_value = None;
2024-08-14 18:28:39 +00:00
while let Some(statement) = self.abstract_tree.statements.pop_front() {
2024-08-14 19:52:04 +00:00
let new_position = statement.position();
2024-08-12 12:54:21 +00:00
previous_value = self.run_statement(statement)?;
2024-08-12 12:54:21 +00:00
self.context.collect_garbage(previous_position.1);
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-05 02:15:31 +00:00
Ok(previous_value)
}
2024-08-16 03:17:49 +00:00
fn run_statement(&self, statement: Statement) -> Result<Option<Value>, VmError> {
2024-08-16 04:41:52 +00:00
let position = statement.position();
let result = match statement {
2024-08-16 09:14:00 +00:00
Statement::Expression(expression) => self
.run_expression(expression)
.map(|evaluation| evaluation.value()),
2024-08-16 03:17:49 +00:00
Statement::ExpressionNullified(expression) => {
self.run_expression(expression.inner)?;
Ok(None)
}
Statement::Let(_) => todo!(),
Statement::StructDefinition(_) => todo!(),
2024-08-16 04:41:52 +00:00
};
result.map_err(|error| VmError::Trace {
error: Box::new(error),
position,
})
2024-08-16 03:17:49 +00:00
}
2024-08-16 09:14:00 +00:00
fn run_expression(&self, expression: Expression) -> Result<Evaluation, VmError> {
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 04:41:52 +00:00
Expression::Block(Node { inner, .. }) => self.run_block(*inner),
2024-08-16 09:14:00 +00:00
Expression::Call(call) => self.run_call(*call.inner),
Expression::FieldAccess(field_access) => self.run_field_access(*field_access.inner),
Expression::Grouped(expression) => self.run_expression(*expression.inner),
Expression::Identifier(identifier) => {
let get_value = self.context.get_value(&identifier.inner);
if let Some(value) = get_value {
Ok(Evaluation::Return(Some(value)))
} else {
Err(VmError::UndefinedVariable {
identifier: identifier.inner,
position: identifier.position,
})
}
}
2024-08-16 09:14:00 +00:00
Expression::If(if_expression) => self.run_if(*if_expression.inner),
Expression::List(list_expression) => self.run_list(*list_expression.inner),
Expression::ListIndex(list_index) => self.run_list_index(*list_index.inner),
Expression::Literal(literal) => self.run_literal(*literal.inner),
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner),
Expression::Operator(operator_expression) => {
self.run_operator(*operator_expression.inner)
}
2024-08-16 09:14:00 +00:00
Expression::Range(_) => todo!(),
Expression::Struct(_) => todo!(),
Expression::TupleAccess(_) => todo!(),
};
2024-08-16 03:17:49 +00:00
2024-08-16 09:14:00 +00:00
evaluation_result.map_err(|error| VmError::Trace {
error: Box::new(error),
position,
})
}
2024-08-16 03:17:49 +00:00
2024-08-16 09:14:00 +00:00
fn run_operator(&self, operator: OperatorExpression) -> Result<Evaluation, VmError> {
match operator {
OperatorExpression::Assignment { assignee, value } => {
let assignee_position = assignee.position();
let assignee = self
.run_expression(assignee)?
.expect_value(assignee_position)?;
let value_position = value.position();
let value = self.run_expression(value)?.expect_value(value_position)?;
assignee.mutate(value);
Ok(Evaluation::Return(None))
}
2024-08-16 09:14:00 +00:00
OperatorExpression::Comparison {
left,
operator,
right,
} => {
let left_position = left.position();
let left_value = self.run_expression(left)?.expect_value(left_position)?;
let right_position = right.position();
let right_value = self.run_expression(right)?.expect_value(right_position)?;
let outcome =
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)
.map_err(|error| VmError::ValueError {
error,
left_position,
right_position,
})?,
ComparisonOperator::GreaterThanOrEqual => left_value
.greater_than_or_equal(&right_value)
.map_err(|error| VmError::ValueError {
error,
left_position,
right_position,
})?,
ComparisonOperator::LessThan => left_value
.less_than(&right_value)
.map_err(|error| VmError::ValueError {
error,
left_position,
right_position,
})?,
ComparisonOperator::LessThanOrEqual => left_value
.less_than_or_equal(&right_value)
.map_err(|error| VmError::ValueError {
error,
left_position,
right_position,
})?,
};
Ok(Evaluation::Return(Some(outcome)))
}
2024-08-16 09:14:00 +00:00
OperatorExpression::CompoundAssignment {
assignee,
operator,
modifier,
} => todo!(),
OperatorExpression::ErrorPropagation(_) => todo!(),
OperatorExpression::Negation(_) => todo!(),
OperatorExpression::Not(_) => todo!(),
OperatorExpression::Math {
left,
operator,
right,
} => {
let left_position = left.position();
let left_value = self.run_expression(left)?.expect_value(left_position)?;
let right_position = right.position();
let right_value = self.run_expression(right)?.expect_value(right_position)?;
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),
}
.map_err(|value_error| VmError::ValueError {
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,
} => {
let left_position = left.position();
let left_value = self.run_expression(left)?.expect_value(left_position)?;
let right_position = right.position();
let right_value = self.run_expression(right)?.expect_value(right_position)?;
let outcome = match operator.inner {
LogicOperator::And => left_value.and(&right_value),
LogicOperator::Or => left_value.or(&right_value),
}
.map_err(|value_error| VmError::ValueError {
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-16 09:14:00 +00:00
fn run_loop(&self, loop_expression: LoopExpression) -> Result<Evaluation, VmError> {
match loop_expression {
LoopExpression::Infinite { block } => loop {
self.run_expression(Expression::block(block.inner.clone(), block.position))?;
},
LoopExpression::While { condition, block } => todo!(),
LoopExpression::For {
identifier,
iterator,
block,
} => todo!(),
}
}
2024-08-16 03:17:49 +00:00
2024-08-16 09:14:00 +00:00
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, VmError> {
let value = match literal {
LiteralExpression::Boolean(boolean) => Value::boolean(boolean),
LiteralExpression::Float(float) => Value::float(float),
LiteralExpression::Integer(integer) => Value::integer(integer),
LiteralExpression::String(string) => Value::string(string),
LiteralExpression::Value(value) => value,
};
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 09:14:00 +00:00
fn run_list_index(&self, list_index: ListIndexExpression) -> Result<Evaluation, VmError> {
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();
let list_value = self.run_expression(list)?.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();
let index_value = self.run_expression(index)?.expect_value(index_position)?;
2024-08-16 03:17:49 +00:00
2024-08-16 09:14:00 +00:00
let index = if let Some(index) = index_value.as_integer() {
index as usize
} else {
return Err(VmError::ExpectedInteger {
position: index_position,
});
};
2024-08-16 04:41:52 +00:00
2024-08-16 09:14:00 +00:00
let value_option = list_value.get_index(index);
Ok(Evaluation::Return(value_option))
}
fn run_call(&self, call_expression: CallExpression) -> Result<Evaluation, VmError> {
let CallExpression { invoker, arguments } = call_expression;
let invoker_position = invoker.position();
let invoker_value = if let Some(value) = self.run_expression(invoker)?.value() {
value
} else {
return Err(VmError::ExpectedValue {
position: invoker_position,
});
};
let function = if let Some(function) = invoker_value.as_function() {
function
} else {
return Err(VmError::ExpectedFunction {
actual: invoker_value,
position: invoker_position,
});
};
let mut value_arguments = Vec::new();
for argument in arguments {
let position = argument.position();
if let Some(value) = self.run_expression(argument)?.value() {
value_arguments.push(value);
} else {
return Err(VmError::ExpectedValue { position });
2024-08-16 04:41:52 +00:00
}
2024-08-16 09:14:00 +00:00
}
let context = Context::new();
function
.call(None, Some(value_arguments), &context)
.map(Evaluation::Return)
2024-08-16 09:14:00 +00:00
}
fn run_field_access(&self, field_access: FieldAccessExpression) -> Result<Evaluation, VmError> {
let FieldAccessExpression { container, field } = field_access;
let container_position = container.position();
let container_value = if let Some(value) = self.run_expression(container)?.value() {
value
} else {
return Err(VmError::ExpectedValue {
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 09:14:00 +00:00
fn run_list(&self, list_expression: ListExpression) -> Result<Evaluation, VmError> {
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
.run_expression(length_operand)?
.expect_value(position)?
.as_integer()
.ok_or(VmError::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
.run_expression(repeat_operand)?
.expect_value(position)?;
Ok(Evaluation::Return(Some(Value::list(vec![
value;
length as usize
]))))
2024-08-16 04:41:52 +00:00
}
ListExpression::Ordered(expressions) => {
let mut values = Vec::new();
for expression in expressions {
let position = expression.position();
2024-08-16 09:14:00 +00:00
let value = self.run_expression(expression)?.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-16 09:14:00 +00:00
Ok(Evaluation::Return(Some(Value::list(values))))
2024-08-16 04:41:52 +00:00
}
}
}
2024-08-16 09:14:00 +00:00
fn run_block(&self, block: BlockExpression) -> Result<Evaluation, VmError> {
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));
let statements_length = statements.len();
let error_option =
statements
.into_par_iter()
.enumerate()
.find_map_any(|(i, statement)| {
let evaluation_result = self.run_statement(statement);
match evaluation_result {
Ok(evaluation) => {
if i == statements_length - 1 {
let mut final_result = final_result.lock().unwrap();
*final_result = evaluation;
}
None
}
Err(error) => Some(error),
}
});
2024-08-16 04:41:52 +00:00
if let Some(error) = error_option {
Err(error)
} else {
Ok(Evaluation::Return(final_result.lock().unwrap().clone()))
2024-08-16 04:41:52 +00:00
}
}
2024-08-16 09:14:00 +00:00
BlockExpression::Sync(statements) => {
2024-08-16 04:41:52 +00:00
let mut previous_value = None;
for statement in statements {
let position = statement.position();
previous_value = self.run_statement(statement)?;
self.context.collect_garbage(position.1);
}
2024-08-16 09:14:00 +00:00
Ok(Evaluation::Return(previous_value))
2024-08-16 04:41:52 +00:00
}
}
}
2024-08-16 09:14:00 +00:00
fn run_if(&self, if_expression: IfExpression) -> Result<Evaluation, VmError> {
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
.run_expression(condition)?
.expect_value(position)?
.as_boolean()
.ok_or(VmError::ExpectedBoolean { position })?;
if boolean {
self.run_expression(Expression::block(if_block.inner, if_block.position))?;
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
.run_expression(condition)?
.expect_value(position)?
.as_boolean()
.ok_or(VmError::ExpectedBoolean { position })?;
if boolean {
self.run_expression(Expression::block(if_block.inner, if_block.position))?;
2024-08-16 04:41:52 +00:00
}
match r#else {
ElseExpression::If(if_expression) => {
self.run_expression(Expression::If(if_expression))
}
ElseExpression::Block(block) => {
self.run_expression(Expression::block(block.inner, block.position))
}
}
}
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 {
Break,
Return(Option<Value>),
}
impl Evaluation {
pub fn value(self) -> Option<Value> {
match self {
Evaluation::Break => None,
Evaluation::Return(value_option) => value_option,
}
}
pub fn expect_value(self, position: Span) -> Result<Value, VmError> {
if let Evaluation::Return(Some(value)) = self {
Ok(value)
} else {
Err(VmError::ExpectedValue { position })
}
}
}
2024-08-05 02:15:31 +00:00
#[derive(Clone, Debug, PartialEq)]
pub enum VmError {
2024-08-05 02:15:31 +00:00
ParseError(ParseError),
2024-08-16 04:41:52 +00:00
Trace {
error: Box<VmError>,
position: Span,
},
2024-08-09 04:49:17 +00:00
ValueError {
error: ValueError,
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,
position: Span,
},
2024-08-14 18:28:39 +00:00
CannotMutate {
value: Value,
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-16 09:14:00 +00:00
identifier: Identifier,
position: Span,
2024-08-09 04:49:17 +00:00
},
UndefinedProperty {
value: Value,
value_position: Span,
property: Identifier,
property_position: Span,
},
}
impl VmError {
pub fn position(&self) -> Span {
match self {
Self::ParseError(parse_error) => parse_error.position(),
Self::Trace { position, .. } => *position,
Self::ValueError {
left_position,
right_position,
..
} => (left_position.0, right_position.1),
Self::BuiltInFunctionError { position, .. } => *position,
Self::CannotMutate { position, .. } => *position,
Self::ExpectedBoolean { position } => *position,
Self::ExpectedIdentifier { position } => *position,
Self::ExpectedIntegerOrRange { position } => *position,
Self::ExpectedIdentifierOrString { position } => *position,
Self::ExpectedInteger { position } => *position,
Self::ExpectedNumber { position } => *position,
Self::ExpectedMap { position } => *position,
Self::ExpectedFunction { position, .. } => *position,
Self::ExpectedList { position } => *position,
Self::ExpectedValue { position } => *position,
Self::UndefinedVariable { position, .. } => *position,
Self::UndefinedProperty {
property_position, ..
} => *property_position,
}
}
}
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-16 04:41:52 +00:00
Self::Trace { error, position } => {
write!(
f,
"Error during execution at position: {:?}\n{}",
position, error
)
}
Self::ValueError {
error,
left_position,
right_position,
} => {
write!(
f,
"Value error with values at positions: {:?} and {:?} {}",
left_position, right_position, error
)
}
2024-08-14 18:28:39 +00:00
Self::CannotMutate { value, .. } => {
write!(f, "Cannot mutate immutable value {}", value)
}
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,
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-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)
}
Self::UndefinedVariable {
identifier,
position,
} => {
write!(
f,
"Undefined variable {} at position: {:?}",
identifier, position
)
2024-08-09 04:49:17 +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 08:59:27 +00:00
#[test]
fn mutate_variable() {
let input = "
mut x = ''
x += 'foo'
x += 'bar'
x
";
assert_eq!(run(input), Ok(Some(Value::string_mut("foobar"))));
}
2024-08-14 03:45:17 +00:00
#[test]
fn async_block() {
2024-08-14 18:28:39 +00:00
let input = "mut x = 1; async { x += 1; x -= 1; } x";
2024-08-14 03:45:17 +00:00
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))
]
})))
);
}
#[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))));
}
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"))));
}
#[test]
fn to_string() {
2024-08-11 23:18:13 +00:00
let input = "to_string(42)";
2024-08-12 01:42:16 +00:00
assert_eq!(run(input), Ok(Some(Value::string("42".to_string()))));
}
#[test]
fn r#if() {
let input = "if true { 1 }";
2024-08-12 01:42:16 +00:00
assert_eq!(run(input), Ok(None));
}
#[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))));
}
#[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));
}
#[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-10 09:23:43 +00:00
#[test]
fn while_loop() {
2024-08-14 18:28:39 +00:00
let input = "mut x = 0; while x < 5 { x += 1; } x";
2024-08-10 09:23:43 +00:00
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() {
2024-08-14 18:28:39 +00:00
let input = "mut x = 1; x -= 1; x";
2024-08-14 01:24:56 +00:00
assert_eq!(run(input), Ok(Some(Value::integer(0))));
}
2024-08-09 22:14:46 +00:00
#[test]
fn add_assign() {
2024-08-14 18:28:39 +00:00
let input = "mut x = 1; x += 1; x";
2024-08-09 22:14:46 +00:00
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
}
#[test]
fn and() {
let input = "true && true";
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
}
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
}
#[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))));
}
#[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))));
}
#[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))));
}
#[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))));
}
#[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))));
}
#[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))));
}
#[test]
fn multiply() {
let input = "2 * 3";
2024-08-12 01:42:16 +00:00
assert_eq!(run(input), Ok(Some(Value::integer(6))));
}
#[test]
fn boolean() {
let input = "true";
2024-08-12 01:42:16 +00:00
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
}
#[test]
fn is_even() {
2024-08-11 23:18:13 +00:00
let input = "is_even(42)";
2024-08-12 01:42:16 +00:00
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
}
#[test]
fn is_odd() {
2024-08-11 23:18:13 +00:00
let input = "is_odd(42)";
2024-08-12 01:42:16 +00:00
assert_eq!(run(input), Ok(Some(Value::boolean(false))));
}
2024-08-05 18:58:58 +00:00
#[test]
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
}