Precedence parsing
Using the Pratt parser algorithm (probably with some bugs as of yet). Need to clean up the code some as well
This commit is contained in:
parent
c19946bb6d
commit
5889998126
@ -374,17 +374,22 @@ pub enum TypeBody {
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
IntLiteral(u64),
|
IntLiteral(u64),
|
||||||
FloatLiteral(f64),
|
FloatLiteral(f64),
|
||||||
BinExp(Operator, Box<Expression>, Box<Expression>)
|
BinExp(Operation, Box<Expression>, Box<Expression>)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Operator {
|
pub struct Operation {
|
||||||
op: [char; 5] //operators can be at most 5 characters long
|
op: Rc<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operator {
|
impl Operation {
|
||||||
fn get_precedence(&self) -> i32 {
|
fn min_precedence() -> i32 {
|
||||||
match self.op[0] {
|
i32::min_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_precedence(op: Rc<String>) -> i32 {
|
||||||
|
let c: char = op.chars().next().unwrap();
|
||||||
|
match c {
|
||||||
'+' | '-' => 10,
|
'+' | '-' => 10,
|
||||||
'*' | '/' | '%' => 20,
|
'*' | '/' | '%' => 20,
|
||||||
_ => 30,
|
_ => 30,
|
||||||
@ -437,8 +442,34 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> ParseResult<Expression> {
|
fn expression(&mut self) -> ParseResult<Expression> {
|
||||||
let lhs = self.primary()?;
|
self.precedence_expr(Operation::min_precedence())
|
||||||
//self.primary()
|
}
|
||||||
|
|
||||||
|
// this implements Pratt parsing, see http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
||||||
|
fn precedence_expr(&mut self, precedence: i32) -> ParseResult<Expression> {
|
||||||
|
use self::Expression::*;
|
||||||
|
|
||||||
|
//TODO clean this up
|
||||||
|
let mut lhs = self.primary()?;
|
||||||
|
loop {
|
||||||
|
let op_str = match self.peek() {
|
||||||
|
Operator(op) => op,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
println!("Opstr: {}", op_str);
|
||||||
|
let new_precedence = Operation::get_precedence(op_str);
|
||||||
|
println!("new {} and old {} precedence", new_precedence, precedence);
|
||||||
|
if precedence >= new_precedence {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let op_str = match self.next() {
|
||||||
|
Operator(op) => op,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let rhs = self.precedence_expr(new_precedence)?;
|
||||||
|
let operation = Operation { op: op_str };
|
||||||
|
lhs = BinExp(operation, Box::new(lhs), Box::new(rhs));
|
||||||
|
}
|
||||||
Ok(lhs)
|
Ok(lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +487,7 @@ impl Parser {
|
|||||||
fn literal(&mut self) -> ParseResult<Expression> {
|
fn literal(&mut self) -> ParseResult<Expression> {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
DigitGroup(_) | HexNumberSigil | BinNumberSigil | Period => self.number_literal(),
|
DigitGroup(_) | HexNumberSigil | BinNumberSigil | Period => self.number_literal(),
|
||||||
_ => unimplemented!(),
|
t => panic!("trying to parse {:?}", t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn number_literal(&mut self) -> ParseResult<Expression> {
|
fn number_literal(&mut self) -> ParseResult<Expression> {
|
||||||
@ -543,6 +574,12 @@ mod parse_tests {
|
|||||||
macro_rules! parse_test {
|
macro_rules! parse_test {
|
||||||
($string:expr, $correct:expr) => { assert_eq!(parse(tokenize($string)).unwrap(), $correct) }
|
($string:expr, $correct:expr) => { assert_eq!(parse(tokenize($string)).unwrap(), $correct) }
|
||||||
}
|
}
|
||||||
|
macro_rules! binexp {
|
||||||
|
($op:expr, $lhs:expr, $rhs:expr) => { BinExp($op, Box::new($lhs), Box::new($rhs)) }
|
||||||
|
}
|
||||||
|
macro_rules! op {
|
||||||
|
($op:expr) => { Operation { op: Rc::new($op.to_string()) } }
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parsing() {
|
fn test_parsing() {
|
||||||
@ -551,5 +588,15 @@ mod parse_tests {
|
|||||||
parse_test!("3; 4; 4.3", AST(
|
parse_test!("3; 4; 4.3", AST(
|
||||||
vec![Expression(IntLiteral(3)), Expression(IntLiteral(4)),
|
vec![Expression(IntLiteral(3)), Expression(IntLiteral(4)),
|
||||||
Expression(FloatLiteral(4.3))]));
|
Expression(FloatLiteral(4.3))]));
|
||||||
|
|
||||||
|
parse_test!("1 + 2 * 3", AST(vec!
|
||||||
|
[
|
||||||
|
Expression(binexp!(op!("+"), IntLiteral(1), binexp!(op!("*"), IntLiteral(2), IntLiteral(3))))
|
||||||
|
]));
|
||||||
|
|
||||||
|
parse_test!("1 * 2 + 3", AST(vec!
|
||||||
|
[
|
||||||
|
Expression(binexp!(op!("+"), binexp!(op!("*"), IntLiteral(1), IntLiteral(2)), IntLiteral(3)))
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user