Improve AST

This commit is contained in:
Jeff 2023-10-01 12:17:27 -04:00
parent e9db34be8b
commit 597d6bd8b8
3 changed files with 144 additions and 88 deletions

View File

@ -5,7 +5,7 @@
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::{Node, Parser, Tree as TSTree}; use tree_sitter::{Node, Parser, Tree as TSTree, TreeCursor};
use crate::{language, Error, Result, Value, VariableMap}; use crate::{language, Error, Result, Value, VariableMap};
@ -99,28 +99,26 @@ impl<'context, 'code> Evaluator<'context, 'code> {
} }
fn run(self) -> Vec<Result<Value>> { fn run(self) -> Vec<Result<Value>> {
let root_node = self.tree.root_node();
let mut cursor = self.tree.walk(); let mut cursor = self.tree.walk();
let mut items = Vec::new(); let node = cursor.node();
let mut results = Vec::new(); let item_count = node.child_count();
let mut results = Vec::with_capacity(item_count);
for (index, node) in root_node.children(&mut cursor).enumerate() { println!("{}", node.to_sexp());
match Item::new(node, self.source) {
Ok(item) => items.push(item), assert_eq!(cursor.node().kind(), "root");
for item_node in node.children(&mut cursor) {
let item_result = Item::new(item_node, self.source);
match item_result {
Ok(item) => {
let eval_result = item.run(self.context);
results.push(eval_result);
}
Err(error) => results.push(Err(error)), Err(error) => results.push(Err(error)),
} }
// This iterator will run forever without this check.
if index == root_node.child_count() - 1 {
break;
}
}
for item in &items {
match item {
Item::Comment(comment) => results.push(Ok(Value::String(comment.to_string()))),
Item::Statement(statement) => results.push(statement.run(self.context)),
}
} }
results results
@ -138,35 +136,34 @@ pub enum Item {
Statement(Statement), Statement(Statement),
} }
impl Item { impl EvaluatorTree for Item {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
if node.kind() != "item" { assert_eq!(node.kind(), "item");
return Err(Error::UnexpectedSyntax {
expected: "item",
actual: node.kind(),
location: node.start_position(),
});
}
let child = node.child(0).unwrap(); let child = node.child(0).unwrap();
if child.kind() == "comment" { if child.kind() == "comment" {
let byte_range = node.byte_range(); let byte_range = child.byte_range();
let comment_text = &source[byte_range]; let comment_text = &source[byte_range];
Ok(Item::Comment(comment_text.to_string())) Ok(Item::Comment(comment_text.to_string()))
} else if child.kind() == "statement" { } else if child.kind() == "statement" {
let grandchild = child.child(0).unwrap(); Ok(Item::Statement(Statement::new(child, source)?))
Ok(Item::Statement(Statement::new(grandchild, source)?))
} else { } else {
Err(Error::UnexpectedSyntax { Err(Error::UnexpectedSyntax {
expected: "comment or statement", expected: "comment or statement",
actual: node.kind(), actual: child.kind(),
location: node.start_position(), location: child.start_position(),
}) })
} }
} }
fn run(&self, context: &mut VariableMap) -> Result<Value> {
match self {
Item::Comment(text) => Ok(Value::String(text.clone())),
Item::Statement(statement) => statement.run(context),
}
}
} }
/// Abstract representation of a statement. /// Abstract representation of a statement.
@ -181,18 +178,15 @@ pub enum Statement {
impl EvaluatorTree for Statement { impl EvaluatorTree for Statement {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
let node = if node.kind() == "statement" { assert_eq!(node.kind(), "statement");
node.child(0).unwrap() let child = node.child(0).unwrap();
} else {
node
};
match node.kind() { match child.kind() {
"expression" => Ok(Self::Expression(Expression::new(node, source)?)), "expression" => Ok(Self::Expression(Expression::new(child, source)?)),
_ => Err(Error::UnexpectedSyntax { _ => Err(Error::UnexpectedSyntax {
expected: "expression", expected: "expression",
actual: node.kind(), actual: child.kind(),
location: node.start_position(), location: child.start_position(),
}), }),
} }
} }
@ -211,29 +205,27 @@ pub enum Expression {
ControlFlow(Box<ControlFlow>), ControlFlow(Box<ControlFlow>),
Assignment(Box<Assignment>), Assignment(Box<Assignment>),
Math(Box<Math>), Math(Box<Math>),
FunctionCall(FunctionCall),
} }
impl EvaluatorTree for Expression { impl EvaluatorTree for Expression {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
let node = if node.kind() == "expression" { assert_eq!(node.kind(), "expression");
node.child(0).unwrap()
} else {
node
};
let expression = match node.kind() { let child = node.child(0).unwrap();
"identifier" => Self::Identifier(Identifier::new(node, source)?), let expression = match child.kind() {
"value" => Expression::Value(Value::new(node, source)?), "identifier" => Self::Identifier(Identifier::new(child, source)?),
"control_flow" => Expression::ControlFlow(Box::new(ControlFlow::new(node, source)?)), "value" => Expression::Value(Value::new(child, source)?),
"assignment" => Expression::Assignment(Box::new(Assignment::new(node, source)?)), "control_flow" => Expression::ControlFlow(Box::new(ControlFlow::new(child, source)?)),
"math" => Expression::Math(Box::new(Math::new(node, source)?)), "assignment" => Expression::Assignment(Box::new(Assignment::new(child, source)?)),
_ => { "math" => Expression::Math(Box::new(Math::new(child, source)?)),
return Err(Error::UnexpectedSyntax { "function_call" => Expression::FunctionCall(FunctionCall::new(child, source)?),
expected: "identifier, operation, control_flow, assignment, math or value", _ => return Err(Error::UnexpectedSyntax {
actual: node.kind(), expected:
location: node.start_position(), "identifier, operation, control_flow, assignment, math, function_call or value",
}) actual: child.kind(),
} location: child.start_position(),
}),
}; };
Ok(expression) Ok(expression)
@ -246,6 +238,7 @@ impl EvaluatorTree for Expression {
Expression::ControlFlow(control_flow) => control_flow.run(context), Expression::ControlFlow(control_flow) => control_flow.run(context),
Expression::Assignment(assignment) => assignment.run(context), Expression::Assignment(assignment) => assignment.run(context),
Expression::Math(math) => math.run(context), Expression::Math(math) => math.run(context),
Expression::FunctionCall(function_call) => function_call.run(context),
} }
} }
} }
@ -265,8 +258,9 @@ impl Identifier {
impl EvaluatorTree for Identifier { impl EvaluatorTree for Identifier {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
let byte_range = node.byte_range(); assert_eq!(node.kind(), "identifier");
let identifier = &source[byte_range];
let identifier = &source[node.byte_range()];
Ok(Identifier(identifier.to_string())) Ok(Identifier(identifier.to_string()))
} }
@ -287,19 +281,22 @@ pub struct ControlFlow {
impl EvaluatorTree for ControlFlow { impl EvaluatorTree for ControlFlow {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
assert_eq!(node.kind(), "control_flow");
// Skip the child nodes for the keywords "if", "then" and "else". // Skip the child nodes for the keywords "if", "then" and "else".
let second_child = node.child(1).unwrap(); let if_expression_node = node.child(1).unwrap();
let fourth_child = node.child(3).unwrap(); let then_statement_node = node.child(3).unwrap();
let sixth_child = node.child(5); let else_statement_node = node.child(5);
let else_statement = if let Some(child) = sixth_child {
let else_statement = if let Some(child) = else_statement_node {
Some(Statement::new(child, source)?) Some(Statement::new(child, source)?)
} else { } else {
None None
}; };
Ok(ControlFlow { Ok(ControlFlow {
if_expression: Expression::new(second_child, source)?, if_expression: Expression::new(if_expression_node, source)?,
then_statement: Statement::new(fourth_child, source)?, then_statement: Statement::new(then_statement_node, source)?,
else_statement, else_statement,
}) })
} }
@ -325,17 +322,14 @@ pub struct Assignment {
impl EvaluatorTree for Assignment { impl EvaluatorTree for Assignment {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
let sexp = node.to_sexp(); assert_eq!(node.kind(), "assignment");
println!("{sexp}");
let identifier_node = node.child(0).unwrap(); let identifier_node = node.child(0).unwrap();
let statement_node = node.child(2).unwrap(); let statement_node = node.child(2).unwrap();
let identifier = Identifier::new(identifier_node, source)?;
let statement = Statement::new(statement_node, source)?;
Ok(Assignment { Ok(Assignment {
identifier, identifier: Identifier::new(identifier_node, source)?,
statement, statement: Statement::new(statement_node, source)?,
}) })
} }
@ -357,6 +351,8 @@ pub struct Math {
impl EvaluatorTree for Math { impl EvaluatorTree for Math {
fn new(node: Node, source: &str) -> Result<Self> { fn new(node: Node, source: &str) -> Result<Self> {
assert_eq!(node.kind(), "math");
let left_node = node.child(0).unwrap(); let left_node = node.child(0).unwrap();
let operator_node = node.child(1).unwrap().child(0).unwrap(); let operator_node = node.child(1).unwrap().child(0).unwrap();
let right_node = node.child(2).unwrap(); let right_node = node.child(2).unwrap();
@ -406,6 +402,47 @@ pub enum MathOperator {
Modulo, Modulo,
} }
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct FunctionCall {
identifier: Identifier,
expressions: Vec<Expression>,
}
impl EvaluatorTree for FunctionCall {
fn new(node: Node, source: &str) -> Result<Self> {
assert_eq!(node.kind(), "function_call");
let identifier_node = node.child(0).unwrap();
let mut expressions = Vec::new();
for index in 2..node.child_count() - 1 {
let child = node.child(index).unwrap();
if child.kind() == "expression" {
let expression = Expression::new(node, source)?;
expressions.push(expression);
}
}
Ok(FunctionCall {
identifier: Identifier::new(identifier_node, source)?,
expressions,
})
}
fn run(&self, context: &mut VariableMap) -> Result<Value> {
let mut arguments = Vec::with_capacity(self.expressions.len());
for expression in &self.expressions {
let value = expression.run(context)?;
arguments.push(value);
}
context.call_function(self.identifier.inner(), &Value::List(arguments))
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::Table; use crate::Table;
@ -414,9 +451,8 @@ mod tests {
#[test] #[test]
fn evaluate_empty() { fn evaluate_empty() {
assert_eq!(eval(""), vec![]); assert_eq!(eval("x = 9"), vec![Ok(Value::Empty)]);
assert_eq!(eval("x = 9"), vec![]); assert_eq!(eval("x = 'foo' + 'bar'"), vec![Ok(Value::Empty)]);
assert_eq!(eval("'foo' + 'bar'"), vec![]);
} }
#[test] #[test]

View File

@ -44,9 +44,12 @@ impl Tool for AssertEqual {
let arguments = argument.as_fixed_len_list(2)?; let arguments = argument.as_fixed_len_list(2)?;
if arguments[0] == arguments[1] { if arguments[0] == arguments[1] {
Ok(Value::Empty) Ok(Value::Empty)
} else { } else {
Err(Error::AssertEqualFailed { expected: arguments[0].clone(), actual: arguments[1].clone() }) Err(Error::AssertEqualFailed {
expected: arguments[0].clone(),
actual: arguments[1].clone()
})
} }
} }

View File

@ -10,7 +10,7 @@ use serde::{
ser::SerializeTuple, ser::SerializeTuple,
Deserialize, Serialize, Serializer, Deserialize, Serialize, Serializer,
}; };
use tree_sitter::Node; use tree_sitter::{Node, TreeCursor};
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
@ -32,7 +32,7 @@ pub mod variable_map;
/// Every whale variable has a key and a Value. Variables are represented by /// Every whale variable has a key and a Value. Variables are represented by
/// storing them in a VariableMap. This means the map of variables is itself a /// storing them in a VariableMap. This means the map of variables is itself a
/// value that can be treated as any other. /// value that can be treated as any other.
#[derive(Clone, Debug, PartialEq, Default)] #[derive(Clone, Debug, Default)]
pub enum Value { pub enum Value {
String(String), String(String),
Float(f64), Float(f64),
@ -49,15 +49,12 @@ pub enum Value {
impl Value { impl Value {
pub fn new(node: Node, source: &str) -> Result<Self> { pub fn new(node: Node, source: &str) -> Result<Self> {
let node = if node.kind() == "value" { assert_eq!(node.kind(), "value");
node.child(0).unwrap()
} else {
node
};
let child = node.child(0).unwrap();
let value_snippet = &source[node.byte_range()]; let value_snippet = &source[node.byte_range()];
match node.kind() { match child.kind() {
"integer" => { "integer" => {
let raw = value_snippet.parse::<i64>().unwrap_or_default(); let raw = value_snippet.parse::<i64>().unwrap_or_default();
@ -179,7 +176,7 @@ impl Value {
} }
"empty" => Ok(Value::Empty), "empty" => Ok(Value::Empty),
_ => Err(Error::UnexpectedSyntax { _ => Err(Error::UnexpectedSyntax {
expected: "integer, string, boolean, float, list or empty", expected: "integer, string, boolean, float, list, table, function or empty",
actual: node.kind(), actual: node.kind(),
location: node.start_position(), location: node.start_position(),
}), }),
@ -447,6 +444,26 @@ impl Sub for Value {
impl Eq for Value {} impl Eq for Value {}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::String(left), Value::String(right)) => left == right,
(Value::Float(left), Value::Float(right)) => left == right,
(Value::Integer(left), Value::Integer(right)) => left == right,
(Value::Float(float), Value::Integer(integer))
| (Value::Integer(integer), Value::Float(float)) => *float == *integer as f64,
(Value::Boolean(left), Value::Boolean(right)) => left == right,
(Value::List(left), Value::List(right)) => left == right,
(Value::Map(left), Value::Map(right)) => left == right,
(Value::Table(left), Value::Table(right)) => left == right,
(Value::Time(left), Value::Time(right)) => left == right,
(Value::Function(left), Value::Function(right)) => left == right,
(Value::Empty, Value::Empty) => true,
_ => false,
}
}
}
impl PartialOrd for Value { impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))