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
|
## 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 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)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
WrongArgumentAmount {
|
WrongOperatorArgumentAmount {
|
||||||
|
expected: usize,
|
||||||
|
actual: usize,
|
||||||
|
},
|
||||||
|
WrongFunctionArgumentAmount {
|
||||||
expected: usize,
|
expected: usize,
|
||||||
actual: usize,
|
actual: usize,
|
||||||
},
|
},
|
||||||
@ -50,8 +54,12 @@ pub enum Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
pub fn wrong_argument_amount(actual: usize, expected: usize) -> Self {
|
pub fn wrong_operator_argument_amount(actual: usize, expected: usize) -> Self {
|
||||||
Error::WrongArgumentAmount { actual, expected }
|
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 {
|
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 {
|
if actual == expected {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} 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> {
|
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)
|
(self.function)(arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
91
src/lib.rs
91
src/lib.rs
@ -175,6 +175,8 @@
|
|||||||
//! See [LICENSE](LICENSE) for details.
|
//! See [LICENSE](LICENSE) for details.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
mod configuration;
|
mod configuration;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod function;
|
mod function;
|
||||||
@ -210,7 +212,7 @@ pub fn build_operator_tree(string: &str) -> Result<Node, Error> {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::{eval, value::Value};
|
use crate::{eval, value::Value};
|
||||||
use configuration::HashMapConfiguration;
|
use configuration::HashMapConfiguration;
|
||||||
use error::Error;
|
use error::{expect_number, Error};
|
||||||
use eval_with_configuration;
|
use eval_with_configuration;
|
||||||
use Function;
|
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]
|
#[test]
|
||||||
fn test_errors() {
|
fn test_errors() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -387,7 +471,10 @@ mod test {
|
|||||||
eval("1-true"),
|
eval("1-true"),
|
||||||
Err(Error::expected_number(Value::Boolean(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));
|
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 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.
|
/// Returns the precedence of the operator.
|
||||||
/// A high precedence means that the operator has priority to be deeper in the tree.
|
/// A high precedence means that the operator has priority to be deeper in the tree.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
fn precedence(&self) -> i32;
|
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.
|
/// True if this operator is a leaf, meaning it accepts no arguments.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
fn is_leaf(&self) -> bool {
|
fn is_leaf(&self) -> bool {
|
||||||
@ -56,6 +64,9 @@ pub struct Or;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Not;
|
pub struct Not;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Tuple;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Const {
|
pub struct Const {
|
||||||
value: Value,
|
value: Value,
|
||||||
@ -94,12 +105,16 @@ impl Operator for RootNode {
|
|||||||
200
|
200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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())
|
Ok(arguments[0].clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,12 +124,16 @@ impl Operator for Add {
|
|||||||
95
|
95
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -135,12 +154,16 @@ impl Operator for Sub {
|
|||||||
95
|
95
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -161,12 +184,16 @@ impl Operator for Neg {
|
|||||||
110
|
110
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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])?;
|
expect_number(&arguments[0])?;
|
||||||
|
|
||||||
if arguments[0].is_int() {
|
if arguments[0].is_int() {
|
||||||
@ -182,12 +209,16 @@ impl Operator for Mul {
|
|||||||
100
|
100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -208,12 +239,16 @@ impl Operator for Div {
|
|||||||
100
|
100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -234,12 +269,16 @@ impl Operator for Mod {
|
|||||||
100
|
100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -260,12 +299,16 @@ impl Operator for Eq {
|
|||||||
80
|
80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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] {
|
if arguments[0] == arguments[1] {
|
||||||
Ok(Value::Boolean(true))
|
Ok(Value::Boolean(true))
|
||||||
@ -280,12 +323,16 @@ impl Operator for Neq {
|
|||||||
80
|
80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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] {
|
if arguments[0] != arguments[1] {
|
||||||
Ok(Value::Boolean(true))
|
Ok(Value::Boolean(true))
|
||||||
@ -300,12 +347,16 @@ impl Operator for Gt {
|
|||||||
80
|
80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -330,12 +381,16 @@ impl Operator for Lt {
|
|||||||
80
|
80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -360,12 +415,16 @@ impl Operator for Geq {
|
|||||||
80
|
80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -390,12 +449,16 @@ impl Operator for Leq {
|
|||||||
80
|
80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -420,12 +483,16 @@ impl Operator for And {
|
|||||||
75
|
75
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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 a = expect_boolean(&arguments[0])?;
|
||||||
let b = expect_boolean(&arguments[1])?;
|
let b = expect_boolean(&arguments[1])?;
|
||||||
|
|
||||||
@ -442,12 +509,16 @@ impl Operator for Or {
|
|||||||
70
|
70
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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 a = expect_boolean(&arguments[0])?;
|
||||||
let b = expect_boolean(&arguments[1])?;
|
let b = expect_boolean(&arguments[1])?;
|
||||||
|
|
||||||
@ -464,12 +535,16 @@ impl Operator for Not {
|
|||||||
110
|
110
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
|
|
||||||
if !a {
|
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 {
|
impl Operator for Const {
|
||||||
fn precedence(&self) -> i32 {
|
fn precedence(&self) -> i32 {
|
||||||
200
|
200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
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())
|
Ok(self.value.clone())
|
||||||
}
|
}
|
||||||
@ -501,6 +617,10 @@ impl Operator for VariableIdentifier {
|
|||||||
200
|
200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@ -519,13 +639,24 @@ impl Operator for FunctionIdentifier {
|
|||||||
190
|
190
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_left_to_right(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_amount(&self) -> usize {
|
fn argument_amount(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result<Value, Error> {
|
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) {
|
if let Some(function) = configuration.get_function(&self.identifier) {
|
||||||
// Function::call checks for correct argument amount
|
|
||||||
function.call(arguments)
|
function.call(arguments)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::FunctionIdentifierNotFound(self.identifier.clone()))
|
Err(Error::FunctionIdentifierNotFound(self.identifier.clone()))
|
||||||
|
@ -3,7 +3,6 @@ use value::{FloatType, IntType};
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
// Single character tokens
|
|
||||||
// Arithmetic
|
// Arithmetic
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
@ -26,7 +25,10 @@ pub enum Token {
|
|||||||
LBrace,
|
LBrace,
|
||||||
RBrace,
|
RBrace,
|
||||||
|
|
||||||
// Complex tokens
|
// Aggregation
|
||||||
|
Comma,
|
||||||
|
|
||||||
|
// Values, Variables and Functions
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Float(FloatType),
|
Float(FloatType),
|
||||||
Int(IntType),
|
Int(IntType),
|
||||||
@ -65,6 +67,8 @@ fn char_to_partial_token(c: char) -> PartialToken {
|
|||||||
'(' => PartialToken::Token(Token::LBrace),
|
'(' => PartialToken::Token(Token::LBrace),
|
||||||
')' => PartialToken::Token(Token::RBrace),
|
')' => PartialToken::Token(Token::RBrace),
|
||||||
|
|
||||||
|
',' => PartialToken::Token(Token::Comma),
|
||||||
|
|
||||||
c => {
|
c => {
|
||||||
if c.is_whitespace() {
|
if c.is_whitespace() {
|
||||||
PartialToken::Whitespace
|
PartialToken::Whitespace
|
||||||
@ -98,6 +102,8 @@ impl Token {
|
|||||||
Token::LBrace => true,
|
Token::LBrace => true,
|
||||||
Token::RBrace => false,
|
Token::RBrace => false,
|
||||||
|
|
||||||
|
Token::Comma => false,
|
||||||
|
|
||||||
Token::Identifier(_) => true,
|
Token::Identifier(_) => true,
|
||||||
Token::Float(_) => true,
|
Token::Float(_) => true,
|
||||||
Token::Int(_) => true,
|
Token::Int(_) => true,
|
||||||
@ -127,6 +133,8 @@ impl Token {
|
|||||||
Token::LBrace => false,
|
Token::LBrace => false,
|
||||||
Token::RBrace => true,
|
Token::RBrace => true,
|
||||||
|
|
||||||
|
Token::Comma => false,
|
||||||
|
|
||||||
Token::Identifier(_) => true,
|
Token::Identifier(_) => true,
|
||||||
Token::Float(_) => true,
|
Token::Float(_) => true,
|
||||||
Token::Int(_) => 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 crate::{configuration::Configuration, error::Error, operator::*, value::Value};
|
||||||
use token::Token;
|
use token::Token;
|
||||||
|
|
||||||
|
mod display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
@ -40,14 +42,18 @@ impl Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> Result<(), Error> {
|
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() {
|
if self.operator().is_leaf() {
|
||||||
Err(Error::AppendedToLeafNode)
|
Err(Error::AppendedToLeafNode)
|
||||||
} else if self.has_correct_amount_of_children() {
|
} else if self.has_correct_amount_of_children() {
|
||||||
if self.children.last().unwrap().operator().precedence()
|
if self.children.last().unwrap().operator().precedence()
|
||||||
< node.operator().precedence()
|
< node.operator().precedence()
|
||||||
// Function call
|
// Right-to-left chaining
|
||||||
//|| self.children().last().unwrap()
|
|| (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
|
self.children
|
||||||
.last_mut()
|
.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) => {
|
Token::Identifier(identifier) => {
|
||||||
let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone())));
|
let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone())));
|
||||||
if let Some(next) = next {
|
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;
|
use error::Error;
|
||||||
|
|
||||||
|
mod display;
|
||||||
|
|
||||||
pub type IntType = i64;
|
pub type IntType = i64;
|
||||||
pub type FloatType = f64;
|
pub type FloatType = f64;
|
||||||
|
|
||||||
@ -9,6 +11,7 @@ pub enum Value {
|
|||||||
Float(FloatType),
|
Float(FloatType),
|
||||||
Int(IntType),
|
Int(IntType),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
|
Tuple(Vec<Value>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
@ -72,8 +75,14 @@ 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> {
|
impl From<Value> for Result<Value, Error> {
|
||||||
fn from(value: Value) -> Self {
|
fn from(value: Value) -> Self {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user