Named structs

This commit is contained in:
Greg Shuflin 2021-11-18 21:02:33 -08:00
parent 58a1782162
commit 7e2b95593f
2 changed files with 107 additions and 77 deletions

View File

@ -4,16 +4,14 @@ use nom::{
branch::alt, branch::alt,
bytes::complete::{escaped_transform, tag, take_till, take_while}, bytes::complete::{escaped_transform, tag, take_till, take_while},
character::{ character::{
complete::{ complete::{alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space1},
alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0, space1,
},
is_alphanumeric, is_alphanumeric,
}, },
combinator::{map, not, opt, peek, recognize, value}, combinator::{cond, flat_map, map, not, opt, peek, recognize, value},
error::{context, ParseError, VerboseError}, error::{context, ParseError, VerboseError},
multi::{fold_many1, many0, many1, separated_list0, separated_list1}, multi::{many0, many1, separated_list0, separated_list1},
sequence::{delimited, pair, preceded, tuple}, sequence::{delimited, pair, preceded, separated_pair, tuple},
Err, IResult, Parser, IResult, Parser,
}; };
use nom_locate::{position, LocatedSpan}; use nom_locate::{position, LocatedSpan};
@ -99,8 +97,9 @@ pub fn program(input: Span) -> ParseResult<AST> {
Ok((rest, ast)) Ok((rest, ast))
} }
fn block_template<'a, O>(input_parser: impl Parser<Span<'a>, O, VerboseError<Span<'a>>>) -> impl FnMut(Span<'a>) -> fn block_template<'a, O>(
IResult<Span<'a>, Vec<O>, VerboseError<Span<'a>>> { input_parser: impl Parser<Span<'a>, O, VerboseError<Span<'a>>>,
) -> impl FnMut(Span<'a>) -> IResult<Span<'a>, Vec<O>, VerboseError<Span<'a>>> {
map( map(
delimited( delimited(
tok(char('{')), tok(char('{')),
@ -286,9 +285,20 @@ fn module(input: Span) -> ParseResult<Declaration> {
pub fn expression(input: Span) -> ParseResult<Expression> { pub fn expression(input: Span) -> ParseResult<Expression> {
let id = fresh_id(&input); let id = fresh_id(&input);
map(pair(expression_kind, opt(type_anno)), move |(kind, type_anno)| Expression { id, type_anno, kind })( map(pair(expression_kind(true), opt(type_anno)), move |(kind, type_anno)| Expression {
input, 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> { 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) delimited(tok(char('<')), separated_list1(tok(char(',')), type_identifier), tok(char('>')))(input)
} }
pub fn expression_kind(input: Span) -> ParseResult<ExpressionKind> { pub fn expression_kind(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
context("expression-kind", precedence_expr)(input) 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 handle = input.extra.clone();
let precedence_continuation = pair(operator, prefix_expr(allow_struct));
map( map(
pair(prefix_expr, many0(precedence_continuation)), pair(prefix_expr(allow_struct), many0(precedence_continuation)),
move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| { move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| {
let mut handle_ref = handle.borrow_mut(); let mut handle_ref = handle.borrow_mut();
BinopSequence { first, rest }.do_precedence(&mut handle_ref) BinopSequence { first, rest }.do_precedence(&mut handle_ref)
}, },
)(input) )(input)
} }
fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> {
pair(operator, prefix_expr)(input)
} }
fn operator(input: Span) -> ParseResult<BinOp> { 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) 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(); let handle = input.extra.clone();
context( context(
"prefix-expr", "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 { if let Some(prefix) = prefix {
let expr = Expression::new(fresh_id_rc(&handle), expr); let expr = Expression::new(fresh_id_rc(&handle), expr);
ExpressionKind::PrefixExp(prefix, Box::new(expr)) ExpressionKind::PrefixExp(prefix, Box::new(expr))
@ -360,6 +370,7 @@ fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
}), }),
)(input) )(input)
} }
}
#[derive(Debug)] #[derive(Debug)]
enum ExtendedPart<'a> { enum ExtendedPart<'a> {
@ -368,9 +379,10 @@ enum ExtendedPart<'a> {
Accessor(&'a str), 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)) = 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); let mut expression = Expression::new(fresh_id(&s), primary);
for part in parts.into_iter() { for part in parts.into_iter() {
@ -388,6 +400,7 @@ fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
Ok((s, expression.kind)) Ok((s, expression.kind))
} }
}
fn extended_expr_part(input: Span) -> ParseResult<ExtendedPart> { fn extended_expr_part(input: Span) -> ParseResult<ExtendedPart> {
fn index_part(input: Span) -> ParseResult<Vec<Expression>> { fn index_part(input: Span) -> ParseResult<Vec<Expression>> {
@ -420,13 +433,14 @@ fn invocation_argument(input: Span) -> ParseResult<InvocationArgument> {
))(input) ))(input)
} }
fn primary_expr(input: Span) -> ParseResult<ExpressionKind> { fn primary_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
context( move |input: Span| {
"primary-expr", if allow_struct {
alt(( context("primary-expr", alt((named_struct, primary_expr_no_struct)))(input)
primary_expr_no_struct, } else {
)), context("primary-expr", primary_expr_no_struct)(input)
)(input) }
}
} }
fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> { fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> {
@ -445,12 +459,25 @@ fn primary_expr_no_struct(input: Span) -> ParseResult<ExpressionKind> {
)(input) )(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> { fn while_expr(input: Span) -> ParseResult<ExpressionKind> {
let id = fresh_id(&input); let id = fresh_id(&input);
map(preceded(kw("while"), pair(opt(expression), block)), map(preceded(kw("while"), pair(opt(expression_no_struct), block)), move |(condition, body)| {
move |(condition, body)| ExpressionKind::WhileExpression { ExpressionKind::WhileExpression { condition: condition.map(Box::new), body }
condition: condition.map(Box::new),
body,
})(input) })(input)
} }
@ -695,12 +722,15 @@ mod test {
#[test] #[test]
fn combinator_test2() { fn combinator_test2() {
for s in [" 15", " 0b1111", " 1_5_", "0XF__", "0Xf"].iter() { 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!( 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)) ExpressionKind::Value(qn!(barnaby))
); );
} }

View File

@ -318,14 +318,14 @@ fn identifiers() {
#[test] #[test]
fn named_struct() { fn named_struct() {
use ExpressionKind::*; use ExpressionKind::*;
assert_expr!( assert_expr_comb!(
"Pandas { a: x + y }", "Pandas { a: x + y }",
expr(NamedStruct { expr(NamedStruct {
name: qn!(Pandas), name: qn!(Pandas),
fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))] fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))]
}) })
); );
assert_expr!( assert_expr_comb!(
"Trousers { a:1, b:800 }", "Trousers { a:1, b:800 }",
expr(NamedStruct { expr(NamedStruct {
name: qn!(Trousers), name: qn!(Trousers),