Named structs
This commit is contained in:
parent
58a1782162
commit
7e2b95593f
@ -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))
|
||||||
@ -359,6 +369,7 @@ fn prefix_expr(input: Span) -> ParseResult<ExpressionKind> {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)(input)
|
)(input)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -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() {
|
||||||
@ -387,6 +399,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> {
|
||||||
@ -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))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user