diff --git a/src/interface.rs b/src/interface.rs index 3389c05..ce4890d 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -20,10 +20,10 @@ use crate::{language, Error, Result, Value, VariableMap}; /// # use dust_lib::*; /// assert_eq!(eval("1 + 2 + 3"), vec![Ok(Value::from(6))]); /// ``` -pub fn eval(source: &str) -> Vec> { +pub fn evaluate(source: &str) -> Vec> { let mut context = VariableMap::new(); - eval_with_context(source, &mut context) + evaluate_with_context(source, &mut context) } /// Evaluate the given source code with the given context. @@ -45,7 +45,7 @@ pub fn eval(source: &str) -> Vec> { /// vec![Ok(Value::Primitive(Primitive::Empty)), Ok(Value::from(10))] /// ); /// ``` -pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec> { +pub fn evaluate_with_context(source: &str, context: &mut VariableMap) -> Vec> { let mut parser = Parser::new(); parser.set_language(language()).unwrap(); @@ -255,6 +255,10 @@ impl EvaluatorTree for Expression { pub struct Identifier(String); impl Identifier { + pub fn new(inner: String) -> Self { + Identifier(inner) + } + pub fn take_inner(self) -> String { self.0 } @@ -458,45 +462,54 @@ impl EvaluatorTree for FunctionCall { #[cfg(test)] mod tests { - use crate::Table; + use crate::{Function, Table}; use super::*; #[test] fn evaluate_empty() { - assert_eq!(eval("x = 9"), vec![Ok(Value::Empty)]); - assert_eq!(eval("x = 'foo' + 'bar'"), vec![Ok(Value::Empty)]); + assert_eq!(evaluate("x = 9"), vec![Ok(Value::Empty)]); + assert_eq!(evaluate("x = 'foo' + 'bar'"), vec![Ok(Value::Empty)]); } #[test] fn evaluate_integer() { - assert_eq!(eval("1"), vec![Ok(Value::Integer(1))]); - assert_eq!(eval("123"), vec![Ok(Value::Integer(123))]); - assert_eq!(eval("-666"), vec![Ok(Value::Integer(-666))]); + 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))]); } #[test] fn evaluate_float() { - assert_eq!(eval("0.1"), vec![Ok(Value::Float(0.1))]); - assert_eq!(eval("12.3"), vec![Ok(Value::Float(12.3))]); - assert_eq!(eval("-6.66"), vec![Ok(Value::Float(-6.66))]); + 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))]); } #[test] fn evaluate_string() { - assert_eq!(eval("\"one\""), vec![Ok(Value::String("one".to_string()))]); - assert_eq!(eval("'one'"), vec![Ok(Value::String("one".to_string()))]); - assert_eq!(eval("`one`"), vec![Ok(Value::String("one".to_string()))]); assert_eq!( - eval("`'one'`"), + 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!( - eval("'`one`'"), + evaluate("'`one`'"), vec![Ok(Value::String("`one`".to_string()))] ); assert_eq!( - eval("\"'one'\""), + evaluate("\"'one'\""), vec![Ok(Value::String("'one'".to_string()))] ); } @@ -504,7 +517,7 @@ mod tests { #[test] fn evaluate_list() { assert_eq!( - eval("[1, 2, 'foobar']"), + evaluate("[1, 2, 'foobar']"), vec![Ok(Value::List(vec![ Value::Integer(1), Value::Integer(2), @@ -521,7 +534,7 @@ mod tests { map.set_value("foo".to_string(), Value::String("bar".to_string())) .unwrap(); - assert_eq!(eval("{ x = 1 foo = 'bar' }"), vec![Ok(Value::Map(map))]); + assert_eq!(evaluate("{ x = 1 foo = 'bar' }"), vec![Ok(Value::Map(map))]); } #[test] @@ -539,7 +552,7 @@ mod tests { .unwrap(); assert_eq!( - eval( + evaluate( " table { ['hiya', 42] @@ -553,18 +566,21 @@ mod tests { } #[test] - fn if_then() { + fn evaluate_if_then() { assert_eq!( - eval("if true then 'true'"), + evaluate("if true then 'true'"), vec![Ok(Value::String("true".to_string()))] ); } #[test] - fn if_then_else() { - assert_eq!(eval("if false then 1 else 2"), vec![Ok(Value::Integer(2))]); + fn evaluate_if_then_else() { assert_eq!( - eval("if true then 1.0 else 42.0"), + evaluate("if false then 1 else 2"), + vec![Ok(Value::Integer(2))] + ); + assert_eq!( + evaluate("if true then 1.0 else 42.0"), vec![Ok(Value::Float(1.0))] ); } diff --git a/src/main.rs b/src/main.rs index b31e999..dd99380 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use rustyline::{ use std::{borrow::Cow, fs::read_to_string}; -use dust::{eval, eval_with_context, Value, VariableMap}; +use dust::{evaluate, evaluate_with_context, Value, VariableMap}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -35,9 +35,9 @@ fn main() { let eval_results = if let Some(path) = args.path { let file_contents = read_to_string(path).unwrap(); - eval(&file_contents) + evaluate(&file_contents) } else if let Some(command) = args.command { - eval(&command) + evaluate(&command) } else { vec![Ok(Value::Empty)] }; @@ -143,7 +143,7 @@ fn run_cli_shell() { rl.add_history_entry(line).unwrap(); - let eval_results = eval_with_context(line, &mut context); + let eval_results = evaluate_with_context(line, &mut context); for result in eval_results { match result { diff --git a/src/value/function.rs b/src/value/function.rs index bb9bb99..20ae441 100644 --- a/src/value/function.rs +++ b/src/value/function.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{Identifier, Result, Statement, Value, VariableMap}; +use crate::{EvaluatorTree, Identifier, Result, Statement, Value, VariableMap}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct Function { @@ -17,12 +17,19 @@ impl Function { statements, } } +} - pub fn run(&self) -> Result { - todo!() +impl EvaluatorTree for Function { + fn from_syntax_node(node: tree_sitter::Node, source: &str) -> Result { + debug_assert_eq!(node.kind(), "function"); + + Ok(Function { + identifiers: vec![], + statements: vec![], + }) } - pub fn run_with_context(&self, _context: &mut VariableMap) -> Result { + fn run(&self, context: &mut VariableMap) -> Result { todo!() } } @@ -36,3 +43,25 @@ impl Display for Function { ) } } + +#[cfg(test)] +mod tests { + use crate::{evaluate, Expression}; + + use super::*; + + #[test] + fn evaluate_function() { + let function = Function::new( + vec![Identifier::new("output".to_string())], + vec![Statement::Expression(Expression::Identifier( + Identifier::new("output".to_string()), + ))], + ); + + assert_eq!( + evaluate("function { output }"), + vec![Ok(Value::Function(function))] + ); + } +} diff --git a/src/value/mod.rs b/src/value/mod.rs index 406ff86..0e028d9 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -10,14 +10,14 @@ use serde::{ ser::SerializeTuple, Deserialize, Serialize, Serializer, }; -use tree_sitter::{Node, TreeCursor}; +use tree_sitter::Node; use std::{ cmp::Ordering, convert::TryFrom, fmt::{self, Display, Formatter}, marker::PhantomData, - ops::{Add, Range, Sub}, + ops::{Add, Sub}, }; pub mod function; @@ -166,23 +166,23 @@ impl Value { for index in 0..child_count { let child = child.child(index).unwrap(); - // if child.kind() == "identifier" { - // let identifier = Identifier::new(source, cursor)?; + if child.kind() == "identifier" { + let identifier = Identifier::from_syntax_node(child, source)?; - // identifiers.push(identifier) - // } + identifiers.push(identifier) + } - // if child.kind() == "statement" { - // let statement = Statement::new(source, cursor)?; + if child.kind() == "statement" { + let statement = Statement::from_syntax_node(child, source)?; - // statements.push(statement) - // } + statements.push(statement) + } } Ok(Value::Function(Function::new(identifiers, statements))) } _ => Err(Error::UnexpectedSyntax { - expected: "integer, float, boolean, string list, table, map, function or empty", + expected: "string, integer, float, boolean, list, table, map, function or empty", actual: child.kind(), location: child.start_position(), }), @@ -428,7 +428,7 @@ impl Add for Value { impl Sub for Value { type Output = Result; - fn sub(self, other: Self) -> Self::Output { + fn sub(self, _other: Self) -> Self::Output { todo!() } }