Refactor the abstract syntax tree
This commit is contained in:
parent
b9081f8653
commit
8c8fde94ce
@ -35,12 +35,17 @@ impl<T: Display> Display for Node<T> {
|
|||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
// Top-level statements
|
// Top-level statements
|
||||||
Assign(Box<Node<Statement>>, Box<Node<Statement>>),
|
Assignment {
|
||||||
|
identifier: Identifier,
|
||||||
|
value_node: Box<Node<Statement>>,
|
||||||
|
},
|
||||||
|
|
||||||
// Math expressions
|
// Logic, math and comparison expressions
|
||||||
Add(Box<Node<Statement>>, Box<Node<Statement>>),
|
BinaryOperation {
|
||||||
Subtract(Box<Node<Statement>>, Box<Node<Statement>>),
|
left: Box<Node<Statement>>,
|
||||||
Multiply(Box<Node<Statement>>, Box<Node<Statement>>),
|
operator: Node<BinaryOperator>,
|
||||||
|
right: Box<Node<Statement>>,
|
||||||
|
},
|
||||||
|
|
||||||
// Function calls
|
// Function calls
|
||||||
BuiltInFunctionCall {
|
BuiltInFunctionCall {
|
||||||
@ -54,31 +59,25 @@ pub enum Statement {
|
|||||||
value_arguments: Option<Vec<Node<Statement>>>,
|
value_arguments: Option<Vec<Node<Statement>>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Comparison expressions
|
// Property access expression
|
||||||
Comparison(
|
|
||||||
Box<Node<Statement>>,
|
|
||||||
Node<ComparisonOperator>,
|
|
||||||
Box<Node<Statement>>,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Property access
|
|
||||||
PropertyAccess(Box<Node<Statement>>, Box<Node<Statement>>),
|
PropertyAccess(Box<Node<Statement>>, Box<Node<Statement>>),
|
||||||
|
|
||||||
// Value collections
|
// Identifier expression
|
||||||
|
Identifier(Identifier),
|
||||||
|
|
||||||
|
// Value collection expressions
|
||||||
List(Vec<Node<Statement>>),
|
List(Vec<Node<Statement>>),
|
||||||
|
|
||||||
// Hard-coded values
|
// Hard-coded values
|
||||||
Constant(Value),
|
Constant(Value),
|
||||||
Identifier(Identifier),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn expected_type(&self, variables: &HashMap<Identifier, Value>) -> Option<Type> {
|
pub fn expected_type(&self, variables: &HashMap<Identifier, Value>) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Add(left, _) => left.inner.expected_type(variables),
|
Statement::Assignment { .. } => None,
|
||||||
Statement::Assign(_, _) => None,
|
Statement::BinaryOperation { left, .. } => left.inner.expected_type(variables),
|
||||||
Statement::BuiltInFunctionCall { function, .. } => function.expected_type(),
|
Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(),
|
||||||
Statement::Comparison(_, _, _) => Some(Type::Boolean),
|
|
||||||
Statement::Constant(value) => Some(value.r#type(variables)),
|
Statement::Constant(value) => Some(value.r#type(variables)),
|
||||||
Statement::FunctionCall { function, .. } => function.inner.expected_type(variables),
|
Statement::FunctionCall { function, .. } => function.inner.expected_type(variables),
|
||||||
Statement::Identifier(identifier) => variables
|
Statement::Identifier(identifier) => variables
|
||||||
@ -88,9 +87,7 @@ impl Statement {
|
|||||||
.first()
|
.first()
|
||||||
.map(|node| node.inner.expected_type(variables))
|
.map(|node| node.inner.expected_type(variables))
|
||||||
.flatten(),
|
.flatten(),
|
||||||
Statement::Multiply(left, _) => left.inner.expected_type(variables),
|
|
||||||
Statement::PropertyAccess(_, _) => None,
|
Statement::PropertyAccess(_, _) => None,
|
||||||
Statement::Subtract(left, _) => left.inner.expected_type(variables),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,8 +95,19 @@ impl Statement {
|
|||||||
impl Display for Statement {
|
impl Display for Statement {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assign(left, right) => write!(f, "{left} = {right}"),
|
Statement::Assignment {
|
||||||
Statement::Add(left, right) => write!(f, "{left} + {right}"),
|
identifier,
|
||||||
|
value_node: value,
|
||||||
|
} => {
|
||||||
|
write!(f, "{identifier} = {value}")
|
||||||
|
}
|
||||||
|
Statement::BinaryOperation {
|
||||||
|
left,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
} => {
|
||||||
|
write!(f, "{left} {operator} {right}")
|
||||||
|
}
|
||||||
Statement::BuiltInFunctionCall {
|
Statement::BuiltInFunctionCall {
|
||||||
function,
|
function,
|
||||||
type_arguments: type_parameters,
|
type_arguments: type_parameters,
|
||||||
@ -135,7 +143,6 @@ impl Display for Statement {
|
|||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
Statement::Comparison(left, operator, right) => write!(f, "{left} {operator} {right}"),
|
|
||||||
Statement::Constant(value) => write!(f, "{value}"),
|
Statement::Constant(value) => write!(f, "{value}"),
|
||||||
Statement::FunctionCall {
|
Statement::FunctionCall {
|
||||||
function,
|
function,
|
||||||
@ -183,28 +190,34 @@ impl Display for Statement {
|
|||||||
}
|
}
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
Statement::Multiply(left, right) => write!(f, "{left} * {right}"),
|
|
||||||
Statement::PropertyAccess(left, right) => write!(f, "{left}.{right}"),
|
Statement::PropertyAccess(left, right) => write!(f, "{left}.{right}"),
|
||||||
Statement::Subtract(left, right) => write!(f, "{left} - {right}"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum ComparisonOperator {
|
pub enum BinaryOperator {
|
||||||
GreaterThan,
|
Add,
|
||||||
GreaterThanOrEqual,
|
Divide,
|
||||||
LessThan,
|
Greater,
|
||||||
LessThanOrEqual,
|
GreaterOrEqual,
|
||||||
|
Less,
|
||||||
|
LessOrEqual,
|
||||||
|
Multiply,
|
||||||
|
Subtract,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ComparisonOperator {
|
impl Display for BinaryOperator {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ComparisonOperator::GreaterThan => write!(f, ">"),
|
BinaryOperator::Add => write!(f, "+"),
|
||||||
ComparisonOperator::GreaterThanOrEqual => write!(f, ">="),
|
BinaryOperator::Divide => write!(f, "/"),
|
||||||
ComparisonOperator::LessThan => write!(f, "<"),
|
BinaryOperator::Greater => write!(f, ">"),
|
||||||
ComparisonOperator::LessThanOrEqual => write!(f, "<="),
|
BinaryOperator::GreaterOrEqual => write!(f, ">="),
|
||||||
|
BinaryOperator::Less => write!(f, "<"),
|
||||||
|
BinaryOperator::LessOrEqual => write!(f, "<="),
|
||||||
|
BinaryOperator::Multiply => write!(f, "*"),
|
||||||
|
BinaryOperator::Subtract => write!(f, "-"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,10 @@ use std::{
|
|||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{AbstractSyntaxTree, BuiltInFunction, Identifier, Node, Span, Statement, Type, Value};
|
use crate::{
|
||||||
|
abstract_tree::BinaryOperator, AbstractSyntaxTree, BuiltInFunction, Identifier, Node, Span,
|
||||||
|
Statement, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
/// Analyzes the abstract syntax tree for errors.
|
/// Analyzes the abstract syntax tree for errors.
|
||||||
///
|
///
|
||||||
@ -74,68 +77,26 @@ impl<'a> Analyzer<'a> {
|
|||||||
|
|
||||||
fn analyze_node(&self, node: &Node<Statement>) -> Result<(), AnalyzerError> {
|
fn analyze_node(&self, node: &Node<Statement>) -> Result<(), AnalyzerError> {
|
||||||
match &node.inner {
|
match &node.inner {
|
||||||
Statement::Add(left, right) => {
|
Statement::Assignment {
|
||||||
|
identifier,
|
||||||
|
value_node: value,
|
||||||
|
} => {
|
||||||
|
if let None = value.inner.expected_type(self.variables) {
|
||||||
|
return Err(AnalyzerError::ExpectedValue {
|
||||||
|
actual: value.as_ref().clone(),
|
||||||
|
position: value.position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::BinaryOperation {
|
||||||
|
left,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
} => {
|
||||||
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 right_type = right.inner.expected_type(self.variables);
|
|
||||||
|
|
||||||
match (left_type, right_type) {
|
|
||||||
(Some(Type::Integer), Some(Type::Integer)) => {}
|
|
||||||
(Some(Type::Float), Some(Type::Float)) => {}
|
|
||||||
(Some(Type::String), Some(Type::String)) => {}
|
|
||||||
(Some(Type::Integer), _) | (Some(Type::Float), _) | (Some(Type::String), _) => {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerFloatOrString {
|
|
||||||
actual: right.as_ref().clone(),
|
|
||||||
position: right.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerFloatOrString {
|
|
||||||
actual: left.as_ref().clone(),
|
|
||||||
position: left.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Statement::Assign(left, right) => {
|
|
||||||
if let Statement::Identifier(_) = &left.inner {
|
|
||||||
// Identifier is in the correct position
|
|
||||||
} else {
|
|
||||||
return Err(AnalyzerError::ExpectedIdentifier {
|
|
||||||
actual: left.as_ref().clone(),
|
|
||||||
position: left.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.analyze_node(right)?;
|
|
||||||
}
|
}
|
||||||
Statement::BuiltInFunctionCall { .. } => {}
|
Statement::BuiltInFunctionCall { .. } => {}
|
||||||
Statement::Comparison(left, _, right) => {
|
|
||||||
self.analyze_node(left)?;
|
|
||||||
self.analyze_node(right)?;
|
|
||||||
|
|
||||||
if let Some(Type::Integer) | Some(Type::Float) =
|
|
||||||
left.inner.expected_type(self.variables)
|
|
||||||
{
|
|
||||||
} else {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerOrFloat {
|
|
||||||
actual: left.as_ref().clone(),
|
|
||||||
position: left.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Type::Integer) | Some(Type::Float) =
|
|
||||||
right.inner.expected_type(self.variables)
|
|
||||||
{
|
|
||||||
} else {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerOrFloat {
|
|
||||||
actual: right.as_ref().clone(),
|
|
||||||
position: right.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Statement::Constant(_) => {}
|
Statement::Constant(_) => {}
|
||||||
Statement::FunctionCall { function, .. } => {
|
Statement::FunctionCall { function, .. } => {
|
||||||
if let Statement::Identifier(_) = &function.inner {
|
if let Statement::Identifier(_) = &function.inner {
|
||||||
@ -158,37 +119,13 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_node(statement)?;
|
self.analyze_node(statement)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::Multiply(left, right) => {
|
|
||||||
self.analyze_node(left)?;
|
|
||||||
self.analyze_node(right)?;
|
|
||||||
|
|
||||||
if let Some(Type::Integer) | Some(Type::Float) =
|
|
||||||
left.inner.expected_type(self.variables)
|
|
||||||
{
|
|
||||||
} else {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerOrFloat {
|
|
||||||
actual: left.as_ref().clone(),
|
|
||||||
position: left.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Type::Integer) | Some(Type::Float) =
|
|
||||||
right.inner.expected_type(self.variables)
|
|
||||||
{
|
|
||||||
} else {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerOrFloat {
|
|
||||||
actual: right.as_ref().clone(),
|
|
||||||
position: right.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Statement::PropertyAccess(left, right) => {
|
Statement::PropertyAccess(left, right) => {
|
||||||
if let Statement::Identifier(_) | Statement::Constant(_) | Statement::List(_) =
|
if let Statement::Identifier(_) | Statement::Constant(_) | Statement::List(_) =
|
||||||
&left.inner
|
&left.inner
|
||||||
{
|
{
|
||||||
// Left side is valid
|
// Left side is valid
|
||||||
} else {
|
} else {
|
||||||
return Err(AnalyzerError::ExpectedIdentifierOrValue {
|
return Err(AnalyzerError::ExpectedValue {
|
||||||
actual: left.as_ref().clone(),
|
actual: left.as_ref().clone(),
|
||||||
position: left.position,
|
position: left.position,
|
||||||
});
|
});
|
||||||
@ -208,30 +145,6 @@ impl<'a> Analyzer<'a> {
|
|||||||
|
|
||||||
self.analyze_node(right)?;
|
self.analyze_node(right)?;
|
||||||
}
|
}
|
||||||
Statement::Subtract(left, right) => {
|
|
||||||
self.analyze_node(left)?;
|
|
||||||
self.analyze_node(right)?;
|
|
||||||
|
|
||||||
let left_type = left.inner.expected_type(self.variables);
|
|
||||||
let right_type = right.inner.expected_type(self.variables);
|
|
||||||
|
|
||||||
match (left_type, right_type) {
|
|
||||||
(Some(Type::Integer), Some(Type::Integer)) => {}
|
|
||||||
(Some(Type::Float), Some(Type::Float)) => {}
|
|
||||||
(Some(Type::Integer), _) | (Some(Type::Float), _) => {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerOrFloat {
|
|
||||||
actual: right.as_ref().clone(),
|
|
||||||
position: right.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(AnalyzerError::ExpectedIntegerOrFloat {
|
|
||||||
actual: left.as_ref().clone(),
|
|
||||||
position: left.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -244,6 +157,10 @@ pub enum AnalyzerError {
|
|||||||
actual: Node<Statement>,
|
actual: Node<Statement>,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
ExpectedFloat {
|
||||||
|
actual: Node<Statement>,
|
||||||
|
position: (usize, usize),
|
||||||
|
},
|
||||||
ExpectedFunction {
|
ExpectedFunction {
|
||||||
actual: Node<Statement>,
|
actual: Node<Statement>,
|
||||||
position: Span,
|
position: Span,
|
||||||
@ -252,7 +169,7 @@ pub enum AnalyzerError {
|
|||||||
actual: Node<Statement>,
|
actual: Node<Statement>,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ExpectedIdentifierOrValue {
|
ExpectedInteger {
|
||||||
actual: Node<Statement>,
|
actual: Node<Statement>,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
@ -264,22 +181,38 @@ pub enum AnalyzerError {
|
|||||||
actual: Node<Statement>,
|
actual: Node<Statement>,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
ExpectedString {
|
||||||
|
actual: Node<Statement>,
|
||||||
|
position: (usize, usize),
|
||||||
|
},
|
||||||
|
ExpectedValue {
|
||||||
|
actual: Node<Statement>,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
UnexpectedIdentifier {
|
UnexpectedIdentifier {
|
||||||
identifier: Node<Statement>,
|
identifier: Node<Statement>,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
UnexectedString {
|
||||||
|
actual: Node<Statement>,
|
||||||
|
position: (usize, usize),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnalyzerError {
|
impl AnalyzerError {
|
||||||
pub fn position(&self) -> Span {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
AnalyzerError::ExpectedBoolean { position, .. } => *position,
|
AnalyzerError::ExpectedBoolean { position, .. } => *position,
|
||||||
|
AnalyzerError::ExpectedFloat { position, .. } => *position,
|
||||||
AnalyzerError::ExpectedFunction { position, .. } => *position,
|
AnalyzerError::ExpectedFunction { position, .. } => *position,
|
||||||
AnalyzerError::ExpectedIdentifier { position, .. } => *position,
|
AnalyzerError::ExpectedIdentifier { position, .. } => *position,
|
||||||
AnalyzerError::ExpectedIdentifierOrValue { position, .. } => *position,
|
AnalyzerError::ExpectedValue { position, .. } => *position,
|
||||||
|
AnalyzerError::ExpectedInteger { position, .. } => *position,
|
||||||
AnalyzerError::ExpectedIntegerOrFloat { position, .. } => *position,
|
AnalyzerError::ExpectedIntegerOrFloat { position, .. } => *position,
|
||||||
AnalyzerError::ExpectedIntegerFloatOrString { position, .. } => *position,
|
AnalyzerError::ExpectedIntegerFloatOrString { position, .. } => *position,
|
||||||
|
AnalyzerError::ExpectedString { position, .. } => *position,
|
||||||
AnalyzerError::UnexpectedIdentifier { position, .. } => *position,
|
AnalyzerError::UnexpectedIdentifier { position, .. } => *position,
|
||||||
|
AnalyzerError::UnexectedString { position, .. } => *position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,11 +228,14 @@ impl Display for AnalyzerError {
|
|||||||
AnalyzerError::ExpectedFunction { actual, .. } => {
|
AnalyzerError::ExpectedFunction { actual, .. } => {
|
||||||
write!(f, "Expected function, found {}", actual)
|
write!(f, "Expected function, found {}", actual)
|
||||||
}
|
}
|
||||||
|
AnalyzerError::ExpectedFloat { actual, .. } => {
|
||||||
|
write!(f, "Expected float, found {}", actual)
|
||||||
|
}
|
||||||
AnalyzerError::ExpectedIdentifier { actual, .. } => {
|
AnalyzerError::ExpectedIdentifier { actual, .. } => {
|
||||||
write!(f, "Expected identifier, found {}", actual)
|
write!(f, "Expected identifier, found {}", actual)
|
||||||
}
|
}
|
||||||
AnalyzerError::ExpectedIdentifierOrValue { actual, .. } => {
|
AnalyzerError::ExpectedInteger { actual, .. } => {
|
||||||
write!(f, "Expected identifier or value, found {}", actual)
|
write!(f, "Expected integer, found {}", actual)
|
||||||
}
|
}
|
||||||
AnalyzerError::ExpectedIntegerOrFloat { actual, .. } => {
|
AnalyzerError::ExpectedIntegerOrFloat { actual, .. } => {
|
||||||
write!(f, "Expected integer or float, found {}", actual)
|
write!(f, "Expected integer or float, found {}", actual)
|
||||||
@ -307,9 +243,18 @@ impl Display for AnalyzerError {
|
|||||||
AnalyzerError::ExpectedIntegerFloatOrString { actual, .. } => {
|
AnalyzerError::ExpectedIntegerFloatOrString { actual, .. } => {
|
||||||
write!(f, "Expected integer, float, or string, found {}", actual)
|
write!(f, "Expected integer, float, or string, found {}", actual)
|
||||||
}
|
}
|
||||||
|
AnalyzerError::ExpectedString { actual, .. } => {
|
||||||
|
write!(f, "Expected string, found {}", actual)
|
||||||
|
}
|
||||||
|
AnalyzerError::ExpectedValue { actual, .. } => {
|
||||||
|
write!(f, "Expected value, found {}", actual)
|
||||||
|
}
|
||||||
AnalyzerError::UnexpectedIdentifier { identifier, .. } => {
|
AnalyzerError::UnexpectedIdentifier { identifier, .. } => {
|
||||||
write!(f, "Unexpected identifier {}", identifier)
|
write!(f, "Unexpected identifier {}", identifier)
|
||||||
}
|
}
|
||||||
|
AnalyzerError::UnexectedString { actual, .. } => {
|
||||||
|
write!(f, "Unexpected string {}", actual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,11 +269,12 @@ mod tests {
|
|||||||
fn add_expects_same_types() {
|
fn add_expects_same_types() {
|
||||||
let abstract_tree = AbstractSyntaxTree {
|
let abstract_tree = AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Add(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Box::new(Node::new(Statement::Constant(Value::float(1.0)), (1, 2))),
|
operator: Node::new(BinaryOperator::Add, (1, 2)),
|
||||||
),
|
right: Box::new(Node::new(Statement::Constant(Value::float(1.0)), (3, 4))),
|
||||||
(0, 2),
|
},
|
||||||
|
(0, 4),
|
||||||
)]
|
)]
|
||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
@ -348,10 +294,11 @@ mod tests {
|
|||||||
fn add_expects_integer_float_or_string() {
|
fn add_expects_integer_float_or_string() {
|
||||||
let abstract_tree = AbstractSyntaxTree {
|
let abstract_tree = AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Add(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::boolean(true)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (1, 2))),
|
operator: Node::new(BinaryOperator::Add, (1, 2)),
|
||||||
),
|
right: Box::new(Node::new(Statement::Constant(Value::boolean(true)), (3, 4))),
|
||||||
|
},
|
||||||
(0, 2),
|
(0, 2),
|
||||||
)]
|
)]
|
||||||
.into(),
|
.into(),
|
||||||
@ -433,13 +380,14 @@ mod tests {
|
|||||||
fn multiply_expect_integer_or_float() {
|
fn multiply_expect_integer_or_float() {
|
||||||
let abstract_tree = AbstractSyntaxTree {
|
let abstract_tree = AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Multiply(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Multiply, (1, 2)),
|
||||||
|
right: Box::new(Node::new(
|
||||||
Statement::Constant(Value::boolean(false)),
|
Statement::Constant(Value::boolean(false)),
|
||||||
(1, 2),
|
(3, 4),
|
||||||
)),
|
)),
|
||||||
),
|
},
|
||||||
(0, 2),
|
(0, 2),
|
||||||
)]
|
)]
|
||||||
.into(),
|
.into(),
|
||||||
@ -460,10 +408,10 @@ mod tests {
|
|||||||
fn assignment_expect_identifier() {
|
fn assignment_expect_identifier() {
|
||||||
let abstract_tree = AbstractSyntaxTree {
|
let abstract_tree = AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Assign(
|
Statement::Assignment {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
identifier: Identifier::new("x"),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (1, 2))),
|
value_node: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
),
|
},
|
||||||
(0, 2),
|
(0, 2),
|
||||||
)]
|
)]
|
||||||
.into(),
|
.into(),
|
||||||
|
@ -113,7 +113,7 @@ impl BuiltInFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expected_type(&self) -> Option<Type> {
|
pub fn expected_return_type(&self) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunction::IsEven => Some(Type::Boolean),
|
BuiltInFunction::IsEven => Some(Type::Boolean),
|
||||||
BuiltInFunction::IsOdd => Some(Type::Boolean),
|
BuiltInFunction::IsOdd => Some(Type::Boolean),
|
||||||
|
@ -20,15 +20,17 @@ pub struct Identifier(Arc<String>);
|
|||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
pub fn new<T: ToString>(text: T) -> Self {
|
pub fn new<T: ToString>(text: T) -> Self {
|
||||||
let cache = identifier_cache();
|
let cache = identifier_cache().read().unwrap();
|
||||||
|
|
||||||
let new = Identifier(Arc::new(text.to_string()));
|
let new = Identifier(Arc::new(text.to_string()));
|
||||||
|
|
||||||
if let Some(identifier) = cache.read().unwrap().get(&new).cloned() {
|
if cache.contains(&new) {
|
||||||
return identifier;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.write().unwrap().insert(new.clone());
|
drop(cache);
|
||||||
|
|
||||||
|
identifier_cache().write().unwrap().insert(new.clone());
|
||||||
|
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::ComparisonOperator, built_in_function::BuiltInFunction, token::TokenOwned,
|
abstract_tree::BinaryOperator, built_in_function::BuiltInFunction, token::TokenOwned,
|
||||||
AbstractSyntaxTree, Identifier, LexError, Lexer, Node, Span, Statement, Token, Value,
|
AbstractSyntaxTree, Identifier, LexError, Lexer, Node, Span, Statement, Token, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,16 +169,27 @@ impl<'src> Parser<'src> {
|
|||||||
(Token::Equal, _) => {
|
(Token::Equal, _) => {
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
|
let identifier = if let Statement::Identifier(identifier) = left_node.inner {
|
||||||
|
identifier
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::ExpectedIdentifier {
|
||||||
|
actual: left_node.inner,
|
||||||
|
position: left_node.position,
|
||||||
|
});
|
||||||
|
};
|
||||||
let right_node = self.parse_node(self.current_precedence())?;
|
let right_node = self.parse_node(self.current_precedence())?;
|
||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Assign(Box::new(left_node), Box::new(right_node)),
|
Statement::Assignment {
|
||||||
|
identifier,
|
||||||
|
value_node: Box::new(right_node),
|
||||||
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::Greater, _) => {
|
(Token::Greater, _) => {
|
||||||
let operator_position = self.current.1;
|
let operator = Node::new(BinaryOperator::Greater, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
@ -186,16 +197,16 @@ impl<'src> Parser<'src> {
|
|||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(left_node),
|
left: Box::new(left_node),
|
||||||
Node::new(ComparisonOperator::GreaterThan, operator_position),
|
operator,
|
||||||
Box::new(right_node),
|
right: Box::new(right_node),
|
||||||
),
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::GreaterEqual, _) => {
|
(Token::GreaterEqual, _) => {
|
||||||
let operator_position = self.current.1;
|
let operator = Node::new(BinaryOperator::GreaterOrEqual, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
@ -203,16 +214,16 @@ impl<'src> Parser<'src> {
|
|||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(left_node),
|
left: Box::new(left_node),
|
||||||
Node::new(ComparisonOperator::GreaterThanOrEqual, operator_position),
|
operator,
|
||||||
Box::new(right_node),
|
right: Box::new(right_node),
|
||||||
),
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::Less, _) => {
|
(Token::Less, _) => {
|
||||||
let operator_position = self.current.1;
|
let operator = Node::new(BinaryOperator::Less, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
@ -220,16 +231,16 @@ impl<'src> Parser<'src> {
|
|||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(left_node),
|
left: Box::new(left_node),
|
||||||
Node::new(ComparisonOperator::LessThan, operator_position),
|
operator,
|
||||||
Box::new(right_node),
|
right: Box::new(right_node),
|
||||||
),
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::LessEqual, _) => {
|
(Token::LessEqual, _) => {
|
||||||
let operator_position = self.current.1;
|
let operator = Node::new(BinaryOperator::LessOrEqual, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
@ -237,44 +248,62 @@ impl<'src> Parser<'src> {
|
|||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(left_node),
|
left: Box::new(left_node),
|
||||||
Node::new(ComparisonOperator::LessThanOrEqual, operator_position),
|
operator,
|
||||||
Box::new(right_node),
|
right: Box::new(right_node),
|
||||||
),
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::Minus, _) => {
|
(Token::Minus, _) => {
|
||||||
|
let operator = Node::new(BinaryOperator::Subtract, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
let right_node = self.parse_node(self.current_precedence())?;
|
let right_node = self.parse_node(self.current_precedence())?;
|
||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Subtract(Box::new(left_node), Box::new(right_node)),
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(left_node),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right_node),
|
||||||
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::Plus, _) => {
|
(Token::Plus, _) => {
|
||||||
|
let operator = Node::new(BinaryOperator::Add, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
let right_node = self.parse_node(self.current_precedence())?;
|
let right_node = self.parse_node(self.current_precedence())?;
|
||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Add(Box::new(left_node), Box::new(right_node)),
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(left_node),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right_node),
|
||||||
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
(Token::Star, _) => {
|
(Token::Star, _) => {
|
||||||
|
let operator = Node::new(BinaryOperator::Multiply, self.current.1);
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
let right_node = self.parse_node(self.current_precedence())?;
|
let right_node = self.parse_node(self.current_precedence())?;
|
||||||
let right_end = right_node.position.1;
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
return Ok(Node::new(
|
return Ok(Node::new(
|
||||||
Statement::Multiply(Box::new(left_node), Box::new(right_node)),
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(left_node),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right_node),
|
||||||
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -447,12 +476,31 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
LexError { error: LexError, position: Span },
|
LexError {
|
||||||
|
error: LexError,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
|
||||||
ExpectedClosingParenthesis { actual: TokenOwned, position: Span },
|
ExpectedClosingParenthesis {
|
||||||
ExpectedClosingSquareBrace { actual: TokenOwned, position: Span },
|
actual: TokenOwned,
|
||||||
ExpectedOpeningParenthesis { actual: TokenOwned, position: Span },
|
position: Span,
|
||||||
UnexpectedToken { actual: TokenOwned, position: Span },
|
},
|
||||||
|
ExpectedClosingSquareBrace {
|
||||||
|
actual: TokenOwned,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
ExpectedIdentifier {
|
||||||
|
actual: Statement,
|
||||||
|
position: (usize, usize),
|
||||||
|
},
|
||||||
|
ExpectedOpeningParenthesis {
|
||||||
|
actual: TokenOwned,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
UnexpectedToken {
|
||||||
|
actual: TokenOwned,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseError {
|
impl ParseError {
|
||||||
@ -461,6 +509,7 @@ impl ParseError {
|
|||||||
Self::LexError { position, .. } => *position,
|
Self::LexError { position, .. } => *position,
|
||||||
Self::ExpectedClosingParenthesis { position, .. } => *position,
|
Self::ExpectedClosingParenthesis { position, .. } => *position,
|
||||||
Self::ExpectedClosingSquareBrace { position, .. } => *position,
|
Self::ExpectedClosingSquareBrace { position, .. } => *position,
|
||||||
|
Self::ExpectedIdentifier { position, .. } => *position,
|
||||||
Self::ExpectedOpeningParenthesis { position, .. } => *position,
|
Self::ExpectedOpeningParenthesis { position, .. } => *position,
|
||||||
Self::UnexpectedToken { position, .. } => *position,
|
Self::UnexpectedToken { position, .. } => *position,
|
||||||
}
|
}
|
||||||
@ -486,6 +535,9 @@ impl Display for ParseError {
|
|||||||
Self::ExpectedClosingSquareBrace { actual, .. } => {
|
Self::ExpectedClosingSquareBrace { actual, .. } => {
|
||||||
write!(f, "Expected closing square brace, found {actual}",)
|
write!(f, "Expected closing square brace, found {actual}",)
|
||||||
}
|
}
|
||||||
|
Self::ExpectedIdentifier { actual, .. } => {
|
||||||
|
write!(f, "Expected identifier, found {actual}")
|
||||||
|
}
|
||||||
Self::ExpectedOpeningParenthesis { actual, .. } => {
|
Self::ExpectedOpeningParenthesis { actual, .. } => {
|
||||||
write!(f, "Expected opening parenthesis, found {actual}",)
|
write!(f, "Expected opening parenthesis, found {actual}",)
|
||||||
}
|
}
|
||||||
@ -496,7 +548,7 @@ impl Display for ParseError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{abstract_tree::ComparisonOperator, Identifier};
|
use crate::{abstract_tree::BinaryOperator, Identifier};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -508,11 +560,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Node::new(ComparisonOperator::LessThan, (2, 3)),
|
operator: Node::new(BinaryOperator::Less, (2, 3)),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5)))
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
||||||
),
|
},
|
||||||
(0, 5)
|
(0, 5)
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -528,11 +580,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Node::new(ComparisonOperator::LessThanOrEqual, (2, 4)),
|
operator: Node::new(BinaryOperator::Less, (2, 4)),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6)))
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6))),
|
||||||
),
|
},
|
||||||
(0, 6)
|
(0, 6)
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -548,11 +600,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Node::new(ComparisonOperator::GreaterThanOrEqual, (2, 4)),
|
operator: Node::new(BinaryOperator::Greater, (2, 4)),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6)))
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6))),
|
||||||
),
|
},
|
||||||
(0, 6)
|
(0, 6)
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -568,11 +620,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Comparison(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Node::new(ComparisonOperator::GreaterThan, (2, 3)),
|
operator: Node::new(BinaryOperator::Greater, (2, 3)),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5)))
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
||||||
),
|
},
|
||||||
(0, 5)
|
(0, 5)
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -588,10 +640,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Subtract(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(-1)), (0, 2))),
|
left: Node::new(Statement::Constant(Value::integer(1)), (1, 2)).into(),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(-2)), (5, 7)))
|
operator: Node::new(BinaryOperator::Subtract, (3, 4)),
|
||||||
),
|
right: Node::new(Statement::Constant(Value::integer(2)), (6, 7)).into()
|
||||||
|
},
|
||||||
(0, 7)
|
(0, 7)
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -607,17 +660,18 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Add(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(
|
left: Box::new(Node::new(
|
||||||
Statement::Constant(Value::string("Hello, ")),
|
Statement::Constant(Value::string("Hello, ")),
|
||||||
(0, 9)
|
(0, 8)
|
||||||
)),
|
)),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Add, (9, 10)),
|
||||||
|
right: Box::new(Node::new(
|
||||||
Statement::Constant(Value::string("World!")),
|
Statement::Constant(Value::string("World!")),
|
||||||
(12, 20)
|
(11, 19)
|
||||||
))
|
))
|
||||||
),
|
},
|
||||||
(0, 20)
|
(0, 19)
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
@ -740,33 +794,42 @@ mod tests {
|
|||||||
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(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (4, 5))),
|
left: Box::new(Node::new(
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (8, 9))),
|
Statement::Constant(Value::integer(1)),
|
||||||
),
|
(4, 5)
|
||||||
(4, 9),
|
)),
|
||||||
|
operator: Node::new(BinaryOperator::Add, (6, 7)),
|
||||||
|
right: Box::new(Node::new(
|
||||||
|
Statement::Constant(Value::integer(1)),
|
||||||
|
(8, 9)
|
||||||
|
))
|
||||||
|
},
|
||||||
|
(4, 9)
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
Statement::Add(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(
|
left: Box::new(Node::new(
|
||||||
Statement::Constant(Value::integer(2)),
|
Statement::Constant(Value::integer(2)),
|
||||||
(11, 12)
|
(11, 12)
|
||||||
)),
|
)),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Add, (13, 14)),
|
||||||
Statement::Multiply(
|
right: Box::new(Node::new(
|
||||||
Box::new(Node::new(
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(Node::new(
|
||||||
Statement::Constant(Value::integer(4)),
|
Statement::Constant(Value::integer(4)),
|
||||||
(16, 17)
|
(16, 17)
|
||||||
)),
|
)),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Multiply, (18, 19)),
|
||||||
|
right: Box::new(Node::new(
|
||||||
Statement::Constant(Value::integer(10)),
|
Statement::Constant(Value::integer(10)),
|
||||||
(20, 22)
|
(20, 22)
|
||||||
)),
|
))
|
||||||
),
|
},
|
||||||
(15, 23),
|
(15, 23)
|
||||||
),),
|
))
|
||||||
),
|
},
|
||||||
(11, 23),
|
(11, 23)
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
(0, 24),
|
(0, 24),
|
||||||
@ -827,10 +890,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Add(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
operator: Node::new(BinaryOperator::Add, (2, 3)),
|
||||||
),
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5)),)
|
||||||
|
},
|
||||||
(0, 5),
|
(0, 5),
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -846,10 +910,11 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Multiply(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
operator: Node::new(BinaryOperator::Multiply, (2, 3)),
|
||||||
),
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5)),)
|
||||||
|
},
|
||||||
(0, 5),
|
(0, 5),
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -865,16 +930,24 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Add(
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Add, (2, 3)),
|
||||||
Statement::Multiply(
|
right: Box::new(Node::new(
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(3)), (8, 9))),
|
left: Box::new(Node::new(
|
||||||
),
|
Statement::Constant(Value::integer(2)),
|
||||||
(4, 9),
|
(4, 5)
|
||||||
)),
|
)),
|
||||||
),
|
operator: Node::new(BinaryOperator::Multiply, (6, 7)),
|
||||||
|
right: Box::new(Node::new(
|
||||||
|
Statement::Constant(Value::integer(3)),
|
||||||
|
(8, 9)
|
||||||
|
),)
|
||||||
|
},
|
||||||
|
(4, 9)
|
||||||
|
),)
|
||||||
|
},
|
||||||
(0, 9),
|
(0, 9),
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
@ -890,31 +963,33 @@ mod tests {
|
|||||||
parse(input),
|
parse(input),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
nodes: [Node::new(
|
nodes: [Node::new(
|
||||||
Statement::Assign(
|
Statement::Assignment {
|
||||||
Box::new(Node::new(
|
identifier: Identifier::new("a"),
|
||||||
Statement::Identifier(Identifier::new("a")),
|
value_node: Box::new(Node::new(
|
||||||
(0, 1)
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(Node::new(
|
||||||
|
Statement::Constant(Value::integer(1)),
|
||||||
|
(4, 5)
|
||||||
)),
|
)),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Add, (6, 7)),
|
||||||
Statement::Add(
|
right: Box::new(Node::new(
|
||||||
Box::new(Node::new(Statement::Constant(Value::integer(1)), (4, 5))),
|
Statement::BinaryOperation {
|
||||||
Box::new(Node::new(
|
left: Box::new(Node::new(
|
||||||
Statement::Multiply(
|
|
||||||
Box::new(Node::new(
|
|
||||||
Statement::Constant(Value::integer(2)),
|
Statement::Constant(Value::integer(2)),
|
||||||
(8, 9)
|
(8, 9)
|
||||||
)),
|
)),
|
||||||
Box::new(Node::new(
|
operator: Node::new(BinaryOperator::Multiply, (10, 11)),
|
||||||
|
right: Box::new(Node::new(
|
||||||
Statement::Constant(Value::integer(3)),
|
Statement::Constant(Value::integer(3)),
|
||||||
(12, 13)
|
(12, 13)
|
||||||
)),
|
),)
|
||||||
),
|
},
|
||||||
(8, 13),
|
(8, 13)
|
||||||
)),
|
),)
|
||||||
),
|
},
|
||||||
(4, 13),
|
(4, 13)
|
||||||
)),
|
),)
|
||||||
),
|
},
|
||||||
(0, 13),
|
(0, 13),
|
||||||
)]
|
)]
|
||||||
.into()
|
.into()
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::ComparisonOperator, parse, AbstractSyntaxTree, Analyzer, AnalyzerError,
|
abstract_tree::BinaryOperator, parse, AbstractSyntaxTree, Analyzer, AnalyzerError,
|
||||||
BuiltInFunctionError, Identifier, Node, ParseError, Span, Statement, Value, ValueError,
|
BuiltInFunctionError, Identifier, Node, ParseError, Span, Statement, Value, ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,53 +52,65 @@ impl Vm {
|
|||||||
variables: &mut HashMap<Identifier, Value>,
|
variables: &mut HashMap<Identifier, Value>,
|
||||||
) -> Result<Option<Value>, VmError> {
|
) -> Result<Option<Value>, VmError> {
|
||||||
match node.inner {
|
match node.inner {
|
||||||
Statement::Add(left, right) => {
|
Statement::Assignment {
|
||||||
let left_span = left.position;
|
identifier,
|
||||||
let left = if let Some(value) = self.run_node(*left, variables)? {
|
value_node,
|
||||||
|
} => {
|
||||||
|
let value_node_position = value_node.position;
|
||||||
|
let value = if let Some(value) = self.run_node(*value_node, variables)? {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedValue {
|
return Err(VmError::ExpectedValue {
|
||||||
position: left_span,
|
position: value_node_position,
|
||||||
});
|
|
||||||
};
|
|
||||||
let right_span = right.position;
|
|
||||||
let right = if let Some(value) = self.run_node(*right, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: right_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let sum = left
|
|
||||||
.add(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Some(sum))
|
|
||||||
}
|
|
||||||
Statement::Assign(left, right) => {
|
|
||||||
let identifier = if let Statement::Identifier(identifier) = &left.inner {
|
|
||||||
identifier
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedIdentifier {
|
|
||||||
position: left.position,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let right_span = right.position;
|
|
||||||
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);
|
variables.insert(identifier, value);
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
Statement::BinaryOperation {
|
||||||
|
left,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
} => {
|
||||||
|
let left_position = left.position;
|
||||||
|
let left_value = if let Some(value) = self.run_node(*left, variables)? {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
return Err(VmError::ExpectedValue {
|
||||||
|
position: left_position,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let right_position = right.position;
|
||||||
|
let right_value = if let Some(value) = self.run_node(*right, variables)? {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
return Err(VmError::ExpectedValue {
|
||||||
|
position: right_position,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = match operator.inner {
|
||||||
|
BinaryOperator::Add => left_value.add(&right_value),
|
||||||
|
BinaryOperator::Divide => todo!(),
|
||||||
|
BinaryOperator::Greater => left_value.greater_than(&right_value),
|
||||||
|
BinaryOperator::GreaterOrEqual => {
|
||||||
|
left_value.greater_than_or_equal(&right_value)
|
||||||
|
}
|
||||||
|
BinaryOperator::Less => left_value.less_than(&right_value),
|
||||||
|
BinaryOperator::LessOrEqual => left_value.less_than_or_equal(&right_value),
|
||||||
|
BinaryOperator::Multiply => left_value.multiply(&right_value),
|
||||||
|
BinaryOperator::Subtract => left_value.subtract(&right_value),
|
||||||
|
}
|
||||||
|
.map_err(|value_error| VmError::ValueError {
|
||||||
|
error: value_error,
|
||||||
|
position: node.position,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Some(result))
|
||||||
|
}
|
||||||
Statement::BuiltInFunctionCall {
|
Statement::BuiltInFunctionCall {
|
||||||
function,
|
function,
|
||||||
type_arguments: _,
|
type_arguments: _,
|
||||||
@ -132,54 +144,6 @@ impl Vm {
|
|||||||
|
|
||||||
Ok(function_call_return)
|
Ok(function_call_return)
|
||||||
}
|
}
|
||||||
Statement::Comparison(left, operator, right) => {
|
|
||||||
let left_span = left.position;
|
|
||||||
let left = if let Some(value) = self.run_node(*left, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: left_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let right_span = right.position;
|
|
||||||
let right = if let Some(value) = self.run_node(*right, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: right_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let comparison = match operator.inner {
|
|
||||||
ComparisonOperator::GreaterThan => {
|
|
||||||
left.greater_than(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?
|
|
||||||
}
|
|
||||||
ComparisonOperator::GreaterThanOrEqual => left
|
|
||||||
.greater_than_or_equal(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?,
|
|
||||||
ComparisonOperator::LessThan => {
|
|
||||||
left.less_than(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?
|
|
||||||
}
|
|
||||||
ComparisonOperator::LessThanOrEqual => left
|
|
||||||
.less_than_or_equal(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(comparison))
|
|
||||||
}
|
|
||||||
Statement::Constant(value) => Ok(Some(value.clone())),
|
Statement::Constant(value) => Ok(Some(value.clone())),
|
||||||
Statement::FunctionCall {
|
Statement::FunctionCall {
|
||||||
function: function_node,
|
function: function_node,
|
||||||
@ -250,32 +214,6 @@ impl Vm {
|
|||||||
|
|
||||||
Ok(Some(Value::list(values)))
|
Ok(Some(Value::list(values)))
|
||||||
}
|
}
|
||||||
Statement::Multiply(left, right) => {
|
|
||||||
let left_span = left.position;
|
|
||||||
let left = if let Some(value) = self.run_node(*left, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: left_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let right_span = right.position;
|
|
||||||
let right = if let Some(value) = self.run_node(*right, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: right_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let product = left
|
|
||||||
.multiply(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Some(product))
|
|
||||||
}
|
|
||||||
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, variables)? {
|
||||||
@ -337,32 +275,6 @@ impl Vm {
|
|||||||
position: right_span,
|
position: right_span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Statement::Subtract(left, right) => {
|
|
||||||
let left_span = left.position;
|
|
||||||
let left = if let Some(value) = self.run_node(*left, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: left_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let right_span = right.position;
|
|
||||||
let right = if let Some(value) = self.run_node(*right, variables)? {
|
|
||||||
value
|
|
||||||
} else {
|
|
||||||
return Err(VmError::ExpectedValue {
|
|
||||||
position: right_span,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let difference =
|
|
||||||
left.subtract(&right)
|
|
||||||
.map_err(|value_error| VmError::ValueError {
|
|
||||||
error: value_error,
|
|
||||||
position: (left_span.0, right_span.1),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Some(difference))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user