diff options
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/eval.cc | 82 | ||||
-rw-r--r-- | src/libexpr/eval.hh | 25 | ||||
-rw-r--r-- | src/libexpr/nixexpr.cc | 68 | ||||
-rw-r--r-- | src/libexpr/nixexpr.hh | 2 | ||||
-rw-r--r-- | src/libexpr/parser.y | 12 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 99 | ||||
-rw-r--r-- | src/libexpr/symbol-table.hh | 6 | ||||
-rw-r--r-- | src/libexpr/value-to-json.cc | 11 | ||||
-rw-r--r-- | src/libexpr/value-to-xml.cc | 11 | ||||
-rw-r--r-- | src/libexpr/value.hh | 50 |
10 files changed, 251 insertions, 115 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5b9db6eeaa6e..298f6a3a60e3 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(); } @@ -180,6 +184,7 @@ EvalState::EvalState(const Strings & _searchPath) , sFile(symbols.create("file")) , sLine(symbols.create("line")) , sColumn(symbols.create("column")) + , sFunctor(symbols.create("__functor")) , repair(false) , baseEnv(allocEnv(128)) , staticBaseEnv(false, 0) @@ -212,9 +217,9 @@ EvalState::EvalState(const Strings & _searchPath) allocated. This might be a problem on systems that don't overcommit. */ if (!getenv("GC_INITIAL_HEAP_SIZE")) { - size_t maxSize = 384 * 1024 * 1024; size_t size = 32 * 1024 * 1024; #if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES) + size_t maxSize = 384 * 1024 * 1024; long pageSize = sysconf(_SC_PAGESIZE); long pages = sysconf(_SC_PHYS_PAGES); if (pageSize != -1) @@ -242,7 +247,6 @@ EvalState::EvalState(const Strings & _searchPath) EvalState::~EvalState() { fileEvalCache.clear(); - printCanaries(); } @@ -312,11 +316,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const Symbol & sym, co throw EvalError(format(s) % sym % p1 % p2); } -LocalNoInlineNoReturn(void throwTypeError(const char * s)) -{ - throw TypeError(s); -} - LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos)) { throw TypeError(format(s) % pos); @@ -327,11 +326,6 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1)) throw TypeError(format(s) % s1); } -LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2)) -{ - throw TypeError(format(s) % s1 % s2); -} - LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2, const Pos & pos)) { throw TypeError(format(s) % fun.showNamePos() % s2 % pos); @@ -895,6 +889,17 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po return; } + if (fun.type == tAttrs) { + auto found = fun.attrs->find(sFunctor); + if (found != fun.attrs->end()) { + forceValue(*found->value); + Value * v2 = allocValue(); + callFunction(*found->value, fun, *v2, pos); + forceValue(*v2); + return callFunction(*v2, arg, v, pos); + } + } + if (fun.type != tLambda) throwTypeError("attempt to call something which is not a function but %1%, at %2%", fun, pos); @@ -1255,9 +1260,9 @@ void copyContext(const Value & v, PathSet & context) } -string EvalState::forceString(Value & v, PathSet & context) +string EvalState::forceString(Value & v, PathSet & context, const Pos & pos) { - string s = forceString(v); + string s = forceString(v, pos); copyContext(v, context); return s; } @@ -1312,6 +1317,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 @@ -1432,6 +1440,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)); } @@ -1502,26 +1513,6 @@ void EvalState::printStats() } -void EvalState::printCanaries() -{ -#if HAVE_BOEHMGC - if (!settings.get("debug-gc", false)) return; - - GC_gcollect(); - - if (gcCanaries.empty()) { - printMsg(lvlError, "all canaries have been garbage-collected"); - return; - } - - printMsg(lvlError, "the following canaries have not been garbage-collected:"); - - for (auto i : gcCanaries) - printMsg(lvlError, format(" %1%") % i->string.s); -#endif -} - - size_t valueSize(Value & v) { std::set<const void *> seen; @@ -1573,6 +1564,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: ; } @@ -1599,4 +1595,22 @@ size_t valueSize(Value & v) } +string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const +{ + throw TypeError(format("cannot coerce %1% to a string, at %2%") % + showType() % pos); +} + + +bool ExternalValueBase::operator==(const ExternalValueBase & b) const +{ + return false; +} + + +std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) { + return v.print(str); +} + + } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index daf53846ffd5..f7415fb78dfd 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -39,10 +39,10 @@ public: typedef uint32_t size_t; private: - size_t size_, capacity; + size_t size_, capacity_; Attr attrs[0]; - Bindings(uint32_t capacity) : size_(0), capacity(capacity) { } + Bindings(size_t capacity) : size_(0), capacity_(capacity) { } Bindings(const Bindings & bindings) = delete; public: @@ -54,7 +54,7 @@ public: void push_back(const Attr & attr) { - assert(size_ < capacity); + assert(size_ < capacity_); attrs[size_++] = attr; } @@ -76,6 +76,8 @@ public: void sort(); + size_t capacity() { return capacity_; } + friend class EvalState; }; @@ -126,7 +128,7 @@ public: const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, - sFile, sLine, sColumn; + sFile, sLine, sColumn, sFunctor; Symbol sDerivationNix; /* If set, force copying files to the Nix store even if they @@ -169,7 +171,7 @@ public: /* Look up a file in the search path. */ Path findFile(const string & path); - Path findFile(SearchPath & searchPath, const string & path); + Path findFile(SearchPath & searchPath, const string & path, const Pos & pos = noPos); /* Evaluate an expression to normal form, storing the result in value `v'. */ @@ -200,7 +202,7 @@ public: inline void forceList(Value & v, const Pos & pos); void forceFunction(Value & v, const Pos & pos); // either lambda or primop string forceString(Value & v, const Pos & pos = noPos); - string forceString(Value & v, PathSet & context); + string forceString(Value & v, PathSet & context, const Pos & pos = noPos); string forceStringNoCtx(Value & v, const Pos & pos = noPos); /* Return true iff the value `v' denotes a derivation (i.e. a @@ -287,8 +289,6 @@ public: /* Print statistics. */ void printStats(); - void printCanaries(); - private: unsigned long nrEnvs; @@ -320,12 +320,6 @@ private: friend struct ExprOpConcatLists; friend struct ExprSelect; friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v); - -#if HAVE_BOEHMGC - std::set<Value *> gcCanaries; - friend void canaryFinalizer(GC_PTR obj, GC_PTR client_data); - friend void prim_gcCanary(EvalState & state, const Pos & pos, Value * * args, Value & v); -#endif }; @@ -340,6 +334,9 @@ struct InvalidPathError : EvalError { Path path; InvalidPathError(const Path & path); +#ifdef EXCEPTION_NEEDS_THROW_SPEC + ~InvalidPathError() throw () { }; +#endif }; /* Realise all paths in `context' */ diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index c8521718b82a..50997e096fd1 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -16,6 +16,47 @@ std::ostream & operator << (std::ostream & str, Expr & e) return str; } +static void showString(std::ostream & str, const string & s) +{ + str << '"'; + for (auto c : (string) s) + if (c == '"' || c == '\\' || c == '$') str << "\\" << c; + else if (c == '\n') str << "\\n"; + else if (c == '\r') str << "\\r"; + else if (c == '\t') str << "\\t"; + else str << c; + str << '"'; +} + +static void showId(std::ostream & str, const string & s) +{ + assert(!s.empty()); + if (s == "if") + str << '"' << s << '"'; + else { + char c = s[0]; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) { + showString(str, s); + return; + } + for (auto c : s) + if (!((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_' || c == '\'' || c == '-')) { + showString(str, s); + return; + } + str << s; + } +} + +std::ostream & operator << (std::ostream & str, const Symbol & sym) +{ + showId(str, *sym.s); + return str; +} + void Expr::show(std::ostream & str) { abort(); @@ -28,7 +69,7 @@ void ExprInt::show(std::ostream & str) void ExprString::show(std::ostream & str) { - str << "\"" << s << "\""; // !!! escaping + showString(str, s); } void ExprPath::show(std::ostream & str) @@ -44,12 +85,12 @@ void ExprVar::show(std::ostream & str) void ExprSelect::show(std::ostream & str) { str << "(" << *e << ")." << showAttrPath(attrPath); - if (def) str << " or " << *def; + if (def) str << " or (" << *def << ")"; } void ExprOpHasAttr::show(std::ostream & str) { - str << "(" << *e << ") ? " << showAttrPath(attrPath); + str << "((" << *e << ") ? " << showAttrPath(attrPath) << ")"; } void ExprAttrs::show(std::ostream & str) @@ -85,6 +126,10 @@ void ExprLambda::show(std::ostream & str) str << i->name; if (i->def) str << " ? " << *i->def; } + if (formals->ellipsis) { + if (!first) str << ", "; + str << "..."; + } str << " }"; if (!arg.empty()) str << " @ "; } @@ -94,23 +139,24 @@ void ExprLambda::show(std::ostream & str) void ExprLet::show(std::ostream & str) { - str << "let "; + str << "(let "; foreach (ExprAttrs::AttrDefs::iterator, i, attrs->attrs) - if (i->second.inherited) + if (i->second.inherited) { str << "inherit " << i->first << "; "; + } else str << i->first << " = " << *i->second.e << "; "; - str << "in " << *body; + str << "in " << *body << ")"; } void ExprWith::show(std::ostream & str) { - str << "with " << *attrs << "; " << *body; + str << "(with " << *attrs << "; " << *body << ")"; } void ExprIf::show(std::ostream & str) { - str << "if " << *cond << " then " << *then << " else " << *else_; + str << "(if " << *cond << " then " << *then << " else " << *else_ << ")"; } void ExprAssert::show(std::ostream & str) @@ -120,16 +166,18 @@ void ExprAssert::show(std::ostream & str) void ExprOpNot::show(std::ostream & str) { - str << "! " << *e; + str << "(! " << *e << ")"; } void ExprConcatStrings::show(std::ostream & str) { bool first = true; + str << "("; foreach (vector<Expr *>::iterator, i, *es) { if (first) first = false; else str << " + "; str << **i; } + str << ")"; } void ExprPos::show(std::ostream & str) @@ -143,7 +191,7 @@ std::ostream & operator << (std::ostream & str, const Pos & pos) if (!pos) str << "undefined position"; else - str << (format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%") % pos.file % pos.line % pos.column).str(); + str << (format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%") % (string) pos.file % pos.line % pos.column).str(); return str; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 0eaa362fd68b..121dc58f25f7 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -280,7 +280,7 @@ struct ExprOpNot : Expr Expr##name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \ void show(std::ostream & str) \ { \ - str << *e1 << " " s " " << *e2; \ + str << "(" << *e1 << " " s " " << *e2 << ")"; \ } \ void bindVars(const StaticEnv & env) \ { \ diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index dcb270b862a3..7d877cd67862 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -53,10 +53,6 @@ namespace nix { #include "parser-tab.hh" #include "lexer-tab.hh" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - YY_DECL; using namespace nix; @@ -630,7 +626,7 @@ Path EvalState::findFile(const string & path) } -Path EvalState::findFile(SearchPath & searchPath, const string & path) +Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos & pos) { foreach (SearchPath::iterator, i, searchPath) { Path res; @@ -645,7 +641,11 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path) } if (pathExists(res)) return canonPath(res); } - throw ThrownError(format("file ‘%1%’ was not found in the Nix search path (add it using $NIX_PATH or -I)") % path); + format f = format( + "file ‘%1%’ was not found in the Nix search path (add it using $NIX_PATH or -I)" + + string(pos ? ", at %2%" : "")); + f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); + throw ThrownError(f % path % pos); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index a7884cb85521..6c30e6d549ec 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -35,7 +35,7 @@ std::pair<string, string> decodeContext(const string & s) size_t index = s.find("!", 1); return std::pair<string, string>(string(s, index + 1), string(s, 1, index - 1)); } else - return std::pair<string, string>(s, ""); + return std::pair<string, string>(s.at(0) == '/' ? s: string(s, 1), ""); } @@ -51,7 +51,7 @@ void realiseContext(const PathSet & context) assert(isStorePath(ctx)); if (!store->isValidPath(ctx)) throw InvalidPathError(ctx); - if (isDerivation(ctx)) + if (!decoded.second.empty() && isDerivation(ctx)) drvs.insert(decoded.first + "!" + decoded.second); } if (!drvs.empty()) { @@ -84,16 +84,19 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args Derivation drv = readDerivation(path); Value & w = *state.allocValue(); state.mkAttrs(w, 2 + drv.outputs.size()); - mkString(*state.allocAttr(w, state.sDrvPath), path, singleton<PathSet>("=" + path)); - state.mkList(*state.allocAttr(w, state.symbols.create("outputs")), drv.outputs.size()); + Value * v2 = state.allocAttr(w, state.sDrvPath); + mkString(*v2, path, singleton<PathSet>("=" + path)); + Value * outputsVal = + state.allocAttr(w, state.symbols.create("outputs")); + state.mkList(*outputsVal, drv.outputs.size()); unsigned int outputs_index = 0; - Value * outputsVal = w.attrs->find(state.symbols.create("outputs"))->value; - foreach (DerivationOutputs::iterator, i, drv.outputs) { - mkString(*state.allocAttr(w, state.symbols.create(i->first)), - i->second.path, singleton<PathSet>("!" + i->first + "!" + path)); - mkString(*(outputsVal->list.elems[outputs_index++] = state.allocValue()), - i->first); + for (const auto & o : drv.outputs) { + v2 = state.allocAttr(w, state.symbols.create(o.first)); + mkString(*v2, o.second.path, + singleton<PathSet>("!" + o.first + "!" + path)); + outputsVal->list.elems[outputs_index] = state.allocValue(); + mkString(*(outputsVal->list.elems[outputs_index++]), o.first); } w.attrs->sort(); Value fun; @@ -184,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)); @@ -411,32 +417,6 @@ static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value } -#if HAVE_BOEHMGC -void canaryFinalizer(GC_PTR obj, GC_PTR client_data) -{ - Value * v = (Value *) obj; - EvalState & state(* (EvalState *) client_data); - printMsg(lvlError, format("canary ‘%1%’ garbage-collected") % v->string.s); - auto i = state.gcCanaries.find(v); - assert(i != state.gcCanaries.end()); - state.gcCanaries.erase(i); -} -#endif - - -void prim_gcCanary(EvalState & state, const Pos & pos, Value * * args, Value & v) -{ - string s = state.forceStringNoCtx(*args[0], pos); - state.mkList(v, 1); - Value * canary = v.list.elems[0] = state.allocValue(); -#if HAVE_BOEHMGC - state.gcCanaries.insert(canary); - GC_register_finalizer(canary, canaryFinalizer, &state, 0, 0); -#endif - mkString(*canary, s); -} - - void prim_valueSize(EvalState & state, const Pos & pos, Value * * args, Value & v) { /* We're not forcing the argument on purpose. */ @@ -750,8 +730,12 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va { PathSet context; Path path = state.coerceToPath(pos, *args[0], context); - if (!context.empty()) - throw EvalError(format("string ‘%1%’ cannot refer to other paths, at %2%") % path % pos); + try { + realiseContext(context); + } catch (InvalidPathError & e) { + throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") + % path % e.path % pos); + } mkString(v, readFile(path).c_str()); } @@ -791,7 +775,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va % path % e.path % pos); } - mkPath(v, state.findFile(searchPath, path).c_str()); + mkPath(v, state.findFile(searchPath, path, pos).c_str()); } /* Read a directory (without . or ..) */ @@ -812,7 +796,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val for (auto & ent : entries) { Value * ent_val = state.allocAttr(v, state.symbols.create(ent.name)); if (ent.type == DT_UNKNOWN) - ent.type = getFileType(path); + ent.type = getFileType(path + "/" + ent.name); mkStringNoCopy(*ent_val, ent.type == DT_REG ? "regular" : ent.type == DT_DIR ? "directory" : @@ -867,7 +851,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu { PathSet context; string name = state.forceStringNoCtx(*args[0], pos); - string contents = state.forceString(*args[1], context); + string contents = state.forceString(*args[1], context, pos); PathSet refs; @@ -1424,10 +1408,37 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args, throw Error(format("unknown hash type ‘%1%’, at %2%") % type % pos); PathSet context; // discarded - string s = state.forceString(*args[1], context); + string s = state.forceString(*args[1], context, pos); mkString(v, printHash(hashString(ht, s)), context); -}; +} + + +/* Match a regular expression against a string and return either + ‘null’ or a list containing substring matches. */ +static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + Regex regex(state.forceStringNoCtx(*args[0], pos), true); + + PathSet context; + string s = state.forceString(*args[1], context, pos); + + Regex::Subs subs; + if (!regex.matches(s, subs)) { + mkNull(v); + return; + } + + unsigned int len = subs.empty() ? 0 : subs.rbegin()->first + 1; + state.mkList(v, len); + for (unsigned int n = 0; n < len; ++n) { + auto i = subs.find(n); + if (i == subs.end()) + mkNull(*(v.list.elems[n] = state.allocValue())); + else + mkString(*(v.list.elems[n] = state.allocValue()), i->second); + } +} /************************************************************* @@ -1523,7 +1534,6 @@ void EvalState::createBaseEnv() // Debugging addPrimOp("__trace", 2, prim_trace); - addPrimOp("__gcCanary", 1, prim_gcCanary); addPrimOp("__valueSize", 1, prim_valueSize); // Paths @@ -1581,6 +1591,7 @@ void EvalState::createBaseEnv() addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); addPrimOp("__hashString", 2, prim_hashString); + addPrimOp("__match", 2, prim_match); // Versions addPrimOp("__parseDrvName", 1, prim_parseDrvName); diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh index 140662b51501..2fdf820211c8 100644 --- a/src/libexpr/symbol-table.hh +++ b/src/libexpr/symbol-table.hh @@ -58,12 +58,6 @@ public: friend std::ostream & operator << (std::ostream & str, const Symbol & sym); }; -inline std::ostream & operator << (std::ostream & str, const Symbol & sym) -{ - str << *sym.s; - return str; -} - class SymbolTable { private: diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index d1ec9b566d66..cdb71341875a 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) const +{ + 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 3934a83eec25..bbbb7039bf70 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) const +{ + 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 5f18f629e632..c06b5a6d1153 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, const ExternalValueBase & v); + protected: + /* Print out the value */ + virtual std::ostream & print(std::ostream & str) const = 0; + + public: + /* Return a simple string describing the type */ + virtual string showType() const = 0; + + /* Return a string to be used in builtins.typeOf */ + virtual string typeOf() const = 0; + + /* How much space does this value take up */ + virtual size_t valueSize(std::set<const void *> & seen) const = 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) const; + + /* Compare to another value of the same type. Defaults to uncomparable, + * i.e. always false. + */ + virtual bool operator==(const ExternalValueBase & b) const; + + /* 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) const; + + /* Print the value as XML. Defaults to unevaluated */ + virtual void printValueAsXML(EvalState & state, bool strict, bool location, + XMLWriter & doc, PathSet & context, PathSet & drvsSeen) const; + + virtual ~ExternalValueBase() + { + }; +}; + +std::ostream & operator << (std::ostream & str, const ExternalValueBase & v); + struct Value { @@ -88,6 +137,7 @@ struct Value struct { Value * left, * right; } primOpApp; + ExternalValueBase * external; }; }; |