From 06617e5b2f43a98482fcade8796070e4c6103d2e Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Thu, 10 Oct 2019 22:10:23 +0800 Subject: [PATCH] formal arg with ellipsis --- nix-parser/src/parser/expr/func.rs | 29 +++++++++++++++++++++-------- nix-parser/src/parser/expr/util.rs | 3 +++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/nix-parser/src/parser/expr/func.rs b/nix-parser/src/parser/expr/func.rs index 5bfe68d..08f91f7 100644 --- a/nix-parser/src/parser/expr/func.rs +++ b/nix-parser/src/parser/expr/func.rs @@ -5,7 +5,7 @@ use nom::combinator::{map, opt}; use nom::multi::many0; use nom::sequence::{delimited, pair, preceded, terminated}; -use super::{expr, util}; +use super::{expr, util::error_expr_if}; use crate::ast::tokens::Ident; use crate::ast::{ExprFnDecl, FnDeclFormals, FnDeclSimple, Formal}; use crate::error::{Errors, ExpectedFoundError}; @@ -23,7 +23,7 @@ pub fn fn_decl(input: Tokens) -> IResult> { } fn simple(input: Tokens) -> IResult> { - let expr = alt((expr, util::error_expr_if(tokens::eof, ""))); + let expr = alt((expr, error_expr_if(tokens::eof, ""))); map_partial(pair_partial(identifier_arg, expr), |(ident, body)| { let span = Span::merge(ident.span(), body.span()); FnDeclSimple::new(ident, body, span) @@ -31,7 +31,7 @@ fn simple(input: Tokens) -> IResult> { } fn formals(input: Tokens) -> IResult> { - let value = alt((expr, util::error_expr_if(tokens::comma, "comma"))); + let value = alt((expr, error_expr_if(tokens::comma, "comma"))); let default = opt(preceded(tokens::op_question, verify_full(value))); let formal = map(pair(tokens::identifier, default), |(name, def)| { let name_span = name.span(); @@ -39,14 +39,27 @@ fn formals(input: Tokens) -> IResult> { Partial::from(Formal::new(name, def, Span::merge(name_span, default_span))) }); - let args = separated_list_partial(tokens::comma, tokens::brace_right, formal); + // overloading trailing comma + let ellipsis = alt(( + map(tokens::comma, |_| None), + map(preceded(tokens::comma, tokens::ellipsis), |ellipsis| { + Some(ellipsis) + }), + )); + let args = pair_partial( + separated_list_partial(tokens::comma, tokens::brace_right, formal), + map(opt(ellipsis), |e: Option<_>| { + Partial::from(e.and_then(std::convert::identity)) + }), + ); let term = pair(tokens::brace_right, tokens::colon); let formals = delimited(tokens::brace_left, args, term); - let expr = alt((expr, util::error_expr_if(tokens::eof, ""))); - map_partial_spanned(pair_partial(formals, expr), |span, (formals, expr)| { - FnDeclFormals::new(formals, None, None, expr, span) - })(input) + let expr = alt((expr, error_expr_if(tokens::eof, ""))); + map_partial_spanned( + pair_partial(formals, expr), + |span, ((formals, ellipsis), expr)| FnDeclFormals::new(formals, ellipsis, None, expr, span), + )(input) } fn identifier_arg(input: Tokens) -> IResult> { diff --git a/nix-parser/src/parser/expr/util.rs b/nix-parser/src/parser/expr/util.rs index 4cc991b..40fa3a3 100644 --- a/nix-parser/src/parser/expr/util.rs +++ b/nix-parser/src/parser/expr/util.rs @@ -7,6 +7,9 @@ use crate::parser::partial::Partial; use crate::parser::IResult; use crate::ToSpan; +/// parser transformer that peeks for a reasonable termination token and +/// provides designated grammatical hint `found` and hint for expected +/// "expression" grammatical tokens pub fn error_expr_if<'a, O, F>( parser: F, found: &'a str,