if exprs
This commit is contained in:
parent
ec51659452
commit
721a499384
@ -300,6 +300,16 @@ fn expression_no_struct(input: Span) -> ParseResult<Expression> {
|
|||||||
})(input)
|
})(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expr_or_block(input: Span) -> ParseResult<Block> {
|
||||||
|
let (input, pos) = position(input)?;
|
||||||
|
let id = fresh_id(&input);
|
||||||
|
let location = pos.location_offset().into();
|
||||||
|
alt((
|
||||||
|
block,
|
||||||
|
map(expression, move |expr| Statement { id, location, kind: StatementKind::Expression(expr) }.into()),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
fn type_anno(input: Span) -> ParseResult<TypeIdentifier> {
|
fn type_anno(input: Span) -> ParseResult<TypeIdentifier> {
|
||||||
preceded(tok(char(':')), type_identifier)(input)
|
preceded(tok(char(':')), type_identifier)(input)
|
||||||
}
|
}
|
||||||
@ -444,11 +454,13 @@ fn primary_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<Expressio
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> {
|
fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> {
|
||||||
|
println!("PRIM EXPR: {}", input.fragment());
|
||||||
context(
|
context(
|
||||||
"primary-expr-no-struct",
|
"primary-expr-no-struct",
|
||||||
alt((
|
alt((
|
||||||
while_expr,
|
while_expr,
|
||||||
for_expr,
|
for_expr,
|
||||||
|
if_expr,
|
||||||
list_expr,
|
list_expr,
|
||||||
paren_expr,
|
paren_expr,
|
||||||
string_literal,
|
string_literal,
|
||||||
@ -482,10 +494,119 @@ fn while_expr(input: Span) -> ParseResult<ExpressionKind> {
|
|||||||
})(input)
|
})(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn if_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||||
|
fn else_case(input: Span) -> ParseResult<Option<Block>> {
|
||||||
|
opt(preceded(kw("else"), expr_or_block))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cond_block(input: Span) -> ParseResult<IfExpressionBody> {
|
||||||
|
map(block_template(cond_arm), IfExpressionBody::CondList)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cond_arm(input: Span) -> ParseResult<ConditionArm> {
|
||||||
|
let condition = map(preceded(kw("is"), pattern), Condition::Pattern);
|
||||||
|
let condition_guard = opt(preceded(kw("if"), expression));
|
||||||
|
alt((
|
||||||
|
map(preceded(kw("else"), expr_or_block), |body| ConditionArm {
|
||||||
|
condition: Condition::Else,
|
||||||
|
guard: None,
|
||||||
|
body,
|
||||||
|
}),
|
||||||
|
map(
|
||||||
|
tuple((condition, condition_guard, kw("then"), expr_or_block)),
|
||||||
|
|(condition, guard, _, body)| ConditionArm { condition, guard, body },
|
||||||
|
),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_pattern_match(input: Span) -> ParseResult<IfExpressionBody> {
|
||||||
|
map(
|
||||||
|
tuple((preceded(kw("is"), pattern), preceded(kw("then"), pair(expr_or_block, else_case)))),
|
||||||
|
|(pattern, (then_case, else_case))| IfExpressionBody::SimplePatternMatch {
|
||||||
|
pattern,
|
||||||
|
then_case,
|
||||||
|
else_case,
|
||||||
|
},
|
||||||
|
)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_conditional(input: Span) -> ParseResult<IfExpressionBody> {
|
||||||
|
map(preceded(kw("then"), pair(expr_or_block, else_case)), |(then_case, else_case)| {
|
||||||
|
IfExpressionBody::SimpleConditional { then_case, else_case }
|
||||||
|
})(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_expr_body(input: Span) -> ParseResult<IfExpressionBody> {
|
||||||
|
alt((cond_block, simple_pattern_match, simple_conditional))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
map(preceded(kw("if"), pair(opt(expression_no_struct), if_expr_body)), |(discriminator, body)| {
|
||||||
|
ExpressionKind::IfExpression { discriminator: discriminator.map(Box::new), body: Box::new(body) }
|
||||||
|
})(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pattern(input: Span) -> ParseResult<Pattern> {
|
||||||
|
alt((
|
||||||
|
map(
|
||||||
|
delimited(tok(char('(')), separated_list1(tok(char(',')), pattern), tok(char(')'))),
|
||||||
|
Pattern::TuplePattern,
|
||||||
|
),
|
||||||
|
simple_pattern,
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_pattern(input: Span) -> ParseResult<Pattern> {
|
||||||
|
fn record_pattern_entry(input: Span) -> ParseResult<(Rc<String>, Pattern)> {
|
||||||
|
let id = fresh_id(&input);
|
||||||
|
alt((
|
||||||
|
map(separated_pair(identifier, tok(char(':')), pattern), |(ident, pat)| {
|
||||||
|
(rc_string(ident.fragment()), pat)
|
||||||
|
}),
|
||||||
|
map(identifier, move |ident| {
|
||||||
|
let qn = QualifiedName { id, components: vec![rc_string(ident.fragment())] };
|
||||||
|
(rc_string(ident.fragment()), Pattern::VarOrName(qn))
|
||||||
|
}),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
alt((
|
||||||
|
pattern_literal,
|
||||||
|
map(
|
||||||
|
pair(
|
||||||
|
qualified_identifier,
|
||||||
|
delimited(tok(char('(')), separated_list0(tok(char(',')), pattern), tok(char(')'))),
|
||||||
|
),
|
||||||
|
|(qn, members)| Pattern::TupleStruct(qn, members),
|
||||||
|
),
|
||||||
|
map(
|
||||||
|
pair(
|
||||||
|
qualified_identifier,
|
||||||
|
delimited(
|
||||||
|
tok(char('{')),
|
||||||
|
separated_list0(tok(char(',')), record_pattern_entry),
|
||||||
|
tok(char('}')),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|(qn, members)| Pattern::Record(qn, members),
|
||||||
|
),
|
||||||
|
map(qualified_identifier, Pattern::VarOrName),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pattern_literal(input: Span) -> ParseResult<Pattern> {
|
||||||
|
alt((
|
||||||
|
value(Pattern::Ignored, kw("_")),
|
||||||
|
value(Pattern::Literal(PatternLiteral::BoolPattern(true)), kw("true")),
|
||||||
|
value(Pattern::Literal(PatternLiteral::BoolPattern(false)), kw("false")),
|
||||||
|
map(tok(bare_string_literal), |s| Pattern::Literal(PatternLiteral::StringPattern(Rc::new(s)))),
|
||||||
|
map(pair(opt(tok(char('-'))), alt((float_literal, number_literal))), |(sign, num)| {
|
||||||
|
Pattern::Literal(PatternLiteral::NumPattern { neg: sign.is_some(), num })
|
||||||
|
}),
|
||||||
|
))(input)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_expr(input: Span) -> ParseResult<ExpressionKind> {
|
fn for_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||||
println!("IN FOR EXPR: {}", input.fragment());
|
|
||||||
fn for_enumerators(input: Span) -> ParseResult<Vec<Enumerator>> {
|
fn for_enumerators(input: Span) -> ParseResult<Vec<Enumerator>> {
|
||||||
println!("NEUMS: {}", input.fragment());
|
|
||||||
alt((
|
alt((
|
||||||
delimited(tok(char('{')), separated_list0(tok(char(',')), enumerator), tok(char('}'))),
|
delimited(tok(char('{')), separated_list0(tok(char(',')), enumerator), tok(char('}'))),
|
||||||
map(enumerator, |enumerator| vec![enumerator]),
|
map(enumerator, |enumerator| vec![enumerator]),
|
||||||
@ -543,6 +664,7 @@ fn string_literal(input: Span) -> ParseResult<ExpressionKind> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bare_string_literal(input: Span) -> ParseResult<String> {
|
fn bare_string_literal(input: Span) -> ParseResult<String> {
|
||||||
|
println!("BARE STRING: {}", input.fragment());
|
||||||
let string_escape_transforms =
|
let string_escape_transforms =
|
||||||
alt((value("\\", tag("\\")), value("\"", tag("\"")), value("\n", tag("n")), value("\t", tag("t"))));
|
alt((value("\\", tag("\\")), value("\"", tag("\"")), value("\n", tag("n")), value("\t", tag("t"))));
|
||||||
alt((
|
alt((
|
||||||
|
@ -134,7 +134,7 @@ macro_rules! assert_expr {
|
|||||||
macro_rules! assert_expr_comb {
|
macro_rules! assert_expr_comb {
|
||||||
($input:expr, $correct:expr) => {
|
($input:expr, $correct:expr) => {
|
||||||
let mut parser = Parser::new();
|
let mut parser = Parser::new();
|
||||||
let expr = parser.expression_comb($input);
|
let expr = parser.expression_comb($input.trim_start());
|
||||||
if expr.is_err() {
|
if expr.is_err() {
|
||||||
println!("Expression parse error: {}", expr.unwrap_err().msg);
|
println!("Expression parse error: {}", expr.unwrap_err().msg);
|
||||||
panic!();
|
panic!();
|
||||||
@ -1097,7 +1097,7 @@ fn imports() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn if_exprs() {
|
fn if_exprs() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
"if a() then { tuah(); }",
|
"if a() then { tuah(); }",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Call { f: bx(expr(Value(qn!(a)))), arguments: vec![] }))),
|
discriminator: Some(bx(expr(Call { f: bx(expr(Value(qn!(a)))), arguments: vec![] }))),
|
||||||
@ -1108,7 +1108,8 @@ fn if_exprs() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
//TODO add tests for named expressions
|
||||||
|
assert_expr_comb!(
|
||||||
"if a then b else c",
|
"if a then b else c",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(a))))),
|
discriminator: Some(bx(expr(Value(qn!(a))))),
|
||||||
@ -1119,9 +1120,8 @@ fn if_exprs() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
r#"
|
r#"if true then {
|
||||||
if true then {
|
|
||||||
let a = 10
|
let a = 10
|
||||||
b
|
b
|
||||||
} else {
|
} else {
|
||||||
@ -1151,7 +1151,7 @@ fn pattern_matching() {
|
|||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
|
|
||||||
for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] {
|
for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] {
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
item,
|
item,
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1164,7 +1164,7 @@ fn pattern_matching() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
"if x is Something { a, b: x } then { 4 } else { 9 }",
|
"if x is Something { a, b: x } then { 4 } else { 9 }",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1179,7 +1179,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
"if x is -1 then 1 else 2",
|
"if x is -1 then 1 else 2",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1191,7 +1191,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
"if x is true then 1 else 2",
|
"if x is true then 1 else 2",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1203,7 +1203,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
"if x { is 1 then 5; else 20 }",
|
"if x { is 1 then 5; else 20 }",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1225,7 +1225,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr_comb!(
|
||||||
r#"if x is "gnosticism" then 1 else 2"#,
|
r#"if x is "gnosticism" then 1 else 2"#,
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1237,7 +1237,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr! {
|
assert_expr_comb! {
|
||||||
r#"
|
r#"
|
||||||
if (45, "panda", false, 2.2) {
|
if (45, "panda", false, 2.2) {
|
||||||
is (49, "pablo", _, 28.4) then "no"
|
is (49, "pablo", _, 28.4) then "no"
|
||||||
|
Loading…
Reference in New Issue
Block a user