aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/lexer.l17
-rw-r--r--src/libexpr/parser-state.hh262
-rw-r--r--src/libexpr/parser.y409
3 files changed, 337 insertions, 351 deletions
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index ced1c4c39..b362f4907 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -35,12 +35,7 @@ using namespace nix;
namespace nix {
-static inline PosIdx makeCurPos(const YYLTYPE & loc, ParseData * data)
-{
- return data->state.positions.add(data->origin, loc.first_line, loc.first_column);
-}
-
-#define CUR_POS makeCurPos(*yylloc, data)
+#define CUR_POS state->makeCurPos(*yylloc)
static void initLoc(YYLTYPE * loc)
{
@@ -159,7 +154,7 @@ or { return OR_KW; }
} catch (const boost::bad_lexical_cast &) {
throw ParseError({
.msg = hintfmt("invalid integer '%1%'", yytext),
- .errPos = data->state.positions[CUR_POS],
+ .errPos = state->state.positions[CUR_POS],
});
}
return INT;
@@ -169,7 +164,7 @@ or { return OR_KW; }
if (errno != 0)
throw ParseError({
.msg = hintfmt("invalid float '%1%'", yytext),
- .errPos = data->state.positions[CUR_POS],
+ .errPos = state->state.positions[CUR_POS],
});
return FLOAT;
}
@@ -192,7 +187,7 @@ or { return OR_KW; }
/* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */
- yylval->str = unescapeStr(data->symbols, yytext, yyleng);
+ yylval->str = unescapeStr(state->symbols, yytext, yyleng);
return STR;
}
<STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
@@ -220,7 +215,7 @@ or { return OR_KW; }
return IND_STR;
}
<IND_STRING>\'\'\\{ANY} {
- yylval->str = unescapeStr(data->symbols, yytext + 2, yyleng - 2);
+ yylval->str = unescapeStr(state->symbols, yytext + 2, yyleng - 2);
return IND_STR;
}
<IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
@@ -298,7 +293,7 @@ or { return OR_KW; }
<INPATH_SLASH><<EOF>> {
throw ParseError({
.msg = hintfmt("path has a trailing slash"),
- .errPos = data->state.positions[CUR_POS],
+ .errPos = state->state.positions[CUR_POS],
});
}
diff --git a/src/libexpr/parser-state.hh b/src/libexpr/parser-state.hh
new file mode 100644
index 000000000..b33311743
--- /dev/null
+++ b/src/libexpr/parser-state.hh
@@ -0,0 +1,262 @@
+#pragma once
+
+#include "eval.hh"
+
+namespace nix {
+
+// using C a struct allows us to avoid having to define the special
+// members that using string_view here would implicitly delete.
+struct StringToken {
+ const char * p;
+ size_t l;
+ bool hasIndentation;
+ operator std::string_view() const { return {p, l}; }
+};
+
+struct ParserLocation {
+ int first_line, first_column;
+ int last_line, last_column;
+
+ // backup to recover from yyless(0)
+ int stashed_first_line, stashed_first_column;
+ int stashed_last_line, stashed_last_column;
+
+ void stash() {
+ stashed_first_line = first_line;
+ stashed_first_column = first_column;
+ stashed_last_line = last_line;
+ stashed_last_column = last_column;
+ }
+
+ void unstash() {
+ first_line = stashed_first_line;
+ first_column = stashed_first_column;
+ last_line = stashed_last_line;
+ last_column = stashed_last_column;
+ }
+};
+
+struct ParserState {
+ EvalState & state;
+ SymbolTable & symbols;
+ Expr * result;
+ SourcePath basePath;
+ PosTable::Origin origin;
+
+ void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
+ void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
+ void addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos);
+ Formals * validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
+ Expr * stripIndentation(const PosIdx pos,
+ std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
+ PosIdx makeCurPos(const ParserLocation & loc);
+};
+
+inline void ParserState::dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos)
+{
+ throw ParseError({
+ .msg = hintfmt("attribute '%1%' already defined at %2%",
+ showAttrPath(state.symbols, attrPath), state.positions[prevPos]),
+ .errPos = state.positions[pos]
+ });
+}
+
+inline void ParserState::dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos)
+{
+ throw ParseError({
+ .msg = hintfmt("attribute '%1%' already defined at %2%", state.symbols[attr], state.positions[prevPos]),
+ .errPos = state.positions[pos]
+ });
+}
+
+inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos)
+{
+ AttrPath::iterator i;
+ // All attrpaths have at least one attr
+ assert(!attrPath.empty());
+ // Checking attrPath validity.
+ // ===========================
+ for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
+ if (i->symbol) {
+ ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
+ if (j != attrs->attrs.end()) {
+ if (!j->second.inherited) {
+ ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
+ if (!attrs2) dupAttr(attrPath, pos, j->second.pos);
+ attrs = attrs2;
+ } else
+ dupAttr(attrPath, pos, j->second.pos);
+ } else {
+ ExprAttrs * nested = new ExprAttrs;
+ attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
+ attrs = nested;
+ }
+ } else {
+ ExprAttrs *nested = new ExprAttrs;
+ attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
+ attrs = nested;
+ }
+ }
+ // Expr insertion.
+ // ==========================
+ if (i->symbol) {
+ ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
+ if (j != attrs->attrs.end()) {
+ // This attr path is already defined. However, if both
+ // e and the expr pointed by the attr path are two attribute sets,
+ // we want to merge them.
+ // Otherwise, throw an error.
+ auto ae = dynamic_cast<ExprAttrs *>(e);
+ auto jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
+ if (jAttrs && ae) {
+ for (auto & ad : ae->attrs) {
+ auto j2 = jAttrs->attrs.find(ad.first);
+ if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
+ dupAttr(ad.first, j2->second.pos, ad.second.pos);
+ jAttrs->attrs.emplace(ad.first, ad.second);
+ }
+ jAttrs->dynamicAttrs.insert(jAttrs->dynamicAttrs.end(), ae->dynamicAttrs.begin(), ae->dynamicAttrs.end());
+ } else {
+ dupAttr(attrPath, pos, j->second.pos);
+ }
+ } else {
+ // This attr path is not defined. Let's create it.
+ attrs->attrs.emplace(i->symbol, ExprAttrs::AttrDef(e, pos));
+ e->setName(i->symbol);
+ }
+ } else {
+ attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
+ }
+}
+
+inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
+{
+ std::sort(formals->formals.begin(), formals->formals.end(),
+ [] (const auto & a, const auto & b) {
+ return std::tie(a.name, a.pos) < std::tie(b.name, b.pos);
+ });
+
+ std::optional<std::pair<Symbol, PosIdx>> duplicate;
+ for (size_t i = 0; i + 1 < formals->formals.size(); i++) {
+ if (formals->formals[i].name != formals->formals[i + 1].name)
+ continue;
+ std::pair thisDup{formals->formals[i].name, formals->formals[i + 1].pos};
+ duplicate = std::min(thisDup, duplicate.value_or(thisDup));
+ }
+ if (duplicate)
+ throw ParseError({
+ .msg = hintfmt("duplicate formal function argument '%1%'", symbols[duplicate->first]),
+ .errPos = state.positions[duplicate->second]
+ });
+
+ if (arg && formals->has(arg))
+ throw ParseError({
+ .msg = hintfmt("duplicate formal function argument '%1%'", symbols[arg]),
+ .errPos = state.positions[pos]
+ });
+
+ return formals;
+}
+
+inline Expr * ParserState::stripIndentation(const PosIdx pos,
+ std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es)
+{
+ if (es.empty()) return new ExprString("");
+
+ /* Figure out the minimum indentation. Note that by design
+ whitespace-only final lines are not taken into account. (So
+ the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
+ bool atStartOfLine = true; /* = seen only whitespace in the current line */
+ size_t minIndent = 1000000;
+ size_t curIndent = 0;
+ for (auto & [i_pos, i] : es) {
+ auto * str = std::get_if<StringToken>(&i);
+ if (!str || !str->hasIndentation) {
+ /* Anti-quotations and escaped characters end the current start-of-line whitespace. */
+ if (atStartOfLine) {
+ atStartOfLine = false;
+ if (curIndent < minIndent) minIndent = curIndent;
+ }
+ continue;
+ }
+ for (size_t j = 0; j < str->l; ++j) {
+ if (atStartOfLine) {
+ if (str->p[j] == ' ')
+ curIndent++;
+ else if (str->p[j] == '\n') {
+ /* Empty line, doesn't influence minimum
+ indentation. */
+ curIndent = 0;
+ } else {
+ atStartOfLine = false;
+ if (curIndent < minIndent) minIndent = curIndent;
+ }
+ } else if (str->p[j] == '\n') {
+ atStartOfLine = true;
+ curIndent = 0;
+ }
+ }
+ }
+
+ /* Strip spaces from each line. */
+ auto * es2 = new std::vector<std::pair<PosIdx, Expr *>>;
+ atStartOfLine = true;
+ size_t curDropped = 0;
+ size_t n = es.size();
+ auto i = es.begin();
+ const auto trimExpr = [&] (Expr * e) {
+ atStartOfLine = false;
+ curDropped = 0;
+ es2->emplace_back(i->first, e);
+ };
+ const auto trimString = [&] (const StringToken & t) {
+ std::string s2;
+ for (size_t j = 0; j < t.l; ++j) {
+ if (atStartOfLine) {
+ if (t.p[j] == ' ') {
+ if (curDropped++ >= minIndent)
+ s2 += t.p[j];
+ }
+ else if (t.p[j] == '\n') {
+ curDropped = 0;
+ s2 += t.p[j];
+ } else {
+ atStartOfLine = false;
+ curDropped = 0;
+ s2 += t.p[j];
+ }
+ } else {
+ s2 += t.p[j];
+ if (t.p[j] == '\n') atStartOfLine = true;
+ }
+ }
+
+ /* Remove the last line if it is empty and consists only of
+ spaces. */
+ if (n == 1) {
+ std::string::size_type p = s2.find_last_of('\n');
+ if (p != std::string::npos && s2.find_first_not_of(' ', p + 1) == std::string::npos)
+ s2 = std::string(s2, 0, p + 1);
+ }
+
+ es2->emplace_back(i->first, new ExprString(std::move(s2)));
+ };
+ for (; i != es.end(); ++i, --n) {
+ std::visit(overloaded { trimExpr, trimString }, i->second);
+ }
+
+ /* If this is a single string, then don't do a concatenation. */
+ if (es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0].second)) {
+ auto *const result = (*es2)[0].second;
+ delete es2;
+ return result;
+ }
+ return new ExprConcatStrings(pos, true, es2);
+}
+
+inline PosIdx ParserState::makeCurPos(const ParserLocation & loc)
+{
+ return state.positions.add(origin, loc.first_line, loc.first_column);
+}
+
+}
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index ed9e32b93..6b134ca06 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -5,9 +5,9 @@
%defines
/* %no-lines */
%parse-param { void * scanner }
-%parse-param { nix::ParseData * data }
+%parse-param { nix::ParserState * state }
%lex-param { void * scanner }
-%lex-param { nix::ParseData * data }
+%lex-param { nix::ParserState * state }
%expect 1
%expect-rr 1
@@ -25,64 +25,11 @@
#include "eval.hh"
#include "eval-settings.hh"
#include "globals.hh"
-
-// using C a struct allows us to avoid having to define the special
-// members that using string_view here would implicitly delete.
-struct StringToken {
- const char * p;
- size_t l;
- bool hasIndentation;
- operator std::string_view() const { return {p, l}; }
-};
-
-namespace nix {
+#include "parser-state.hh"
#define YYLTYPE ::nix::ParserLocation
- struct ParserLocation
- {
- int first_line, first_column;
- int last_line, last_column;
-
- // backup to recover from yyless(0)
- int stashed_first_line, stashed_first_column;
- int stashed_last_line, stashed_last_column;
-
- void stash() {
- stashed_first_line = first_line;
- stashed_first_column = first_column;
- stashed_last_line = last_line;
- stashed_last_column = last_column;
- }
-
- void unstash() {
- first_line = stashed_first_line;
- first_column = stashed_first_column;
- last_line = stashed_last_line;
- last_column = stashed_last_column;
- }
- };
-
- struct ParseData
- {
- EvalState & state;
- SymbolTable & symbols;
- Expr * result;
- SourcePath basePath;
- PosTable::Origin origin;
-
- void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
- void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
- void addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos);
- Formals * validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
- Expr * stripIndentation(const PosIdx pos,
- std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
- PosIdx makeCurPos(const ParserLocation & loc);
- };
-
-}
-
#define YY_DECL int yylex \
- (YYSTYPE * yylval_param, YYLTYPE * yylloc_param, yyscan_t yyscanner, nix::ParseData * data)
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param, yyscan_t yyscanner, nix::ParserState * state)
#endif
@@ -97,232 +44,14 @@ YY_DECL;
using namespace nix;
-
-namespace nix {
-
-
-void ParseData::dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos)
-{
- throw ParseError({
- .msg = hintfmt("attribute '%1%' already defined at %2%",
- showAttrPath(state.symbols, attrPath), state.positions[prevPos]),
- .errPos = state.positions[pos]
- });
-}
-
-void ParseData::dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos)
-{
- throw ParseError({
- .msg = hintfmt("attribute '%1%' already defined at %2%", state.symbols[attr], state.positions[prevPos]),
- .errPos = state.positions[pos]
- });
-}
-
-
-void ParseData::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos)
-{
- AttrPath::iterator i;
- // All attrpaths have at least one attr
- assert(!attrPath.empty());
- // Checking attrPath validity.
- // ===========================
- for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
- if (i->symbol) {
- ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
- if (j != attrs->attrs.end()) {
- if (!j->second.inherited) {
- ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
- if (!attrs2) dupAttr(attrPath, pos, j->second.pos);
- attrs = attrs2;
- } else
- dupAttr(attrPath, pos, j->second.pos);
- } else {
- ExprAttrs * nested = new ExprAttrs;
- attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
- attrs = nested;
- }
- } else {
- ExprAttrs *nested = new ExprAttrs;
- attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
- attrs = nested;
- }
- }
- // Expr insertion.
- // ==========================
- if (i->symbol) {
- ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
- if (j != attrs->attrs.end()) {
- // This attr path is already defined. However, if both
- // e and the expr pointed by the attr path are two attribute sets,
- // we want to merge them.
- // Otherwise, throw an error.
- auto ae = dynamic_cast<ExprAttrs *>(e);
- auto jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
- if (jAttrs && ae) {
- for (auto & ad : ae->attrs) {
- auto j2 = jAttrs->attrs.find(ad.first);
- if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
- dupAttr(ad.first, j2->second.pos, ad.second.pos);
- jAttrs->attrs.emplace(ad.first, ad.second);
- }
- jAttrs->dynamicAttrs.insert(jAttrs->dynamicAttrs.end(), ae->dynamicAttrs.begin(), ae->dynamicAttrs.end());
- } else {
- dupAttr(attrPath, pos, j->second.pos);
- }
- } else {
- // This attr path is not defined. Let's create it.
- attrs->attrs.emplace(i->symbol, ExprAttrs::AttrDef(e, pos));
- e->setName(i->symbol);
- }
- } else {
- attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
- }
-}
-
-
-Formals * ParseData::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
-{
- std::sort(formals->formals.begin(), formals->formals.end(),
- [] (const auto & a, const auto & b) {
- return std::tie(a.name, a.pos) < std::tie(b.name, b.pos);
- });
-
- std::optional<std::pair<Symbol, PosIdx>> duplicate;
- for (size_t i = 0; i + 1 < formals->formals.size(); i++) {
- if (formals->formals[i].name != formals->formals[i + 1].name)
- continue;
- std::pair thisDup{formals->formals[i].name, formals->formals[i + 1].pos};
- duplicate = std::min(thisDup, duplicate.value_or(thisDup));
- }
- if (duplicate)
- throw ParseError({
- .msg = hintfmt("duplicate formal function argument '%1%'", symbols[duplicate->first]),
- .errPos = state.positions[duplicate->second]
- });
-
- if (arg && formals->has(arg))
- throw ParseError({
- .msg = hintfmt("duplicate formal function argument '%1%'", symbols[arg]),
- .errPos = state.positions[pos]
- });
-
- return formals;
-}
-
-
-Expr * ParseData::stripIndentation(const PosIdx pos,
- std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es)
-{
- if (es.empty()) return new ExprString("");
-
- /* Figure out the minimum indentation. Note that by design
- whitespace-only final lines are not taken into account. (So
- the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
- bool atStartOfLine = true; /* = seen only whitespace in the current line */
- size_t minIndent = 1000000;
- size_t curIndent = 0;
- for (auto & [i_pos, i] : es) {
- auto * str = std::get_if<StringToken>(&i);
- if (!str || !str->hasIndentation) {
- /* Anti-quotations and escaped characters end the current start-of-line whitespace. */
- if (atStartOfLine) {
- atStartOfLine = false;
- if (curIndent < minIndent) minIndent = curIndent;
- }
- continue;
- }
- for (size_t j = 0; j < str->l; ++j) {
- if (atStartOfLine) {
- if (str->p[j] == ' ')
- curIndent++;
- else if (str->p[j] == '\n') {
- /* Empty line, doesn't influence minimum
- indentation. */
- curIndent = 0;
- } else {
- atStartOfLine = false;
- if (curIndent < minIndent) minIndent = curIndent;
- }
- } else if (str->p[j] == '\n') {
- atStartOfLine = true;
- curIndent = 0;
- }
- }
- }
-
- /* Strip spaces from each line. */
- auto * es2 = new std::vector<std::pair<PosIdx, Expr *>>;
- atStartOfLine = true;
- size_t curDropped = 0;
- size_t n = es.size();
- auto i = es.begin();
- const auto trimExpr = [&] (Expr * e) {
- atStartOfLine = false;
- curDropped = 0;
- es2->emplace_back(i->first, e);
- };
- const auto trimString = [&] (const StringToken & t) {
- std::string s2;
- for (size_t j = 0; j < t.l; ++j) {
- if (atStartOfLine) {
- if (t.p[j] == ' ') {
- if (curDropped++ >= minIndent)
- s2 += t.p[j];
- }
- else if (t.p[j] == '\n') {
- curDropped = 0;
- s2 += t.p[j];
- } else {
- atStartOfLine = false;
- curDropped = 0;
- s2 += t.p[j];
- }
- } else {
- s2 += t.p[j];
- if (t.p[j] == '\n') atStartOfLine = true;
- }
- }
-
- /* Remove the last line if it is empty and consists only of
- spaces. */
- if (n == 1) {
- std::string::size_type p = s2.find_last_of('\n');
- if (p != std::string::npos && s2.find_first_not_of(' ', p + 1) == std::string::npos)
- s2 = std::string(s2, 0, p + 1);
- }
-
- es2->emplace_back(i->first, new ExprString(std::move(s2)));
- };
- for (; i != es.end(); ++i, --n) {
- std::visit(overloaded { trimExpr, trimString }, i->second);
- }
-
- /* If this is a single string, then don't do a concatenation. */
- if (es2->size() == 1 && dynamic_cast<ExprString *>((*es2)[0].second)) {
- auto *const result = (*es2)[0].second;
- delete es2;
- return result;
- }
- return new ExprConcatStrings(pos, true, es2);
-}
-
-
-PosIdx ParseData::makeCurPos(const ParserLocation & loc)
-{
- return state.positions.add(origin, loc.first_line, loc.first_column);
-}
-
-#define CUR_POS data->makeCurPos(*yylocp)
-
-
-}
+#define CUR_POS state->makeCurPos(*yylocp)
-void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error)
+void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char * error)
{
throw ParseError({
.msg = hintfmt(error),
- .errPos = data->state.positions[data->makeCurPos(*loc)]
+ .errPos = state->state.positions[state->makeCurPos(*loc)]
});
}
@@ -338,13 +67,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
nix::Formal * formal;
nix::NixInt n;
nix::NixFloat nf;
- StringToken id; // !!! -> Symbol
- StringToken path;
- StringToken uri;
- StringToken str;
+ nix::StringToken id; // !!! -> Symbol
+ nix::StringToken path;
+ nix::StringToken uri;
+ nix::StringToken str;
std::vector<nix::AttrName> * attrNames;
std::vector<std::pair<nix::PosIdx, nix::Expr *>> * string_parts;
- std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, StringToken>>> * ind_string_parts;
+ std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, nix::StringToken>>> * ind_string_parts;
}
%type <e> start expr expr_function expr_if expr_op
@@ -384,24 +113,24 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%%
-start: expr { data->result = $1; };
+start: expr { state->result = $1; };
expr: expr_function;
expr_function
: ID ':' expr_function
- { $$ = new ExprLambda(CUR_POS, data->symbols.create($1), 0, $3); }
+ { $$ = new ExprLambda(CUR_POS, state->symbols.create($1), 0, $3); }
| '{' formals '}' ':' expr_function
- { $$ = new ExprLambda(CUR_POS, data->validateFormals($2), $5); }
+ { $$ = new ExprLambda(CUR_POS, state->validateFormals($2), $5); }
| '{' formals '}' '@' ID ':' expr_function
{
- auto arg = data->symbols.create($5);
- $$ = new ExprLambda(CUR_POS, arg, data->validateFormals($2, CUR_POS, arg), $7);
+ auto arg = state->symbols.create($5);
+ $$ = new ExprLambda(CUR_POS, arg, state->validateFormals($2, CUR_POS, arg), $7);
}
| ID '@' '{' formals '}' ':' expr_function
{
- auto arg = data->symbols.create($1);
- $$ = new ExprLambda(CUR_POS, arg, data->validateFormals($4, CUR_POS, arg), $7);
+ auto arg = state->symbols.create($1);
+ $$ = new ExprLambda(CUR_POS, arg, state->validateFormals($4, CUR_POS, arg), $7);
}
| ASSERT expr ';' expr_function
{ $$ = new ExprAssert(CUR_POS, $2, $4); }
@@ -411,7 +140,7 @@ expr_function
{ if (!$2->dynamicAttrs.empty())
throw ParseError({
.msg = hintfmt("dynamic attributes not allowed in let"),
- .errPos = data->state.positions[CUR_POS]
+ .errPos = state->state.positions[CUR_POS]
});
$$ = new ExprLet($2, $4);
}
@@ -425,24 +154,24 @@ expr_if
expr_op
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
- | '-' expr_op %prec NEGATE { $$ = new ExprCall(CUR_POS, new ExprVar(data->symbols.create("__sub")), {new ExprInt(0), $2}); }
+ | '-' expr_op %prec NEGATE { $$ = new ExprCall(CUR_POS, new ExprVar(state->symbols.create("__sub")), {new ExprInt(0), $2}); }
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
- | expr_op '<' expr_op { $$ = new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__lessThan")), {$1, $3}); }
- | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__lessThan")), {$3, $1})); }
- | expr_op '>' expr_op { $$ = new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__lessThan")), {$3, $1}); }
- | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__lessThan")), {$1, $3})); }
- | expr_op AND expr_op { $$ = new ExprOpAnd(data->makeCurPos(@2), $1, $3); }
- | expr_op OR expr_op { $$ = new ExprOpOr(data->makeCurPos(@2), $1, $3); }
- | expr_op IMPL expr_op { $$ = new ExprOpImpl(data->makeCurPos(@2), $1, $3); }
- | expr_op UPDATE expr_op { $$ = new ExprOpUpdate(data->makeCurPos(@2), $1, $3); }
+ | expr_op '<' expr_op { $$ = new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__lessThan")), {$1, $3}); }
+ | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__lessThan")), {$3, $1})); }
+ | expr_op '>' expr_op { $$ = new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__lessThan")), {$3, $1}); }
+ | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__lessThan")), {$1, $3})); }
+ | expr_op AND expr_op { $$ = new ExprOpAnd(state->makeCurPos(@2), $1, $3); }
+ | expr_op OR expr_op { $$ = new ExprOpOr(state->makeCurPos(@2), $1, $3); }
+ | expr_op IMPL expr_op { $$ = new ExprOpImpl(state->makeCurPos(@2), $1, $3); }
+ | expr_op UPDATE expr_op { $$ = new ExprOpUpdate(state->makeCurPos(@2), $1, $3); }
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, std::move(*$3)); delete $3; }
| expr_op '+' expr_op
- { $$ = new ExprConcatStrings(data->makeCurPos(@2), false, new std::vector<std::pair<PosIdx, Expr *> >({{data->makeCurPos(@1), $1}, {data->makeCurPos(@3), $3}})); }
- | expr_op '-' expr_op { $$ = new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__sub")), {$1, $3}); }
- | expr_op '*' expr_op { $$ = new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__mul")), {$1, $3}); }
- | expr_op '/' expr_op { $$ = new ExprCall(data->makeCurPos(@2), new ExprVar(data->symbols.create("__div")), {$1, $3}); }
- | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(data->makeCurPos(@2), $1, $3); }
+ { $$ = new ExprConcatStrings(state->makeCurPos(@2), false, new std::vector<std::pair<PosIdx, Expr *> >({{state->makeCurPos(@1), $1}, {state->makeCurPos(@3), $3}})); }
+ | expr_op '-' expr_op { $$ = new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__sub")), {$1, $3}); }
+ | expr_op '*' expr_op { $$ = new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__mul")), {$1, $3}); }
+ | expr_op '/' expr_op { $$ = new ExprCall(state->makeCurPos(@2), new ExprVar(state->symbols.create("__div")), {$1, $3}); }
+ | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(state->makeCurPos(@2), $1, $3); }
| expr_app
;
@@ -465,7 +194,7 @@ expr_select
| /* Backwards compatibility: because Nixpkgs has a rarely used
function named ‘or’, allow stuff like ‘map or [...]’. */
expr_simple OR_KW
- { $$ = new ExprCall(CUR_POS, $1, {new ExprVar(CUR_POS, data->symbols.create("or"))}); }
+ { $$ = new ExprCall(CUR_POS, $1, {new ExprVar(CUR_POS, state->symbols.create("or"))}); }
| expr_simple
;
@@ -475,25 +204,25 @@ expr_simple
if ($1.l == s.size() && strncmp($1.p, s.data(), s.size()) == 0)
$$ = new ExprPos(CUR_POS);
else
- $$ = new ExprVar(CUR_POS, data->symbols.create($1));
+ $$ = new ExprVar(CUR_POS, state->symbols.create($1));
}
| INT { $$ = new ExprInt($1); }
| FLOAT { $$ = new ExprFloat($1); }
| '"' string_parts '"' { $$ = $2; }
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
- $$ = data->stripIndentation(CUR_POS, std::move(*$2));
+ $$ = state->stripIndentation(CUR_POS, std::move(*$2));
delete $2;
}
| path_start PATH_END
| path_start string_parts_interpolated PATH_END {
- $2->insert($2->begin(), {data->makeCurPos(@1), $1});
+ $2->insert($2->begin(), {state->makeCurPos(@1), $1});
$$ = new ExprConcatStrings(CUR_POS, false, $2);
}
| SPATH {
std::string path($1.p + 1, $1.l - 2);
$$ = new ExprCall(CUR_POS,
- new ExprVar(data->symbols.create("__findFile")),
- {new ExprVar(data->symbols.create("__nixPath")),
+ new ExprVar(state->symbols.create("__findFile")),
+ {new ExprVar(state->symbols.create("__nixPath")),
new ExprString(std::move(path))});
}
| URI {
@@ -501,7 +230,7 @@ expr_simple
if (noURLLiterals)
throw ParseError({
.msg = hintfmt("URL literals are disabled"),
- .errPos = data->state.positions[CUR_POS]
+ .errPos = state->state.positions[CUR_POS]
});
$$ = new ExprString(std::string($1));
}
@@ -509,7 +238,7 @@ expr_simple
/* Let expressions `let {..., body = ...}' are just desugared
into `(rec {..., body = ...}).body'. */
| LET '{' binds '}'
- { $3->recursive = true; $$ = new ExprSelect(noPos, $3, data->symbols.create("body")); }
+ { $3->recursive = true; $$ = new ExprSelect(noPos, $3, state->symbols.create("body")); }
| REC '{' binds '}'
{ $3->recursive = true; $$ = $3; }
| '{' binds '}'
@@ -525,19 +254,19 @@ string_parts
string_parts_interpolated
: string_parts_interpolated STR
- { $$ = $1; $1->emplace_back(data->makeCurPos(@2), new ExprString(std::string($2))); }
- | string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(data->makeCurPos(@2), $3); }
- | DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<PosIdx, Expr *>>; $$->emplace_back(data->makeCurPos(@1), $2); }
+ { $$ = $1; $1->emplace_back(state->makeCurPos(@2), new ExprString(std::string($2))); }
+ | string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(state->makeCurPos(@2), $3); }
+ | DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<PosIdx, Expr *>>; $$->emplace_back(state->makeCurPos(@1), $2); }
| STR DOLLAR_CURLY expr '}' {
$$ = new std::vector<std::pair<PosIdx, Expr *>>;
- $$->emplace_back(data->makeCurPos(@1), new ExprString(std::string($1)));
- $$->emplace_back(data->makeCurPos(@2), $3);
+ $$->emplace_back(state->makeCurPos(@1), new ExprString(std::string($1)));
+ $$->emplace_back(state->makeCurPos(@2), $3);
}
;
path_start
: PATH {
- Path path(absPath({$1.p, $1.l}, data->basePath.path.abs()));
+ Path path(absPath({$1.p, $1.l}, state->basePath.path.abs()));
/* add back in the trailing '/' to the first segment */
if ($1.p[$1.l-1] == '/' && $1.l > 1)
path += "/";
@@ -556,19 +285,19 @@ path_start
;
ind_string_parts
- : ind_string_parts IND_STR { $$ = $1; $1->emplace_back(data->makeCurPos(@2), $2); }
- | ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(data->makeCurPos(@2), $3); }
+ : ind_string_parts IND_STR { $$ = $1; $1->emplace_back(state->makeCurPos(@2), $2); }
+ | ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(state->makeCurPos(@2), $3); }
| { $$ = new std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>>; }
;
binds
- : binds attrpath '=' expr ';' { $$ = $1; data->addAttr($$, std::move(*$2), $4, data->makeCurPos(@2)); delete $2; }
+ : binds attrpath '=' expr ';' { $$ = $1; state->addAttr($$, std::move(*$2), $4, state->makeCurPos(@2)); delete $2; }
| binds INHERIT attrs ';'
{ $$ = $1;
for (auto & i : *$3) {
if ($$->attrs.find(i.symbol) != $$->attrs.end())
- data->dupAttr(i.symbol, data->makeCurPos(@3), $$->attrs[i.symbol].pos);
- auto pos = data->makeCurPos(@3);
+ state->dupAttr(i.symbol, state->makeCurPos(@3), $$->attrs[i.symbol].pos);
+ auto pos = state->makeCurPos(@3);
$$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprVar(CUR_POS, i.symbol), pos, true));
}
delete $3;
@@ -578,48 +307,48 @@ binds
/* !!! Should ensure sharing of the expression in $4. */
for (auto & i : *$6) {
if ($$->attrs.find(i.symbol) != $$->attrs.end())
- data->dupAttr(i.symbol, data->makeCurPos(@6), $$->attrs[i.symbol].pos);
- $$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), data->makeCurPos(@6)));
+ state->dupAttr(i.symbol, state->makeCurPos(@6), $$->attrs[i.symbol].pos);
+ $$->attrs.emplace(i.symbol, ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), state->makeCurPos(@6)));
}
delete $6;
}
- | { $$ = new ExprAttrs(data->makeCurPos(@0)); }
+ | { $$ = new ExprAttrs(state->makeCurPos(@0)); }
;
attrs
- : attrs attr { $$ = $1; $1->push_back(AttrName(data->symbols.create($2))); }
+ : attrs attr { $$ = $1; $1->push_back(AttrName(state->symbols.create($2))); }
| attrs string_attr
{ $$ = $1;
ExprString * str = dynamic_cast<ExprString *>($2);
if (str) {
- $$->push_back(AttrName(data->symbols.create(str->s)));
+ $$->push_back(AttrName(state->symbols.create(str->s)));
delete str;
} else
throw ParseError({
.msg = hintfmt("dynamic attributes not allowed in inherit"),
- .errPos = data->state.positions[data->makeCurPos(@2)]
+ .errPos = state->state.positions[state->makeCurPos(@2)]
});
}
| { $$ = new AttrPath; }
;
attrpath
- : attrpath '.' attr { $$ = $1; $1->push_back(AttrName(data->symbols.create($3))); }
+ : attrpath '.' attr { $$ = $1; $1->push_back(AttrName(state->symbols.create($3))); }
| attrpath '.' string_attr
{ $$ = $1;
ExprString * str = dynamic_cast<ExprString *>($3);
if (str) {
- $$->push_back(AttrName(data->symbols.create(str->s)));
+ $$->push_back(AttrName(state->symbols.create(str->s)));
delete str;
} else
$$->push_back(AttrName($3));
}
- | attr { $$ = new std::vector<AttrName>; $$->push_back(AttrName(data->symbols.create($1))); }
+ | attr { $$ = new std::vector<AttrName>; $$->push_back(AttrName(state->symbols.create($1))); }
| string_attr
{ $$ = new std::vector<AttrName>;
ExprString *str = dynamic_cast<ExprString *>($1);
if (str) {
- $$->push_back(AttrName(data->symbols.create(str->s)));
+ $$->push_back(AttrName(state->symbols.create(str->s)));
delete str;
} else
$$->push_back(AttrName($1));
@@ -653,8 +382,8 @@ formals
;
formal
- : ID { $$ = new Formal{CUR_POS, data->symbols.create($1), 0}; }
- | ID '?' expr { $$ = new Formal{CUR_POS, data->symbols.create($1), $3}; }
+ : ID { $$ = new Formal{CUR_POS, state->symbols.create($1), 0}; }
+ | ID '?' expr { $$ = new Formal{CUR_POS, state->symbols.create($1), $3}; }
;
%%
@@ -683,7 +412,7 @@ Expr * EvalState::parse(
std::shared_ptr<StaticEnv> & staticEnv)
{
yyscan_t scanner;
- ParseData data {
+ ParserState state {
.state = *this,
.symbols = symbols,
.basePath = basePath,
@@ -694,11 +423,11 @@ Expr * EvalState::parse(
Finally _destroy([&] { yylex_destroy(scanner); });
yy_scan_buffer(text, length, scanner);
- yyparse(scanner, &data);
+ yyparse(scanner, &state);
- data.result->bindVars(*this, staticEnv);
+ state.result->bindVars(*this, staticEnv);
- return data.result;
+ return state.result;
}