Refactor and clean up

This commit is contained in:
Jeff 2024-08-05 00:40:51 -04:00
parent 2268fc827d
commit 61f136edd2
6 changed files with 294 additions and 164 deletions

View File

@ -2,25 +2,28 @@ use crate::{Identifier, Span, Value};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Node { pub struct Node {
pub operation: Statement, pub statement: Statement,
pub span: Span, pub span: Span,
} }
impl Node { impl Node {
pub fn new(operation: Statement, span: Span) -> Self { pub fn new(operation: Statement, span: Span) -> Self {
Self { operation, span } Self {
statement: operation,
span,
}
} }
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Statement { pub enum Statement {
// Top-level statements // Top-level statements
Assign(Box<(Node, Node)>), Assign(Box<Node>, Box<Node>),
// Expressions // Expressions
Add(Box<(Node, Node)>), Add(Box<Node>, Box<Node>),
List(Vec<Node>), List(Vec<Node>),
Multiply(Box<(Node, Node)>), Multiply(Box<Node>, Box<Node>),
// Hard-coded values // Hard-coded values
Constant(Value), Constant(Value),

View File

@ -1,5 +1,11 @@
use crate::{Node, Span, Statement}; use crate::{Node, Span, Statement};
pub fn analyze(abstract_tree: Vec<Node>) -> Result<(), AnalyzerError> {
let analyzer = Analyzer::new(abstract_tree);
analyzer.analyze()
}
pub struct Analyzer { pub struct Analyzer {
abstract_tree: Vec<Node>, abstract_tree: Vec<Node>,
} }
@ -18,33 +24,36 @@ impl Analyzer {
} }
fn analyze_node(&self, node: &Node) -> Result<(), AnalyzerError> { fn analyze_node(&self, node: &Node) -> Result<(), AnalyzerError> {
match &node.operation { match &node.statement {
Statement::Add(instructions) => { Statement::Add(left, right) => {
self.analyze_node(&instructions.0)?; self.analyze_node(&left)?;
self.analyze_node(&instructions.1)?; self.analyze_node(&right)?;
} }
Statement::Assign(instructions) => { Statement::Assign(left, right) => {
if let Statement::Identifier(_) = &instructions.0.operation { if let Statement::Identifier(_) = &left.statement {
// Identifier // Identifier is in the correct position
} else { } else {
return Err(AnalyzerError::ExpectedIdentifier { return Err(AnalyzerError::ExpectedIdentifier {
actual: instructions.0.clone(), actual: left.as_ref().clone(),
}); });
} }
self.analyze_node(&instructions.0)?; self.analyze_node(&right)?;
self.analyze_node(&instructions.1)?;
} }
Statement::Constant(_) => {} Statement::Constant(_) => {}
Statement::Identifier(_) => {} Statement::Identifier(_) => {
Statement::List(instructions) => { return Err(AnalyzerError::UnexpectedIdentifier {
for instruction in instructions { identifier: node.clone(),
self.analyze_node(instruction)?; });
}
Statement::List(statements) => {
for statement in statements {
self.analyze_node(statement)?;
} }
} }
Statement::Multiply(instructions) => { Statement::Multiply(left, right) => {
self.analyze_node(&instructions.0)?; self.analyze_node(&left)?;
self.analyze_node(&instructions.1)?; self.analyze_node(&right)?;
} }
} }
@ -55,22 +64,23 @@ impl Analyzer {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum AnalyzerError { pub enum AnalyzerError {
ExpectedIdentifier { actual: Node }, ExpectedIdentifier { actual: Node },
UnexpectedIdentifier { identifier: Node },
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::Value; use crate::{Identifier, Value};
use super::*; use super::*;
#[test] #[test]
fn analyze() { fn assignment_expect_identifier() {
let abstract_tree = vec![Node::new( let abstract_tree = vec![Node::new(
Statement::Assign(Box::new(( Statement::Assign(
Node::new(Statement::Constant(Value::integer(1)), (0, 1)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
Node::new(Statement::Constant(Value::integer(2)), (1, 2)), Box::new(Node::new(Statement::Constant(Value::integer(2)), (1, 2))),
))), ),
(0, 1), (0, 2),
)]; )];
let analyzer = Analyzer::new(abstract_tree); let analyzer = Analyzer::new(abstract_tree);
@ -82,4 +92,44 @@ mod tests {
}) })
) )
} }
#[test]
fn unexpected_identifier_simple() {
let abstract_tree = vec![Node::new(
Statement::Identifier(Identifier::new("x")),
(0, 1),
)];
let analyzer = Analyzer::new(abstract_tree);
assert_eq!(
analyzer.analyze(),
Err(AnalyzerError::UnexpectedIdentifier {
identifier: Node::new(Statement::Identifier(Identifier::new("x")), (0, 1))
})
)
}
#[test]
fn unexpected_identifier_nested() {
let abstract_tree = vec![Node::new(
Statement::Add(
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
Box::new(Node::new(
Statement::Identifier(Identifier::new("x")),
(1, 2),
)),
),
(0, 1),
)];
let analyzer = Analyzer::new(abstract_tree);
assert_eq!(
analyzer.analyze(),
Err(AnalyzerError::UnexpectedIdentifier {
identifier: Node::new(Statement::Identifier(Identifier::new("x")), (1, 2))
})
)
}
} }

View File

@ -22,17 +22,20 @@ pub fn lex(input: &str) -> Result<Vec<(Token, Span)>, LexError> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Lexer<'a> { pub struct Lexer<'a> {
input: &'a str, source: &'a str,
position: usize, position: usize,
} }
impl<'a> Lexer<'a> { impl<'a> Lexer<'a> {
pub fn new(input: &'a str) -> Self { pub fn new(input: &'a str) -> Self {
Lexer { input, position: 0 } Lexer {
source: input,
position: 0,
}
} }
fn next_char(&mut self) -> Option<char> { fn next_char(&mut self) -> Option<char> {
self.input[self.position..].chars().next().map(|c| { self.source[self.position..].chars().next().map(|c| {
self.position += c.len_utf8(); self.position += c.len_utf8();
c c
}) })
@ -97,7 +100,7 @@ impl<'a> Lexer<'a> {
} }
fn peek_char(&self) -> Option<char> { fn peek_char(&self) -> Option<char> {
self.input[self.position..].chars().next() self.source[self.position..].chars().next()
} }
fn lex_number(&mut self) -> Result<(Token, Span), LexError> { fn lex_number(&mut self) -> Result<(Token, Span), LexError> {
@ -127,11 +130,11 @@ impl<'a> Lexer<'a> {
} }
if is_float { if is_float {
let float = self.input[start_pos..self.position].parse::<f64>()?; let float = self.source[start_pos..self.position].parse::<f64>()?;
Ok((Token::Float(float), (start_pos, self.position))) Ok((Token::Float(float), (start_pos, self.position)))
} else { } else {
let integer = self.input[start_pos..self.position].parse::<i64>()?; let integer = self.source[start_pos..self.position].parse::<i64>()?;
Ok((Token::Integer(integer), (start_pos, self.position))) Ok((Token::Integer(integer), (start_pos, self.position)))
} }
@ -148,7 +151,7 @@ impl<'a> Lexer<'a> {
} }
} }
let identifier = &self.input[start_pos..self.position]; let identifier = &self.source[start_pos..self.position];
let token = Token::Identifier(Identifier::new(identifier)); let token = Token::Identifier(Identifier::new(identifier));
Ok((token, (start_pos, self.position))) Ok((token, (start_pos, self.position)))

View File

@ -18,13 +18,13 @@ pub mod value;
pub mod vm; pub mod vm;
pub use abstract_tree::{Node, Statement}; pub use abstract_tree::{Node, Statement};
pub use analyzer::Analyzer; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lex::{lex, LexError, Lexer}; pub use lex::{lex, LexError, Lexer};
pub use parse::{parse, ParseError, Parser}; pub use parse::{parse, ParseError, Parser};
pub use r#type::Type; pub use r#type::Type;
pub use token::Token; pub use token::Token;
pub use value::{Value, ValueError}; pub use value::{Value, ValueError};
pub use vm::Vm; pub use vm::{run, Vm, VmError};
pub type Span = (usize, usize); pub type Span = (usize, usize);

View File

@ -1,24 +1,26 @@
use std::collections::VecDeque;
use crate::{ use crate::{
lex::{LexError, Lexer}, lex::{LexError, Lexer},
Node, Span, Statement, Token, Value, Node, Span, Statement, Token, Value,
}; };
pub fn parse(input: &str) -> Result<Vec<Node>, ParseError> { pub fn parse(input: &str) -> Result<VecDeque<Node>, ParseError> {
let lexer = Lexer::new(input); let lexer = Lexer::new(input);
let mut parser = Parser::new(lexer); let mut parser = Parser::new(lexer);
let mut instructions = Vec::new(); let mut nodes = VecDeque::new();
loop { loop {
let instruction = parser.parse()?; let node = parser.parse()?;
instructions.push(instruction); nodes.push_back(node);
if let Token::Eof = parser.current.0 { if let Token::Eof = parser.current.0 {
break; break;
} }
} }
Ok(instructions) Ok(nodes)
} }
pub struct Parser<'src> { pub struct Parser<'src> {
@ -35,7 +37,7 @@ impl<'src> Parser<'src> {
} }
pub fn parse(&mut self) -> Result<Node, ParseError> { pub fn parse(&mut self) -> Result<Node, ParseError> {
self.parse_instruction(0) self.parse_node(0)
} }
fn next_token(&mut self) -> Result<(), ParseError> { fn next_token(&mut self) -> Result<(), ParseError> {
@ -44,42 +46,42 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_instruction(&mut self, precedence: u8) -> Result<Node, ParseError> { fn parse_node(&mut self, precedence: u8) -> Result<Node, ParseError> {
let left_instruction = self.parse_primary()?; let left_node = self.parse_primary()?;
let left_start = left_instruction.span.0; let left_start = left_node.span.0;
if precedence < self.current_precedence() { if precedence < self.current_precedence() {
match &self.current { match &self.current {
(Token::Plus, _) => { (Token::Plus, _) => {
self.next_token()?; self.next_token()?;
let right_instruction = self.parse_instruction(self.current_precedence())?; let right_node = self.parse_node(self.current_precedence())?;
let right_end = right_instruction.span.1; let right_end = right_node.span.1;
return Ok(Node::new( return Ok(Node::new(
Statement::Add(Box::new((left_instruction, right_instruction))), Statement::Add(Box::new(left_node), Box::new(right_node)),
(left_start, right_end), (left_start, right_end),
)); ));
} }
(Token::Star, _) => { (Token::Star, _) => {
self.next_token()?; self.next_token()?;
let right_instruction = self.parse_instruction(self.current_precedence())?; let right_node = self.parse_node(self.current_precedence())?;
let right_end = right_instruction.span.1; let right_end = right_node.span.1;
return Ok(Node::new( return Ok(Node::new(
Statement::Multiply(Box::new((left_instruction, right_instruction))), Statement::Multiply(Box::new(left_node), Box::new(right_node)),
(left_start, right_end), (left_start, right_end),
)); ));
} }
(Token::Equal, _) => { (Token::Equal, _) => {
self.next_token()?; self.next_token()?;
let right_instruction = self.parse_instruction(self.current_precedence())?; let right_node = self.parse_node(self.current_precedence())?;
let right_end = right_instruction.span.1; let right_end = right_node.span.1;
return Ok(Node::new( return Ok(Node::new(
Statement::Assign(Box::new((left_instruction, right_instruction))), Statement::Assign(Box::new(left_node), Box::new(right_node)),
(left_start, right_end), (left_start, right_end),
)); ));
} }
@ -87,7 +89,7 @@ impl<'src> Parser<'src> {
} }
} }
Ok(left_instruction) Ok(left_node)
} }
fn parse_primary(&mut self) -> Result<Node, ParseError> { fn parse_primary(&mut self) -> Result<Node, ParseError> {
@ -110,13 +112,13 @@ impl<'src> Parser<'src> {
(Token::LeftParenthesis, left_span) => { (Token::LeftParenthesis, left_span) => {
self.next_token()?; self.next_token()?;
let instruction = self.parse_instruction(0)?; let instruction = self.parse_node(0)?;
if let (Token::RightParenthesis, right_span) = self.current { if let (Token::RightParenthesis, right_span) = self.current {
self.next_token()?; self.next_token()?;
Ok(Node::new( Ok(Node::new(
instruction.operation, instruction.statement,
(left_span.0, right_span.1), (left_span.0, right_span.1),
)) ))
} else { } else {
@ -147,7 +149,7 @@ impl<'src> Parser<'src> {
continue; continue;
} }
if let Ok(instruction) = self.parse_instruction(0) { if let Ok(instruction) = self.parse_node(0) {
instructions.push(instruction); instructions.push(instruction);
} else { } else {
return Err(ParseError::ExpectedClosingSquareBrace { return Err(ParseError::ExpectedClosingSquareBrace {
@ -197,32 +199,39 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(
Statement::List(vec![ Statement::List(vec![
Node::new(Statement::Constant(Value::integer(1)), (1, 2)), Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
Node::new( Node::new(
Statement::Add(Box::new(( Statement::Add(
Node::new(Statement::Constant(Value::integer(1)), (4, 5)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (4, 5))),
Node::new(Statement::Constant(Value::integer(1)), (8, 9)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (8, 9))),
))), ),
(4, 9) (4, 9),
), ),
Node::new( Node::new(
Statement::Add(Box::new(( Statement::Add(
Node::new(Statement::Constant(Value::integer(2)), (11, 12)), Box::new(Node::new(Statement::Constant(Value::integer(2)), (11, 12))),
Node::new( Box::new(Node::new(
Statement::Multiply(Box::new(( Statement::Multiply(
Node::new(Statement::Constant(Value::integer(4)), (16, 17)), Box::new(Node::new(
Node::new(Statement::Constant(Value::integer(10)), (20, 22)), Statement::Constant(Value::integer(4)),
))), (16, 17)
(15, 23) )),
), Box::new(Node::new(
))), Statement::Constant(Value::integer(10)),
(11, 23) (20, 22)
) )),
),
(15, 23),
),),
),
(11, 23),
),
]), ]),
(0, 24) (0, 24),
)]) )]
.into())
); );
} }
@ -232,13 +241,14 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(
Statement::List(vec![ Statement::List(vec![
Node::new(Statement::Constant(Value::integer(1)), (1, 2)), Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
Node::new(Statement::Constant(Value::integer(2)), (4, 5)), Node::new(Statement::Constant(Value::integer(2)), (4, 5)),
]), ]),
(0, 6) (0, 6),
)]) )]
.into())
); );
} }
@ -248,7 +258,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new(Statement::List(vec![]), (0, 2))]) Ok([Node::new(Statement::List(vec![]), (0, 2))].into())
); );
} }
@ -258,10 +268,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(Statement::Constant(Value::float(42.0)), (0, 4))].into())
Statement::Constant(Value::float(42.0)),
(0, 4)
)])
); );
} }
@ -271,13 +278,14 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(
Statement::Add(Box::new(( Statement::Add(
Node::new(Statement::Constant(Value::integer(1)), (0, 1)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
Node::new(Statement::Constant(Value::integer(2)), (4, 5)), Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
))), ),
(0, 5) (0, 5),
)]) )]
.into())
); );
} }
@ -287,13 +295,14 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(
Statement::Multiply(Box::new(( Statement::Multiply(
Node::new(Statement::Constant(Value::integer(1)), (0, 1)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
Node::new(Statement::Constant(Value::integer(2)), (4, 5)), Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
))), ),
(0, 5) (0, 5),
)]) )]
.into())
); );
} }
@ -303,19 +312,20 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(
Statement::Add(Box::new(( Statement::Add(
Node::new(Statement::Constant(Value::integer(1)), (0, 1)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
Node::new( Box::new(Node::new(
Statement::Multiply(Box::new(( Statement::Multiply(
Node::new(Statement::Constant(Value::integer(2)), (4, 5)), Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
Node::new(Statement::Constant(Value::integer(3)), (8, 9)), Box::new(Node::new(Statement::Constant(Value::integer(3)), (8, 9))),
))), ),
(4, 9) (4, 9),
), )),
))), ),
(0, 9) (0, 9),
)]) )]
.into())
); );
} }
@ -325,25 +335,35 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(vec![Node::new( Ok([Node::new(
Statement::Assign(Box::new(( Statement::Assign(
Node::new(Statement::Identifier(Identifier::new("a")), (0, 1)), Box::new(Node::new(
Node::new( Statement::Identifier(Identifier::new("a")),
Statement::Add(Box::new(( (0, 1)
Node::new(Statement::Constant(Value::integer(1)), (4, 5)), )),
Node::new( Box::new(Node::new(
Statement::Multiply(Box::new(( Statement::Add(
Node::new(Statement::Constant(Value::integer(2)), (8, 9)), Box::new(Node::new(Statement::Constant(Value::integer(1)), (4, 5))),
Node::new(Statement::Constant(Value::integer(3)), (12, 13)), Box::new(Node::new(
))), Statement::Multiply(
(8, 13) Box::new(Node::new(
), Statement::Constant(Value::integer(2)),
))), (8, 9)
(4, 13) )),
), Box::new(Node::new(
))), Statement::Constant(Value::integer(3)),
(0, 13) (12, 13)
)]) )),
),
(8, 13),
)),
),
(4, 13),
)),
),
(0, 13),
)]
.into())
); );
} }
} }

