|
|
|
@ -1,8 +1,4 @@
|
|
|
|
|
//! The top level of Dust's API with functions to interpret Dust code.
|
|
|
|
|
//!
|
|
|
|
|
//! You can use this library externally by calling either of the "eval"
|
|
|
|
|
//! functions or by constructing your own Evaluator.
|
|
|
|
|
use std::fmt::{self, Debug, Formatter};
|
|
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use tree_sitter::{Node, Parser, Tree as TSTree, TreeCursor};
|
|
|
|
@ -34,9 +30,9 @@ pub fn eval(source: &str) -> Vec<Result<Value>> {
|
|
|
|
|
/// # use dust_lib::*;
|
|
|
|
|
/// let mut context = VariableMap::new();
|
|
|
|
|
///
|
|
|
|
|
/// context.set_value("one".into(), 1.into());
|
|
|
|
|
/// context.set_value("two".into(), 2.into());
|
|
|
|
|
/// context.set_value("three".into(), 3.into());
|
|
|
|
|
/// context.set_value("one".into(), 1.into()).unwrap(); // Do proper error handling here
|
|
|
|
|
/// context.set_value("two".into(), 2.into()).unwrap(); // Do proper error handling here
|
|
|
|
|
/// context.set_value("three".into(), 3.into()).unwrap(); // Do proper error handling here
|
|
|
|
|
///
|
|
|
|
|
/// let dust_code = "four = 4 one + two + three + four";
|
|
|
|
|
///
|
|
|
|
@ -47,12 +43,20 @@ pub fn eval(source: &str) -> Vec<Result<Value>> {
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec<Result<Value>> {
|
|
|
|
|
let mut parser = Parser::new();
|
|
|
|
|
|
|
|
|
|
parser.set_language(language()).unwrap();
|
|
|
|
|
|
|
|
|
|
Evaluator::new(parser, context, source).run()
|
|
|
|
|
let tree = parser.parse(source, None).unwrap();
|
|
|
|
|
let mut cursor = tree.walk();
|
|
|
|
|
let evaluator = Evaluator::new(tree.clone(), source).unwrap();
|
|
|
|
|
let results = evaluator.run(context, &mut cursor, source);
|
|
|
|
|
|
|
|
|
|
println!("{results:?}");
|
|
|
|
|
|
|
|
|
|
results
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trait EvaluatorTree: Sized {
|
|
|
|
|
pub trait EvaluatorTree: Sized {
|
|
|
|
|
/// Interpret the syntax tree at the given node and return the abstraction.
|
|
|
|
|
///
|
|
|
|
|
/// This function is used to convert nodes in the Tree Sitter concrete
|
|
|
|
@ -65,51 +69,33 @@ trait EvaluatorTree: Sized {
|
|
|
|
|
fn new(node: Node, source: &str) -> Result<Self>;
|
|
|
|
|
|
|
|
|
|
/// Execute dust code by traversing the tree
|
|
|
|
|
fn run() -> Vec<Result<Value>>;
|
|
|
|
|
fn run(
|
|
|
|
|
&self,
|
|
|
|
|
context: &mut VariableMap,
|
|
|
|
|
cursor: &mut TreeCursor,
|
|
|
|
|
source: &str,
|
|
|
|
|
) -> Vec<Result<Value>>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A collection of statements and comments interpreted from a syntax tree.
|
|
|
|
|
///
|
|
|
|
|
/// The Evaluator turns a tree sitter concrete syntax tree into a vector of
|
|
|
|
|
/// abstract trees called [Item][]s that can be run to execute the source code.
|
|
|
|
|
pub struct Evaluator<'context, 'code> {
|
|
|
|
|
_parser: Parser,
|
|
|
|
|
context: &'context mut VariableMap,
|
|
|
|
|
source: &'code str,
|
|
|
|
|
tree: TSTree,
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct Evaluator {
|
|
|
|
|
items: Vec<Item>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Debug for Evaluator<'_, '_> {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
write!(f, "Evaluator context: {}", self.context)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'context, 'code> Evaluator<'context, 'code> {
|
|
|
|
|
fn new(mut parser: Parser, context: &'context mut VariableMap, source: &'code str) -> Self {
|
|
|
|
|
let tree = parser.parse(source, None).unwrap();
|
|
|
|
|
|
|
|
|
|
Evaluator {
|
|
|
|
|
_parser: parser,
|
|
|
|
|
context,
|
|
|
|
|
source,
|
|
|
|
|
tree,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run(self) -> Vec<Result<Value>> {
|
|
|
|
|
let root_node = self.tree.root_node();
|
|
|
|
|
let mut cursor = self.tree.walk();
|
|
|
|
|
impl Evaluator {
|
|
|
|
|
fn new(tree_sitter_tree: TSTree, source: &str) -> Result<Self> {
|
|
|
|
|
let root_node = tree_sitter_tree.root_node();
|
|
|
|
|
let mut cursor = tree_sitter_tree.walk();
|
|
|
|
|
let mut items = Vec::new();
|
|
|
|
|
let mut results = Vec::new();
|
|
|
|
|
|
|
|
|
|
for (index, node) in root_node.children(&mut cursor).enumerate() {
|
|
|
|
|
match Item::new(node, self.source) {
|
|
|
|
|
Ok(item) => items.push(item),
|
|
|
|
|
Err(error) => results.push(Err(error)),
|
|
|
|
|
}
|
|
|
|
|
let item = Item::new(node, source)?;
|
|
|
|
|
|
|
|
|
|
println!("{node:?}");
|
|
|
|
|
items.push(item);
|
|
|
|
|
|
|
|
|
|
// This iterator will run forever without this check.
|
|
|
|
|
if index == root_node.child_count() - 1 {
|
|
|
|
@ -117,11 +103,22 @@ impl<'context, 'code> Evaluator<'context, 'code> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for item in &items {
|
|
|
|
|
Ok(Evaluator { items })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run(
|
|
|
|
|
&self,
|
|
|
|
|
context: &mut VariableMap,
|
|
|
|
|
mut cursor: &mut TreeCursor,
|
|
|
|
|
source: &str,
|
|
|
|
|
) -> Vec<Result<Value>> {
|
|
|
|
|
let mut results = Vec::with_capacity(self.items.len());
|
|
|
|
|
|
|
|
|
|
for item in &self.items {
|
|
|
|
|
match item {
|
|
|
|
|
Item::Comment(comment) => results.push(Ok(Value::String(comment.to_string()))),
|
|
|
|
|
Item::Comment(comment) => results.push(Ok(Value::String(comment.clone()))),
|
|
|
|
|
Item::Statement(statement) => {
|
|
|
|
|
results.push(statement.run(self.context, &mut cursor, self.source))
|
|
|
|
|
results.push(statement.run(context, &mut cursor, source))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -147,7 +144,6 @@ impl Item {
|
|
|
|
|
return Err(Error::UnexpectedSourceNode {
|
|
|
|
|
expected: "item",
|
|
|
|
|
actual: node.kind(),
|
|
|
|
|
location: node.start_position(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -155,9 +151,9 @@ impl Item {
|
|
|
|
|
|
|
|
|
|
if child.kind() == "comment" {
|
|
|
|
|
let byte_range = node.byte_range();
|
|
|
|
|
let comment_text = &source[byte_range];
|
|
|
|
|
let value_string = &source[byte_range];
|
|
|
|
|
|
|
|
|
|
Ok(Item::Comment(comment_text.to_string()))
|
|
|
|
|
Ok(Item::Comment(value_string.to_string()))
|
|
|
|
|
} else if child.kind() == "statement" {
|
|
|
|
|
let child = node.child(0).unwrap();
|
|
|
|
|
Ok(Item::Statement(Statement::new(child, source)?))
|
|
|
|
@ -165,7 +161,6 @@ impl Item {
|
|
|
|
|
Err(Error::UnexpectedSourceNode {
|
|
|
|
|
expected: "comment or statement",
|
|
|
|
|
actual: node.kind(),
|
|
|
|
|
location: node.start_position(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -178,7 +173,7 @@ impl Item {
|
|
|
|
|
/// referencing variables.
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
|
pub enum Statement {
|
|
|
|
|
Expression(Expression),
|
|
|
|
|
Open(Expression),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Statement {
|
|
|
|
@ -188,15 +183,13 @@ impl Statement {
|
|
|
|
|
} else {
|
|
|
|
|
node
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let child = node.child(0).unwrap();
|
|
|
|
|
|
|
|
|
|
match node.kind() {
|
|
|
|
|
"expression" => Ok(Self::Expression(Expression::new(child, source)?)),
|
|
|
|
|
"open_statement" => Ok(Self::Open(Expression::new(child, source)?)),
|
|
|
|
|
_ => Err(Error::UnexpectedSourceNode {
|
|
|
|
|
expected: "expression",
|
|
|
|
|
expected: "open_statement",
|
|
|
|
|
actual: node.kind(),
|
|
|
|
|
location: node.start_position(),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -208,7 +201,7 @@ impl Statement {
|
|
|
|
|
source: &str,
|
|
|
|
|
) -> Result<Value> {
|
|
|
|
|
match self {
|
|
|
|
|
Statement::Expression(expression) => expression.run(context, &mut cursor, source),
|
|
|
|
|
Statement::Open(expression) => expression.run(context, &mut cursor, source),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -217,31 +210,8 @@ impl Statement {
|
|
|
|
|
pub enum Expression {
|
|
|
|
|
Identifier(String),
|
|
|
|
|
Value(Value),
|
|
|
|
|
Operation(Box<Operation>),
|
|
|
|
|
ControlFlow(Box<ControlFlow>),
|
|
|
|
|
Assignment(Box<Assignment>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
|
pub struct Assignment {
|
|
|
|
|
identifier: String,
|
|
|
|
|
statement: Statement,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Assignment {
|
|
|
|
|
pub fn new(node: Node, source: &str) -> Result<Self> {
|
|
|
|
|
let sexp = node.to_sexp();
|
|
|
|
|
println!("{sexp}");
|
|
|
|
|
|
|
|
|
|
let identifier_node = node.child(0).unwrap();
|
|
|
|
|
let statement_node = node.child(2).unwrap();
|
|
|
|
|
let identifier = source[identifier_node.byte_range()].to_string();
|
|
|
|
|
let statement = Statement::new(statement_node, source)?;
|
|
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
|
identifier,
|
|
|
|
|
statement,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Expression {
|
|
|
|
@ -259,19 +229,18 @@ impl Expression {
|
|
|
|
|
Ok(Self::Identifier(identifier.to_string()))
|
|
|
|
|
} else if node.kind() == "value" {
|
|
|
|
|
Ok(Expression::Value(Value::new(node, source)?))
|
|
|
|
|
} else if node.kind() == "operation" {
|
|
|
|
|
Ok(Expression::Operation(Box::new(Operation::new(
|
|
|
|
|
node, source,
|
|
|
|
|
)?)))
|
|
|
|
|
} else if node.kind() == "control_flow" {
|
|
|
|
|
Ok(Expression::ControlFlow(Box::new(ControlFlow::new(
|
|
|
|
|
node, source,
|
|
|
|
|
)?)))
|
|
|
|
|
} else if node.kind() == "assignment" {
|
|
|
|
|
Ok(Expression::Assignment(Box::new(Assignment::new(
|
|
|
|
|
node, source,
|
|
|
|
|
)?)))
|
|
|
|
|
} else {
|
|
|
|
|
Err(Error::UnexpectedSourceNode {
|
|
|
|
|
expected: "identifier, operation, control_flow, assignment or value",
|
|
|
|
|
expected: "identifier, operation, control_flow or value",
|
|
|
|
|
actual: node.kind(),
|
|
|
|
|
location: node.start_position(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -293,12 +262,64 @@ impl Expression {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Expression::Value(value) => Ok(value.clone()),
|
|
|
|
|
Expression::Operation(operation) => operation.run(context, &mut cursor, source),
|
|
|
|
|
Expression::ControlFlow(control_flow) => control_flow.run(context, &mut cursor, source),
|
|
|
|
|
Expression::Assignment(_) => todo!(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
|
pub struct Operation {
|
|
|
|
|
left: Expression,
|
|
|
|
|
operator: String,
|
|
|
|
|
right: Expression,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Operation {
|
|
|
|
|
fn new(node: Node, source: &str) -> Result<Self> {
|
|
|
|
|
let first_child = node.child(0).unwrap();
|
|
|
|
|
let second_child = node.child(1).unwrap();
|
|
|
|
|
let third_child = node.child(2).unwrap();
|
|
|
|
|
let left = Expression::new(first_child, source)?;
|
|
|
|
|
let operator = second_child.child(0).unwrap().kind().to_string();
|
|
|
|
|
let right = Expression::new(third_child, source)?;
|
|
|
|
|
|
|
|
|
|
Ok(Operation {
|
|
|
|
|
left,
|
|
|
|
|
operator,
|
|
|
|
|
right,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run(
|
|
|
|
|
&self,
|
|
|
|
|
context: &mut VariableMap,
|
|
|
|
|
mut cursor: &mut TreeCursor,
|
|
|
|
|
source: &str,
|
|
|
|
|
) -> Result<Value> {
|
|
|
|
|
let left = self.left.run(context, &mut cursor, source)?;
|
|
|
|
|
let right = self.right.run(context, &mut cursor, source)?;
|
|
|
|
|
|
|
|
|
|
match self.operator.as_str() {
|
|
|
|
|
"+" => left + right,
|
|
|
|
|
"-" => left - right,
|
|
|
|
|
"=" => {
|
|
|
|
|
if let Expression::Identifier(key) = &self.left {
|
|
|
|
|
context.set_value(key, right)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Value::Empty)
|
|
|
|
|
}
|
|
|
|
|
"==" => Ok(Value::Boolean(left == right)),
|
|
|
|
|
_ => Err(Error::CustomMessage("Operator not supported.".to_string())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Respresentation of an if-then-else logic gate.
|
|
|
|
|
///
|
|
|
|
|
/// A ControlFlow instance represents work to be done when the "run" method is
|
|
|
|
|
/// called.
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
|
pub struct ControlFlow {
|
|
|
|
|
if_expression: Expression,
|
|
|
|
@ -354,23 +375,14 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn evaluate_empty() {
|
|
|
|
|
assert_eq!(eval(""), vec![]);
|
|
|
|
|
assert_eq!(eval("x = 9"), vec![]);
|
|
|
|
|
assert_eq!(eval("'foo' + 'bar'"), vec![]);
|
|
|
|
|
assert_eq!(eval("()"), vec![Ok(Value::Empty)]);
|
|
|
|
|
assert_eq!(eval("x = 9"), vec![Ok(Value::Empty)]);
|
|
|
|
|
assert_eq!(eval("y = 'foobar'"), vec![Ok(Value::Empty)]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn evaluate_integer() {
|
|
|
|
|
assert_eq!(eval("1"), vec![Ok(Value::Integer(1))]);
|
|
|
|
|
assert_eq!(eval("123"), vec![Ok(Value::Integer(123))]);
|
|
|
|
|
assert_eq!(eval("-666"), vec![Ok(Value::Integer(-666))]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn evaluate_float() {
|
|
|
|
|
assert_eq!(eval("0.1"), vec![Ok(Value::Float(0.1))]);
|
|
|
|
|
assert_eq!(eval("12.3"), vec![Ok(Value::Float(12.3))]);
|
|
|
|
|
assert_eq!(eval("-6.66"), vec![Ok(Value::Float(-6.66))]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|