about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/fix-ng/eval.cc43
-rw-r--r--src/fix-ng/fix-expr.cc6
-rw-r--r--src/fix-ng/fix-expr.hh4
-rw-r--r--src/fix-ng/fix.sdf18
-rw-r--r--src/fix-ng/primops.cc13
-rw-r--r--src/fix-ng/primops.hh9
6 files changed, 77 insertions, 16 deletions
diff --git a/src/fix-ng/eval.cc b/src/fix-ng/eval.cc
index 770802f321fb..1f131fb7b0df 100644
--- a/src/fix-ng/eval.cc
+++ b/src/fix-ng/eval.cc
@@ -13,11 +13,6 @@ EvalState::EvalState()
 }
 
 
-Expr getAttr(EvalState & state, Expr e, const string & name)
-{
-}
-
-
 /* Substitute an argument set into the body of a function. */
 static Expr substArgs(Expr body, ATermList formals, Expr arg)
 {
@@ -142,7 +137,8 @@ Expr evalExpr2(EvalState & state, Expr e)
         ATmatch(e, "Bool(<term>)", &e1) ||
         ATmatch(e, "Function([<list>], <term>)", &e1, &e2) ||
         ATmatch(e, "Attrs([<list>])", &e1) ||
-        ATmatch(e, "List([<list>])", &e1))
+        ATmatch(e, "List([<list>])", &e1) ||
+        ATmatch(e, "Null", &e1))
         return e;
 
     /* Any encountered variables must be undeclared or primops. */
@@ -163,6 +159,8 @@ Expr evalExpr2(EvalState & state, Expr e)
             if (primop == "derivation") return primDerivation(state, e2);
             if (primop == "toString") return primToString(state, e2);
             if (primop == "baseNameOf") return primBaseNameOf(state, e2);
+            if (primop == "null") return primNull(state, e2);
+            if (primop == "isNull") return primIsNull(state, e2);
             else throw badTerm("undefined variable/primop", e1);
         }
 
@@ -200,13 +198,36 @@ Expr evalExpr2(EvalState & state, Expr e)
             return evalExpr(state, e3);
     }
 
-    /* Equality.  Just strings for now. */
-    if (ATmatch(e, "OpEq(<term>, <term>)", &e1, &e2)) {
-        string s1 = evalString(state, e1);
-        string s2 = evalString(state, e2);
-        return s1 == s2 ? ATmake("Bool(True)") : ATmake("Bool(False)");
+    /* Assertions. */
+    if (ATmatch(e, "Assert(<term>, <term>)", &e1, &e2)) {
+        if (!evalBool(state, e1)) throw badTerm("guard failed", e);
+        return evalExpr(state, e2);
     }
 
+    /* Generic equality. */
+    if (ATmatch(e, "OpEq(<term>, <term>)", &e1, &e2))
+        return makeBool(evalExpr(state, e1) == evalExpr(state, e2));
+
+    /* Generic inequality. */
+    if (ATmatch(e, "OpNEq(<term>, <term>)", &e1, &e2))
+        return makeBool(evalExpr(state, e1) != evalExpr(state, e2));
+
+    /* Negation. */
+    if (ATmatch(e, "OpNot(<term>)", &e1))
+        return makeBool(!evalBool(state, e1));
+
+    /* Implication. */
+    if (ATmatch(e, "OpImpl(<term>, <term>)", &e1, &e2))
+        return makeBool(!evalBool(state, e1) || evalBool(state, e2));
+
+    /* Conjunction (logical AND). */
+    if (ATmatch(e, "OpAnd(<term>, <term>)", &e1, &e2))
+        return makeBool(evalBool(state, e1) && evalBool(state, e2));
+
+    /* Disjunction (logical OR). */
+    if (ATmatch(e, "OpOr(<term>, <term>)", &e1, &e2))
+        return makeBool(evalBool(state, e1) || evalBool(state, e2));
+
     /* Barf. */
     throw badTerm("invalid expression", e);
 }
diff --git a/src/fix-ng/fix-expr.cc b/src/fix-ng/fix-expr.cc
index 6e73b29341ff..1ce4a55e475a 100644
--- a/src/fix-ng/fix-expr.cc
+++ b/src/fix-ng/fix-expr.cc
@@ -222,3 +222,9 @@ Expr substitute(const ATermMap & subs, Expr e)
 
     return e;
 }
+
+
+Expr makeBool(bool b)
+{
+    return b ? ATmake("Bool(True)") : ATmake("Bool(False)");
+}
diff --git a/src/fix-ng/fix-expr.hh b/src/fix-ng/fix-expr.hh
index 93a010abeda6..6c1e51d9ccd6 100644
--- a/src/fix-ng/fix-expr.hh
+++ b/src/fix-ng/fix-expr.hh
@@ -45,7 +45,6 @@ public:
 ATerm string2ATerm(const string & s);
 string aterm2String(ATerm t);
 
