1
0

Compare commits

...

3 Commits

Author SHA1 Message Date
2ae75dcdd0 Make meticulous changes to pratt parser 2024-08-10 00:01:50 -04:00
9ea203f419 Use context and replace old variable map 2024-08-09 21:12:36 -04:00
e1b04328d5 Add context 2024-08-09 20:52:13 -04:00
10 changed files with 347 additions and 247 deletions

View File

@ -1,12 +1,12 @@
//! In-memory representation of a Dust program. //! In-memory representation of a Dust program.
use std::{ use std::{
collections::{BTreeMap, HashMap, VecDeque}, collections::{BTreeMap, VecDeque},
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{BuiltInFunction, Identifier, Span, Type, Value}; use crate::{BuiltInFunction, Context, Identifier, Span, Type, Value};
/// In-memory representation of a Dust program. /// In-memory representation of a Dust program.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -75,18 +75,16 @@ pub enum Statement {
} }
impl Statement { impl Statement {
pub fn expected_type(&self, variables: &HashMap<Identifier, Value>) -> Option<Type> { pub fn expected_type(&self, context: &Context) -> Option<Type> {
match self { match self {
Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(variables), Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context),
Statement::BinaryOperation { left, .. } => left.inner.expected_type(variables), Statement::BinaryOperation { left, .. } => left.inner.expected_type(context),
Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(), Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(),
Statement::Constant(value) => Some(value.r#type(variables)), Statement::Constant(value) => Some(value.r#type(context)),
Statement::FunctionCall { function, .. } => function.inner.expected_type(variables), Statement::FunctionCall { function, .. } => function.inner.expected_type(context),
Statement::Identifier(identifier) => variables Statement::Identifier(identifier) => context.get_type(identifier).cloned(),
.get(identifier)
.map(|value| value.r#type(variables)),
Statement::List(nodes) => { Statement::List(nodes) => {
let item_type = nodes.first().unwrap().inner.expected_type(variables)?; let item_type = nodes.first().unwrap().inner.expected_type(context)?;
Some(Type::List { Some(Type::List {
length: nodes.len(), length: nodes.len(),
@ -98,7 +96,7 @@ impl Statement {
for (identifier, item) in nodes { for (identifier, item) in nodes {
if let Statement::Identifier(identifier) = &identifier.inner { if let Statement::Identifier(identifier) = &identifier.inner {
types.insert(identifier.clone(), item.inner.expected_type(variables)?); types.insert(identifier.clone(), item.inner.expected_type(context)?);
} }
} }

View File

@ -6,14 +6,13 @@
//! - `analyze` convenience function //! - `analyze` convenience function
//! - `Analyzer` struct //! - `Analyzer` struct
use std::{ use std::{
collections::HashMap,
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
}; };
use crate::{ use crate::{
abstract_tree::BinaryOperator, AbstractSyntaxTree, BuiltInFunction, Identifier, Node, Span, abstract_tree::BinaryOperator, AbstractSyntaxTree, BuiltInFunction, Context, Node, Span,
Statement, Type, Value, Statement, Type,
}; };
/// Analyzes the abstract syntax tree for errors. /// Analyzes the abstract syntax tree for errors.
@ -31,9 +30,9 @@ use crate::{
/// ``` /// ```
pub fn analyze( pub fn analyze(
abstract_tree: &AbstractSyntaxTree, abstract_tree: &AbstractSyntaxTree,
variables: &HashMap<Identifier, Value>, context: &mut Context,
) -> Result<(), AnalyzerError> { ) -> Result<(), AnalyzerError> {
let analyzer = Analyzer::new(abstract_tree, variables); let mut analyzer = Analyzer::new(abstract_tree, context);
analyzer.analyze() analyzer.analyze()
} }
@ -53,21 +52,18 @@ pub fn analyze(
/// assert!(result.is_err()); /// assert!(result.is_err());
pub struct Analyzer<'a> { pub struct Analyzer<'a> {
abstract_tree: &'a AbstractSyntaxTree, abstract_tree: &'a AbstractSyntaxTree,
variables: &'a HashMap<Identifier, Value>, context: &'a mut Context,
} }
impl<'a> Analyzer<'a> { impl<'a> Analyzer<'a> {
pub fn new( pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: &'a mut Context) -> Self {
abstract_tree: &'a AbstractSyntaxTree,
variables: &'a HashMap<Identifier, Value>,
) -> Self {
Self { Self {
abstract_tree, abstract_tree,
variables, context,
} }
} }
pub fn analyze(&self) -> Result<(), AnalyzerError> { pub fn analyze(&mut self) -> Result<(), AnalyzerError> {
for node in &self.abstract_tree.nodes { for node in &self.abstract_tree.nodes {
self.analyze_node(node)?; self.analyze_node(node)?;
} }
@ -75,17 +71,27 @@ impl<'a> Analyzer<'a> {
Ok(()) Ok(())
} }
fn analyze_node(&self, node: &Node<Statement>) -> Result<(), AnalyzerError> { fn analyze_node(&mut self, node: &Node<Statement>) -> Result<(), AnalyzerError> {
match &node.inner { match &node.inner {
Statement::BinaryOperation { Statement::BinaryOperation {
left, left,
operator, operator,
right, right,
} => { } => {
if let BinaryOperator::AddAssign | BinaryOperator::Assign = operator.inner { if let BinaryOperator::Assign = operator.inner {
if let Statement::Identifier(_) = left.inner { if let Statement::Identifier(identifier) = &left.inner {
self.analyze_node(right)?; self.analyze_node(right)?;
let right_type = right.inner.expected_type(self.context);
self.context.set_type(
identifier.clone(),
right_type.ok_or(AnalyzerError::ExpectedValue {
actual: right.as_ref().clone(),
position: right.position,
})?,
);
return Ok(()); return Ok(());
} }
} }
@ -93,8 +99,8 @@ impl<'a> Analyzer<'a> {
self.analyze_node(left)?; self.analyze_node(left)?;
self.analyze_node(right)?; self.analyze_node(right)?;
let left_type = left.inner.expected_type(self.variables); let left_type = left.inner.expected_type(self.context);
let right_type = right.inner.expected_type(self.variables); let right_type = right.inner.expected_type(self.context);
if let BinaryOperator::Add if let BinaryOperator::Add
| BinaryOperator::Subtract | BinaryOperator::Subtract
@ -154,7 +160,7 @@ impl<'a> Analyzer<'a> {
} }
} }
Statement::Identifier(identifier) => { Statement::Identifier(identifier) => {
if !self.variables.contains_key(identifier) { if !self.context.contains(identifier) {
return Err(AnalyzerError::UndefinedVariable { return Err(AnalyzerError::UndefinedVariable {
identifier: node.clone(), identifier: node.clone(),
}); });
@ -184,7 +190,7 @@ impl<'a> Analyzer<'a> {
if let Statement::BuiltInFunctionCall { function, .. } = &right.inner { if let Statement::BuiltInFunctionCall { function, .. } = &right.inner {
if function == &BuiltInFunction::IsEven || function == &BuiltInFunction::IsOdd { if function == &BuiltInFunction::IsEven || function == &BuiltInFunction::IsOdd {
if let Some(Type::Integer) = left.inner.expected_type(self.variables) { if let Some(Type::Integer) = left.inner.expected_type(self.context) {
} else { } else {
return Err(AnalyzerError::ExpectedIntegerOrFloat { return Err(AnalyzerError::ExpectedIntegerOrFloat {
actual: left.as_ref().clone(), actual: left.as_ref().clone(),
@ -348,8 +354,8 @@ mod tests {
)] )]
.into(), .into(),
}; };
let variables = HashMap::new(); let mut context = Context::new();
let analyzer = Analyzer::new(&abstract_tree, &variables); let mut analyzer = Analyzer::new(&abstract_tree, &mut context);
assert_eq!( assert_eq!(
analyzer.analyze(), analyzer.analyze(),
@ -373,8 +379,8 @@ mod tests {
)] )]
.into(), .into(),
}; };
let variables = HashMap::new(); let mut context = Context::new();
let analyzer = Analyzer::new(&abstract_tree, &variables); let mut analyzer = Analyzer::new(&abstract_tree, &mut context);
assert_eq!( assert_eq!(
analyzer.analyze(), analyzer.analyze(),
@ -404,8 +410,8 @@ mod tests {
)] )]
.into(), .into(),
}; };
let variables = HashMap::new(); let mut context = Context::new();
let analyzer = Analyzer::new(&abstract_tree, &variables); let mut analyzer = Analyzer::new(&abstract_tree, &mut context);
assert_eq!( assert_eq!(
analyzer.analyze(), analyzer.analyze(),
@ -434,8 +440,8 @@ mod tests {
)] )]
.into(), .into(),
}; };
let variables = HashMap::new(); let mut context = Context::new();
let analyzer = Analyzer::new(&abstract_tree, &variables); let mut analyzer = Analyzer::new(&abstract_tree, &mut context);
assert_eq!( assert_eq!(
analyzer.analyze(), analyzer.analyze(),
@ -455,8 +461,8 @@ mod tests {
)] )]
.into(), .into(),
}; };
let variables = HashMap::new(); let mut context = Context::new();
let analyzer = Analyzer::new(&abstract_tree, &variables); let mut analyzer = Analyzer::new(&abstract_tree, &mut context);
assert_eq!( assert_eq!(
analyzer.analyze(), analyzer.analyze(),

84
dust-lang/src/context.rs Normal file
View File

@ -0,0 +1,84 @@
//! Garbage-collecting context for variables.
use std::collections::HashMap;
use crate::{Identifier, Type, Value};
/// Garbage-collecting context for variables.
#[derive(Debug, Clone)]
pub struct Context {
pub variables: HashMap<Identifier, (VariableData, UsageData)>,
}
impl Context {
pub fn new() -> Self {
Self {
variables: HashMap::new(),
}
}
pub fn contains(&self, identifier: &Identifier) -> bool {
self.variables.contains_key(identifier)
}
pub fn get(&self, identifier: &Identifier) -> Option<&(VariableData, UsageData)> {
self.variables.get(identifier)
}
pub fn get_type(&self, identifier: &Identifier) -> Option<&Type> {
match self.variables.get(identifier) {
Some((VariableData::Type(r#type), _)) => Some(r#type),
_ => None,
}
}
pub fn get_value(&self, identifier: &Identifier) -> Option<&Value> {
match self.variables.get(identifier) {
Some((VariableData::Value(value), _)) => Some(value),
_ => None,
}
}
pub fn get_variable_data(&self, identifier: &Identifier) -> Option<&VariableData> {
match self.variables.get(identifier) {
Some((variable_data, _)) => Some(variable_data),
_ => None,
}
}
pub fn set_type(&mut self, identifier: Identifier, r#type: Type) {
self.variables.insert(
identifier,
(VariableData::Type(r#type), UsageData::default()),
);
}
pub fn set_value(&mut self, identifier: Identifier, value: Value) {
self.variables.insert(
identifier,
(VariableData::Value(value), UsageData::default()),
);
}
pub fn collect_garbage(&mut self) {
self.variables
.retain(|_, (_, usage_data)| usage_data.used < usage_data.allowed_uses);
}
}
impl Default for Context {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub enum VariableData {
Value(Value),
Type(Type),
}
#[derive(Default, Debug, Clone)]
pub struct UsageData {
pub allowed_uses: u16,
pub used: u16,
}

View File

@ -228,7 +228,10 @@ impl Lexer {
} else { } else {
self.position += 1; self.position += 1;
return Err(LexError::UnexpectedCharacter(c)); return Err(LexError::UnexpectedCharacter {
character: c,
position: self.position,
});
} }
} }
';' => { ';' => {
@ -244,13 +247,19 @@ impl Lexer {
} else { } else {
self.position += 1; self.position += 1;
return Err(LexError::UnexpectedCharacter(c)); return Err(LexError::UnexpectedCharacter {
character: c,
position: self.position,
});
} }
} }
_ => { _ => {
self.position += 1; self.position += 1;
return Err(LexError::UnexpectedCharacter(c)); return Err(LexError::UnexpectedCharacter {
character: c,
position: self.position,
});
} }
} }
} else { } else {
@ -433,13 +442,21 @@ impl Default for Lexer {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum LexError { pub enum LexError {
UnexpectedCharacter(char), UnexpectedCharacter { character: char, position: usize },
}
impl LexError {
pub fn position(&self) -> Span {
match self {
Self::UnexpectedCharacter { position, .. } => (*position, *position),
}
}
} }
impl Error for LexError { impl Error for LexError {
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
match self { match self {
Self::UnexpectedCharacter(_) => None, Self::UnexpectedCharacter { .. } => None,
} }
} }
} }
@ -447,7 +464,7 @@ impl Error for LexError {
impl Display for LexError { impl Display for LexError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::UnexpectedCharacter(character) => { Self::UnexpectedCharacter { character, .. } => {
write!(f, "Unexpected character: '{}'", character) write!(f, "Unexpected character: '{}'", character)
} }
} }

View File

@ -4,6 +4,7 @@
pub mod abstract_tree; pub mod abstract_tree;
pub mod analyzer; pub mod analyzer;
pub mod built_in_function; pub mod built_in_function;
pub mod context;
pub mod dust_error; pub mod dust_error;
pub mod identifier; pub mod identifier;
pub mod lex; pub mod lex;
@ -13,15 +14,16 @@ pub mod r#type;
pub mod value; pub mod value;
pub mod vm; pub mod vm;
pub use abstract_tree::{AbstractSyntaxTree, Node, Statement}; pub use abstract_tree::{AbstractSyntaxTree, BinaryOperator, Node, Statement};
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
pub use context::{Context, UsageData, VariableData};
pub use dust_error::DustError; pub use dust_error::DustError;
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, TokenOwned};
pub use value::{Value, ValueError}; pub use value::{Value, ValueError};
pub use vm::{run, Vm, VmError}; pub use vm::{run, Vm, VmError};

View File

@ -12,8 +12,8 @@ use std::{
}; };
use crate::{ use crate::{
abstract_tree::BinaryOperator, built_in_function::BuiltInFunction, token::TokenOwned, AbstractSyntaxTree, BinaryOperator, BuiltInFunction, Identifier, LexError, Lexer, Node, Span,
AbstractSyntaxTree, Identifier, LexError, Lexer, Node, Span, Statement, Token, Value, Statement, Token, TokenOwned, Value,
}; };
/// Parses the input into an abstract syntax tree. /// Parses the input into an abstract syntax tree.
@ -121,44 +121,32 @@ impl<'src> Parser<'src> {
} }
} }
pub fn parse(&mut self) -> Result<Node<Statement>, ParseError> {
self.parse_node(0)
}
pub fn current(&self) -> &(Token, Span) { pub fn current(&self) -> &(Token, Span) {
&self.current &self.current
} }
pub fn parse(&mut self) -> Result<Node<Statement>, ParseError> {
self.parse_statement(0)
}
fn next_token(&mut self) -> Result<(), ParseError> { fn next_token(&mut self) -> Result<(), ParseError> {
let next = self.lexer.next_token(self.source); self.current = self.lexer.next_token(self.source)?;
self.current = match next {
Ok((token, position)) => (token, position),
Err(lex_error) => {
let position = {
self.next_token()?;
self.current.1
};
return Err(ParseError::LexError {
error: lex_error,
position,
});
}
};
Ok(()) Ok(())
} }
fn parse_node(&mut self, precedence: u8) -> Result<Node<Statement>, ParseError> { fn parse_statement(&mut self, precedence: u8) -> Result<Node<Statement>, ParseError> {
let left = self.parse_primary()?; let mut left = self.parse_primary()?;
if precedence < self.current_precedence() { while precedence < self.current.0.precedence() {
self.parse_infix(left) if self.current.0.is_postfix() {
} else { left = self.parse_postfix(left)?;
Ok(left) } else {
left = self.parse_infix(left)?;
}
} }
Ok(left)
} }
fn parse_primary(&mut self) -> Result<Node<Statement>, ParseError> { fn parse_primary(&mut self) -> Result<Node<Statement>, ParseError> {
@ -241,7 +229,7 @@ impl<'src> Parser<'src> {
)); ));
} }
let next_node = self.parse_node(0)?; let next_node = self.parse_statement(0)?;
// If the next node is an assignment, this might be a map // If the next node is an assignment, this might be a map
if let Statement::BinaryOperation { if let Statement::BinaryOperation {
@ -264,20 +252,20 @@ impl<'src> Parser<'src> {
if let Statement::Map(map_properties) = if let Statement::Map(map_properties) =
statement.get_or_insert_with(|| Statement::Map(Vec::new())) statement.get_or_insert_with(|| Statement::Map(Vec::new()))
{ {
// Ignore commas after properties
if let Token::Comma = self.current.0 {
self.next_token()?;
}
// Add the new property to the map // Add the new property to the map
map_properties.push((*left, *right)); map_properties.push((*left, *right));
} }
// Ignore commas after properties
if let Token::Comma = self.current.0 {
self.next_token()?;
}
} }
// Otherwise, the new statement is a block // Otherwise, the new statement is a block
} else if let Statement::Block(statements) = } else if let Statement::Block(statements) =
statement.get_or_insert_with(|| Statement::Block(Vec::new())) statement.get_or_insert_with(|| Statement::Block(Vec::new()))
{ {
// Add the assignment statement to the block // Add the statement to the block
statements.push(next_node); statements.push(next_node);
} }
} }
@ -285,7 +273,7 @@ impl<'src> Parser<'src> {
(Token::LeftParenthesis, left_position) => { (Token::LeftParenthesis, left_position) => {
self.next_token()?; self.next_token()?;
let node = self.parse_node(0)?; let node = self.parse_statement(0)?;
if let (Token::RightParenthesis, right_position) = self.current { if let (Token::RightParenthesis, right_position) = self.current {
self.next_token()?; self.next_token()?;
@ -320,7 +308,7 @@ impl<'src> Parser<'src> {
continue; continue;
} }
if let Ok(instruction) = self.parse_node(0) { if let Ok(instruction) = self.parse_statement(0) {
nodes.push(instruction); nodes.push(instruction);
} else { } else {
return Err(ParseError::ExpectedToken { return Err(ParseError::ExpectedToken {
@ -369,7 +357,7 @@ impl<'src> Parser<'src> {
continue; continue;
} }
if let Ok(node) = self.parse_node(0) { if let Ok(node) = self.parse_statement(0) {
if let Some(ref mut arguments) = value_arguments { if let Some(ref mut arguments) = value_arguments {
arguments.push(node); arguments.push(node);
} else { } else {
@ -403,59 +391,51 @@ impl<'src> Parser<'src> {
fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> { fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
let left_start = left.position.0; let left_start = left.position.0;
// Postfix operations if let Token::Dot = &self.current.0 {
if let Token::Semicolon = &self.current.0 {
self.next_token()?; self.next_token()?;
let right_end = self.current.1 .1; let right = self.parse_statement(Token::Dot.precedence() + 1)?;
let right_end = right.position.1;
return Ok(Node::new( return Ok(Node::new(
Statement::Nil(Box::new(left)), Statement::PropertyAccess(Box::new(left), Box::new(right)),
(left_start, right_end), (left_start, right_end),
)); ));
}; }
// Infix operations let binary_operator = match &self.current.0 {
let binary_operator = match &self.current { Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1),
(Token::Dot, _) => { Token::DoubleEqual => Node::new(BinaryOperator::Equal, self.current.1),
self.next_token()?; Token::DoublePipe => Node::new(BinaryOperator::Or, self.current.1),
Token::Equal => Node::new(BinaryOperator::Assign, self.current.1),
let right = self.parse_node(0)?; Token::Greater => Node::new(BinaryOperator::Greater, self.current.1),
let right_end = right.position.1; Token::GreaterEqual => Node::new(BinaryOperator::GreaterOrEqual, self.current.1),
Token::Less => Node::new(BinaryOperator::Less, self.current.1),
return Ok(Node::new( Token::LessEqual => Node::new(BinaryOperator::LessOrEqual, self.current.1),
Statement::PropertyAccess(Box::new(left), Box::new(right)), Token::Minus => Node::new(BinaryOperator::Subtract, self.current.1),
(left_start, right_end), Token::Plus => Node::new(BinaryOperator::Add, self.current.1),
)); Token::PlusEqual => Node::new(BinaryOperator::AddAssign, self.current.1),
} Token::Star => Node::new(BinaryOperator::Multiply, self.current.1),
(Token::DoubleAmpersand, _) => Node::new(BinaryOperator::And, self.current.1), Token::Slash => Node::new(BinaryOperator::Divide, self.current.1),
(Token::DoubleEqual, _) => Node::new(BinaryOperator::Equal, self.current.1), Token::Percent => Node::new(BinaryOperator::Modulo, self.current.1),
(Token::DoublePipe, _) => Node::new(BinaryOperator::Or, self.current.1),
(Token::Equal, _) => Node::new(BinaryOperator::Assign, self.current.1),
(Token::Greater, _) => Node::new(BinaryOperator::Greater, self.current.1),
(Token::GreaterEqual, _) => Node::new(BinaryOperator::GreaterOrEqual, self.current.1),
(Token::Less, _) => Node::new(BinaryOperator::Less, self.current.1),
(Token::LessEqual, _) => Node::new(BinaryOperator::LessOrEqual, self.current.1),
(Token::Minus, _) => Node::new(BinaryOperator::Subtract, self.current.1),
(Token::Plus, _) => Node::new(BinaryOperator::Add, self.current.1),
(Token::PlusEqual, _) => Node::new(BinaryOperator::AddAssign, self.current.1),
(Token::Star, _) => Node::new(BinaryOperator::Multiply, self.current.1),
(Token::Slash, _) => Node::new(BinaryOperator::Divide, self.current.1),
(Token::Percent, _) => Node::new(BinaryOperator::Modulo, self.current.1),
_ => { _ => {
self.next_token()?;
return Err(ParseError::UnexpectedToken { return Err(ParseError::UnexpectedToken {
actual: self.current.0.to_owned(), actual: self.current.0.to_owned(),
position: self.current.1, position: self.current.1,
}); });
} }
}; };
let operator_precedence = self.current.0.precedence()
- if self.current.0.is_right_associative() {
1
} else {
0
};
self.next_token()?; self.next_token()?;
let left_start = left.position.0; let left_start = left.position.0;
let right = self.parse_node(0)?; let right = self.parse_statement(operator_precedence)?;
let right_end = right.position.1; let right_end = right.position.1;
Ok(Node::new( Ok(Node::new(
@ -468,33 +448,21 @@ impl<'src> Parser<'src> {
)) ))
} }
fn current_precedence(&self) -> u8 { fn parse_postfix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
match self.current.0 { if let Token::Semicolon = &self.current.0 {
Token::Semicolon => 10, self.next_token()?;
Token::Equal | Token::PlusEqual => 8,
Token::DoubleEqual => 7, let left_start = left.position.0;
Token::DoubleAmpersand | Token::DoublePipe => 6, let operator_end = self.current.1 .1;
Token::Greater | Token::GreaterEqual | Token::Less | Token::LessEqual => 5,
Token::Dot => 4, Ok(Node::new(
Token::Percent => 3, Statement::Nil(Box::new(left)),
Token::Star => 2, (left_start, operator_end),
Token::Slash => 2, ))
Token::Plus => 1, } else {
Token::Minus => 1, Ok(left)
_ => 0,
} }
} }
fn peek_token(&mut self) -> Token {
self.lexer
.peek_token(self.source)
.map(|(token, _)| token)
.unwrap_or(Token::Eof)
}
fn next_is_postfix(&mut self) -> bool {
matches!(self.peek_token(), Token::Semicolon)
}
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -503,10 +471,7 @@ pub enum ParseError {
error: ParseBoolError, error: ParseBoolError,
position: Span, position: Span,
}, },
LexError { LexError(LexError),
error: LexError,
position: Span,
},
ExpectedIdentifier { ExpectedIdentifier {
actual: TokenOwned, actual: TokenOwned,
position: Span, position: Span,
@ -530,6 +495,12 @@ pub enum ParseError {
}, },
} }
impl From<LexError> for ParseError {
fn from(v: LexError) -> Self {
Self::LexError(v)
}
}
impl ParseError { impl ParseError {
pub fn position(&self) -> Span { pub fn position(&self) -> Span {
match self { match self {
@ -538,7 +509,7 @@ impl ParseError {
ParseError::ExpectedToken { position, .. } => *position, ParseError::ExpectedToken { position, .. } => *position,
ParseError::FloatError { position, .. } => *position, ParseError::FloatError { position, .. } => *position,
ParseError::IntegerError { position, .. } => *position, ParseError::IntegerError { position, .. } => *position,
ParseError::LexError { position, .. } => *position, ParseError::LexError(error) => error.position(),
ParseError::UnexpectedToken { position, .. } => *position, ParseError::UnexpectedToken { position, .. } => *position,
} }
} }
@ -547,7 +518,7 @@ impl ParseError {
impl Error for ParseError { impl Error for ParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
match self { match self {
Self::LexError { error, .. } => Some(error), Self::LexError(error) => Some(error),
_ => None, _ => None,
} }
} }
@ -565,7 +536,7 @@ impl Display for ParseError {
} => write!(f, "Expected token {expected}, found {actual}"), } => write!(f, "Expected token {expected}, found {actual}"),
Self::FloatError { error, .. } => write!(f, "{}", error), Self::FloatError { error, .. } => write!(f, "{}", error),
Self::IntegerError { error, .. } => write!(f, "{}", error), Self::IntegerError { error, .. } => write!(f, "{}", error),
Self::LexError { error, .. } => write!(f, "{}", error), Self::LexError(error) => write!(f, "{}", error),
Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"), Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"),
} }
} }

View File

@ -127,6 +127,40 @@ impl<'src> Token<'src> {
Token::WriteLine => "write_line", Token::WriteLine => "write_line",
} }
} }
pub fn is_eof(&self) -> bool {
matches!(self, Token::Eof)
}
pub fn precedence(&self) -> u8 {
match self {
Token::Equal | Token::PlusEqual => 8,
Token::Semicolon => 7,
Token::DoubleAmpersand | Token::DoublePipe => 6,
Token::Greater
| Token::GreaterEqual
| Token::Less
| Token::LessEqual
| Token::DoubleEqual => 5,
Token::Dot => 4,
Token::Percent => 3,
Token::Star | Token::Slash => 2,
Token::Plus | Token::Minus => 1,
_ => 0,
}
}
pub fn is_left_associative(&self) -> bool {
!self.is_right_associative()
}
pub fn is_right_associative(&self) -> bool {
matches!(self, Token::Semicolon)
}
pub fn is_postfix(&self) -> bool {
matches!(self, Token::Semicolon)
}
} }
impl<'src> Display for Token<'src> { impl<'src> Display for Token<'src> {

View File

@ -1,7 +1,7 @@
//! Dust value representation //! Dust value representation
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{BTreeMap, HashMap}, collections::BTreeMap,
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ops::Range, ops::Range,
@ -14,7 +14,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Deserialize, Deserializer, Serialize,
}; };
use crate::{identifier::Identifier, AbstractSyntaxTree, Type, Vm, VmError}; use crate::{identifier::Identifier, AbstractSyntaxTree, Context, Type, Vm, VmError};
/// Dust value representation /// Dust value representation
/// ///
@ -89,8 +89,8 @@ impl Value {
Value(Arc::new(ValueInner::String(to_string.to_string()))) Value(Arc::new(ValueInner::String(to_string.to_string())))
} }
pub fn r#type(&self, variables: &HashMap<Identifier, Value>) -> Type { pub fn r#type(&self, context: &Context) -> Type {
self.0.r#type(variables) self.0.r#type(context)
} }
pub fn as_boolean(&self) -> Option<bool> { pub fn as_boolean(&self) -> Option<bool> {
@ -626,18 +626,18 @@ pub enum ValueInner {
} }
impl ValueInner { impl ValueInner {
pub fn r#type(&self, variables: &HashMap<Identifier, Value>) -> Type { pub fn r#type(&self, context: &Context) -> Type {
match self { match self {
ValueInner::Boolean(_) => Type::Boolean, ValueInner::Boolean(_) => Type::Boolean,
ValueInner::Float(_) => Type::Float, ValueInner::Float(_) => Type::Float,
ValueInner::Function(function) => Type::Function { ValueInner::Function(function) => Type::Function {
type_parameters: function.type_parameters.clone(), type_parameters: function.type_parameters.clone(),
value_parameters: function.value_parameters.clone(), value_parameters: function.value_parameters.clone(),
return_type: function.return_type(variables).map(Box::new), return_type: function.return_type(context).map(Box::new),
}, },
ValueInner::Integer(_) => Type::Integer, ValueInner::Integer(_) => Type::Integer,
ValueInner::List(values) => { ValueInner::List(values) => {
let item_type = values.first().unwrap().r#type(variables); let item_type = values.first().unwrap().r#type(context);
Type::List { Type::List {
length: values.len(), length: values.len(),
@ -648,7 +648,7 @@ impl ValueInner {
let mut type_map = BTreeMap::new(); let mut type_map = BTreeMap::new();
for (identifier, value) in value_map { for (identifier, value) in value_map {
let r#type = value.r#type(variables); let r#type = value.r#type(context);
type_map.insert(identifier.clone(), r#type); type_map.insert(identifier.clone(), r#type);
} }
@ -715,24 +715,24 @@ impl Function {
self, self,
_type_arguments: Option<Vec<Type>>, _type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>, value_arguments: Option<Vec<Value>>,
variables: &HashMap<Identifier, Value>, context: &mut Context,
) -> Result<Option<Value>, VmError> { ) -> Result<Option<Value>, VmError> {
let mut new_variables = variables.clone(); let mut new_context = context.clone();
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)
{ {
for ((identifier, _), value) in value_parameters.into_iter().zip(value_arguments) { for ((identifier, _), value) in value_parameters.into_iter().zip(value_arguments) {
new_variables.insert(identifier, value); new_context.set_value(identifier, value);
} }
} }
let mut vm = Vm::new(self.body); let mut vm = Vm::new(self.body);
vm.run(&mut new_variables) vm.run(&mut new_context)
} }
pub fn return_type(&self, variables: &HashMap<Identifier, Value>) -> Option<Type> { pub fn return_type(&self, variables: &Context) -> Option<Type> {
self.body self.body
.nodes .nodes
.iter() .iter()

View File

@ -1,27 +1,24 @@
//! Virtual machine for running the abstract syntax tree. //! Virtual machine for running the abstract syntax tree.
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::BTreeMap,
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
}; };
use crate::{ use crate::{
abstract_tree::BinaryOperator, parse, AbstractSyntaxTree, Analyzer, AnalyzerError, abstract_tree::BinaryOperator, parse, AbstractSyntaxTree, Analyzer, AnalyzerError,
BuiltInFunctionError, Identifier, Node, ParseError, Span, Statement, Value, ValueError, BuiltInFunctionError, Context, Node, ParseError, Span, Statement, Value, ValueError,
}; };
pub fn run( pub fn run(input: &str, context: &mut Context) -> Result<Option<Value>, VmError> {
input: &str,
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
let abstract_syntax_tree = parse(input)?; let abstract_syntax_tree = parse(input)?;
let analyzer = Analyzer::new(&abstract_syntax_tree, variables); let mut analyzer = Analyzer::new(&abstract_syntax_tree, context);
analyzer.analyze()?; analyzer.analyze()?;
let mut vm = Vm::new(abstract_syntax_tree); let mut vm = Vm::new(abstract_syntax_tree);
vm.run(variables) vm.run(context)
} }
pub struct Vm { pub struct Vm {
@ -33,14 +30,11 @@ impl Vm {
Self { abstract_tree } Self { abstract_tree }
} }
pub fn run( pub fn run(&mut self, context: &mut Context) -> Result<Option<Value>, VmError> {
&mut self,
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
let mut previous_value = None; let mut previous_value = None;
while let Some(node) = self.abstract_tree.nodes.pop_front() { while let Some(node) = self.abstract_tree.nodes.pop_front() {
previous_value = self.run_node(node, variables)?; previous_value = self.run_node(node, context)?;
} }
Ok(previous_value) Ok(previous_value)
@ -49,7 +43,7 @@ impl Vm {
fn run_node( fn run_node(
&self, &self,
node: Node<Statement>, node: Node<Statement>,
variables: &mut HashMap<Identifier, Value>, context: &mut Context,
) -> Result<Option<Value>, VmError> { ) -> Result<Option<Value>, VmError> {
match node.inner { match node.inner {
Statement::BinaryOperation { Statement::BinaryOperation {
@ -68,7 +62,7 @@ impl Vm {
}); });
}; };
let value = if let Some(value) = self.run_node(*right, variables)? { let value = if let Some(value) = self.run_node(*right, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
@ -76,9 +70,9 @@ impl Vm {
}); });
}; };
variables.insert(identifier, value.clone()); context.set_value(identifier, value);
return Ok(Some(value)); return Ok(None);
} }
if let BinaryOperator::AddAssign = operator.inner { if let BinaryOperator::AddAssign = operator.inner {
@ -89,25 +83,21 @@ impl Vm {
position: left.position, position: left.position,
}); });
}; };
let right_value = if let Some(value) = self.run_node(*right, context)? {
let right_value = if let Some(value) = self.run_node(*right, variables)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
position: right_position, position: right_position,
}); });
}; };
let left_value = context.get_value(&identifier).ok_or_else(|| {
let left_value = VmError::UndefinedVariable {
variables identifier: Node::new(
.get(&identifier) Statement::Identifier(identifier.clone()),
.ok_or_else(|| VmError::UndefinedVariable { left.position,
identifier: Node::new( ),
Statement::Identifier(identifier.clone()), }
left.position, })?;
),
})?;
let new_value = left_value.add(&right_value).map_err(|value_error| { let new_value = left_value.add(&right_value).map_err(|value_error| {
VmError::ValueError { VmError::ValueError {
error: value_error, error: value_error,
@ -115,21 +105,20 @@ impl Vm {
} }
})?; })?;
variables.insert(identifier, new_value.clone()); context.set_value(identifier, new_value);
return Ok(Some(new_value)); return Ok(None);
} }
let left_position = left.position; let left_position = left.position;
let left_value = if let Some(value) = self.run_node(*left, variables)? { let left_value = if let Some(value) = self.run_node(*left, context)? {
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_node(*right, context)? {
let right_value = if let Some(value) = self.run_node(*right, variables)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
@ -164,7 +153,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_node(statement, variables)?; previous_value = self.run_node(statement, context)?;
} }
Ok(previous_value) Ok(previous_value)
@ -179,7 +168,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_node(node, variables)? { let value = if let Some(value) = self.run_node(node, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -209,14 +198,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_node(*function_node, context)? {
if let Some(value) = self.run_node(*function_node, variables)? { 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 {
@ -231,7 +219,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_node(node, variables)? { let value = if let Some(value) = self.run_node(node, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -245,10 +233,10 @@ impl Vm {
None None
}; };
Ok(function.clone().call(None, value_parameters, variables)?) Ok(function.clone().call(None, value_parameters, context)?)
} }
Statement::Identifier(identifier) => { Statement::Identifier(identifier) => {
if let Some(value) = variables.get(&identifier) { if let Some(value) = context.get_value(&identifier) {
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else { } else {
Err(VmError::UndefinedVariable { Err(VmError::UndefinedVariable {
@ -261,7 +249,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_node(node, variables)? { if let Some(value) = self.run_node(node, context)? {
Ok(value) Ok(value)
} else { } else {
Err(VmError::ExpectedValue { position: span }) Err(VmError::ExpectedValue { position: span })
@ -283,7 +271,7 @@ impl Vm {
}); });
}; };
let position = value_node.position; let position = value_node.position;
let value = if let Some(value) = self.run_node(value_node, variables)? { let value = if let Some(value) = self.run_node(value_node, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -295,13 +283,13 @@ impl Vm {
Ok(Some(Value::map(values))) Ok(Some(Value::map(values)))
} }
Statement::Nil(node) => { Statement::Nil(node) => {
let _return = self.run_node(*node, variables)?; let _return = self.run_node(*node, context)?;
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_node(*left, variables)? { let left_value = if let Some(value) = self.run_node(*left, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
@ -336,7 +324,7 @@ impl Vm {
if let Some(value_nodes) = value_argument_nodes { if let Some(value_nodes) = value_argument_nodes {
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_node(node, variables)? { let value = if let Some(value) = self.run_node(node, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -495,7 +483,7 @@ mod tests {
fn add_assign() { fn add_assign() {
let input = "x = 1; x += 1; x"; let input = "x = 1; x += 1; x";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(2))));
} }
#[test] #[test]
@ -503,7 +491,7 @@ mod tests {
let input = "true || false"; let input = "true || false";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -513,7 +501,7 @@ mod tests {
let input = "{ y = 'foo', } == { y = 'foo', }"; let input = "{ y = 'foo', } == { y = 'foo', }";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -523,7 +511,7 @@ mod tests {
let input = "42 == 42"; let input = "42 == 42";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -532,7 +520,7 @@ mod tests {
fn modulo() { fn modulo() {
let input = "42 % 2"; let input = "42 % 2";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(0)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(0))));
} }
#[test] #[test]
@ -540,7 +528,7 @@ mod tests {
let input = "42 / 2"; let input = "42 / 2";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::integer(21))) Ok(Some(Value::integer(21)))
); );
} }
@ -550,7 +538,7 @@ mod tests {
let input = "2 < 3"; let input = "2 < 3";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -560,7 +548,7 @@ mod tests {
let input = "42 <= 42"; let input = "42 <= 42";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -570,7 +558,7 @@ mod tests {
let input = "2 > 3"; let input = "2 > 3";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(false))) Ok(Some(Value::boolean(false)))
); );
} }
@ -580,7 +568,7 @@ mod tests {
let input = "42 >= 42"; let input = "42 >= 42";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -590,7 +578,7 @@ mod tests {
let input = "9223372036854775807 + 1"; let input = "9223372036854775807 + 1";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::integer(i64::MAX))) Ok(Some(Value::integer(i64::MAX)))
); );
} }
@ -600,7 +588,7 @@ mod tests {
let input = "-9223372036854775808 - 1"; let input = "-9223372036854775808 - 1";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::integer(i64::MIN))) Ok(Some(Value::integer(i64::MIN)))
); );
} }
@ -609,7 +597,7 @@ mod tests {
fn multiply() { fn multiply() {
let input = "2 * 3"; let input = "2 * 3";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(6)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(6))));
} }
#[test] #[test]
@ -617,7 +605,7 @@ mod tests {
let input = "true"; let input = "true";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -627,7 +615,7 @@ mod tests {
let input = "42.is_even()"; let input = "42.is_even()";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(true))) Ok(Some(Value::boolean(true)))
); );
} }
@ -637,7 +625,7 @@ mod tests {
let input = "42.is_odd()"; let input = "42.is_odd()";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut Context::new()),
Ok(Some(Value::boolean(false))) Ok(Some(Value::boolean(false)))
); );
} }
@ -646,27 +634,27 @@ mod tests {
fn length() { fn length() {
let input = "[1, 2, 3].length()"; let input = "[1, 2, 3].length()";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(3))));
} }
#[test] #[test]
fn list_access() { fn list_access() {
let input = "[1, 2, 3].1"; let input = "[1, 2, 3].1";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(2))));
} }
#[test] #[test]
fn add() { fn add() {
let input = "1 + 2"; let input = "1 + 2";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(3))));
} }
#[test] #[test]
fn add_multiple() { fn add_multiple() {
let input = "1 + 2 + 3"; let input = "1 + 2 + 3";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(6)))); assert_eq!(run(input, &mut Context::new()), Ok(Some(Value::integer(6))));
} }
} }

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, fs::read_to_string}; use std::fs::read_to_string;
use clap::Parser; use clap::Parser;
use dust_lang::{run, DustError, Identifier, Value}; use dust_lang::{run, Context, DustError};
#[derive(Parser)] #[derive(Parser)]
struct Cli { struct Cli {
@ -13,20 +13,20 @@ struct Cli {
fn main() { fn main() {
let args = Cli::parse(); let args = Cli::parse();
let mut variables = HashMap::new(); let mut context = Context::new();
if let Some(command) = &args.command { if let Some(command) = &args.command {
run_and_display_errors(command, &mut variables); run_and_display_errors(command, &mut context);
} else if let Some(path) = &args.path { } else if let Some(path) = &args.path {
let source = read_to_string(path).expect("Failed to read file"); let source = read_to_string(path).expect("Failed to read file");
run_and_display_errors(&source, &mut variables) run_and_display_errors(&source, &mut context)
} else { } else {
panic!("No command or path provided"); panic!("No command or path provided");
}; };
} }
fn run_and_display_errors(source: &str, variables: &mut HashMap<Identifier, Value>) { fn run_and_display_errors(source: &str, variables: &mut Context) {
match run(source, variables) { match run(source, variables) {
Ok(return_value) => { Ok(return_value) => {
if let Some(value) = return_value { if let Some(value) = return_value {