1
0

Implement new grammar

This commit is contained in:
Jeff 2023-10-09 15:54:47 -04:00
parent fd9a4c04cb
commit 39692b3bd7
18 changed files with 329 additions and 313 deletions

11
examples/fibonacci.ds Normal file
View File

@ -0,0 +1,11 @@
fibonacci = function <i> {
if i <= 1 {
1
} else if i == 2 {
2
} else {
output (fibonacci - 1) + (fibonacci - 2)
}
}
(fibonacci 20)

View File

@ -1,31 +1,15 @@
fizzbuzz_basic = function <limit> {
count = 1 count = 1
while count < limit { while count <= 15 {
if count % 3 == 0 && count % 5 == 0 {
(output 'fizzbuzz')
} else f count % 3 == 0 {
(output 'fizz')
} else if count % 5 == 0 {
(output 'buzz')
} else
(output count) (output count)
if count % 3 == 0 {
(output 'fizz')
}
if count % 5 == 0 {
(output 'buzz')
}
count += 1 count += 1
} }
}
fizzbuzz_match <limit> {
count = 1
while count < 1 {
output match [count % 3 == 0, count % 5 == 0] {
[true, false] => 'fizz'
[false, true] => 'buzz'
[true, true] => 'fizzbuzz'
}
}
}
fizzbuzz_basic<15>
fizzbuzz_match<15>

9
examples/hello_world.ds Normal file
View File

@ -0,0 +1,9 @@
(output 'Hello, world!')
main = function <message> {
while 1 == 1 {
(output message)
}
}
(main 'Hello dust ~*')

View File

