Prefix operators

This commit is contained in:
greg 2017-09-17 17:44:06 -07:00
parent 8fe7c85b00
commit fc350cd03e
1 changed files with 38 additions and 7 deletions

View File

@ -346,7 +346,10 @@ binding_declaration: 'var' IDENTIFIER '=' expression
type_anno := ':' type
expression := precedence_expr
precedence_expr := primary
precedence_expr := prefix_expr
prefix_expr := prefix_op primary
prefix_op := '+' | '-' | '!' | '~'
primary := literal | paren_expr | identifier_expr
paren_expr := LParen expression RParen
@ -465,6 +468,7 @@ pub enum Expression {
StringLiteral(Rc<String>),
BoolLiteral(bool),
BinExp(Operation, Box<Expression>, Box<Expression>),
PrefixExp(Operation, Box<Expression>),
Variable(Rc<String>),
Call {
name: Rc<String>,
@ -487,13 +491,19 @@ impl Operation {
}
fn get_precedence(op: &str) -> i32 {
let c: char = op.chars().next().unwrap();
match c {
'+' | '-' => 10,
'*' | '/' | '%' => 20,
match op {
"+" | "-" => 10,
"*" | "/" | "%" => 20,
_ => 30,
}
}
fn is_prefix(op: &str) -> bool {
match op {
"+" | "-" | "!" | "~" => true,
_ => false,
}
}
}
macro_rules! parse_method {
@ -603,8 +613,7 @@ impl Parser {
};
self.parse_record.push(record);
//TODO clean this up
let mut lhs = self.primary()?;
let mut lhs = self.prefix_expr()?;
loop {
let new_precedence = match self.peek() {
Operator(op) => Operation::get_precedence(&*op),
@ -627,6 +636,20 @@ impl Parser {
Ok(lhs)
}
parse_method!(prefix_expr(&mut self) -> ParseResult<Expression> {
match self.peek() {
Operator(ref op) if Operation::is_prefix(&*op) => {
let op_str = match self.next() {
Operator(op) => op,
_ => unreachable!(),
};
let expr = self.primary()?;
Ok(Expression::PrefixExp(Operation { op: op_str }, Box::new(expr)))
},
_ => self.primary()
}
});
parse_method!(primary(&mut self) -> ParseResult<Expression> {
match self.peek() {
LParen => self.paren_expr(),
@ -814,6 +837,9 @@ mod parse_tests {
macro_rules! binexp {
($op:expr, $lhs:expr, $rhs:expr) => { BinExp($op, Box::new($lhs), Box::new($rhs)) }
}
macro_rules! prefexp {
($op:expr, $lhs:expr) => { PrefixExp($op, Box::new($lhs)) }
}
macro_rules! op {
($op:expr) => { Operation { op: Rc::new($op.to_string()) } }
}
@ -879,6 +905,11 @@ mod parse_tests {
binexp!(op!("."), var!("a"), var!("b")),
var!("c")),
var!("d")))]));
parse_test!("-3", AST(vec![Expression(prefexp!(op!("-"), IntLiteral(3)))]));
parse_test!("-0.2", AST(vec![Expression(prefexp!(op!("-"), FloatLiteral(0.2)))]));
parse_test!("!3", AST(vec![Expression(prefexp!(op!("!"), IntLiteral(3)))]));
parse_test!("a <- -b", AST(vec![Expression(binexp!(op!("<-"), var!("a"), prefexp!(op!("-"), var!("b"))))]));
parse_test!("a <--b", AST(vec![Expression(binexp!(op!("<--"), var!("a"), var!("b")))]));
}
#[test]