add more bool operators
This commit is contained in:
@@ -165,6 +165,15 @@ where
|
|||||||
(Value::String(x), Value::String(y)) => Ok(Value::Bool(x == y)),
|
(Value::String(x), Value::String(y)) => Ok(Value::Bool(x == y)),
|
||||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("==".into(), vec![x, y])),
|
(x, y) => Err(RuntimeError::NoOverloadForTypes("==".into(), vec![x, y])),
|
||||||
},
|
},
|
||||||
|
ParseTree::NotEqualTo(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
||||||
|
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x != y)),
|
||||||
|
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 != y)),
|
||||||
|
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x != y as f64)),
|
||||||
|
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x != y)),
|
||||||
|
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x != y)),
|
||||||
|
(Value::String(x), Value::String(y)) => Ok(Value::Bool(x != y)),
|
||||||
|
(x, y) => Err(RuntimeError::NoOverloadForTypes("!=".into(), vec![x, y])),
|
||||||
|
},
|
||||||
ParseTree::GreaterThan(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
ParseTree::GreaterThan(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
||||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x > y)),
|
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x > y)),
|
||||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 > y)),
|
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 > y)),
|
||||||
@@ -197,6 +206,14 @@ where
|
|||||||
Value::Bool(x) => Ok(Value::Bool(!x)),
|
Value::Bool(x) => Ok(Value::Bool(!x)),
|
||||||
x => Err(RuntimeError::NoOverloadForTypes("not".into(), vec![x]))
|
x => Err(RuntimeError::NoOverloadForTypes("not".into(), vec![x]))
|
||||||
},
|
},
|
||||||
|
ParseTree::And(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
||||||
|
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x && y)),
|
||||||
|
(x, y) => Err(RuntimeError::NoOverloadForTypes("&&".into(), vec![x, y]))
|
||||||
|
},
|
||||||
|
ParseTree::Or(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) {
|
||||||
|
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x || y)),
|
||||||
|
(x, y) => Err(RuntimeError::NoOverloadForTypes("||".into(), vec![x, y]))
|
||||||
|
},
|
||||||
ParseTree::Equ(ident, body, scope) => {
|
ParseTree::Equ(ident, body, scope) => {
|
||||||
if self.globals.contains_key(&ident) || locals.contains_key(&ident) {
|
if self.globals.contains_key(&ident) || locals.contains_key(&ident) {
|
||||||
Err(RuntimeError::ImmutableError(ident.clone()))
|
Err(RuntimeError::ImmutableError(ident.clone()))
|
||||||
|
|||||||
117
src/parser.rs
117
src/parser.rs
@@ -47,11 +47,14 @@ pub(crate) enum ParseTree {
|
|||||||
|
|
||||||
// Boolean Operations
|
// Boolean Operations
|
||||||
EqualTo(Box<ParseTree>, Box<ParseTree>),
|
EqualTo(Box<ParseTree>, Box<ParseTree>),
|
||||||
|
NotEqualTo(Box<ParseTree>, Box<ParseTree>),
|
||||||
GreaterThan(Box<ParseTree>, Box<ParseTree>),
|
GreaterThan(Box<ParseTree>, Box<ParseTree>),
|
||||||
GreaterThanOrEqualTo(Box<ParseTree>, Box<ParseTree>),
|
GreaterThanOrEqualTo(Box<ParseTree>, Box<ParseTree>),
|
||||||
LessThan(Box<ParseTree>, Box<ParseTree>),
|
LessThan(Box<ParseTree>, Box<ParseTree>),
|
||||||
LessThanOrEqualTo(Box<ParseTree>, Box<ParseTree>),
|
LessThanOrEqualTo(Box<ParseTree>, Box<ParseTree>),
|
||||||
Not(Box<ParseTree>),
|
Not(Box<ParseTree>),
|
||||||
|
And(Box<ParseTree>, Box<ParseTree>),
|
||||||
|
Or(Box<ParseTree>, Box<ParseTree>),
|
||||||
|
|
||||||
// Defining Objects
|
// Defining Objects
|
||||||
Equ(String, Box<ParseTree>, Box<ParseTree>),
|
Equ(String, Box<ParseTree>, Box<ParseTree>),
|
||||||
@@ -81,6 +84,30 @@ pub(crate) enum ParseTree {
|
|||||||
Print(Box<ParseTree>),
|
Print(Box<ParseTree>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! one_arg {
|
||||||
|
($op:ident, $tokens:ident, $globals:ident, $locals:ident) => {
|
||||||
|
Ok(ParseTree::$op(
|
||||||
|
Box::new(ParseTree::parse($tokens, $globals, $locals)?)
|
||||||
|
))}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! two_arg {
|
||||||
|
($op:ident, $tokens:ident, $globals:ident, $locals:ident) => {
|
||||||
|
Ok(ParseTree::$op(
|
||||||
|
Box::new(ParseTree::parse($tokens, $globals, $locals)?),
|
||||||
|
Box::new(ParseTree::parse($tokens, $globals, $locals)?)
|
||||||
|
))}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! three_arg {
|
||||||
|
($op:ident, $tokens:ident, $globals:ident, $locals:ident) => {
|
||||||
|
Ok(ParseTree::$op(
|
||||||
|
Box::new(ParseTree::parse($tokens, $globals, $locals)?),
|
||||||
|
Box::new(ParseTree::parse($tokens, $globals, $locals)?),
|
||||||
|
Box::new(ParseTree::parse($tokens, $globals, $locals)?)
|
||||||
|
))}
|
||||||
|
}
|
||||||
|
|
||||||
impl ParseTree {
|
impl ParseTree {
|
||||||
fn parse<I>(
|
fn parse<I>(
|
||||||
tokens: &mut I,
|
tokens: &mut I,
|
||||||
@@ -108,30 +135,12 @@ impl ParseTree {
|
|||||||
}
|
}
|
||||||
Token::Operator(op) => {
|
Token::Operator(op) => {
|
||||||
match op {
|
match op {
|
||||||
Op::Add => Ok(ParseTree::Add(
|
Op::Add => two_arg!(Add, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
Op::Sub => two_arg!(Sub, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
Op::Mul => two_arg!(Mul, tokens, globals, locals),
|
||||||
)),
|
Op::Div => two_arg!(Div, tokens, globals, locals),
|
||||||
Op::Sub => Ok(ParseTree::Sub(
|
Op::Exp => two_arg!(Exp, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
Op::Mod => two_arg!(Mod, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::Mul => Ok(ParseTree::Mul(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::Div => Ok(ParseTree::Div(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::Exp => Ok(ParseTree::Exp(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::Mod => Ok(ParseTree::Mod(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::Equ | Op::LazyEqu => {
|
Op::Equ | Op::LazyEqu => {
|
||||||
let token = tokens.next()
|
let token = tokens.next()
|
||||||
.ok_or(ParseError::UnexpectedEndInput)?
|
.ok_or(ParseError::UnexpectedEndInput)?
|
||||||
@@ -183,48 +192,21 @@ impl ParseTree {
|
|||||||
Err(ParseError::InvalidIdentifier)
|
Err(ParseError::InvalidIdentifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::Compose => Ok(ParseTree::Compose(
|
Op::Compose => two_arg!(Compose, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
Op::Id => one_arg!(Id, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
Op::If => two_arg!(If, tokens, globals, locals),
|
||||||
)),
|
Op::IfElse => three_arg!(IfElse, tokens, globals, locals),
|
||||||
Op::Id => Ok(ParseTree::Id(
|
Op::EqualTo => two_arg!(EqualTo, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
Op::GreaterThan => two_arg!(GreaterThan, tokens, globals, locals),
|
||||||
)),
|
Op::LessThan => two_arg!(LessThan, tokens, globals, locals),
|
||||||
Op::If => Ok(ParseTree::If(
|
Op::GreaterThanOrEqualTo => two_arg!(GreaterThanOrEqualTo, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
Op::LessThanOrEqualTo => two_arg!(LessThanOrEqualTo, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
Op::Not => one_arg!(Not, tokens, globals, locals),
|
||||||
)),
|
Op::IntCast => one_arg!(IntCast, tokens, globals, locals),
|
||||||
Op::IfElse => Ok(ParseTree::IfElse(
|
Op::FloatCast => one_arg!(FloatCast, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
Op::BoolCast => one_arg!(BoolCast, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
Op::StringCast => one_arg!(StringCast, tokens, globals, locals),
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
Op::Print => one_arg!(Print, tokens, globals, locals),
|
||||||
)),
|
|
||||||
Op::EqualTo => Ok(ParseTree::EqualTo(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::GreaterThan => Ok(ParseTree::GreaterThan(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::LessThan => Ok(ParseTree::LessThan(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::GreaterThanOrEqualTo => Ok(ParseTree::GreaterThanOrEqualTo(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::LessThanOrEqualTo => Ok(ParseTree::LessThanOrEqualTo(
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?),
|
|
||||||
Box::new(ParseTree::parse(tokens, globals, locals)?)
|
|
||||||
)),
|
|
||||||
Op::Not => Ok(ParseTree::Not(Box::new(ParseTree::parse(tokens, globals, locals)?))),
|
|
||||||
Op::IntCast => Ok(ParseTree::IntCast(Box::new(ParseTree::parse(tokens, globals, locals)?))),
|
|
||||||
Op::FloatCast => Ok(ParseTree::FloatCast(Box::new(ParseTree::parse(tokens, globals, locals)?))),
|
|
||||||
Op::BoolCast => Ok(ParseTree::BoolCast(Box::new(ParseTree::parse(tokens, globals, locals)?))),
|
|
||||||
Op::StringCast => Ok(ParseTree::StringCast(Box::new(ParseTree::parse(tokens, globals, locals)?))),
|
|
||||||
Op::Print => Ok(ParseTree::Print(Box::new(ParseTree::parse(tokens, globals, locals)?))),
|
|
||||||
Op::OpenArray => {
|
Op::OpenArray => {
|
||||||
let mut depth = 1;
|
let mut depth = 1;
|
||||||
|
|
||||||
@@ -258,6 +240,9 @@ impl ParseTree {
|
|||||||
}
|
}
|
||||||
Op::Empty => Ok(ParseTree::Constant(Value::Array(vec![]))),
|
Op::Empty => Ok(ParseTree::Constant(Value::Array(vec![]))),
|
||||||
Op::CloseArray => Err(ParseError::UnmatchedArrayClose),
|
Op::CloseArray => Err(ParseError::UnmatchedArrayClose),
|
||||||
|
Op::NotEqualTo => two_arg!(NotEqualTo, tokens, globals, locals),
|
||||||
|
Op::And => two_arg!(And, tokens, globals, locals),
|
||||||
|
Op::Or => two_arg!(Or, tokens, globals, locals),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ pub(crate) enum Op {
|
|||||||
GreaterThan,
|
GreaterThan,
|
||||||
LessThan,
|
LessThan,
|
||||||
EqualTo,
|
EqualTo,
|
||||||
|
NotEqualTo,
|
||||||
GreaterThanOrEqualTo,
|
GreaterThanOrEqualTo,
|
||||||
LessThanOrEqualTo,
|
LessThanOrEqualTo,
|
||||||
Not,
|
Not,
|
||||||
@@ -68,6 +69,8 @@ pub(crate) enum Op {
|
|||||||
OpenArray,
|
OpenArray,
|
||||||
CloseArray,
|
CloseArray,
|
||||||
Empty,
|
Empty,
|
||||||
|
And,
|
||||||
|
Or,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -101,7 +104,6 @@ impl Token {
|
|||||||
// Match keywords first
|
// Match keywords first
|
||||||
"true" => Ok(Token::Constant(Value::Bool(true))),
|
"true" => Ok(Token::Constant(Value::Bool(true))),
|
||||||
"false" => Ok(Token::Constant(Value::Bool(false))),
|
"false" => Ok(Token::Constant(Value::Bool(false))),
|
||||||
"not" => Ok(Token::Operator(Op::Not)),
|
|
||||||
"int" => Ok(Token::Operator(Op::IntCast)),
|
"int" => Ok(Token::Operator(Op::IntCast)),
|
||||||
"float" => Ok(Token::Operator(Op::FloatCast)),
|
"float" => Ok(Token::Operator(Op::FloatCast)),
|
||||||
"bool" => Ok(Token::Operator(Op::BoolCast)),
|
"bool" => Ok(Token::Operator(Op::BoolCast)),
|
||||||
@@ -164,8 +166,12 @@ impl<R: BufRead> Tokenizer<R> {
|
|||||||
(">=", Op::GreaterThanOrEqualTo),
|
(">=", Op::GreaterThanOrEqualTo),
|
||||||
("<=", Op::LessThanOrEqualTo),
|
("<=", Op::LessThanOrEqualTo),
|
||||||
("==", Op::EqualTo),
|
("==", Op::EqualTo),
|
||||||
|
("!=", Op::NotEqualTo),
|
||||||
("[", Op::OpenArray),
|
("[", Op::OpenArray),
|
||||||
("]", Op::CloseArray),
|
("]", Op::CloseArray),
|
||||||
|
("!", Op::Not),
|
||||||
|
("&&", Op::And),
|
||||||
|
("||", Op::Or),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let c = if let Some(c) = iter.next() {
|
let c = if let Some(c) = iter.next() {
|
||||||
@@ -217,11 +223,15 @@ impl<R: BufRead> Tokenizer<R> {
|
|||||||
let mut token = String::from(c);
|
let mut token = String::from(c);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// get a list of all tokens this current token could possibly be
|
||||||
let possible: HashMap<&'static str, Op> = operators
|
let possible: HashMap<&'static str, Op> = operators
|
||||||
.clone().into_iter()
|
.clone().into_iter()
|
||||||
.filter(|(key, _)| key.starts_with(&token))
|
.filter(|(key, _)| key.starts_with(&token))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// checks if a character is "expected", aka based on how many chars
|
||||||
|
// we have eaten so far, which characters out of the current nominees
|
||||||
|
// are expected in the next position
|
||||||
let is_expected = |c: &char|
|
let is_expected = |c: &char|
|
||||||
possible.iter().any(|(op, _)| match op.chars().nth(token.len()) {
|
possible.iter().any(|(op, _)| match op.chars().nth(token.len()) {
|
||||||
Some(i) => *c == i,
|
Some(i) => *c == i,
|
||||||
@@ -230,20 +240,37 @@ impl<R: BufRead> Tokenizer<R> {
|
|||||||
|
|
||||||
match possible.len() {
|
match possible.len() {
|
||||||
1 => {
|
1 => {
|
||||||
self.tokens.push_back(Ok(Token::Operator(match possible.get(token.as_str()).unwrap().clone() {
|
// if the current operator exists in possible, we push it
|
||||||
Op::FunctionDeclare(n) => {
|
// if not, we need to make sure that the next characters
|
||||||
let count = match get_dot_count(&mut iter) {
|
// we grab *actually* match the last operator
|
||||||
Some(count) => count,
|
if let Some(op) = possible.get(token.as_str()) {
|
||||||
None => {
|
self.tokens.push_back(Ok(Token::Operator(match op {
|
||||||
self.tokens.push_back(Err(TokenizeError::InvalidDynamicOperator(token)));
|
// special handling for "dynamic" operators
|
||||||
return;
|
Op::FunctionDeclare(n) => {
|
||||||
}
|
let count = match get_dot_count(&mut iter) {
|
||||||
};
|
Some(count) => count,
|
||||||
Op::FunctionDeclare(n + count)
|
None => {
|
||||||
}
|
self.tokens.push_back(Err(TokenizeError::InvalidDynamicOperator(token)));
|
||||||
op => op,
|
return;
|
||||||
})));
|
}
|
||||||
break;
|
};
|
||||||
|
Op::FunctionDeclare(n + count)
|
||||||
|
}
|
||||||
|
op => op.clone(),
|
||||||
|
})));
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
let next = match iter.next_if(is_expected) {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
self.tokens.push_back(Err(TokenizeError::UnableToMatchToken(format!("{token}"))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
token.push(next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
0 => unreachable!(),
|
0 => unreachable!(),
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
Reference in New Issue
Block a user