about summary refs log tree commit diff
path: root/src/libexpr/parser.y
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2011-08-06T16·05+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2011-08-06T16·05+0000
commit1ecc97b6bdb27e56d832ca48cdafd3dbb5185a04 (patch)
tree4de27ee42f04bb50766f33a58d830677bd8fa80b /src/libexpr/parser.y
parent54945a2950174ded83d58336061b4a9990cdbbfd (diff)
* Add a Nix expression search path feature. Paths between angle
  brackets, e.g.

    import <nixpkgs/pkgs/lib>

  are resolved by looking them up relative to the elements listed in
  the search path.  This allows us to get rid of hacks like

    import "${builtins.getEnv "NIXPKGS_ALL"}/pkgs/lib"

  The search path can be specified through the ‘-I’ command-line flag
  and through the colon-separated ‘NIX_PATH’ environment variable,
  e.g.,

    $ nix-build -I /etc/nixos ...

  If a file is not found in the search path, an error message is
  lazily thrown.

Diffstat (limited to 'src/libexpr/parser.y')
-rw-r--r--src/libexpr/parser.y47
1 files changed, 42 insertions, 5 deletions
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index a64d327b454b..cd63666dc5f0 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -17,19 +17,22 @@
 #include "util.hh"
     
 #include "nixexpr.hh"
+#include "eval.hh"
 
 namespace nix {
 
     struct ParseData 
     {
+        EvalState & state;
         SymbolTable & symbols;
         Expr * result;
         Path basePath;
         Path path;
         string error;
         Symbol sLetBody;
-        ParseData(SymbolTable & symbols)
-            : symbols(symbols)
+        ParseData(EvalState & state)
+            : state(state)
+            , symbols(state.symbols)
             , sLetBody(symbols.create("<let-body>"))
             { };
     };
@@ -253,7 +256,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
 %token <id> ID ATTRPATH
 %token <e> STR IND_STR
 %token <n> INT
-%token <path> PATH
+%token <path> PATH SPATH
 %token <uri> URI
 %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
 %token DOLLAR_CURLY /* == ${ */
@@ -350,6 +353,20 @@ expr_simple
       $$ = stripIndentation(data->symbols, *$2);
   }
   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
+  | SPATH {
+      string path($1 + 1, strlen($1) - 2);
+      Path path2 = data->state.findFile(path);
+      /* The file wasn't found in the search path.  However, we can't
+         throw an error here, because the expression might never be
+         evaluated.  So return an expression that lazily calls
+         ‘abort’. */
+      $$ = path2 == ""
+          ? (Expr * ) new ExprApp(
+              new ExprVar(data->symbols.create("throw")),
+              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())))
+          : (Expr * ) new ExprPath(path2);
+  }
   | URI { $$ = new ExprString(data->symbols.create($1)); }
   | '(' expr ')' { $$ = $2; }
   /* Let expressions `let {..., body = ...}' are just desugared
@@ -454,7 +471,7 @@ Expr * EvalState::parse(const char * text,
     const Path & path, const Path & basePath)
 {
     yyscan_t scanner;
-    ParseData data(symbols);
+    ParseData data(*this);
     data.basePath = basePath;
     data.path = path;
 
@@ -510,5 +527,25 @@ Expr * EvalState::parseExprFromString(const string & s, const Path & basePath)
     return parse(s.c_str(), "(string)", basePath);
 }
 
- 
+
+void EvalState::addToSearchPath(const string & s)
+{
+    Path path = absPath(s);
+    if (pathExists(path)) {
+        debug(format("adding path `%1%' to the search path") % path);
+        searchPath.insert(searchPathInsertionPoint, path);
+    }
+}
+
+
+Path EvalState::findFile(const string & path)
+{
+    foreach (Paths::iterator, i, searchPath) {
+        Path res = *i + "/" + path;
+        if (pathExists(res)) return canonPath(res);
+    }
+    return "";
+}
+
+
 }