aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpiegames <git@piegames.de>2024-07-11 10:49:15 +0200
committerpiegames <git@piegames.de>2024-08-08 11:13:53 +0200
commit28ae24f3f738a50903bd9b9bf8eece84a1075c30 (patch)
treedae4696680c5acd3ada9f170976c6b7581e9be82 /src
parent6fdb47f0b259a9ffbe4bdb349d6aaf03a0144092 (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')
-rw-r--r--src/libexpr/parser/grammar.hh7
-rw-r--r--src/libexpr/parser/parser.cc25
-rw-r--r--src/libutil/experimental-features.cc10
-rw-r--r--src/libutil/experimental-features.hh1
4 files changed, 43 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)
};
}
diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc
index 3a834293a..15a18c770 100644
--- a/src/libutil/experimental-features.cc
+++ b/src/libutil/experimental-features.cc
@@ -167,6 +167,16 @@ constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails
)",
},
{
+ .tag = Xp::PipeOperator,
+ .name = "pipe-operator",
+ .description = R"(
+ Enable new operators for function application to "pipe" arguments through a chain of functions similar to `lib.pipe`.
+ This implementation is based on Nix [RFC 148](https://github.com/NixOS/rfcs/pull/148).
+
+ Tracking issue: https://git.lix.systems/lix-project/lix/issues/438
+ )",
+ },
+ {
.tag = Xp::FetchClosure,
.name = "fetch-closure",
.description = R"(
diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh
index 38889e7bc..121318d23 100644
--- a/src/libutil/experimental-features.hh
+++ b/src/libutil/experimental-features.hh
@@ -21,6 +21,7 @@ enum struct ExperimentalFeature
NixCommand,
RecursiveNix,
NoUrlLiterals,
+ PipeOperator,
FetchClosure,
ReplFlake,
AutoAllocateUids,