@ -1,33 +1,71 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Result, Value, VariableMap}; use crate::{AbstractTree, Error, Result, Value, VariableMap};
use super::{identifier::Identifier, statement::Statement}; use super::{identifier::Identifier, statement::Statement};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment { pub struct Assignment {
identifier: Identifier, identifier: Identifier,
operator: AssignmentOperator,
statement: Statement, statement: Statement,
} }
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum AssignmentOperator {
Equal,
PlusEqual,
MinusEqual,
}
impl AbstractTree for Assignment { impl AbstractTree for Assignment {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> { fn from_syntax_node(node: Node, source: &str) -> Result<Self> {
let identifier_node = node.child(0).unwrap(); let identifier_node = node.child(0).unwrap();
let identifier = Identifier::from_syntax_node(identifier_node, source)?; let identifier = Identifier::from_syntax_node(identifier_node, source)?;
let operator_node = node.child(1).unwrap().child(0).unwrap();
let operator = match operator_node.kind() {
"=" => AssignmentOperator::Equal,
"+=" => AssignmentOperator::PlusEqual,
"-=" => AssignmentOperator::MinusEqual,
_ => {
return Err(Error::UnexpectedSyntax {
expected: "=, += or -=",
actual: operator_node.kind(),
location: operator_node.start_position(),
relevant_source: source[node.byte_range()].to_string(),
})
}
};
let statement_node = node.child(2).unwrap(); let statement_node = node.child(2).unwrap();
let statement = Statement::from_syntax_node(statement_node, source)?; let statement = Statement::from_syntax_node(statement_node, source)?;
Ok(Assignment { Ok(Assignment {
identifier, identifier,
operator,
statement, statement,
}) })
} }
fn run(&self, context: &mut VariableMap) -> Result<Value> { fn run(&self, context: &mut VariableMap) -> Result<Value> {
let key = self.identifier.clone().take_inner(); let key = self.identifier.clone().take_inner();
let value = self.statement.run(context)?; let mut value = self.statement.run(context)?;
match self.operator {
AssignmentOperator::PlusEqual => {
if let Some(previous_value) = context.get_value(&key)? {
value += previous_value
}
}
AssignmentOperator::MinusEqual => {
if let Some(previous_value) = context.get_value(&key)? {
value -= previous_value
}
}
AssignmentOperator::Equal => {}
}
context.set_value(key, value)?; context.set_value(key, value)?;

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{tool::Tool, AbstractTree, Error, Identifier, Result, Value, VariableMap}; use crate::{AbstractTree, Error, Identifier, Result, Value, VariableMap};
use super::{function_call::FunctionCall, logic::Logic, math::Math}; use super::{function_call::FunctionCall, logic::Logic, math::Math};
@ -12,7 +12,6 @@ pub enum Expression {
Math(Box<Math>), Math(Box<Math>),
Logic(Box<Logic>), Logic(Box<Logic>),
FunctionCall(FunctionCall), FunctionCall(FunctionCall),
ToolCall(Box<Tool>),
} }
impl AbstractTree for Expression { impl AbstractTree for Expression {
@ -29,7 +28,6 @@ impl AbstractTree for Expression {
"function_call" => { "function_call" => {
Expression::FunctionCall(FunctionCall::from_syntax_node(child, source)?) Expression::FunctionCall(FunctionCall::from_syntax_node(child, source)?)
} }
"tool_call" => Expression::ToolCall(Box::new(Tool::from_syntax_node(child, source)?)),
_ => { _ => {
return Err(Error::UnexpectedSyntax { return Err(Error::UnexpectedSyntax {
expected: "value, identifier, math or function_call", expected: "value, identifier, math or function_call",
@ -50,7 +48,6 @@ impl AbstractTree for Expression {
Expression::Math(math) => math.run(context), Expression::Math(math) => math.run(context),
Expression::Logic(logic) => logic.run(context), Expression::Logic(logic) => logic.run(context),
Expression::FunctionCall(function_call) => function_call.run(context), Expression::FunctionCall(function_call) => function_call.run(context),
Expression::ToolCall(tool_call) => tool_call.run(context),
} }
} }
} }

View File

@ -1,72 +1,89 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Result, Value, VariableMap}; use crate::{tool::Tool, AbstractTree, Result, Value, VariableMap};
use super::{expression::Expression, identifier::Identifier}; use super::{expression::Expression, identifier::Identifier};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct FunctionCall { pub struct FunctionCall {
identifier: Identifier, name: FunctionName,
expressions: Vec<Expression>, arguments: Vec<Expression>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum FunctionName {
Identifier(Identifier),
Tool(Tool),
} }
impl AbstractTree for FunctionCall { impl AbstractTree for FunctionCall {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> { fn from_syntax_node(node: Node, source: &str) -> Result<Self> {
debug_assert_eq!("function_call", node.kind()); debug_assert_eq!("function_call", node.kind());
let identifier_node = node.child(1).unwrap(); let name_node = node.child(1).unwrap();
let identifier = Identifier::from_syntax_node(identifier_node, source)?;
let mut expressions = Vec::new(); let name = match name_node.kind() {
"identifier" => {
FunctionName::Identifier(Identifier::from_syntax_node(name_node, source)?)
}
"tool" => {
let tool_node = name_node.child(0).unwrap();
let tool = match tool_node.kind() {
"output" => Tool::Output,
"read" => Tool::Read,
_ => panic!(""),
};
FunctionName::Tool(tool)
}
_ => panic!(""),
};
let mut arguments = Vec::new();
let mut current_index = 2; let mut current_index = 2;
while current_index < node.child_count() - 1 { while current_index < node.child_count() - 1 {
let expression_node = node.child(current_index).unwrap(); let expression_node = node.child(current_index).unwrap();
let expression = Expression::from_syntax_node(expression_node, source)?; let expression = Expression::from_syntax_node(expression_node, source)?;
expressions.push(expression); arguments.push(expression);
current_index += 1; current_index += 1;
} }
Ok(FunctionCall { Ok(FunctionCall { name, arguments })
identifier,
expressions,
})
} }
fn run(&self, context: &mut VariableMap) -> Result<Value> { fn run(&self, context: &mut VariableMap) -> Result<Value> {
let identifier = &self.identifier; let identifier = match &self.name {
FunctionName::Identifier(identifier) => identifier,
FunctionName::Tool(tool) => {
let value = self
.arguments
.first()
.map(|expression| expression.run(context))
.unwrap_or(Ok(Value::Empty))?;
return tool.run(&value);
}
};
let definition = if let Some(value) = context.get_value(identifier.inner())? { let definition = if let Some(value) = context.get_value(identifier.inner())? {
value.as_function().cloned()? value.as_function().cloned()?
} else { } else {
return Err(crate::Error::FunctionIdentifierNotFound(identifier.clone())); return Err(crate::Error::FunctionIdentifierNotFound(identifier.clone()));
}; };
let id_expr_pairs = definition.identifiers().iter().zip(self.expressions.iter()); let id_expr_pairs = definition.identifiers().iter().zip(self.arguments.iter());
let mut function_context = context.clone();
for (identifier, expression) in id_expr_pairs { for (identifier, expression) in id_expr_pairs {
let key = identifier.clone().take_inner(); let key = identifier.clone().take_inner();
let value = expression.run(context)?; let value = expression.run(&mut function_context)?;
context.set_value(key, value)?; function_context.set_value(key, value)?;
} }
let mut results = Vec::with_capacity(self.expressions.len()); definition.body().run(&mut function_context)
for item in definition.items() {
let result = item.run(context)?;
results.push(result);
}
for identifier in definition.identifiers() {
let key = identifier.inner();
context.remove(&key);
}
Ok(Value::List(results))
} }
} }

View File

@ -11,38 +11,52 @@ use crate::{AbstractTree, Error, Result, Statement, Value, VariableMap};
/// to produce a single value or interact with a context by creating or /// to produce a single value or interact with a context by creating or
/// referencing variables. /// referencing variables.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Item { pub struct Item {
Comment(String), statements: Vec<Statement>,
Statement(Statement), }
impl Item {
pub fn new(statements: Vec<Statement>) -> Self {
Self { statements }
}
} }
impl AbstractTree for Item { impl AbstractTree for Item {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> { fn from_syntax_node(node: Node, source: &str) -> Result<Self> {
debug_assert_eq!("item", node.kind()); debug_assert_eq!("item", node.kind());
let child = node.child(0).unwrap(); let child_count = node.child_count();
let mut statements = Vec::with_capacity(child_count);
if child.kind() == "comment" { for index in 0..child_count {
let byte_range = child.byte_range(); let child = node.child(index).unwrap();
let comment_text = &source[byte_range];
Ok(Item::Comment(comment_text.to_string())) let statement = match child.kind() {
} else if child.kind() == "statement" { "statement" => Statement::from_syntax_node(child, source)?,
Ok(Item::Statement(Statement::from_syntax_node(child, source)?)) _ => {
} else { return Err(Error::UnexpectedSyntax {
Err(Error::UnexpectedSyntax {
expected: "comment or statement", expected: "comment or statement",
actual: child.kind(), actual: child.kind(),
location: child.start_position(), location: child.start_position(),
relevant_source: source[node.byte_range()].to_string(), relevant_source: source[node.byte_range()].to_string(),
}) })
} }
};
statements.push(statement);
}
Ok(Item { statements })
} }
fn run(&self, context: &mut VariableMap) -> Result<Value> { fn run(&self, context: &mut VariableMap) -> Result<Value> {
match self { let mut prev_result = Ok(Value::Empty);
Item::Comment(text) => Ok(Value::String(text.clone())),
Item::Statement(statement) => statement.run(context), for statement in &self.statements {
} prev_result?;
prev_result = statement.run(context);
}
prev_result
} }
} }

View File

@ -20,6 +20,10 @@ impl AbstractTree for Logic {
"==" => LogicOperator::Equal, "==" => LogicOperator::Equal,
"&&" => LogicOperator::And, "&&" => LogicOperator::And,
"||" => LogicOperator::Or, "||" => LogicOperator::Or,
">" => LogicOperator::Greater,
"<" => LogicOperator::Less,
">=" => LogicOperator::GreaterOrEqual,
"<=" => LogicOperator::LessOrEqaul,
_ => { _ => {
return Err(Error::UnexpectedSyntax { return Err(Error::UnexpectedSyntax {
expected: "==, && or ||", expected: "==, && or ||",
@ -41,15 +45,25 @@ impl AbstractTree for Logic {
} }
fn run(&self, context: &mut VariableMap) -> Result<Value> { fn run(&self, context: &mut VariableMap) -> Result<Value> {
let left_value = self.left.run(context)?; let left = self.left.run(context)?;
let right_value = self.right.run(context)?; let right = self.right.run(context)?;
let outcome = match self.operator { let result = match self.operator {
LogicOperator::Equal => left_value == right_value, LogicOperator::Equal => {
LogicOperator::And => left_value.as_boolean()? && right_value.as_boolean()?, if let (Ok(left_num), Ok(right_num)) = (left.as_number(), right.as_number()) {
LogicOperator::Or => left_value.as_boolean()? || right_value.as_boolean()?, left_num == right_num
} else {
left == right
}
}
LogicOperator::And => left.as_boolean()? && right.as_boolean()?,
LogicOperator::Or => left.as_boolean()? || right.as_boolean()?,
LogicOperator::Greater => left > right,
LogicOperator::Less => left < right,
LogicOperator::GreaterOrEqual => left >= right,
LogicOperator::LessOrEqaul => left <= right,
}; };
Ok(Value::Boolean(outcome)) Ok(Value::Boolean(result))
} }
} }
@ -58,4 +72,8 @@ pub enum LogicOperator {
Equal, Equal,
And, And,
Or, Or,
Greater,
Less,
GreaterOrEqual,
LessOrEqaul,
} }

View File

@ -2,21 +2,20 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{ use crate::{
r#while::While, tool::Tool, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, r#while::While, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, Value,
Value, VariableMap, VariableMap,
}; };
/// Abstract representation of a statement. /// Abstract representation of a statement.
/// ///
/// Items are either comments, which do nothing, or statements, which can be run /// A statement may evaluate to an Empty value when run. If a Statement is an
/// to produce a single value or interact with their context. /// Expression, it will always return a non-empty value when run.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement { pub enum Statement {
Assignment(Box<Assignment>), Assignment(Box<Assignment>),
Expression(Expression), Expression(Expression),
IfElse(Box<IfElse>), IfElse(Box<IfElse>),
Match(Match), Match(Match),
Tool(Tool),
While(Box<While>), While(Box<While>),
} }
@ -57,7 +56,6 @@ impl AbstractTree for Statement {
Statement::Expression(expression) => expression.run(context), Statement::Expression(expression) => expression.run(context),
Statement::IfElse(if_else) => if_else.run(context), Statement::IfElse(if_else) => if_else.run(context),
Statement::Match(r#match) => r#match.run(context), Statement::Match(r#match) => r#match.run(context),
Statement::Tool(tool) => tool.run(context),
Statement::While(r#while) => r#while.run(context), Statement::While(r#while) => r#while.run(context),
} }
} }

View File

@ -1,43 +1,30 @@
use serde::{Deserialize, Serialize}; use std::fs::read_to_string;
use tree_sitter::Node;
use crate::{AbstractTree, Error, Expression, Result, Value, VariableMap}; use serde::{Deserialize, Serialize};
use crate::{Result, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Tool { pub enum Tool {
Output(Expression), Output,
Read,
} }
impl AbstractTree for Tool { impl Tool {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> { pub fn run(&self, value: &Value) -> Result<Value> {
let tool_node = node.child(1).unwrap(); let value = match self {
let tool_name = tool_node.kind(); Tool::Output => {
println!("{value}");
match tool_name { Value::Empty
"output" => { }
let expression_node = tool_node.child(1).unwrap(); Tool::Read => {
let expression = Expression::from_syntax_node(expression_node, source)?; let file_contents = read_to_string(value.as_string()?)?;
Ok(Tool::Output(expression)) Value::String(file_contents)
}
_ => Err(Error::UnexpectedSyntax {
expected: "output",
actual: tool_name,
location: tool_node.start_position(),
relevant_source: tool_node.kind().to_string(),
}),
}
} }
};
fn run(&self, context: &mut VariableMap) -> Result<Value> { Ok(value)
match self {
Tool::Output(expression) => {
let value = expression.run(context)?;
println!("{value}")
}
}
Ok(Value::Empty)
} }
} }

View File

@ -1,11 +1,11 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{AbstractTree, Expression, Item}; use crate::{AbstractTree, Expression, Item, Result, Value, VariableMap};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct While { pub struct While {
expression: Expression, expression: Expression,
item: Item, items: Vec<Item>,
} }
impl AbstractTree for While { impl AbstractTree for While {
@ -15,15 +15,24 @@ impl AbstractTree for While {
let expression_node = node.child(1).unwrap(); let expression_node = node.child(1).unwrap();
let expression = Expression::from_syntax_node(expression_node, source)?; let expression = Expression::from_syntax_node(expression_node, source)?;
let item_node = node.child(3).unwrap(); let child_count = node.child_count();
let mut items = Vec::with_capacity(child_count);
for index in 3..child_count - 1 {
let item_node = node.child(index).unwrap();
let item = Item::from_syntax_node(item_node, source)?; let item = Item::from_syntax_node(item_node, source)?;
Ok(While { expression, item }) items.push(item);
} }
fn run(&self, context: &mut crate::VariableMap) -> crate::Result<crate::Value> { Ok(While { expression, items })
}
fn run(&self, context: &mut VariableMap) -> Result<Value> {
while self.expression.run(context)?.as_boolean()? { while self.expression.run(context)?.as_boolean()? {
self.item.run(context)?; for item in &self.items {
item.run(context)?;
}
} }
Ok(crate::Value::Empty) Ok(crate::Value::Empty)
@ -36,9 +45,6 @@ mod tests {
#[test] #[test]
fn evalualate_while_loop() { fn evalualate_while_loop() {
assert_eq!( assert_eq!(evaluate("while false { 'foo' }"), Ok(crate::Value::Empty))
evaluate("while false { 'foo' }"),
vec![Ok(crate::Value::Empty)]
)
} }
} }

View File

@ -19,7 +19,7 @@ use crate::{abstract_tree::item::Item, language, AbstractTree, Result, Value, Va
/// # use dust::*; /// # use dust::*;
/// assert_eq!(evaluate("1 + 2 + 3"), vec![Ok(Value::Integer(6))]); /// assert_eq!(evaluate("1 + 2 + 3"), vec![Ok(Value::Integer(6))]);
/// ``` /// ```
pub fn evaluate(source: &str) -> Vec<Result<Value>> { pub fn evaluate(source: &str) -> Result<Value> {
let mut context = VariableMap::new(); let mut context = VariableMap::new();
evaluate_with_context(source, &mut context) evaluate_with_context(source, &mut context)
@ -44,7 +44,7 @@ pub fn evaluate(source: &str) -> Vec<Result<Value>> {
/// vec![Ok(Value::Empty), Ok(Value::Integer(10))] /// vec![Ok(Value::Empty), Ok(Value::Integer(10))]
/// ); /// );
/// ``` /// ```
pub fn evaluate_with_context(source: &str, context: &mut VariableMap) -> Vec<Result<Value>> { pub fn evaluate_with_context(source: &str, context: &mut VariableMap) -> Result<Value> {
let mut parser = Parser::new(); let mut parser = Parser::new();
parser.set_language(language()).unwrap(); parser.set_language(language()).unwrap();
@ -80,26 +80,17 @@ impl<'context, 'code> Evaluator<'context, 'code> {
} }
} }
fn run(self) -> Vec<Result<Value>> { fn run(self) -> Result<Value> {
let mut cursor = self.syntax_tree.walk(); let mut cursor = self.syntax_tree.walk();
let root_node = cursor.node(); let root_node = cursor.node();
let item_count = root_node.child_count(); let mut prev_result = Ok(Value::Empty);
let mut results = Vec::with_capacity(item_count);
for item_node in root_node.children(&mut cursor) { for item_node in root_node.children(&mut cursor) {
let item_result = Item::from_syntax_node(item_node, self.source); let item = Item::from_syntax_node(item_node, self.source)?;
prev_result = item.run(self.context);
match item_result {
Ok(item) => {
let eval_result = item.run(self.context);
results.push(eval_result);
}
Err(error) => results.push(Err(error)),
}
} }
results prev_result
} }
} }
@ -114,49 +105,34 @@ mod tests {
#[test] #[test]
fn evaluate_empty() { fn evaluate_empty() {
assert_eq!(evaluate("x = 9"), vec![Ok(Value::Empty)]); assert_eq!(evaluate("x = 9"), Ok(Value::Empty));
assert_eq!(evaluate("x = 1 + 1"), vec![Ok(Value::Empty)]); assert_eq!(evaluate("x = 1 + 1"), Ok(Value::Empty));
} }
#[test] #[test]
fn evaluate_integer() { fn evaluate_integer() {
assert_eq!(evaluate("1"), vec![Ok(Value::Integer(1))]); assert_eq!(evaluate("1"), Ok(Value::Integer(1)));
assert_eq!(evaluate("123"), vec![Ok(Value::Integer(123))]); assert_eq!(evaluate("123"), Ok(Value::Integer(123)));
assert_eq!(evaluate("-666"), vec![Ok(Value::Integer(-666))]); assert_eq!(evaluate("-666"), Ok(Value::Integer(-666)));
} }
#[test] #[test]
fn evaluate_float() { fn evaluate_float() {
assert_eq!(evaluate("0.1"), vec![Ok(Value::Float(0.1))]); assert_eq!(evaluate("0.1"), Ok(Value::Float(0.1)));
assert_eq!(evaluate("12.3"), vec![Ok(Value::Float(12.3))]); assert_eq!(evaluate("12.3"), Ok(Value::Float(12.3)));
assert_eq!(evaluate("-6.66"), vec![Ok(Value::Float(-6.66))]); assert_eq!(evaluate("-6.66"), Ok(Value::Float(-6.66)));
} }
#[test] #[test]
fn evaluate_string() { fn evaluate_string() {
assert_eq!( assert_eq!(evaluate("\"one\""), Ok(Value::String("one".to_string())));
evaluate("\"one\""), assert_eq!(evaluate("'one'"), Ok(Value::String("one".to_string())));
vec![Ok(Value::String("one".to_string()))] assert_eq!(evaluate("`one`"), Ok(Value::String("one".to_string())));
); assert_eq!(evaluate("`'one'`"), Ok(Value::String("'one'".to_string())));
assert_eq!( assert_eq!(evaluate("'`one`'"), Ok(Value::String("`one`".to_string())));
evaluate("'one'"),
vec![Ok(Value::String("one".to_string()))]
);
assert_eq!(
evaluate("`one`"),
vec![Ok(Value::String("one".to_string()))]
);
assert_eq!(
evaluate("`'one'`"),
vec![Ok(Value::String("'one'".to_string()))]
);
assert_eq!(
evaluate("'`one`'"),
vec![Ok(Value::String("`one`".to_string()))]
);
assert_eq!( assert_eq!(
evaluate("\"'one'\""), evaluate("\"'one'\""),
vec![Ok(Value::String("'one'".to_string()))] Ok(Value::String("'one'".to_string()))
); );
} }
@ -164,11 +140,11 @@ mod tests {
fn evaluate_list() { fn evaluate_list() {
assert_eq!( assert_eq!(
evaluate("[1, 2, 'foobar']"), evaluate("[1, 2, 'foobar']"),
vec![Ok(Value::List(vec![ Ok(Value::List(vec![
Value::Integer(1), Value::Integer(1),
Value::Integer(2), Value::Integer(2),
Value::String("foobar".to_string()), Value::String("foobar".to_string()),
]))] ]))
); );
} }
@ -180,7 +156,7 @@ mod tests {
map.set_value("foo".to_string(), Value::String("bar".to_string())) map.set_value("foo".to_string(), Value::String("bar".to_string()))
.unwrap(); .unwrap();
assert_eq!(evaluate("{ x = 1 foo = 'bar' }"), vec![Ok(Value::Map(map))]); assert_eq!(evaluate("{ x = 1 foo = 'bar' }"), Ok(Value::Map(map)));
} }
#[test] #[test]
@ -207,7 +183,7 @@ mod tests {
} }
" "
), ),
vec![Ok(Value::Table(table))] Ok(Value::Table(table))
); );
} }
@ -215,19 +191,16 @@ mod tests {
fn evaluate_if_then() { fn evaluate_if_then() {
assert_eq!( assert_eq!(
evaluate("if true then 'true'"), evaluate("if true then 'true'"),
vec![Ok(Value::String("true".to_string()))] Ok(Value::String("true".to_string()))
); );
} }
#[test] #[test]
fn evaluate_if_then_else() { fn evaluate_if_then_else() {
assert_eq!( assert_eq!(evaluate("if false then 1 else 2"), Ok(Value::Integer(2)));
evaluate("if false then 1 else 2"),
vec![Ok(Value::Integer(2))]
);
assert_eq!( assert_eq!(
evaluate("if true then 1.0 else 42.0"), evaluate("if true then 1.0 else 42.0"),
vec![Ok(Value::Float(1.0))] Ok(Value::Float(1.0))
); );
} }
@ -244,7 +217,7 @@ mod tests {
'ok' 'ok'
" "
), ),
vec![Ok(Value::String("ok".to_string()))] Ok(Value::String("ok".to_string()))
); );
} }
@ -264,7 +237,7 @@ mod tests {
else 'ok' else 'ok'
" "
), ),
vec![Ok(Value::String("ok".to_string()))] Ok(Value::String("ok".to_string()))
); );
} }
@ -272,14 +245,14 @@ mod tests {
fn evaluate_function() { fn evaluate_function() {
let function = Function::new( let function = Function::new(
vec![Identifier::new("message".to_string())], vec![Identifier::new("message".to_string())],
vec![Item::Statement(Statement::Expression( Item::new(vec![Statement::Expression(Expression::Identifier(
Expression::Identifier(Identifier::new("message".to_string())), Identifier::new("message".to_string()),
))], ))]),
); );
assert_eq!( assert_eq!(
evaluate("function <message> { message }"), evaluate("function <message> { message }"),
vec![Ok(Value::Function(function))] Ok(Value::Function(function))
); );
} }
@ -295,15 +268,12 @@ mod tests {
", ",
&mut context &mut context
), ),
vec![ Ok(Value::String("Hiya".to_string()))
Ok(Value::Empty),
Ok(Value::List(vec![Value::String("Hiya".to_string())]))
]
); );
} }
#[test] #[test]
fn evaluate_tool_call() { fn evaluate_tool_call() {
assert_eq!(evaluate("(output 'Hiya')"), vec![Ok(Value::Empty)]); assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty));
} }
} }

View File

@ -32,23 +32,21 @@ fn main() {
return run_cli_shell(); return run_cli_shell();
} }
let eval_results = if let Some(path) = args.path { let eval_result = if let Some(path) = args.path {
let file_contents = read_to_string(path).unwrap(); let file_contents = read_to_string(path).unwrap();
evaluate(&file_contents) evaluate(&file_contents)
} else if let Some(command) = args.command { } else if let Some(command) = args.command {
evaluate(&command) evaluate(&command)
} else { } else {
vec![Ok(Value::Empty)] Ok(Value::Empty)
}; };
for result in eval_results { match eval_result {
match result {
Ok(value) => println!("{value}"), Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"), Err(error) => eprintln!("{error}"),
} }
} }
}
#[derive(Helper, Completer, Validator)] #[derive(Helper, Completer, Validator)]
struct DustReadline { struct DustReadline {
@ -143,21 +141,15 @@ fn run_cli_shell() {
rl.add_history_entry(line).unwrap(); rl.add_history_entry(line).unwrap();
let eval_results = evaluate_with_context(line, &mut context); let eval_result = evaluate_with_context(line, &mut context);
for result in eval_results { match eval_result {
match result {
Ok(value) => println!("{value}"), Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"), Err(error) => eprintln!("{error}"),
} }
} }
} Err(ReadlineError::Interrupted) => break,
Err(ReadlineError::Interrupted) => { Err(ReadlineError::Eof) => break,
break;
}
Err(ReadlineError::Eof) => {
break;
}
Err(error) => eprintln!("{error}"), Err(error) => eprintln!("{error}"),
} }
} }