View File

@ -1,74 +1,128 @@
use crate::{parse, Node, ParseError, Parser, Statement, Value, ValueError}; use std::collections::{HashMap, VecDeque};
pub fn run(input: &str) -> Result<Option<Value>, VmError> { use crate::{parse, Identifier, Node, ParseError, Span, Statement, Value, ValueError};
pub fn run(
input: &str,
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
let instructions = parse(input)?; let instructions = parse(input)?;
let vm = Vm::new(instructions); let mut vm = Vm::new(instructions);
vm.run() vm.run(variables)
} }
pub struct Vm { pub struct Vm {
instructions: Vec<Node>, statement_nodes: VecDeque<Node>,
} }
impl Vm { impl Vm {
pub fn new(instructions: Vec<Node>) -> Self { pub fn new(statement_nodes: VecDeque<Node>) -> Self {
Vm { instructions } Vm { statement_nodes }
} }
pub fn run(&self) -> Result<Option<Value>, VmError> { pub fn run(
&mut self,
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
let mut previous_value = None; let mut previous_value = None;
for instruction in &self.instructions { while let Some(node) = self.statement_nodes.pop_front() {
previous_value = self.run_instruction(instruction)?; previous_value = self.run_node(node, variables)?;
} }
Ok(previous_value) Ok(previous_value)
} }
fn run_instruction(&self, instruction: &Node) -> Result<Option<Value>, VmError> { fn run_node(
match &instruction.operation { &self,
Statement::Add(instructions) => { node: Node,
let left = if let Some(value) = self.run_instruction(&instructions.0)? { variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
match node.statement {
Statement::Add(left, right) => {
let left_span = left.span;
let left = if let Some(value) = self.run_node(*left, variables)? {
value value
} else { } else {
return Err(VmError::ExpectedValue(instructions.0.operation.clone())); return Err(VmError::ExpectedValue {
position: left_span,
});
}; };
let right = if let Some(value) = self.run_instruction(&instructions.1)? { let right_span = right.span;
let right = if let Some(value) = self.run_node(*right, variables)? {
value value
} else { } else {
return Err(VmError::ExpectedValue(instructions.1.operation.clone())); return Err(VmError::ExpectedValue {
position: right_span,
});
}; };
let sum = left.add(&right)?; let sum = left.add(&right)?;
Ok(Some(sum)) Ok(Some(sum))
} }
Statement::Assign(_) => todo!(), Statement::Assign(left, right) => {
let identifier = if let Statement::Identifier(identifier) = &left.statement {
identifier
} else {
return Err(VmError::ExpectedValue {
position: left.span,
});
};
let right_span = right.span;
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)
}
Statement::Constant(value) => Ok(Some(value.clone())), Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Identifier(_) => todo!(), Statement::Identifier(_) => Ok(None),
Statement::List(_) => todo!(), Statement::List(nodes) => {
Statement::Multiply(_) => todo!(), let values = nodes
.into_iter()
.map(|node| {
let span = node.span;
if let Some(value) = self.run_node(node, variables)? {
Ok(value)
} else {
Err(VmError::ExpectedValue { position: span })
}
})
.collect::<Result<Vec<Value>, VmError>>()?;
Ok(Some(Value::list(values)))
}
Statement::Multiply(_, _) => todo!(),
} }
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum VmError { pub enum VmError {
ExpectedValue(Statement),
InvalidOperation(Statement),
ParseError(ParseError), ParseError(ParseError),
ValueError(ValueError), ValueError(ValueError),
// Anaylsis Failures
// These should be prevented by running the analyzer before the VM
ExpectedValue { position: Span },
} }
impl From<ParseError> for VmError { impl From<ParseError> for VmError {
fn from(v: ParseError) -> Self { fn from(error: ParseError) -> Self {
Self::ParseError(v) Self::ParseError(error)
} }
} }
impl From<ValueError> for VmError { impl From<ValueError> for VmError {
fn from(v: ValueError) -> Self { fn from(error: ValueError) -> Self {
Self::ValueError(v) Self::ValueError(error)
} }
} }
@ -80,13 +134,13 @@ mod tests {
fn add() { fn add() {
let input = "1 + 2"; let input = "1 + 2";
assert_eq!(run(input), Ok(Some(Value::integer(3)))); assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
} }
#[test] #[test]
fn add_multiple() { fn add_multiple() {
let input = "(a + b = 1)"; let input = "1 + 2 + 3";
assert_eq!(run(input), Ok(Some(Value::integer(6)))); assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(6))));
} }
} }