Extended exprs
This commit is contained in:
parent
7a9e43bf8e
commit
b7b4e75f01
@ -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,
|
||||
|
@ -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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user