aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/parser/grammar.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/parser/grammar.hh')
-rw-r--r--src/libexpr/parser/grammar.hh122
1 files changed, 71 insertions, 51 deletions
diff --git a/src/libexpr/parser/grammar.hh b/src/libexpr/parser/grammar.hh
index 2c5a3d1be..701b40505 100644
--- a/src/libexpr/parser/grammar.hh
+++ b/src/libexpr/parser/grammar.hh
@@ -12,7 +12,7 @@
// eolf rules in favor of reproducing the old flex lexer as faithfully as
// possible, and deferring calculation of positions to downstream users.
-namespace nix::parser::grammar {
+namespace nix::parser::grammar::v1 {
using namespace tao::pegtl;
namespace p = tao::pegtl;
@@ -225,7 +225,8 @@ struct string : _string, seq<
> {};
struct _ind_string {
- template<bool Indented, typename... Inner>
+ struct line_start : semantic, star<one<' '>> {};
+ template<typename... Inner>
struct literal : semantic, seq<Inner...> {};
struct interpolation : semantic, seq<
p::string<'$', '{'>, seps,
@@ -233,34 +234,53 @@ struct _ind_string {
must<one<'}'>>
> {};
struct escape : semantic, must<any> {};
+ /* Marker for non-empty lines */
+ struct has_content : semantic, seq<> {};
};
struct ind_string : _ind_string, seq<
TAO_PEGTL_STRING("''"),
+ // Strip first line completely if empty
opt<star<one<' '>>, one<'\n'>>,
- star<
- sor<
- _ind_string::literal<
- true,
+ list<
+ seq<
+ // Start a line with some indentation
+ // (we always match even the empty string if no indentation, as this creates the line)
+ _ind_string::line_start,
+ // The actual line
+ opt<
plus<
sor<
- not_one<'$', '\''>,
- seq<one<'$'>, not_one<'{', '\''>>,
- seq<one<'\''>, not_one<'\'', '$'>>
- >
- >
- >,
- _ind_string::interpolation,
- _ind_string::literal<false, one<'$'>>,
- _ind_string::literal<false, one<'\''>, not_at<one<'\''>>>,
- seq<one<'\''>, _ind_string::literal<false, p::string<'\'', '\''>>>,
- seq<
- p::string<'\'', '\''>,
- sor<
- _ind_string::literal<false, one<'$'>>,
- seq<one<'\\'>, _ind_string::escape>
+ _ind_string::literal<
+ plus<
+ sor<
+ not_one<'$', '\'', '\n'>,
+ // TODO probably factor this out like the others for performance
+ seq<one<'$'>, not_one<'{', '\'', '\n'>>,
+ seq<one<'$'>, at<one<'\n'>>>,
+ seq<one<'\''>, not_one<'\'', '$', '\n'>>,
+ seq<one<'\''>, at<one<'\n'>>>
+ >
+ >
+ >,
+ _ind_string::interpolation,
+ _ind_string::literal<one<'$'>>,
+ _ind_string::literal<one<'\''>, not_at<one<'\''>>>,
+ seq<one<'\''>, _ind_string::literal<p::string<'\'', '\''>>>,
+ seq<
+ p::string<'\'', '\''>,
+ sor<
+ _ind_string::literal<one<'$'>>,
+ seq<one<'\\'>, _ind_string::escape>
+ >
+ >
+ >,
+ _ind_string::has_content
>
>
- >
+ >,
+ // End of line, LF. CR is just ignored and not treated as ending a line
+ // (for the purpose of indentation stripping)
+ _ind_string::literal<one<'\n'>>
>,
must<TAO_PEGTL_STRING("''")>
> {};
@@ -352,10 +372,10 @@ struct formals : semantic, _formals, seq<
struct _attr {
struct simple : semantic, sor<t::identifier, t::kw_or> {};
- struct string : semantic, seq<grammar::string> {};
+ struct string : semantic, seq<grammar::v1::string> {};
struct expr : semantic, seq<
TAO_PEGTL_STRING("${"), seps,
- must<grammar::expr>, seps,
+ must<grammar::v1::expr>, seps,
must<one<'}'>>
> {};
};
@@ -452,9 +472,9 @@ struct _expr {
struct id : semantic, t::identifier {};
struct int_ : semantic, t::integer {};
struct float_ : semantic, t::floating {};
- struct string : semantic, seq<grammar::string> {};
- struct ind_string : semantic, seq<grammar::ind_string> {};
- struct path : semantic, seq<grammar::path> {};
+ struct string : semantic, seq<grammar::v1::string> {};
+ struct ind_string : semantic, seq<grammar::v1::ind_string> {};
+ struct path : semantic, seq<grammar::v1::path> {};
struct uri : semantic, t::uri {};
struct ancient_let : semantic, _attrset<must, t::kw_let, seps> {};
struct rec_set : semantic, _attrset<must, t::kw_rec, seps> {};
@@ -628,34 +648,34 @@ struct nothing : p::nothing<Rule> {
template<typename Self, typename OpCtx, typename AttrPathT, typename ExprT>
struct operator_semantics {
- struct has_attr : grammar::op::has_attr {
+ struct has_attr : grammar::v1::op::has_attr {
AttrPathT path;
};
struct OpEntry {
OpCtx ctx;
uint8_t prec;
- grammar::op::kind assoc;
+ grammar::v1::op::kind assoc;
std::variant<
- grammar::op::not_,
- grammar::op::unary_minus,
- grammar::op::implies,
- grammar::op::or_,
- grammar::op::and_,
- grammar::op::equals,
- grammar::op::not_equals,
- grammar::op::less_eq,
- grammar::op::greater_eq,
- grammar::op::update,
- grammar::op::concat,
- grammar::op::less,
- grammar::op::greater,
- grammar::op::plus,
- grammar::op::minus,
- grammar::op::mul,
- grammar::op::div,
- grammar::op::pipe_right,
- grammar::op::pipe_left,
+ grammar::v1::op::not_,
+ grammar::v1::op::unary_minus,
+ grammar::v1::op::implies,
+ grammar::v1::op::or_,
+ grammar::v1::op::and_,
+ grammar::v1::op::equals,
+ grammar::v1::op::not_equals,
+ grammar::v1::op::less_eq,
+ grammar::v1::op::greater_eq,
+ grammar::v1::op::update,
+ grammar::v1::op::concat,
+ grammar::v1::op::less,
+ grammar::v1::op::greater,
+ grammar::v1::op::plus,
+ grammar::v1::op::minus,
+ grammar::v1::op::mul,
+ grammar::v1::op::div,
+ grammar::v1::op::pipe_right,
+ grammar::v1::op::pipe_left,
has_attr
> op;
};
@@ -676,7 +696,7 @@ struct operator_semantics {
auto & [ctx, precedence, kind, op] = ops.back();
// NOTE this relies on associativity not being mixed within a precedence level.
if ((precedence > toPrecedence)
- || (kind != grammar::op::kind::leftAssoc && precedence == toPrecedence))
+ || (kind != grammar::v1::op::kind::leftAssoc && precedence == toPrecedence))
break;
std::visit([&, ctx=std::move(ctx)] (auto & op) {
exprs.push_back(static_cast<Self &>(*this).applyOp(ctx, op, args...));
@@ -694,9 +714,9 @@ struct operator_semantics {
void pushOp(OpCtx ctx, auto o, auto &... args)
{
- if (o.kind != grammar::op::kind::unary)
+ if (o.kind != grammar::v1::op::kind::unary)
reduce(o.precedence, args...);
- if (!ops.empty() && o.kind == grammar::op::kind::nonAssoc) {
+ if (!ops.empty() && o.kind == grammar::v1::op::kind::nonAssoc) {
auto & [_pos, _prec, _kind, _o] = ops.back();
if (_kind == o.kind && _prec == o.precedence)
Self::badOperator(ctx, args...);