Show the exact position of undefined variables

In particular, undefined variable errors in a "with" previously didn't
show *any* position information, so this should help a lot in those
cases.
This commit is contained in:
Eelco Dolstra 2013-10-08 14:40:51 +02:00
parent a5e0f64db3
commit 6b47de580f
4 changed files with 18 additions and 21 deletions

View file

@ -315,7 +315,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
return j->value; return j->value;
} }
if (!env->prevWith) if (!env->prevWith)
throwEvalError("undefined variable `%1%'", var.name); throw EvalError(format("undefined variable `%1%' at %2%") % var.name % var.pos);
for (unsigned int l = env->prevWith; l; --l, env = env->up) ; for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
} }
} }

View file

@ -198,7 +198,7 @@ void ExprVar::bindVars(const StaticEnv & env)
/* Otherwise, the variable must be obtained from the nearest /* Otherwise, the variable must be obtained from the nearest
enclosing `with'. If there is no `with', then we can issue an enclosing `with'. If there is no `with', then we can issue an
"undefined variable" error now. */ "undefined variable" error now. */
if (withLevel == -1) throw EvalError(format("undefined variable `%1%'") % name); if (withLevel == -1) throw ParseError(format("undefined variable `%1%' at %2%") % name % pos);
fromWith = true; fromWith = true;
this->level = withLevel; this->level = withLevel;

View file

@ -109,6 +109,7 @@ struct ExprPath : Expr
struct ExprVar : Expr struct ExprVar : Expr
{ {
Pos pos;
Symbol name; Symbol name;
/* Whether the variable comes from an environment (e.g. a rec, let /* Whether the variable comes from an environment (e.g. a rec, let
@ -124,7 +125,7 @@ struct ExprVar : Expr
unsigned int level; unsigned int level;
unsigned int displ; unsigned int displ;
ExprVar(const Symbol & name) : name(name) { }; ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
COMMON_METHODS COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env); Value * maybeThunk(EvalState & state, Env & env);
}; };

View file

@ -310,13 +310,13 @@ expr_if
expr_op expr_op
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); } : '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
| '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__sub")), new ExprInt(0)), $2); } | '-' expr_op %prec NEGATE { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), new ExprInt(0)), $2); }
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); } | expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); } | expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
| expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3); } | expr_op '<' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3); }
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1)); } | expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1)); }
| expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $3), $1); } | expr_op '>' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $3), $1); }
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__lessThan")), $1), $3)); } | expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__lessThan")), $1), $3)); }
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); } | expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); } | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); } | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
@ -328,9 +328,9 @@ expr_op
l->push_back($3); l->push_back($3);
$$ = new ExprConcatStrings(false, l); $$ = new ExprConcatStrings(false, l);
} }
| expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__sub")), $1), $3); } | expr_op '-' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__sub")), $1), $3); }
| expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__mul")), $1), $3); } | expr_op '*' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__mul")), $1), $3); }
| expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(data->symbols.create("__div")), $1), $3); } | expr_op '/' expr_op { $$ = new ExprApp(new ExprApp(new ExprVar(noPos, data->symbols.create("__div")), $1), $3); }
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); } | expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
| expr_app | expr_app
; ;
@ -349,12 +349,12 @@ expr_select
| /* Backwards compatibility: because Nixpkgs has a rarely used | /* Backwards compatibility: because Nixpkgs has a rarely used
function named or, allow stuff like map or [...]. */ function named or, allow stuff like map or [...]. */
expr_simple OR_KW expr_simple OR_KW
{ $$ = new ExprApp($1, new ExprVar(data->symbols.create("or"))); } { $$ = new ExprApp($1, new ExprVar(CUR_POS, data->symbols.create("or"))); }
| expr_simple { $$ = $1; } | expr_simple { $$ = $1; }
; ;
expr_simple expr_simple
: ID { $$ = new ExprVar(data->symbols.create($1)); } : ID { $$ = new ExprVar(CUR_POS, data->symbols.create($1)); }
| INT { $$ = new ExprInt($1); } | INT { $$ = new ExprInt($1); }
| '"' string_parts '"' { | '"' string_parts '"' {
/* For efficiency, and to simplify parse trees a bit. */ /* For efficiency, and to simplify parse trees a bit. */
@ -372,10 +372,10 @@ expr_simple
/* The file wasn't found in the search path. However, we can't /* The file wasn't found in the search path. However, we can't
throw an error here, because the expression might never be throw an error here, because the expression might never be
evaluated. So return an expression that lazily calls evaluated. So return an expression that lazily calls
abort. */ throw. */
$$ = path2 == "" $$ = path2 == ""
? (Expr * ) new ExprApp( ? (Expr * ) new ExprApp(
new ExprVar(data->symbols.create("throw")), new ExprVar(noPos, data->symbols.create("throw")),
new ExprString(data->symbols.create( new ExprString(data->symbols.create(
(format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str()))) (format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str())))
: (Expr * ) new ExprPath(path2); : (Expr * ) new ExprPath(path2);
@ -413,7 +413,7 @@ binds
if ($$->attrs.find(*i) != $$->attrs.end()) if ($$->attrs.find(*i) != $$->attrs.end())
dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos); dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
Pos pos = makeCurPos(@3, data); Pos pos = makeCurPos(@3, data);
$$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(*i), pos, true); $$->attrs[*i] = ExprAttrs::AttrDef(new ExprVar(CUR_POS, *i), pos, true);
} }
} }
| binds INHERIT '(' expr ')' attrs ';' | binds INHERIT '(' expr ')' attrs ';'
@ -495,11 +495,7 @@ Expr * EvalState::parse(const char * text,
if (res) throw ParseError(data.error); if (res) throw ParseError(data.error);
try { data.result->bindVars(staticEnv);
data.result->bindVars(staticEnv);
} catch (Error & e) {
throw ParseError(format("%1%, in `%2%'") % e.msg() % path);
}
return data.result; return data.result;
} }