Improve AST
This commit is contained in:
parent
e9db34be8b
commit
597d6bd8b8
190
src/interface.rs
190
src/interface.rs
@ -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]
|
||||||
|
@ -46,7 +46,10 @@ impl Tool for AssertEqual {
|
|||||||
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()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user