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,15 +97,16 @@ 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('{')),
tuple(( tuple((
many0(statement_delimiter), many0(statement_delimiter),
separated_list0(statement_delimiter, input_parser), separated_list0(statement_delimiter, input_parser),
many0(statement_delimiter), many0(statement_delimiter),
)), )),
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> {
let handle = input.extra.clone(); move |input: Span| {
map( let handle = input.extra.clone();
pair(prefix_expr, many0(precedence_continuation)), let precedence_continuation = pair(operator, prefix_expr(allow_struct));
move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| { map(
let mut handle_ref = handle.borrow_mut(); pair(prefix_expr(allow_struct), many0(precedence_continuation)),
BinopSequence { first, rest }.do_precedence(&mut handle_ref) move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| {
}, let mut handle_ref = handle.borrow_mut();
)(input) 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> { fn operator(input: Span) -> ParseResult<BinOp> {
@ -346,19 +355,21 @@ 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> {
let handle = input.extra.clone(); move |input: Span| {
context( let handle = input.extra.clone();
"prefix-expr", context(
map(pair(opt(prefix_op), extended_expr), move |(prefix, expr)| { "prefix-expr",
if let Some(prefix) = prefix { map(pair(opt(prefix_op), extended_expr(allow_struct)), move |(prefix, expr)| {
let expr = Expression::new(fresh_id_rc(&handle), expr); if let Some(prefix) = prefix {
ExpressionKind::PrefixExp(prefix, Box::new(expr)) let expr = Expression::new(fresh_id_rc(&handle), expr);
} else { ExpressionKind::PrefixExp(prefix, Box::new(expr))
expr } else {
} expr
}), }
)(input) }),
)(input)
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -368,25 +379,27 @@ 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> {
let (s, (primary, parts)) = move |input: Span| {
context("extended-expr", pair(primary_expr, many0(extended_expr_part)))(input)?; let (s, (primary, parts)) =
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() {
let kind = match part { let kind = match part {
ExtendedPart::Index(indexers) => ExtendedPart::Index(indexers) =>
ExpressionKind::Index { indexee: Box::new(expression), indexers }, ExpressionKind::Index { indexee: Box::new(expression), indexers },
ExtendedPart::Call(arguments) => ExpressionKind::Call { f: Box::new(expression), arguments }, ExtendedPart::Call(arguments) => ExpressionKind::Call { f: Box::new(expression), arguments },
ExtendedPart::Accessor(name) => { ExtendedPart::Accessor(name) => {
let name = rc_string(name); let name = rc_string(name);
ExpressionKind::Access { name, expr: Box::new(expression) } ExpressionKind::Access { name, expr: Box::new(expression) }
} }
}; };
expression = Expression::new(fresh_id(&s), kind); expression = Expression::new(fresh_id(&s), kind);
}
Ok((s, expression.kind))
} }
Ok((s, expression.kind))
} }
fn extended_expr_part(input: Span) -> ParseResult<ExtendedPart> { fn extended_expr_part(input: Span) -> ParseResult<ExtendedPart> {
@ -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),
@ -375,7 +375,7 @@ fn index() {
fn while_expression() { fn while_expression() {
use ExpressionKind::*; use ExpressionKind::*;
// assert_expr_comb!("while { }", expr(WhileExpression { condition: None, body: Block::default() })); // assert_expr_comb!("while { }", expr(WhileExpression { condition: None, body: Block::default() }));
assert_expr_comb!( assert_expr_comb!(
"while a == b { }", "while a == b { }",
expr(WhileExpression { expr(WhileExpression {