Extended exprs

This commit is contained in:
Greg Shuflin 2021-11-18 14:38:29 -08:00
parent 7a9e43bf8e
commit b7b4e75f01
2 changed files with 85 additions and 13 deletions

View File

@ -176,10 +176,82 @@ fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
)(input)
}
fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
context("extended-expr", primary_expr)(input)
#[derive(Debug)]
enum ExtendedPart<'a> {
Index(Vec<Expression>),
Call(Vec<InvocationArgument>),
Accessor(&'a str),
}
fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
let (s, (primary, parts)) = context("extended-expr",
pair(primary_expr, many0(extended_expr_part)))(input)?;
let mut expression = Expression::new(fresh_id(&s), primary);
for part in parts.into_iter() {
let kind = match part {
ExtendedPart::Index(indexers) => {
ExpressionKind::Index { indexee: Box::new(expression), indexers }
},
ExtendedPart::Call(arguments) => {
ExpressionKind::Call { f: Box::new(expression), arguments }
}
ExtendedPart::Accessor(name) => {
let name = rc_string(name);
ExpressionKind::Access { name, expr: Box::new(expression) }
},
};
expression = Expression::new(fresh_id(&s), kind);
}
Ok((s, expression.kind))
}
fn extended_expr_part(input: Span) -> ParseResult<ExtendedPart> {
fn index_part(input: Span) -> ParseResult<Vec<Expression>> {
delimited(
tok(char('[')),
separated_list1(tok(char(',')), expression),
tok(char(']')),
)(input)
}
fn call_part(input: Span) -> ParseResult<Vec<InvocationArgument>> {
delimited(
tok(char('(')),
separated_list0(tok(char(',')), invocation_argument),
tok(char(')')),
)(input)
}
fn access_part(input: Span) -> ParseResult<&str> {
preceded(
tok(char('.')),
map(identifier, |item| *item.fragment())
)(input)
}
alt((
map(index_part, ExtendedPart::Index),
map(call_part, ExtendedPart::Call),
map(access_part, ExtendedPart::Accessor)
))(input)
}
//TODO this shouldn't be an expression b/c type annotations disallowed here
fn invocation_argument(input: Span) -> ParseResult<InvocationArgument> {
alt((
map(tok(char('_')), |_| InvocationArgument::Ignored),
map(tuple((
tok(identifier),
tok(char('=')),
expression,
)), |(name, _, expr)| InvocationArgument::Keyword { name: rc_string(name.fragment()), expr }),
map(expression, InvocationArgument::Positional),
))(input)
}
fn primary_expr(input: Span) -> ParseResult<ExpressionKind> {
context("primary-expr", alt((
list_expr, paren_expr,

View File

@ -222,8 +222,8 @@ fn prefix_exps() {
assert_expr_comb!("-0.2", prefixop("-", expr(FloatLiteral(0.2))));
assert_expr_comb!("!3", prefixop("!", expr(NatLiteral(3))));
assert_expr_comb!("!t", prefixop("!", expr(Value(qn!(t)))));
assert_expr!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b))))));
assert_expr!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b)))));
assert_expr_comb!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b))))));
assert_expr_comb!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b)))));
}
#[test]
@ -239,15 +239,15 @@ fn operators() {
fn accessors() {
use ExpressionKind::*;
assert_expr!("a.b", expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) }));
assert_expr!(
assert_expr_comb!("a.b", expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) }));
assert_expr_comb!(
"a.b.c",
expr(Access {
name: rc("c"),
expr: bx(expr(Access { name: rc("b"), expr: bx(expr(Value(qn!(a)))) }))
})
);
assert_expr!(
assert_expr_comb!(
"a.b.c(3)",
expr(Call {
f: bx(expr(Access {
@ -257,7 +257,7 @@ fn accessors() {
arguments: vec![InvocationArgument::Positional(expr(NatLiteral(3)))],
})
);
assert_expr!(
assert_expr_comb!(
"a.b().c",
expr(Access {
name: rc("c"),
@ -296,7 +296,7 @@ fn identifiers() {
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!(
assert_expr_comb!(
"thing::item::call()",
expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] })
);
@ -324,14 +324,14 @@ fn named_struct() {
#[test]
fn index() {
use ExpressionKind::*;
assert_expr!(
assert_expr_comb!(
"armok[b,c]",
expr(Index {
indexee: bx(expr(Value(qn!(armok)))),
indexers: vec![expr(Value(qn!(b))), expr(Value(qn!(c)))]
})
);
assert_expr!(
assert_expr_comb!(
"a[b,c][1]",
expr(Index {
indexee: bx(expr(Index {
@ -341,7 +341,7 @@ fn index() {
indexers: vec![expr(NatLiteral(1))]
})
);
assert_expr!(
assert_expr_comb!(
"perspicacity()[a]",
expr(Index {
indexee: bx(expr(Call { f: bx(expr(Value(qn!(perspicacity)))), arguments: vec![] })),
@ -353,7 +353,7 @@ fn index() {
let b = expr(Index { indexee: bx(a), indexers: vec![expr(Value(qn!(b)))] });
let c = expr(Call { f: bx(b), arguments: vec![] });
let d = expr(Index { indexee: bx(c), indexers: vec![expr(Value(qn!(d)))] });
assert_expr!("a()[b]()[d]", d);
assert_expr_comb!("a()[b]()[d]", d);
assert_fail_expr!("a[]", "Empty index expressions are not allowed");
}