Refactor to move assingment out of other binary operations
This commit is contained in:
parent
b1337900fb
commit
5757f52dbd
@ -34,6 +34,12 @@ impl<T: Display> Display for Node<T> {
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Statement {
|
||||
Assignment {
|
||||
identifier: Node<Identifier>,
|
||||
operator: Node<AssignmentOperator>,
|
||||
value: Box<Node<Statement>>,
|
||||
},
|
||||
|
||||
// A sequence of statements
|
||||
Block(Vec<Node<Statement>>),
|
||||
|
||||
@ -99,7 +105,7 @@ pub enum Statement {
|
||||
|
||||
// Value collection expressions
|
||||
List(Vec<Node<Statement>>),
|
||||
Map(Vec<(Node<Statement>, Node<Statement>)>),
|
||||
Map(Vec<(Node<Identifier>, Node<Statement>)>),
|
||||
|
||||
// Hard-coded value
|
||||
Constant(Value),
|
||||
@ -112,6 +118,7 @@ pub enum Statement {
|
||||
impl Statement {
|
||||
pub fn expected_type(&self, context: &Context) -> Option<Type> {
|
||||
match self {
|
||||
Statement::Assignment { .. } => None,
|
||||
Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context),
|
||||
Statement::BinaryOperation {
|
||||
left,
|
||||
@ -132,8 +139,6 @@ impl Statement {
|
||||
| BinaryOperator::And
|
||||
| BinaryOperator::Or => Some(Type::Boolean),
|
||||
|
||||
BinaryOperator::Assign | BinaryOperator::AddAssign => None,
|
||||
|
||||
BinaryOperator::FieldAccess => {
|
||||
let left_type = left.inner.expected_type(context)?;
|
||||
|
||||
@ -180,9 +185,7 @@ impl Statement {
|
||||
let mut types = BTreeMap::new();
|
||||
|
||||
for (identifier, item) in nodes {
|
||||
if let Statement::Identifier(identifier) = &identifier.inner {
|
||||
types.insert(identifier.clone(), item.inner.expected_type(context)?);
|
||||
}
|
||||
types.insert(identifier.inner.clone(), item.inner.expected_type(context)?);
|
||||
}
|
||||
|
||||
Some(Type::Map(types))
|
||||
@ -215,7 +218,7 @@ impl Statement {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node<Statement>, Node<Statement>)>> {
|
||||
pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node<Identifier>, Node<Statement>)>> {
|
||||
match self {
|
||||
Statement::Map(properties) => Some(properties),
|
||||
_ => None,
|
||||
@ -226,6 +229,13 @@ impl Statement {
|
||||
impl Display for Statement {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Statement::Assignment {
|
||||
identifier,
|
||||
operator,
|
||||
value,
|
||||
} => {
|
||||
write!(f, "{identifier} {operator} {value}")
|
||||
}
|
||||
Statement::Block(statements) => {
|
||||
write!(f, "{{ ")?;
|
||||
|
||||
@ -248,8 +258,6 @@ impl Display for Statement {
|
||||
BinaryOperator::FieldAccess => return write!(f, "{left}.{right}"),
|
||||
BinaryOperator::ListIndex => return write!(f, "{left}[{right}]"),
|
||||
BinaryOperator::Add => "+",
|
||||
BinaryOperator::AddAssign => "+=",
|
||||
BinaryOperator::Assign => "=",
|
||||
BinaryOperator::Divide => "/",
|
||||
BinaryOperator::Equal => "==",
|
||||
BinaryOperator::Greater => ">",
|
||||
@ -422,6 +430,25 @@ impl Display for Statement {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum AssignmentOperator {
|
||||
Assign,
|
||||
AddAssign,
|
||||
SubtractAssign,
|
||||
}
|
||||
|
||||
impl Display for AssignmentOperator {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let operator = match self {
|
||||
AssignmentOperator::Assign => "=",
|
||||
AssignmentOperator::AddAssign => "+=",
|
||||
AssignmentOperator::SubtractAssign => "-=",
|
||||
};
|
||||
|
||||
write!(f, "{operator}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum BinaryOperator {
|
||||
// Accessors
|
||||
@ -445,10 +472,6 @@ pub enum BinaryOperator {
|
||||
// Logic
|
||||
And,
|
||||
Or,
|
||||
|
||||
// Assignment
|
||||
Assign,
|
||||
AddAssign,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
|
@ -75,28 +75,29 @@ impl<'a> Analyzer<'a> {
|
||||
|
||||
fn analyze_statement(&mut self, node: &Node<Statement>) -> Result<(), AnalyzerError> {
|
||||
match &node.inner {
|
||||
Statement::Assignment {
|
||||
identifier, value, ..
|
||||
} => {
|
||||
self.analyze_statement(value)?;
|
||||
|
||||
let value_type = value.inner.expected_type(self.context);
|
||||
|
||||
if let Some(r#type) = value_type {
|
||||
self.context
|
||||
.set_type(identifier.inner.clone(), r#type, identifier.position);
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedValue {
|
||||
actual: value.as_ref().clone(),
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
Statement::BinaryOperation {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => {
|
||||
if let BinaryOperator::Assign | BinaryOperator::AddAssign = operator.inner {
|
||||
self.analyze_statement(right)?;
|
||||
|
||||
if let Statement::Identifier(identifier) = &left.inner {
|
||||
let right_type = right.inner.expected_type(self.context).ok_or(
|
||||
AnalyzerError::ExpectedValue {
|
||||
actual: right.as_ref().clone(),
|
||||
},
|
||||
)?;
|
||||
|
||||
self.context
|
||||
.set_type(identifier.clone(), right_type, left.position);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
if let BinaryOperator::FieldAccess = operator.inner {
|
||||
self.analyze_statement(left)?;
|
||||
|
||||
@ -738,7 +739,7 @@ mod tests {
|
||||
identifier: Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)),
|
||||
statement: Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)),
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(Statement::Constant(Value::integer(1)), (6, 7))
|
||||
)]),
|
||||
(0, 9)
|
||||
@ -760,7 +761,7 @@ mod tests {
|
||||
identifier: Node::new(Statement::Constant(Value::string("y")), (10, 13)),
|
||||
statement: Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)),
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(Statement::Constant(Value::integer(1)), (6, 7))
|
||||
)]),
|
||||
(0, 9)
|
||||
|
@ -15,8 +15,8 @@ pub mod value;
|
||||
pub mod vm;
|
||||
|
||||
pub use abstract_tree::{
|
||||
AbstractSyntaxTree, BinaryOperator, Node, Statement, StructDefinition, StructInstantiation,
|
||||
UnaryOperator,
|
||||
AbstractSyntaxTree, AssignmentOperator, BinaryOperator, Node, Statement, StructDefinition,
|
||||
StructInstantiation, UnaryOperator,
|
||||
};
|
||||
pub use analyzer::{analyze, Analyzer, AnalyzerError};
|
||||
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
||||
|
@ -12,9 +12,9 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
AbstractSyntaxTree, BinaryOperator, BuiltInFunction, DustError, Identifier, LexError, Lexer,
|
||||
Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, UnaryOperator,
|
||||
Value,
|
||||
AbstractSyntaxTree, AssignmentOperator, BinaryOperator, BuiltInFunction, DustError, Identifier,
|
||||
LexError, Lexer, Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type,
|
||||
UnaryOperator, Value,
|
||||
};
|
||||
|
||||
/// Parses the input into an abstract syntax tree.
|
||||
@ -22,7 +22,7 @@ use crate::{
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use dust_lang::*;
|
||||
/// let tree = parse("x = 42").unwrap();
|
||||
/// let tree = parse("x + 42").unwrap();
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// tree,
|
||||
@ -35,7 +35,7 @@ use crate::{
|
||||
/// (0, 1),
|
||||
/// )),
|
||||
/// operator: Node::new(
|
||||
/// BinaryOperator::Assign,
|
||||
/// BinaryOperator::Add,
|
||||
/// (2, 3)
|
||||
/// ),
|
||||
/// right: Box::new(Node::new(
|
||||
@ -93,28 +93,8 @@ pub fn parse(source: &str) -> Result<AbstractSyntaxTree, DustError> {
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// nodes,
|
||||
/// Into::<VecDeque<Node<Statement>>>::into([
|
||||
/// Node::new(
|
||||
/// Statement::BinaryOperation {
|
||||
/// left: Box::new(Node::new(
|
||||
/// Statement::Identifier(Identifier::new("x")),
|
||||
/// (0, 1),
|
||||
/// )),
|
||||
/// operator: Node::new(
|
||||
/// BinaryOperator::Assign,
|
||||
/// (2, 3),
|
||||
/// ),
|
||||
/// right: Box::new(Node::new(
|
||||
/// Statement::Constant(Value::integer(42)),
|
||||
/// (4, 6),
|
||||
/// )),
|
||||
/// },
|
||||
/// (0, 6),
|
||||
/// )
|
||||
/// ]),
|
||||
/// );
|
||||
/// let tree = AbstractSyntaxTree { nodes };
|
||||
///
|
||||
/// ```
|
||||
pub struct Parser<'src> {
|
||||
source: &'src str,
|
||||
@ -382,14 +362,14 @@ impl<'src> Parser<'src> {
|
||||
// Determine whether the new statement is a block or a map
|
||||
//
|
||||
// If the first node is an assignment, this might be a map
|
||||
let mut statement = if let Statement::BinaryOperation {
|
||||
left,
|
||||
let mut statement = if let Statement::Assignment {
|
||||
identifier: left,
|
||||
operator:
|
||||
Node {
|
||||
inner: BinaryOperator::Assign,
|
||||
..
|
||||
inner: AssignmentOperator::Assign,
|
||||
position: operator_position,
|
||||
},
|
||||
right,
|
||||
value: right,
|
||||
} = first_node.inner
|
||||
{
|
||||
// If the current token is a comma or closing brace
|
||||
@ -400,14 +380,14 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
|
||||
// The new statement is a map
|
||||
Statement::Map(vec![(*left, *right)])
|
||||
Statement::Map(vec![(left, *right)])
|
||||
} else {
|
||||
// Otherwise, the new statement is a block
|
||||
Statement::Block(vec![Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left,
|
||||
operator: Node::new(BinaryOperator::Assign, (0, 0)),
|
||||
right,
|
||||
Statement::Assignment {
|
||||
identifier: left,
|
||||
operator: Node::new(AssignmentOperator::Assign, operator_position),
|
||||
value: right,
|
||||
},
|
||||
first_node.position,
|
||||
)])
|
||||
@ -437,18 +417,18 @@ impl<'src> Parser<'src> {
|
||||
// If the new statement is already a map
|
||||
if let Some(map_properties) = statement.map_properties_mut() {
|
||||
// Expect the next node to be an assignment
|
||||
if let Statement::BinaryOperation {
|
||||
left,
|
||||
if let Statement::Assignment {
|
||||
identifier,
|
||||
operator:
|
||||
Node {
|
||||
inner: BinaryOperator::Assign,
|
||||
inner: AssignmentOperator::Assign,
|
||||
..
|
||||
},
|
||||
right,
|
||||
value,
|
||||
} = next_node.inner
|
||||
{
|
||||
// Add the new property to the map
|
||||
map_properties.push((*left, *right));
|
||||
map_properties.push((identifier, *value));
|
||||
|
||||
// Allow commas after properties
|
||||
if let Token::Comma = self.current.0 {
|
||||
@ -654,6 +634,39 @@ impl<'src> Parser<'src> {
|
||||
};
|
||||
let left_start = left.position.0;
|
||||
|
||||
if let Token::Equal | Token::PlusEqual | Token::MinusEqual = &self.current.0 {
|
||||
let operator_position = self.current.1;
|
||||
let operator = match self.current.0 {
|
||||
Token::Equal => AssignmentOperator::Assign,
|
||||
Token::PlusEqual => AssignmentOperator::AddAssign,
|
||||
Token::MinusEqual => AssignmentOperator::SubtractAssign,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let identifier = if let Statement::Identifier(identifier) = left.inner {
|
||||
Node::new(identifier, left.position)
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Identifier,
|
||||
actual: self.current.0.to_owned(),
|
||||
position: self.current.1,
|
||||
});
|
||||
};
|
||||
let right = self.parse_statement(operator_precedence)?;
|
||||
let right_end = right.position.1;
|
||||
|
||||
return Ok(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier,
|
||||
operator: Node::new(operator, operator_position),
|
||||
value: Box::new(right),
|
||||
},
|
||||
(left_start, right_end),
|
||||
));
|
||||
}
|
||||
|
||||
if let Token::Dot = &self.current.0 {
|
||||
let operator_position = self.current.1;
|
||||
|
||||
@ -724,14 +737,12 @@ impl<'src> Parser<'src> {
|
||||
Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1),
|
||||
Token::DoubleEqual => Node::new(BinaryOperator::Equal, 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),
|
||||
@ -1168,16 +1179,10 @@ mod tests {
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(
|
||||
Statement::Identifier(Identifier::new("x")),
|
||||
(2, 3)
|
||||
),
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(
|
||||
Statement::Identifier(Identifier::new("y")),
|
||||
(8, 9)
|
||||
),
|
||||
Node::new(Identifier::new("y"), (8, 9)),
|
||||
Node::new(
|
||||
Statement::Constant(Value::integer(42)),
|
||||
(12, 14)
|
||||
@ -1231,13 +1236,10 @@ mod tests {
|
||||
nodes: [
|
||||
Node::new(
|
||||
Statement::Nil(Box::new(Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("a")),
|
||||
(0, 1)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (2, 3)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (2, 3)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::integer(1)),
|
||||
(4, 5)
|
||||
)),
|
||||
@ -1336,13 +1338,10 @@ mod tests {
|
||||
nodes: [
|
||||
Node::new(
|
||||
Statement::Nil(Box::new(Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("a")),
|
||||
(0, 1)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (2, 3)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (2, 3)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::boolean(false)),
|
||||
(4, 9)
|
||||
)),
|
||||
@ -1486,13 +1485,10 @@ mod tests {
|
||||
parse_error: ParseError::ExpectedAssignment {
|
||||
actual: Node::new(
|
||||
Statement::Nil(Box::new(Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("z")),
|
||||
(16, 17)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (18, 19)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("z"), (16, 17)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (18, 19)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::integer(3)),
|
||||
(20, 21)
|
||||
)),
|
||||
@ -1531,13 +1527,10 @@ mod tests {
|
||||
)),
|
||||
body: Box::new(Node::new(
|
||||
Statement::Block(vec![Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("x")),
|
||||
(15, 16)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::AddAssign, (17, 19)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("x"), (15, 16)),
|
||||
operator: Node::new(AssignmentOperator::AddAssign, (17, 19)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::integer(1)),
|
||||
(20, 21)
|
||||
)),
|
||||
@ -1562,13 +1555,10 @@ mod tests {
|
||||
parse(input),
|
||||
Ok(AbstractSyntaxTree {
|
||||
nodes: [Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("a")),
|
||||
(0, 1)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::AddAssign, (2, 4)),
|
||||
right: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))),
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
||||
operator: Node::new(AssignmentOperator::AddAssign, (2, 4)),
|
||||
value: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))),
|
||||
},
|
||||
(0, 6)
|
||||
)]
|
||||
@ -1659,13 +1649,10 @@ mod tests {
|
||||
Statement::Block(vec![
|
||||
Node::new(
|
||||
Statement::Nil(Box::new(Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("foo")),
|
||||
(2, 5)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (6, 7)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("foo"), (2, 5)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (6, 7)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::integer(42)),
|
||||
(8, 10)
|
||||
)),
|
||||
@ -1676,13 +1663,10 @@ mod tests {
|
||||
),
|
||||
Node::new(
|
||||
Statement::Nil(Box::new(Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("bar")),
|
||||
(12, 15)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (16, 17)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("bar"), (12, 15)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (16, 17)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::integer(42)),
|
||||
(18, 20)
|
||||
)),
|
||||
@ -1692,13 +1676,10 @@ mod tests {
|
||||
(12, 21)
|
||||
),
|
||||
Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("baz")),
|
||||
(22, 25)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (26, 27)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("baz"), (22, 25)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (26, 27)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::Constant(Value::string("42")),
|
||||
(28, 32)
|
||||
)),
|
||||
@ -1735,15 +1716,15 @@ mod tests {
|
||||
nodes: [Node::new(
|
||||
Statement::Map(vec![
|
||||
(
|
||||
Node::new(Statement::Identifier(Identifier::new("foo")), (2, 5)),
|
||||
Node::new(Identifier::new("foo"), (2, 5)),
|
||||
Node::new(Statement::Constant(Value::integer(42)), (8, 10))
|
||||
),
|
||||
(
|
||||
Node::new(Statement::Identifier(Identifier::new("bar")), (12, 15)),
|
||||
Node::new(Identifier::new("bar"), (12, 15)),
|
||||
Node::new(Statement::Constant(Value::integer(42)), (18, 20))
|
||||
),
|
||||
(
|
||||
Node::new(Statement::Identifier(Identifier::new("baz")), (22, 25)),
|
||||
Node::new(Identifier::new("baz"), (22, 25)),
|
||||
Node::new(Statement::Constant(Value::string("42")), (28, 32))
|
||||
),
|
||||
]),
|
||||
@ -1764,11 +1745,11 @@ mod tests {
|
||||
nodes: [Node::new(
|
||||
Statement::Map(vec![
|
||||
(
|
||||
Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)),
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(Statement::Constant(Value::integer(42)), (6, 8))
|
||||
),
|
||||
(
|
||||
Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)),
|
||||
Node::new(Identifier::new("y"), (10, 11)),
|
||||
Node::new(Statement::Constant(Value::string("foobar")), (14, 22))
|
||||
)
|
||||
]),
|
||||
@ -1788,7 +1769,7 @@ mod tests {
|
||||
Ok(AbstractSyntaxTree {
|
||||
nodes: [Node::new(
|
||||
Statement::Map(vec![(
|
||||
Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)),
|
||||
Node::new(Identifier::new("x"), (2, 3)),
|
||||
Node::new(Statement::Constant(Value::integer(42)), (6, 8))
|
||||
)]),
|
||||
(0, 10)
|
||||
@ -2271,13 +2252,10 @@ mod tests {
|
||||
parse(input),
|
||||
Ok(AbstractSyntaxTree {
|
||||
nodes: [Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Identifier(Identifier::new("a")),
|
||||
(0, 1)
|
||||
)),
|
||||
operator: Node::new(BinaryOperator::Assign, (2, 3)),
|
||||
right: Box::new(Node::new(
|
||||
Statement::Assignment {
|
||||
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
||||
operator: Node::new(AssignmentOperator::Assign, (2, 3)),
|
||||
value: Box::new(Node::new(
|
||||
Statement::BinaryOperation {
|
||||
left: Box::new(Node::new(
|
||||
Statement::Constant(Value::integer(1)),
|
||||
|
@ -50,6 +50,7 @@ pub enum Token<'src> {
|
||||
Less,
|
||||
LessEqual,
|
||||
Minus,
|
||||
MinusEqual,
|
||||
Percent,
|
||||
Plus,
|
||||
PlusEqual,
|
||||
@ -94,6 +95,7 @@ impl<'src> Token<'src> {
|
||||
Token::Less => TokenOwned::Less,
|
||||
Token::LessEqual => TokenOwned::LessOrEqual,
|
||||
Token::Minus => TokenOwned::Minus,
|
||||
Token::MinusEqual => TokenOwned::MinusEqual,
|
||||
Token::Percent => TokenOwned::Percent,
|
||||
Token::Plus => TokenOwned::Plus,
|
||||
Token::PlusEqual => TokenOwned::PlusEqual,
|
||||
@ -147,6 +149,7 @@ impl<'src> Token<'src> {
|
||||
Token::Less => "<",
|
||||
Token::LessEqual => "<=",
|
||||
Token::Minus => "-",
|
||||
Token::MinusEqual => "-=",
|
||||
Token::Percent => "%",
|
||||
Token::Plus => "+",
|
||||
Token::PlusEqual => "+=",
|
||||
@ -197,6 +200,7 @@ impl<'src> Token<'src> {
|
||||
Token::Less => TokenKind::Less,
|
||||
Token::LessEqual => TokenKind::LessOrEqual,
|
||||
Token::Minus => TokenKind::Minus,
|
||||
Token::MinusEqual => TokenKind::MinusEqual,
|
||||
Token::Percent => TokenKind::Percent,
|
||||
Token::Plus => TokenKind::Plus,
|
||||
Token::PlusEqual => TokenKind::PlusEqual,
|
||||
@ -322,6 +326,7 @@ pub enum TokenOwned {
|
||||
Less,
|
||||
LessOrEqual,
|
||||
Minus,
|
||||
MinusEqual,
|
||||
Percent,
|
||||
Plus,
|
||||
PlusEqual,
|
||||
@ -367,6 +372,7 @@ impl Display for TokenOwned {
|
||||
TokenOwned::Less => Token::Less.fmt(f),
|
||||
TokenOwned::LessOrEqual => Token::LessEqual.fmt(f),
|
||||
TokenOwned::Minus => Token::Minus.fmt(f),
|
||||
TokenOwned::MinusEqual => Token::MinusEqual.fmt(f),
|
||||
TokenOwned::Percent => Token::Percent.fmt(f),
|
||||
TokenOwned::Plus => Token::Plus.fmt(f),
|
||||
TokenOwned::PlusEqual => Token::PlusEqual.fmt(f),
|
||||
@ -433,6 +439,7 @@ pub enum TokenKind {
|
||||
Less,
|
||||
LessOrEqual,
|
||||
Minus,
|
||||
MinusEqual,
|
||||
Percent,
|
||||
Plus,
|
||||
PlusEqual,
|
||||
@ -478,6 +485,7 @@ impl Display for TokenKind {
|
||||
TokenKind::Less => Token::Less.fmt(f),
|
||||
TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
|
||||
TokenKind::Minus => Token::Minus.fmt(f),
|
||||
TokenKind::MinusEqual => Token::MinusEqual.fmt(f),
|
||||
TokenKind::Percent => Token::Percent.fmt(f),
|
||||
TokenKind::Plus => Token::Plus.fmt(f),
|
||||
TokenKind::PlusEqual => Token::PlusEqual.fmt(f),
|
||||
|
@ -10,9 +10,10 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError,
|
||||
Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructDefinition,
|
||||
StructInstantiation, StructType, Type, UnaryOperator, Value, ValueError,
|
||||
parse, value::ValueInner, AbstractSyntaxTree, Analyzer, AssignmentOperator, BinaryOperator,
|
||||
BuiltInFunctionError, Context, DustError, Identifier, Node, ParseError, Span, Statement,
|
||||
Struct, StructDefinition, StructInstantiation, StructType, Type, UnaryOperator, Value,
|
||||
ValueError,
|
||||
};
|
||||
|
||||
/// Run the source code and return the result.
|
||||
@ -96,6 +97,53 @@ impl Vm {
|
||||
|
||||
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
|
||||
match node.inner {
|
||||
Statement::Assignment {
|
||||
identifier,
|
||||
operator,
|
||||
value,
|
||||
} => match operator.inner {
|
||||
AssignmentOperator::Assign => {
|
||||
let position = value.position;
|
||||
let value = if let Some(value) = self.run_statement(*value)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
self.context.set_value(identifier.inner, value);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
AssignmentOperator::AddAssign => {
|
||||
let left_value = if let Some(value) = self.context.get_value(&identifier.inner)
|
||||
{
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::UndefinedVariable { identifier });
|
||||
};
|
||||
let value_position = value.position;
|
||||
let right_value = if let Some(value) = self.run_statement(*value)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: value_position,
|
||||
});
|
||||
};
|
||||
let new_value = left_value.add(&right_value).map_err(|value_error| {
|
||||
VmError::ValueError {
|
||||
error: value_error,
|
||||
position: (identifier.position.0, value_position.1),
|
||||
}
|
||||
})?;
|
||||
|
||||
self.context.set_value(identifier.inner, new_value);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
AssignmentOperator::SubtractAssign => {
|
||||
todo!()
|
||||
}
|
||||
},
|
||||
Statement::BinaryOperation {
|
||||
left,
|
||||
operator,
|
||||
@ -103,64 +151,6 @@ impl Vm {
|
||||
} => {
|
||||
let right_position = right.position;
|
||||
|
||||
if let BinaryOperator::Assign = operator.inner {
|
||||
let identifier = if let Statement::Identifier(identifier) = left.inner {
|
||||
identifier
|
||||
} else {
|
||||
return Err(VmError::ExpectedIdentifier {
|
||||
position: left.position,
|
||||
});
|
||||
};
|
||||
let value = if let Some(value) = self.run_statement(*right)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: right_position,
|
||||
});
|
||||
};
|
||||
|
||||
self.context.set_value(identifier, value);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if let BinaryOperator::AddAssign = operator.inner {
|
||||
let (identifier, left_value) =
|
||||
if let Statement::Identifier(identifier) = left.inner {
|
||||
let value = self.context.get_value(&identifier).ok_or_else(|| {
|
||||
VmError::UndefinedVariable {
|
||||
identifier: Node::new(
|
||||
Statement::Identifier(identifier.clone()),
|
||||
left.position,
|
||||
),
|
||||
}
|
||||
})?;
|
||||
|
||||
(identifier, value)
|
||||
} else {
|
||||
return Err(VmError::ExpectedIdentifier {
|
||||
position: left.position,
|
||||
});
|
||||
};
|
||||
let right_value = if let Some(value) = self.run_statement(*right)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: right_position,
|
||||
});
|
||||
};
|
||||
let new_value = left_value.add(&right_value).map_err(|value_error| {
|
||||
VmError::ValueError {
|
||||
error: value_error,
|
||||
position: right_position,
|
||||
}
|
||||
})?;
|
||||
|
||||
self.context.set_value(identifier, new_value);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if let BinaryOperator::FieldAccess = operator.inner {
|
||||
let left_span = left.position;
|
||||
let left_value = if let Some(value) = self.run_statement(*left)? {
|
||||
@ -416,7 +406,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
Err(VmError::UndefinedVariable {
|
||||
identifier: Node::new(Statement::Identifier(identifier), node.position),
|
||||
identifier: Node::new(identifier, node.position),
|
||||
})
|
||||
}
|
||||
Statement::If { condition, body } => {
|
||||
@ -586,13 +576,6 @@ impl Vm {
|
||||
let mut values = BTreeMap::new();
|
||||
|
||||
for (identifier, value_node) in nodes {
|
||||
let identifier = if let Statement::Identifier(identifier) = identifier.inner {
|
||||
identifier
|
||||
} else {
|
||||
return Err(VmError::ExpectedIdentifier {
|
||||
position: identifier.position,
|
||||
});
|
||||
};
|
||||
let position = value_node.position;
|
||||
let value = if let Some(value) = self.run_statement(value_node)? {
|
||||
value
|
||||
@ -600,7 +583,7 @@ impl Vm {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
};
|
||||
|
||||
values.insert(identifier, value);
|
||||
values.insert(identifier.inner, value);
|
||||
}
|
||||
|
||||
Ok(Some(Value::map(values)))
|
||||
@ -754,7 +737,7 @@ pub enum VmError {
|
||||
position: Span,
|
||||
},
|
||||
UndefinedVariable {
|
||||
identifier: Node<Statement>,
|
||||
identifier: Node<Identifier>,
|
||||
},
|
||||
UndefinedProperty {
|
||||
value: Value,
|
||||
|
Loading…
Reference in New Issue
Block a user