From a4660cbafb303b24073c01edbe75e3ef6d6a0b96 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 2 Oct 2023 17:15:05 -0400 Subject: [PATCH] Improve internal API --- src/error.rs | 64 ++++---- src/interface.rs | 107 +++++++++---- src/lib.rs | 5 +- src/main.rs | 12 +- src/value/mod.rs | 322 +++++++++++++++++++------------------- src/value/table.rs | 42 +++-- src/value/value_type.rs | 12 +- src/value/variable_map.rs | 64 ++++---- 8 files changed, 336 insertions(+), 292 deletions(-) diff --git a/src/error.rs b/src/error.rs index 6b3d046..b84e2ae 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,7 +3,7 @@ //! To deal with errors from dependencies, either create a new error variant //! or use the MacroFailure variant if the error can only occur inside a macro. -use crate::{value::value_type::ValueType, value::Value, ToolInfo}; +use crate::{value::value_type::ValueType, value::Value, Primitive}; use std::{fmt, io, time::SystemTimeError}; @@ -24,12 +24,6 @@ pub enum Error { empty_node_sexp: String, }, - /// Dust's internal type checking failed to identify a type mismatch. This should never happen, /// the error prompts the user to report the bug. - TypeCheckFailure { - tool_info: ToolInfo<'static>, - argument: Value, - }, - /// The 'assert' macro did not resolve successfully. AssertEqualFailed { expected: Value, @@ -142,14 +136,6 @@ pub enum Error { actual: Value, }, - /// A macro or function was called with the wrong type of input. - MacroArgumentType { - /// The macro that was called. - macro_info: ToolInfo<'static>, - /// The actual value. - actual: Value, - }, - /// An operator is used with a wrong combination of types. WrongTypeCombination { /// The operator that whose evaluation caused the error. @@ -396,19 +382,13 @@ impl Error { /// Returns `Ok(())` if the given value is a string or a numeric. pub fn expect_number_or_string(actual: &Value) -> Result<()> { match actual { - Value::String(_) | Value::Float(_) | Value::Integer(_) => Ok(()), + Value::Primitive(Primitive::String(_)) + | Value::Primitive(Primitive::Float(_)) + | Value::Primitive(Primitive::Integer(_)) => Ok(()), _ => Err(Error::expected_number_or_string(actual.clone())), } } -/// Returns `Ok(())` if the given value is a String, List, Map or Table. -pub fn _expect_collection(actual: &Value) -> Result<()> { - match actual { - Value::String(_) | Value::List(_) | Value::Map(_) | Value::Table(_) => Ok(()), - _ => Err(Error::expected_collection(actual.clone())), - } -} - impl std::error::Error for Error {} impl fmt::Display for Error { @@ -416,9 +396,14 @@ impl fmt::Display for Error { use Error::*; match self { - TypeCheckFailure { tool_info, argument } => write!(f, "Type check failure. This is a bug with the tool or with Dust's internal type checking. Please report this bug and include this error message.\nToolInfo = {tool_info:?}\nargument = {argument}"), - AssertEqualFailed {expected, actual } => write!(f, "Equality assertion failed. {expected} does not equal {actual}."), - AssertFailed => write!(f, "Assertion failed. A false value was passed to \"assert\"."), + AssertEqualFailed { expected, actual } => write!( + f, + "Equality assertion failed. {expected} does not equal {actual}." + ), + AssertFailed => write!( + f, + "Assertion failed. A false value was passed to \"assert\"." + ), ExpectedOperatorArgumentAmount { expected, actual } => write!( f, "An operator expected {} arguments, but got {}.", @@ -543,20 +528,25 @@ impl fmt::Display for Error { f, "Wrong number of columns for this table. Expected {expected}, found {actual}." ), - MacroArgumentType { - macro_info, + UnexpectedSyntax { + expected, actual, + location, } => write!( f, - "Wrong argument of type {:?} was passed to {}. Expected one of the following types: {:?}.", - actual.value_type(), - macro_info.identifier, - macro_info.inputs + "Unexpected syntax at {location}. Expected {expected}, but found {actual}." ), - UnexpectedSyntax { expected, actual, location } => write!(f, "Unexpected syntax at {location}. Expected {expected}, but found {actual}."), - ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."), - WrongTypeCombination { expected, actual } => write!(f, "Wrong type combination. Expected {expected}, found {actual}."), - ExpectedChildNode { empty_node_sexp } => write!(f, "Expected this node to have a child, {empty_node_sexp}."), + ExpectedFieldName => write!( + f, + "Expected a field name for this node, but none was found." + ), + WrongTypeCombination { expected, actual } => write!( + f, + "Wrong type combination. Expected {expected}, found {actual}." + ), + ExpectedChildNode { empty_node_sexp } => { + write!(f, "Expected this node to have a child, {empty_node_sexp}.") + } } } } diff --git a/src/interface.rs b/src/interface.rs index 68dc794..63e0958 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -7,7 +7,7 @@ use std::fmt::{self, Debug, Formatter}; use serde::{Deserialize, Serialize}; use tree_sitter::{Node, Parser, Tree as TSTree, TreeCursor}; -use crate::{language, Error, Result, Value, VariableMap}; +use crate::{language, Error, Primitive, Result, Value, VariableMap}; /// Evaluate the given source code. /// @@ -42,7 +42,7 @@ pub fn eval(source: &str) -> Vec> { /// /// assert_eq!( /// eval_with_context(dust_code, &mut context), -/// vec![Ok(Value::Empty), Ok(Value::from(10))] +/// vec![Ok(Value::Primitive(Primitive::Empty)), Ok(Value::from(10))] /// ); /// ``` pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec> { @@ -165,7 +165,7 @@ impl EvaluatorTree for Item { fn run(&self, context: &mut VariableMap) -> Result { match self { - Item::Comment(text) => Ok(Value::String(text.clone())), + Item::Comment(text) => Ok(Value::Primitive(Primitive::String(text.clone()))), Item::Statement(statement) => statement.run(context), } } @@ -226,7 +226,7 @@ impl EvaluatorTree for Expression { let expression = match child.kind() { "identifier" => Self::Identifier(Identifier::new(source, cursor)?), - "value" => Expression::Value(Value::new(source, cursor)?), + "value" => Expression::Value(Value::from_source(source, cursor)?), "control_flow" => Expression::ControlFlow(Box::new(ControlFlow::new(source, cursor)?)), "assignment" => Expression::Assignment(Box::new(Assignment::new(source, cursor)?)), "math" => Expression::Math(Box::new(Math::new(source, cursor)?)), @@ -330,7 +330,7 @@ impl EvaluatorTree for ControlFlow { } else if let Some(statement) = &self.else_statement { statement.run(context) } else { - Ok(Value::Empty) + Ok(Value::Primitive(Primitive::Empty)) } } } @@ -367,7 +367,7 @@ impl EvaluatorTree for Assignment { context.set_value(key, value)?; - Ok(Value::Empty) + Ok(Value::Primitive(Primitive::Empty)) } } @@ -424,7 +424,7 @@ impl EvaluatorTree for Math { MathOperator::Modulo => left_value % right_value, }; - Ok(Value::Float(outcome)) + Ok(Value::Primitive(Primitive::Float(outcome))) } } @@ -488,40 +488,67 @@ mod tests { #[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!(eval("x = 9"), vec![Ok(Value::Primitive(Primitive::Empty))]); + assert_eq!( + eval("x = 'foo' + 'bar'"), + vec![Ok(Value::Primitive(Primitive::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!(eval("1"), vec![Ok(Value::Primitive(Primitive::Integer(1)))]); + assert_eq!( + eval("123"), + vec![Ok(Value::Primitive(Primitive::Integer(123)))] + ); + assert_eq!( + eval("-666"), + vec![Ok(Value::Primitive(Primitive::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!( + eval("0.1"), + vec![Ok(Value::Primitive(Primitive::Float(0.1)))] + ); + assert_eq!( + eval("12.3"), + vec![Ok(Value::Primitive(Primitive::Float(12.3)))] + ); + assert_eq!( + eval("-6.66"), + vec![Ok(Value::Primitive(Primitive::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\""), + vec![Ok(Value::Primitive(Primitive::String("one".to_string())))] + ); + assert_eq!( + eval("'one'"), + vec![Ok(Value::Primitive(Primitive::String("one".to_string())))] + ); + assert_eq!( + eval("`one`"), + vec![Ok(Value::Primitive(Primitive::String("one".to_string())))] + ); assert_eq!( eval("`'one'`"), - vec![Ok(Value::String("'one'".to_string()))] + vec![Ok(Value::Primitive(Primitive::String("'one'".to_string())))] ); assert_eq!( eval("'`one`'"), - vec![Ok(Value::String("`one`".to_string()))] + vec![Ok(Value::Primitive(Primitive::String("`one`".to_string())))] ); assert_eq!( eval("\"'one'\""), - vec![Ok(Value::String("'one'".to_string()))] + vec![Ok(Value::Primitive(Primitive::String("'one'".to_string())))] ); } @@ -530,9 +557,9 @@ mod tests { assert_eq!( eval("[1, 2, 'foobar']"), vec![Ok(Value::List(vec![ - Value::Integer(1), - Value::Integer(2), - Value::String("foobar".to_string()), + Value::Primitive(Primitive::Integer(1)), + Value::Primitive(Primitive::Integer(2)), + Value::Primitive(Primitive::String("foobar".to_string())), ]))] ); } @@ -541,9 +568,13 @@ mod tests { fn evaluate_map() { let mut map = VariableMap::new(); - map.set_value("x".to_string(), Value::Integer(1)).unwrap(); - map.set_value("foo".to_string(), Value::String("bar".to_string())) + map.set_value("x".to_string(), Value::Primitive(Primitive::Integer(1))) .unwrap(); + map.set_value( + "foo".to_string(), + Value::Primitive(Primitive::String("bar".to_string())), + ) + .unwrap(); assert_eq!(eval("map { x = 1 foo = 'bar' }"), vec![Ok(Value::Map(map))]); } @@ -553,13 +584,22 @@ mod tests { let mut table = Table::new(vec!["messages".to_string(), "numbers".to_string()]); table - .insert(vec![Value::String("hiya".to_string()), Value::Integer(42)]) + .insert(vec![ + Value::Primitive(Primitive::String("hiya".to_string())), + Value::Primitive(Primitive::Integer(42)), + ]) .unwrap(); table - .insert(vec![Value::String("foo".to_string()), Value::Integer(57)]) + .insert(vec![ + Value::Primitive(Primitive::String("foo".to_string())), + Value::Primitive(Primitive::Integer(57)), + ]) .unwrap(); table - .insert(vec![Value::String("bar".to_string()), Value::Float(99.99)]) + .insert(vec![ + Value::Primitive(Primitive::String("bar".to_string())), + Value::Primitive(Primitive::Float(99.99)), + ]) .unwrap(); assert_eq!( @@ -580,16 +620,19 @@ mod tests { fn if_then() { assert_eq!( eval("if true then 'true'"), - vec![Ok(Value::String("true".to_string()))] + vec![Ok(Value::Primitive(Primitive::String("true".to_string())))] ); } #[test] fn if_then_else() { - assert_eq!(eval("if false then 1 else 2"), vec![Ok(Value::Integer(2))]); + assert_eq!( + eval("if false then 1 else 2"), + vec![Ok(Value::Primitive(Primitive::Integer(2)))] + ); assert_eq!( eval("if true then 1.0 else 42.0"), - vec![Ok(Value::Float(1.0))] + vec![Ok(Value::Primitive(Primitive::Float(1.0)))] ); } } diff --git a/src/lib.rs b/src/lib.rs index a8a046b..f0fef03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,15 +7,12 @@ pub use crate::{ error::*, interface::*, - tools::{Tool, ToolInfo, TOOL_LIST}, value::{ function::Function, table::Table, time::Time, value_type::ValueType, - variable_map::VariableMap, Value, + variable_map::VariableMap, Primitive, Value, }, }; -pub mod tools; - mod error; mod interface; mod value; diff --git a/src/main.rs b/src/main.rs index 4c5f338..0b89ab2 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_lib::{eval, eval_with_context, Value, VariableMap, TOOL_LIST}; +use dust_lib::{eval, eval_with_context, Primitive, Value, VariableMap}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -39,7 +39,7 @@ fn main() { } else if let Some(command) = args.command { eval(&command) } else { - vec![Ok(Value::Empty)] + vec![Ok(Value::Primitive(Primitive::Empty))] }; for result in eval_results { @@ -66,13 +66,7 @@ impl DustReadline { Self { completer: FilenameCompleter::new(), _hinter: HistoryHinter {}, - tool_hints: TOOL_LIST - .iter() - .map(|tool| ToolHint { - display: tool.info().identifier.to_string() + "()", - complete_to: tool.info().identifier.len(), - }) - .collect(), + tool_hints: Vec::new(), } } } diff --git a/src/value/mod.rs b/src/value/mod.rs index 9ff755f..9f2c4c9 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -27,28 +27,54 @@ pub mod time; pub mod value_type; pub mod variable_map; +#[derive(Clone, Debug, Default, PartialEq, PartialOrd, Serialize, Deserialize)] +pub enum Primitive { + String(String), + Float(f64), + Integer(i64), + Boolean(bool), + #[default] + Empty, +} + +impl Eq for Primitive {} + +impl Ord for Primitive { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Primitive::String(left), Primitive::String(right)) => left.cmp(right), + (Primitive::Float(left), Primitive::Float(right)) => { + left.to_le_bytes().cmp(&right.to_le_bytes()) + } + (Primitive::Integer(left), Primitive::Integer(right)) => left.cmp(right), + (Primitive::Boolean(left), Primitive::Boolean(right)) => left.cmp(right), + (Primitive::Empty, Primitive::Empty) => Ordering::Equal, + (Primitive::String(_), _) => Ordering::Greater, + (Primitive::Float(_), _) => Ordering::Greater, + (Primitive::Integer(_), _) => Ordering::Greater, + (Primitive::Boolean(_), _) => Ordering::Greater, + (Primitive::Empty, _) => Ordering::Less, + } + } +} + /// Whale value representation. /// /// Every whale variable has a key and a Value. Variables are represented by /// storing them in a VariableMap. This means the map of variables is itself a /// value that can be treated as any other. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub enum Value { - String(String), - Float(f64), - Integer(i64), - Boolean(bool), + Primitive(Primitive), List(Vec), Map(VariableMap), Table(Table), Time(Time), Function(Function), - #[default] - Empty, } impl Value { - pub fn new(source: &str, mut cursor: &mut TreeCursor) -> Result { + pub fn from_source(source: &str, mut cursor: &mut TreeCursor) -> Result { let node = cursor.node(); cursor.goto_first_child(); let child = cursor.node(); @@ -57,7 +83,7 @@ impl Value { match child.kind() { "integer" | "float" | "boolean" | "string" | "empty" => { - Value::from_syntax_node(child, source) + Value::simple_from_syntax_node(node, source) } "list" => { let list_length = child.named_child_count(); @@ -66,7 +92,7 @@ impl Value { cursor.goto_first_child(); for value_node in child.children_by_field_name("item", &mut cursor) { - let value = Value::from_syntax_node(value_node.child(0).unwrap(), source)?; + let value = Value::simple_from_syntax_node(value_node, source)?; values.push(value); } @@ -81,25 +107,19 @@ impl Value { Ok(Value::Table(table)) } "map" => { - let grandchild_count = child.child_count(); let mut map = VariableMap::new(); - let mut previous_grandchild = child.child(0).unwrap(); - let mut key = String::new(); + let mut current_key = String::new(); - for _ in 0..grandchild_count { - if let Some(current_node) = previous_grandchild.next_sibling() { - if current_node.kind() == "identifier" { - key = Identifier::new(source, cursor)?.take_inner(); - } + for key_value_node in child.children_by_field_name("key_value_pair", &mut cursor) { + if key_value_node.kind() == "identifier" { + let identifier_text = &source[key_value_node.byte_range()]; + current_key = identifier_text.to_string(); + } - if current_node.kind() == "value" { - let value = Value::new(source, cursor)?; - - map.set_value(key.clone(), value)?; - } - - previous_grandchild = current_node + if key_value_node.kind() == "value" { + let value = Value::simple_from_syntax_node(key_value_node, source)?; + map.set_value(current_key.to_string(), value)?; } } @@ -136,17 +156,23 @@ impl Value { } } - pub fn from_syntax_node(node: Node, source: &str) -> Result { - match node.kind() { - "integer" => Value::integer_from_source(source, node.byte_range()), - "float" => Value::integer_from_source(source, node.byte_range()), - "boolean" => Value::integer_from_source(source, node.byte_range()), - "string" => Value::integer_from_source(source, node.byte_range()), - "empty" => Ok(Value::Empty), + /// Creates a simple value from the given source code and a node in the + /// syntax tree. + /// + /// + pub fn simple_from_syntax_node(node: Node, source: &str) -> Result { + let child = node.child(0).unwrap(); + + match child.kind() { + "integer" => Value::integer_from_source(source, child.byte_range()), + "float" => Value::float_from_source(source, child.byte_range()), + "boolean" => Value::boolean_from_source(source, child.byte_range()), + "string" => Value::string_from_source(source, child.byte_range()), + "empty" => Ok(Value::Primitive(Primitive::Empty)), _ => Err(Error::UnexpectedSyntax { expected: "integer, float, boolean, string or empty", - actual: node.kind(), - location: node.start_position(), + actual: child.kind(), + location: child.start_position(), }), } } @@ -155,29 +181,30 @@ impl Value { let value_snippet = &source[byte_range]; let raw = value_snippet.parse::().unwrap_or_default(); - Ok(Value::Integer(raw)) + Ok(Value::Primitive(Primitive::Integer(raw))) } pub fn float_from_source(source: &str, byte_range: Range) -> Result { let value_snippet = &source[byte_range]; let raw = value_snippet.parse::().unwrap_or_default(); - Ok(Value::Float(raw)) + Ok(Value::Primitive(Primitive::Float(raw))) } pub fn boolean_from_source(source: &str, byte_range: Range) -> Result { let value_snippet = &source[byte_range]; let raw = value_snippet.parse::().unwrap_or_default(); - Ok(Value::Boolean(raw)) + Ok(Value::Primitive(Primitive::Boolean(raw))) } pub fn string_from_source(source: &str, byte_range: Range) -> Result { let value_snippet = &source[byte_range]; - let quote_str = &value_snippet.chars().nth(0).unwrap(); - let without_quotes = value_snippet.trim_matches(*quote_str); + let without_quotes = &value_snippet[1..value_snippet.len() - 1]; - Ok(Value::String(without_quotes.to_string())) + Ok(Value::Primitive(Primitive::String( + without_quotes.to_string(), + ))) } pub fn value_type(&self) -> ValueType { @@ -189,23 +216,26 @@ impl Value { } pub fn is_string(&self) -> bool { - matches!(self, Value::String(_)) + matches!(self, Value::Primitive(Primitive::String(_))) } pub fn is_integer(&self) -> bool { - matches!(self, Value::Integer(_)) + matches!(self, Value::Primitive(Primitive::Integer(_))) } pub fn is_float(&self) -> bool { - matches!(self, Value::Float(_)) + matches!(self, Value::Primitive(Primitive::Float(_))) } pub fn is_number(&self) -> bool { - matches!(self, Value::Integer(_) | Value::Float(_)) + matches!( + self, + Value::Primitive(Primitive::Integer(_)) | Value::Primitive(Primitive::Float(_)) + ) } pub fn is_boolean(&self) -> bool { - matches!(self, Value::Boolean(_)) + matches!(self, Value::Primitive(Primitive::Boolean(_))) } pub fn is_list(&self) -> bool { @@ -213,7 +243,7 @@ impl Value { } pub fn is_empty(&self) -> bool { - matches!(self, Value::Empty) + matches!(self, Value::Primitive(Primitive::Empty)) } pub fn is_map(&self) -> bool { @@ -224,10 +254,10 @@ impl Value { matches!(self, Value::Map(_)) } - /// Borrows the value stored in `self` as `String`, or returns `Err` if `self` is not a `Value::String`. + /// Borrows the value stored in `self` as `String`, or returns `Err` if `self` is not a `Value::Primitive(Primitive::String`. pub fn as_string(&self) -> Result<&String> { match self { - Value::String(string) => Ok(string), + Value::Primitive(Primitive::String(string)) => Ok(string), value => Err(Error::expected_string(value.clone())), } } @@ -235,33 +265,33 @@ impl Value { /// Copies the value stored in `self` as `i64`, or returns `Err` if `self` is not a `Value::Int`. pub fn as_int(&self) -> Result { match self { - Value::Integer(i) => Ok(*i), + Value::Primitive(Primitive::Integer(i)) => Ok(*i), value => Err(Error::expected_int(value.clone())), } } - /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Value::Float`. + /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float`. pub fn as_float(&self) -> Result { match self { - Value::Float(f) => Ok(*f), + Value::Primitive(Primitive::Float(f)) => Ok(*f), value => Err(Error::expected_float(value.clone())), } } - /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Value::Float` or `Value::Int`. + /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float` or `Value::Int`. /// Note that this method silently converts `i64` to `f64`, if `self` is a `Value::Int`. pub fn as_number(&self) -> Result { match self { - Value::Float(f) => Ok(*f), - Value::Integer(i) => Ok(*i as f64), + Value::Primitive(Primitive::Float(f)) => Ok(*f), + Value::Primitive(Primitive::Integer(i)) => Ok(*i as f64), value => Err(Error::expected_number(value.clone())), } } - /// Copies the value stored in `self` as `bool`, or returns `Err` if `self` is not a `Value::Boolean`. + /// Copies the value stored in `self` as `bool`, or returns `Err` if `self` is not a `Primitive::Boolean`. pub fn as_boolean(&self) -> Result { match self { - Value::Boolean(boolean) => Ok(*boolean), + Value::Primitive(Primitive::Boolean(boolean)) => Ok(*boolean), value => Err(Error::expected_boolean(value.clone())), } } @@ -333,7 +363,7 @@ impl Value { /// Returns `()`, or returns`Err` if `self` is not a `Value::Tuple`. pub fn as_empty(&self) -> Result<()> { match self { - Value::Empty => Ok(()), + Value::Primitive(Primitive::Empty) => Ok(()), value => Err(Error::expected_empty(value.clone())), } } @@ -349,33 +379,54 @@ impl Value { } } +impl Default for Value { + fn default() -> Self { + Value::Primitive(Primitive::Empty) + } +} + impl Add for Value { type Output = Result; fn add(self, other: Self) -> Self::Output { match (self, other) { - (Value::String(left), Value::String(right)) => { + ( + Value::Primitive(Primitive::String(left)), + Value::Primitive(Primitive::String(right)), + ) => { let concatenated = left + &right; - Ok(Value::String(concatenated)) + Ok(Value::Primitive(Primitive::String(concatenated))) } - (Value::String(_), other) | (other, Value::String(_)) => { + (Value::Primitive(Primitive::String(_)), other) + | (other, Value::Primitive(Primitive::String(_))) => { Err(Error::ExpectedString { actual: other }) } - (Value::Float(left), Value::Float(right)) => { + ( + Value::Primitive(Primitive::Float(left)), + Value::Primitive(Primitive::Float(right)), + ) => { let addition = left + right; - Ok(Value::Float(addition)) + Ok(Value::Primitive(Primitive::Float(addition))) } - (Value::Float(_), other) | (other, Value::Float(_)) => { + (Value::Primitive(Primitive::Float(_)), other) + | (other, Value::Primitive(Primitive::Float(_))) => { Err(Error::ExpectedFloat { actual: other }) } - (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)), - (Value::Integer(_), other) | (other, Value::Integer(_)) => { + ( + Value::Primitive(Primitive::Integer(left)), + Value::Primitive(Primitive::Integer(right)), + ) => Ok(Value::Primitive(Primitive::Integer(left + right))), + (Value::Primitive(Primitive::Integer(_)), other) + | (other, Value::Primitive(Primitive::Integer(_))) => { Err(Error::ExpectedInt { actual: other }) } - (Value::Boolean(_), Value::Boolean(_)) => todo!(), - (Value::Boolean(_), other) | (other, Value::Boolean(_)) => { + (Value::Primitive(Primitive::Boolean(_)), Value::Primitive(Primitive::Boolean(_))) => { + todo!() + } + (Value::Primitive(Primitive::Boolean(_)), other) + | (other, Value::Primitive(Primitive::Boolean(_))) => { Err(Error::ExpectedBoolean { actual: other }) } (Value::List(_), Value::List(_)) => todo!(), @@ -386,7 +437,9 @@ impl Add for Value { (Value::Map(_), other) | (other, Value::Map(_)) => { Err(Error::ExpectedMap { actual: other }) } - (Value::Empty, Value::Empty) => Ok(Value::Empty), + (Value::Primitive(Primitive::Empty), Value::Primitive(Primitive::Empty)) => { + Ok(Value::Primitive(Primitive::Empty)) + } _ => Err(Error::CustomMessage( "Cannot add the given types.".to_string(), )), @@ -398,44 +451,7 @@ impl Sub for Value { type Output = Result; fn sub(self, other: Self) -> Self::Output { - match (&self, &other) { - (Value::String(_), Value::String(_)) => Err(Error::ExpectedNumber { - actual: self.clone(), - }), - (Value::String(_), other) | (other, Value::String(_)) => Err(Error::ExpectedNumber { - actual: other.clone(), - }), - (Value::Float(left), Value::Float(right)) => { - let addition = left - right; - - Ok(Value::Float(addition)) - } - (Value::Float(_), other) | (other, Value::Float(_)) => Err(Error::ExpectedNumber { - actual: other.clone(), - }), - (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)), - (Value::Integer(_), other) | (other, Value::Integer(_)) => Err(Error::ExpectedInt { - actual: other.clone(), - }), - (Value::Boolean(_), Value::Boolean(_)) => todo!(), - (Value::Boolean(_), other) | (other, Value::Boolean(_)) => { - Err(Error::ExpectedBoolean { - actual: other.clone(), - }) - } - (Value::List(_), Value::List(_)) => todo!(), - (Value::List(_), other) | (other, Value::List(_)) => Err(Error::ExpectedList { - actual: other.clone(), - }), - (Value::Map(_), Value::Map(_)) => todo!(), - (Value::Map(_), other) | (other, Value::Map(_)) => Err(Error::ExpectedMap { - actual: other.clone(), - }), - (Value::Empty, Value::Empty) => Ok(Value::Empty), - _ => Err(Error::CustomMessage( - "Cannot add the given types.".to_string(), - )), - } + todo!() } } @@ -444,18 +460,12 @@ impl Eq for Value {} impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { match (self, other) { - (Value::String(left), Value::String(right)) => left == right, - (Value::Float(left), Value::Float(right)) => left == right, - (Value::Integer(left), Value::Integer(right)) => left == right, - (Value::Float(float), Value::Integer(integer)) - | (Value::Integer(integer), Value::Float(float)) => *float == *integer as f64, - (Value::Boolean(left), Value::Boolean(right)) => left == right, (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, + (Value::Primitive(left), Value::Primitive(right)) => left == right, _ => false, } } @@ -470,14 +480,6 @@ impl PartialOrd for Value { impl Ord for Value { fn cmp(&self, other: &Self) -> Ordering { match (self, other) { - (Value::String(left), Value::String(right)) => left.cmp(right), - (Value::String(_), _) => Ordering::Greater, - (Value::Integer(left), Value::Integer(right)) => left.cmp(right), - (Value::Integer(_), _) => Ordering::Greater, - (Value::Boolean(left), Value::Boolean(right)) => left.cmp(right), - (Value::Boolean(_), _) => Ordering::Greater, - (Value::Float(left), Value::Float(right)) => left.total_cmp(right), - (Value::Float(_), _) => Ordering::Greater, (Value::List(left), Value::List(right)) => left.cmp(right), (Value::List(_), _) => Ordering::Greater, (Value::Map(left), Value::Map(right)) => left.cmp(right), @@ -488,8 +490,8 @@ impl Ord for Value { (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, + (Value::Primitive(left), Value::Primitive(right)) => left.cmp(right), + (Value::Primitive(_), _) => Ordering::Less, } } } @@ -500,10 +502,10 @@ impl Serialize for Value { S: Serializer, { match self { - Value::String(inner) => serializer.serialize_str(inner), - Value::Float(inner) => serializer.serialize_f64(*inner), - Value::Integer(inner) => serializer.serialize_i64(*inner), - Value::Boolean(inner) => serializer.serialize_bool(*inner), + Value::Primitive(Primitive::String(inner)) => serializer.serialize_str(inner), + Value::Primitive(Primitive::Float(inner)) => serializer.serialize_f64(*inner), + Value::Primitive(Primitive::Integer(inner)) => serializer.serialize_i64(*inner), + Value::Primitive(Primitive::Boolean(inner)) => serializer.serialize_bool(*inner), Value::List(inner) => { let mut tuple = serializer.serialize_tuple(inner.len())?; @@ -513,7 +515,7 @@ impl Serialize for Value { tuple.end() } - Value::Empty => todo!(), + Value::Primitive(Primitive::Empty) => todo!(), Value::Map(inner) => inner.serialize(serializer), Value::Table(inner) => inner.serialize(serializer), Value::Function(inner) => inner.serialize(serializer), @@ -525,11 +527,11 @@ impl Serialize for Value { impl Display for Value { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - Value::String(string) => write!(f, "{string}"), - Value::Float(float) => write!(f, "{}", float), - Value::Integer(int) => write!(f, "{}", int), - Value::Boolean(boolean) => write!(f, "{}", boolean), - Value::Empty => write!(f, "()"), + Value::Primitive(Primitive::String(string)) => write!(f, "{string}"), + Value::Primitive(Primitive::Float(float)) => write!(f, "{}", float), + Value::Primitive(Primitive::Integer(int)) => write!(f, "{}", int), + Value::Primitive(Primitive::Boolean(boolean)) => write!(f, "{}", boolean), + Value::Primitive(Primitive::Empty) => write!(f, "()"), Value::List(list) => Table::from(list).fmt(f), Value::Map(map) => write!(f, "{map}"), Value::Table(table) => write!(f, "{table}"), @@ -541,31 +543,31 @@ impl Display for Value { impl From for Value { fn from(string: String) -> Self { - Value::String(string) + Value::Primitive(Primitive::String(string)) } } impl From<&str> for Value { fn from(string: &str) -> Self { - Value::String(string.to_string()) + Value::Primitive(Primitive::String(string.to_string())) } } impl From for Value { fn from(float: f64) -> Self { - Value::Float(float) + Value::Primitive(Primitive::Float(float)) } } impl From for Value { fn from(int: i64) -> Self { - Value::Integer(int) + Value::Primitive(Primitive::Integer(int)) } } impl From for Value { fn from(boolean: bool) -> Self { - Value::Boolean(boolean) + Value::Primitive(Primitive::Boolean(boolean)) } } @@ -583,7 +585,7 @@ impl From for Result { impl From<()> for Value { fn from(_: ()) -> Self { - Value::Empty + Value::Primitive(Primitive::Empty) } } @@ -594,11 +596,11 @@ impl TryFrom for Value { use JsonValue::*; match json_value { - Null => Ok(Value::Empty), - Short(short) => Ok(Value::String(short.to_string())), - String(string) => Ok(Value::String(string)), - Number(number) => Ok(Value::Float(f64::from(number))), - Boolean(boolean) => Ok(Value::Boolean(boolean)), + Null => Ok(Value::Primitive(Primitive::Empty)), + Short(short) => Ok(Value::Primitive(Primitive::String(short.to_string()))), + String(string) => Ok(Value::Primitive(Primitive::String(string))), + Number(number) => Ok(Value::Primitive(Primitive::Float(f64::from(number)))), + Boolean(boolean) => Ok(Value::Primitive(Primitive::Boolean(boolean))), Object(object) => { let mut map = VariableMap::new(); @@ -632,11 +634,11 @@ impl TryFrom<&JsonValue> for Value { use JsonValue::*; match json_value { - Null => Ok(Value::Empty), - Short(short) => Ok(Value::String(short.to_string())), - String(string) => Ok(Value::String(string.clone())), - Number(number) => Ok(Value::Float(f64::from(*number))), - Boolean(boolean) => Ok(Value::Boolean(*boolean)), + Null => Ok(Value::Primitive(Primitive::Empty)), + Short(short) => Ok(Value::Primitive(Primitive::String(short.to_string()))), + String(string) => Ok(Value::Primitive(Primitive::String(string.clone()))), + Number(number) => Ok(Value::Primitive(Primitive::Float(f64::from(*number)))), + Boolean(boolean) => Ok(Value::Primitive(Primitive::Boolean(*boolean))), Object(object) => { let mut map = VariableMap::new(); @@ -667,7 +669,7 @@ impl TryFrom for String { type Error = Error; fn try_from(value: Value) -> std::result::Result { - if let Value::String(value) = value { + if let Value::Primitive(Primitive::String(value)) = value { Ok(value) } else { Err(Error::ExpectedString { actual: value }) @@ -679,7 +681,7 @@ impl TryFrom for f64 { type Error = Error; fn try_from(value: Value) -> std::result::Result { - if let Value::Float(value) = value { + if let Value::Primitive(Primitive::Float(value)) = value { Ok(value) } else { Err(Error::ExpectedFloat { actual: value }) @@ -691,7 +693,7 @@ impl TryFrom for i64 { type Error = Error; fn try_from(value: Value) -> std::result::Result { - if let Value::Integer(value) = value { + if let Value::Primitive(Primitive::Integer(value)) = value { Ok(value) } else { Err(Error::ExpectedInt { actual: value }) @@ -703,7 +705,7 @@ impl TryFrom for bool { type Error = Error; fn try_from(value: Value) -> std::result::Result { - if let Value::Boolean(value) = value { + if let Value::Primitive(Primitive::Boolean(value)) = value { Ok(value) } else { Err(Error::ExpectedBoolean { actual: value }) @@ -734,7 +736,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Ok(Value::Boolean(v)) + Ok(Value::Primitive(Primitive::Boolean(v))) } fn visit_i8(self, v: i8) -> std::result::Result @@ -762,7 +764,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Ok(Value::Integer(v)) + Ok(Value::Primitive(Primitive::Integer(v))) } fn visit_i128(self, v: i128) -> std::result::Result @@ -770,9 +772,9 @@ impl<'de> Visitor<'de> for ValueVisitor { E: serde::de::Error, { if v > i64::MAX as i128 { - Ok(Value::Integer(i64::MAX)) + Ok(Value::Primitive(Primitive::Integer(i64::MAX))) } else { - Ok(Value::Integer(v as i64)) + Ok(Value::Primitive(Primitive::Integer(v as i64))) } } @@ -822,7 +824,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Ok(Value::Float(v)) + Ok(Value::Primitive(Primitive::Float(v))) } fn visit_char(self, v: char) -> std::result::Result @@ -836,7 +838,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Ok(Value::String(v.to_string())) + Ok(Value::Primitive(Primitive::String(v.to_string()))) } fn visit_borrowed_str(self, v: &'de str) -> std::result::Result @@ -850,7 +852,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where E: serde::de::Error, { - Ok(Value::String(v)) + Ok(Value::Primitive(Primitive::String(v))) } fn visit_bytes(self, v: &[u8]) -> std::result::Result diff --git a/src/value/table.rs b/src/value/table.rs index 9dee03b..ea744ba 100644 --- a/src/value/table.rs +++ b/src/value/table.rs @@ -1,4 +1,4 @@ -use crate::{Error, Result, Value, VariableMap}; +use crate::{Error, Primitive, Result, Value, VariableMap}; use comfy_table::{Cell, Color, ContentArrangement, Table as ComfyTable}; use serde::{Deserialize, Serialize}; use std::{ @@ -98,7 +98,7 @@ impl Table { if let Some(index) = new_table_column_index { while new_row.len() < index + 1 { - new_row.push(Value::Empty); + new_row.push(Value::Primitive(Primitive::Empty)); } new_row[index] = value.clone(); } @@ -180,7 +180,7 @@ impl Display for Table { Value::Map(map) => format!("Map ({} items)", map.len()), Value::Table(table) => format!("Table ({} items)", table.len()), Value::Function(_) => "Function".to_string(), - Value::Empty => "Empty".to_string(), + Value::Primitive(Primitive::Empty) => "Empty".to_string(), value => value.to_string(), }; @@ -220,38 +220,46 @@ impl Display for Table { impl From<&Value> for Table { fn from(value: &Value) -> Self { match value { - Value::String(string) => { + Value::Primitive(Primitive::String(string)) => { let mut table = Table::new(vec!["string".to_string()]); table - .insert(vec![Value::String(string.to_string())]) + .insert(vec![Value::Primitive(Primitive::String( + string.to_string(), + ))]) .unwrap(); table } - Value::Float(float) => { + Value::Primitive(Primitive::Float(float)) => { let mut table = Table::new(vec!["float".to_string()]); - table.insert(vec![Value::Float(*float)]).unwrap(); + table + .insert(vec![Value::Primitive(Primitive::Float(*float))]) + .unwrap(); table } - Value::Integer(integer) => { + Value::Primitive(Primitive::Integer(integer)) => { let mut table = Table::new(vec!["integer".to_string()]); - table.insert(vec![Value::Integer(*integer)]).unwrap(); + table + .insert(vec![Value::Primitive(Primitive::Integer(*integer))]) + .unwrap(); table } - Value::Boolean(boolean) => { + Value::Primitive(Primitive::Boolean(boolean)) => { let mut table = Table::new(vec!["boolean".to_string()]); - table.insert(vec![Value::Boolean(*boolean)]).unwrap(); + table + .insert(vec![Value::Primitive(Primitive::Boolean(*boolean))]) + .unwrap(); table } Value::List(list) => Self::from(list), - Value::Empty => Table::new(Vec::with_capacity(0)), + Value::Primitive(Primitive::Empty) => Table::new(Vec::with_capacity(0)), Value::Map(map) => Self::from(map), Value::Table(table) => table.clone(), Value::Function(function) => { @@ -274,7 +282,10 @@ impl From<&Vec> for Table { for (i, value) in list.iter().enumerate() { table - .insert(vec![Value::Integer(i as i64), value.clone()]) + .insert(vec![ + Value::Primitive(Primitive::Integer(i as i64)), + value.clone(), + ]) .unwrap(); } @@ -291,7 +302,10 @@ impl From<&mut Vec> for Table { table.insert(list.clone()).unwrap(); } else { table - .insert(vec![Value::Integer(i as i64), value.clone()]) + .insert(vec![ + Value::Primitive(Primitive::Integer(i as i64)), + value.clone(), + ]) .unwrap(); } } diff --git a/src/value/value_type.rs b/src/value/value_type.rs index fc0c359..2aa1b76 100644 --- a/src/value/value_type.rs +++ b/src/value/value_type.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Debug, Display, Formatter}; -use crate::Value; +use crate::{Primitive, Value}; /// The type of a `Value`. #[derive(Clone)] @@ -94,16 +94,16 @@ impl Debug for ValueType { impl From<&Value> for ValueType { fn from(value: &Value) -> Self { match value { - Value::String(_) => ValueType::String, - Value::Float(_) => ValueType::Float, - Value::Integer(_) => ValueType::Integer, - Value::Boolean(_) => ValueType::Boolean, + Value::Primitive(Primitive::String(_)) => ValueType::String, + Value::Primitive(Primitive::Float(_)) => ValueType::Float, + Value::Primitive(Primitive::Integer(_)) => ValueType::Integer, + Value::Primitive(Primitive::Boolean(_)) => ValueType::Boolean, + Value::Primitive(Primitive::Empty) => ValueType::Empty, Value::List(list) => { let values = list.iter().map(|value| value.value_type()).collect(); ValueType::ListExact(values) } - Value::Empty => ValueType::Empty, Value::Map(_) => ValueType::Map, Value::Table { .. } => ValueType::Table, Value::Function(_) => ValueType::Function, diff --git a/src/value/variable_map.rs b/src/value/variable_map.rs index 04d8ecf..5fca1d9 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, Error, Result, Table, TOOL_LIST}; +use crate::{value::Value, Error, Primitive, Result, Table}; /// A collection dust variables comprised of key-value pairs. /// @@ -27,34 +27,34 @@ impl VariableMap { /// argument. Returns an error a tool is called with the wrong inputs or if the identifier does /// not match any tools or functions. pub fn call_function(&self, identifier: &str, argument: &Value) -> Result { - for macro_item in TOOL_LIST { - let valid_input_types = macro_item.info().inputs; + // for macro_item in TOOL_LIST { + // let valid_input_types = macro_item.info().inputs; - if identifier == macro_item.info().identifier { - let input_type = argument.value_type(); + // if identifier == macro_item.info().identifier { + // let input_type = argument.value_type(); - if valid_input_types.contains(&input_type) { - return macro_item.run(argument); - } else { - return Err(Error::MacroArgumentType { - macro_info: macro_item.info(), - actual: argument.clone(), - }); - } - } - } + // if valid_input_types.contains(&input_type) { + // return macro_item.run(argument); + // } else { + // return Err(Error::MacroArgumentType { + // macro_info: macro_item.info(), + // actual: argument.clone(), + // }); + // } + // } + // } - for (key, value) in &self.variables { - if identifier == key { - if let Ok(function) = value.as_function() { - let mut context = self.clone(); + // for (key, value) in &self.variables { + // if identifier == key { + // if let Ok(function) = value.as_function() { + // let mut context = self.clone(); - context.set_value("input".to_string(), argument.clone())?; + // context.set_value("input".to_string(), argument.clone())?; - return function.run_with_context(&mut context); - } - } - } + // return function.run_with_context(&mut context); + // } + // } + // } Err(Error::FunctionIdentifierNotFound(identifier.to_string())) } @@ -77,9 +77,9 @@ impl VariableMap { let index = if let Ok(index) = next_identifier.parse::() { index } else { - return Err(Error::expected_int(Value::String( + return Err(Error::expected_int(Value::Primitive(Primitive::String( next_identifier.to_string(), - ))); + )))); }; Ok(list.get(index).cloned()) @@ -106,9 +106,9 @@ impl VariableMap { let index = if let Ok(index) = next_identifier.parse::() { index } else { - return Err(Error::expected_int(Value::String( + return Err(Error::expected_int(Value::Primitive(Primitive::String( next_identifier.to_string(), - ))); + )))); }; let mut missing_elements = index.saturating_sub(list.len()) + 1; @@ -193,9 +193,13 @@ mod tests { fn get_and_set_simple_value() { let mut map = VariableMap::new(); - map.set_value("x".to_string(), Value::Integer(1)).unwrap(); + map.set_value("x".to_string(), Value::Primitive(Primitive::Integer(1))) + .unwrap(); - assert_eq!(Value::Integer(1), map.get_value("x").unwrap().unwrap()); + assert_eq!( + Value::Primitive(Primitive::Integer(1)), + map.get_value("x").unwrap().unwrap() + ); } #[test]