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,
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,15 +97,16 @@ 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('{')),
tuple((
many0(statement_delimiter),
separated_list0(statement_delimiter, input_parser),
many0(statement_delimiter),
many0(statement_delimiter),
separated_list0(statement_delimiter, input_parser),
many0(statement_delimiter),
)),
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> {
let handle = input.extra.clone();
map(
pair(prefix_expr, 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 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(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 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)
}
fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
let handle = input.extra.clone();
context(
"prefix-expr",
map(pair(opt(prefix_op), extended_expr), move |(prefix, expr)| {
if let Some(prefix) = prefix {
let expr = Expression::new(fresh_id_rc(&handle), expr);
ExpressionKind::PrefixExp(prefix, Box::new(expr))
} else {
expr
}
}),
)(input)
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(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))
} else {
expr
}
}),
)(input)
}
}
#[derive(Debug)]
@ -368,25 +379,27 @@ enum ExtendedPart<'a> {
Accessor(&'a str),
}
fn extended_expr(input: Span) -> ParseResult<ExpressionKind> {
let (s, (primary, parts)) =
context("extended-expr", pair(primary_expr, many0(extended_expr_part)))(input)?;
fn extended_expr(allow_struct: bool) -> impl FnMut(Span) -> ParseResult<ExpressionKind> {
move |input: Span| {
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);
for part in parts.into_iter() {
let kind = match part {
ExtendedPart::Index(indexers) =>
ExpressionKind::Index { indexee: Box::new(expression), indexers },
ExtendedPart::Call(arguments) => ExpressionKind::Call { f: Box::new(expression), arguments },
ExtendedPart::Accessor(name) => {
let name = rc_string(name);
ExpressionKind::Access { name, expr: Box::new(expression) }
}
};
expression = Expression::new(fresh_id(&s), kind);
let mut expression = Expression::new(fresh_id(&s), primary);
for part in parts.into_iter() {
let kind = match part {
ExtendedPart::Index(indexers) =>
ExpressionKind::Index { indexee: Box::new(expression), indexers },
ExtendedPart::Call(arguments) => ExpressionKind::Call { f: Box::new(expression), arguments },
ExtendedPart::Accessor(name) => {
let name = rc_string(name);
ExpressionKind::Access { name, expr: Box::new(expression) }
}
};
expression = Expression::new(fresh_id(&s), kind);
}
Ok((s, expression.kind))
}
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))
);
}

View File

@ -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),
@ -375,7 +375,7 @@ fn index() {
fn while_expression() {
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!(
"while a == b { }",
expr(WhileExpression {