ops, negative number parsing
This commit is contained in:
parent
2372f0d254
commit
8e9ac2262a
8 changed files with 451 additions and 30 deletions
|
|
@ -39,3 +39,11 @@ pub fn define_expr(name: &str, expr: Expr) -> Definition {
|
|||
pub fn func(args: Vec<Arg>, body: Expr) -> Expr {
|
||||
Expr::Func(Box::new(Fn { args, body }))
|
||||
}
|
||||
|
||||
pub fn op(op: Op, a: Expr, b: Expr) -> Expr {
|
||||
Expr::Op {
|
||||
op,
|
||||
lhs: Box::new(a),
|
||||
rhs: Box::new(b),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use std::collections::BTreeMap;
|
|||
/// An expression.
|
||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||
pub enum Expr {
|
||||
Not(Box<Expr>),
|
||||
Op {
|
||||
lhs: Box<Expr>,
|
||||
op: Op,
|
||||
|
|
@ -41,7 +42,36 @@ pub enum Expr {
|
|||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||
pub enum Op {
|
||||
Assign,
|
||||
// Equals,
|
||||
Compare(Cmp),
|
||||
Calc(Calc),
|
||||
Bool(BoolOp),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||
pub enum BoolOp {
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||
pub enum Cmp {
|
||||
Eq,
|
||||
NotEq,
|
||||
Gt,
|
||||
Lt,
|
||||
Gte,
|
||||
Lte,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||
pub enum Calc {
|
||||
Add,
|
||||
Sub,
|
||||
Div,
|
||||
Mul,
|
||||
Mod,
|
||||
BinAnd,
|
||||
BinOr,
|
||||
}
|
||||
|
||||
/// A statement.
|
||||
|
|
|
|||
|
|
@ -172,6 +172,10 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
|
|||
Backtrace::capture(),
|
||||
)),
|
||||
},
|
||||
ast::Expr::Not(e) => match eval_expr(&expr_env, state, e)? {
|
||||
ast::Value::Boolean(b) => Ok(ast::Value::Boolean(!b)),
|
||||
v => Err(Error::NotABoolean(v, Backtrace::capture())),
|
||||
},
|
||||
ast::Expr::Value(v) => match v {
|
||||
ast::Value::Closure { expr, env } => {
|
||||
let closure_env: Env = state.envs.get(env)?.clone();
|
||||
|
|
@ -189,13 +193,124 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
|
|||
}
|
||||
v => Err(Error::NotAReference(v.clone(), Backtrace::capture())),
|
||||
},
|
||||
/*
|
||||
_ => {
|
||||
let _lhs = eval_expr(expr_env, state, lhs)?;
|
||||
let _rhs = eval_expr(expr_env, state, rhs)?;
|
||||
todo!()
|
||||
ast::Op::Calc(cop) => {
|
||||
let lhs = eval_expr(expr_env, state, lhs)?;
|
||||
let rhs = eval_expr(expr_env, state, rhs)?;
|
||||
|
||||
match (lhs, rhs) {
|
||||
(ast::Value::Int(a), ast::Value::Int(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Calc::Add => |a, b| a + b,
|
||||
ast::Calc::Sub => |a, b| a - b,
|
||||
ast::Calc::Mul => |a, b| a * b,
|
||||
ast::Calc::Div => |a, b| a / b,
|
||||
ast::Calc::Mod => |a, b| a % b,
|
||||
ast::Calc::BinAnd => |a, b| a & b,
|
||||
ast::Calc::BinOr => |a, b| a | b,
|
||||
};
|
||||
Ok(ast::Value::Int(cop(a, b)))
|
||||
}
|
||||
(ast::Value::Float(a), ast::Value::Int(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Calc::Add => |a, b| a + b,
|
||||
ast::Calc::Sub => |a, b| a - b,
|
||||
ast::Calc::Mul => |a, b| a * b,
|
||||
ast::Calc::Div => |a, b| a / b,
|
||||
ast::Calc::Mod => |a, b| a % b,
|
||||
_ => todo!(),
|
||||
};
|
||||
Ok(ast::Value::Float(cop(a, b as f32)))
|
||||
}
|
||||
(ast::Value::Int(a), ast::Value::Float(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Calc::Add => |a, b| a + b,
|
||||
ast::Calc::Sub => |a, b| a - b,
|
||||
ast::Calc::Mul => |a, b| a * b,
|
||||
ast::Calc::Div => |a, b| a / b,
|
||||
ast::Calc::Mod => |a, b| a % b,
|
||||
_ => todo!(),
|
||||
};
|
||||
Ok(ast::Value::Float(cop(a as f32, b)))
|
||||
}
|
||||
(ast::Value::Float(a), ast::Value::Float(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Calc::Add => |a, b| a + b,
|
||||
ast::Calc::Sub => |a, b| a - b,
|
||||
ast::Calc::Mul => |a, b| a * b,
|
||||
ast::Calc::Div => |a, b| a / b,
|
||||
ast::Calc::Mod => |a, b| a % b,
|
||||
_ => todo!(),
|
||||
};
|
||||
Ok(ast::Value::Float(cop(a, b)))
|
||||
}
|
||||
(lhs, rhs) => Err(Error::OpError(lhs, op.clone(), rhs, Backtrace::capture())),
|
||||
}
|
||||
}
|
||||
ast::Op::Compare(cop) => {
|
||||
let lhs = eval_expr(expr_env, state, lhs)?;
|
||||
let rhs = eval_expr(expr_env, state, rhs)?;
|
||||
match (lhs, rhs) {
|
||||
(ast::Value::Int(a), ast::Value::Int(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Cmp::Eq => |a, b| a == b,
|
||||
ast::Cmp::NotEq => |a, b| a != b,
|
||||
ast::Cmp::Gt => |a, b| a > b,
|
||||
ast::Cmp::Gte => |a, b| a >= b,
|
||||
ast::Cmp::Lt => |a, b| a < b,
|
||||
ast::Cmp::Lte => |a, b| a <= b,
|
||||
};
|
||||
Ok(ast::Value::Boolean(cop(a, b)))
|
||||
}
|
||||
(ast::Value::Float(a), ast::Value::Float(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Cmp::Eq => |a, b| a == b,
|
||||
ast::Cmp::NotEq => |a, b| a != b,
|
||||
ast::Cmp::Gt => |a, b| a > b,
|
||||
ast::Cmp::Gte => |a, b| a >= b,
|
||||
ast::Cmp::Lt => |a, b| a < b,
|
||||
ast::Cmp::Lte => |a, b| a <= b,
|
||||
};
|
||||
Ok(ast::Value::Boolean(cop(a, b)))
|
||||
}
|
||||
(ast::Value::Boolean(a), ast::Value::Boolean(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Cmp::Eq => |a, b| a == b,
|
||||
ast::Cmp::NotEq => |a, b| a != b,
|
||||
ast::Cmp::Gt => |a, b| a > b,
|
||||
ast::Cmp::Gte => |a, b| a >= b,
|
||||
ast::Cmp::Lt => |a, b| a < b,
|
||||
ast::Cmp::Lte => |a, b| a <= b,
|
||||
};
|
||||
Ok(ast::Value::Boolean(cop(a, b)))
|
||||
}
|
||||
(ast::Value::String(a), ast::Value::String(b)) => {
|
||||
let cop = match cop {
|
||||
ast::Cmp::Eq => |a, b| a == b,
|
||||
ast::Cmp::NotEq => |a, b| a != b,
|
||||
ast::Cmp::Gt => |a, b| a > b,
|
||||
ast::Cmp::Gte => |a, b| a >= b,
|
||||
ast::Cmp::Lt => |a, b| a < b,
|
||||
ast::Cmp::Lte => |a, b| a <= b,
|
||||
};
|
||||
Ok(ast::Value::Boolean(cop(a, b)))
|
||||
}
|
||||
(lhs, rhs) => Err(Error::OpError(lhs, op.clone(), rhs, Backtrace::capture())),
|
||||
}
|
||||
}
|
||||
ast::Op::Bool(bop) => {
|
||||
let lhs = eval_expr(expr_env, state, lhs)?;
|
||||
let rhs = eval_expr(expr_env, state, rhs)?;
|
||||
match (lhs, rhs) {
|
||||
(ast::Value::Boolean(a), ast::Value::Boolean(b)) => {
|
||||
let bop = match bop {
|
||||
ast::BoolOp::And => |a, b| a && b,
|
||||
ast::BoolOp::Or => |a, b| a || b,
|
||||
};
|
||||
Ok(ast::Value::Boolean(bop(a, b)))
|
||||
}
|
||||
(lhs, rhs) => Err(Error::OpError(lhs, op.clone(), rhs, Backtrace::capture())),
|
||||
}
|
||||
}
|
||||
*/
|
||||
},
|
||||
ast::Expr::Record(record) => {
|
||||
let mut map = BTreeMap::new();
|
||||
|
|
@ -316,6 +431,55 @@ mod tests {
|
|||
assert_eq!(result, Ok(0.into()));
|
||||
}
|
||||
#[test]
|
||||
fn main_not() {
|
||||
let program = vec![helpers::define_expr(
|
||||
"main",
|
||||
helpers::func(vec![], ast::Expr::Not(Box::new(false.into()))),
|
||||
)]
|
||||
.into();
|
||||
let result = run(program, "main".into(), vec![]);
|
||||
assert_eq!(result, Ok(true.into()));
|
||||
}
|
||||
#[test]
|
||||
fn main_or() {
|
||||
let program = vec![helpers::define_expr(
|
||||
"main",
|
||||
helpers::func(
|
||||
vec![],
|
||||
helpers::op(ast::Op::Bool(ast::BoolOp::Or), false.into(), true.into()),
|
||||
),
|
||||
)]
|
||||
.into();
|
||||
let result = run(program, "main".into(), vec![]);
|
||||
assert_eq!(result, Ok(true.into()));
|
||||
}
|
||||
#[test]
|
||||
fn main_and() {
|
||||
let program = vec![helpers::define_expr(
|
||||
"main",
|
||||
helpers::func(
|
||||
vec![],
|
||||
helpers::op(ast::Op::Bool(ast::BoolOp::And), false.into(), true.into()),
|
||||
),
|
||||
)]
|
||||
.into();
|
||||
let result = run(program, "main".into(), vec![]);
|
||||
assert_eq!(result, Ok(false.into()));
|
||||
}
|
||||
#[test]
|
||||
fn main_add() {
|
||||
let program = vec![helpers::define_expr(
|
||||
"main",
|
||||
helpers::func(
|
||||
vec![],
|
||||
helpers::op(ast::Op::Calc(ast::Calc::Add), 7.into(), 8.into()),
|
||||
),
|
||||
)]
|
||||
.into();
|
||||
let result = run(program, "main".into(), vec![]);
|
||||
assert_eq!(result, Ok(15.into()));
|
||||
}
|
||||
#[test]
|
||||
fn var_lookup() {
|
||||
let program = vec![
|
||||
helpers::define_expr("main", helpers::func(vec![], "lit".into())),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ pub enum Error {
|
|||
NotARecord(ast::Value, Backtrace),
|
||||
NotAReference(ast::Value, Backtrace),
|
||||
NotABoolean(ast::Value, Backtrace),
|
||||
OpError(ast::Value, ast::Op, ast::Value, Backtrace),
|
||||
ArgumentsMismatch(Backtrace),
|
||||
}
|
||||
impl PartialEq for Error {
|
||||
|
|
@ -60,6 +61,7 @@ impl std::fmt::Display for Error {
|
|||
Error::NotAReference(a, b) => write!(f, "Not a reference {a:?}\n{b}"),
|
||||
Error::NotABoolean(a, b) => write!(f, "Not a boolean {a:?}\n{b}"),
|
||||
Error::ArgumentsMismatch(a) => write!(f, "Arguments mismatch\n{a}"),
|
||||
Error::OpError(a, b, c, d) => write!(f, "Op Error {a:?} {b:?} {c:?}\n{d}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,25 @@ fn parse_definitions(tokens: &mut Tokens) -> ParseResult<Vec<ast::Definition>> {
|
|||
tokens.many(parse_definition)
|
||||
}
|
||||
|
||||
fn parse_op(tokens: &mut Tokens) -> ParseResult<(ast::Expr, Op)> {
|
||||
if let Some(LocatedToken {
|
||||
token: Token::Op(op),
|
||||
..
|
||||
}) = tokens.next_if(&Token::Op(Op::Add))
|
||||
{
|
||||
if let Some(expr) = parse_expr(tokens)? {
|
||||
Ok(Some((expr, op)))
|
||||
} else {
|
||||
Err(Error::UnexpectedTokenForParser(
|
||||
"parse_op".into(),
|
||||
tokens.next(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_set(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||
if let Some(_eq) = tokens.next_if(&Token::Equals) {
|
||||
if let Some(expr) = parse_expr(tokens)? {
|
||||
|
|
@ -97,6 +116,29 @@ fn parse_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
|||
func: Box::new(expr1),
|
||||
args,
|
||||
}))
|
||||
} else if let Some((expr2, op)) = parse_op(tokens)? {
|
||||
let op = match op {
|
||||
Op::Eq => ast::Op::Compare(ast::Cmp::Eq),
|
||||
Op::NotEq => ast::Op::Compare(ast::Cmp::NotEq),
|
||||
Op::Gt => ast::Op::Compare(ast::Cmp::Gt),
|
||||
Op::Gte => ast::Op::Compare(ast::Cmp::Gte),
|
||||
Op::Lt => ast::Op::Compare(ast::Cmp::Lt),
|
||||
Op::Lte => ast::Op::Compare(ast::Cmp::Lte),
|
||||
Op::Add => ast::Op::Calc(ast::Calc::Add),
|
||||
Op::Sub => ast::Op::Calc(ast::Calc::Sub),
|
||||
Op::Mul => ast::Op::Calc(ast::Calc::Mul),
|
||||
Op::Div => ast::Op::Calc(ast::Calc::Div),
|
||||
Op::Mod => ast::Op::Calc(ast::Calc::Mod),
|
||||
Op::BinAnd => ast::Op::Calc(ast::Calc::BinAnd),
|
||||
Op::BinOr => ast::Op::Calc(ast::Calc::BinOr),
|
||||
Op::And => ast::Op::Bool(ast::BoolOp::And),
|
||||
Op::Or => ast::Op::Bool(ast::BoolOp::Or),
|
||||
};
|
||||
Ok(Some(ast::Expr::Op {
|
||||
op,
|
||||
lhs: Box::new(expr1.clone()),
|
||||
rhs: Box::new(expr2),
|
||||
}))
|
||||
} else {
|
||||
Ok(parse_set(tokens)?
|
||||
.map(|expr2| ast::Expr::Op {
|
||||
|
|
@ -113,6 +155,13 @@ fn parse_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
|||
|
||||
fn parse_simple_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||
tokens.one_of(vec![
|
||||
|t| {
|
||||
if let Some(_) = t.next_if(&Token::Not) {
|
||||
Ok(parse_expr(t)?.map(|expr| ast::Expr::Not(Box::new(expr))))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
},
|
||||
parse_number,
|
||||
parse_identifier,
|
||||
parse_string,
|
||||
|
|
@ -334,6 +383,12 @@ mod tests {
|
|||
insta::assert_debug_snapshot!(result);
|
||||
}
|
||||
#[test]
|
||||
fn negative_number() {
|
||||
let program = "-108".to_string();
|
||||
let result = parse(&mut scan(program), parse_expr);
|
||||
insta::assert_debug_snapshot!(result);
|
||||
}
|
||||
#[test]
|
||||
fn paren_identifier() {
|
||||
let program = "(hello)".to_string();
|
||||
let result = parse(&mut scan(program), parse_expr);
|
||||
|
|
|
|||
|
|
@ -93,11 +93,135 @@ pub fn scan(source: String) -> Tokens {
|
|||
end: scanner.cursor(),
|
||||
token: Token::CloseBracket,
|
||||
}),
|
||||
'=' => tokens.push(LocatedToken {
|
||||
'+' => tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Equals,
|
||||
token: Token::Op(Op::Add),
|
||||
}),
|
||||
'*' => tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Op(Op::Mul),
|
||||
}),
|
||||
'/' => tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Op(Op::Div),
|
||||
}),
|
||||
'%' => tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Op(Op::Mod),
|
||||
}),
|
||||
'-' => {
|
||||
let c = c.clone();
|
||||
let is_number = scanner.peek().map(|ch| ch.is_numeric()) == Some(true);
|
||||
if is_number {
|
||||
tokens.push(lex_number(&mut scanner, start, &c));
|
||||
} else {
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Op(Op::Sub),
|
||||
});
|
||||
}
|
||||
}
|
||||
'<' => {
|
||||
let token = if let Some(ch) = scanner.peek()
|
||||
&& *ch == '='
|
||||
{
|
||||
scanner.pop();
|
||||
Token::Op(Op::Lte)
|
||||
} else {
|
||||
Token::Op(Op::Lt)
|
||||
};
|
||||
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token,
|
||||
})
|
||||
}
|
||||
'>' => {
|
||||
let token = if let Some(ch) = scanner.peek()
|
||||
&& *ch == '='
|
||||
{
|
||||
scanner.pop();
|
||||
Token::Op(Op::Gte)
|
||||
} else {
|
||||
Token::Op(Op::Gt)
|
||||
};
|
||||
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token,
|
||||
})
|
||||
}
|
||||
'=' => {
|
||||
let token = if let Some(ch) = scanner.peek()
|
||||
&& *ch == '='
|
||||
{
|
||||
scanner.pop();
|
||||
Token::Op(Op::Eq)
|
||||
} else {
|
||||
Token::Equals
|
||||
};
|
||||
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token,
|
||||
})
|
||||
}
|
||||
'|' => {
|
||||
let token = if let Some(ch) = scanner.peek()
|
||||
&& *ch == '|'
|
||||
{
|
||||
scanner.pop();
|
||||
Token::Op(Op::Or)
|
||||
} else {
|
||||
Token::Op(Op::BinOr)
|
||||
};
|
||||
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token,
|
||||
})
|
||||
}
|
||||
'&' => {
|
||||
let token = if let Some(ch) = scanner.peek()
|
||||
&& *ch == '&'
|
||||
{
|
||||
scanner.pop();
|
||||
Token::Op(Op::And)
|
||||
} else {
|
||||
Token::Op(Op::BinAnd)
|
||||
};
|
||||
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token,
|
||||
})
|
||||
}
|
||||
'!' => {
|
||||
let token = if let Some(ch) = scanner.peek()
|
||||
&& *ch == '='
|
||||
{
|
||||
scanner.pop();
|
||||
Token::Op(Op::NotEq)
|
||||
} else {
|
||||
Token::Not
|
||||
};
|
||||
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token,
|
||||
})
|
||||
}
|
||||
// labels
|
||||
'.' => {
|
||||
let mut str = "".to_string();
|
||||
|
|
@ -152,25 +276,8 @@ pub fn scan(source: String) -> Tokens {
|
|||
_ if c.is_whitespace() => {}
|
||||
// numbers
|
||||
_ if c.is_numeric() => {
|
||||
let mut str = c.to_string();
|
||||
loop {
|
||||
if let Some(ch) = scanner.peek()
|
||||
&& !ch.is_numeric()
|
||||
{
|
||||
break;
|
||||
}
|
||||
if let Some(ch) = scanner.pop() {
|
||||
str.push(*ch);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let i = str.parse::<u16>().unwrap();
|
||||
tokens.push(LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Number(i),
|
||||
});
|
||||
let c = c.clone();
|
||||
tokens.push(lex_number(&mut scanner, start, &c));
|
||||
}
|
||||
// identifiers and keywords
|
||||
_ if c.is_alphabetic() || *c == '_' => {
|
||||
|
|
@ -216,6 +323,28 @@ pub fn scan(source: String) -> Tokens {
|
|||
tokens.into()
|
||||
}
|
||||
|
||||
fn lex_number(scanner: &mut Scanner, start: Pos, c: &char) -> LocatedToken {
|
||||
let mut str = c.to_string();
|
||||
loop {
|
||||
if let Some(ch) = scanner.peek()
|
||||
&& !ch.is_numeric()
|
||||
{
|
||||
break;
|
||||
}
|
||||
if let Some(ch) = scanner.pop() {
|
||||
str.push(*ch);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let i = str.parse::<i32>().unwrap();
|
||||
LocatedToken {
|
||||
start,
|
||||
end: scanner.cursor(),
|
||||
token: Token::Number(i),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
source: src/parser/parser.rs
|
||||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Int(
|
||||
-108,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -22,7 +22,6 @@ pub enum Token {
|
|||
Fn,
|
||||
Mut,
|
||||
Return,
|
||||
Equals,
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
OpenBracket,
|
||||
|
|
@ -34,12 +33,34 @@ pub enum Token {
|
|||
Colon,
|
||||
True,
|
||||
False,
|
||||
Number(u16),
|
||||
Equals,
|
||||
Not,
|
||||
Op(Op),
|
||||
Number(i32),
|
||||
String(String),
|
||||
Identifier(String),
|
||||
Label(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Op {
|
||||
Eq,
|
||||
NotEq,
|
||||
Gt,
|
||||
Lt,
|
||||
Gte,
|
||||
Lte,
|
||||
Add,
|
||||
Sub,
|
||||
Div,
|
||||
Mul,
|
||||
Mod,
|
||||
And,
|
||||
Or,
|
||||
BinAnd,
|
||||
BinOr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Tokens(pub Vec<LocatedToken>);
|
||||
|
||||
|
|
@ -65,6 +86,7 @@ impl Tokens {
|
|||
(Token::Number(_), Token::Number(_)) => true,
|
||||
(Token::String(_), Token::String(_)) => true,
|
||||
(Token::Label(_), Token::Label(_)) => true,
|
||||
(Token::Op(_), Token::Op(_)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue