diff --git a/src/eval_result.rs b/src/completion.rs similarity index 50% rename from src/eval_result.rs rename to src/completion.rs index eabf7df..69e5c05 100644 --- a/src/eval_result.rs +++ b/src/completion.rs @@ -1,29 +1,29 @@ use super::*; -pub enum EvalResult<'a> { +pub enum Completion<'a> { Break, Continue, Return(Value<'a>), Value(Value<'a>), } -impl<'a> EvalResult<'a> { +impl<'a> Completion<'a> { pub(crate) fn unwrap(&self) -> Value<'a> { match self { - EvalResult::Value(v) | EvalResult::Return(v) => v.clone(), - EvalResult::Break | EvalResult::Continue => Value::Null, + Completion::Value(v) | Completion::Return(v) => v.clone(), + Completion::Break | Completion::Continue => Value::Null, } } pub(crate) fn is_return(&self) -> bool { - matches!(self, EvalResult::Return(_)) + matches!(self, Completion::Return(_)) } pub(crate) fn is_break(&self) -> bool { - matches!(self, EvalResult::Break) + matches!(self, Completion::Break) } pub(crate) fn is_continue(&self) -> bool { - matches!(self, EvalResult::Continue) + matches!(self, Completion::Continue) } } diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..2512293 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,31 @@ +#[derive(Default)] +pub(crate) struct Context { + function_depth: usize, + loop_depth: usize, +} + +impl Context { + pub(crate) fn enter_function(&mut self) { + self.function_depth += 1; + } + + pub(crate) fn exit_function(&mut self) { + self.function_depth -= 1; + } + + pub(crate) fn enter_loop(&mut self) { + self.loop_depth += 1; + } + + pub(crate) fn exit_loop(&mut self) { + self.loop_depth -= 1; + } + + pub(crate) fn inside_function(&self) -> bool { + self.function_depth > 0 + } + + pub(crate) fn inside_loop(&self) -> bool { + self.loop_depth > 0 + } +} diff --git a/src/evaluator.rs b/src/evaluator.rs index 63bd23b..4ae5d72 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -1,17 +1,15 @@ -use super::*; +use {super::*, crate::context::Context}; pub struct Evaluator<'a> { + context: Context, pub environment: Environment<'a>, - pub inside_function: bool, - pub inside_loop: bool, } impl<'a> From> for Evaluator<'a> { fn from(environment: Environment<'a>) -> Self { Self { environment, - inside_function: false, - inside_loop: false, + context: Context::default(), } } } @@ -26,6 +24,26 @@ fn finite_non_negative_usize(number: f64) -> Option { } impl<'a> Evaluator<'a> { + pub(crate) fn enter_function( + &mut self, + f: impl FnOnce(&mut Self) -> Result, + ) -> Result { + self.context.enter_function(); + let result = f(self); + self.context.exit_function(); + result + } + + fn enter_loop( + &mut self, + f: impl FnOnce(&mut Self) -> Result, + ) -> Result { + self.context.enter_loop(); + let result = f(self); + self.context.exit_loop(); + result + } + /// # Errors /// /// Returns an evaluation error when a statement or expression is invalid. @@ -40,13 +58,13 @@ impl<'a> Evaluator<'a> { let mut result = Value::Null; for statement in statements { - let eval_result = self.eval_statement(statement)?; + let completion = self.eval_statement(statement)?; - result = eval_result.unwrap(); + result = completion.unwrap(); - if eval_result.is_return() - || eval_result.is_break() - || eval_result.is_continue() + if completion.is_return() + || completion.is_break() + || completion.is_continue() { break; } @@ -60,7 +78,7 @@ impl<'a> Evaluator<'a> { pub(crate) fn eval_statement( &mut self, statement: &Spanned>, - ) -> Result, Error> { + ) -> Result, Error> { let (node, span) = statement; match node { @@ -138,79 +156,73 @@ impl<'a> Evaluator<'a> { } } - Ok(EvalResult::Value(value)) + Ok(Completion::Value(value)) } Statement::Block(statements) => { let mut result = Value::Null; for statement in statements { - let eval_result = self.eval_statement(statement)?; + let completion = self.eval_statement(statement)?; - result = eval_result.unwrap(); + result = completion.unwrap(); - if eval_result.is_return() - || eval_result.is_break() - || eval_result.is_continue() + if completion.is_return() + || completion.is_break() + || completion.is_continue() { - return Ok(eval_result); + return Ok(completion); } } - Ok(EvalResult::Value(result)) + Ok(Completion::Value(result)) } Statement::Break => { - if !self.inside_loop { + if !self.context.inside_loop() { return Err(Error::new( *span, "Cannot use 'break' outside of a loop", )); } - Ok(EvalResult::Break) + Ok(Completion::Break) } Statement::Continue => { - if !self.inside_loop { + if !self.context.inside_loop() { return Err(Error::new( *span, "Cannot use 'continue' outside of a loop", )); } - Ok(EvalResult::Continue) + Ok(Completion::Continue) } Statement::Expression(expression) => { - Ok(EvalResult::Value(self.eval_expression(expression)?)) + Ok(Completion::Value(self.eval_expression(expression)?)) } Statement::For(name, iterable, body) => { let list = self.eval_expression(iterable)?.list(iterable.1)?; let mut result = Value::Null; - let old_inside_loop = self.inside_loop; + self.enter_loop(|evaluator| { + for item in list { + evaluator.environment.add_symbol(name, item); - self.inside_loop = true; + for statement in body { + let completion = evaluator.eval_statement(statement)?; - for item in list { - self.environment.add_symbol(name, item); - - for statement in body { - let eval_result = self.eval_statement(statement)?; + result = completion.unwrap(); - result = eval_result.unwrap(); - - if eval_result.is_return() { - self.inside_loop = old_inside_loop; - return Ok(EvalResult::Return(result)); - } else if eval_result.is_break() { - self.inside_loop = old_inside_loop; - return Ok(EvalResult::Value(result)); - } else if eval_result.is_continue() { - break; + if completion.is_return() { + return Ok(Completion::Return(result)); + } else if completion.is_break() { + return Ok(Completion::Value(result)); + } else if completion.is_continue() { + break; + } } } - } - - self.inside_loop = old_inside_loop; - Ok(EvalResult::Value(result)) + Ok(Completion::Value(result)) + }) } Statement::Function(name, params, body) => { let function = Function::UserDefined { @@ -222,76 +234,70 @@ impl<'a> Evaluator<'a> { self.environment.add_function(name, function.clone()); - Ok(EvalResult::Value(Value::Function(function))) + Ok(Completion::Value(Value::Function(function))) } Statement::If(condition, then_branch, else_branch) => { if self.eval_expression(condition)?.boolean(condition.1)? { let mut result = Value::Null; for statement in then_branch { - let eval_result = self.eval_statement(statement)?; + let completion = self.eval_statement(statement)?; - result = eval_result.unwrap(); + result = completion.unwrap(); - if eval_result.is_return() - || eval_result.is_break() - || eval_result.is_continue() + if completion.is_return() + || completion.is_break() + || completion.is_continue() { - return Ok(eval_result); + return Ok(completion); } } - Ok(EvalResult::Value(result)) + Ok(Completion::Value(result)) } else if let Some(else_statements) = else_branch { let mut result = Value::Null; for statement in else_statements { - let eval_result = self.eval_statement(statement)?; + let completion = self.eval_statement(statement)?; - result = eval_result.unwrap(); + result = completion.unwrap(); - if eval_result.is_return() - || eval_result.is_break() - || eval_result.is_continue() + if completion.is_return() + || completion.is_break() + || completion.is_continue() { - return Ok(eval_result); + return Ok(completion); } } - Ok(EvalResult::Value(result)) + Ok(Completion::Value(result)) } else { - Ok(EvalResult::Value(Value::Null)) + Ok(Completion::Value(Value::Null)) } } - Statement::Loop(body) => { - let old_inside_loop = self.inside_loop; - - self.inside_loop = true; - + Statement::Loop(body) => self.enter_loop(|evaluator| { loop { for statement in body { - let eval_result = self.eval_statement(statement)?; + let completion = evaluator.eval_statement(statement)?; - let result = eval_result.unwrap(); + let result = completion.unwrap(); - if eval_result.is_return() { - self.inside_loop = old_inside_loop; - return Ok(EvalResult::Return(result)); - } else if eval_result.is_break() { - self.inside_loop = old_inside_loop; - return Ok(EvalResult::Value(result)); - } else if eval_result.is_continue() { + if completion.is_return() { + return Ok(Completion::Return(result)); + } else if completion.is_break() { + return Ok(Completion::Value(result)); + } else if completion.is_continue() { break; } } } - } + }), Statement::Return(expr) => { - if !self.inside_function { + if !self.context.inside_function() { return Err(Error::new(*span, "Cannot return outside of a function")); } - Ok(EvalResult::Return(match expr { + Ok(Completion::Return(match expr { Some(expr) => self.eval_expression(expr)?, None => Value::Null, })) @@ -299,31 +305,25 @@ impl<'a> Evaluator<'a> { Statement::While(condition, body) => { let mut result = Value::Null; - let old_inside_loop = self.inside_loop; - - self.inside_loop = true; + self.enter_loop(|evaluator| { + while evaluator.eval_expression(condition)?.boolean(condition.1)? { + for statement in body { + let completion = evaluator.eval_statement(statement)?; - while self.eval_expression(condition)?.boolean(condition.1)? { - for statement in body { - let eval_result = self.eval_statement(statement)?; - - result = eval_result.unwrap(); + result = completion.unwrap(); - if eval_result.is_return() { - self.inside_loop = old_inside_loop; - return Ok(EvalResult::Return(result)); - } else if eval_result.is_break() { - self.inside_loop = old_inside_loop; - return Ok(EvalResult::Value(result)); - } else if eval_result.is_continue() { - break; + if completion.is_return() { + return Ok(Completion::Return(result)); + } else if completion.is_break() { + return Ok(Completion::Value(result)); + } else if completion.is_continue() { + break; + } } } - } - - self.inside_loop = old_inside_loop; - Ok(EvalResult::Value(result)) + Ok(Completion::Value(result)) + }) } } } diff --git a/src/function.rs b/src/function.rs index 76edead..e39579a 100644 --- a/src/function.rs +++ b/src/function.rs @@ -54,22 +54,21 @@ impl<'src> Function<'src> { call_environment.add_symbol(parameter, argument.clone()); } - let mut evaluator = Evaluator::from(call_environment); - evaluator.inside_function = true; - - if body.is_empty() { - return Ok(Value::Null); - } + Evaluator::from(call_environment).enter_function(|evaluator| { + if body.is_empty() { + return Ok(Value::Null); + } - for statement in body { - let result = evaluator.eval_statement(statement)?; + for statement in body { + let result = evaluator.eval_statement(statement)?; - if result.is_return() { - return Ok(result.unwrap()); + if result.is_return() { + return Ok(result.unwrap()); + } } - } - Ok(Value::Null) + Ok(Value::Null) + }) } } } diff --git a/src/lib.rs b/src/lib.rs index 24cba85..6bea7a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,10 +38,10 @@ pub use crate::{ arguments::Arguments, ast::{BinaryOp, Expression, Program, Statement, UnaryOp}, builtin::{Builtin, BuiltinFunction, BuiltinFunctionPayload}, + completion::Completion, config::Config, environment::Environment, error::Error, - eval_result::EvalResult, evaluator::Evaluator, float_ext::FloatExt, function::Function, @@ -64,10 +64,11 @@ mod highlighter; mod ast; mod builtin; mod builtins; +mod completion; mod config; +mod context; mod environment; mod error; -mod eval_result; mod evaluator; mod float_ext; mod function;