forked from lix-project/lix
don't immediately throw parser errors
now that destructors are hooked up we want to give the C skeleton a
chance to actually run them. since bison does not call destructors on
values that have been passed to semantic actions even when the action
causes an abort we will also have to do some manual deleting.
partially reverts e8d9de967f
.
This commit is contained in:
parent
ceacc823c7
commit
6bcdd2c39a
|
@ -27,6 +27,12 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
|
#define THROW(...) \
|
||||||
|
do { \
|
||||||
|
state->error.reset(new auto(__VA_ARGS__)); \
|
||||||
|
return YYerror; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
#define CUR_POS state->at(*yylloc)
|
#define CUR_POS state->at(*yylloc)
|
||||||
|
@ -129,20 +135,20 @@ or { return OR_KW; }
|
||||||
try {
|
try {
|
||||||
yylval->n = boost::lexical_cast<int64_t>(yytext);
|
yylval->n = boost::lexical_cast<int64_t>(yytext);
|
||||||
} catch (const boost::bad_lexical_cast &) {
|
} catch (const boost::bad_lexical_cast &) {
|
||||||
throw ParseError(ErrorInfo{
|
THROW(ParseError({
|
||||||
.msg = HintFmt("invalid integer '%1%'", yytext),
|
.msg = HintFmt("invalid integer '%1%'", yytext),
|
||||||
.pos = state->positions[CUR_POS],
|
.pos = state->positions[CUR_POS],
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
return INT_LIT;
|
return INT_LIT;
|
||||||
}
|
}
|
||||||
{FLOAT} { errno = 0;
|
{FLOAT} { errno = 0;
|
||||||
yylval->nf = strtod(yytext, 0);
|
yylval->nf = strtod(yytext, 0);
|
||||||
if (errno != 0)
|
if (errno != 0)
|
||||||
throw ParseError(ErrorInfo{
|
THROW(ParseError({
|
||||||
.msg = HintFmt("invalid float '%1%'", yytext),
|
.msg = HintFmt("invalid float '%1%'", yytext),
|
||||||
.pos = state->positions[CUR_POS],
|
.pos = state->positions[CUR_POS],
|
||||||
});
|
}));
|
||||||
return FLOAT_LIT;
|
return FLOAT_LIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,10 +274,10 @@ or { return OR_KW; }
|
||||||
|
|
||||||
<INPATH_SLASH>{ANY} |
|
<INPATH_SLASH>{ANY} |
|
||||||
<INPATH_SLASH><<EOF>> {
|
<INPATH_SLASH><<EOF>> {
|
||||||
throw ParseError(ErrorInfo{
|
THROW(ParseError({
|
||||||
.msg = HintFmt("path has a trailing slash"),
|
.msg = HintFmt("path has a trailing slash"),
|
||||||
.pos = state->positions[CUR_POS],
|
.pos = state->positions[CUR_POS],
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
{SPATH} { yylval->path = {yytext, (size_t) yyleng}; return SPATH; }
|
{SPATH} { yylval->path = {yytext, (size_t) yyleng}; return SPATH; }
|
||||||
|
|
|
@ -46,34 +46,35 @@ struct ParserState
|
||||||
PosTable::Origin origin;
|
PosTable::Origin origin;
|
||||||
const ref<InputAccessor> rootFS;
|
const ref<InputAccessor> rootFS;
|
||||||
const Expr::AstSymbols & s;
|
const Expr::AstSymbols & s;
|
||||||
|
std::unique_ptr<Error> error;
|
||||||
|
|
||||||
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
|
[[nodiscard]] ParseError dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
|
||||||
void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
|
[[nodiscard]] ParseError dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
|
||||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos);
|
[[nodiscard]] std::optional<ParseError> addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos);
|
||||||
Formals * validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
|
[[nodiscard]] std::optional<ParseError> validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
|
||||||
Expr * stripIndentation(const PosIdx pos,
|
Expr * stripIndentation(const PosIdx pos,
|
||||||
std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
|
std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
|
||||||
PosIdx at(const ParserLocation & loc);
|
PosIdx at(const ParserLocation & loc);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void ParserState::dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos)
|
inline ParseError ParserState::dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos)
|
||||||
{
|
{
|
||||||
throw ParseError({
|
return ParseError({
|
||||||
.msg = HintFmt("attribute '%1%' already defined at %2%",
|
.msg = HintFmt("attribute '%1%' already defined at %2%",
|
||||||
showAttrPath(symbols, attrPath), positions[prevPos]),
|
showAttrPath(symbols, attrPath), positions[prevPos]),
|
||||||
.pos = positions[pos]
|
.pos = positions[pos]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ParserState::dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos)
|
inline ParseError ParserState::dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos)
|
||||||
{
|
{
|
||||||
throw ParseError({
|
return ParseError({
|
||||||
.msg = HintFmt("attribute '%1%' already defined at %2%", symbols[attr], positions[prevPos]),
|
.msg = HintFmt("attribute '%1%' already defined at %2%", symbols[attr], positions[prevPos]),
|
||||||
.pos = positions[pos]
|
.pos = positions[pos]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos)
|
inline std::optional<ParseError> ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos)
|
||||||
{
|
{
|
||||||
AttrPath::iterator i;
|
AttrPath::iterator i;
|
||||||
// All attrpaths have at least one attr
|
// All attrpaths have at least one attr
|
||||||
|
@ -86,10 +87,10 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr *
|
||||||
if (j != attrs->attrs.end()) {
|
if (j != attrs->attrs.end()) {
|
||||||
if (j->second.kind != ExprAttrs::AttrDef::Kind::Inherited) {
|
if (j->second.kind != ExprAttrs::AttrDef::Kind::Inherited) {
|
||||||
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
|
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||||
if (!attrs2) dupAttr(attrPath, pos, j->second.pos);
|
if (!attrs2) return dupAttr(attrPath, pos, j->second.pos);
|
||||||
attrs = attrs2;
|
attrs = attrs2;
|
||||||
} else
|
} else
|
||||||
dupAttr(attrPath, pos, j->second.pos);
|
return dupAttr(attrPath, pos, j->second.pos);
|
||||||
} else {
|
} else {
|
||||||
ExprAttrs * nested = new ExprAttrs;
|
ExprAttrs * nested = new ExprAttrs;
|
||||||
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
|
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
|
||||||
|
@ -118,7 +119,7 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr *
|
||||||
for (auto & ad : ae->attrs) {
|
for (auto & ad : ae->attrs) {
|
||||||
auto j2 = jAttrs->attrs.find(ad.first);
|
auto j2 = jAttrs->attrs.find(ad.first);
|
||||||
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
|
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
|
||||||
dupAttr(ad.first, j2->second.pos, ad.second.pos);
|
return dupAttr(ad.first, j2->second.pos, ad.second.pos);
|
||||||
jAttrs->attrs.emplace(ad.first, ad.second);
|
jAttrs->attrs.emplace(ad.first, ad.second);
|
||||||
if (ad.second.kind == ExprAttrs::AttrDef::Kind::InheritedFrom) {
|
if (ad.second.kind == ExprAttrs::AttrDef::Kind::InheritedFrom) {
|
||||||
auto & sel = dynamic_cast<ExprSelect &>(*ad.second.e);
|
auto & sel = dynamic_cast<ExprSelect &>(*ad.second.e);
|
||||||
|
@ -132,7 +133,7 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr *
|
||||||
ae->inheritFromExprs->begin(), ae->inheritFromExprs->end());
|
ae->inheritFromExprs->begin(), ae->inheritFromExprs->end());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dupAttr(attrPath, pos, j->second.pos);
|
return dupAttr(attrPath, pos, j->second.pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This attr path is not defined. Let's create it.
|
// This attr path is not defined. Let's create it.
|
||||||
|
@ -142,9 +143,11 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr *
|
||||||
} else {
|
} else {
|
||||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
|
inline std::optional<ParseError> ParserState::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
|
||||||
{
|
{
|
||||||
std::sort(formals->formals.begin(), formals->formals.end(),
|
std::sort(formals->formals.begin(), formals->formals.end(),
|
||||||
[] (const auto & a, const auto & b) {
|
[] (const auto & a, const auto & b) {
|
||||||
|
@ -159,18 +162,18 @@ inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Sym
|
||||||
duplicate = std::min(thisDup, duplicate.value_or(thisDup));
|
duplicate = std::min(thisDup, duplicate.value_or(thisDup));
|
||||||
}
|
}
|
||||||
if (duplicate)
|
if (duplicate)
|
||||||
throw ParseError({
|
return ParseError({
|
||||||
.msg = HintFmt("duplicate formal function argument '%1%'", symbols[duplicate->first]),
|
.msg = HintFmt("duplicate formal function argument '%1%'", symbols[duplicate->first]),
|
||||||
.pos = positions[duplicate->second]
|
.pos = positions[duplicate->second]
|
||||||
});
|
});
|
||||||
|
|
||||||
if (arg && formals->has(arg))
|
if (arg && formals->has(arg))
|
||||||
throw ParseError({
|
return ParseError({
|
||||||
.msg = HintFmt("duplicate formal function argument '%1%'", symbols[arg]),
|
.msg = HintFmt("duplicate formal function argument '%1%'", symbols[arg]),
|
||||||
.pos = positions[pos]
|
.pos = positions[pos]
|
||||||
});
|
});
|
||||||
|
|
||||||
return formals;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Expr * ParserState::stripIndentation(const PosIdx pos,
|
inline Expr * ParserState::stripIndentation(const PosIdx pos,
|
||||||
|
|
|
@ -64,6 +64,13 @@ using namespace nix;
|
||||||
// otherwise destructors cause compiler errors
|
// otherwise destructors cause compiler errors
|
||||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
|
|
||||||
|
#define THROW(err, ...) \
|
||||||
|
do { \
|
||||||
|
state->error.reset(new auto(err)); \
|
||||||
|
[](auto... d) { (delete d, ...); }(__VA_ARGS__); \
|
||||||
|
YYABORT; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char * error)
|
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char * error)
|
||||||
{
|
{
|
||||||
if (std::string_view(error).starts_with("syntax error, unexpected end of file")) {
|
if (std::string_view(error).starts_with("syntax error, unexpected end of file")) {
|
||||||
|
@ -155,16 +162,19 @@ expr_function
|
||||||
: ID ':' expr_function
|
: ID ':' expr_function
|
||||||
{ $$ = new ExprLambda(CUR_POS, state->symbols.create($1), 0, $3); }
|
{ $$ = new ExprLambda(CUR_POS, state->symbols.create($1), 0, $3); }
|
||||||
| '{' formals '}' ':' expr_function
|
| '{' formals '}' ':' expr_function
|
||||||
{ $$ = new ExprLambda(CUR_POS, state->validateFormals($2), $5); }
|
{ if (auto e = state->validateFormals($2)) THROW(*e);
|
||||||
|
$$ = new ExprLambda(CUR_POS, $2, $5); }
|
||||||
| '{' formals '}' '@' ID ':' expr_function
|
| '{' formals '}' '@' ID ':' expr_function
|
||||||
{
|
{
|
||||||
auto arg = state->symbols.create($5);
|
auto arg = state->symbols.create($5);
|
||||||
$$ = new ExprLambda(CUR_POS, arg, state->validateFormals($2, CUR_POS, arg), $7);
|
if (auto e = state->validateFormals($2, CUR_POS, arg)) THROW(*e, $2, $7);
|
||||||
|
$$ = new ExprLambda(CUR_POS, arg, $2, $7);
|
||||||
}
|
}
|
||||||
| ID '@' '{' formals '}' ':' expr_function
|
| ID '@' '{' formals '}' ':' expr_function
|
||||||
{
|
{
|
||||||
auto arg = state->symbols.create($1);
|
auto arg = state->symbols.create($1);
|
||||||
$$ = new ExprLambda(CUR_POS, arg, state->validateFormals($4, CUR_POS, arg), $7);
|
if (auto e = state->validateFormals($4, CUR_POS, arg)) THROW(*e, $4, $7);
|
||||||
|
$$ = new ExprLambda(CUR_POS, arg, $4, $7);
|
||||||
}
|
}
|
||||||
| ASSERT expr ';' expr_function
|
| ASSERT expr ';' expr_function
|
||||||
{ $$ = new ExprAssert(CUR_POS, $2, $4); }
|
{ $$ = new ExprAssert(CUR_POS, $2, $4); }
|
||||||
|
@ -172,10 +182,10 @@ expr_function
|
||||||
{ $$ = new ExprWith(CUR_POS, $2, $4); }
|
{ $$ = new ExprWith(CUR_POS, $2, $4); }
|
||||||
| LET binds IN_KW expr_function
|
| LET binds IN_KW expr_function
|
||||||
{ if (!$2->dynamicAttrs.empty())
|
{ if (!$2->dynamicAttrs.empty())
|
||||||
throw ParseError({
|
THROW(ParseError({
|
||||||
.msg = HintFmt("dynamic attributes not allowed in let"),
|
.msg = HintFmt("dynamic attributes not allowed in let"),
|
||||||
.pos = state->positions[CUR_POS]
|
.pos = state->positions[CUR_POS]
|
||||||
});
|
}), $2, $4);
|
||||||
$$ = new ExprLet($2, $4);
|
$$ = new ExprLet($2, $4);
|
||||||
}
|
}
|
||||||
| expr_if
|
| expr_if
|
||||||
|
@ -262,10 +272,10 @@ expr_simple
|
||||||
| URI {
|
| URI {
|
||||||
static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals);
|
static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals);
|
||||||
if (noURLLiterals)
|
if (noURLLiterals)
|
||||||
throw ParseError({
|
THROW(ParseError({
|
||||||
.msg = HintFmt("URL literals are disabled"),
|
.msg = HintFmt("URL literals are disabled"),
|
||||||
.pos = state->positions[CUR_POS]
|
.pos = state->positions[CUR_POS]
|
||||||
});
|
}));
|
||||||
$$ = new ExprString(std::string($1));
|
$$ = new ExprString(std::string($1));
|
||||||
}
|
}
|
||||||
| '(' expr ')' { $$ = $2; }
|
| '(' expr ')' { $$ = $2; }
|
||||||
|
@ -308,10 +318,10 @@ path_start
|
||||||
}
|
}
|
||||||
| HPATH {
|
| HPATH {
|
||||||
if (evalSettings.pureEval) {
|
if (evalSettings.pureEval) {
|
||||||
throw Error(
|
THROW(Error(
|
||||||
"the path '%s' can not be resolved in pure mode",
|
"the path '%s' can not be resolved in pure mode",
|
||||||
std::string_view($1.p, $1.l)
|
std::string_view($1.p, $1.l)
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
Path path(getHome() + std::string($1.p + 1, $1.l - 1));
|
Path path(getHome() + std::string($1.p + 1, $1.l - 1));
|
||||||
$$ = new ExprPath(ref<InputAccessor>(state->rootFS), std::move(path));
|
$$ = new ExprPath(ref<InputAccessor>(state->rootFS), std::move(path));
|
||||||
|
@ -325,12 +335,16 @@ ind_string_parts
|
||||||
;
|
;
|
||||||
|
|
||||||
binds
|
binds
|
||||||
: binds attrpath '=' expr ';' { $$ = $1; state->addAttr($$, std::move(*$2), $4, state->at(@2)); delete $2; }
|
: binds attrpath '=' expr ';'
|
||||||
|
{ $$ = $1;
|
||||||
|
if (auto e = state->addAttr($$, std::move(*$2), $4, state->at(@2))) THROW(*e, $1, $2);
|
||||||
|
delete $2;
|
||||||
|
}
|
||||||
| binds INHERIT attrs ';'
|
| binds INHERIT attrs ';'
|
||||||
{ $$ = $1;
|
{ $$ = $1;
|
||||||
for (auto & [i, iPos] : *$3) {
|
for (auto & [i, iPos] : *$3) {
|
||||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||||
state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos);
|
THROW(state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos), $1);
|
||||||
$$->attrs.emplace(
|
$$->attrs.emplace(
|
||||||
i.symbol,
|
i.symbol,
|
||||||
ExprAttrs::AttrDef(new ExprVar(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited));
|
ExprAttrs::AttrDef(new ExprVar(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited));
|
||||||
|
@ -345,7 +359,7 @@ binds
|
||||||
auto from = new nix::ExprInheritFrom(state->at(@4), $$->inheritFromExprs->size() - 1);
|
auto from = new nix::ExprInheritFrom(state->at(@4), $$->inheritFromExprs->size() - 1);
|
||||||
for (auto & [i, iPos] : *$6) {
|
for (auto & [i, iPos] : *$6) {
|
||||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||||
state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos);
|
THROW(state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos), $1);
|
||||||
$$->attrs.emplace(
|
$$->attrs.emplace(
|
||||||
i.symbol,
|
i.symbol,
|
||||||
ExprAttrs::AttrDef(
|
ExprAttrs::AttrDef(
|
||||||
|
@ -367,10 +381,10 @@ attrs
|
||||||
$$->emplace_back(AttrName(state->symbols.create(str->s)), state->at(@2));
|
$$->emplace_back(AttrName(state->symbols.create(str->s)), state->at(@2));
|
||||||
delete str;
|
delete str;
|
||||||
} else
|
} else
|
||||||
throw ParseError({
|
THROW(ParseError({
|
||||||
.msg = HintFmt("dynamic attributes not allowed in inherit"),
|
.msg = HintFmt("dynamic attributes not allowed in inherit"),
|
||||||
.pos = state->positions[state->at(@2)]
|
.pos = state->positions[state->at(@2)]
|
||||||
});
|
}), $1, $2);
|
||||||
}
|
}
|
||||||
| { $$ = new std::vector<std::pair<AttrName, PosIdx>>; }
|
| { $$ = new std::vector<std::pair<AttrName, PosIdx>>; }
|
||||||
;
|
;
|
||||||
|
@ -461,6 +475,10 @@ Expr * parseExprFromBuf(
|
||||||
|
|
||||||
yy_scan_buffer(text, length, scanner);
|
yy_scan_buffer(text, length, scanner);
|
||||||
yyparse(scanner, &state);
|
yyparse(scanner, &state);
|
||||||
|
if (state.error) {
|
||||||
|
delete state.result;
|
||||||
|
throw *state.error;
|
||||||
|
}
|
||||||
|
|
||||||
return state.result;
|
return state.result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue