Add comma operator and display implementations
+ Add comma token + Add tuple operator + Add tuple value type + Implement display for `tree::Node` and all related types + Add support for right-to-left chaining of operators with same precedence The priority of chaining of operators with the same precedence remains left-to-right. Only if two consecutive operators with the same precedence are right-to-left, they will be ordered right-to-left. Implements #4.
This commit is contained in:
parent
265b1214b0
commit
c631171ff0
@ -191,3 +191,4 @@ See [LICENSE](LICENSE) for details.
|
||||
## Closing Notes
|
||||
|
||||
If you have any ideas for features or see any problems in the code, architecture, interface, algorithmics or documentation, please open an issue on github.
|
||||
If there is already an issue describing what you want to say, please add a thumbs up or whatever emoji you think fits to the issue, so I know which ones I should prioritize.
|
||||
|
@ -3,7 +3,11 @@ use token::PartialToken;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
WrongArgumentAmount {
|
||||
WrongOperatorArgumentAmount {
|
||||
expected: usize,
|
||||
actual: usize,
|
||||
},
|
||||
WrongFunctionArgumentAmount {
|
||||
expected: usize,
|
||||
actual: usize,
|
||||
},
|
||||
@ -50,8 +54,12 @@ pub enum Error {
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn wrong_argument_amount(actual: usize, expected: usize) -> Self {
|
||||
Error::WrongArgumentAmount { actual, expected }
|
||||
pub fn wrong_operator_argument_amount(actual: usize, expected: usize) -> Self {
|
||||
Error::WrongOperatorArgumentAmount { actual, expected }
|
||||
}
|
||||
|
||||
pub fn wrong_function_argument_amount(actual: usize, expected: usize) -> Self {
|
||||
Error::WrongFunctionArgumentAmount { actual, expected }
|
||||
}
|
||||
|
||||
pub fn expected_number(actual: Value) -> Self {
|
||||
@ -67,11 +75,19 @@ impl Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_argument_amount(actual: usize, expected: usize) -> Result<(), Error> {
|
||||
pub fn expect_operator_argument_amount(actual: usize, expected: usize) -> Result<(), Error> {
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::wrong_argument_amount(actual, expected))
|
||||
Err(Error::wrong_operator_argument_amount(actual, expected))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_function_argument_amount(actual: usize, expected: usize) -> Result<(), Error> {
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::wrong_function_argument_amount(actual, expected))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl Function {
|
||||
}
|
||||
|
||||
pub fn call(&self, arguments: &[Value]) -> Result<Value, Error> {
|
||||
error::expect_argument_amount(self.argument_amount, arguments.len())?;
|
||||
error::expect_function_argument_amount(arguments.len(), self.argument_amount)?;
|
||||
(self.function)(arguments)
|
||||
}
|
||||
}
|
||||
|
91
src/lib.rs
91
src/lib.rs
@ -175,6 +175,8 @@
|
||||
//! See [LICENSE](LICENSE) for details.
|
||||
//!
|
||||
|
||||
extern crate core;
|
||||
|
||||
mod configuration;
|
||||
pub mod error;
|
||||
mod function;
|
||||
@ -210,7 +212,7 @@ pub fn build_operator_tree(string: &str) -> Result<Node, Error> {
|
||||
mod test {
|
||||
use crate::{eval, value::Value};
|
||||
use configuration::HashMapConfiguration;
|
||||
use error::Error;
|
||||
use error::{expect_number, Error};
|
||||
use eval_with_configuration;
|
||||
use Function;
|
||||
|
||||
@ -377,6 +379,88 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_n_ary_functions() {
|
||||
let mut configuration = HashMapConfiguration::new();
|
||||
configuration.insert_function(
|
||||
"sub2",
|
||||
Function::new(
|
||||
1,
|
||||
Box::new(|arguments| {
|
||||
if let Value::Int(int) = arguments[0] {
|
||||
Ok(Value::Int(int - 2))
|
||||
} else if let Value::Float(float) = arguments[0] {
|
||||
Ok(Value::Float(float - 2.0))
|
||||
} else {
|
||||
Err(Error::expected_number(arguments[0].clone()))
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
configuration.insert_function(
|
||||
"avg",
|
||||
Function::new(
|
||||
2,
|
||||
Box::new(|arguments| {
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
if let (Value::Int(a), Value::Int(b)) = (&arguments[0], &arguments[1]) {
|
||||
Ok(Value::Int((a + b) / 2))
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
(arguments[0].as_float()? + arguments[1].as_float()?) / 2.0,
|
||||
))
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
configuration.insert_function(
|
||||
"muladd",
|
||||
Function::new(
|
||||
3,
|
||||
Box::new(|arguments| {
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
expect_number(&arguments[2])?;
|
||||
|
||||
if let (Value::Int(a), Value::Int(b), Value::Int(c)) =
|
||||
(&arguments[0], &arguments[1], &arguments[2])
|
||||
{
|
||||
Ok(Value::Int(a * b + c))
|
||||
} else {
|
||||
Ok(Value::Float(
|
||||
arguments[0].as_float()? * arguments[1].as_float()?
|
||||
+ arguments[2].as_float()?,
|
||||
))
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
configuration.insert_variable("five".to_string(), Value::Int(5));
|
||||
|
||||
assert_eq!(
|
||||
eval_with_configuration("avg(7, 5)", &configuration),
|
||||
Ok(Value::Int(6))
|
||||
);
|
||||
assert_eq!(
|
||||
eval_with_configuration("avg(sub2 5, 5)", &configuration),
|
||||
Ok(Value::Int(4))
|
||||
);
|
||||
assert_eq!(
|
||||
eval_with_configuration("sub2(avg(3, 6))", &configuration),
|
||||
Ok(Value::Int(2))
|
||||
);
|
||||
assert_eq!(
|
||||
eval_with_configuration("sub2 avg(3, 6)", &configuration),
|
||||
Ok(Value::Int(2))
|
||||
);
|
||||
assert_eq!(
|
||||
eval_with_configuration("muladd(3, 6, -4)", &configuration),
|
||||
Ok(Value::Int(14))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_errors() {
|
||||
assert_eq!(
|
||||
@ -387,7 +471,10 @@ mod test {
|
||||
eval("1-true"),
|
||||
Err(Error::expected_number(Value::Boolean(true)))
|
||||
);
|
||||
assert_eq!(eval("true-"), Err(Error::wrong_argument_amount(1, 2)));
|
||||
assert_eq!(
|
||||
eval("true-"),
|
||||
Err(Error::wrong_operator_argument_amount(1, 2))
|
||||
);
|
||||
assert_eq!(eval("!(()true)"), Err(Error::AppendedToLeafNode));
|
||||
}
|
||||
}
|
||||
|
122
src/operator/display.rs
Normal file
122
src/operator/display.rs
Normal file
@ -0,0 +1,122 @@
|
||||
use operator::*;
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
|
||||
impl Display for RootNode {
|
||||
fn fmt(&self, _f: &mut Formatter) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Add {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "+")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Sub {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Neg {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Mul {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "*")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Div {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "/")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Mod {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "%")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Eq {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "==")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Neq {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "!=")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Gt {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, ">")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Lt {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "<")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Geq {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, ">=")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Leq {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "<=")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for And {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "&&")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Or {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "||")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Not {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "!")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Tuple {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Const {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for VariableIdentifier {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "{}", self.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionIdentifier {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "{}", self.identifier)
|
||||
}
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
use crate::{configuration::Configuration, error::*, value::Value};
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
pub trait Operator: Debug {
|
||||
mod display;
|
||||
|
||||
pub trait Operator: Debug + Display {
|
||||
/// Returns the precedence of the operator.
|
||||
/// A high precedence means that the operator has priority to be deeper in the tree.
|
||||
// Make this a const fn once #57563 is resolved
|
||||
fn precedence(&self) -> i32;
|
||||
|
||||
/// 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.
|
||||
// Make this a const fn once #57563 is resolved
|
||||
fn is_left_to_right(&self) -> bool;
|
||||
|
||||
/// True if this operator is a leaf, meaning it accepts no arguments.
|
||||
// Make this a const fn once #57563 is resolved
|
||||
fn is_leaf(&self) -> bool {
|
||||
@ -56,6 +64,9 @@ pub struct Or;
|
||||
#[derive(Debug)]
|
||||
pub struct Not;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tuple;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Const {
|
||||
value: Value,
|
||||
@ -94,12 +105,16 @@ impl Operator for RootNode {
|
||||
200
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 1)?;
|
||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||
Ok(arguments[0].clone())
|
||||
}
|
||||
}
|
||||
@ -109,12 +124,16 @@ impl Operator for Add {
|
||||
95
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -135,12 +154,16 @@ impl Operator for Sub {
|
||||
95
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -161,12 +184,16 @@ impl Operator for Neg {
|
||||
110
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 1)?;
|
||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||
expect_number(&arguments[0])?;
|
||||
|
||||
if arguments[0].is_int() {
|
||||
@ -182,12 +209,16 @@ impl Operator for Mul {
|
||||
100
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -208,12 +239,16 @@ impl Operator for Div {
|
||||
100
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -234,12 +269,16 @@ impl Operator for Mod {
|
||||
100
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -260,12 +299,16 @@ impl Operator for Eq {
|
||||
80
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
|
||||
if arguments[0] == arguments[1] {
|
||||
Ok(Value::Boolean(true))
|
||||
@ -280,12 +323,16 @@ impl Operator for Neq {
|
||||
80
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
|
||||
if arguments[0] != arguments[1] {
|
||||
Ok(Value::Boolean(true))
|
||||
@ -300,12 +347,16 @@ impl Operator for Gt {
|
||||
80
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -330,12 +381,16 @@ impl Operator for Lt {
|
||||
80
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -360,12 +415,16 @@ impl Operator for Geq {
|
||||
80
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -390,12 +449,16 @@ impl Operator for Leq {
|
||||
80
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
expect_number(&arguments[0])?;
|
||||
expect_number(&arguments[1])?;
|
||||
|
||||
@ -420,12 +483,16 @@ impl Operator for And {
|
||||
75
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
let a = expect_boolean(&arguments[0])?;
|
||||
let b = expect_boolean(&arguments[1])?;
|
||||
|
||||
@ -442,12 +509,16 @@ impl Operator for Or {
|
||||
70
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 2)?;
|
||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||
let a = expect_boolean(&arguments[0])?;
|
||||
let b = expect_boolean(&arguments[1])?;
|
||||
|
||||
@ -464,12 +535,16 @@ impl Operator for Not {
|
||||
110
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 1)?;
|
||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||
let a = expect_boolean(&arguments[0])?;
|
||||
|
||||
if !a {
|
||||
@ -480,17 +555,58 @@ impl Operator for Not {
|
||||
}
|
||||
}
|
||||
|
||||
impl Operator for Tuple {
|
||||
fn precedence(&self) -> i32 {
|
||||
40
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
if let Value::Tuple(tuple) = &arguments[0] {
|
||||
let mut tuple = tuple.clone();
|
||||
if let Value::Tuple(tuple2) = &arguments[1] {
|
||||
tuple.extend(tuple2.iter().cloned());
|
||||
} else {
|
||||
tuple.push(arguments[1].clone());
|
||||
}
|
||||
Ok(Value::from(tuple))
|
||||
} else {
|
||||
if let Value::Tuple(tuple) = &arguments[1] {
|
||||
let mut tuple = tuple.clone();
|
||||
tuple.insert(0, arguments[0].clone());
|
||||
Ok(Value::from(tuple))
|
||||
} else {
|
||||
Ok(Value::from(vec![
|
||||
arguments[0].clone(),
|
||||
arguments[1].clone(),
|
||||
]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Operator for Const {
|
||||
fn precedence(&self) -> i32 {
|
||||
200
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_argument_amount(arguments.len(), 0)?;
|
||||
expect_operator_argument_amount(arguments.len(), 0)?;
|
||||
|
||||
Ok(self.value.clone())
|
||||
}
|
||||
@ -501,6 +617,10 @@ impl Operator for VariableIdentifier {
|
||||
200
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
0
|
||||
}
|
||||
@ -519,13 +639,24 @@ impl Operator for FunctionIdentifier {
|
||||
190
|
||||
}
|
||||
|
||||
fn is_left_to_right(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn argument_amount(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result<Value, Error> {
|
||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||
|
||||
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
|
||||
arguments
|
||||
} else {
|
||||
arguments
|
||||
};
|
||||
|
||||
if let Some(function) = configuration.get_function(&self.identifier) {
|
||||
// Function::call checks for correct argument amount
|
||||
function.call(arguments)
|
||||
} else {
|
||||
Err(Error::FunctionIdentifierNotFound(self.identifier.clone()))
|
||||
|
@ -3,7 +3,6 @@ use value::{FloatType, IntType};
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Token {
|
||||
// Single character tokens
|
||||
// Arithmetic
|
||||
Plus,
|
||||
Minus,
|
||||
@ -26,7 +25,10 @@ pub enum Token {
|
||||
LBrace,
|
||||
RBrace,
|
||||
|
||||
// Complex tokens
|
||||
// Aggregation
|
||||
Comma,
|
||||
|
||||
// Values, Variables and Functions
|
||||
Identifier(String),
|
||||
Float(FloatType),
|
||||
Int(IntType),
|
||||
@ -65,6 +67,8 @@ fn char_to_partial_token(c: char) -> PartialToken {
|
||||
'(' => PartialToken::Token(Token::LBrace),
|
||||
')' => PartialToken::Token(Token::RBrace),
|
||||
|
||||
',' => PartialToken::Token(Token::Comma),
|
||||
|
||||
c => {
|
||||
if c.is_whitespace() {
|
||||
PartialToken::Whitespace
|
||||
@ -98,6 +102,8 @@ impl Token {
|
||||
Token::LBrace => true,
|
||||
Token::RBrace => false,
|
||||
|
||||
Token::Comma => false,
|
||||
|
||||
Token::Identifier(_) => true,
|
||||
Token::Float(_) => true,
|
||||
Token::Int(_) => true,
|
||||
@ -127,6 +133,8 @@ impl Token {
|
||||
Token::LBrace => false,
|
||||
Token::RBrace => true,
|
||||
|
||||
Token::Comma => false,
|
||||
|
||||
Token::Identifier(_) => true,
|
||||
Token::Float(_) => true,
|
||||
Token::Int(_) => true,
|
||||
|
12
src/tree/display.rs
Normal file
12
src/tree/display.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
use Node;
|
||||
|
||||
impl Display for Node {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
self.operator.fmt(f)?;
|
||||
for child in self.children() {
|
||||
write!(f, " {}", child)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
use crate::{configuration::Configuration, error::Error, operator::*, value::Value};
|
||||
use token::Token;
|
||||
|
||||
mod display;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Node {
|
||||
children: Vec<Node>,
|
||||
@ -40,14 +42,18 @@ impl Node {
|
||||
}
|
||||
|
||||
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> Result<(), Error> {
|
||||
if self.operator().precedence() < node.operator().precedence() || is_root_node {
|
||||
if self.operator().precedence() < node.operator().precedence() || 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)
|
||||
} else if self.has_correct_amount_of_children() {
|
||||
if self.children.last().unwrap().operator().precedence()
|
||||
< node.operator().precedence()
|
||||
// Function call
|
||||
//|| self.children().last().unwrap()
|
||||
// Right-to-left chaining
|
||||
|| (self.children.last().unwrap().operator().precedence()
|
||||
== node.operator().precedence() && !self.children.last().unwrap().operator().is_left_to_right() && !node.operator().is_left_to_right())
|
||||
{
|
||||
self.children
|
||||
.last_mut()
|
||||
@ -118,6 +124,8 @@ pub fn tokens_to_operator_tree(tokens: Vec<Token>) -> Result<Node, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
Token::Comma => Some(Node::new(Tuple)),
|
||||
|
||||
Token::Identifier(identifier) => {
|
||||
let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone())));
|
||||
if let Some(next) = next {
|
||||
|
26
src/value/display.rs
Normal file
26
src/value/display.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
use Value;
|
||||
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
match self {
|
||||
Value::String(string) => write!(f, "\"{}\"", string),
|
||||
Value::Float(float) => write!(f, "{}", float),
|
||||
Value::Int(int) => write!(f, "{}", int),
|
||||
Value::Boolean(boolean) => write!(f, "{}", boolean),
|
||||
Value::Tuple(tuple) => {
|
||||
write!(f, "(")?;
|
||||
let mut once = false;
|
||||
for value in tuple {
|
||||
if once {
|
||||
write!(f, ", ")?;
|
||||
} else {
|
||||
once = true;
|
||||
}
|
||||
value.fmt(f)?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
use error::Error;
|
||||
|
||||
mod display;
|
||||
|
||||
pub type IntType = i64;
|
||||
pub type FloatType = f64;
|
||||
|
||||
@ -9,6 +11,7 @@ pub enum Value {
|
||||
Float(FloatType),
|
||||
Int(IntType),
|
||||
Boolean(bool),
|
||||
Tuple(Vec<Value>),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
@ -72,6 +75,12 @@ impl From<bool> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Value>> for Value {
|
||||
fn from(tuple: Vec<Value>) -> Self {
|
||||
Value::Tuple(tuple)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Value> for Result<Value, Error> {
|
||||
fn from(value: Value) -> Self {
|
||||
Ok(value)
|
||||
|
Loading…
Reference in New Issue
Block a user