-
 /* Generic bottomup traversal over ATerms.  The traversal first
    recursively descends into subterms, and then applies the given term
    function to the resulting term. */
@@ -69,5 +68,8 @@ Expr makeAttrs(const ATermMap & attrs);
 /* Perform a set of substitutions on an expression. */
 Expr substitute(const ATermMap & subs, Expr e);
 
+/* Create an expression representing a boolean. */
+Expr makeBool(bool b);
+
 
 #endif /* !__FIXEXPR_H */
diff --git a/src/fix-ng/fix.sdf b/src/fix-ng/fix.sdf
index 9dc04d937391..0cc486e14d80 100644
--- a/src/fix-ng/fix.sdf
+++ b/src/fix-ng/fix.sdf
@@ -38,6 +38,8 @@ exports
     Id -> Formal {cons("NoDefFormal")}
     Id "?" Expr -> Formal {cons("DefFormal")}
 
+    "assert" Expr ";" Expr -> Expr {cons("Assert"), right}
+
     "rec" "{" Binds "}" -> Expr {cons("Rec")}
     "let" "{" Binds "}" -> Expr {cons("LetRec")}
     "{" Binds "}" -> Expr {cons("Attrs")}
@@ -55,7 +57,13 @@ exports
 
     "if" Expr "then" Expr "else" Expr -> Expr {cons("If")}
 
-    Expr "==" Expr -> Expr {cons("OpEq")}
+    Expr "==" Expr -> Expr {cons("OpEq"), non-assoc}
+    Expr "!=" Expr -> Expr {cons("OpNEq"), non-assoc}
+
+    "!" Expr -> Expr {cons("OpNot")}
+    Expr "&&" Expr -> Expr {cons("OpAnd"), right}
+    Expr "||" Expr -> Expr {cons("OpOr"), right}
+    Expr "->" Expr -> Expr {cons("OpImpl"), right}
 
     Bool -> Expr {cons("Bool")}
 
@@ -64,6 +72,13 @@ exports
     Expr "." Id -> Expr
   > Expr ExprList -> ExprList
   > Expr Expr -> Expr
+  > "!" Expr -> Expr
+  > Expr "==" Expr -> Expr
+  > Expr "!=" Expr -> Expr
+  > Expr "&&" Expr -> Expr
+  > Expr "||" Expr -> Expr
+  > Expr "->" Expr -> Expr
+  > "assert" Expr ";" Expr -> Expr
   > "{" {Formal ","}* "}" ":" Expr -> Expr
 
 
@@ -78,6 +93,7 @@ exports
     "rec" -> Id {reject}
     "true" -> Id {reject}
     "false" -> Id {reject}
+    "assert" -> Id {reject}
 
     [0-9]+ -> Int
 
diff --git a/src/fix-ng/primops.cc b/src/fix-ng/primops.cc
index ef0fd354ef6d..f5a278f669b5 100644
--- a/src/fix-ng/primops.cc
+++ b/src/fix-ng/primops.cc
@@ -225,3 +225,16 @@ Expr primToString(EvalState & state, Expr arg)
         return ATmake("Str(<str>)", s);
     else throw badTerm("cannot coerce to string", arg);
 }
+
+
+Expr primNull(EvalState & state, Expr arg)
+{
+    return ATmake("Null");
+}
+
+
+Expr primIsNull(EvalState & state, Expr arg)
+{
+    arg = evalExpr(state, arg);
+    return makeBool(ATmatch(arg, "Null"));
+}
diff --git a/src/fix-ng/primops.hh b/src/fix-ng/primops.hh
index e48883b0bb01..775ec5568208 100644
--- a/src/fix-ng/primops.hh
+++ b/src/fix-ng/primops.hh
@@ -8,7 +8,6 @@
    argument. */ 
 Expr primImport(EvalState & state, Expr arg);
 
-
 /* Construct (as a unobservable) side effect) a Nix derivation
    expression that performs the derivation described by the argument
    set.  Returns the original set extended with the following
@@ -18,14 +17,18 @@ Expr primImport(EvalState & state, Expr arg);
    derivation. */
 Expr primDerivation(EvalState & state, Expr args);
 
-
 /* Return the base name of the given string, i.e., everything
    following the last slash. */
 Expr primBaseNameOf(EvalState & state, Expr arg);
 
-
 /* Convert the argument (which can be a path or a uri) to a string. */
 Expr primToString(EvalState & state, Expr arg);
 
+/* Return the null value. */
+Expr primNull(EvalState & state, Expr arg);
+
+/* Determine whether the argument is the null value. */
+Expr primIsNull(EvalState & state, Expr arg);
+
 
 #endif /* !__PRIMOPS_H */