about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.cc48
1 files changed, 42 insertions, 6 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 01d33ad00c6b..2b9b96559d7d 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -644,6 +644,44 @@ LocalNoInline(Expr evalOpConcat(EvalState & state, Expr e1, Expr e2))
 }
 
 
+/* Implementation of the `==' and `!=' operators. */
+LocalNoInline(bool areEqual(EvalState & state, Expr e1, Expr e2))
+{
+    e1 = evalExpr(state, e1);
+    e2 = evalExpr(state, e2);
+
+    /* We cannot test functions/primops for equality, and we currently
+       don't support testing equality between attribute sets or lists
+       - that would have to be a deep equality test to be sound. */
+    AFun sym1 = ATgetAFun(e1);
+    AFun sym2 = ATgetAFun(e2);
+
+    if (sym1 != sym2) return false;
+
+    /* Functions are incomparable. */
+    if (sym1 == symFunction || sym1 == symPrimOp) return false;
+
+    if (sym1 == symAttrs)
+        throw EvalError("comparison of attribute sets is not implemented");
+
+    if (e1 == e2) return true;
+    
+    if (sym1 == symList) {
+        ATermList es1; matchList(e1, es1);
+        ATermList es2; matchList(e2, es2);
+        if (ATgetLength(es1) != ATgetLength(es2)) return false;
+        ATermIterator i(es1), j(es2);
+        while (*i) {
+            if (!areEqual(state, *i, *j)) return false;
+            ++i; ++j;
+        }
+        return true;
+    }
+    
+    return false;
+}
+
+
 static char * deepestStack = (char *) -1; /* for measuring stack usage */
 
 
@@ -707,12 +745,10 @@ Expr evalExpr2(EvalState & state, Expr e)
        However, we don't want to make (==) strict, because that would
        make operations like `big_derivation == null' very slow (unless
        we were to evaluate them side-by-side). */
-    if (matchOpEq(e, e1, e2))
-        return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
-
-    if (matchOpNEq(e, e1, e2))
-        return makeBool(evalExpr(state, e1) != evalExpr(state, e2));
-
+    if (matchOpEq(e, e1, e2)) return makeBool(areEqual(state, e1, e2));
+        
+    if (matchOpNEq(e, e1, e2)) return makeBool(!areEqual(state, e1, e2));
+        
     /* Negation. */
     if (matchOpNot(e, e1))
         return makeBool(!evalBool(state, e1));