2024-08-09 01:59:09 +00:00
|
|
|
//! Virtual machine for running the abstract syntax tree.
|
2024-08-09 00:58:56 +00:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
error::Error,
|
|
|
|
fmt::{self, Display, Formatter},
|
|
|
|
};
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-05 19:54:48 +00:00
|
|
|
use crate::{
|
2024-08-07 23:44:01 +00:00
|
|
|
parse, AbstractSyntaxTree, Analyzer, AnalyzerError, BuiltInFunctionError, Identifier, Node,
|
|
|
|
ParseError, Span, Statement, Value, ValueError,
|
2024-08-05 19:54:48 +00:00
|
|
|
};
|
2024-08-05 04:40:51 +00:00
|
|
|
|
|
|
|
pub fn run(
|
|
|
|
input: &str,
|
|
|
|
variables: &mut HashMap<Identifier, Value>,
|
2024-08-07 23:03:50 +00:00
|
|
|
) -> Result<Option<Value>, VmError> {
|
2024-08-05 22:45:43 +00:00
|
|
|
let abstract_syntax_tree = parse(input)?;
|
2024-08-07 15:57:15 +00:00
|
|
|
let analyzer = Analyzer::new(&abstract_syntax_tree, variables);
|
2024-08-07 15:38:08 +00:00
|
|
|
|
|
|
|
analyzer.analyze()?;
|
|
|
|
|
2024-08-05 22:45:43 +00:00
|
|
|
let mut vm = Vm::new(abstract_syntax_tree);
|
2024-08-05 02:15:31 +00:00
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
vm.run(variables)
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 23:03:50 +00:00
|
|
|
pub struct Vm {
|
|
|
|
abstract_tree: AbstractSyntaxTree,
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 23:03:50 +00:00
|
|
|
impl Vm {
|
|
|
|
pub fn new(abstract_tree: AbstractSyntaxTree) -> Self {
|
2024-08-07 15:38:08 +00:00
|
|
|
Self { abstract_tree }
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
pub fn run(
|
|
|
|
&mut self,
|
|
|
|
variables: &mut HashMap<Identifier, Value>,
|
2024-08-07 23:03:50 +00:00
|
|
|
) -> Result<Option<Value>, VmError> {
|
2024-08-05 02:15:31 +00:00
|
|
|
let mut previous_value = None;
|
|
|
|
|
2024-08-07 15:38:08 +00:00
|
|
|
while let Some(node) = self.abstract_tree.nodes.pop_front() {
|
2024-08-05 04:40:51 +00:00
|
|
|
previous_value = self.run_node(node, variables)?;
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(previous_value)
|
|
|
|
}
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
fn run_node(
|
|
|
|
&self,
|
2024-08-07 23:03:50 +00:00
|
|
|
node: Node,
|
2024-08-05 04:40:51 +00:00
|
|
|
variables: &mut HashMap<Identifier, Value>,
|
2024-08-07 23:03:50 +00:00
|
|
|
) -> Result<Option<Value>, VmError> {
|
2024-08-05 04:40:51 +00:00
|
|
|
match node.statement {
|
|
|
|
Statement::Add(left, right) => {
|
2024-08-07 19:47:37 +00:00
|
|
|
let left_span = left.position;
|
2024-08-05 04:40:51 +00:00
|
|
|
let left = if let Some(value) = self.run_node(*left, variables)? {
|
2024-08-05 02:15:31 +00:00
|
|
|
value
|
|
|
|
} else {
|
2024-08-05 04:40:51 +00:00
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_span,
|
|
|
|
});
|
2024-08-05 02:15:31 +00:00
|
|
|
};
|
2024-08-07 19:47:37 +00:00
|
|
|
let right_span = right.position;
|
2024-08-05 04:40:51 +00:00
|
|
|
let right = if let Some(value) = self.run_node(*right, variables)? {
|
2024-08-05 02:15:31 +00:00
|
|
|
value
|
|
|
|
} else {
|
2024-08-05 04:40:51 +00:00
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_span,
|
|
|
|
});
|
2024-08-05 02:15:31 +00:00
|
|
|
};
|
2024-08-09 04:31:38 +00:00
|
|
|
let sum = left
|
|
|
|
.add(&right)
|
|
|
|
.map_err(|value_error| VmError::ValueError {
|
|
|
|
error: value_error,
|
|
|
|
position: (left_span.0, right_span.1),
|
|
|
|
})?;
|
2024-08-05 02:15:31 +00:00
|
|
|
|
|
|
|
Ok(Some(sum))
|
|
|
|
}
|
2024-08-05 04:40:51 +00:00
|
|
|
Statement::Assign(left, right) => {
|
|
|
|
let identifier = if let Statement::Identifier(identifier) = &left.statement {
|
|
|
|
identifier
|
|
|
|
} else {
|
2024-08-07 14:03:33 +00:00
|
|
|
return Err(VmError::ExpectedIdentifier {
|
2024-08-07 19:47:37 +00:00
|
|
|
position: left.position,
|
2024-08-05 04:40:51 +00:00
|
|
|
});
|
|
|
|
};
|
2024-08-07 19:47:37 +00:00
|
|
|
let right_span = right.position;
|
2024-08-05 04:40:51 +00:00
|
|
|
let value = if let Some(value) = self.run_node(*right, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_span,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
variables.insert(identifier.clone(), value);
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
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;
|
|
|
|
let value = if let Some(value) = self.run_node(node, variables)? {
|
|
|
|
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())),
|
|
|
|
Statement::FunctionCall {
|
|
|
|
function: function_node,
|
2024-08-07 22:46:40 +00:00
|
|
|
type_arguments: _,
|
2024-08-07 22:24:25 +00:00
|
|
|
value_arguments: value_parameter_nodes,
|
|
|
|
} => {
|
|
|
|
let function_position = function_node.position;
|
|
|
|
let function_value =
|
|
|
|
if let Some(value) = self.run_node(*function_node, variables)? {
|
|
|
|
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,
|
2024-08-07 22:24:25 +00:00
|
|
|
position: function_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;
|
|
|
|
let value = if let Some(value) = self.run_node(node, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue { position });
|
|
|
|
};
|
|
|
|
|
|
|
|
value_parameters.push(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(value_parameters)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2024-08-07 23:03:50 +00:00
|
|
|
Ok(function.clone().call(None, value_parameters, variables)?)
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
2024-08-09 04:49:17 +00:00
|
|
|
Statement::Identifier(identifier) => {
|
|
|
|
if let Some(value) = variables.get(&identifier) {
|
|
|
|
Ok(Some(value.clone()))
|
|
|
|
} else {
|
|
|
|
Err(VmError::UndefinedIdentifier {
|
|
|
|
identifier,
|
|
|
|
position: node.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-05 04:40:51 +00:00
|
|
|
if let Some(value) = self.run_node(node, variables)? {
|
|
|
|
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 03:28:47 +00:00
|
|
|
Statement::Multiply(left, right) => {
|
|
|
|
let left_span = left.position;
|
|
|
|
let left = if let Some(value) = self.run_node(*left, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_span,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let right_span = right.position;
|
|
|
|
let right = if let Some(value) = self.run_node(*right, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_span,
|
|
|
|
});
|
|
|
|
};
|
2024-08-09 04:31:38 +00:00
|
|
|
let product = left
|
|
|
|
.multiply(&right)
|
|
|
|
.map_err(|value_error| VmError::ValueError {
|
|
|
|
error: value_error,
|
|
|
|
position: (left_span.0, right_span.1),
|
|
|
|
})?;
|
2024-08-09 03:28:47 +00:00
|
|
|
|
|
|
|
Ok(Some(product))
|
|
|
|
}
|
2024-08-05 18:31:08 +00:00
|
|
|
Statement::PropertyAccess(left, right) => {
|
2024-08-07 19:47:37 +00:00
|
|
|
let left_span = left.position;
|
2024-08-07 22:24:25 +00:00
|
|
|
let left_value = if let Some(value) = self.run_node(*left, variables)? {
|
2024-08-05 18:31:08 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_span,
|
|
|
|
});
|
|
|
|
};
|
2024-08-07 19:47:37 +00:00
|
|
|
let right_span = right.position;
|
2024-08-05 18:31:08 +00:00
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
if let (Some(list), Statement::Constant(value)) =
|
|
|
|
(left_value.as_list(), &right.statement)
|
2024-08-05 19:54:48 +00:00
|
|
|
{
|
2024-08-05 18:58:58 +00:00
|
|
|
if let Some(index) = value.as_integer() {
|
2024-08-05 19:54:48 +00:00
|
|
|
let value = list.get(index as usize).cloned();
|
2024-08-05 18:58:58 +00:00
|
|
|
|
2024-08-05 19:54:48 +00:00
|
|
|
return Ok(value);
|
2024-08-05 18:58:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
if let (
|
|
|
|
value,
|
|
|
|
Statement::BuiltInFunctionCall {
|
|
|
|
function,
|
2024-08-07 22:46:40 +00:00
|
|
|
type_arguments: _,
|
|
|
|
value_arguments: value_argument_nodes,
|
2024-08-07 22:24:25 +00:00
|
|
|
},
|
|
|
|
) = (left_value, right.statement)
|
|
|
|
{
|
2024-08-07 22:39:28 +00:00
|
|
|
let mut value_arguments = Vec::new();
|
2024-08-07 22:24:25 +00:00
|
|
|
|
2024-08-07 22:39:28 +00:00
|
|
|
value_arguments.push(value);
|
2024-08-07 22:24:25 +00:00
|
|
|
|
2024-08-07 22:39:28 +00:00
|
|
|
if let Some(value_nodes) = value_argument_nodes {
|
2024-08-07 22:24:25 +00:00
|
|
|
for node in value_nodes {
|
|
|
|
let position = node.position;
|
|
|
|
let value = if let Some(value) = self.run_node(node, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue { position });
|
|
|
|
};
|
|
|
|
|
|
|
|
value_arguments.push(value);
|
|
|
|
}
|
2024-08-07 22:39:28 +00:00
|
|
|
}
|
2024-08-07 22:24:25 +00:00
|
|
|
|
2024-08-09 05:43:58 +00:00
|
|
|
let function_call_return = function.call(None, Some(value_arguments)).map_err(
|
|
|
|
|built_in_function_error| VmError::BuiltInFunctionError {
|
|
|
|
error: built_in_function_error,
|
|
|
|
position: right_span,
|
|
|
|
},
|
|
|
|
)?;
|
2024-08-07 22:24:25 +00:00
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
return Ok(function_call_return);
|
2024-08-07 22:24:25 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
Err(VmError::ExpectedIdentifierOrInteger {
|
|
|
|
position: right_span,
|
|
|
|
})
|
2024-08-05 18:31:08 +00:00
|
|
|
}
|
2024-08-09 03:28:47 +00:00
|
|
|
Statement::Subtract(left, right) => {
|
|
|
|
let left_span = left.position;
|
|
|
|
let left = if let Some(value) = self.run_node(*left, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: left_span,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let right_span = right.position;
|
|
|
|
let right = if let Some(value) = self.run_node(*right, variables)? {
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(VmError::ExpectedValue {
|
|
|
|
position: right_span,
|
|
|
|
});
|
|
|
|
};
|
2024-08-09 04:31:38 +00:00
|
|
|
let difference =
|
|
|
|
left.subtract(&right)
|
|
|
|
.map_err(|value_error| VmError::ValueError {
|
|
|
|
error: value_error,
|
|
|
|
position: (left_span.0, right_span.1),
|
|
|
|
})?;
|
2024-08-09 03:28:47 +00:00
|
|
|
|
|
|
|
Ok(Some(difference))
|
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2024-08-07 23:03:50 +00:00
|
|
|
pub enum VmError {
|
|
|
|
AnaylyzerError(AnalyzerError),
|
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-09 04:49:17 +00:00
|
|
|
ExpectedIdentifier {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedIdentifierOrInteger {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedInteger {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedFunction {
|
|
|
|
actual: Value,
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedList {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
ExpectedValue {
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
UndefinedIdentifier {
|
|
|
|
identifier: Identifier,
|
|
|
|
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::AnaylyzerError(analyzer_error) => analyzer_error.position(),
|
|
|
|
Self::ParseError(parse_error) => parse_error.position(),
|
|
|
|
Self::ValueError { position, .. } => *position,
|
|
|
|
Self::BuiltInFunctionError { position, .. } => *position,
|
|
|
|
Self::ExpectedIdentifier { position } => *position,
|
|
|
|
Self::ExpectedIdentifierOrInteger { position } => *position,
|
|
|
|
Self::ExpectedInteger { position } => *position,
|
|
|
|
Self::ExpectedFunction { position, .. } => *position,
|
|
|
|
Self::ExpectedList { position } => *position,
|
|
|
|
Self::ExpectedValue { position } => *position,
|
|
|
|
Self::UndefinedIdentifier { position, .. } => *position,
|
|
|
|
}
|
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<AnalyzerError> for VmError {
|
|
|
|
fn from(error: AnalyzerError) -> Self {
|
2024-08-07 15:38:08 +00:00
|
|
|
Self::AnaylyzerError(error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 Error for VmError {
|
|
|
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
|
|
match self {
|
|
|
|
Self::AnaylyzerError(analyzer_error) => Some(analyzer_error),
|
|
|
|
Self::ParseError(parse_error) => Some(parse_error),
|
2024-08-09 04:31:38 +00:00
|
|
|
Self::ValueError { error, .. } => Some(error),
|
2024-08-09 05:43:58 +00:00
|
|
|
Self::BuiltInFunctionError { error, .. } => Some(error),
|
2024-08-09 00:58:56 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for VmError {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
Self::AnaylyzerError(analyzer_error) => write!(f, "{}", analyzer_error),
|
|
|
|
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
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
Self::ExpectedIdentifierOrInteger { position } => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Expected an identifier or integer at position: {:?}",
|
|
|
|
position
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Self::ExpectedInteger { position } => {
|
|
|
|
write!(f, "Expected an integer at position: {:?}", position)
|
|
|
|
}
|
|
|
|
Self::ExpectedList { position } => {
|
|
|
|
write!(f, "Expected a list at position: {:?}", position)
|
|
|
|
}
|
|
|
|
Self::ExpectedValue { position } => {
|
|
|
|
write!(f, "Expected a value at position: {:?}", position)
|
|
|
|
}
|
2024-08-09 04:49:17 +00:00
|
|
|
Self::UndefinedIdentifier {
|
|
|
|
identifier,
|
|
|
|
position,
|
|
|
|
} => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Undefined identifier: {} at position: {:?}",
|
|
|
|
identifier, position
|
|
|
|
)
|
|
|
|
}
|
2024-08-09 00:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
2024-08-09 03:28:47 +00:00
|
|
|
#[test]
|
|
|
|
fn integer_saturating_add() {
|
|
|
|
let input = "9223372036854775807 + 1";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input, &mut HashMap::new()),
|
|
|
|
Ok(Some(Value::integer(i64::MAX)))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn integer_saturating_sub() {
|
|
|
|
let input = "-9223372036854775808 - 1";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input, &mut HashMap::new()),
|
|
|
|
Ok(Some(Value::integer(i64::MIN)))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiply() {
|
|
|
|
let input = "2 * 3";
|
|
|
|
|
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(6))));
|
|
|
|
}
|
|
|
|
|
2024-08-07 14:50:19 +00:00
|
|
|
#[test]
|
|
|
|
fn boolean() {
|
|
|
|
let input = "true";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input, &mut HashMap::new()),
|
|
|
|
Ok(Some(Value::boolean(true)))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 19:54:48 +00:00
|
|
|
#[test]
|
|
|
|
fn is_even() {
|
2024-08-07 22:24:25 +00:00
|
|
|
let input = "42.is_even()";
|
2024-08-05 19:54:48 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input, &mut HashMap::new()),
|
|
|
|
Ok(Some(Value::boolean(true)))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn is_odd() {
|
2024-08-07 22:24:25 +00:00
|
|
|
let input = "42.is_odd()";
|
2024-08-05 19:54:48 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
run(input, &mut HashMap::new()),
|
|
|
|
Ok(Some(Value::boolean(false)))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
#[test]
|
2024-08-07 22:24:25 +00:00
|
|
|
fn length() {
|
|
|
|
let input = "[1, 2, 3].length()";
|
2024-08-05 18:58:58 +00:00
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
|
2024-08-05 18:58:58 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 18:31:08 +00:00
|
|
|
#[test]
|
2024-08-07 22:24:25 +00:00
|
|
|
fn list_access() {
|
|
|
|
let input = "[1, 2, 3].1";
|
2024-08-05 18:31:08 +00:00
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2))));
|
2024-08-05 18:31:08 +00:00
|
|
|
}
|
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
#[test]
|
|
|
|
fn add() {
|
|
|
|
let input = "1 + 2";
|
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
assert_eq!(run(input, &mut HashMap::new()), 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-05 04:40:51 +00:00
|
|
|
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(6))));
|
2024-08-05 03:11:04 +00:00
|
|
|
}
|
2024-08-05 02:15:31 +00:00
|
|
|
}
|