Named structs
This commit is contained in:
parent
58a1782162
commit
7e2b95593f
@ -4,16 +4,14 @@ use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::{escaped_transform, tag, take_till, take_while},
|
||||
character::{
|
||||
complete::{
|
||||
alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0, space1,
|
||||
},
|
||||
complete::{alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space1},
|
||||
is_alphanumeric,
|
||||
},
|
||||
combinator::{map, not, opt, peek, recognize, value},
|
||||
combinator::{cond, flat_map, map, not, opt, peek, recognize, value},
|
||||
error::{context, ParseError, VerboseError},
|
||||
multi::{fold_many1, many0, many1, separated_list0, separated_list1},
|
||||
sequence::{delimited, pair, preceded, tuple},
|
||||
Err, IResult, Parser,
|
||||
multi::{many0, many1, separated_list0, separated_list1},
|
||||
sequence::{delimited, pair, preceded, separated_pair, tuple},
|
||||
IResult, Parser,
|
||||
};
|
||||
use nom_locate::{position, LocatedSpan};
|
||||
|
||||
@ -99,8 +97,9 @@ pub fn program(input: Span) -> ParseResult<AST> {
|
||||
Ok((rest, ast))
|
||||
}
|
||||
|
||||
fn block_template<'a, O>(input_parser: impl Parser<Span<'a>, O, VerboseError<Span<'a>>>) -> impl FnMut(Span<'a>) ->
|
||||
IResult<Span<'a>, Vec<O>, VerboseError<Span<'a>>> {
|
||||
fn block_template<'a, O>(
|
||||
input_parser: impl Parser<Span<'a>, O, VerboseError<Span<'a>>>,
|
||||
) -> impl FnMut(Span<'a>) -> IResult<Span<'a>, Vec<O>, VerboseError<Span<'a>>> {
|
||||
map(
|
||||
delimited(
|
||||
tok(char('{')),
|
||||
@ -286,9 +285,20 @@ fn module(input: Span) -> ParseResult<Declaration> {
|
||||
|
||||
pub fn expression(input: Span) -> ParseResult<Expression> {
|
||||
let id = fresh_id(&input);
|
||||
map(pair(expression_kind, opt(type_anno)), move |(kind, type_anno)| Expression { id, type_anno, kind })(
|
||||
input,
|
||||
)
|
||||
map(pair(expression_kind(true), opt(type_anno)), move |(kind, type_anno)| Expression {
|
||||
id,
|
||||
type_anno,
|
||||
kind,
|
||||
})(input)
|
||||
}
|
||||
|
||||
fn expression_no_struct(input: Span) -> ParseResult<Expression> {
|
||||
let id = fresh_id(&input);
|
||||
map(pair(expression_kind(false), opt(type_anno)), move |(kind, type_anno)| Expression {
|
||||
id,
|
||||
type_anno,
|
||||
kind,
|
||||
})(input)
|
||||
}
|
||||
|
||||
fn type_anno(input: Span) -> ParseResult<TypeIdentifier> {
|
||||
@ -316,23 +326,22 @@ fn type_params(input: Span) -> ParseResult<Vec<TypeIdentifier>> {
|
||||
delimited(tok(char('<')), separated_list1(tok(char(',')), type_identifier), tok(char('>')))(input)
|
||||
}
|
||||
|
||||
pub fn expression_kind(input: Span) -> ParseResult<ExpressionKind> {
|
||||
context("expression-kind", precedence_expr)(input)
|
||||
pub fn expression_kind(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
|
||||
move |input: Span| context("expression-kind", precedence_expr(allow_struct))(input)
|
||||
}
|
||||
|
||||
fn precedence_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
fn precedence_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
|
||||
move |input: Span| {
|
||||
let handle = input.extra.clone();
|
||||
let precedence_continuation = pair(operator, prefix_expr(allow_struct));
|
||||
map(
|
||||
pair(prefix_expr, many0(precedence_continuation)),
|
||||
pair(prefix_expr(allow_struct), many0(precedence_continuation)),
|
||||
move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| {
|
||||
let mut handle_ref = handle.borrow_mut();
|
||||
BinopSequence { first, rest }.do_precedence(&mut handle_ref)
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> {
|
||||
pair(operator, prefix_expr)(input)
|
||||
}
|
||||
}
|
||||
|
||||
fn operator(input: Span) -> ParseResult<BinOp> {
|
||||
@ -346,11 +355,12 @@ fn prefix_op(input: Span) -> ParseResult<PrefixOp> {
|
||||
tok(map(recognize(one_of("+-!")), |sigil: Span| PrefixOp::from_sigil(sigil.fragment())))(input)
|
||||
}
|
||||
|
||||
fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
fn prefix_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
|
||||
move |input: Span| {
|
||||
let handle = input.extra.clone();
|
||||
context(
|
||||
"prefix-expr",
|
||||
map(pair(opt(prefix_op), extended_expr), move |(prefix, expr)| {
|
||||
map(pair(opt(prefix_op), extended_expr(allow_struct)), move |(prefix, expr)| {
|
||||
if let Some(prefix) = prefix {
|
||||
let expr = Expression::new(fresh_id_rc(&handle), expr);
|
||||
ExpressionKind::PrefixExp(prefix, Box::new(expr))
|
||||
@ -359,6 +369,7 @@ fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
}
|
||||
}),
|
||||
)(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -368,9 +379,10 @@ enum ExtendedPart<'a> {
|
||||
Accessor(&'a str),
|
||||
}
|
||||
|
||||
fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
fn extended_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
|
||||
move |input: Span| {
|
||||
let (s, (primary, parts)) =
|
||||
context("extended-expr", pair(primary_expr, many0(extended_expr_part)))(input)?;
|
||||
context("extended-expr", pair(primary_expr(allow_struct), many0(extended_expr_part)))(input)?;
|
||||
|
||||
let mut expression = Expression::new(fresh_id(&s), primary);
|
||||
for part in parts.into_iter() {
|
||||
@ -387,6 +399,7 @@ fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
}
|
||||
|
||||
Ok((s, expression.kind))
|
||||
}
|
||||
}
|
||||
|
||||
fn extended_expr_part(input: Span) -> ParseResult<ExtendedPart> {
|
||||
@ -420,13 +433,14 @@ fn invocation_argument(input: Span) -> ParseResult<InvocationArgument> {
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn primary_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
context(
|
||||
"primary-expr",
|
||||
alt((
|
||||
primary_expr_no_struct,
|
||||
)),
|
||||
)(input)
|
||||
fn primary_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
|
||||
move |input: Span| {
|
||||
if allow_struct {
|
||||
context("primary-expr", alt((named_struct, primary_expr_no_struct)))(input)
|
||||
} else {
|
||||
context("primary-expr", primary_expr_no_struct)(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> {
|
||||
@ -445,12 +459,25 @@ fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> {
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn named_struct(input: Span) -> ParseResult<ExpressionKind> {
|
||||
map(pair(qualified_identifier, record_block), |(name, fields)| ExpressionKind::NamedStruct {
|
||||
name,
|
||||
fields,
|
||||
})(input)
|
||||
}
|
||||
|
||||
//TODO support anonymous structs and Elm-style update syntax for structs
|
||||
fn record_block(input: Span) -> ParseResult<Vec<(Rc<String>, Expression)>> {
|
||||
let record_entry =
|
||||
separated_pair(map(tok(identifier), |span| rc_string(span.fragment())), tok(char(':')), expression);
|
||||
|
||||
delimited(tok(char('{')), separated_list0(tok(char(',')), record_entry), tok(char('}')))(input)
|
||||
}
|
||||
|
||||
fn while_expr(input: Span) -> ParseResult<ExpressionKind> {
|
||||
let id = fresh_id(&input);
|
||||
map(preceded(kw("while"), pair(opt(expression), block)),
|
||||
move |(condition, body)| ExpressionKind::WhileExpression {
|
||||
condition: condition.map(Box::new),
|
||||
body,
|
||||
map(preceded(kw("while"), pair(opt(expression_no_struct), block)), move |(condition, body)| {
|
||||
ExpressionKind::WhileExpression { condition: condition.map(Box::new), body }
|
||||
})(input)
|
||||
}
|
||||
|
||||
@ -695,12 +722,15 @@ mod test {
|
||||
#[test]
|
||||
fn combinator_test2() {
|
||||
for s in [" 15", " 0b1111", " 1_5_", "0XF__", "0Xf"].iter() {
|
||||
assert_eq!(span!(expression_kind, s).unwrap().1, ExpressionKind::NatLiteral(15));
|
||||
assert_eq!(span!(expression_kind(true), s).unwrap().1, ExpressionKind::NatLiteral(15));
|
||||
}
|
||||
|
||||
assert_eq!(span!(expression_kind, " /*gay*/ true").unwrap().1, ExpressionKind::BoolLiteral(true));
|
||||
assert_eq!(
|
||||
span!(expression_kind, " /*yolo*/ barnaby").unwrap().1,
|
||||
span!(expression_kind(true), " /*gay*/ true").unwrap().1,
|
||||
ExpressionKind::BoolLiteral(true)
|
||||
);
|
||||
assert_eq!(
|
||||
span!(expression_kind(true), " /*yolo*/ barnaby").unwrap().1,
|
||||
ExpressionKind::Value(qn!(barnaby))
|
||||
);
|
||||
}
|
||||
|
@ -318,14 +318,14 @@ fn identifiers() {
|
||||
#[test]
|
||||
fn named_struct() {
|
||||
use ExpressionKind::*;
|
||||
assert_expr!(
|
||||
assert_expr_comb!(
|
||||
"Pandas { a: x + y }",
|
||||
expr(NamedStruct {
|
||||
name: qn!(Pandas),
|
||||
fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))]
|
||||
})
|
||||
);
|
||||
assert_expr!(
|
||||
assert_expr_comb!(
|
||||
"Trousers { a:1, b:800 }",
|
||||
expr(NamedStruct {
|
||||
name: qn!(Trousers),
|
||||
|
Loading…
Reference in New Issue
Block a user