Compare commits

..

No commits in common. "b476818ba3a5e005684fe3e3ee144b1014a6d5d0" and "f596c6b5811cabc9b1b8ef87b9c6ce627b567c93" have entirely different histories.

5 changed files with 117 additions and 105 deletions

View File

@ -15,7 +15,6 @@ pub enum Error {
UnexpectedSourceNode { UnexpectedSourceNode {
expected: &'static str, expected: &'static str,
actual: &'static str, actual: &'static str,
location: tree_sitter::Point,
}, },
ExpectedFieldName, ExpectedFieldName,
@ -553,7 +552,7 @@ impl fmt::Display for Error {
macro_info.identifier, macro_info.identifier,
macro_info.inputs macro_info.inputs
), ),
UnexpectedSourceNode { expected, actual, location } => write!(f, "Unexpected syntax at {location}. Expected {expected}, but found {actual}."), UnexpectedSourceNode { expected, actual } => write!(f, "Unexpected source node. Expected {expected}, but found {actual}."),
ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."), ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."),
WrongTypeCombination { expected, actual } => write!(f, "Wrong type combination. Expected {expected}, found {actual}."), WrongTypeCombination { expected, actual } => write!(f, "Wrong type combination. Expected {expected}, found {actual}."),
ExpectedChildNode { empty_node_sexp } => write!(f, "Expected this node to have a child, {empty_node_sexp}."), ExpectedChildNode { empty_node_sexp } => write!(f, "Expected this node to have a child, {empty_node_sexp}."),

View File

@ -1,8 +1,4 @@
//! The top level of Dust's API with functions to interpret Dust code. //! 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 serde::{Deserialize, Serialize};
use tree_sitter::{Node, Parser, Tree as TSTree, TreeCursor}; use tree_sitter::{Node, Parser, Tree as TSTree, TreeCursor};
@ -34,9 +30,9 @@ pub fn eval(source: &str) -> Vec<Result<Value>> {
/// # use dust_lib::*; /// # use dust_lib::*;
/// let mut context = VariableMap::new(); /// let mut context = VariableMap::new();
/// ///
/// context.set_value("one".into(), 1.into()); /// context.set_value("one".into(), 1.into()).unwrap(); // Do proper error handling here
/// context.set_value("two".into(), 2.into()); /// context.set_value("two".into(), 2.into()).unwrap(); // Do proper error handling here
/// context.set_value("three".into(), 3.into()); /// context.set_value("three".into(), 3.into()).unwrap(); // Do proper error handling here
/// ///
/// let dust_code = "four = 4 one + two + three + four"; /// 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>> { pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec<Result<Value>> {
let mut parser = Parser::new(); let mut parser = Parser::new();
parser.set_language(language()).unwrap(); 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. /// Interpret the syntax tree at the given node and return the abstraction.
/// ///
/// This function is used to convert nodes in the Tree Sitter concrete /// 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>; fn new(node: Node, source: &str) -> Result<Self>;
/// Execute dust code by traversing the tree /// 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. /// A collection of statements and comments interpreted from a syntax tree.
/// ///
/// The Evaluator turns a tree sitter concrete syntax tree into a vector of /// 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. /// abstract trees called [Item][]s that can be run to execute the source code.
pub struct Evaluator<'context, 'code> { #[derive(Debug)]
_parser: Parser, pub struct Evaluator {
context: &'context mut VariableMap, items: Vec<Item>,
source: &'code str,
tree: TSTree,
} }
impl Debug for Evaluator<'_, '_> { impl Evaluator {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn new(tree_sitter_tree: TSTree, source: &str) -> Result<Self> {
write!(f, "Evaluator context: {}", self.context) let root_node = tree_sitter_tree.root_node();
} let mut cursor = tree_sitter_tree.walk();
}
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();
let mut items = Vec::new(); let mut items = Vec::new();
let mut results = Vec::new();
for (index, node) in root_node.children(&mut cursor).enumerate() { for (index, node) in root_node.children(&mut cursor).enumerate() {
match Item::new(node, self.source) { let item = Item::new(node, source)?;
Ok(item) => items.push(item),
Err(error) => results.push(Err(error)),
}
println!("{node:?}"); items.push(item);
// This iterator will run forever without this check. // This iterator will run forever without this check.
if index == root_node.child_count() - 1 { 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 { 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) => { 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 { return Err(Error::UnexpectedSourceNode {
expected: "item", expected: "item",
actual: node.kind(), actual: node.kind(),
location: node.start_position(),
}); });
} }
@ -155,9 +151,9 @@ impl Item {
if child.kind() == "comment" { if child.kind() == "comment" {
let byte_range = node.byte_range(); 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" { } else if child.kind() == "statement" {
let child = node.child(0).unwrap(); let child = node.child(0).unwrap();
Ok(Item::Statement(Statement::new(child, source)?)) Ok(Item::Statement(Statement::new(child, source)?))
@ -165,7 +161,6 @@ impl Item {
Err(Error::UnexpectedSourceNode { Err(Error::UnexpectedSourceNode {
expected: "comment or statement", expected: "comment or statement",
actual: node.kind(), actual: node.kind(),
location: node.start_position(),
}) })
} }
} }
@ -178,7 +173,7 @@ impl Item {
/// referencing variables. /// referencing variables.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement { pub enum Statement {
Expression(Expression), Open(Expression),
} }
impl Statement { impl Statement {
@ -188,15 +183,13 @@ impl Statement {
} else { } else {
node node
}; };
let child = node.child(0).unwrap(); let child = node.child(0).unwrap();
match node.kind() { match node.kind() {
"expression" => Ok(Self::Expression(Expression::new(child, source)?)), "open_statement" => Ok(Self::Open(Expression::new(child, source)?)),
_ => Err(Error::UnexpectedSourceNode { _ => Err(Error::UnexpectedSourceNode {
expected: "expression", expected: "open_statement",
actual: node.kind(), actual: node.kind(),
location: node.start_position(),
}), }),
} }
} }
@ -208,7 +201,7 @@ impl Statement {
source: &str, source: &str,
) -> Result<Value> { ) -> Result<Value> {
match self { 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 { pub enum Expression {
Identifier(String), Identifier(String),
Value(Value), Value(Value),
Operation(Box<Operation>),
ControlFlow(Box<ControlFlow>), 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 { impl Expression {
@ -259,19 +229,18 @@ impl Expression {
Ok(Self::Identifier(identifier.to_string())) Ok(Self::Identifier(identifier.to_string()))
} else if node.kind() == "value" { } else if node.kind() == "value" {
Ok(Expression::Value(Value::new(node, source)?)) 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" { } else if node.kind() == "control_flow" {
Ok(Expression::ControlFlow(Box::new(ControlFlow::new( Ok(Expression::ControlFlow(Box::new(ControlFlow::new(
node, source, node, source,
)?))) )?)))
} else if node.kind() == "assignment" {
Ok(Expression::Assignment(Box::new(Assignment::new(
node, source,
)?)))
} else { } else {
Err(Error::UnexpectedSourceNode { Err(Error::UnexpectedSourceNode {
expected: "identifier, operation, control_flow, assignment or value", expected: "identifier, operation, control_flow or value",
actual: node.kind(), actual: node.kind(),
location: node.start_position(),
}) })
} }
} }
@ -293,12 +262,64 @@ impl Expression {
} }
} }
Expression::Value(value) => Ok(value.clone()), 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::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)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct ControlFlow { pub struct ControlFlow {
if_expression: Expression, if_expression: Expression,
@ -354,23 +375,14 @@ mod tests {
#[test] #[test]
fn evaluate_empty() { fn evaluate_empty() {
assert_eq!(eval(""), vec![]); assert_eq!(eval("()"), vec![Ok(Value::Empty)]);
assert_eq!(eval("x = 9"), vec![]); assert_eq!(eval("x = 9"), vec![Ok(Value::Empty)]);
assert_eq!(eval("'foo' + 'bar'"), vec![]); assert_eq!(eval("y = 'foobar'"), vec![Ok(Value::Empty)]);
} }
#[test] #[test]
fn evaluate_integer() { fn evaluate_integer() {
assert_eq!(eval("1"), vec![Ok(Value::Integer(1))]); 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] #[test]

View File

@ -9,7 +9,9 @@ use eframe::{
}; };
use egui_extras::{Column, StripBuilder, TableBuilder}; use egui_extras::{Column, StripBuilder, TableBuilder};
use crate::{Error, Result, Table, Tool, ToolInfo, Value, ValueType, VariableMap}; use crate::{
eval_with_context, Error, Result, Table, Tool, ToolInfo, Value, ValueType, VariableMap,
};
pub struct BarGraph; pub struct BarGraph;
@ -169,7 +171,7 @@ impl eframe::App for PlotGui {
pub struct GuiApp { pub struct GuiApp {
text_edit_buffer: String, text_edit_buffer: String,
_whale_context: VariableMap, whale_context: VariableMap,
eval_result: Result<Value>, eval_result: Result<Value>,
} }
@ -177,7 +179,7 @@ impl GuiApp {
pub fn new(result: Result<Value>) -> Self { pub fn new(result: Result<Value>) -> Self {
GuiApp { GuiApp {
text_edit_buffer: String::new(), text_edit_buffer: String::new(),
_whale_context: VariableMap::new(), whale_context: VariableMap::new(),
eval_result: result, eval_result: result,
} }
} }

View File

@ -22,7 +22,7 @@ impl Function {
todo!() todo!()
} }
pub fn run_with_context(&self, _context: &mut VariableMap) -> Result<Value> { pub fn run_with_context(&self, context: &mut VariableMap) -> Result<Value> {
todo!() todo!()
} }
} }

View File

@ -187,7 +187,6 @@ impl Value {
_ => Err(Error::UnexpectedSourceNode { _ => Err(Error::UnexpectedSourceNode {
expected: "integer, string, boolean, float, list or empty", expected: "integer, string, boolean, float, list or empty",
actual: node.kind(), actual: node.kind(),
location: node.start_position(),
}), }),
} }
} }