aiken/crates/aiken-lang/src/parser/expr/anonymous_binop.rs

115 lines
3.4 KiB
Rust

use chumsky::prelude::*;
use crate::{
ast,
expr::{FnStyle, UntypedExpr},
parser::{error::ParseError, token::Token},
};
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
select! {
Token::EqualEqual => ast::BinOp::Eq,
Token::NotEqual => ast::BinOp::NotEq,
Token::Less => ast::BinOp::LtInt,
Token::LessEqual => ast::BinOp::LtEqInt,
Token::Greater => ast::BinOp::GtInt,
Token::GreaterEqual => ast::BinOp::GtEqInt,
Token::VbarVbar => ast::BinOp::Or,
Token::AmperAmper => ast::BinOp::And,
Token::Plus => ast::BinOp::AddInt,
Token::Minus => ast::BinOp::SubInt,
Token::Slash => ast::BinOp::DivInt,
Token::Star => ast::BinOp::MultInt,
Token::Percent => ast::BinOp::ModInt,
}
.map_with_span(|name, location| {
use ast::BinOp::*;
let arg_annotation = match name {
Or | And => Some(ast::Annotation::boolean(location)),
Eq | NotEq => None,
LtInt | LtEqInt | GtInt | GtEqInt | AddInt | SubInt | MultInt | DivInt | ModInt => {
Some(ast::Annotation::int(location))
}
};
let return_annotation = match name {
Or | And | Eq | NotEq | LtInt | LtEqInt | GtInt | GtEqInt => {
Some(ast::Annotation::boolean(location))
}
AddInt | SubInt | MultInt | DivInt | ModInt => Some(ast::Annotation::int(location)),
};
let arguments = vec![
ast::Arg {
arg_name: ast::ArgName::Named {
name: "left".to_string(),
label: "left".to_string(),
location,
is_validator_param: false,
},
annotation: arg_annotation.clone(),
location,
tipo: (),
},
ast::Arg {
arg_name: ast::ArgName::Named {
name: "right".to_string(),
label: "right".to_string(),
location,
is_validator_param: false,
},
annotation: arg_annotation,
location,
tipo: (),
},
];
let body = UntypedExpr::BinOp {
location,
name,
left: Box::new(UntypedExpr::Var {
location,
name: "left".to_string(),
}),
right: Box::new(UntypedExpr::Var {
location,
name: "right".to_string(),
}),
};
UntypedExpr::Fn {
arguments,
body: Box::new(body),
return_annotation,
fn_style: FnStyle::BinOp(name),
location,
}
})
}
#[cfg(test)]
mod tests {
use crate::assert_expr;
#[test]
fn first_class_binop() {
assert_expr!(
r#"
compare_with(a, >, b)
compare_with(a, >=, b)
compare_with(a, <, b)
compare_with(a, <=, b)
compare_with(a, ==, b)
compare_with(a, !=, b)
combine_with(a, &&, b)
combine_with(a, ||, b)
compute_with(a, +, b)
compute_with(a, -, b)
compute_with(a, /, b)
compute_with(a, *, b)
compute_with(a, %, b)"#
);
}
}