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 {
if count % 3 == 0 && count % 5 == 0 {
(output 'fizzbuzz')
} else f count % 3 == 0 {
(output 'fizz')
} else if count % 5 == 0 {
(output 'buzz')
} else
while count <= 15 {
(output count)
if count % 3 == 0 {
(output 'fizz')
}
if count % 5 == 0 {
(output 'buzz')
}
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 tree_sitter::Node;
use crate::{AbstractTree, Result, Value, VariableMap};
use crate::{AbstractTree, Error, Result, Value, VariableMap};
use super::{identifier::Identifier, statement::Statement};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment {
identifier: Identifier,
operator: AssignmentOperator,
statement: Statement,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum AssignmentOperator {
Equal,
PlusEqual,
MinusEqual,
}
impl AbstractTree for Assignment {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> {
let identifier_node = node.child(0).unwrap();
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 = Statement::from_syntax_node(statement_node, source)?;
Ok(Assignment {
identifier,
operator,
statement,
})
}
fn run(&self, context: &mut VariableMap) -> Result<Value> {
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)?;

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
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};
@ -12,7 +12,6 @@ pub enum Expression {
Math(Box<Math>),
Logic(Box<Logic>),
FunctionCall(FunctionCall),
ToolCall(Box<Tool>),
}
impl AbstractTree for Expression {
@ -29,7 +28,6 @@ impl AbstractTree for Expression {
"function_call" => {
Expression::FunctionCall(FunctionCall::from_syntax_node(child, source)?)
}
"tool_call" => Expression::ToolCall(Box::new(Tool::from_syntax_node(child, source)?)),
_ => {
return Err(Error::UnexpectedSyntax {
expected: "value, identifier, math or function_call",
@ -50,7 +48,6 @@ impl AbstractTree for Expression {
Expression::Math(math) => math.run(context),
Expression::Logic(logic) => logic.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 tree_sitter::Node;
use crate::{AbstractTree, Result, Value, VariableMap};
use crate::{tool::Tool, AbstractTree, Result, Value, VariableMap};
use super::{expression::Expression, identifier::Identifier};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct FunctionCall {
identifier: Identifier,
expressions: Vec<Expression>,
name: FunctionName,
arguments: Vec<Expression>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum FunctionName {
Identifier(Identifier),
Tool(Tool),
}
impl AbstractTree for FunctionCall {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> {
debug_assert_eq!("function_call", node.kind());
let identifier_node = node.child(1).unwrap();
let identifier = Identifier::from_syntax_node(identifier_node, source)?;
let name_node = node.child(1).unwrap();
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;
while current_index < node.child_count() - 1 {
let expression_node = node.child(current_index).unwrap();
let expression = Expression::from_syntax_node(expression_node, source)?;
expressions.push(expression);
arguments.push(expression);
current_index += 1;
}
Ok(FunctionCall {
identifier,
expressions,
})
Ok(FunctionCall { name, arguments })
}
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())? {
value.as_function().cloned()?
} else {
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 {
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());
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))
definition.body().run(&mut function_context)
}
}

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
/// referencing variables.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Item {
Comment(String),
Statement(Statement),
pub struct Item {
statements: Vec<Statement>,
}
impl Item {
pub fn new(statements: Vec<Statement>) -> Self {
Self { statements }
}
}
impl AbstractTree for Item {
fn from_syntax_node(node: Node, source: &str) -> Result<Self> {
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" {
let byte_range = child.byte_range();
let comment_text = &source[byte_range];
for index in 0..child_count {
let child = node.child(index).unwrap();
Ok(Item::Comment(comment_text.to_string()))
} else if child.kind() == "statement" {
Ok(Item::Statement(Statement::from_syntax_node(child, source)?))
} else {
Err(Error::UnexpectedSyntax {
let statement = match child.kind() {
"statement" => Statement::from_syntax_node(child, source)?,
_ => {
return Err(Error::UnexpectedSyntax {
expected: "comment or statement",
actual: child.kind(),
location: child.start_position(),
relevant_source: source[node.byte_range()].to_string(),
})
}
};
statements.push(statement);
}
Ok(Item { statements })
}
fn run(&self, context: &mut VariableMap) -> Result<Value> {
match self {
Item::Comment(text) => Ok(Value::String(text.clone())),
Item::Statement(statement) => statement.run(context),
let mut prev_result = Ok(Value::Empty);
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::And,
"||" => LogicOperator::Or,
">" => LogicOperator::Greater,
"<" => LogicOperator::Less,
">=" => LogicOperator::GreaterOrEqual,
"<=" => LogicOperator::LessOrEqaul,
_ => {
return Err(Error::UnexpectedSyntax {
expected: "==, && or ||",
@ -41,15 +45,25 @@ impl AbstractTree for Logic {
}
fn run(&self, context: &mut VariableMap) -> Result<Value> {
let left_value = self.left.run(context)?;
let right_value = self.right.run(context)?;
let outcome = match self.operator {
LogicOperator::Equal => left_value == right_value,
LogicOperator::And => left_value.as_boolean()? && right_value.as_boolean()?,
LogicOperator::Or => left_value.as_boolean()? || right_value.as_boolean()?,
let left = self.left.run(context)?;
let right = self.right.run(context)?;
let result = match self.operator {
LogicOperator::Equal => {
if let (Ok(left_num), Ok(right_num)) = (left.as_number(), right.as_number()) {
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,
And,
Or,
Greater,
Less,
GreaterOrEqual,
LessOrEqaul,
}

View File

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

View File

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

View File

@ -1,11 +1,11 @@
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)]
pub struct While {
expression: Expression,
item: Item,
items: Vec<Item>,
}
impl AbstractTree for While {
@ -15,15 +15,24 @@ impl AbstractTree for While {
let expression_node = node.child(1).unwrap();
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)?;
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()? {
self.item.run(context)?;
for item in &self.items {
item.run(context)?;
}
}
Ok(crate::Value::Empty)
@ -36,9 +45,6 @@ mod tests {
#[test]
fn evalualate_while_loop() {
assert_eq!(
evaluate("while false { 'foo' }"),
vec![Ok(crate::Value::Empty)]
)
assert_eq!(evaluate("while false { 'foo' }"), Ok(crate::Value::Empty))
}
}

View File

@ -19,7 +19,7 @@ use crate::{abstract_tree::item::Item, language, AbstractTree, Result, Value, Va
/// # use dust::*;
/// 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();
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))]
/// );
/// ```
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();
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 root_node = cursor.node();
let item_count = root_node.child_count();
let mut results = Vec::with_capacity(item_count);
let mut prev_result = Ok(Value::Empty);
for item_node in root_node.children(&mut cursor) {
let item_result = Item::from_syntax_node(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)),
}
let item = Item::from_syntax_node(item_node, self.source)?;
prev_result = item.run(self.context);
}
results
prev_result
}
}
@ -114,49 +105,34 @@ mod tests {
#[test]
fn evaluate_empty() {
assert_eq!(evaluate("x = 9"), vec![Ok(Value::Empty)]);
assert_eq!(evaluate("x = 1 + 1"), vec![Ok(Value::Empty)]);
assert_eq!(evaluate("x = 9"), Ok(Value::Empty));
assert_eq!(evaluate("x = 1 + 1"), Ok(Value::Empty));
}
#[test]
fn evaluate_integer() {
assert_eq!(evaluate("1"), vec![Ok(Value::Integer(1))]);
assert_eq!(evaluate("123"), vec![Ok(Value::Integer(123))]);
assert_eq!(evaluate("-666"), vec![Ok(Value::Integer(-666))]);
assert_eq!(evaluate("1"), Ok(Value::Integer(1)));
assert_eq!(evaluate("123"), Ok(Value::Integer(123)));
assert_eq!(evaluate("-666"), Ok(Value::Integer(-666)));
}
#[test]
fn evaluate_float() {
assert_eq!(evaluate("0.1"), vec![Ok(Value::Float(0.1))]);
assert_eq!(evaluate("12.3"), vec![Ok(Value::Float(12.3))]);
assert_eq!(evaluate("-6.66"), vec![Ok(Value::Float(-6.66))]);
assert_eq!(evaluate("0.1"), Ok(Value::Float(0.1)));
assert_eq!(evaluate("12.3"), Ok(Value::Float(12.3)));
assert_eq!(evaluate("-6.66"), Ok(Value::Float(-6.66)));
}
#[test]
fn evaluate_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!(
evaluate("`'one'`"),
vec![Ok(Value::String("'one'".to_string()))]
);
assert_eq!(
evaluate("'`one`'"),
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!(evaluate("`one`"), 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!(
evaluate("\"'one'\""),
vec![Ok(Value::String("'one'".to_string()))]
Ok(Value::String("'one'".to_string()))
);
}
@ -164,11 +140,11 @@ mod tests {
fn evaluate_list() {
assert_eq!(
evaluate("[1, 2, 'foobar']"),
vec![Ok(Value::List(vec![
Ok(Value::List(vec![
Value::Integer(1),
Value::Integer(2),
Value::String("foobar".to_string()),
]))]
]))
);
}
@ -180,7 +156,7 @@ mod tests {
map.set_value("foo".to_string(), Value::String("bar".to_string()))
.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]
@ -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() {
assert_eq!(
evaluate("if true then 'true'"),
vec![Ok(Value::String("true".to_string()))]
Ok(Value::String("true".to_string()))
);
}
#[test]
fn evaluate_if_then_else() {
assert_eq!(
evaluate("if false then 1 else 2"),
vec![Ok(Value::Integer(2))]
);
assert_eq!(evaluate("if false then 1 else 2"), Ok(Value::Integer(2)));
assert_eq!(
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'
"
),
vec![Ok(Value::String("ok".to_string()))]
Ok(Value::String("ok".to_string()))
);
}
@ -264,7 +237,7 @@ mod tests {
else 'ok'
"
),
vec![Ok(Value::String("ok".to_string()))]
Ok(Value::String("ok".to_string()))
);
}
@ -272,14 +245,14 @@ mod tests {
fn evaluate_function() {
let function = Function::new(
vec![Identifier::new("message".to_string())],
vec![Item::Statement(Statement::Expression(
Expression::Identifier(Identifier::new("message".to_string())),
))],
Item::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("message".to_string()),
))]),
);
assert_eq!(
evaluate("function <message> { message }"),
vec![Ok(Value::Function(function))]
Ok(Value::Function(function))
);
}
@ -295,15 +268,12 @@ mod tests {
",
&mut context
),
vec![
Ok(Value::Empty),
Ok(Value::List(vec![Value::String("Hiya".to_string())]))
]
Ok(Value::String("Hiya".to_string()))
);
}
#[test]
fn evaluate_tool_call() {
assert_eq!(evaluate("(output 'Hiya')"), vec![Ok(Value::Empty)]);
assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty));
}
}

View File

@ -32,22 +32,20 @@ fn main() {
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();
evaluate(&file_contents)
} else if let Some(command) = args.command {
evaluate(&command)
} else {
vec![Ok(Value::Empty)]
Ok(Value::Empty)
};
for result in eval_results {
match result {
match eval_result {
Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"),
}
}
}
#[derive(Helper, Completer, Validator)]
@ -143,21 +141,15 @@ fn run_cli_shell() {
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 result {
match eval_result {
Ok(value) => println!("{value}"),
Err(error) => eprintln!("{error}"),
}
}
}
Err(ReadlineError::Interrupted) => {
break;
}
Err(ReadlineError::Eof) => {
break;
}
Err(ReadlineError::Interrupted) => break,
Err(ReadlineError::Eof) => break,
Err(error) => eprintln!("{error}"),
}
}

View File

@ -7,11 +7,11 @@ use crate::{Identifier, Item};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function {
parameters: Vec<Identifier>,
body: Vec<Item>,
body: Item,
}
impl Function {
pub fn new(identifiers: Vec<Identifier>, items: Vec<Item>) -> Self {
pub fn new(identifiers: Vec<Identifier>, items: Item) -> Self {
Function {
parameters: identifiers,
body: items,
@ -22,7 +22,7 @@ impl Function {
&self.parameters
}
pub fn items(&self) -> &Vec<Item> {
pub fn body(&self) -> &Item {
&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,
fmt::{self, Display, Formatter},
marker::PhantomData,
ops::{Add, Sub},
ops::{Add, AddAssign, Sub, SubAssign},
};
pub mod function;
pub mod iter;
pub mod table;
pub mod value_type;
pub mod variable_map;
@ -157,13 +156,11 @@ impl Value {
"function" => {
let child_count = child.child_count();
let mut identifiers = Vec::new();
let mut items = Vec::new();
let mut item = None;
for index in 0..child_count {
let child = child.child(index).unwrap();
println!("{child:?}");
if child.kind() == "identifier" {
let identifier = Identifier::from_syntax_node(child, source)?;
@ -171,13 +168,11 @@ impl Value {
}
if child.kind() == "item" {
let item = Item::from_syntax_node(child, source)?;
items.push(item)
item = Some(Item::from_syntax_node(child, source)?);
}
}
Ok(Value::Function(Function::new(identifiers, items)))
Ok(Value::Function(Function::new(identifiers, item.unwrap())))
}
_ => Err(Error::UnexpectedSyntax {
expected: "string, integer, float, boolean, list, table, map, function or empty",
@ -370,54 +365,67 @@ impl Add for Value {
type Output = Result<Value>;
fn add(self, other: Self) -> Self::Output {
match (self, other) {
(Value::String(left), Value::String(right)) => {
let concatenated = left + &right;
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,
};
Ok(Value::String(concatenated))
}
(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(),
)),
}
Err(Error::ExpectedNumber { actual: non_number })
}
}
impl Sub for Value {
type Output = Result<Self>;
fn sub(self, _other: Self) -> Self::Output {
todo!()
fn sub(self, other: Self) -> Self::Output {
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() {
let file_contents = read_to_string("examples/collections.ds").unwrap();
for result in evaluate(&file_contents) {
result.unwrap();
}
evaluate(&file_contents).unwrap();
}
#[test]
fn list() {
let file_contents = read_to_string("examples/list.ds").unwrap();
for result in evaluate(&file_contents) {
result.unwrap();
}
evaluate(&file_contents).unwrap();
}
#[test]
fn table() {
let file_contents = read_to_string("examples/table.ds").unwrap();
for result in evaluate(&file_contents) {
result.unwrap();
}
evaluate(&file_contents).unwrap();
}
#[test]
fn variables() {
let file_contents = read_to_string("examples/variables.ds").unwrap();
for result in evaluate(&file_contents) {
result.unwrap();
}
evaluate(&file_contents).unwrap();
}
#[test]
fn scope() {
let file_contents = read_to_string("examples/scope.ds").unwrap();
for result in evaluate(&file_contents) {
result.unwrap();
}
evaluate(&file_contents).unwrap();
}
#[test]
fn data_formats() {
let file_contents = read_to_string("examples/data_formats.ds").unwrap();
for result in evaluate(&file_contents) {
result.unwrap();
}
evaluate(&file_contents).unwrap();
}

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