if expression

This commit is contained in:
greg 2020-03-09 03:45:03 -07:00
parent dd9a1b8a2e
commit 744ba2fc74

View File

@ -6,7 +6,7 @@ use std::str::FromStr;
use nom::IResult;
use nom::character::complete::{one_of, space0, alphanumeric0};
use nom::bytes::complete::{tag, take, take_while, take_while1, take_until};
use nom::combinator::{cut, map, map_res, value, opt, verify};
use nom::combinator::{cut, cond, map, map_res, value, opt, verify};
use nom::multi::{separated_list, separated_nonempty_list, many1, many0};
use nom::error::{context, ParseError, VerboseError};
use nom::branch::alt;
@ -51,10 +51,15 @@ fn identifier(text: &str) -> ParseResult<Rc<String>> {
}
const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|";
fn parse_binop(text: &str) -> ParseResult<BinOp> {
let (text, op): (_, Vec<char>) = context("Binop", many1(one_of(OPERATOR_CHARS)))(text)?;
let sigil: String = op.into_iter().collect();
Ok((text, BinOp::from_sigil(&sigil)))
fn operator(text: &str) -> ParseResult<Vec<char>> {
many1(one_of(OPERATOR_CHARS))(text)
}
fn binop(text: &str) -> ParseResult<BinOp> {
context("Binop", map(
operator,
|op| BinOp::from_sigil(&op.into_iter().collect::<String>())
))(text)
}
fn bool_literal(text: &str) -> ParseResult<ExpressionKind> {
@ -68,7 +73,7 @@ fn bool_literal(text: &str) -> ParseResult<ExpressionKind> {
fn number_literal(text: &str) -> ParseResult<ExpressionKind> {
let num_lit = many1(alt((
map(one_of("1234567890"), |s: char| Some(s)),
map(nom::character::complete::char('_'), |_| None)
value(None, nom::character::complete::char('_')),
)));
let (text, n) = map_res(num_lit,
@ -143,10 +148,10 @@ fn primary_expr(text: &str) -> ParseResult<ExpressionKind> {
// primary := literal | paren_expr | if_expr | for_expr | while_expr | identifier_expr | lambda_expr | anonymous_struct | list_expr
alt((
if_expr,
literal,
paren_expr,
identifier_expr,
//if_expr,
))(text)
}
@ -160,19 +165,21 @@ fn invocation_argument(text: &str) -> ParseResult<InvocationArgument> {
))(text)
}
/*
fn if_expr(text: &str) -> ParseResult<ExpressionKind> {
let p = preceded(tag("if"), pair(discriminator, if_expr_body));
let p = preceded(tag("if"), pair(ws(discriminator), ws(if_expr_body)));
map(p, |(discriminator, body)| {
let discriminator = discriminator.map(Box::new);
let body = Box::new(body);
ExpressionKind::IfExpression { discriminator, body }
}) (text)
let expr = IfExpression {
discriminator: Option<Box<Expression>>,
body: Box<IfExpressionBody>,
};
}
*/
fn discriminator(text: &str) -> ParseResult<Option<Expression>> {
use nom::combinator::verify;
cond(text.chars().next().map(|c| c != '{').unwrap_or(true),
expression
)(text)
}
fn if_expr_body(text: &str) -> ParseResult<IfExpressionBody> {
alt((
@ -244,7 +251,38 @@ fn pattern_literal(text: &str) -> ParseResult<PatternLiteral> {
}
fn cond_block(text: &str) -> ParseResult<IfExpressionBody> {
unimplemented!()
use nom::character::complete::char;
//TODO maybe change this bit of syntax
let comma_or_delimitor = alt((value((), char(',')), statement_sep));
let p = delimited(char('{'),
separated_nonempty_list(comma_or_delimitor, cond_arm),
char('}'));
map(p, IfExpressionBody::CondList)(text)
}
fn cond_arm(text: &str) -> ParseResult<ConditionArm> {
let variant_1 = map(
tuple((condition, guard, tag("then"), expr_or_block)),
|(condition, guard, _, body)| ConditionArm { condition, guard, body }
);
let variant_2 = map(
preceded(tag("else"), expr_or_block),
|body| ConditionArm { condition: Condition::Else, guard: None, body }
);
alt((variant_1, variant_2))(text)
}
fn condition(text: &str) -> ParseResult<Condition> {
alt((
map(preceded(tag("is"), pattern), Condition::Pattern),
map(tuple((binop, expression)), |(op, expr)|
Condition::TruncatedOp(op, expr)),
map(expression, Condition::Expression),
))(text)
}
fn guard(text: &str) -> ParseResult<Option<Expression>> {
opt(preceded(tag("if"), expression))(text)
}
fn expr_or_block(text: &str) -> ParseResult<Block> {
@ -294,7 +332,7 @@ fn precedence_expr(text: &str) -> ParseResult<ExpressionKind> {
let (mut outer_rest, mut lhs) = prefix_expr(input)?;
loop {
let (rest, _) = space0(outer_rest)?;
let (rest, maybe_binop) = opt(parse_binop)(rest)?;
let (rest, maybe_binop) = opt(binop)(rest)?;
let (new_precedence, binop) = match maybe_binop {
Some(binop) => (binop.precedence(), binop),
None => break,