Pratt parsing

This commit is contained in:
greg 2020-02-13 02:48:38 -08:00
parent b7f7ba57d7
commit c6b0f7d7d1
2 changed files with 52 additions and 13 deletions

View File

@ -68,6 +68,10 @@ impl BinOp {
let s = token_kind_to_sigil(op_tok)?; let s = token_kind_to_sigil(op_tok)?;
Some(binop_precedences(s)) Some(binop_precedences(s))
} }
pub fn precedence(&self) -> i32 {
binop_precedences(self.sigil.as_str())
}
} }
fn token_kind_to_sigil<'a>(tok: &'a TokenKind) -> Option<&'a str> { fn token_kind_to_sigil<'a>(tok: &'a TokenKind) -> Option<&'a str> {

View File

@ -4,28 +4,21 @@ use std::rc::Rc;
use std::str::FromStr; use std::str::FromStr;
use nom::IResult; use nom::IResult;
use nom::character::complete::{one_of};
use nom::bytes::complete::{tag, take_while}; use nom::bytes::complete::{tag, take_while};
use nom::combinator::{map_res, value, opt}; use nom::combinator::{map, map_res, value, opt};
use nom::multi::many1; use nom::multi::many1;
//use nom::error::{ParseError, ErrorKind}; use nom::error::{ParseError, ErrorKind};
use nom::branch::alt; use nom::branch::alt;
use nom::sequence::delimited;
use crate::ast::*; use crate::ast::*;
use crate::builtin::Builtin; use crate::builtin::Builtin;
/*
#[derive(Debug, Clone)]
enum Prefix {
Plus,
Minus,
Bang,
}
*/
const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|"; const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|";
fn parse_operator(input: &str) -> IResult<&str, BinOp> { fn parse_binop(input: &str) -> IResult<&str, BinOp> {
use nom::character::complete::one_of; use nom::character::complete::one_of;
let (rest, op): (_, Vec<char>) = many1(one_of(OPERATOR_CHARS))(input)?; let (rest, op): (_, Vec<char>) = many1(one_of(OPERATOR_CHARS))(input)?;
let sigil: String = op.into_iter().collect(); let sigil: String = op.into_iter().collect();
@ -41,6 +34,22 @@ fn parse_bool_literal(input: &str) -> IResult<&str, ExpressionKind> {
Ok((rest, ExpressionKind::BoolLiteral(value))) Ok((rest, ExpressionKind::BoolLiteral(value)))
} }
fn parse_number_literal(input: &str) -> IResult<&str, ExpressionKind> {
let num_lit = many1(alt((
map(one_of("1234567890"), |s: char| Some(s)),
map(nom::character::complete::char('_'), |_| None)
)));
let (rest, n) = map_res(num_lit,
|digits: Vec<Option<char>>| {
let num_str: String = digits.into_iter().filter_map(|x| x).collect();
u64::from_str_radix(&num_str, 10)
})(input)?;
Ok((rest, ExpressionKind::NatLiteral(n)))
}
fn parse_binary_literal(input: &str) -> IResult<&str, ExpressionKind> { fn parse_binary_literal(input: &str) -> IResult<&str, ExpressionKind> {
let (rest, _) = tag("0b")(input)?; let (rest, _) = tag("0b")(input)?;
let (rest, n): (&str, u64) = map_res( let (rest, n): (&str, u64) = map_res(
@ -72,6 +81,7 @@ fn parse_string_literal(input: &str) -> IResult<&str, ExpressionKind> {
fn parse_literal(input: &str) -> IResult<&str, ExpressionKind> { fn parse_literal(input: &str) -> IResult<&str, ExpressionKind> {
alt(( alt((
parse_string_literal, parse_string_literal,
parse_number_literal,
parse_hex_literal, parse_hex_literal,
parse_binary_literal, parse_binary_literal,
parse_bool_literal parse_bool_literal
@ -119,8 +129,33 @@ fn prefix_expr(input: &str) -> IResult<&str, ExpressionKind> {
} }
} }
// this implements Pratt parsing, see http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
fn precedence_expr(input: &str, precedence: i32) -> IResult<&str, ExpressionKind> {
let (mut outer_rest, mut lhs) = prefix_expr(input)?;
loop {
let (rest, maybe_binop) = opt(parse_binop)(outer_rest)?;
println!("REST: {} | and maybe: {:?}", rest, maybe_binop);
let (new_precedence, binop) = match maybe_binop {
Some(binop) => (binop.precedence(), binop),
None => break,
};
println!("Calculated new precedence: {} for binop: {:?}", new_precedence, binop);
if precedence >= new_precedence {
break;
}
let (rest, rhs) = precedence_expr(rest, new_precedence)?;
outer_rest = rest;
lhs = ExpressionKind::BinExp(binop,
bx!(Expression::new(ItemId::new(0), lhs)),
bx!(Expression::new(ItemId::new(0), rhs))
);
}
Ok((outer_rest, lhs))
}
fn expression_kind(input: &str) -> IResult<&str, ExpressionKind> { fn expression_kind(input: &str) -> IResult<&str, ExpressionKind> {
prefix_expr(input) precedence_expr(input, BinOp::min_precedence())
} }
pub fn perform_parsing(input: &str) -> Result<String, String> { pub fn perform_parsing(input: &str) -> Result<String, String> {