if expression

This commit is contained in:
greg 2020-03-09 03:45:03 -07:00
parent dd9a1b8a2e
commit 744ba2fc74
1 changed files with 57 additions and 19 deletions

View File

@ -6,7 +6,7 @@ use std::str::FromStr;
use nom::IResult; use nom::IResult;
use nom::character::complete::{one_of, space0, alphanumeric0}; use nom::character::complete::{one_of, space0, alphanumeric0};
use nom::bytes::complete::{tag, take, take_while, take_while1, take_until}; 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::multi::{separated_list, separated_nonempty_list, many1, many0};
use nom::error::{context, ParseError, VerboseError}; use nom::error::{context, ParseError, VerboseError};
use nom::branch::alt; use nom::branch::alt;
@ -51,10 +51,15 @@ fn identifier(text: &str) -> ParseResult<Rc<String>> {
} }
const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|"; const OPERATOR_CHARS: &'static str = "~`!@#$%^&*-+=<>?/|";
fn parse_binop(text: &str) -> ParseResult<BinOp> { fn operator(text: &str) -> ParseResult<Vec<char>> {
let (text, op): (_, Vec<char>) = context("Binop", many1(one_of(OPERATOR_CHARS)))(text)?; many1(one_of(OPERATOR_CHARS))(text)
let sigil: String = op.into_iter().collect(); }
Ok((text, BinOp::from_sigil(&sigil)))
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> { 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> { fn number_literal(text: &str) -> ParseResult<ExpressionKind> {
let num_lit = many1(alt(( let num_lit = many1(alt((
map(one_of("1234567890"), |s: char| Some(s)), 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, 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 // primary := literal | paren_expr | if_expr | for_expr | while_expr | identifier_expr | lambda_expr | anonymous_struct | list_expr
alt(( alt((
if_expr,
literal, literal,
paren_expr, paren_expr,
identifier_expr, identifier_expr,
//if_expr,
))(text) ))(text)
} }
@ -160,19 +165,21 @@ fn invocation_argument(text: &str) -> ParseResult<InvocationArgument> {
))(text) ))(text)
} }
/*
fn if_expr(text: &str) -> ParseResult<ExpressionKind> { 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)| { map(p, |(discriminator, body)| {
let discriminator = discriminator.map(Box::new);
})(text) let body = Box::new(body);
ExpressionKind::IfExpression { discriminator, body }
let expr = IfExpression { }) (text)
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> { fn if_expr_body(text: &str) -> ParseResult<IfExpressionBody> {
alt(( alt((
@ -244,7 +251,38 @@ fn pattern_literal(text: &str) -> ParseResult<PatternLiteral> {
} }
fn cond_block(text: &str) -> ParseResult<IfExpressionBody> { 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> { 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)?; let (mut outer_rest, mut lhs) = prefix_expr(input)?;
loop { loop {
let (rest, _) = space0(outer_rest)?; 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 { let (new_precedence, binop) = match maybe_binop {
Some(binop) => (binop.precedence(), binop), Some(binop) => (binop.precedence(), binop),
None => break, None => break,