From e1711bdc9a81b3fa047fb4bd11e2e5af158a52f3 Mon Sep 17 00:00:00 2001 From: Eyal Kalderon Date: Sun, 20 Oct 2019 01:23:12 +0800 Subject: [PATCH] Add parser support for question mark operator The benchmark results below indicate that this addition does not regress performance, likely thanks in part to commit c913d3f: ``` parse_example/parse example.nix time: [304.64 us 306.29 us 308.22 us] thrpt: [1.5502 MiB/s 1.5599 MiB/s 1.5684 MiB/s] change: time: [-4.5555% -0.1801% +4.1732%] (p = 0.94 > 0.05) thrpt: [-4.0060% +0.1804% +4.7729%] No change in performance detected. Found 10 outliers among 100 measurements (10.00%) 3 (3.00%) high mild 7 (7.00%) high severe ``` --- nix-parser/src/parser/expr.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/nix-parser/src/parser/expr.rs b/nix-parser/src/parser/expr.rs index 6984c1c..22bcf9c 100644 --- a/nix-parser/src/parser/expr.rs +++ b/nix-parser/src/parser/expr.rs @@ -183,7 +183,7 @@ fn product(input: Tokens) -> IResult> { } fn concat(input: Tokens) -> IResult> { - let expr = pair(unary, many0(preceded(tokens::op_concat, unary))); + let expr = pair(has_attr, many0(preceded(tokens::op_concat, has_attr))); map(expr, |(first, rest)| { let exprs = Partial::from_iter(iter::once(first).chain(rest)); exprs.map(|mut exprs| { @@ -196,6 +196,20 @@ fn concat(input: Tokens) -> IResult> { })(input) } +fn has_attr(input: Tokens) -> IResult> { + let rhs = alt((unary, util::error_expr_if(tokens::eof))); + let expr = pair(unary, opt(preceded(tokens::op_question, rhs))); + map(expr, |(lhs, rhs)| match rhs { + None => lhs, + Some(rhs) => lhs.flat_map(|lhs| { + rhs.map(|rhs| { + let span = Span::merge(lhs.span(), rhs.span()); + Expr::from(ExprBinary::new(BinaryOp::HasAttr, lhs, rhs, span)) + }) + }), + })(input) +} + fn unary(input: Tokens) -> IResult> { let neg = map(tokens::op_sub, |_| UnaryOp::Neg); let not = map(tokens::op_not, |_| UnaryOp::Not);