about summary refs log tree commit diff
path: root/src/libexpr/nixexpr.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-04-05T22·27+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-04-05T22·27+0000
commit59b94ee18ac0cba5c7b261ee72550a4d3db0acb5 (patch)
tree9dbe6721699439cda3ce68ac86acbe38e9839e66 /src/libexpr/nixexpr.cc
parenta520b1cbc3327dfb8e3c6f503dfd0bd41e0a6d55 (diff)
* When something goes wrong in the evaluation of a Nix expression,
  print a nice backtrace of the stack, rather than vomiting a gigantic
  (and useless) aterm on the screen.  Example:

    error: while evaluating file `.../pkgs/system/test.nix':
    while evaluating attribute `subversion' at `.../pkgs/system/all-packages-generic.nix', line 533:
    while evaluating function at `.../pkgs/applications/version-management/subversion/default.nix', line 1:
    assertion failed at `.../pkgs/applications/version-management/subversion/default.nix', line 13

  Since the Nix expression language is lazy, the trace may be
  misleading.  The purpose is to provide a hint as to the location of
  the problem.    
  

Diffstat (limited to 'src/libexpr/nixexpr.cc')
-rw-r--r--src/libexpr/nixexpr.cc74
1 files changed, 58 insertions, 16 deletions
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 2736daf323..dec734e466 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -104,6 +104,19 @@ string aterm2String(ATerm t)
 {
     return ATgetName(ATgetAFun(t));
 }
+
+
+string showPos(ATerm pos)
+{
+    ATMatcher m;
+    Path path;
+    int line, column;
+    if (atMatch(m, pos) >> "NoPos")
+        return "undefined position";
+    if (!(atMatch(m, pos) >> "Pos" >> path >> line >> column))
+        throw badTerm("position expected", pos);
+    return (format("`%1%', line %2%") % path % line).str();
+}
     
 
 ATerm bottomupRewrite(TermFun & f, ATerm e)
@@ -135,37 +148,66 @@ ATerm bottomupRewrite(TermFun & f, ATerm e)
 }
 
 
-void queryAllAttrs(Expr e, ATermMap & attrs)
+void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos)
 {
     ATMatcher m;
     ATermList bnds;
     if (!(atMatch(m, e) >> "Attrs" >> bnds))
-        throw badTerm("expected attribute set", e);
+        throw Error("attribute set expected");
 
     for (ATermIterator i(bnds); i; ++i) {
         string s;
         Expr e;
-        if (!(atMatch(m, *i) >> "Bind" >> s >> e))
+        ATerm pos;
+        if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos))
             abort(); /* can't happen */
-        attrs.set(s, e);
+        attrs.set(s, withPos ? ATmake("(<term>, <term>)", e, pos) : e);
     }
 }
 
 
 Expr queryAttr(Expr e, const string & name)
 {
-    ATermMap attrs;
-    queryAllAttrs(e, attrs);
-    return attrs.get(name);
+    ATerm dummy;
+    return queryAttr(e, name, dummy);
+}
+
+
+Expr queryAttr(Expr e, const string & name, ATerm & pos)
+{
+    ATMatcher m;
+    ATermList bnds;
+    if (!(atMatch(m, e) >> "Attrs" >> bnds))
+        throw Error("attribute set expected");
+
+    for (ATermIterator i(bnds); i; ++i) {
+        string s;
+        Expr e;
+        ATerm pos2;
+        if (!(atMatch(m, *i) >> "Bind" >> s >> e >> pos2))
+            abort(); /* can't happen */
+        if (s == name) {
+            pos = pos2;
+            return e;
+        }
+    }
+
+    return 0;
 }
 
 
 Expr makeAttrs(const ATermMap & attrs)
 {
+    ATMatcher m;
     ATermList bnds = ATempty;
-    for (ATermIterator i(attrs.keys()); i; ++i)
+    for (ATermIterator i(attrs.keys()); i; ++i) {
+        Expr e;
+        ATerm pos;
+        if (!(atMatch(m, attrs.get(*i)) >> "" >> e >> pos))
+            abort(); /* can't happen */
         bnds = ATinsert(bnds, 
-            ATmake("Bind(<term>, <term>)", *i, attrs.get(*i)));
+            ATmake("Bind(<term>, <term>, <term>)", *i, e, pos));
+    }
     return ATmake("Attrs(<term>)", ATreverse(bnds));
 }
 
@@ -175,7 +217,7 @@ Expr substitute(const ATermMap & subs, Expr e)
     checkInterrupt();
 
     ATMatcher m;
-    ATerm name;
+    ATerm name, pos;
 
     /* As an optimisation, don't substitute in subterms known to be
        closed. */
@@ -190,7 +232,7 @@ Expr substitute(const ATermMap & subs, Expr e)
        function. */
     ATermList formals;
     ATerm body;
-    if (atMatch(m, e) >> "Function" >> formals >> body) {
+    if (atMatch(m, e) >> "Function" >> formals >> body >> pos) {
         ATermMap subs2(subs);
         for (ATermIterator i(formals); i; ++i) {
             if (!(atMatch(m, *i) >> "NoDefFormal" >> name) &&
@@ -198,16 +240,16 @@ Expr substitute(const ATermMap & subs, Expr e)
                 abort();
             subs2.remove(name);
         }
-        return ATmake("Function(<term>, <term>)",
+        return ATmake("Function(<term>, <term>, <term>)",
             substitute(subs, (ATerm) formals),
-            substitute(subs2, body));
+            substitute(subs2, body), pos);
     }
 
-    if (atMatch(m, e) >> "Function1" >> name >> body) {
+    if (atMatch(m, e) >> "Function1" >> name >> body >> pos) {
         ATermMap subs2(subs);
         subs2.remove(name);
-        return ATmake("Function1(<term>, <term>)", name,
-            substitute(subs2, body));
+        return ATmake("Function1(<term>, <term>, <term>)", name,
+            substitute(subs2, body), pos);
     }
         
     /* Idem for a mutually recursive attribute set. */