View File

@ -7,11 +7,11 @@ use crate::{Identifier, Item};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function { pub struct Function {
parameters: Vec<Identifier>, parameters: Vec<Identifier>,
body: Vec<Item>, body: Item,
} }
impl Function { impl Function {
pub fn new(identifiers: Vec<Identifier>, items: Vec<Item>) -> Self { pub fn new(identifiers: Vec<Identifier>, items: Item) -> Self {
Function { Function {
parameters: identifiers, parameters: identifiers,
body: items, body: items,
@ -22,7 +22,7 @@ impl Function {
&self.parameters &self.parameters
} }
pub fn items(&self) -> &Vec<Item> { pub fn body(&self) -> &Item {
&self.body &self.body
} }
} }

View File

@ -1,21 +0,0 @@
use crate::Value;
pub struct Iter(Value);
impl IntoIterator for Value {
type Item = Value;
type IntoIter = Iter;
fn into_iter(self) -> Self::IntoIter {
Iter(self)
}
}
impl Iterator for Iter {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}

View File

@ -17,11 +17,10 @@ use std::{
convert::TryFrom, convert::TryFrom,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
marker::PhantomData, marker::PhantomData,
ops::{Add, Sub}, ops::{Add, AddAssign, Sub, SubAssign},
}; };
pub mod function; pub mod function;
pub mod iter;
pub mod table; pub mod table;
pub mod value_type; pub mod value_type;
pub mod variable_map; pub mod variable_map;
@ -157,13 +156,11 @@ impl Value {
"function" => { "function" => {
let child_count = child.child_count(); let child_count = child.child_count();
let mut identifiers = Vec::new(); let mut identifiers = Vec::new();
let mut items = Vec::new(); let mut item = None;
for index in 0..child_count { for index in 0..child_count {
let child = child.child(index).unwrap(); let child = child.child(index).unwrap();
println!("{child:?}");
if child.kind() == "identifier" { if child.kind() == "identifier" {
let identifier = Identifier::from_syntax_node(child, source)?; let identifier = Identifier::from_syntax_node(child, source)?;
@ -171,13 +168,11 @@ impl Value {
} }
if child.kind() == "item" { if child.kind() == "item" {
let item = Item::from_syntax_node(child, source)?; item = Some(Item::from_syntax_node(child, source)?);
items.push(item)
} }
} }
Ok(Value::Function(Function::new(identifiers, items))) Ok(Value::Function(Function::new(identifiers, item.unwrap())))
} }
_ => Err(Error::UnexpectedSyntax { _ => Err(Error::UnexpectedSyntax {
expected: "string, integer, float, boolean, list, table, map, function or empty", expected: "string, integer, float, boolean, list, table, map, function or empty",
@ -370,54 +365,67 @@ impl Add for Value {
type Output = Result<Value>; type Output = Result<Value>;
fn add(self, other: Self) -> Self::Output { fn add(self, other: Self) -> Self::Output {
match (self, other) { let non_number = match (self, other) {
(Value::String(left), Value::String(right)) => { (Value::Integer(left), Value::Integer(right)) => {
let concatenated = left + &right; return Ok(Value::Integer(left + right))
}
(Value::Float(left), Value::Float(right)) => return Ok(Value::Float(left + right)),
(Value::Integer(left), Value::Float(right)) => {
return Ok(Value::Float(left as f64 + right))
}
(Value::Float(left), Value::Integer(right)) => {
return Ok(Value::Float(left + right as f64))
}
(non_number, Value::Integer(_)) | (non_number, Value::Float(_)) => non_number,
(non_number, _) => non_number,
};
Ok(Value::String(concatenated)) Err(Error::ExpectedNumber { actual: non_number })
}
(Value::String(_), other) | (other, Value::String(_)) => {
Err(Error::ExpectedString { actual: other })
}
(Value::Float(left), Value::Float(right)) => {
let addition = left + right;
Ok(Value::Float(addition))
}
(Value::Float(_), other) | (other, Value::Float(_)) => {
Err(Error::ExpectedFloat { actual: other })
}
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)),
(Value::Integer(_), other) | (other, Value::Integer(_)) => {
Err(Error::ExpectedInt { actual: other })
}
(Value::Boolean(_), Value::Boolean(_)) => {
todo!()
}
(Value::Boolean(_), other) | (other, Value::Boolean(_)) => {
Err(Error::ExpectedBoolean { actual: other })
}
(Value::List(_), Value::List(_)) => todo!(),
(Value::List(_), other) | (other, Value::List(_)) => {
Err(Error::ExpectedList { actual: other })
}
(Value::Map(_), Value::Map(_)) => todo!(),
(Value::Map(_), other) | (other, Value::Map(_)) => {
Err(Error::ExpectedMap { actual: other })
}
(Value::Empty, Value::Empty) => Ok(Value::Empty),
_ => Err(Error::CustomMessage(
"Cannot add the given types.".to_string(),
)),
}
} }
} }
impl Sub for Value { impl Sub for Value {
type Output = Result<Self>; type Output = Result<Self>;
fn sub(self, _other: Self) -> Self::Output { fn sub(self, other: Self) -> Self::Output {
todo!() let non_number = match (self, other) {
(Value::Integer(left), Value::Integer(right)) => {
return Ok(Value::Integer(left + right))
}
(Value::Float(left), Value::Float(right)) => return Ok(Value::Float(left + right)),
(Value::Integer(left), Value::Float(right)) => {
return Ok(Value::Float(left as f64 + right))
}
(Value::Float(left), Value::Integer(right)) => {
return Ok(Value::Float(left + right as f64))
}
(non_number, Value::Integer(_)) | (non_number, Value::Float(_)) => non_number,
(non_number, _) => non_number,
};
Err(Error::ExpectedNumber { actual: non_number })
}
}
impl AddAssign for Value {
fn add_assign(&mut self, other: Self) {
match (self, other) {
(Value::Integer(left), Value::Integer(right)) => *left += right,
(Value::Float(left), Value::Float(right)) => *left += right,
(Value::Float(left), Value::Integer(right)) => *left += right as f64,
_ => {}
}
}
}
impl SubAssign for Value {
fn sub_assign(&mut self, other: Self) {
match (self, other) {
(Value::Integer(left), Value::Integer(right)) => *left -= right,
(Value::Float(left), Value::Float(right)) => *left -= right,
(Value::Float(left), Value::Integer(right)) => *left -= right as f64,
_ => {}
}
} }
} }

View File

@ -6,52 +6,40 @@ use dust::*;
fn collections() { fn collections() {
let file_contents = read_to_string("examples/collections.ds").unwrap(); let file_contents = read_to_string("examples/collections.ds").unwrap();
for result in evaluate(&file_contents) { evaluate(&file_contents).unwrap();
result.unwrap();
}
} }
#[test] #[test]
fn list() { fn list() {
let file_contents = read_to_string("examples/list.ds").unwrap(); let file_contents = read_to_string("examples/list.ds").unwrap();
for result in evaluate(&file_contents) { evaluate(&file_contents).unwrap();
result.unwrap();
}
} }
#[test] #[test]
fn table() { fn table() {
let file_contents = read_to_string("examples/table.ds").unwrap(); let file_contents = read_to_string("examples/table.ds").unwrap();
for result in evaluate(&file_contents) { evaluate(&file_contents).unwrap();
result.unwrap();
}
} }
#[test] #[test]
fn variables() { fn variables() {
let file_contents = read_to_string("examples/variables.ds").unwrap(); let file_contents = read_to_string("examples/variables.ds").unwrap();
for result in evaluate(&file_contents) { evaluate(&file_contents).unwrap();
result.unwrap();
}
} }
#[test] #[test]
fn scope() { fn scope() {
let file_contents = read_to_string("examples/scope.ds").unwrap(); let file_contents = read_to_string("examples/scope.ds").unwrap();
for result in evaluate(&file_contents) { evaluate(&file_contents).unwrap();
result.unwrap();
}
} }
#[test] #[test]
fn data_formats() { fn data_formats() {
let file_contents = read_to_string("examples/data_formats.ds").unwrap(); let file_contents = read_to_string("examples/data_formats.ds").unwrap();
for result in evaluate(&file_contents) { evaluate(&file_contents).unwrap();
result.unwrap();
}
} }

@ -1 +1 @@
Subproject commit d7ff4e57c58d9ff0708dc2902262384b99c4bc2c Subproject commit 532c751c36a1f8c33197b018dd6e947b73abbdc4