guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

314/376: Allow external code using libnixexpr to add types


From: Ludovic Courtès
Subject: 314/376: Allow external code using libnixexpr to add types
Date: Wed, 28 Jan 2015 22:05:51 +0000

civodul pushed a commit to tag 1.8
in repository guix.

commit 320659b0cd161249c95e736c3fb309b1a73ea728
Author: Shea Levy <address@hidden>
Date:   Sun Nov 30 13:16:19 2014 -0500

    Allow external code using libnixexpr to add types
    
    Code that links to libnixexpr (e.g. plugins loaded with importNative, or
    nix-exec) may want to provide custom value types and operations on
    values of those types. For example, nix-exec is currently using sets
    where a custom IO value type would be more appropriate. This commit
    provides a generic hook for such types in the form of tExternal and the
    ExternalBase virtual class, which contains all functions necessary for
    libnixexpr's type-polymorphic functions (e.g. `showType`) to be
    implemented.
---
 src/libexpr/eval.cc          |   33 +++++++++++++++++++++++++++
 src/libexpr/primops.cc       |    3 ++
 src/libexpr/value-to-json.cc |   11 +++++++++
 src/libexpr/value-to-xml.cc  |   11 +++++++++
 src/libexpr/value.hh         |   50 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index ebb2802..b0afccd 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -104,6 +104,9 @@ static void printValue(std::ostream & str, std::set<const 
Value *> & active, con
     case tPrimOpApp:
         str << "<PRIMOP-APP>";
         break;
+    case tExternal:
+        str << *v.external;
+        break;
     default:
         throw Error("invalid value");
     }
@@ -136,6 +139,7 @@ string showType(const Value & v)
         case tBlackhole: return "a black hole";
         case tPrimOp: return "a built-in function";
         case tPrimOpApp: return "a partially applied built-in function";
+        case tExternal: return v.external->showType();
     }
     abort();
 }
@@ -1314,6 +1318,9 @@ string EvalState::coerceToString(const Pos & pos, Value & 
v, PathSet & context,
         return coerceToString(pos, *i->value, context, coerceMore, 
copyToStore);
     }
 
+    if (v.type == tExternal)
+        return v.external->coerceToString(pos, context, coerceMore, 
copyToStore);
+
     if (coerceMore) {
 
         /* Note that `false' is represented as an empty string for
@@ -1434,6 +1441,9 @@ bool EvalState::eqValues(Value & v1, Value & v2)
         case tPrimOpApp:
             return false;
 
+        case tExternal:
+            return *v1.external == *v2.external;
+
         default:
             throwEvalError("cannot compare %1% with %2%", showType(v1), 
showType(v2));
     }
@@ -1575,6 +1585,11 @@ size_t valueSize(Value & v)
             sz += doValue(*v.primOpApp.left);
             sz += doValue(*v.primOpApp.right);
             break;
+        case tExternal:
+            if (seen.find(v.external) != seen.end()) break;
+            seen.insert(v.external);
+            sz += v.external->valueSize(seen);
+            break;
         default:
             ;
         }
@@ -1601,4 +1616,22 @@ size_t valueSize(Value & v)
 }
 
 
+string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, 
bool copyMore, bool copyToStore)
+{
+    throw TypeError(format("cannot coerce %1% to a string, at %2%") %
+        showType() % pos);
+}
+
+
+bool ExternalValueBase::operator==(const ExternalValueBase & b)
+{
+    return false;
+}
+
+
+std::ostream & operator << (std::ostream & str, ExternalValueBase & v) {
+    return v.print(str);
+}
+
+
 }
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index b0596da..e7b7960 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -187,6 +187,9 @@ static void prim_typeOf(EvalState & state, const Pos & pos, 
Value * * args, Valu
         case tPrimOpApp:
             t = "lambda";
             break;
+       case tExternal:
+            t = args[0]->external->typeOf();
+            break;
         default: abort();
     }
     mkString(v, state.symbols.create(t));
diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc
index d1ec9b5..b9f3e65 100644
--- a/src/libexpr/value-to-json.cc
+++ b/src/libexpr/value-to-json.cc
@@ -80,10 +80,21 @@ void printValueAsJSON(EvalState & state, bool strict,
             break;
         }
 
+       case tExternal:
+            v.external->printValueAsJSON(state, strict, str, context);
+            break;
+
         default:
             throw TypeError(format("cannot convert %1% to JSON") % 
showType(v));
     }
 }
 
 
+void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
+      std::ostream & str, PathSet & context)
+{
+    throw TypeError(format("cannot convert %1% to JSON") % showType());
+}
+
+
 }
diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc
index 3934a83..3cecc33 100644
--- a/src/libexpr/value-to-xml.cc
+++ b/src/libexpr/value-to-xml.cc
@@ -144,12 +144,23 @@ static void printValueAsXML(EvalState & state, bool 
strict, bool location,
             break;
         }
 
+        case tExternal:
+            v.external->printValueAsXML(state, strict, location, doc, context, 
drvsSeen);
+            break;
+
         default:
             doc.writeEmptyElement("unevaluated");
     }
 }
 
 
+void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
+    bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
+{
+    doc.writeEmptyElement("unevaluated");
+}
+
+
 void printValueAsXML(EvalState & state, bool strict, bool location,
     Value & v, std::ostream & out, PathSet & context)
 {
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 5f18f62..227a81f 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -19,6 +19,7 @@ typedef enum {
     tBlackhole,
     tPrimOp,
     tPrimOpApp,
+    tExternal,
 } ValueType;
 
 
@@ -29,10 +30,58 @@ struct ExprLambda;
 struct PrimOp;
 struct PrimOp;
 class Symbol;
+struct Pos;
+class EvalState;
+class XMLWriter;
 
 
 typedef long NixInt;
 
+/* External values must descend from ExternalValueBase, so that
+ * type-agnostic nix functions (e.g. showType) can be implemented
+ */
+class ExternalValueBase
+{
+    friend std::ostream & operator << (std::ostream & str, ExternalValueBase & 
v);
+    protected:
+    /* Print out the value */
+    virtual std::ostream & print(std::ostream & str) = 0;
+
+    public:
+    /* Return a simple string describing the type */
+    virtual string showType() = 0;
+
+    /* Return a string to be used in builtins.typeOf */
+    virtual string typeOf() = 0;
+
+    /* How much space does this value take up */
+    virtual size_t valueSize(std::set<const void *> & seen) = 0;
+
+    /* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
+     * error
+     */
+    virtual string coerceToString(const Pos & pos, PathSet & context, bool 
copyMore, bool copyToStore);
+
+    /* Compare to another value of the same type. Defaults to uncomparable,
+     * i.e. always false.
+     */
+    virtual bool operator==(const ExternalValueBase & b);
+
+    /* Print the value as JSON. Defaults to unconvertable, i.e. throws an 
error */
+    virtual void printValueAsJSON(EvalState & state, bool strict,
+        std::ostream & str, PathSet & context);
+
+    /* Print the value as XML. Defaults to unevaluated */
+    virtual void printValueAsXML(EvalState & state, bool strict, bool location,
+        XMLWriter & doc, PathSet & context, PathSet & drvsSeen);
+
+    virtual ~ExternalValueBase()
+    {
+    };
+};
+
+std::ostream & operator << (std::ostream & str, ExternalValueBase & v);
+
 
 struct Value
 {
@@ -88,6 +137,7 @@ struct Value
         struct {
             Value * left, * right;
         } primOpApp;
+        ExternalValueBase * external;
     };
 };
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]