dust/dust-lang/src/vm.rs

1025 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::{
collections::BTreeMap,
2024-08-09 00:58:56 +00:00
fmt::{self, Display, Formatter},
};
2024-08-05 02:15:31 +00:00
use crate::{
2024-08-12 12:54:21 +00:00
parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError,
Context, DustError, Identifier, Node, ParseError, Span, Statement, UnaryOperator, Value,
ValueError,
};
2024-08-05 04:40:51 +00:00
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-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 })
}
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;
while let Some(statement) = self.abstract_tree.nodes.pop_front() {
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-12 12:54:21 +00:00
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
match node.inner {
2024-08-09 08:23:02 +00:00
Statement::BinaryOperation {
left,
operator,
right,
} => {
2024-08-09 22:14:46 +00:00
let right_position = right.position;
if let BinaryOperator::Assign = operator.inner {
let identifier = if let Statement::Identifier(identifier) = left.inner {
identifier
} else {
return Err(VmError::ExpectedIdentifier {
position: left.position,
});
};
2024-08-12 12:54:21 +00:00
let value = if let Some(value) = self.run_statement(*right)? {
2024-08-09 22:14:46 +00:00
value
} else {
return Err(VmError::ExpectedValue {
position: right_position,
});
};
2024-08-12 12:54:21 +00:00
self.context.set_value(identifier, value);
2024-08-09 22:14:46 +00:00
return Ok(None);
2024-08-09 22:14:46 +00:00
}
if let BinaryOperator::AddAssign = operator.inner {
let (identifier, left_value) =
if let Statement::Identifier(identifier) = left.inner {
2024-08-12 12:54:21 +00:00
let value = self.context.get_value(&identifier).ok_or_else(|| {
VmError::UndefinedVariable {
identifier: Node::new(
Statement::Identifier(identifier.clone()),
left.position,
),
}
})?;
(identifier, value)
} else {
return Err(VmError::ExpectedIdentifier {
position: left.position,
});
};
2024-08-12 12:54:21 +00:00
let right_value = if let Some(value) = self.run_statement(*right)? {
2024-08-09 22:14:46 +00:00
value
} else {
return Err(VmError::ExpectedValue {
position: right_position,
});
};
let new_value = left_value.add(&right_value).map_err(|value_error| {
VmError::ValueError {
error: value_error,
position: right_position,
}
})?;
2024-08-12 12:54:21 +00:00
self.context.set_value(identifier, new_value);
2024-08-09 22:14:46 +00:00
return Ok(None);
2024-08-09 22:14:46 +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 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-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)? {
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)? {
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)
}
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 {
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)? {
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,
})?;
Ok(function_call_return)
}
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::FunctionCall {
function: function_node,
2024-08-07 22:46:40 +00:00
type_arguments: _,
value_arguments: value_parameter_nodes,
} => {
let function_position = function_node.position;
2024-08-12 12:54:21 +00:00
let function_value = if let Some(value) = self.run_statement(*function_node)? {
value
} else {
return Err(VmError::ExpectedValue {
position: function_position,
});
};
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,
position: function_position,
2024-08-09 00:58:56 +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)? {
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-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);
if let Some(value) = value_option {
2024-08-09 04:49:17 +00:00
Ok(Some(value.clone()))
} else {
2024-08-09 22:14:46 +00:00
Err(VmError::UndefinedVariable {
identifier: Node::new(Statement::Identifier(identifier), node.position),
2024-08-09 04:49:17 +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,
});
};
let condition = if let Some(condition) = condition_value.as_boolean() {
condition
} else {
return Err(VmError::ExpectedBoolean {
position: condition_position,
});
};
if condition {
2024-08-12 12:54:21 +00:00
self.run_statement(*body)?;
}
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,
});
};
if let Some(condition) = condition_value.as_boolean() {
if condition {
2024-08-12 12:54:21 +00:00
self.run_statement(*if_body)
} else {
2024-08-12 12:54:21 +00:00
self.run_statement(*else_body)
}
} 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,
});
};
if let Some(condition) = condition_value.as_boolean() {
if condition {
2024-08-12 12:54:21 +00:00
self.run_statement(*if_body)
} else {
for (condition, body) in else_ifs {
let condition_position = condition.position;
let condition_value =
2024-08-12 12:54:21 +00:00
if let Some(value) = self.run_statement(condition)? {
value
} else {
return Err(VmError::ExpectedValue {
position: condition_position,
});
};
let condition = if let Some(condition) = condition_value.as_boolean() {
condition
} else {
return Err(VmError::ExpectedBoolean {
position: condition_position,
});
};
if condition {
2024-08-12 12:54:21 +00:00
self.run_statement(body)?;
}
}
Ok(None)
}
} else {
Err(VmError::ExpectedBoolean {
position: condition_position,
})
}
}
Statement::IfElseIfElse {
condition,
if_body,
else_ifs,
else_body,
} => {
let condition_position = condition.position;
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,
});
};
if let Some(condition) = condition_value.as_boolean() {
if condition {
2024-08-12 12:54:21 +00:00
self.run_statement(*if_body)
} else {
for (condition, body) in else_ifs {
let condition_position = condition.position;
let condition_value =
2024-08-12 12:54:21 +00:00
if let Some(value) = self.run_statement(condition)? {
value
} else {
return Err(VmError::ExpectedValue {
position: condition_position,
});
};
let condition = if let Some(condition) = condition_value.as_boolean() {
condition
} else {
return Err(VmError::ExpectedBoolean {
position: condition_position,
});
};
if condition {
2024-08-12 12:54:21 +00:00
return self.run_statement(body);
}
}
2024-08-12 12:54:21 +00:00
self.run_statement(*else_body)
}
} 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 })
}
})
.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 {
2024-08-09 22:14:46 +00:00
let identifier = if let Statement::Identifier(identifier) = identifier.inner {
identifier
} else {
return Err(VmError::ExpectedIdentifier {
position: identifier.position,
});
};
2024-08-09 10:09:59 +00:00
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-09 22:14:46 +00:00
values.insert(identifier, 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-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-10 09:23:43 +00:00
if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() {
if !condition_value {
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)]
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 {
identifier: Node<Statement>,
2024-08-09 04:49:17 +00:00
},
UndefinedProperty {
value: Value,
value_position: Span,
property: Identifier,
property_position: Span,
},
}
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,
Self::UndefinedProperty {
property_position, ..
} => *property_position,
2024-08-09 05:43:58 +00:00
}
}
2024-08-05 02:15:31 +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
}
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 {
use super::*;
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"))));
}
#[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() {
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-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
}
#[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
}