decouple parser and EvalState

there's no reason the parser itself should be doing semantic analysis
like bindVars. split this bit apart (retaining the previous name in
EvalState) and have the parser really do *only* parsing, decoupled from
EvalState.
This commit is contained in:
pennae 2024-01-15 16:52:18 +01:00
parent e1aa585964
commit b596cc9e79
4 changed files with 53 additions and 22 deletions

View File

@ -22,6 +22,7 @@
#include "fetch-to-store.hh"
#include "tarball.hh"
#include "flake/flakeref.hh"
#include "parser-tab.hh"
#include <algorithm>
#include <chrono>
@ -2800,6 +2801,21 @@ std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Pa
}
Expr * EvalState::parse(
char * text,
size_t length,
Pos::Origin origin,
const SourcePath & basePath,
std::shared_ptr<StaticEnv> & staticEnv)
{
auto result = parseExprFromBuf(text, length, origin, basePath, symbols, positions, rootFS);
result->bindVars(*this, staticEnv);
return result;
}
std::string ExternalValueBase::coerceToString(const Pos & pos, NixStringContext & context, bool copyMore, bool copyToStore) const
{
throw TypeError({

View File

@ -148,7 +148,7 @@ or { return OR_KW; }
} catch (const boost::bad_lexical_cast &) {
throw ParseError({
.msg = hintfmt("invalid integer '%1%'", yytext),
.errPos = state->state.positions[CUR_POS],
.errPos = state->positions[CUR_POS],
});
}
return INT_LIT;
@ -158,7 +158,7 @@ or { return OR_KW; }
if (errno != 0)
throw ParseError({
.msg = hintfmt("invalid float '%1%'", yytext),
.errPos = state->state.positions[CUR_POS],
.errPos = state->positions[CUR_POS],
});
return FLOAT_LIT;
}
@ -287,7 +287,7 @@ or { return OR_KW; }
<INPATH_SLASH><<EOF>> {
throw ParseError({
.msg = hintfmt("path has a trailing slash"),
.errPos = state->state.positions[CUR_POS],
.errPos = state->positions[CUR_POS],
});
}

View File

@ -37,11 +37,12 @@ struct ParserLocation {
};
struct ParserState {
EvalState & state;
SymbolTable & symbols;
PosTable & positions;
Expr * result;
SourcePath basePath;
PosTable::Origin origin;
const ref<InputAccessor> rootFS;
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
@ -56,16 +57,16 @@ inline void ParserState::dupAttr(const AttrPath & attrPath, const PosIdx pos, co
{
throw ParseError({
.msg = hintfmt("attribute '%1%' already defined at %2%",
showAttrPath(state.symbols, attrPath), state.positions[prevPos]),
.errPos = state.positions[pos]
showAttrPath(symbols, attrPath), positions[prevPos]),
.errPos = 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]
.msg = hintfmt("attribute '%1%' already defined at %2%", symbols[attr], positions[prevPos]),
.errPos = positions[pos]
});
}
@ -146,13 +147,13 @@ inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Sym
if (duplicate)
throw ParseError({
.msg = hintfmt("duplicate formal function argument '%1%'", symbols[duplicate->first]),
.errPos = state.positions[duplicate->second]
.errPos = positions[duplicate->second]
});
if (arg && formals->has(arg))
throw ParseError({
.msg = hintfmt("duplicate formal function argument '%1%'", symbols[arg]),
.errPos = state.positions[pos]
.errPos = positions[pos]
});
return formals;
@ -256,7 +257,7 @@ inline Expr * ParserState::stripIndentation(const PosIdx pos,
inline PosIdx ParserState::at(const ParserLocation & loc)
{
return state.positions.add(origin, loc.first_line, loc.first_column);
return positions.add(origin, loc.first_line, loc.first_column);
}
}

View File

@ -32,6 +32,19 @@
#define YY_DECL int yylex \
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param, yyscan_t yyscanner, nix::ParserState * state)
namespace nix {
Expr * parseExprFromBuf(
char * text,
size_t length,
Pos::Origin origin,
const SourcePath & basePath,
SymbolTable & symbols,
PosTable & positions,
const ref<InputAccessor> rootFS);
}
#endif
}
@ -52,7 +65,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char *
{
throw ParseError({
.msg = hintfmt(error),
.errPos = state->state.positions[state->at(*loc)]
.errPos = state->positions[state->at(*loc)]
});
}
@ -141,7 +154,7 @@ expr_function
{ if (!$2->dynamicAttrs.empty())
throw ParseError({
.msg = hintfmt("dynamic attributes not allowed in let"),
.errPos = state->state.positions[CUR_POS]
.errPos = state->positions[CUR_POS]
});
$$ = new ExprLet($2, $4);
}
@ -231,7 +244,7 @@ expr_simple
if (noURLLiterals)
throw ParseError({
.msg = hintfmt("URL literals are disabled"),
.errPos = state->state.positions[CUR_POS]
.errPos = state->positions[CUR_POS]
});
$$ = new ExprString(std::string($1));
}
@ -271,7 +284,7 @@ path_start
/* add back in the trailing '/' to the first segment */
if ($1.p[$1.l-1] == '/' && $1.l > 1)
path += "/";
$$ = new ExprPath(ref<InputAccessor>(state->state.rootFS), std::move(path));
$$ = new ExprPath(ref<InputAccessor>(state->rootFS), std::move(path));
}
| HPATH {
if (evalSettings.pureEval) {
@ -281,7 +294,7 @@ path_start
);
}
Path path(getHome() + std::string($1.p + 1, $1.l - 1));
$$ = new ExprPath(ref<InputAccessor>(state->state.rootFS), std::move(path));
$$ = new ExprPath(ref<InputAccessor>(state->rootFS), std::move(path));
}
;
@ -327,7 +340,7 @@ attrs
} else
throw ParseError({
.msg = hintfmt("dynamic attributes not allowed in inherit"),
.errPos = state->state.positions[state->at(@2)]
.errPos = state->positions[state->at(@2)]
});
}
| { $$ = new AttrPath; }
@ -394,19 +407,22 @@ formal
namespace nix {
Expr * EvalState::parse(
Expr * parseExprFromBuf(
char * text,
size_t length,
Pos::Origin origin,
const SourcePath & basePath,
std::shared_ptr<StaticEnv> & staticEnv)
SymbolTable & symbols,
PosTable & positions,
const ref<InputAccessor> rootFS)
{
yyscan_t scanner;
ParserState state {
.state = *this,
.symbols = symbols,
.positions = positions,
.basePath = basePath,
.origin = {origin},
.rootFS = rootFS,
};
yylex_init(&scanner);
@ -415,8 +431,6 @@ Expr * EvalState::parse(
yy_scan_buffer(text, length, scanner);
yyparse(scanner, &state);
state.result->bindVars(*this, staticEnv);
return state.result;
}