diff --git a/src/abstract_tree/expression.rs b/src/abstract_tree/expression.rs index c25268d..c18cc7f 100644 --- a/src/abstract_tree/expression.rs +++ b/src/abstract_tree/expression.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Node; -use crate::{tool::ToolCall, AbstractTree, Error, Identifier, Result, Value, VariableMap}; +use crate::{tool::Tool, AbstractTree, Error, Identifier, Result, Value, VariableMap}; use super::{function_call::FunctionCall, logic::Logic, math::Math}; @@ -12,7 +12,7 @@ pub enum Expression { Math(Box), Logic(Box), FunctionCall(FunctionCall), - ToolCall(Box), + ToolCall(Box), } impl AbstractTree for Expression { @@ -29,9 +29,7 @@ impl AbstractTree for Expression { "function_call" => { Expression::FunctionCall(FunctionCall::from_syntax_node(child, source)?) } - "tool_call" => { - Expression::ToolCall(Box::new(ToolCall::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", diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index 03f45aa..aae7faa 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -39,12 +39,28 @@ impl AbstractTree for FunctionCall { fn run(&self, context: &mut VariableMap) -> Result { let identifier = &self.identifier; let definition = if let Some(value) = context.get_value(identifier.inner())? { - value + value.as_function().cloned()? } else { return Err(crate::Error::FunctionIdentifierNotFound(identifier.clone())); }; - let mut arguments = Vec::with_capacity(self.expressions.len()); - Ok(Value::List(arguments)) + let id_expr_pairs = definition.identifiers().iter().zip(self.expressions.iter()); + + for (identifier, expression) in id_expr_pairs { + let key = identifier.clone().take_inner(); + let value = expression.run(context)?; + + context.set_value(key, value)?; + } + + let mut results = Vec::with_capacity(self.expressions.len()); + + for statement in definition.statements() { + let result = statement.run(context)?; + + results.push(result); + } + + Ok(Value::List(results)) } } diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index 5dad58a..be19a9f 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -12,11 +12,11 @@ use crate::{AbstractTree, Result, Value, VariableMap}; pub struct Match {} impl AbstractTree for Match { - fn from_syntax_node(node: Node, source: &str) -> Result { + fn from_syntax_node(_node: Node, _source: &str) -> Result { todo!() } - fn run(&self, context: &mut VariableMap) -> Result { + fn run(&self, _context: &mut VariableMap) -> Result { todo!() } } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index 2070ec2..d3e8b5a 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Node; use crate::{ - tool::ToolCall, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, Value, + tool::Tool, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, Value, VariableMap, }; @@ -16,7 +16,7 @@ pub enum Statement { Expression(Expression), IfElse(Box), Match(Match), - Tool(ToolCall), + Tool(Tool), } impl AbstractTree for Statement { diff --git a/src/abstract_tree/tool.rs b/src/abstract_tree/tool.rs index 96a248b..05a4b48 100644 --- a/src/abstract_tree/tool.rs +++ b/src/abstract_tree/tool.rs @@ -4,21 +4,21 @@ use tree_sitter::Node; use crate::{AbstractTree, Error, Expression, Result, Value, VariableMap}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] -pub enum ToolCall { +pub enum Tool { Output(Expression), } -impl AbstractTree for ToolCall { +impl AbstractTree for Tool { fn from_syntax_node(node: Node, source: &str) -> Result { let tool_node = node.child(1).unwrap(); let tool_name = tool_node.kind(); match tool_name { "output" => { - let expression_node = node.child(1).unwrap(); + let expression_node = tool_node.child(1).unwrap(); let expression = Expression::from_syntax_node(expression_node, source)?; - Ok(ToolCall::Output(expression)) + Ok(Tool::Output(expression)) } _ => Err(Error::UnexpectedSyntax { expected: "output", @@ -29,9 +29,9 @@ impl AbstractTree for ToolCall { } } - fn run(&self, context: &mut VariableMap) -> Result { + fn run(&self, context: &mut VariableMap) -> Result { match self { - ToolCall::Output(expression) => { + Tool::Output(expression) => { let value = expression.run(context)?; println!("{value}") diff --git a/src/error.rs b/src/error.rs index c78cfc9..f62831b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -283,7 +283,7 @@ impl From for Error { } impl Error { - pub(crate) fn expect_function_argument_amount( + pub(crate) fn _expect_function_argument_amount( identifier: &str, actual: usize, expected: usize, @@ -299,7 +299,7 @@ impl Error { } } - pub(crate) fn expected_minimum_function_argument_amount( + pub(crate) fn _expected_minimum_function_argument_amount( identifier: &str, actual: usize, minimum: usize, diff --git a/src/evaluator.rs b/src/evaluator.rs index a90bdad..6465c0a 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -109,9 +109,7 @@ impl<'context, 'code> Evaluator<'context, 'code> { mod tests { use crate::{ abstract_tree::{expression::Expression, identifier::Identifier, statement::Statement}, - tool::ToolCall, - value::variable_map, - Function, FunctionCall, Table, + Function, Table, }; use super::*; @@ -290,20 +288,19 @@ mod tests { #[test] fn evaluate_function_call() { let mut context = VariableMap::new(); - let function = Function::new( - vec![Identifier::new("message".to_string())], - vec![Statement::Expression(Expression::Identifier( - Identifier::new("message".to_string()), - ))], - ); - - context - .set_value("foobar".to_string(), Value::Function(function)) - .unwrap(); assert_eq!( - evaluate("(foobar 'Hiya')"), - vec![Ok(Value::String("Hiya".to_string()))] + evaluate_with_context( + " + foobar = function { message } + (foobar 'Hiya') + ", + &mut context + ), + vec![ + Ok(Value::Empty), + Ok(Value::List(vec![Value::String("Hiya".to_string())])) + ] ); } diff --git a/src/lib.rs b/src/lib.rs index 5aa59eb..6cbb42d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,7 @@ pub use crate::{ error::*, evaluator::*, value::{ - function::Function, table::Table, time::Time, value_type::ValueType, - variable_map::VariableMap, Value, + function::Function, table::Table, value_type::ValueType, variable_map::VariableMap, Value, }, }; diff --git a/src/value/function.rs b/src/value/function.rs index 0da5543..f1d7e56 100644 --- a/src/value/function.rs +++ b/src/value/function.rs @@ -17,6 +17,14 @@ impl Function { statements, } } + + pub fn identifiers(&self) -> &Vec { + &self.identifiers + } + + pub fn statements(&self) -> &Vec { + &self.statements + } } impl Display for Function { diff --git a/src/value/mod.rs b/src/value/mod.rs index 1df8893..ba56b36 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,7 +1,7 @@ //! Types that represent runtime values. use crate::{ error::{Error, Result}, - AbstractTree, Function, Identifier, Statement, Table, Time, ValueType, VariableMap, + AbstractTree, Function, Identifier, Statement, Table, ValueType, VariableMap, }; use json::JsonValue; @@ -23,7 +23,6 @@ use std::{ pub mod function; pub mod iter; pub mod table; -pub mod time; pub mod value_type; pub mod variable_map; @@ -37,7 +36,6 @@ pub enum Value { List(Vec), Map(VariableMap), Table(Table), - Time(Time), Function(Function), String(String), Float(f64), @@ -347,15 +345,6 @@ impl Value { } } - /// Borrows the value stored in `self` as `Time`, or returns `Err` if - /// `self` is not a `Value::Time`. - pub fn as_time(&self) -> Result<&Time> { - match self { - Value::Time(time) => Ok(time), - value => Err(Error::expected_function(value.clone())), - } - } - /// Returns `()`, or returns`Err` if `self` is not a `Value::Tuple`. pub fn as_empty(&self) -> Result<()> { match self { @@ -442,7 +431,6 @@ impl PartialEq for Value { (Value::List(left), Value::List(right)) => left == right, (Value::Map(left), Value::Map(right)) => left == right, (Value::Table(left), Value::Table(right)) => left == right, - (Value::Time(left), Value::Time(right)) => left == right, (Value::Function(left), Value::Function(right)) => left == right, (Value::Empty, Value::Empty) => true, _ => false, @@ -475,8 +463,6 @@ impl Ord for Value { (Value::Table(_), _) => Ordering::Greater, (Value::Function(left), Value::Function(right)) => left.cmp(right), (Value::Function(_), _) => Ordering::Greater, - (Value::Time(left), Value::Time(right)) => left.cmp(right), - (Value::Time(_), _) => Ordering::Greater, (Value::Empty, Value::Empty) => Ordering::Equal, (Value::Empty, _) => Ordering::Less, } @@ -506,7 +492,6 @@ impl Serialize for Value { Value::Map(inner) => inner.serialize(serializer), Value::Table(inner) => inner.serialize(serializer), Value::Function(inner) => inner.serialize(serializer), - Value::Time(inner) => inner.serialize(serializer), } } } @@ -529,7 +514,6 @@ impl Display for Value { Value::Map(map) => write!(f, "{map}"), Value::Table(table) => write!(f, "{table}"), Value::Function(function) => write!(f, "{function}"), - Value::Time(time) => write!(f, "{time}"), } } } diff --git a/src/value/table.rs b/src/value/table.rs index f2a70aa..331d887 100644 --- a/src/value/table.rs +++ b/src/value/table.rs @@ -279,7 +279,6 @@ impl From<&Value> for Table { table } - Value::Time(_) => todo!(), } } } diff --git a/src/value/time.rs b/src/value/time.rs deleted file mode 100644 index 67d66b3..0000000 --- a/src/value/time.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Representation of a moment in time. -//! -//! Dust tries to represent time values correctly. To do this, there must be a clear separation -//! between monotonic timestamps, naive times that do not know their locale and those that have a .. -//! timezone. -//! -//! Only monotonic time instances are guaranteed not to repeat, although an Instant can be used to -//! create and of these variants. Users generally want the timezone included, so the `as_local` is -//! included, which will use no timezone offset if one is not available. - -use std::{ - fmt::{self, Display, Formatter}, - time::{Instant, SystemTime}, -}; - -use chrono::{DateTime, FixedOffset, Local as LocalTime, NaiveDateTime}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Time { - Utc(NaiveDateTime), - Local(DateTime), - Monotonic(Instant), -} - -impl Time { - pub fn utc(instant: Instant) -> Self { - let utc = - NaiveDateTime::from_timestamp_micros(instant.elapsed().as_micros() as i64).unwrap(); - - Time::Utc(utc) - } - - pub fn from_timestamp(microseconds: i64) -> Self { - let utc = NaiveDateTime::from_timestamp_micros(microseconds).unwrap(); - - Time::Utc(utc) - } - - pub fn local(instant: Instant) -> Self { - let local = DateTime::from_local( - NaiveDateTime::from_timestamp_micros(instant.elapsed().as_micros() as i64).unwrap(), - FixedOffset::west_opt(0).unwrap(), - ); - - Time::Local(local) - } - - pub fn monotonic(instant: Instant) -> Self { - Time::Monotonic(instant) - } - - pub fn as_local(&self) -> String { - let date_time = match *self { - Time::Utc(utc) => DateTime::from_utc(utc, FixedOffset::west_opt(0).unwrap()), - Time::Local(local) => local, - Time::Monotonic(instant) => DateTime::from_utc( - NaiveDateTime::from_timestamp_millis(instant.elapsed().as_millis() as i64).unwrap(), - FixedOffset::west_opt(0).unwrap(), - ), - }; - - date_time.to_rfc2822() - } -} - -impl Display for Time { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Time::Utc(inner) => write!(f, "{}", inner), - Time::Local(inner) => write!(f, "{}", inner), - Time::Monotonic(inner) => write!(f, "{:?}", inner), - } - } -} - -impl Serialize for Time { - fn serialize(&self, _serializer: S) -> Result - where - S: serde::Serializer, - { - todo!() - } -} - -impl<'de> Deserialize<'de> for Time { - fn deserialize(_deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - todo!() - } -} - -impl From for Time { - fn from(value: SystemTime) -> Self { - Time::Local(value.into()) - } -} diff --git a/src/value/value_type.rs b/src/value/value_type.rs index 92f248a..a78ca34 100644 --- a/src/value/value_type.rs +++ b/src/value/value_type.rs @@ -107,7 +107,6 @@ impl From<&Value> for ValueType { Value::Map(_) => ValueType::Map, Value::Table { .. } => ValueType::Table, Value::Function(_) => ValueType::Function, - Value::Time(_) => ValueType::Time, } } } diff --git a/src/value/variable_map.rs b/src/value/variable_map.rs index 27c6ca6..fa114ae 100644 --- a/src/value/variable_map.rs +++ b/src/value/variable_map.rs @@ -4,7 +4,7 @@ use std::{ fmt::{self, Display, Formatter}, }; -use crate::{value::Value, AbstractTree, Error, Result, Table}; +use crate::{value::Value, Error, Result, Table}; /// A collection dust variables comprised of key-value pairs. /// diff --git a/tree-sitter-dust b/tree-sitter-dust index 03c5664..a3dbb19 160000 --- a/tree-sitter-dust +++ b/tree-sitter-dust @@ -1 +1 @@ -Subproject commit 03c566485155076983ff78689c62839c59b47327 +Subproject commit a3dbb19ecc40bc49487730c7679358389307559d