diff options
author | piegames <git@piegames.de> | 2024-07-11 10:49:15 +0200 |
---|---|---|
committer | piegames <git@piegames.de> | 2024-08-08 11:13:53 +0200 |
commit | 28ae24f3f738a50903bd9b9bf8eece84a1075c30 (patch) | |
tree | dae4696680c5acd3ada9f170976c6b7581e9be82 /src/libexpr/parser | |
parent | 6fdb47f0b259a9ffbe4bdb349d6aaf03a0144092 (diff) |
libexpr: Add experimental pipe operator
The |> operator is a reverse function operator with low binding strength
to replace lib.pipe. Implements RFC 148, see the RFC text for more
details. Closes #438.
Change-Id: I21df66e8014e0d4dd9753dd038560a2b0b7fd805
Diffstat (limited to 'src/libexpr/parser')
-rw-r--r-- | src/libexpr/parser/grammar.hh | 7 | ||||
-rw-r--r-- | src/libexpr/parser/parser.cc | 25 |
2 files changed, 32 insertions, 0 deletions
diff --git a/src/libexpr/parser/grammar.hh b/src/libexpr/parser/grammar.hh index 82df63bc5..2c5a3d1be 100644 --- a/src/libexpr/parser/grammar.hh +++ b/src/libexpr/parser/grammar.hh @@ -434,6 +434,8 @@ struct op { struct and_ : _op<TAO_PEGTL_STRING("&&"), 12> {}; struct or_ : _op<TAO_PEGTL_STRING("||"), 13> {}; struct implies : _op<TAO_PEGTL_STRING("->"), 14, kind::rightAssoc> {}; + struct pipe_right : _op<TAO_PEGTL_STRING("|>"), 15> {}; + struct pipe_left : _op<TAO_PEGTL_STRING("<|"), 16, kind::rightAssoc> {}; }; struct _expr { @@ -521,6 +523,7 @@ struct _expr { app > {}; + /* Order matters here. The order is the parsing order, not the precedence order: '<=' must be parsed before '<'. */ struct _binary_operator : sor< operator_<op::implies>, operator_<op::update>, @@ -529,6 +532,8 @@ struct _expr { operator_<op::minus>, operator_<op::mul>, operator_<op::div>, + operator_<op::pipe_right>, + operator_<op::pipe_left>, operator_<op::less_eq>, operator_<op::greater_eq>, operator_<op::less>, @@ -649,6 +654,8 @@ struct operator_semantics { grammar::op::minus, grammar::op::mul, grammar::op::div, + grammar::op::pipe_right, + grammar::op::pipe_left, has_attr > op; }; diff --git a/src/libexpr/parser/parser.cc b/src/libexpr/parser/parser.cc index 68aa3ddc5..6d496d141 100644 --- a/src/libexpr/parser/parser.cc +++ b/src/libexpr/parser/parser.cc @@ -113,6 +113,29 @@ struct ExprState return std::make_unique<ExprCall>(pos, std::make_unique<ExprVar>(fn), std::move(args)); } + std::unique_ptr<Expr> pipe(PosIdx pos, State & state, bool flip = false) + { + if (!state.xpSettings.isEnabled(Xp::PipeOperator)) + throw ParseError({ + .msg = HintFmt("Pipe operator is disabled"), + .pos = state.positions[pos] + }); + + // Reverse the order compared to normal function application: arg |> fn + std::unique_ptr<Expr> fn, arg; + if (flip) { + fn = popExprOnly(); + arg = popExprOnly(); + } else { + arg = popExprOnly(); + fn = popExprOnly(); + } + std::vector<std::unique_ptr<Expr>> args{1}; + args[0] = std::move(arg); + + return std::make_unique<ExprCall>(pos, std::move(fn), std::move(args)); + } + std::unique_ptr<Expr> order(PosIdx pos, bool less, State & state) { return call(pos, state.s.lessThan, !less); @@ -162,6 +185,8 @@ struct ExprState [&] (Op::concat) { return applyBinary<ExprOpConcatLists>(pos); }, [&] (has_attr & a) { return applyUnary<ExprOpHasAttr>(std::move(a.path)); }, [&] (Op::unary_minus) { return negate(pos, state); }, + [&] (Op::pipe_right) { return pipe(pos, state, true); }, + [&] (Op::pipe_left) { return pipe(pos, state); }, })(op) }; } |