Prefix operators

This commit is contained in:
greg 2017-09-17 17:44:06 -07:00
parent 8fe7c85b00
commit fc350cd03e

View File

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