Implemented boolean expressions
This commit is contained in:
parent
a1ba054609
commit
bb74bee382
@ -1,4 +1,5 @@
|
|||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
use token::PartialToken;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -9,6 +10,9 @@ pub enum Error {
|
|||||||
ExpectedNumber {
|
ExpectedNumber {
|
||||||
actual: Value,
|
actual: Value,
|
||||||
},
|
},
|
||||||
|
ExpectedBoolean {
|
||||||
|
actual: Value,
|
||||||
|
},
|
||||||
|
|
||||||
/// The given expression is empty
|
/// The given expression is empty
|
||||||
EmptyExpression,
|
EmptyExpression,
|
||||||
@ -35,6 +39,11 @@ pub enum Error {
|
|||||||
|
|
||||||
/// A closing brace without a matching opening brace was found.
|
/// A closing brace without a matching opening brace was found.
|
||||||
UnmatchedRBrace,
|
UnmatchedRBrace,
|
||||||
|
|
||||||
|
UnmatchedPartialToken {
|
||||||
|
first: PartialToken,
|
||||||
|
second: Option<PartialToken>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
@ -45,6 +54,14 @@ impl Error {
|
|||||||
pub fn expected_number(actual: Value) -> Self {
|
pub fn expected_number(actual: Value) -> Self {
|
||||||
Error::ExpectedNumber { actual }
|
Error::ExpectedNumber { actual }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expected_boolean(actual: Value) -> Self {
|
||||||
|
Error::ExpectedBoolean { actual }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmatched_partial_token(first: PartialToken, second: Option<PartialToken>) -> Self {
|
||||||
|
Error::UnmatchedPartialToken {first, second}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_argument_amount(actual: usize, expected: usize) -> Result<(), Error> {
|
pub fn expect_argument_amount(actual: usize, expected: usize) -> Result<(), Error> {
|
||||||
@ -61,3 +78,10 @@ pub fn expect_number(actual: &Value) -> Result<(), Error> {
|
|||||||
_ => Err(Error::expected_number(actual.clone())),
|
_ => Err(Error::expected_number(actual.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_boolean(actual: &Value) -> Result<bool, Error> {
|
||||||
|
match actual {
|
||||||
|
Value::Boolean(boolean) => Ok(*boolean),
|
||||||
|
_ => Err(Error::expected_boolean(actual.clone())),
|
||||||
|
}
|
||||||
|
}
|
14
src/lib.rs
14
src/lib.rs
@ -10,7 +10,7 @@ mod tree;
|
|||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
pub fn eval(string: &str) -> Result<Value, Error> {
|
pub fn eval(string: &str) -> Result<Value, Error> {
|
||||||
tree::tokens_to_operator_tree(token::tokenize(string))?.eval(&EmptyConfiguration)
|
tree::tokens_to_operator_tree(token::tokenize(string)?)?.eval(&EmptyConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -90,7 +90,15 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_type_errors() {
|
fn test_boolean_examples() {
|
||||||
|
assert_eq!(eval("true && false"), Ok(Value::Boolean(false)));
|
||||||
|
assert_eq!(eval("true && false || true && true"), Ok(Value::Boolean(true)));
|
||||||
|
assert_eq!(eval("5 > 4 && 1 <= 1"), Ok(Value::Boolean(true)));
|
||||||
|
assert_eq!(eval("5.0 <= 4.9 || !(4 > 3.5)"), Ok(Value::Boolean(false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_errors() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval("-true"),
|
eval("-true"),
|
||||||
Err(Error::expected_number(Value::Boolean(true)))
|
Err(Error::expected_number(Value::Boolean(true)))
|
||||||
@ -100,6 +108,6 @@ mod test {
|
|||||||
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_argument_amount(1, 2)));
|
||||||
|
assert_eq!(eval("!(()true)"), Err(Error::AppendedToLeafNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,16 @@ pub struct Mul;
|
|||||||
pub struct Div;
|
pub struct Div;
|
||||||
pub struct Mod;
|
pub struct Mod;
|
||||||
|
|
||||||
|
pub struct Eq;
|
||||||
|
pub struct Neq;
|
||||||
|
pub struct Gt;
|
||||||
|
pub struct Lt;
|
||||||
|
pub struct Geq;
|
||||||
|
pub struct Leq;
|
||||||
|
pub struct And;
|
||||||
|
pub struct Or;
|
||||||
|
pub struct Not;
|
||||||
|
|
||||||
pub struct Const {
|
pub struct Const {
|
||||||
value: Value,
|
value: Value,
|
||||||
}
|
}
|
||||||
@ -216,6 +226,231 @@ impl Operator for Mod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Operator for Eq {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
|
||||||
|
if arguments[0] == arguments[1] {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Neq {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
|
||||||
|
if arguments[0] != arguments[1] {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Gt {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
expect_number(&arguments[0])?;
|
||||||
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
|
if arguments[0].as_int().unwrap() > arguments[1].as_int().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if arguments[0].as_float().unwrap() > arguments[1].as_float().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Lt {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
expect_number(&arguments[0])?;
|
||||||
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
|
if arguments[0].as_int().unwrap() < arguments[1].as_int().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if arguments[0].as_float().unwrap() < arguments[1].as_float().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Geq {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
expect_number(&arguments[0])?;
|
||||||
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
|
if arguments[0].as_int().unwrap() >= arguments[1].as_int().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if arguments[0].as_float().unwrap() >= arguments[1].as_float().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Leq {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
expect_number(&arguments[0])?;
|
||||||
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
|
if arguments[0].is_int() && arguments[1].is_int() {
|
||||||
|
if arguments[0].as_int().unwrap() <= arguments[1].as_int().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if arguments[0].as_float().unwrap() <= arguments[1].as_float().unwrap() {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for And {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
75
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
let a = expect_boolean(&arguments[0])?;
|
||||||
|
let b = expect_boolean(&arguments[1])?;
|
||||||
|
|
||||||
|
if a && b {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Or {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
70
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 2)?;
|
||||||
|
let a = expect_boolean(&arguments[0])?;
|
||||||
|
let b = expect_boolean(&arguments[1])?;
|
||||||
|
|
||||||
|
if a || b {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator for Not {
|
||||||
|
fn precedence(&self) -> i32 {
|
||||||
|
110
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_amount(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
|
||||||
|
expect_argument_amount(arguments.len(), 1)?;
|
||||||
|
let a = expect_boolean(&arguments[0])?;
|
||||||
|
|
||||||
|
if !a {
|
||||||
|
Ok(Value::Boolean(true))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Operator for Const {
|
impl Operator for Const {
|
||||||
fn precedence(&self) -> i32 {
|
fn precedence(&self) -> i32 {
|
||||||
200
|
200
|
||||||
|
115
src/token/mod.rs
115
src/token/mod.rs
@ -1,13 +1,28 @@
|
|||||||
use value::{FloatType, IntType};
|
use value::{FloatType, IntType};
|
||||||
|
use error::Error;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
// Single character tokens
|
// Single character tokens
|
||||||
|
// Arithmetic
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
Percent,
|
Percent,
|
||||||
|
|
||||||
|
// Logic
|
||||||
|
Eq,
|
||||||
|
Neq,
|
||||||
|
Gt,
|
||||||
|
Lt,
|
||||||
|
Geq,
|
||||||
|
Leq,
|
||||||
|
And,
|
||||||
|
Or,
|
||||||
|
Not,
|
||||||
|
|
||||||
|
// Precedence
|
||||||
LBrace,
|
LBrace,
|
||||||
RBrace,
|
RBrace,
|
||||||
Whitespace,
|
Whitespace,
|
||||||
@ -19,21 +34,37 @@ pub enum Token {
|
|||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PartialToken {
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PartialToken {
|
||||||
Token(Token),
|
Token(Token),
|
||||||
Literal(String),
|
Literal(String),
|
||||||
|
Eq,
|
||||||
|
ExclamationMark,
|
||||||
|
Gt,
|
||||||
|
Lt,
|
||||||
|
Ampersand,
|
||||||
|
VerticalBar,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make this a const fn as soon as match gets stable (issue #57563)
|
// Make this a const fn as soon as match gets stable (issue #57563)
|
||||||
fn char_to_token(c: char) -> PartialToken {
|
fn char_to_partial_token(c: char) -> PartialToken {
|
||||||
match c {
|
match c {
|
||||||
'+' => PartialToken::Token(Token::Plus),
|
'+' => PartialToken::Token(Token::Plus),
|
||||||
'-' => PartialToken::Token(Token::Minus),
|
'-' => PartialToken::Token(Token::Minus),
|
||||||
'*' => PartialToken::Token(Token::Star),
|
'*' => PartialToken::Token(Token::Star),
|
||||||
'/' => PartialToken::Token(Token::Slash),
|
'/' => PartialToken::Token(Token::Slash),
|
||||||
'%' => PartialToken::Token(Token::Percent),
|
'%' => PartialToken::Token(Token::Percent),
|
||||||
|
|
||||||
|
'=' => PartialToken::Eq,
|
||||||
|
'!' => PartialToken::ExclamationMark,
|
||||||
|
'>' => PartialToken::Gt,
|
||||||
|
'<' => PartialToken::Lt,
|
||||||
|
'&' => PartialToken::Ampersand,
|
||||||
|
'|' => PartialToken::VerticalBar,
|
||||||
|
|
||||||
'(' => PartialToken::Token(Token::LBrace),
|
'(' => PartialToken::Token(Token::LBrace),
|
||||||
')' => PartialToken::Token(Token::RBrace),
|
')' => PartialToken::Token(Token::RBrace),
|
||||||
|
|
||||||
c => {
|
c => {
|
||||||
if c.is_whitespace() {
|
if c.is_whitespace() {
|
||||||
PartialToken::Token(Token::Whitespace)
|
PartialToken::Token(Token::Whitespace)
|
||||||
@ -53,9 +84,21 @@ impl Token {
|
|||||||
Token::Star => false,
|
Token::Star => false,
|
||||||
Token::Slash => false,
|
Token::Slash => false,
|
||||||
Token::Percent => false,
|
Token::Percent => 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::LBrace => false,
|
||||||
Token::RBrace => true,
|
Token::RBrace => true,
|
||||||
Token::Whitespace => false,
|
Token::Whitespace => false,
|
||||||
|
|
||||||
Token::Identifier(_) => true,
|
Token::Identifier(_) => true,
|
||||||
Token::Float(_) => true,
|
Token::Float(_) => true,
|
||||||
Token::Int(_) => true,
|
Token::Int(_) => true,
|
||||||
@ -68,7 +111,7 @@ impl Token {
|
|||||||
fn str_to_tokens(string: &str) -> Vec<PartialToken> {
|
fn str_to_tokens(string: &str) -> Vec<PartialToken> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for c in string.chars() {
|
for c in string.chars() {
|
||||||
let partial_token = char_to_token(c);
|
let partial_token = char_to_partial_token(c);
|
||||||
|
|
||||||
let if_let_successful =
|
let if_let_successful =
|
||||||
if let (Some(PartialToken::Literal(last)), PartialToken::Literal(literal)) =
|
if let (Some(PartialToken::Literal(last)), PartialToken::Literal(literal)) =
|
||||||
@ -87,13 +130,18 @@ fn str_to_tokens(string: &str) -> Vec<PartialToken> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves all literals in the given vector of partial tokens by converting them to complex tokens.
|
/// Resolves all partial tokens by converting them to complex tokens.
|
||||||
fn resolve_literals(tokens: &Vec<PartialToken>) -> Vec<Token> {
|
fn resolve_literals(mut tokens: &[PartialToken]) -> Result<Vec<Token>, Error> {
|
||||||
tokens
|
let mut result = Vec::new();
|
||||||
.iter()
|
while tokens.len() > 0 {
|
||||||
.map(|token| match token {
|
let first = tokens[0].clone();
|
||||||
PartialToken::Token(token) => token.clone(),
|
let second = tokens.get(1).cloned();
|
||||||
|
let mut cutoff = 2;
|
||||||
|
|
||||||
|
result.push(match first {
|
||||||
|
PartialToken::Token(token) => {cutoff = 1; token},
|
||||||
PartialToken::Literal(literal) => {
|
PartialToken::Literal(literal) => {
|
||||||
|
cutoff = 1;
|
||||||
if let Ok(number) = literal.parse::<IntType>() {
|
if let Ok(number) = literal.parse::<IntType>() {
|
||||||
Token::Int(number)
|
Token::Int(number)
|
||||||
} else if let Ok(number) = literal.parse::<FloatType>() {
|
} else if let Ok(number) = literal.parse::<FloatType>() {
|
||||||
@ -103,11 +151,50 @@ fn resolve_literals(tokens: &Vec<PartialToken>) -> Vec<Token> {
|
|||||||
} else {
|
} else {
|
||||||
Token::Identifier(literal.to_string())
|
Token::Identifier(literal.to_string())
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
PartialToken::Eq => {
|
||||||
.collect()
|
match second {
|
||||||
|
Some(PartialToken::Eq) => Token::Eq,
|
||||||
|
_ => return Err(Error::unmatched_partial_token(first, second)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PartialToken::ExclamationMark => {
|
||||||
|
match second {
|
||||||
|
Some(PartialToken::Eq) => Token::Eq,
|
||||||
|
_ => {cutoff = 1; Token::Not},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PartialToken::Gt => {
|
||||||
|
match second {
|
||||||
|
Some(PartialToken::Eq) => Token::Geq,
|
||||||
|
_ => {cutoff = 1; Token::Gt},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PartialToken::Lt => {
|
||||||
|
match second {
|
||||||
|
Some(PartialToken::Eq) => Token::Leq,
|
||||||
|
_ => {cutoff = 1; Token::Lt},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PartialToken::Ampersand => {
|
||||||
|
match second {
|
||||||
|
Some(PartialToken::Ampersand) => Token::And,
|
||||||
|
_ => return Err(Error::unmatched_partial_token(first, second)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PartialToken::VerticalBar => {
|
||||||
|
match second {
|
||||||
|
Some(PartialToken::VerticalBar) => Token::Or,
|
||||||
|
_ => return Err(Error::unmatched_partial_token(first, second)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
tokens = &tokens[cutoff..];
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tokenize(string: &str) -> Vec<Token> {
|
pub fn tokenize(string: &str) -> Result<Vec<Token>, Error> {
|
||||||
resolve_literals(&str_to_tokens(string))
|
resolve_literals(&str_to_tokens(string))
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,17 @@ pub fn tokens_to_operator_tree(tokens: Vec<Token>) -> Result<Node, Error> {
|
|||||||
Token::Star => Some(Node::new(Mul)),
|
Token::Star => Some(Node::new(Mul)),
|
||||||
Token::Slash => Some(Node::new(Div)),
|
Token::Slash => Some(Node::new(Div)),
|
||||||
Token::Percent => Some(Node::new(Mod)),
|
Token::Percent => Some(Node::new(Mod)),
|
||||||
|
|
||||||
|
Token::Eq => Some(Node::new(Eq)),
|
||||||
|
Token::Neq => Some(Node::new(Neq)),
|
||||||
|
Token::Gt => Some(Node::new(Gt)),
|
||||||
|
Token::Lt => Some(Node::new(Lt)),
|
||||||
|
Token::Geq => Some(Node::new(Geq)),
|
||||||
|
Token::Leq => Some(Node::new(Leq)),
|
||||||
|
Token::And => Some(Node::new(And)),
|
||||||
|
Token::Or => Some(Node::new(Or)),
|
||||||
|
Token::Not => Some(Node::new(Not)),
|
||||||
|
|
||||||
Token::LBrace => {
|
Token::LBrace => {
|
||||||
root.push(Node::root_node());
|
root.push(Node::root_node());
|
||||||
None
|
None
|
||||||
@ -100,6 +111,7 @@ pub fn tokens_to_operator_tree(tokens: Vec<Token>) -> Result<Node, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::Whitespace => None,
|
Token::Whitespace => None,
|
||||||
|
|
||||||
Token::Identifier(identifier) => Some(Node::new(Identifier::new(identifier))),
|
Token::Identifier(identifier) => Some(Node::new(Identifier::new(identifier))),
|
||||||
Token::Float(number) => Some(Node::new(Const::new(Value::Float(number)))),
|
Token::Float(number) => Some(Node::new(Const::new(Value::Float(number)))),
|
||||||
Token::Int(number) => Some(Node::new(Const::new(Value::Int(number)))),
|
Token::Int(number) => Some(Node::new(Const::new(Value::Int(number)))),
|
||||||
|
Loading…
Reference in New Issue
Block a user