|
17 | 17 | #include "util.hh" |
18 | 18 |
|
19 | 19 | #include "nixexpr.hh" |
| 20 | +#include "eval.hh" |
20 | 21 |
|
21 | 22 | namespace nix { |
22 | 23 |
|
23 | 24 | struct ParseData |
24 | 25 | { |
| 26 | + EvalState & state; |
25 | 27 | SymbolTable & symbols; |
26 | 28 | Expr * result; |
27 | 29 | Path basePath; |
28 | 30 | Path path; |
29 | 31 | string error; |
30 | 32 | Symbol sLetBody; |
31 | | - ParseData(SymbolTable & symbols) |
32 | | - : symbols(symbols) |
| 33 | + ParseData(EvalState & state) |
| 34 | + : state(state) |
| 35 | + , symbols(state.symbols) |
33 | 36 | , sLetBody(symbols.create("<let-body>")) |
34 | 37 | { }; |
35 | 38 | }; |
@@ -253,7 +256,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err |
253 | 256 | %token <id> ID ATTRPATH |
254 | 257 | %token <e> STR IND_STR |
255 | 258 | %token <n> INT |
256 | | -%token <path> PATH |
| 259 | +%token <path> PATH SPATH |
257 | 260 | %token <uri> URI |
258 | 261 | %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW |
259 | 262 | %token DOLLAR_CURLY /* == ${ */ |
@@ -350,6 +353,20 @@ expr_simple |
350 | 353 | $$ = stripIndentation(data->symbols, *$2); |
351 | 354 | } |
352 | 355 | | PATH { $$ = new ExprPath(absPath($1, data->basePath)); } |
| 356 | + | SPATH { |
| 357 | + string path($1 + 1, strlen($1) - 2); |
| 358 | + Path path2 = data->state.findFile(path); |
| 359 | + /* The file wasn't found in the search path. However, we can't |
| 360 | + throw an error here, because the expression might never be |
| 361 | + evaluated. So return an expression that lazily calls |
| 362 | + ‘abort’. */ |
| 363 | + $$ = path2 == "" |
| 364 | + ? (Expr * ) new ExprApp( |
| 365 | + new ExprVar(data->symbols.create("throw")), |
| 366 | + new ExprString(data->symbols.create( |
| 367 | + (format("file `%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)") % path).str()))) |
| 368 | + : (Expr * ) new ExprPath(path2); |
| 369 | + } |
353 | 370 | | URI { $$ = new ExprString(data->symbols.create($1)); } |
354 | 371 | | '(' expr ')' { $$ = $2; } |
355 | 372 | /* Let expressions `let {..., body = ...}' are just desugared |
@@ -454,7 +471,7 @@ Expr * EvalState::parse(const char * text, |
454 | 471 | const Path & path, const Path & basePath) |
455 | 472 | { |
456 | 473 | yyscan_t scanner; |
457 | | - ParseData data(symbols); |
| 474 | + ParseData data(*this); |
458 | 475 | data.basePath = basePath; |
459 | 476 | data.path = path; |
460 | 477 |
|
@@ -510,5 +527,25 @@ Expr * EvalState::parseExprFromString(const string & s, const Path & basePath) |
510 | 527 | return parse(s.c_str(), "(string)", basePath); |
511 | 528 | } |
512 | 529 |
|
513 | | - |
| 530 | + |
| 531 | +void EvalState::addToSearchPath(const string & s) |
| 532 | +{ |
| 533 | + Path path = absPath(s); |
| 534 | + if (pathExists(path)) { |
| 535 | + debug(format("adding path `%1%' to the search path") % path); |
| 536 | + searchPath.insert(searchPathInsertionPoint, path); |
| 537 | + } |
| 538 | +} |
| 539 | + |
| 540 | + |
| 541 | +Path EvalState::findFile(const string & path) |
| 542 | +{ |
| 543 | + foreach (Paths::iterator, i, searchPath) { |
| 544 | + Path res = *i + "/" + path; |
| 545 | + if (pathExists(res)) return canonPath(res); |
| 546 | + } |
| 547 | + return ""; |
| 548 | +} |
| 549 | + |
| 550 | + |
514 | 551 | } |
0 commit comments