diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 6c15687..98ee6b5 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -1,3 +1,11 @@ +//! Abstract, executable representations of corresponding items found in Dust +//! source code. The types that implement [AbstractTree] are inteded to be +//! created by an [Evaluator]. +//! +//! When adding new lanugage features, first extend the grammar to recognize new +//! syntax nodes. Then add a new AbstractTree type using the existing types as +//! examples. + pub mod assignment; pub mod expression; pub mod function_call; @@ -9,6 +17,7 @@ pub mod r#match; pub mod math; pub mod statement; pub mod tool; +pub mod r#while; pub use { assignment::*, expression::*, function_call::*, identifier::*, if_else::*, item::*, logic::*, diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index d3e8b5a..c84d5e0 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Node; use crate::{ - tool::Tool, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, Value, - VariableMap, + r#while::While, tool::Tool, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, + Value, VariableMap, }; /// Abstract representation of a statement. @@ -17,6 +17,7 @@ pub enum Statement { IfElse(Box), Match(Match), Tool(Tool), + While(Box), } impl AbstractTree for Statement { @@ -38,6 +39,9 @@ impl AbstractTree for Statement { "tool" => Ok(Statement::IfElse(Box::new(IfElse::from_syntax_node( child, source, )?))), + "while" => Ok(Statement::While(Box::new(While::from_syntax_node( + child, source, + )?))), _ => Err(Error::UnexpectedSyntax { expected: "assignment, expression, if...else or tool", actual: child.kind(), @@ -54,6 +58,7 @@ impl AbstractTree for Statement { Statement::IfElse(if_else) => if_else.run(context), Statement::Match(r#match) => r#match.run(context), Statement::Tool(tool) => tool.run(context), + Statement::While(r#while) => r#while.run(context), } } } diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs new file mode 100644 index 0000000..8025ea8 --- /dev/null +++ b/src/abstract_tree/while.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; + +use crate::{AbstractTree, Expression, Statement}; + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] +pub struct While { + expression: Expression, + statement: Statement, +} + +impl AbstractTree for While { + fn from_syntax_node(node: tree_sitter::Node, source: &str) -> crate::Result { + debug_assert_eq!("while", node.kind()); + + let expression_node = node.child(1).unwrap(); + let expression = Expression::from_syntax_node(expression_node, source)?; + + let statement_node = node.child(3).unwrap(); + let statement = Statement::from_syntax_node(statement_node, source)?; + + Ok(While { + expression, + statement, + }) + } + + fn run(&self, context: &mut crate::VariableMap) -> crate::Result { + while self.expression.run(context)?.as_boolean()? { + self.statement.run(context)?; + } + + Ok(crate::Value::Empty) + } +} + +#[cfg(test)] +mod tests { + use crate::evaluate; + + #[test] + fn evalualate_while_loop() { + assert_eq!( + evaluate("while false { 'foo' }"), + vec![Ok(crate::Value::Empty)] + ) + } +} diff --git a/tree-sitter-dust b/tree-sitter-dust index a3dbb19..b55420d 160000 --- a/tree-sitter-dust +++ b/tree-sitter-dust @@ -1 +1 @@ -Subproject commit a3dbb19ecc40bc49487730c7679358389307559d +Subproject commit b55420d51b8431ab9d60f46bf5be753bcf55d953