Implement function calls; Remove Time
This commit is contained in:
parent
3e87d8b322
commit
31e9cb61bb
@ -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<Math>),
|
||||
Logic(Box<Logic>),
|
||||
FunctionCall(FunctionCall),
|
||||
ToolCall(Box<ToolCall>),
|
||||
ToolCall(Box<Tool>),
|
||||
}
|
||||
|
||||
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",
|
||||
|
@ -39,12 +39,28 @@ impl AbstractTree for FunctionCall {
|
||||
fn run(&self, context: &mut VariableMap) -> Result<Value> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -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<Self> {
|
||||
fn from_syntax_node(_node: Node, _source: &str) -> Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn run(&self, context: &mut VariableMap) -> Result<Value> {
|
||||
fn run(&self, _context: &mut VariableMap) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -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<IfElse>),
|
||||
Match(Match),
|
||||
Tool(ToolCall),
|
||||
Tool(Tool),
|
||||
}
|
||||
|
||||
impl AbstractTree for Statement {
|
||||
|
@ -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<Self> {
|
||||
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<crate::Value> {
|
||||
fn run(&self, context: &mut VariableMap) -> Result<Value> {
|
||||
match self {
|
||||
ToolCall::Output(expression) => {
|
||||
Tool::Output(expression) => {
|
||||
let value = expression.run(context)?;
|
||||
|
||||
println!("{value}")
|
||||
|
@ -283,7 +283,7 @@ impl From<toml::de::Error> 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,
|
||||
|
@ -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> { message }
|
||||
(foobar 'Hiya')
|
||||
",
|
||||
&mut context
|
||||
),
|
||||
vec![
|
||||
Ok(Value::Empty),
|
||||
Ok(Value::List(vec![Value::String("Hiya".to_string())]))
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,14 @@ impl Function {
|
||||
statements,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifiers(&self) -> &Vec<Identifier> {
|
||||
&self.identifiers
|
||||
}
|
||||
|
||||
pub fn statements(&self) -> &Vec<Statement> {
|
||||
&self.statements
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Function {
|
||||
|
@ -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<Value>),
|
||||
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}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +279,6 @@ impl From<&Value> for Table {
|
||||
|
||||
table
|
||||
}
|
||||
Value::Time(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<LocalTime>),
|
||||
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<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Time {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SystemTime> for Time {
|
||||
fn from(value: SystemTime) -> Self {
|
||||
Time::Local(value.into())
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 03c566485155076983ff78689c62839c59b47327
|
||||
Subproject commit a3dbb19ecc40bc49487730c7679358389307559d
|
Loading…
Reference in New Issue
Block a user