165 lines
4.7 KiB
Rust
165 lines
4.7 KiB
Rust
extern crate nom;
|
|
|
|
use std::rc::Rc;
|
|
use std::str::FromStr;
|
|
|
|
use nom::IResult;
|
|
use nom::character::complete::{one_of};
|
|
use nom::bytes::complete::{tag, take_while};
|
|
use nom::combinator::{map, map_res, value, opt};
|
|
use nom::multi::many1;
|
|
use nom::error::{ParseError, ErrorKind};
|
|
use nom::branch::alt;
|
|
use nom::sequence::delimited;
|
|
|
|
use crate::ast::*;
|
|
use crate::builtin::Builtin;
|
|
|
|
|
|
const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|";
|
|
|
|
fn parse_binop(input: &str) -> IResult<&str, BinOp> {
|
|
use nom::character::complete::one_of;
|
|
let (rest, op): (_, Vec<char>) = many1(one_of(OPERATOR_CHARS))(input)?;
|
|
let sigil: String = op.into_iter().collect();
|
|
Ok((rest, BinOp::from_sigil(&sigil)))
|
|
}
|
|
|
|
|
|
fn parse_bool_literal(input: &str) -> IResult<&str, ExpressionKind> {
|
|
let (rest, value) = alt((
|
|
value(true, tag("true")),
|
|
value(false, tag("false"))
|
|
))(input)?;
|
|
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> {
|
|
let (rest, _) = tag("0b")(input)?;
|
|
let (rest, n): (&str, u64) = map_res(
|
|
take_while(|c: char| c == '0' || c == '1'),
|
|
|hex_str: &str| u64::from_str_radix(hex_str, 2)
|
|
)(rest)?;
|
|
let expr = ExpressionKind::NatLiteral(n);
|
|
Ok((rest, expr))
|
|
}
|
|
|
|
fn parse_hex_literal(input: &str) -> IResult<&str, ExpressionKind> {
|
|
let (rest, _) = tag("0x")(input)?;
|
|
let (rest, n): (&str, u64) = map_res(
|
|
take_while(|c: char| c.is_digit(16)),
|
|
|hex_str: &str| u64::from_str_radix(hex_str, 16)
|
|
)(rest)?;
|
|
let expr = ExpressionKind::NatLiteral(n);
|
|
Ok((rest, expr))
|
|
}
|
|
|
|
fn parse_string_literal(input: &str) -> IResult<&str, ExpressionKind> {
|
|
let (rest, _) = nom::character::complete::char('"')(input)?;
|
|
let (rest, string_output) = nom::bytes::complete::take_until("\"")(rest)?;
|
|
let (rest, _) = nom::character::complete::char('"')(rest)?;
|
|
let expr = ExpressionKind::StringLiteral(Rc::new(string_output.to_string()));
|
|
Ok((rest, expr))
|
|
}
|
|
|
|
fn parse_literal(input: &str) -> IResult<&str, ExpressionKind> {
|
|
alt((
|
|
parse_string_literal,
|
|
parse_number_literal,
|
|
parse_hex_literal,
|
|
parse_binary_literal,
|
|
parse_bool_literal
|
|
))(input)
|
|
}
|
|
|
|
fn paren_expr(input: &str) -> IResult<&str, ExpressionKind> {
|
|
let (rest, _) = nom::character::complete::char('(')(input)?;
|
|
let (rest, inner) = expression_kind(rest)?;
|
|
let (rest, _) = nom::character::complete::char(')')(rest)?;
|
|
Ok((rest, inner))
|
|
}
|
|
|
|
fn prefix_op(input: &str) -> IResult<&str, PrefixOp> {
|
|
use nom::character::complete::char;
|
|
let (rest, sigil) = alt((
|
|
char('+'),
|
|
char('-'),
|
|
char('!')
|
|
))(input)?;
|
|
let op = PrefixOp::from_str(&sigil.to_string()).unwrap();
|
|
Ok((rest, op))
|
|
|
|
/*
|
|
alt((
|
|
value(Plus, char('+')),
|
|
value(Minus, char('-')),
|
|
value(Bang, char('!'))
|
|
))(input)
|
|
*/
|
|
}
|
|
|
|
fn prefix_expr(input: &str) -> IResult<&str, ExpressionKind> {
|
|
let (rest, pfx) = opt(prefix_op)(input)?;
|
|
let (rest, result) = alt((
|
|
paren_expr,
|
|
parse_literal
|
|
))(rest)?;
|
|
match pfx {
|
|
None => Ok((rest, result)),
|
|
Some(pfx) => {
|
|
let exp = Expression { id: ItemId::new(0), kind: result, type_anno: None };
|
|
Ok((rest, ExpressionKind::PrefixExp(pfx, Box::new(exp))))
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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> {
|
|
precedence_expr(input, BinOp::min_precedence())
|
|
}
|
|
|
|
pub fn perform_parsing(input: &str) -> Result<String, String> {
|
|
let output = expression_kind(input);
|
|
Ok(format!("{:?}", output))
|
|
}
|