Various other expr stuff
This commit is contained in:
parent
a666ac985b
commit
7a9e43bf8e
@ -2,7 +2,8 @@ use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::{tag, escaped_transform, take_till},
|
||||
bytes::complete::{tag, escaped_transform, take_while, take_till},
|
||||
character::is_alphanumeric,
|
||||
character::complete::{
|
||||
alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0,
|
||||
space1,
|
||||
@ -132,14 +133,17 @@ fn type_singleton_name(input: Span) -> ParseResult<TypeSingletonName> {
|
||||
}
|
||||
|
||||
pub fn expression_kind(input: Span) -> ParseResult<ExpressionKind> {
|
||||
context("expression-kind", prefix_expr)(input)
|
||||
context("expression-kind", precedence_expr)(input)
|
||||
}
|
||||
|
||||
fn precedence_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
let handle = input.extra.clone();
|
||||
map(
|
||||
pair(prefix_expr, many0(precedence_continuation)),
|
||||
|(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| unimplemented!(),
|
||||
)(input)
|
||||
move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| {
|
||||
let mut handle_ref = handle.borrow_mut();
|
||||
BinopSequence { first, rest }.do_precedence(&mut handle_ref)
|
||||
})(input)
|
||||
}
|
||||
|
||||
fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> {
|
||||
@ -178,12 +182,25 @@ fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
|
||||
fn primary_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
context("primary-expr", alt((
|
||||
list_expr,
|
||||
list_expr, paren_expr,
|
||||
string_literal, float_literal, number_literal, bool_literal, identifier_expr
|
||||
))
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn paren_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
delimited(
|
||||
tok(char('(')),
|
||||
map(separated_list0(tok(char(',')), expression),
|
||||
|mut exprs| match exprs.len() {
|
||||
1 => exprs.pop().unwrap().kind,
|
||||
_ => ExpressionKind::TupleLiteral(exprs),
|
||||
}),
|
||||
tok(char(')'))
|
||||
)(input)
|
||||
|
||||
}
|
||||
|
||||
fn list_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
map(
|
||||
delimited(
|
||||
@ -230,7 +247,7 @@ fn qualified_identifier(input: Span) -> ParseResult<QualifiedName> {
|
||||
}
|
||||
|
||||
fn identifier(input: Span) -> ParseResult<Span> {
|
||||
recognize(tuple((alt((tag("_"), alpha1)), alphanumeric0)))(input)
|
||||
recognize(pair(alt((tag("_"), alpha1)), take_while(|ch: char| { is_alphanumeric(ch as u8) || ch == '_'})))(input)
|
||||
}
|
||||
|
||||
fn bool_literal(input: Span) -> ParseResult<ExpressionKind> {
|
||||
@ -335,6 +352,40 @@ fn parse_hex(digits: &str) -> Result<u64, &'static str> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BinopSequence {
|
||||
first: ExpressionKind,
|
||||
rest: Vec<(BinOp, ExpressionKind)>,
|
||||
}
|
||||
|
||||
impl BinopSequence {
|
||||
fn do_precedence(self, store: &mut IdStore<ASTItem>) -> ExpressionKind {
|
||||
fn helper(
|
||||
precedence: i32,
|
||||
lhs: ExpressionKind,
|
||||
rest: &mut Vec<(BinOp, ExpressionKind)>,
|
||||
store: &mut IdStore<ASTItem>,
|
||||
) -> Expression {
|
||||
let mut lhs = Expression::new(store.fresh(), lhs);
|
||||
while let Some((next_op, next_rhs)) = rest.pop() {
|
||||
let new_precedence = next_op.get_precedence();
|
||||
if precedence >= new_precedence {
|
||||
rest.push((next_op, next_rhs));
|
||||
break;
|
||||
}
|
||||
let rhs = helper(new_precedence, next_rhs, rest, store);
|
||||
lhs = Expression::new(
|
||||
store.fresh(),
|
||||
ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)),
|
||||
);
|
||||
}
|
||||
lhs
|
||||
}
|
||||
let mut as_stack = self.rest.into_iter().rev().collect();
|
||||
helper(BinOp::min_precedence(), self.first, &mut as_stack, store).kind
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
@ -179,7 +179,7 @@ fn binexps() {
|
||||
use ExpressionKind::*;
|
||||
use StatementKind::Expression;
|
||||
|
||||
assert_expr!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1))));
|
||||
assert_expr_comb!("0xf_f+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1))));
|
||||
assert_ast!(
|
||||
"3; 4; 4.3",
|
||||
vec![
|
||||
@ -189,16 +189,16 @@ fn binexps() {
|
||||
]
|
||||
);
|
||||
|
||||
assert_expr!(
|
||||
assert_expr_comb!(
|
||||
"1 + 2 * 3",
|
||||
binop("+", expr(NatLiteral(1)), binop("*", expr(NatLiteral(2)), expr(NatLiteral(3))))
|
||||
);
|
||||
assert_expr!(
|
||||
assert_expr_comb!(
|
||||
"1 * 2 + 3",
|
||||
binop("+", binop("*", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3)))
|
||||
);
|
||||
assert_expr!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2))));
|
||||
assert_expr!(
|
||||
assert_expr_comb!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2))));
|
||||
assert_expr_comb!(
|
||||
"1 + 2 * 3 + 4",
|
||||
binop(
|
||||
"+",
|
||||
@ -206,12 +206,12 @@ fn binexps() {
|
||||
expr(NatLiteral(4))
|
||||
)
|
||||
);
|
||||
assert_expr!(
|
||||
assert_expr_comb!(
|
||||
"(1 + 2) * 3",
|
||||
binop("*", binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3)))
|
||||
);
|
||||
assert_expr!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2))));
|
||||
assert_expr!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.))));
|
||||
assert_expr_comb!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2))));
|
||||
assert_expr_comb!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -230,9 +230,9 @@ fn prefix_exps() {
|
||||
fn operators() {
|
||||
use ExpressionKind::*;
|
||||
|
||||
assert_expr!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||
assert_expr!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||
assert_expr!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||
assert_expr_comb!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||
assert_expr_comb!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||
assert_expr_comb!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -273,12 +273,12 @@ fn accessors() {
|
||||
fn tuples() {
|
||||
use ExpressionKind::*;
|
||||
|
||||
assert_expr!("()", expr(TupleLiteral(vec![])));
|
||||
assert_expr!(
|
||||
assert_expr_comb!("()", expr(TupleLiteral(vec![])));
|
||||
assert_expr_comb!(
|
||||
r#"("hella", 34)"#,
|
||||
expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))]))
|
||||
);
|
||||
assert_expr!(
|
||||
assert_expr_comb!(
|
||||
r#"(1+2, "slough")"#,
|
||||
expr(TupleLiteral(vec![
|
||||
binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))),
|
||||
@ -291,11 +291,11 @@ fn tuples() {
|
||||
fn identifiers() {
|
||||
use ExpressionKind::*;
|
||||
|
||||
assert_expr!("a", expr(Value(qn!(a))));
|
||||
assert_expr!("some_value", expr(Value(qn!(some_value))));
|
||||
assert_expr!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma))));
|
||||
assert_expr!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
||||
assert_expr!("None", expr(Value(qn!(None))));
|
||||
assert_expr_comb!("a", expr(Value(qn!(a))));
|
||||
assert_expr_comb!("some_value", expr(Value(qn!(some_value))));
|
||||
assert_expr_comb!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma))));
|
||||
assert_expr_comb!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
||||
assert_expr_comb!("None", expr(Value(qn!(None))));
|
||||
assert_expr!(
|
||||
"thing::item::call()",
|
||||
expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] })
|
||||
@ -1387,7 +1387,7 @@ fn comments() {
|
||||
use ExpressionKind::*;
|
||||
|
||||
let source = "1 + /* hella /* bro */ */ 2";
|
||||
assert_expr!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))));
|
||||
assert_expr_comb!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))));
|
||||
|
||||
//TODO make sure this error message makes sense
|
||||
let source = "1 + /* hella /* bro */ 2";
|
||||
|
Loading…
Reference in New Issue
Block a user