Refactor VM to own its context
This commit is contained in:
parent
bf11bd1f0f
commit
c71c4d2d07
@ -1,10 +1,9 @@
|
|||||||
//! Tools for analyzing an abstract syntax tree and catch errors before running the virtual
|
//! Tools for analyzing an abstract syntax tree and catch errors before running the virtual
|
||||||
//! machine.
|
//! machine.
|
||||||
//!
|
//!
|
||||||
//! This module provides to anlysis options, both of which borrow an abstract syntax tree and a
|
//! This module provides two anlysis options:
|
||||||
//! hash map of variables:
|
//! - `analyze` convenience function, which takes a string input
|
||||||
//! - `analyze` convenience function
|
//! - `Analyzer` struct, which borrows an abstract syntax tree and a context
|
||||||
//! - `Analyzer` struct
|
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
@ -28,8 +27,8 @@ use crate::{
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn analyze(source: &str) -> Result<(), DustError> {
|
pub fn analyze(source: &str) -> Result<(), DustError> {
|
||||||
let abstract_tree = parse(source)?;
|
let abstract_tree = parse(source)?;
|
||||||
let mut context = Context::new();
|
let context = Context::new();
|
||||||
let mut analyzer = Analyzer::new(&abstract_tree, &mut context);
|
let mut analyzer = Analyzer::new(&abstract_tree, &context);
|
||||||
|
|
||||||
analyzer
|
analyzer
|
||||||
.analyze()
|
.analyze()
|
||||||
@ -54,11 +53,11 @@ pub fn analyze(source: &str) -> Result<(), DustError> {
|
|||||||
/// assert!(result.is_err());
|
/// assert!(result.is_err());
|
||||||
pub struct Analyzer<'a> {
|
pub struct Analyzer<'a> {
|
||||||
abstract_tree: &'a AbstractSyntaxTree,
|
abstract_tree: &'a AbstractSyntaxTree,
|
||||||
context: &'a mut Context,
|
context: &'a Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Analyzer<'a> {
|
impl<'a> Analyzer<'a> {
|
||||||
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: &'a mut Context) -> Self {
|
pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: &'a Context) -> Self {
|
||||||
Self {
|
Self {
|
||||||
abstract_tree,
|
abstract_tree,
|
||||||
context,
|
context,
|
||||||
|
@ -21,6 +21,15 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_variables_from(other: &Self) -> Self {
|
||||||
|
Self {
|
||||||
|
variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())),
|
||||||
|
is_garbage_collected_to: Arc::new(RwLock::new(
|
||||||
|
*other.is_garbage_collected_to.read().unwrap(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn variable_count(&self) -> usize {
|
pub fn variable_count(&self) -> usize {
|
||||||
self.variables.read().unwrap().len()
|
self.variables.read().unwrap().len()
|
||||||
}
|
}
|
||||||
@ -54,7 +63,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_type(&mut self, identifier: Identifier, r#type: Type, position: Span) {
|
pub fn set_type(&self, identifier: Identifier, r#type: Type, position: Span) {
|
||||||
log::trace!("Setting {identifier} to type {type} at {position:?}");
|
log::trace!("Setting {identifier} to type {type} at {position:?}");
|
||||||
|
|
||||||
self.variables
|
self.variables
|
||||||
@ -63,7 +72,7 @@ impl Context {
|
|||||||
.insert(identifier, (VariableData::Type(r#type), position));
|
.insert(identifier, (VariableData::Type(r#type), position));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(&mut self, identifier: Identifier, value: Value) {
|
pub fn set_value(&self, identifier: Identifier, value: Value) {
|
||||||
log::trace!("Setting {identifier} to value {value}");
|
log::trace!("Setting {identifier} to value {value}");
|
||||||
|
|
||||||
let mut variables = self.variables.write().unwrap();
|
let mut variables = self.variables.write().unwrap();
|
||||||
@ -76,7 +85,7 @@ impl Context {
|
|||||||
variables.insert(identifier, (VariableData::Value(value), last_position));
|
variables.insert(identifier, (VariableData::Value(value), last_position));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_garbage(&mut self, current_position: usize) {
|
pub fn collect_garbage(&self, current_position: usize) {
|
||||||
log::trace!("Collecting garbage up to {current_position}");
|
log::trace!("Collecting garbage up to {current_position}");
|
||||||
|
|
||||||
let mut is_garbage_collected_to = self.is_garbage_collected_to.write().unwrap();
|
let mut is_garbage_collected_to = self.is_garbage_collected_to.write().unwrap();
|
||||||
@ -101,7 +110,7 @@ impl Context {
|
|||||||
*is_garbage_collected_to = current_position;
|
*is_garbage_collected_to = current_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_last_position(&mut self, identifier: &Identifier, position: Span) -> bool {
|
pub fn update_last_position(&self, identifier: &Identifier, position: Span) -> bool {
|
||||||
if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) {
|
if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) {
|
||||||
*last_position = position;
|
*last_position = position;
|
||||||
|
|
||||||
@ -142,9 +151,9 @@ mod tests {
|
|||||||
z = x + y
|
z = x + y
|
||||||
z
|
z
|
||||||
";
|
";
|
||||||
let mut context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
run_with_context(source, &mut context).unwrap();
|
run_with_context(source, context.clone()).unwrap();
|
||||||
|
|
||||||
assert_eq!(context.variable_count(), 0);
|
assert_eq!(context.variable_count(), 0);
|
||||||
}
|
}
|
||||||
@ -158,9 +167,9 @@ mod tests {
|
|||||||
z = z + y
|
z = z + y
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
let mut context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
run_with_context(source, &mut context).unwrap();
|
run_with_context(source, context.clone()).unwrap();
|
||||||
|
|
||||||
assert_eq!(context.variable_count(), 0);
|
assert_eq!(context.variable_count(), 0);
|
||||||
}
|
}
|
||||||
|
@ -748,9 +748,9 @@ impl Function {
|
|||||||
self,
|
self,
|
||||||
_type_arguments: Option<Vec<Type>>,
|
_type_arguments: Option<Vec<Type>>,
|
||||||
value_arguments: Option<Vec<Value>>,
|
value_arguments: Option<Vec<Value>>,
|
||||||
context: &mut Context,
|
context: &Context,
|
||||||
) -> Result<Option<Value>, VmError> {
|
) -> Result<Option<Value>, VmError> {
|
||||||
let mut new_context = context.clone();
|
let new_context = Context::with_variables_from(context);
|
||||||
|
|
||||||
if let (Some(value_parameters), Some(value_arguments)) =
|
if let (Some(value_parameters), Some(value_arguments)) =
|
||||||
(self.value_parameters, value_arguments)
|
(self.value_parameters, value_arguments)
|
||||||
@ -760,9 +760,9 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = Vm::new(self.body);
|
let mut vm = Vm::new(self.body, new_context);
|
||||||
|
|
||||||
vm.run(&mut new_context)
|
vm.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn return_type(&self, variables: &Context) -> Option<Type> {
|
pub fn return_type(&self, variables: &Context) -> Option<Type> {
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
//! Virtual machine for running the abstract syntax tree.
|
//! Virtual machine for running the abstract syntax tree.
|
||||||
|
//!
|
||||||
|
//! 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
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::BinaryOperator, parse, value::ValueInner, AbstractSyntaxTree, Analyzer,
|
parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError,
|
||||||
BuiltInFunctionError, Context, DustError, Identifier, Node, ParseError, Span, Statement,
|
Context, DustError, Identifier, Node, ParseError, Span, Statement, UnaryOperator, Value,
|
||||||
UnaryOperator, Value, ValueError,
|
ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||||
let mut context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
run_with_context(source, &mut context)
|
run_with_context(source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_with_context<'src>(
|
pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>, DustError> {
|
||||||
source: &'src str,
|
|
||||||
context: &mut Context,
|
|
||||||
) -> Result<Option<Value>, DustError<'src>> {
|
|
||||||
let abstract_syntax_tree = parse(source)?;
|
let abstract_syntax_tree = parse(source)?;
|
||||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree, context);
|
let mut analyzer = Analyzer::new(&abstract_syntax_tree, &context);
|
||||||
|
|
||||||
analyzer
|
analyzer
|
||||||
.analyze()
|
.analyze()
|
||||||
@ -30,45 +32,45 @@ pub fn run_with_context<'src>(
|
|||||||
source,
|
source,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut vm = Vm::new(abstract_syntax_tree);
|
let mut vm = Vm::new(abstract_syntax_tree, context);
|
||||||
|
|
||||||
vm.run(context)
|
vm.run()
|
||||||
.map_err(|vm_error| DustError::VmError { vm_error, source })
|
.map_err(|vm_error| DustError::VmError { vm_error, source })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
abstract_tree: AbstractSyntaxTree,
|
abstract_tree: AbstractSyntaxTree,
|
||||||
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn new(abstract_tree: AbstractSyntaxTree) -> Self {
|
pub fn new(abstract_tree: AbstractSyntaxTree, context: Context) -> Self {
|
||||||
Self { abstract_tree }
|
Self {
|
||||||
|
abstract_tree,
|
||||||
|
context,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, context: &mut Context) -> Result<Option<Value>, VmError> {
|
pub fn run(&mut self) -> Result<Option<Value>, VmError> {
|
||||||
let mut previous_position = (0, 0);
|
let mut previous_position = (0, 0);
|
||||||
let mut previous_value = None;
|
let mut previous_value = None;
|
||||||
|
|
||||||
while let Some(statement) = self.abstract_tree.nodes.pop_front() {
|
while let Some(statement) = self.abstract_tree.nodes.pop_front() {
|
||||||
let new_position = statement.position;
|
let new_position = statement.position;
|
||||||
|
|
||||||
previous_value = self.run_statement(statement, context)?;
|
previous_value = self.run_statement(statement)?;
|
||||||
|
|
||||||
context.collect_garbage(previous_position.1);
|
self.context.collect_garbage(previous_position.1);
|
||||||
|
|
||||||
previous_position = new_position;
|
previous_position = new_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.collect_garbage(previous_position.1);
|
self.context.collect_garbage(previous_position.1);
|
||||||
|
|
||||||
Ok(previous_value)
|
Ok(previous_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_statement(
|
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
|
||||||
&self,
|
|
||||||
node: Node<Statement>,
|
|
||||||
context: &mut Context,
|
|
||||||
) -> Result<Option<Value>, VmError> {
|
|
||||||
match node.inner {
|
match node.inner {
|
||||||
Statement::BinaryOperation {
|
Statement::BinaryOperation {
|
||||||
left,
|
left,
|
||||||
@ -85,7 +87,7 @@ impl Vm {
|
|||||||
position: left.position,
|
position: left.position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let value = if let Some(value) = self.run_statement(*right, context)? {
|
let value = if let Some(value) = self.run_statement(*right)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
@ -93,7 +95,7 @@ impl Vm {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_value(identifier, value);
|
self.context.set_value(identifier, value);
|
||||||
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
@ -101,7 +103,7 @@ impl Vm {
|
|||||||
if let BinaryOperator::AddAssign = operator.inner {
|
if let BinaryOperator::AddAssign = operator.inner {
|
||||||
let (identifier, left_value) =
|
let (identifier, left_value) =
|
||||||
if let Statement::Identifier(identifier) = left.inner {
|
if let Statement::Identifier(identifier) = left.inner {
|
||||||
let value = context.get_value(&identifier).ok_or_else(|| {
|
let value = self.context.get_value(&identifier).ok_or_else(|| {
|
||||||
VmError::UndefinedVariable {
|
VmError::UndefinedVariable {
|
||||||
identifier: Node::new(
|
identifier: Node::new(
|
||||||
Statement::Identifier(identifier.clone()),
|
Statement::Identifier(identifier.clone()),
|
||||||
@ -116,7 +118,7 @@ impl Vm {
|
|||||||
position: left.position,
|
position: left.position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let right_value = if let Some(value) = self.run_statement(*right, context)? {
|
let right_value = if let Some(value) = self.run_statement(*right)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
@ -130,20 +132,20 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
context.set_value(identifier, new_value);
|
self.context.set_value(identifier, new_value);
|
||||||
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let left_position = left.position;
|
let left_position = left.position;
|
||||||
let left_value = if let Some(value) = self.run_statement(*left, context)? {
|
let left_value = if let Some(value) = self.run_statement(*left)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
position: left_position,
|
position: left_position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let right_value = if let Some(value) = self.run_statement(*right, context)? {
|
let right_value = if let Some(value) = self.run_statement(*right)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
@ -178,7 +180,7 @@ impl Vm {
|
|||||||
let mut previous_value = None;
|
let mut previous_value = None;
|
||||||
|
|
||||||
for statement in statements {
|
for statement in statements {
|
||||||
previous_value = self.run_statement(statement, context)?;
|
previous_value = self.run_statement(statement)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(previous_value)
|
Ok(previous_value)
|
||||||
@ -193,7 +195,7 @@ impl Vm {
|
|||||||
|
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
let position = node.position;
|
let position = node.position;
|
||||||
let value = if let Some(value) = self.run_statement(node, context)? {
|
let value = if let Some(value) = self.run_statement(node)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue { position });
|
return Err(VmError::ExpectedValue { position });
|
||||||
@ -223,14 +225,13 @@ impl Vm {
|
|||||||
value_arguments: value_parameter_nodes,
|
value_arguments: value_parameter_nodes,
|
||||||
} => {
|
} => {
|
||||||
let function_position = function_node.position;
|
let function_position = function_node.position;
|
||||||
let function_value =
|
let function_value = if let Some(value) = self.run_statement(*function_node)? {
|
||||||
if let Some(value) = self.run_statement(*function_node, context)? {
|
value
|
||||||
value
|
} else {
|
||||||
} else {
|
return Err(VmError::ExpectedValue {
|
||||||
return Err(VmError::ExpectedValue {
|
position: function_position,
|
||||||
position: function_position,
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
let function = if let Some(function) = function_value.as_function() {
|
let function = if let Some(function) = function_value.as_function() {
|
||||||
function
|
function
|
||||||
} else {
|
} else {
|
||||||
@ -245,7 +246,7 @@ impl Vm {
|
|||||||
|
|
||||||
for node in value_nodes {
|
for node in value_nodes {
|
||||||
let position = node.position;
|
let position = node.position;
|
||||||
let value = if let Some(value) = self.run_statement(node, context)? {
|
let value = if let Some(value) = self.run_statement(node)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue { position });
|
return Err(VmError::ExpectedValue { position });
|
||||||
@ -259,10 +260,12 @@ impl Vm {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(function.clone().call(None, value_parameters, context)?)
|
Ok(function
|
||||||
|
.clone()
|
||||||
|
.call(None, value_parameters, &self.context)?)
|
||||||
}
|
}
|
||||||
Statement::Identifier(identifier) => {
|
Statement::Identifier(identifier) => {
|
||||||
let value_option = context.get_value(&identifier);
|
let value_option = self.context.get_value(&identifier);
|
||||||
|
|
||||||
if let Some(value) = value_option {
|
if let Some(value) = value_option {
|
||||||
Ok(Some(value.clone()))
|
Ok(Some(value.clone()))
|
||||||
@ -274,14 +277,13 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
Statement::If { condition, body } => {
|
Statement::If { condition, body } => {
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
let condition_value =
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||||
if let Some(value) = self.run_statement(*condition, context)? {
|
value
|
||||||
value
|
} else {
|
||||||
} else {
|
return Err(VmError::ExpectedValue {
|
||||||
return Err(VmError::ExpectedValue {
|
position: condition_position,
|
||||||
position: condition_position,
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
let condition = if let Some(condition) = condition_value.as_boolean() {
|
let condition = if let Some(condition) = condition_value.as_boolean() {
|
||||||
condition
|
condition
|
||||||
} else {
|
} else {
|
||||||
@ -291,7 +293,7 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if condition {
|
if condition {
|
||||||
self.run_statement(*body, context)?;
|
self.run_statement(*body)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -302,20 +304,19 @@ impl Vm {
|
|||||||
else_body,
|
else_body,
|
||||||
} => {
|
} => {
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
let condition_value =
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||||
if let Some(value) = self.run_statement(*condition, context)? {
|
value
|
||||||
value
|
} else {
|
||||||
} else {
|
return Err(VmError::ExpectedValue {
|
||||||
return Err(VmError::ExpectedValue {
|
position: condition_position,
|
||||||
position: condition_position,
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(condition) = condition_value.as_boolean() {
|
if let Some(condition) = condition_value.as_boolean() {
|
||||||
if condition {
|
if condition {
|
||||||
self.run_statement(*if_body, context)
|
self.run_statement(*if_body)
|
||||||
} else {
|
} else {
|
||||||
self.run_statement(*else_body, context)
|
self.run_statement(*else_body)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VmError::ExpectedBoolean {
|
Err(VmError::ExpectedBoolean {
|
||||||
@ -329,23 +330,22 @@ impl Vm {
|
|||||||
else_ifs,
|
else_ifs,
|
||||||
} => {
|
} => {
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
let condition_value =
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||||
if let Some(value) = self.run_statement(*condition, context)? {
|
value
|
||||||
value
|
} else {
|
||||||
} else {
|
return Err(VmError::ExpectedValue {
|
||||||
return Err(VmError::ExpectedValue {
|
position: condition_position,
|
||||||
position: condition_position,
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(condition) = condition_value.as_boolean() {
|
if let Some(condition) = condition_value.as_boolean() {
|
||||||
if condition {
|
if condition {
|
||||||
self.run_statement(*if_body, context)
|
self.run_statement(*if_body)
|
||||||
} else {
|
} else {
|
||||||
for (condition, body) in else_ifs {
|
for (condition, body) in else_ifs {
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
let condition_value =
|
let condition_value =
|
||||||
if let Some(value) = self.run_statement(condition, context)? {
|
if let Some(value) = self.run_statement(condition)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
@ -361,7 +361,7 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if condition {
|
if condition {
|
||||||
self.run_statement(body, context)?;
|
self.run_statement(body)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,23 +380,22 @@ impl Vm {
|
|||||||
else_body,
|
else_body,
|
||||||
} => {
|
} => {
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
let condition_value =
|
let condition_value = if let Some(value) = self.run_statement(*condition)? {
|
||||||
if let Some(value) = self.run_statement(*condition, context)? {
|
value
|
||||||
value
|
} else {
|
||||||
} else {
|
return Err(VmError::ExpectedValue {
|
||||||
return Err(VmError::ExpectedValue {
|
position: condition_position,
|
||||||
position: condition_position,
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(condition) = condition_value.as_boolean() {
|
if let Some(condition) = condition_value.as_boolean() {
|
||||||
if condition {
|
if condition {
|
||||||
self.run_statement(*if_body, context)
|
self.run_statement(*if_body)
|
||||||
} else {
|
} else {
|
||||||
for (condition, body) in else_ifs {
|
for (condition, body) in else_ifs {
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
let condition_value =
|
let condition_value =
|
||||||
if let Some(value) = self.run_statement(condition, context)? {
|
if let Some(value) = self.run_statement(condition)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
@ -412,11 +411,11 @@ impl Vm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if condition {
|
if condition {
|
||||||
return self.run_statement(body, context);
|
return self.run_statement(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.run_statement(*else_body, context)
|
self.run_statement(*else_body)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VmError::ExpectedBoolean {
|
Err(VmError::ExpectedBoolean {
|
||||||
@ -429,7 +428,7 @@ impl Vm {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|node| {
|
.map(|node| {
|
||||||
let span = node.position;
|
let span = node.position;
|
||||||
if let Some(value) = self.run_statement(node, context)? {
|
if let Some(value) = self.run_statement(node)? {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
} else {
|
} else {
|
||||||
Err(VmError::ExpectedValue { position: span })
|
Err(VmError::ExpectedValue { position: span })
|
||||||
@ -451,7 +450,7 @@ impl Vm {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
let position = value_node.position;
|
let position = value_node.position;
|
||||||
let value = if let Some(value) = self.run_statement(value_node, context)? {
|
let value = if let Some(value) = self.run_statement(value_node)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue { position });
|
return Err(VmError::ExpectedValue { position });
|
||||||
@ -463,13 +462,13 @@ impl Vm {
|
|||||||
Ok(Some(Value::map(values)))
|
Ok(Some(Value::map(values)))
|
||||||
}
|
}
|
||||||
Statement::Nil(node) => {
|
Statement::Nil(node) => {
|
||||||
let _return = self.run_statement(*node, context)?;
|
let _return = self.run_statement(*node)?;
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
Statement::PropertyAccess(left, right) => {
|
Statement::PropertyAccess(left, right) => {
|
||||||
let left_span = left.position;
|
let left_span = left.position;
|
||||||
let left_value = if let Some(value) = self.run_statement(*left, context)? {
|
let left_value = if let Some(value) = self.run_statement(*left)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
@ -502,7 +501,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
Statement::UnaryOperation { operator, operand } => {
|
Statement::UnaryOperation { operator, operand } => {
|
||||||
let position = operand.position;
|
let position = operand.position;
|
||||||
let value = if let Some(value) = self.run_statement(*operand, context)? {
|
let value = if let Some(value) = self.run_statement(*operand)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue { position });
|
return Err(VmError::ExpectedValue { position });
|
||||||
@ -532,7 +531,7 @@ impl Vm {
|
|||||||
|
|
||||||
let condition_position = condition.position;
|
let condition_position = condition.position;
|
||||||
|
|
||||||
while let Some(condition_value) = self.run_statement(*condition.clone(), context)? {
|
while let Some(condition_value) = self.run_statement(*condition.clone())? {
|
||||||
if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() {
|
if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() {
|
||||||
if !condition_value {
|
if !condition_value {
|
||||||
break;
|
break;
|
||||||
@ -543,7 +542,7 @@ impl Vm {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return_value = self.run_statement(*body.clone(), context)?;
|
return_value = self.run_statement(*body.clone())?;
|
||||||
|
|
||||||
if return_value.is_some() {
|
if return_value.is_some() {
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user