From 4907dd9f8f6e7752c393e316a4eea27d1ff7fa3a Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 29 Sep 2023 02:53:31 -0400 Subject: [PATCH] Implement top-level API with docs --- src/error.rs | 57 +--- src/interface.rs | 78 +++-- src/lib.rs | 6 - src/main.rs | 22 +- src/operator.rs | 547 --------------------------------- src/token.rs | 562 ---------------------------------- src/tools/gui.rs | 3 +- src/tree/iter.rs | 94 ------ src/tree/mod.rs | 691 ------------------------------------------ src/value/function.rs | 4 +- src/value/mod.rs | 9 +- 11 files changed, 84 insertions(+), 1989 deletions(-) delete mode 100644 src/operator.rs delete mode 100644 src/token.rs delete mode 100644 src/tree/iter.rs delete mode 100644 src/tree/mod.rs diff --git a/src/error.rs b/src/error.rs index 31bb598..3aa4a24 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,10 +2,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::{ - operator::Operator, token::PartialToken, value::value_type::ValueType, value::Value, Node, - ToolInfo, -}; +use crate::{value::value_type::ValueType, value::Value, ToolInfo}; use std::{fmt, io, time::SystemTimeError}; @@ -118,10 +115,6 @@ pub enum Error { actual: Value, }, - /// Tried to append a child to a leaf node. - /// Leaf nodes cannot have children. - AppendedToLeafNode(Node), - /// Tried to append a child to a node such that the precedence of the child /// is not higher. This error should never occur. If it does, please file a /// bug report. @@ -154,9 +147,9 @@ pub enum Error { /// An operator is used with a wrong combination of types. WrongTypeCombination { /// The operator that whose evaluation caused the error. - operator: Operator, + expected: ValueType, /// The types that were used in the operator causing it to fail. - actual: Vec, + actual: ValueType, }, /// An opening brace without a matching closing brace was found. @@ -169,16 +162,6 @@ pub enum Error { /// For example, writing `4(5)` would yield this error, as the `4` does not have any operands. MissingOperatorOutsideOfBrace, - /// A `PartialToken` is unmatched, such that it cannot be combined into a full `Token`. - /// This happens if for example a single `=` is found, surrounded by whitespace. - /// It is not a token, but it is part of the string representation of some tokens. - UnmatchedPartialToken { - /// The unmatched partial token. - first: PartialToken, - /// The token that follows the unmatched partial token and that cannot be matched to the partial token, or `None`, if `first` is the last partial token in the stream. - second: Option, - }, - /// An addition operation performed by Rust failed. AdditionError { /// The first argument of the addition. @@ -351,10 +334,6 @@ impl Error { Error::TypeError { actual, expected } } - pub fn wrong_type_combination(operator: Operator, actual: Vec) -> Self { - Error::WrongTypeCombination { operator, actual } - } - pub fn expected_string(actual: Value) -> Self { Error::ExpectedString { actual } } @@ -410,13 +389,6 @@ impl Error { Error::ExpectedCollection { actual } } - pub(crate) fn unmatched_partial_token( - first: PartialToken, - second: Option, - ) -> Self { - Error::UnmatchedPartialToken { first, second } - } - pub(crate) fn addition_error(augend: Value, addend: Value) -> Self { Error::AdditionError { augend, addend } } @@ -540,7 +512,6 @@ impl fmt::Display for Error { actual ) } - AppendedToLeafNode(node) => write!(f, "Syntax error at \"{node}\"."), PrecedenceViolation => write!( f, "Tried to append a node to another node with higher precedence." @@ -561,11 +532,6 @@ impl fmt::Display for Error { "Type Error. The value {actual} is not one of the following: {expected:?}.", ) } - WrongTypeCombination { operator, actual } => write!( - f, - "The operator {:?} was called with a wrong combination of types: {:?}", - operator, actual - ), UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."), UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."), MissingOperatorOutsideOfBrace { .. } => write!( @@ -574,22 +540,6 @@ impl fmt::Display for Error { any arguments on the right, or found a closing parenthesis that is succeeded by \ something that does not take any arguments on the left." ), - UnmatchedPartialToken { first, second } => { - if let Some(second) = second { - write!( - f, - "Found a partial token '{}' that should not be followed by '{}'.", - first, second - ) - } else { - write!( - f, - "Found a partial token '{}' that should be followed by another partial \ - token.", - first - ) - } - } AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend), SubtractionError { minuend, @@ -637,6 +587,7 @@ impl fmt::Display for Error { ), UnexpectedSourceNode { expected, actual } => write!(f, "Unexpected source node. 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}."), } } } diff --git a/src/interface.rs b/src/interface.rs index 2823519..9abc222 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,58 +1,62 @@ -//! The top level of Dust's API with functions in interpret Dust code. - -use std::ops::Range; +//! The top level of Dust's API with functions to interpret Dust code. use tree_sitter::{Node, Parser, Tree, TreeCursor}; use crate::{language, Error, Result, Value, VariableMap}; -/// Evaluate the given expression string. +/// Evaluate the given source code. +/// +/// Returns a vector of results from evaluating the source code. Each comment +/// and statemtent will have its own result. /// /// # Examples /// /// ```rust /// # use dust_lib::*; -/// assert_eq!(eval("1 + 2 + 3"), Ok(Value::from(6))); +/// assert_eq!(eval("1 + 2 + 3"), vec![Ok(Value::from(6))]); /// ``` -/// -/// *See the [crate doc](index.html) for more examples and explanations of the expression format.* -pub fn eval(source: &str) -> Result { +pub fn eval(source: &str) -> Vec> { let mut context = VariableMap::new(); eval_with_context(source, &mut context) } -/// Evaluate the given expression string with the given context. +/// Evaluate the given source code with the given context. /// /// # Examples /// /// ```rust /// # use dust_lib::*; /// let mut context = VariableMap::new(); +/// /// context.set_value("one".into(), 1.into()).unwrap(); // Do proper error handling here /// context.set_value("two".into(), 2.into()).unwrap(); // Do proper error handling here /// context.set_value("three".into(), 3.into()).unwrap(); // Do proper error handling here -/// assert_eq!(eval_with_context("one + two + three", &mut context), Ok(Value::from(6))); +/// +/// let dust_code = "one + two + three; one - two - three;"; +/// +/// assert_eq!( +/// eval_with_context(dust_code, &mut context), +/// vec![Ok(Value::from(6)), Ok(Value::from(-4))] +/// ); /// ``` -pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Result { +pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec> { let mut parser = Parser::new(); parser.set_language(language()).unwrap(); let tree = parser.parse(source, None).unwrap(); let sexp = tree.root_node().to_sexp(); - - println!("{sexp}"); - let evaluator = Evaluator::new(tree.clone(), source).unwrap(); let mut cursor = tree.walk(); - let results = evaluator.run(context, &mut cursor, source); + println!("{sexp}"); println!("{evaluator:?}"); println!("{results:?}"); + println!("{context:?}"); - Ok(Value::Empty) + results } #[derive(Debug)] @@ -159,7 +163,7 @@ impl Statement { #[derive(Debug)] enum Expression { - Identifier(&'static str), + Identifier(String), Value(Value), Operation(Operation), } @@ -176,7 +180,10 @@ impl Expression { let child = node.child(0).unwrap(); if child.kind() == "identifier" { - todo!() + let byte_range = child.byte_range(); + let identifier = &source[byte_range]; + + Ok(Self::Identifier(identifier.to_string())) } else if child.kind() == "value" { Ok(Expression::Value(Value::new(child, source)?)) } else if child.kind() == "operation" { @@ -214,7 +221,7 @@ impl Expression { #[derive(Debug)] struct Operation { left: Box, - operator: &'static str, + operator: String, right: Box, } @@ -224,7 +231,7 @@ impl Operation { let second_child = node.child(1).unwrap(); let third_child = node.child(2).unwrap(); let left = { Box::new(Expression::new(first_child, source)?) }; - let operator = { second_child.child(0).unwrap().kind() }; + let operator = { second_child.child(0).unwrap().kind().to_string() }; let right = { Box::new(Expression::new(third_child, source)?) }; Ok(Operation { @@ -242,11 +249,40 @@ impl Operation { ) -> Result { let left = self.left.run(context, &mut cursor, source)?; let right = self.right.run(context, &mut cursor, source)?; - let result = match self.operator { + let result = match self.operator.as_str() { "+" => left + right, + "=" => { + if let Expression::Identifier(key) = self.left.as_ref() { + context.set_value(key, right)?; + } + + Ok(Value::Empty) + } _ => return Err(Error::CustomMessage("Operator not supported.".to_string())), }; Ok(result?) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn evaluate_empty() { + assert_eq!(eval("()"), vec![Ok(Value::Empty)]); + assert_eq!(eval("1;"), vec![Ok(Value::Empty)]); + assert_eq!(eval("'foobar';"), vec![Ok(Value::Empty)]); + } + + #[test] + fn evaluate_integer() { + assert_eq!(eval("1"), vec![Ok(Value::Integer(1))]); + } + + #[test] + fn evaluate_string() { + assert_eq!(eval("'one'"), vec![Ok(Value::String("one".to_string()))]); + } +} diff --git a/src/lib.rs b/src/lib.rs index 55860c7..a8a046b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,7 @@ pub use crate::{ error::*, interface::*, - operator::Operator, - token::PartialToken, tools::{Tool, ToolInfo, TOOL_LIST}, - tree::Node, value::{ function::Function, table::Table, time::Time, value_type::ValueType, variable_map::VariableMap, Value, @@ -21,9 +18,6 @@ pub mod tools; mod error; mod interface; -mod operator; -mod token; -mod tree; mod value; use tree_sitter::Language; diff --git a/src/main.rs b/src/main.rs index a94d623..4c5f338 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,19 +32,21 @@ fn main() { return run_cli_shell(); } - let eval_result = if let Some(path) = args.path { + let eval_results = if let Some(path) = args.path { let file_contents = read_to_string(path).unwrap(); eval(&file_contents) } else if let Some(command) = args.command { eval(&command) } else { - Ok(Value::Empty) + vec![Ok(Value::Empty)] }; - match eval_result { - Ok(value) => println!("{value}"), - Err(error) => eprintln!("{error}"), + for result in eval_results { + match result { + Ok(value) => println!("{value}"), + Err(error) => eprintln!("{error}"), + } } } @@ -147,11 +149,13 @@ fn run_cli_shell() { rl.add_history_entry(line).unwrap(); - let eval_result = eval_with_context(line, &mut context); + let eval_results = eval_with_context(line, &mut context); - match eval_result { - Ok(value) => println!("{value}"), - Err(error) => eprintln!("{error}"), + for result in eval_results { + match result { + Ok(value) => println!("{value}"), + Err(error) => eprintln!("{error}"), + } } } Err(ReadlineError::Interrupted) => { diff --git a/src/operator.rs b/src/operator.rs deleted file mode 100644 index 1809794..0000000 --- a/src/operator.rs +++ /dev/null @@ -1,547 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use crate::{error::*, value::Value, Result, VariableMap}; - -/// An enum that represents operators in the operator tree. -#[derive(Debug, PartialEq, Clone)] -pub enum Operator { - /// A root node in the operator tree. - /// The whole expression is stored under a root node, as well as each subexpression surrounded by parentheses. - RootNode, - - /// A binary addition operator. - Add, - /// A binary subtraction operator. - Sub, - /// A unary negation operator. - Neg, - /// A binary multiplication operator. - Mul, - /// A binary division operator. - Div, - /// A binary modulo operator. - Mod, - /// A binary exponentiation operator. - Exp, - - /// A binary equality comparator. - Eq, - /// A binary inequality comparator. - Neq, - /// A binary greater-than comparator. - Gt, - /// A binary lower-than comparator. - Lt, - /// A binary greater-than-or-equal comparator. - Geq, - /// A binary lower-than-or-equal comparator. - Leq, - /// A binary logical and operator. - And, - /// A binary logical or operator. - Or, - /// A binary logical not operator. - Not, - - /// A binary assignment operator. - Assign, - /// A binary add-assign operator. - AddAssign, - /// A binary subtract-assign operator. - SubAssign, - /// A binary multiply-assign operator. - MulAssign, - /// A binary divide-assign operator. - DivAssign, - /// A binary modulo-assign operator. - ModAssign, - /// A binary exponentiate-assign operator. - ExpAssign, - /// A binary and-assign operator. - AndAssign, - /// A binary or-assign operator. - OrAssign, - - /// An n-ary tuple constructor. - Tuple, - /// An n-ary subexpression chain. - Chain, - - /// A constant value. - Const { - /** The value of the constant. */ - value: Value, - }, - /// A write to a variable identifier. - VariableIdentifierWrite { - /// The identifier of the variable. - identifier: String, - }, - /// A read from a variable identifier. - VariableIdentifierRead { - /// The identifier of the variable. - identifier: String, - }, - /// A function identifier. - FunctionIdentifier { - /// The identifier of the function. - identifier: String, - }, -} - -impl Operator { - pub(crate) fn value(value: Value) -> Self { - Operator::Const { value } - } - - pub(crate) fn variable_identifier_write(identifier: String) -> Self { - Operator::VariableIdentifierWrite { identifier } - } - - pub(crate) fn variable_identifier_read(identifier: String) -> Self { - Operator::VariableIdentifierRead { identifier } - } - - pub(crate) fn function_identifier(identifier: String) -> Self { - Operator::FunctionIdentifier { identifier } - } - - /// Returns the precedence of the operator. - /// A high precedence means that the operator has priority to be deeper in the tree. - pub(crate) const fn precedence(&self) -> i32 { - use crate::operator::Operator::*; - match self { - RootNode => 200, - - Add | Sub => 95, - Neg => 110, - Mul | Div | Mod => 100, - Exp => 120, - - Eq | Neq | Gt | Lt | Geq | Leq => 80, - And => 75, - Or => 70, - Not => 110, - - Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign - | AndAssign | OrAssign => 50, - - Tuple => 40, - Chain => 0, - - Const { .. } => 200, - VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => 200, - FunctionIdentifier { .. } => 190, - } - } - - /// Returns true if chains of operators with the same precedence as this one should be evaluated left-to-right, - /// and false if they should be evaluated right-to-left. - /// Left-to-right chaining has priority if operators with different order but same precedence are chained. - pub(crate) const fn is_left_to_right(&self) -> bool { - use crate::operator::Operator::*; - !matches!(self, Assign | FunctionIdentifier { .. }) - } - - /// Returns true if chains of this operator should be flattened into one operator with many arguments. - pub(crate) const fn is_sequence(&self) -> bool { - use crate::operator::Operator::*; - matches!(self, Tuple | Chain) - } - - /// True if this operator is a leaf, meaning it accepts no arguments. - // Make this a const fn as soon as whatever is missing gets stable (issue #57563) - pub(crate) fn is_leaf(&self) -> bool { - self.max_argument_amount() == Some(0) - } - - /// Returns the maximum amount of arguments required by this operator. - pub(crate) const fn max_argument_amount(&self) -> Option { - use crate::operator::Operator::*; - match self { - Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or - | Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign - | AndAssign | OrAssign => Some(2), - Tuple | Chain => None, - Not | Neg | RootNode => Some(1), - Const { .. } => Some(0), - VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => Some(0), - FunctionIdentifier { .. } => Some(1), - } - } - - /// Returns true if this operator is unary, i.e. it requires exactly one argument. - pub(crate) fn is_unary(&self) -> bool { - self.max_argument_amount() == Some(1) && *self != Operator::RootNode - } - - /// Evaluates the operator with the given arguments and context. - pub(crate) fn eval(&self, arguments: &[Value], context: &VariableMap) -> Result { - use crate::operator::Operator::*; - - match self { - RootNode => { - if let Some(first) = arguments.first() { - Ok(first.clone()) - } else { - Ok(Value::Empty) - } - } - Add => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - expect_number_or_string(&arguments[0])?; - expect_number_or_string(&arguments[1])?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { - let mut result = String::with_capacity(a.len() + b.len()); - result.push_str(a); - result.push_str(b); - Ok(Value::String(result)) - } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - let result = a.checked_add(b); - if let Some(result) = result { - Ok(Value::Integer(result)) - } else { - Err(Error::addition_error( - arguments[0].clone(), - arguments[1].clone(), - )) - } - } else if let (Ok(a), Ok(b)) = (arguments[0].as_number(), arguments[1].as_number()) - { - Ok(Value::Float(a + b)) - } else { - Err(Error::wrong_type_combination( - self.clone(), - vec![ - arguments.get(0).unwrap().into(), - arguments.get(1).unwrap().into(), - ], - )) - } - } - Sub => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - arguments[0].as_number()?; - arguments[1].as_number()?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - let result = a.checked_sub(b); - if let Some(result) = result { - Ok(Value::Integer(result)) - } else { - Err(Error::subtraction_error( - arguments[0].clone(), - arguments[1].clone(), - )) - } - } else { - Ok(Value::Float( - arguments[0].as_number()? - arguments[1].as_number()?, - )) - } - } - Neg => { - Error::expect_operator_argument_amount(arguments.len(), 1)?; - arguments[0].as_number()?; - - if let Ok(a) = arguments[0].as_int() { - let result = a.checked_neg(); - if let Some(result) = result { - Ok(Value::Integer(result)) - } else { - Err(Error::negation_error(arguments[0].clone())) - } - } else { - Ok(Value::Float(-arguments[0].as_number()?)) - } - } - Mul => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - arguments[0].as_number()?; - arguments[1].as_number()?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - let result = a.checked_mul(b); - if let Some(result) = result { - Ok(Value::Integer(result)) - } else { - Err(Error::multiplication_error( - arguments[0].clone(), - arguments[1].clone(), - )) - } - } else { - Ok(Value::Float( - arguments[0].as_number()? * arguments[1].as_number()?, - )) - } - } - Div => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - arguments[0].as_number()?; - arguments[1].as_number()?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - let result = a.checked_div(b); - if let Some(result) = result { - Ok(Value::Integer(result)) - } else { - Err(Error::division_error( - arguments[0].clone(), - arguments[1].clone(), - )) - } - } else { - Ok(Value::Float( - arguments[0].as_number()? / arguments[1].as_number()?, - )) - } - } - Mod => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - arguments[0].as_number()?; - arguments[1].as_number()?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - let result = a.checked_rem(b); - if let Some(result) = result { - Ok(Value::Integer(result)) - } else { - Err(Error::modulation_error( - arguments[0].clone(), - arguments[1].clone(), - )) - } - } else { - Ok(Value::Float( - arguments[0].as_number()? % arguments[1].as_number()?, - )) - } - } - Exp => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - arguments[0].as_number()?; - arguments[1].as_number()?; - - Ok(Value::Float( - arguments[0].as_number()?.powf(arguments[1].as_number()?), - )) - } - Eq => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - - Ok(Value::Boolean(arguments[0] == arguments[1])) - } - Neq => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - - Ok(Value::Boolean(arguments[0] != arguments[1])) - } - Gt => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - expect_number_or_string(&arguments[0])?; - expect_number_or_string(&arguments[1])?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { - Ok(Value::Boolean(a > b)) - } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - Ok(Value::Boolean(a > b)) - } else { - Ok(Value::Boolean( - arguments[0].as_number()? > arguments[1].as_number()?, - )) - } - } - Lt => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - expect_number_or_string(&arguments[0])?; - expect_number_or_string(&arguments[1])?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { - Ok(Value::Boolean(a < b)) - } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - Ok(Value::Boolean(a < b)) - } else { - Ok(Value::Boolean( - arguments[0].as_number()? < arguments[1].as_number()?, - )) - } - } - Geq => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - expect_number_or_string(&arguments[0])?; - expect_number_or_string(&arguments[1])?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { - Ok(Value::Boolean(a >= b)) - } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - Ok(Value::Boolean(a >= b)) - } else { - Ok(Value::Boolean( - arguments[0].as_number()? >= arguments[1].as_number()?, - )) - } - } - Leq => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - expect_number_or_string(&arguments[0])?; - expect_number_or_string(&arguments[1])?; - - if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) { - Ok(Value::Boolean(a <= b)) - } else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) { - Ok(Value::Boolean(a <= b)) - } else { - Ok(Value::Boolean( - arguments[0].as_number()? <= arguments[1].as_number()?, - )) - } - } - And => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - let a = arguments[0].as_boolean()?; - let b = arguments[1].as_boolean()?; - - Ok(Value::Boolean(a && b)) - } - Or => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - let a = arguments[0].as_boolean()?; - let b = arguments[1].as_boolean()?; - - Ok(Value::Boolean(a || b)) - } - Not => { - Error::expect_operator_argument_amount(arguments.len(), 1)?; - let a = arguments[0].as_boolean()?; - - Ok(Value::Boolean(!a)) - } - Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign - | AndAssign | OrAssign => Err(Error::ContextNotMutable), - Tuple => Ok(Value::List(arguments.into())), - Chain => { - if arguments.is_empty() { - return Err(Error::expect_operator_argument_amount(0, 1).unwrap_err()); - } - - Ok(arguments.last().cloned().unwrap_or(Value::Empty)) - } - Const { value } => { - Error::expect_operator_argument_amount(arguments.len(), 0)?; - - Ok(value.clone()) - } - VariableIdentifierWrite { identifier } => { - Error::expect_operator_argument_amount(arguments.len(), 0)?; - - Ok(identifier.clone().into()) - } - VariableIdentifierRead { identifier } => { - Error::expect_operator_argument_amount(arguments.len(), 0)?; - - if let Some(value) = context.get_value(identifier)? { - Ok(value) - } else { - Err(Error::VariableIdentifierNotFound(identifier.clone())) - } - } - FunctionIdentifier { identifier } => { - Error::expect_operator_argument_amount(arguments.len(), 1)?; - let arguments = &arguments[0]; - - context.call_function(identifier, arguments) - } - } - } - - /// Evaluates the operator with the given arguments and mutable context. - pub(crate) fn eval_mut(&self, arguments: &[Value], context: &mut VariableMap) -> Result { - use crate::operator::Operator::*; - match self { - Assign => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - let target = arguments[0].as_string()?; - context.set_value(target, arguments[1].clone())?; - - Ok(Value::Empty) - } - AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign | AndAssign - | OrAssign => { - Error::expect_operator_argument_amount(arguments.len(), 2)?; - - let target = arguments[0].as_string()?; - let left_value = Operator::VariableIdentifierRead { - identifier: target.clone(), - } - .eval(&Vec::new(), context)?; - let arguments = vec![left_value, arguments[1].clone()]; - - let result = match self { - AddAssign => Operator::Add.eval(&arguments, context), - SubAssign => Operator::Sub.eval(&arguments, context), - MulAssign => Operator::Mul.eval(&arguments, context), - DivAssign => Operator::Div.eval(&arguments, context), - ModAssign => Operator::Mod.eval(&arguments, context), - ExpAssign => Operator::Exp.eval(&arguments, context), - AndAssign => Operator::And.eval(&arguments, context), - OrAssign => Operator::Or.eval(&arguments, context), - _ => unreachable!( - "Forgot to add a match arm for an assign operation: {}", - self - ), - }?; - context.set_value(target, result)?; - - Ok(Value::Empty) - } - _ => self.eval(arguments, context), - } - } -} - -impl Display for Operator { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use crate::operator::Operator::*; - match self { - RootNode => Ok(()), - Add => write!(f, "+"), - Sub => write!(f, "-"), - Neg => write!(f, "-"), - Mul => write!(f, "*"), - Div => write!(f, "/"), - Mod => write!(f, "%"), - Exp => write!(f, "^"), - - Eq => write!(f, "=="), - Neq => write!(f, "!="), - Gt => write!(f, ">"), - Lt => write!(f, "<"), - Geq => write!(f, ">="), - Leq => write!(f, "<="), - And => write!(f, "&&"), - Or => write!(f, "||"), - Not => write!(f, "!"), - - Assign => write!(f, " = "), - AddAssign => write!(f, " += "), - SubAssign => write!(f, " -= "), - MulAssign => write!(f, " *= "), - DivAssign => write!(f, " /= "), - ModAssign => write!(f, " %= "), - ExpAssign => write!(f, " ^= "), - AndAssign => write!(f, " &&= "), - OrAssign => write!(f, " ||= "), - - Tuple => write!(f, ", "), - Chain => write!(f, "; "), - - Const { value } => write!(f, "{}", value), - VariableIdentifierWrite { identifier } | VariableIdentifierRead { identifier } => { - write!(f, "{}", identifier) - } - FunctionIdentifier { identifier } => write!(f, "{}", identifier), - } - } -} diff --git a/src/token.rs b/src/token.rs deleted file mode 100644 index f974c59..0000000 --- a/src/token.rs +++ /dev/null @@ -1,562 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use crate::error::{Error, Result}; - -#[derive(Clone, PartialEq, Debug)] -pub enum Token { - // Arithmetic - Plus, - Minus, - Star, - Slash, - Percent, - Hat, - - // Logic - Eq, - Neq, - Gt, - Lt, - Geq, - Leq, - And, - Or, - Not, - - // Precedence - LBrace, - RBrace, - - // Assignment - Assign, - PlusAssign, - MinusAssign, - StarAssign, - SlashAssign, - PercentAssign, - HatAssign, - AndAssign, - OrAssign, - - // Special - Comma, - Semicolon, - Yield(String, String), - - // Values, Variables and Functions - Identifier(String), - Float(f64), - Int(i64), - Boolean(bool), - String(String), - Function(String), -} - -/// A partial token is an input character whose meaning depends on the characters around it. -#[derive(Clone, Debug, PartialEq)] -pub enum PartialToken { - /// A partial token that unambiguously maps to a single token. - Token(Token), - /// A partial token that is a literal. - Literal(String), - /// A plus character '+'. - Plus, - /// A minus character '-'. - Minus, - /// A star character '*'. - Star, - /// A slash character '/'. - Slash, - /// A percent character '%'. - Percent, - /// A hat character '^'. - Hat, - /// A whitespace character, e.g. ' '. - Whitespace, - /// An equal-to character '='. - Eq, - /// An exclamation mark character '!'. - ExclamationMark, - /// A greater-than character '>'. - Gt, - /// A lower-than character '<'. - Lt, - /// An ampersand character '&'. - Ampersand, - /// A vertical bar character '|'. - VerticalBar, -} - -// Make this a const fn as soon as is_whitespace and to_string get stable (issue #57563) -fn char_to_partial_token(c: char) -> PartialToken { - match c { - '+' => PartialToken::Plus, - '-' => PartialToken::Minus, - '*' => PartialToken::Star, - '/' => PartialToken::Slash, - '%' => PartialToken::Percent, - '^' => PartialToken::Hat, - - '(' => PartialToken::Token(Token::LBrace), - ')' => PartialToken::Token(Token::RBrace), - - ',' => PartialToken::Token(Token::Comma), - ';' => PartialToken::Token(Token::Semicolon), - - '=' => PartialToken::Eq, - '!' => PartialToken::ExclamationMark, - '>' => PartialToken::Gt, - '<' => PartialToken::Lt, - '&' => PartialToken::Ampersand, - '|' => PartialToken::VerticalBar, - - c => { - if c.is_whitespace() { - PartialToken::Whitespace - } else { - PartialToken::Literal(c.to_string()) - } - } - } -} - -impl Token { - #[cfg(not(tarpaulin_include))] - pub(crate) const fn is_leftsided_value(&self) -> bool { - match self { - Token::Plus => false, - Token::Minus => false, - Token::Star => false, - Token::Slash => false, - Token::Percent => false, - Token::Hat => false, - - Token::Eq => false, - Token::Neq => false, - Token::Gt => false, - Token::Lt => false, - Token::Geq => false, - Token::Leq => false, - Token::And => false, - Token::Or => false, - Token::Not => false, - - Token::LBrace => true, - Token::RBrace => false, - - Token::Comma => false, - Token::Semicolon => false, - Token::Yield(_, _) => false, - - Token::Assign => false, - Token::PlusAssign => false, - Token::MinusAssign => false, - Token::StarAssign => false, - Token::SlashAssign => false, - Token::PercentAssign => false, - Token::HatAssign => false, - Token::AndAssign => false, - Token::OrAssign => false, - - Token::Identifier(_) => true, - Token::Float(_) => true, - Token::Int(_) => true, - Token::Boolean(_) => true, - Token::String(_) => true, - Token::Function(_) => true, - } - } - - #[cfg(not(tarpaulin_include))] - pub(crate) const fn is_rightsided_value(&self) -> bool { - match self { - Token::Plus => false, - Token::Minus => false, - Token::Star => false, - Token::Slash => false, - Token::Percent => false, - Token::Hat => false, - - Token::Eq => false, - Token::Neq => false, - Token::Gt => false, - Token::Lt => false, - Token::Geq => false, - Token::Leq => false, - Token::And => false, - Token::Or => false, - Token::Not => false, - - Token::LBrace => false, - Token::RBrace => true, - - Token::Comma => false, - Token::Semicolon => false, - Token::Yield(_, _) => false, - - Token::Assign => false, - Token::PlusAssign => false, - Token::MinusAssign => false, - Token::StarAssign => false, - Token::SlashAssign => false, - Token::PercentAssign => false, - Token::HatAssign => false, - Token::AndAssign => false, - Token::OrAssign => false, - - Token::Identifier(_) => true, - Token::Float(_) => true, - Token::Int(_) => true, - Token::Boolean(_) => true, - Token::String(_) => true, - Token::Function(_) => true, - } - } - - #[cfg(not(tarpaulin_include))] - pub(crate) fn is_assignment(&self) -> bool { - use Token::*; - matches!( - self, - Assign - | PlusAssign - | MinusAssign - | StarAssign - | SlashAssign - | PercentAssign - | HatAssign - | AndAssign - | OrAssign - ) - } -} - -/// Parses an escape sequence within a string literal. -fn parse_escape_sequence>(iter: &mut Iter) -> Result { - match iter.next() { - Some('"') => Ok('"'), - Some('\\') => Ok('\\'), - Some(c) => Err(Error::IllegalEscapeSequence(format!("\\{}", c))), - None => Err(Error::IllegalEscapeSequence("\\".to_string())), - } -} - -/// Parses a string value from the given character iterator. -/// -/// The first character from the iterator is interpreted as first character of the string. -/// The string is terminated by a double quote `"`. -/// Occurrences of `"` within the string can be escaped with `\`. -/// The backslash needs to be escaped with another backslash `\`. -fn parse_string_literal>(mut iter: &mut Iter) -> Result { - let mut result = String::new(); - - while let Some(c) = iter.next() { - match c { - '"' => break, - '\\' => result.push(parse_escape_sequence(&mut iter)?), - c => result.push(c), - } - } - - Ok(PartialToken::Token(Token::String(result))) -} - -fn parse_function>(mut iter: &mut Iter) -> Result { - let mut result = String::new(); - - while let Some(c) = iter.next() { - match c { - '\'' => break, - '\\' => result.push(parse_escape_sequence(&mut iter)?), - c => result.push(c), - } - } - - Ok(PartialToken::Token(Token::Function(result))) -} - -/// Converts a string to a vector of partial tokens. -fn str_to_partial_tokens(string: &str) -> Result> { - let mut result = Vec::new(); - let mut iter = string.chars().peekable(); - - while let Some(c) = iter.next() { - if c == '"' { - result.push(parse_string_literal(&mut iter)?); - } else if c == '\'' { - result.push(parse_function(&mut iter)?) - } else { - let partial_token = char_to_partial_token(c); - - let if_let_successful = - if let (Some(PartialToken::Literal(last)), PartialToken::Literal(literal)) = - (result.last_mut(), &partial_token) - { - last.push_str(literal); - true - } else { - false - }; - - if !if_let_successful { - result.push(partial_token); - } - } - } - Ok(result) -} - -/// Resolves all partial tokens by converting them to complex tokens. -fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> Result> { - let mut result = Vec::new(); - while !tokens.is_empty() { - let first = tokens[0].clone(); - let second = tokens.get(1).cloned(); - let third = tokens.get(2).cloned(); - let mut cutoff = 2; - - result.extend( - match first { - PartialToken::Token(token) => { - cutoff = 1; - Some(token) - } - PartialToken::Plus => match second { - Some(PartialToken::Eq) => Some(Token::PlusAssign), - _ => { - cutoff = 1; - Some(Token::Plus) - } - }, - PartialToken::Minus => match second { - Some(PartialToken::Eq) => Some(Token::MinusAssign), - _ => { - cutoff = 1; - Some(Token::Minus) - } - }, - PartialToken::Star => match second { - Some(PartialToken::Eq) => Some(Token::StarAssign), - _ => { - cutoff = 1; - Some(Token::Star) - } - }, - PartialToken::Slash => match second { - Some(PartialToken::Eq) => Some(Token::SlashAssign), - _ => { - cutoff = 1; - Some(Token::Slash) - } - }, - PartialToken::Percent => match second { - Some(PartialToken::Eq) => Some(Token::PercentAssign), - _ => { - cutoff = 1; - Some(Token::Percent) - } - }, - PartialToken::Hat => match second { - Some(PartialToken::Eq) => Some(Token::HatAssign), - _ => { - cutoff = 1; - Some(Token::Hat) - } - }, - PartialToken::Literal(literal) => { - cutoff = 1; - if let Ok(number) = parse_dec_or_hex(&literal) { - Some(Token::Int(number)) - } else if let Ok(number) = literal.parse::() { - Some(Token::Float(number)) - } else if let Ok(boolean) = literal.parse::() { - Some(Token::Boolean(boolean)) - } else { - // If there are two tokens following this one, check if the next one is - // a plus or a minus. If so, then attempt to parse all three tokens as a - // scientific notation number of the form `e{+,-}`, - // for example [Literal("10e"), Minus, Literal("3")] => "1e-3".parse(). - match (second, third) { - (Some(second), Some(third)) - if second == PartialToken::Minus - || second == PartialToken::Plus => - { - if let Ok(number) = - format!("{}{}{}", literal, second, third).parse::() - { - cutoff = 3; - Some(Token::Float(number)) - } else { - Some(Token::Identifier(literal.to_string())) - } - } - _ => Some(Token::Identifier(literal.to_string())), - } - } - } - PartialToken::Whitespace => { - cutoff = 1; - None - } - PartialToken::Eq => match second { - Some(PartialToken::Eq) => Some(Token::Eq), - _ => { - cutoff = 1; - Some(Token::Assign) - } - }, - PartialToken::ExclamationMark => match second { - Some(PartialToken::Eq) => Some(Token::Neq), - _ => { - cutoff = 1; - Some(Token::Not) - } - }, - PartialToken::Gt => match second { - Some(PartialToken::Eq) => Some(Token::Geq), - _ => { - cutoff = 1; - Some(Token::Gt) - } - }, - PartialToken::Lt => match second { - Some(PartialToken::Eq) => Some(Token::Leq), - _ => { - cutoff = 1; - Some(Token::Lt) - } - }, - PartialToken::Ampersand => match second { - Some(PartialToken::Ampersand) => match third { - Some(PartialToken::Eq) => { - cutoff = 3; - Some(Token::AndAssign) - } - _ => Some(Token::And), - }, - _ => return Err(Error::unmatched_partial_token(first, second)), - }, - PartialToken::VerticalBar => match second { - Some(PartialToken::VerticalBar) => match third { - Some(PartialToken::Eq) => { - cutoff = 3; - Some(Token::OrAssign) - } - _ => Some(Token::Or), - }, - _ => return Err(Error::unmatched_partial_token(first, second)), - }, - } - .into_iter(), - ); - - tokens = &tokens[cutoff..]; - } - Ok(result) -} - -impl Display for Token { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use self::Token::*; - match self { - Plus => write!(f, "+"), - Minus => write!(f, "-"), - Star => write!(f, "*"), - Slash => write!(f, "/"), - Percent => write!(f, "%"), - Hat => write!(f, "^"), - - // Logic - Eq => write!(f, "=="), - Neq => write!(f, "!="), - Gt => write!(f, ">"), - Lt => write!(f, "<"), - Geq => write!(f, ">="), - Leq => write!(f, "<="), - And => write!(f, "&&"), - Or => write!(f, "||"), - Not => write!(f, "!"), - - // Precedence - LBrace => write!(f, "("), - RBrace => write!(f, ")"), - - // Assignment - Assign => write!(f, "="), - PlusAssign => write!(f, "+="), - MinusAssign => write!(f, "-="), - StarAssign => write!(f, "*="), - SlashAssign => write!(f, "/="), - PercentAssign => write!(f, "%="), - HatAssign => write!(f, "^="), - AndAssign => write!(f, "&&="), - OrAssign => write!(f, "||="), - - // Special - Comma => write!(f, ","), - Semicolon => write!(f, ";"), - - // Values => write!(f, ""), Variables and Functions - Identifier(identifier) => identifier.fmt(f), - Float(float) => float.fmt(f), - Int(int) => int.fmt(f), - Boolean(boolean) => boolean.fmt(f), - String(string) => fmt::Debug::fmt(string, f), - Function(string) => write!(f, "'{string}'"), - Yield(_, _) => todo!(), - } - } -} - -impl Display for PartialToken { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use self::PartialToken::*; - match self { - Token(token) => token.fmt(f), - Literal(literal) => literal.fmt(f), - Whitespace => write!(f, " "), - Plus => write!(f, "+"), - Minus => write!(f, "-"), - Star => write!(f, "*"), - Slash => write!(f, "/"), - Percent => write!(f, "%"), - Hat => write!(f, "^"), - Eq => write!(f, "="), - ExclamationMark => write!(f, "!"), - Gt => write!(f, ">"), - Lt => write!(f, "<"), - Ampersand => write!(f, "&"), - VerticalBar => write!(f, "|"), - } - } -} - -pub(crate) fn tokenize(string: &str) -> Result> { - partial_tokens_to_tokens(&str_to_partial_tokens(string)?) -} - -fn parse_dec_or_hex(literal: &str) -> std::result::Result { - if let Some(literal) = literal.strip_prefix("0x") { - literal.parse() - } else { - literal.parse() - } -} - -#[cfg(test)] -mod tests { - use crate::token::{tokenize, Token}; - - #[test] - fn assignment_lhs_is_identifier() { - let tokens = tokenize("a = 1").unwrap(); - assert_eq!( - tokens.as_slice(), - [ - Token::Identifier("a".to_string()), - Token::Assign, - Token::Int(1) - ] - ); - } -} diff --git a/src/tools/gui.rs b/src/tools/gui.rs index 077d6b8..e232faf 100644 --- a/src/tools/gui.rs +++ b/src/tools/gui.rs @@ -233,8 +233,7 @@ impl eframe::App for GuiApp { } if submit.clicked() { - self.eval_result = - eval_with_context(&self.text_edit_buffer, &mut self.whale_context); + todo!() } }); }, diff --git a/src/tree/iter.rs b/src/tree/iter.rs deleted file mode 100644 index 0524361..0000000 --- a/src/tree/iter.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{operator::Operator, Node}; -use std::slice::{Iter, IterMut}; - -/// An iterator that traverses an operator tree in pre-order. -pub struct NodeIter<'a> { - stack: Vec>, -} - -impl<'a> NodeIter<'a> { - fn new(node: &'a Node) -> Self { - NodeIter { - stack: vec![node.children.iter()], - } - } -} - -impl<'a> Iterator for NodeIter<'a> { - type Item = &'a Node; - - fn next(&mut self) -> Option { - loop { - let mut result = None; - - if let Some(last) = self.stack.last_mut() { - if let Some(next) = last.next() { - result = Some(next); - } else { - // Can not fail because we just borrowed last. - // We just checked that the iterator is empty, so we can safely discard it. - let _ = self.stack.pop().unwrap(); - } - } else { - return None; - } - - if let Some(result) = result { - self.stack.push(result.children.iter()); - return Some(result); - } - } - } -} - -/// An iterator that mutably traverses an operator tree in pre-order. -pub struct OperatorIterMut<'a> { - stack: Vec>, -} - -impl<'a> OperatorIterMut<'a> { - fn new(node: &'a mut Node) -> Self { - OperatorIterMut { - stack: vec![node.children.iter_mut()], - } - } -} - -impl<'a> Iterator for OperatorIterMut<'a> { - type Item = &'a mut Operator; - - fn next(&mut self) -> Option { - loop { - let mut result = None; - - if let Some(last) = self.stack.last_mut() { - if let Some(next) = last.next() { - result = Some(next); - } else { - // Can not fail because we just borrowed last. - // We just checked that the iterator is empty, so we can safely discard it. - let _ = self.stack.pop().unwrap(); - } - } else { - return None; - } - - if let Some(result) = result { - self.stack.push(result.children.iter_mut()); - return Some(&mut result.operator); - } - } - } -} - -impl Node { - /// Returns an iterator over all nodes in this tree. - pub fn iter(&self) -> impl Iterator { - NodeIter::new(self) - } - - /// Returns a mutable iterator over all operators in this tree. - pub fn iter_operators_mut(&mut self) -> impl Iterator { - OperatorIterMut::new(self) - } -} diff --git a/src/tree/mod.rs b/src/tree/mod.rs deleted file mode 100644 index 4f93746..0000000 --- a/src/tree/mod.rs +++ /dev/null @@ -1,691 +0,0 @@ -use crate::Function; -use crate::{token::Token, VariableMap}; - -use crate::{ - error::{Error, Result}, - operator::*, - value::Value, -}; -use std::{ - fmt::{self, Display, Formatter}, - mem, -}; - -#[cfg(not(tarpaulin_include))] -mod iter; - -/// A node in the operator tree. -/// The operator tree is created by the crate-level `build_operator_tree` method. -/// It can be evaluated for a given context with the `Node::eval` method. -/// -/// The advantage of constructing the operator tree separately from the actual evaluation is that it can be evaluated arbitrarily often with different contexts. -#[derive(Debug, PartialEq, Clone)] -pub struct Node { - operator: Operator, - children: Vec, -} - -impl Node { - fn new(operator: Operator) -> Self { - Self { - children: Vec::new(), - operator, - } - } - - fn root_node() -> Self { - Self::new(Operator::RootNode) - } - - pub fn iter_identifiers(&self) -> impl Iterator { - self.iter().filter_map(|node| match node.operator() { - Operator::VariableIdentifierWrite { identifier } - | Operator::VariableIdentifierRead { identifier } - | Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()), - _ => None, - }) - } - - /// Returns an iterator over all identifiers in this expression, allowing mutation. - /// Each occurrence of an identifier is returned separately. - pub fn iter_identifiers_mut(&mut self) -> impl Iterator { - self.iter_operators_mut() - .filter_map(|operator| match operator { - Operator::VariableIdentifierWrite { identifier } - | Operator::VariableIdentifierRead { identifier } - | Operator::FunctionIdentifier { identifier } => Some(identifier), - _ => None, - }) - } - - /// Returns an iterator over all variable identifiers in this expression. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_variable_identifiers(&self) -> impl Iterator { - self.iter().filter_map(|node| match node.operator() { - Operator::VariableIdentifierWrite { identifier } - | Operator::VariableIdentifierRead { identifier } => Some(identifier.as_str()), - _ => None, - }) - } - - /// Returns an iterator over all variable identifiers in this expression, allowing mutation. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_variable_identifiers_mut(&mut self) -> impl Iterator { - self.iter_operators_mut() - .filter_map(|operator| match operator { - Operator::VariableIdentifierWrite { identifier } - | Operator::VariableIdentifierRead { identifier } => Some(identifier), - _ => None, - }) - } - - /// Returns an iterator over all read variable identifiers in this expression. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_read_variable_identifiers(&self) -> impl Iterator { - self.iter().filter_map(|node| match node.operator() { - Operator::VariableIdentifierRead { identifier } => Some(identifier.as_str()), - _ => None, - }) - } - - /// Returns an iterator over all read variable identifiers in this expression, allowing mutation. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_read_variable_identifiers_mut(&mut self) -> impl Iterator { - self.iter_operators_mut() - .filter_map(|operator| match operator { - Operator::VariableIdentifierRead { identifier } => Some(identifier), - _ => None, - }) - } - - /// Returns an iterator over all write variable identifiers in this expression. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_write_variable_identifiers(&self) -> impl Iterator { - self.iter().filter_map(|node| match node.operator() { - Operator::VariableIdentifierWrite { identifier } => Some(identifier.as_str()), - _ => None, - }) - } - - /// Returns an iterator over all write variable identifiers in this expression, allowing mutation. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_write_variable_identifiers_mut(&mut self) -> impl Iterator { - self.iter_operators_mut() - .filter_map(|operator| match operator { - Operator::VariableIdentifierWrite { identifier } => Some(identifier), - _ => None, - }) - } - - /// Returns an iterator over all function identifiers in this expression. - /// Each occurrence of a function identifier is returned separately. - pub fn iter_function_identifiers(&self) -> impl Iterator { - self.iter().filter_map(|node| match node.operator() { - Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()), - _ => None, - }) - } - - /// Returns an iterator over all function identifiers in this expression, allowing mutation. - /// Each occurrence of a variable identifier is returned separately. - pub fn iter_function_identifiers_mut(&mut self) -> impl Iterator { - self.iter_operators_mut() - .filter_map(|operator| match operator { - Operator::FunctionIdentifier { identifier } => Some(identifier), - _ => None, - }) - } - - /// Evaluates the operator tree rooted at this node with the given context. Fails if one of the - /// operators in the expression tree fails. - pub fn eval_with_context(&self, context: &VariableMap) -> Result { - let mut arguments = Vec::new(); - for child in self.children() { - arguments.push(child.eval_with_context(context)?); - } - self.operator().eval(&arguments, context) - } - - /// Evaluates the operator tree rooted at this node with the given mutable context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_with_context_mut(&self, context: &mut VariableMap) -> Result { - let mut arguments = Vec::new(); - for child in self.children() { - arguments.push(child.eval_with_context_mut(context)?); - } - self.operator().eval_mut(&arguments, context) - } - - /// Evaluates the operator tree rooted at this node. - /// Fails if one of the operators in the expression tree fails. - pub fn eval(&self) -> Result { - self.eval_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into a string with an the given context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_string_with_context(&self, context: &VariableMap) -> Result { - match self.eval_with_context(context) { - Ok(Value::String(string)) => Ok(string), - Ok(value) => Err(Error::expected_string(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a float with an the given context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_float_with_context(&self, context: &VariableMap) -> Result { - match self.eval_with_context(context) { - Ok(Value::Float(float)) => Ok(float), - Ok(value) => Err(Error::expected_float(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into an integer with an the given context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_int_with_context(&self, context: &VariableMap) -> Result { - match self.eval_with_context(context) { - Ok(Value::Integer(int)) => Ok(int), - Ok(value) => Err(Error::expected_int(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a float with an the given context. If - /// the result of the expression is an integer, it is silently converted into a float. Fails /// if one of the operators in the expression tree fails. - pub fn eval_number_with_context(&self, context: &VariableMap) -> Result { - match self.eval_with_context(context) { - Ok(Value::Integer(int)) => Ok(int as f64), - Ok(Value::Float(float)) => Ok(float), - Ok(value) => Err(Error::expected_number(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a boolean with an the given context - /// Fails if one of the operators in the expression tree fails. - pub fn eval_boolean_with_context(&self, context: &VariableMap) -> Result { - match self.eval_with_context(context) { - Ok(Value::Boolean(boolean)) => Ok(boolean), - Ok(value) => Err(Error::expected_boolean(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a tuple with an the given context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_tuple_with_context(&self, context: &VariableMap) -> Result> { - match self.eval_with_context(context) { - Ok(Value::List(tuple)) => Ok(tuple), - Ok(value) => Err(Error::expected_list(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into an empty value with an the given context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_empty_with_context(&self, context: &VariableMap) -> Result<()> { - match self.eval_with_context(context) { - Ok(Value::Empty) => Ok(()), - Ok(value) => Err(Error::expected_empty(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a string with an the given mutable context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_string_with_context_mut(&self, context: &mut VariableMap) -> Result { - match self.eval_with_context_mut(context) { - Ok(Value::String(string)) => Ok(string), - Ok(value) => Err(Error::expected_string(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a float with an the given mutable context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_float_with_context_mut(&self, context: &mut VariableMap) -> Result { - match self.eval_with_context_mut(context) { - Ok(Value::Float(float)) => Ok(float), - Ok(value) => Err(Error::expected_float(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into an integer with an the given mutable context. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_int_with_context_mut(&self, context: &mut VariableMap) -> Result { - match self.eval_with_context_mut(context) { - Ok(Value::Integer(int)) => Ok(int), - Ok(value) => Err(Error::expected_int(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a float with an the given mutable context. - /// If the result of the expression is an integer, it is silently converted into a float. - /// Fails if one of the operators in the expression tree fails. - pub fn eval_number_with_context_mut(&self, context: &mut VariableMap) -> Result { - match self.eval_with_context_mut(context) { - Ok(Value::Integer(int)) => Ok(int as f64), - Ok(Value::Float(float)) => Ok(float), - Ok(value) => Err(Error::expected_number(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a boolean with an the given mutable /// context. Fails if one of the operators in the expression tree fails. - pub fn eval_boolean_with_context_mut(&self, context: &mut VariableMap) -> Result { - match self.eval_with_context_mut(context) { - Ok(Value::Boolean(boolean)) => Ok(boolean), - Ok(value) => Err(Error::expected_boolean(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a tuple with an the given mutable /// context. Fails if one of the operators in the expression tree fails. - pub fn eval_tuple_with_context_mut(&self, context: &mut VariableMap) -> Result> { - match self.eval_with_context_mut(context) { - Ok(Value::List(tuple)) => Ok(tuple), - Ok(value) => Err(Error::expected_list(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into an empty value with an the given /// mutable context. Fails if one of the operators in the expression tree fails. - pub fn eval_empty_with_context_mut(&self, context: &mut VariableMap) -> Result<()> { - match self.eval_with_context_mut(context) { - Ok(Value::Empty) => Ok(()), - Ok(value) => Err(Error::expected_empty(value)), - Err(error) => Err(error), - } - } - - /// Evaluates the operator tree rooted at this node into a string. Fails if one of the /// operators in the expression tree fails. - pub fn eval_string(&self) -> Result { - self.eval_string_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into a float. Fails if one of the operators /// in the expression tree fails. - pub fn eval_float(&self) -> Result { - self.eval_float_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into an integer. Fails if one of the - /// operators in the expression tree fails. - pub fn eval_int(&self) -> Result { - self.eval_int_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into a float. If the result of the - /// expression is an integer, it is silently converted into a float. Fails if one of the /// operators in the expression tree fails. - pub fn eval_number(&self) -> Result { - self.eval_number_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into a boolean. Fails if one of the /// operators in the expression tree fails. - pub fn eval_boolean(&self) -> Result { - self.eval_boolean_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into a tuple. Fails if one of the operators /// in the expression tree fails. - pub fn eval_tuple(&self) -> Result> { - self.eval_tuple_with_context_mut(&mut VariableMap::new()) - } - - /// Evaluates the operator tree rooted at this node into an empty value. Fails if one of the /// operators in the expression tree fails. - pub fn eval_empty(&self) -> Result<()> { - self.eval_empty_with_context_mut(&mut VariableMap::new()) - } - - /// Returns the children of this node as a slice. - pub fn children(&self) -> &[Node] { - &self.children - } - - /// Returns the operator associated with this node. - pub fn operator(&self) -> &Operator { - &self.operator - } - - /// Returns a mutable reference to the vector containing the children of this node. - /// - /// WARNING: Writing to this might have unexpected results, as some operators require certain amounts and types of arguments. - pub fn children_mut(&mut self) -> &mut Vec { - &mut self.children - } - - /// Returns a mutable reference to the operator associated with this node. - /// - /// WARNING: Writing to this might have unexpected results, as some operators require different amounts and types of arguments. - pub fn operator_mut(&mut self) -> &mut Operator { - &mut self.operator - } - - fn has_enough_children(&self) -> bool { - Some(self.children().len()) == self.operator().max_argument_amount() - } - - fn has_too_many_children(&self) -> bool { - if let Some(max_argument_amount) = self.operator().max_argument_amount() { - self.children().len() > max_argument_amount - } else { - false - } - } - - fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> Result<()> { - // println!( - // "Inserting {:?} into {:?}, is_root_node = {is_root_node}", - // node.operator(), - // self.operator() - // ); - // println!("Self is {:?}", self); - if self.operator().precedence() < node.operator().precedence() || node.operator().is_unary() || is_root_node - // Right-to-left chaining - || (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right()) - { - if self.operator().is_leaf() { - Err(Error::AppendedToLeafNode(node)) - } else if self.has_enough_children() { - // Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child - let last_child_operator = self.children.last().unwrap().operator(); - - if last_child_operator.precedence() - < node.operator().precedence() || node.operator().is_unary() - // Right-to-left chaining - || (last_child_operator.precedence() - == node.operator().precedence() && !last_child_operator.is_left_to_right() && !node.operator().is_left_to_right()) - { - // println!( - // "Recursing into {:?}", - // self.children.last().unwrap().operator() - // ); - // Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child - self.children - .last_mut() - .unwrap() - .insert_back_prioritized(node, false) - } else { - // println!("Rotating"); - if node.operator().is_leaf() { - return Err(Error::AppendedToLeafNode(node)); - } - - // Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child - let last_child = self.children.pop().unwrap(); - // Root nodes have at most one child - // TODO I am not sure if this is the correct error - if self.operator() == &Operator::RootNode && !self.children().is_empty() { - return Err(Error::MissingOperatorOutsideOfBrace); - } - // Do not insert root nodes into root nodes. - // TODO I am not sure if this is the correct error - if self.operator() == &Operator::RootNode - && node.operator() == &Operator::RootNode - { - return Err(Error::MissingOperatorOutsideOfBrace); - } - self.children.push(node); - let node = self.children.last_mut().unwrap(); - - // Root nodes have at most one child - // TODO I am not sure if this is the correct error - if node.operator() == &Operator::RootNode && !node.children().is_empty() { - return Err(Error::MissingOperatorOutsideOfBrace); - } - // Do not insert root nodes into root nodes. - // TODO I am not sure if this is the correct error - if node.operator() == &Operator::RootNode - && last_child.operator() == &Operator::RootNode - { - return Err(Error::MissingOperatorOutsideOfBrace); - } - node.children.push(last_child); - Ok(()) - } - } else { - // println!("Inserting as specified"); - self.children.push(node); - Ok(()) - } - } else { - Err(Error::PrecedenceViolation) - } - } -} - -impl Display for Node { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.operator.fmt(f)?; - for child in self.children() { - write!(f, " {}", child)?; - } - Ok(()) - } -} - -fn collapse_root_stack_to( - root_stack: &mut Vec, - mut root: Node, - collapse_goal: &Node, -) -> Result { - loop { - if let Some(mut potential_higher_root) = root_stack.pop() { - // TODO I'm not sure about this >, as I have no example for different sequence operators with the same precedence - if potential_higher_root.operator().precedence() > collapse_goal.operator().precedence() - { - potential_higher_root.children.push(root); - root = potential_higher_root; - } else { - root_stack.push(potential_higher_root); - break; - } - } else { - // This is the only way the topmost root node could have been removed - return Err(Error::UnmatchedRBrace); - } - } - - Ok(root) -} - -fn collapse_all_sequences(root_stack: &mut Vec) -> Result<()> { - // println!("Collapsing all sequences"); - // println!("Initial root stack is: {:?}", root_stack); - let mut root = if let Some(root) = root_stack.pop() { - root - } else { - return Err(Error::UnmatchedRBrace); - }; - - loop { - // println!("Root is: {:?}", root); - if root.operator() == &Operator::RootNode { - // This should fire if parsing something like `4(5)` - if root.has_too_many_children() { - return Err(Error::MissingOperatorOutsideOfBrace); - } - - root_stack.push(root); - break; - } - - if let Some(mut potential_higher_root) = root_stack.pop() { - if root.operator().is_sequence() { - potential_higher_root.children.push(root); - root = potential_higher_root; - } else { - // This should fire if parsing something like `4(5)` - if root.has_too_many_children() { - return Err(Error::MissingOperatorOutsideOfBrace); - } - - root_stack.push(potential_higher_root); - root_stack.push(root); - break; - } - } else { - // This is the only way the topmost root node could have been removed - return Err(Error::UnmatchedRBrace); - } - } - - // println!("Root stack after collapsing all sequences is: {:?}", root_stack); - Ok(()) -} - -pub(crate) fn tokens_to_operator_tree(tokens: Vec) -> Result { - let mut root_stack = vec![Node::root_node()]; - let mut last_token_is_rightsided_value = false; - let mut token_iter = tokens.iter().peekable(); - - while let Some(token) = token_iter.next().cloned() { - let next = token_iter.peek().cloned(); - - let node = match token.clone() { - Token::Plus => Some(Node::new(Operator::Add)), - Token::Minus => { - if last_token_is_rightsided_value { - Some(Node::new(Operator::Sub)) - } else { - Some(Node::new(Operator::Neg)) - } - } - Token::Star => Some(Node::new(Operator::Mul)), - Token::Slash => Some(Node::new(Operator::Div)), - Token::Percent => Some(Node::new(Operator::Mod)), - Token::Hat => Some(Node::new(Operator::Exp)), - - Token::Eq => Some(Node::new(Operator::Eq)), - Token::Neq => Some(Node::new(Operator::Neq)), - Token::Gt => Some(Node::new(Operator::Gt)), - Token::Lt => Some(Node::new(Operator::Lt)), - Token::Geq => Some(Node::new(Operator::Geq)), - Token::Leq => Some(Node::new(Operator::Leq)), - Token::And => Some(Node::new(Operator::And)), - Token::Or => Some(Node::new(Operator::Or)), - Token::Not => Some(Node::new(Operator::Not)), - - Token::LBrace => { - root_stack.push(Node::root_node()); - None - } - Token::RBrace => { - if root_stack.len() <= 1 { - return Err(Error::UnmatchedRBrace); - } else { - collapse_all_sequences(&mut root_stack)?; - root_stack.pop() - } - } - - Token::Assign => Some(Node::new(Operator::Assign)), - Token::PlusAssign => Some(Node::new(Operator::AddAssign)), - Token::MinusAssign => Some(Node::new(Operator::SubAssign)), - Token::StarAssign => Some(Node::new(Operator::MulAssign)), - Token::SlashAssign => Some(Node::new(Operator::DivAssign)), - Token::PercentAssign => Some(Node::new(Operator::ModAssign)), - Token::HatAssign => Some(Node::new(Operator::ExpAssign)), - Token::AndAssign => Some(Node::new(Operator::AndAssign)), - Token::OrAssign => Some(Node::new(Operator::OrAssign)), - - Token::Comma => Some(Node::new(Operator::Tuple)), - Token::Semicolon => Some(Node::new(Operator::Chain)), - Token::Identifier(identifier) => { - let mut result = Some(Node::new(Operator::variable_identifier_read( - identifier.clone(), - ))); - if let Some(next) = next { - if next.is_assignment() { - result = Some(Node::new(Operator::variable_identifier_write( - identifier.clone(), - ))); - } else if next.is_leftsided_value() { - result = Some(Node::new(Operator::function_identifier(identifier))); - } - } - result - } - Token::Float(float) => Some(Node::new(Operator::value(Value::Float(float)))), - Token::Int(int) => Some(Node::new(Operator::value(Value::Integer(int)))), - Token::Boolean(boolean) => Some(Node::new(Operator::value(Value::Boolean(boolean)))), - Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))), - Token::Function(string) => Some(Node::new(Operator::value(Value::Function( - Function::new(&string), - )))), - Token::Yield(_, _) => todo!(), - }; - - if let Some(mut node) = node { - // Need to pop and then repush here, because Rust 1.33.0 cannot release the mutable borrow of root_stack before the end of this complete if-statement - if let Some(mut root) = root_stack.pop() { - if node.operator().is_sequence() { - // println!("Found a sequence operator"); - // println!("Stack before sequence operation: {:?}, {:?}", root_stack, root); - // If root.operator() and node.operator() are of the same variant, ... - if mem::discriminant(root.operator()) == mem::discriminant(node.operator()) { - // ... we create a new root node for the next expression in the sequence - root.children.push(Node::root_node()); - root_stack.push(root); - } else if root.operator() == &Operator::RootNode { - // If the current root is an actual root node, we start a new sequence - node.children.push(root); - node.children.push(Node::root_node()); - root_stack.push(Node::root_node()); - root_stack.push(node); - } else { - // Otherwise, we combine the sequences based on their precedences - // TODO I'm not sure about this <, as I have no example for different sequence operators with the same precedence - if root.operator().precedence() < node.operator().precedence() { - // If the new sequence has a higher precedence, it is part of the last element of the current root sequence - if let Some(last_root_child) = root.children.pop() { - node.children.push(last_root_child); - node.children.push(Node::root_node()); - root_stack.push(root); - root_stack.push(node); - } else { - // Once a sequence has been pushed on top of the stack, it also gets a child - unreachable!() - } - } else { - // If the new sequence doesn't have a higher precedence, then all sequences with a higher precedence are collapsed below this one - root = collapse_root_stack_to(&mut root_stack, root, &node)?; - node.children.push(root); - root_stack.push(node); - } - } - // println!("Stack after sequence operation: {:?}", root_stack); - } else if root.operator().is_sequence() { - if let Some(mut last_root_child) = root.children.pop() { - last_root_child.insert_back_prioritized(node, true)?; - root.children.push(last_root_child); - root_stack.push(root); - } else { - // Once a sequence has been pushed on top of the stack, it also gets a child - unreachable!() - } - } else { - root.insert_back_prioritized(node, true)?; - root_stack.push(root); - } - } else { - return Err(Error::UnmatchedRBrace); - } - } - - last_token_is_rightsided_value = token.is_rightsided_value(); - } - - // In the end, all sequences are implicitly terminated - collapse_all_sequences(&mut root_stack)?; - - if root_stack.len() > 1 { - Err(Error::UnmatchedLBrace) - } else if let Some(root) = root_stack.pop() { - Ok(root) - } else { - Err(Error::UnmatchedRBrace) - } -} diff --git a/src/value/function.rs b/src/value/function.rs index 50a0f36..0f8a15e 100644 --- a/src/value/function.rs +++ b/src/value/function.rs @@ -13,11 +13,11 @@ impl Function { } pub fn run(&self) -> Result { - eval(&self.0) + todo!() } pub fn run_with_context(&self, context: &mut VariableMap) -> Result { - eval_with_context(&self.0, context) + todo!() } } diff --git a/src/value/mod.rs b/src/value/mod.rs index 186fc5e..3bf747e 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -10,7 +10,7 @@ use serde::{ ser::SerializeTuple, Deserialize, Serialize, Serializer, }; -use tree_sitter::{Node, TreeCursor}; +use tree_sitter::Node; use std::{ cmp::Ordering, @@ -66,7 +66,12 @@ impl Value { Ok(Value::Integer(raw)) } - "string" => Ok(Value::String(value_snippet.to_string())), + "string" => { + let without_quotes = &value_snippet[1..value_snippet.len() - 1]; + + Ok(Value::String(without_quotes.to_string())) + } + "empty" => Ok(Value::Empty), _ => Err(Error::UnexpectedSourceNode { expected: "raw value", actual: child.kind(),