* Don't use ATerms for the abstract syntax trees anymore. Not
finished yet.
This commit is contained in:
parent
ed711f73bc
commit
4d6ad5be17
|
@ -8,15 +8,15 @@ libexpr_la_SOURCES = \
|
||||||
pkginclude_HEADERS = \
|
pkginclude_HEADERS = \
|
||||||
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
|
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
|
||||||
get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \
|
get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \
|
||||||
names.hh nixexpr-ast.hh
|
names.hh
|
||||||
|
|
||||||
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
||||||
../boost/format/libformat.la
|
../boost/format/libformat.la
|
||||||
|
|
||||||
BUILT_SOURCES = nixexpr-ast.cc nixexpr-ast.hh \
|
BUILT_SOURCES = \
|
||||||
parser-tab.hh lexer-tab.hh parser-tab.cc lexer-tab.cc
|
parser-tab.hh lexer-tab.hh parser-tab.cc lexer-tab.cc
|
||||||
|
|
||||||
EXTRA_DIST = lexer.l parser.y nixexpr-ast.def nixexpr-ast.cc
|
EXTRA_DIST = lexer.l parser.y
|
||||||
|
|
||||||
AM_CXXFLAGS = \
|
AM_CXXFLAGS = \
|
||||||
-I$(srcdir)/.. ${aterm_include} \
|
-I$(srcdir)/.. ${aterm_include} \
|
||||||
|
@ -34,15 +34,6 @@ lexer-tab.cc lexer-tab.hh: lexer.l
|
||||||
$(flex) --outfile lexer-tab.cc --header-file=lexer-tab.hh $(srcdir)/lexer.l
|
$(flex) --outfile lexer-tab.cc --header-file=lexer-tab.hh $(srcdir)/lexer.l
|
||||||
|
|
||||||
|
|
||||||
# ATerm helper function generation.
|
|
||||||
|
|
||||||
nixexpr-ast.cc nixexpr-ast.hh: ../aterm-helper.pl nixexpr-ast.def
|
|
||||||
$(perl) $(srcdir)/../aterm-helper.pl nixexpr-ast.hh nixexpr-ast.cc < $(srcdir)/nixexpr-ast.def
|
|
||||||
|
|
||||||
|
|
||||||
CLEANFILES =
|
|
||||||
|
|
||||||
|
|
||||||
# SDF stuff (not built by default).
|
# SDF stuff (not built by default).
|
||||||
nix.tbl: nix.sdf
|
nix.tbl: nix.sdf
|
||||||
sdf2table -m Nix -s -i nix.sdf -o nix.tbl
|
sdf2table -m Nix -s -i nix.sdf -o nix.tbl
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +6,7 @@ namespace nix {
|
||||||
|
|
||||||
|
|
||||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
const Bindings & autoArgs, Expr e, Value & v)
|
const Bindings & autoArgs, Expr * e, Value & v)
|
||||||
{
|
{
|
||||||
Strings tokens = tokenizeString(attrPath, ".");
|
Strings tokens = tokenizeString(attrPath, ".");
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
||||||
% curPath % showType(v));
|
% curPath % showType(v));
|
||||||
|
|
||||||
Bindings::iterator a = v.attrs->find(toATerm(attr));
|
Bindings::iterator a = v.attrs->find(attr);
|
||||||
if (a == v.attrs->end())
|
if (a == v.attrs->end())
|
||||||
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
||||||
v = a->second;
|
v = a->second;
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace nix {
|
||||||
|
|
||||||
|
|
||||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
const Bindings & autoArgs, Expr e, Value & v);
|
const Bindings & autoArgs, Expr * e, Value & v);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ bool parseOptionArg(const string & arg, Strings::iterator & i,
|
||||||
if (i == argsEnd) throw error;
|
if (i == argsEnd) throw error;
|
||||||
string value = *i++;
|
string value = *i++;
|
||||||
|
|
||||||
Value & v(autoArgs[toATerm(name)]);
|
Value & v(autoArgs[name]);
|
||||||
|
|
||||||
if (arg == "--arg")
|
if (arg == "--arg")
|
||||||
state.mkThunk_(v, parseExprFromString(state, value, absPath(".")));
|
state.mkThunk_(v, parseExprFromString(value, absPath(".")));
|
||||||
else
|
else
|
||||||
mkString(v, value);
|
mkString(v, value);
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ using namespace nix;
|
||||||
|
|
||||||
void doTest(EvalState & state, string s)
|
void doTest(EvalState & state, string s)
|
||||||
{
|
{
|
||||||
Expr e = parseExprFromString(state, s, absPath("."));
|
Expr * e = parseExprFromString(s, absPath("."));
|
||||||
printMsg(lvlError, format(">>>>> %1%") % e);
|
std::cerr << ">>>>> " << *e << std::endl;
|
||||||
Value v;
|
Value v;
|
||||||
state.eval(e, v);
|
state.eval(e, v);
|
||||||
state.strictForceValue(v);
|
state.strictForceValue(v);
|
||||||
|
@ -24,8 +24,10 @@ void doTest(EvalState & state, string s)
|
||||||
void run(Strings args)
|
void run(Strings args)
|
||||||
{
|
{
|
||||||
EvalState state;
|
EvalState state;
|
||||||
|
|
||||||
printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value));
|
printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value));
|
||||||
|
printMsg(lvlError, format("size of int AST node: %1% bytes") % sizeof(ExprInt));
|
||||||
|
printMsg(lvlError, format("size of attrset AST node: %1% bytes") % sizeof(ExprAttrs));
|
||||||
|
|
||||||
doTest(state, "123");
|
doTest(state, "123");
|
||||||
doTest(state, "{ x = 1; y = 2; }");
|
doTest(state, "{ x = 1; y = 2; }");
|
||||||
|
@ -53,7 +55,7 @@ void run(Strings args)
|
||||||
doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 2)]");
|
doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 2)]");
|
||||||
doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 3)]");
|
doTest(state, "let id = x: x; in [1 2] == [(id 1) (id 3)]");
|
||||||
doTest(state, "[1 2] == [3 (let x = x; in x)]");
|
doTest(state, "[1 2] == [3 (let x = x; in x)]");
|
||||||
doTest(state, "{ x = 1; y.z = 2; } == { y = { z = 2; }; x = 1; }");
|
//doTest(state, "{ x = 1; y.z = 2; } == { y = { z = 2; }; x = 1; }");
|
||||||
doTest(state, "{ x = 1; y = 2; } == { x = 2; }");
|
doTest(state, "{ x = 1; y = 2; } == { x = 2; }");
|
||||||
doTest(state, "{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }");
|
doTest(state, "{ x = [ 1 2 ]; } == { x = [ 1 ] ++ [ 2 ]; }");
|
||||||
doTest(state, "1 != 1");
|
doTest(state, "1 != 1");
|
||||||
|
@ -63,23 +65,23 @@ void run(Strings args)
|
||||||
doTest(state, "__head [ 1 2 3 ]");
|
doTest(state, "__head [ 1 2 3 ]");
|
||||||
doTest(state, "__add 1 2");
|
doTest(state, "__add 1 2");
|
||||||
doTest(state, "null");
|
doTest(state, "null");
|
||||||
doTest(state, "null");
|
//doTest(state, "\"foo\"");
|
||||||
doTest(state, "\"foo\"");
|
//doTest(state, "let s = \"bar\"; in \"foo${s}\"");
|
||||||
doTest(state, "let s = \"bar\"; in \"foo${s}\"");
|
|
||||||
doTest(state, "if true then 1 else 2");
|
doTest(state, "if true then 1 else 2");
|
||||||
doTest(state, "if false then 1 else 2");
|
doTest(state, "if false then 1 else 2");
|
||||||
doTest(state, "if false || true then 1 else 2");
|
doTest(state, "if false || true then 1 else 2");
|
||||||
doTest(state, "let x = x; in if true || x then 1 else 2");
|
doTest(state, "let x = x; in if true || x then 1 else 2");
|
||||||
|
doTest(state, "http://nixos.org/");
|
||||||
doTest(state, "/etc/passwd");
|
doTest(state, "/etc/passwd");
|
||||||
//doTest(state, "import ./foo.nix");
|
//doTest(state, "import ./foo.nix");
|
||||||
doTest(state, "map (x: __add 1 x) [ 1 2 3 ]");
|
doTest(state, "map (x: __add 1 x) [ 1 2 3 ]");
|
||||||
doTest(state, "map (builtins.add 1) [ 1 2 3 ]");
|
doTest(state, "map (builtins.add 1) [ 1 2 3 ]");
|
||||||
doTest(state, "builtins.hasAttr \"x\" { x = 1; }");
|
//doTest(state, "builtins.hasAttr \"x\" { x = 1; }");
|
||||||
doTest(state, "let x = 1; as = rec { inherit x; y = as.x; }; in as.y");
|
doTest(state, "let x = 1; as = rec { inherit x; y = as.x; }; in as.y");
|
||||||
doTest(state, "let as = { x = 1; }; bs = rec { inherit (as) x; y = x; }; in bs.y");
|
doTest(state, "let as = { x = 1; }; bs = rec { inherit (as) x; y = x; }; in bs.y");
|
||||||
doTest(state, "let as = rec { inherit (y) x; y = { x = 1; }; }; in as.x");
|
doTest(state, "let as = rec { inherit (y) x; y = { x = 1; }; }; in as.x");
|
||||||
doTest(state, "builtins.toXML 123");
|
doTest(state, "builtins.toXML 123");
|
||||||
doTest(state, "builtins.toXML { a.b = \"x\" + \"y\"; c = [ 1 2 ] ++ [ 3 4 ]; }");
|
//doTest(state, "builtins.toXML { a.b = \"x\" + \"y\"; c = [ 1 2 ] ++ [ 3 4 ]; }");
|
||||||
|
|
||||||
state.printStats();
|
state.printStats();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -45,7 +44,7 @@ std::ostream & operator << (std::ostream & str, Value & v)
|
||||||
case tAttrs:
|
case tAttrs:
|
||||||
str << "{ ";
|
str << "{ ";
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
foreach (Bindings::iterator, i, *v.attrs)
|
||||||
str << aterm2String(i->first) << " = " << i->second << "; ";
|
str << i->first << " = " << i->second << "; ";
|
||||||
str << "}";
|
str << "}";
|
||||||
break;
|
break;
|
||||||
case tList:
|
case tList:
|
||||||
|
@ -96,8 +95,6 @@ EvalState::EvalState() : baseEnv(allocEnv())
|
||||||
nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0;
|
nrValues = nrEnvs = nrEvaluated = recursionDepth = maxRecursionDepth = 0;
|
||||||
deepestStack = (char *) -1;
|
deepestStack = (char *) -1;
|
||||||
|
|
||||||
initNixExprHelpers();
|
|
||||||
|
|
||||||
createBaseEnv();
|
createBaseEnv();
|
||||||
|
|
||||||
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
|
allowUnsafeEquality = getEnv("NIX_NO_UNSAFE_EQ", "") == "";
|
||||||
|
@ -112,9 +109,9 @@ EvalState::~EvalState()
|
||||||
|
|
||||||
void EvalState::addConstant(const string & name, Value & v)
|
void EvalState::addConstant(const string & name, Value & v)
|
||||||
{
|
{
|
||||||
baseEnv.bindings[toATerm(name)] = v;
|
baseEnv.bindings[name] = v;
|
||||||
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
||||||
(*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v;
|
(*baseEnv.bindings["builtins"].attrs)[name2] = v;
|
||||||
nrValues += 2;
|
nrValues += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +123,9 @@ void EvalState::addPrimOp(const string & name,
|
||||||
v.type = tPrimOp;
|
v.type = tPrimOp;
|
||||||
v.primOp.arity = arity;
|
v.primOp.arity = arity;
|
||||||
v.primOp.fun = primOp;
|
v.primOp.fun = primOp;
|
||||||
baseEnv.bindings[toATerm(name)] = v;
|
baseEnv.bindings[name] = v;
|
||||||
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
||||||
(*baseEnv.bindings[toATerm("builtins")].attrs)[toATerm(name2)] = v;
|
(*baseEnv.bindings["builtins"].attrs)[name2] = v;
|
||||||
nrValues += 2;
|
nrValues += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,12 +209,12 @@ void mkPath(Value & v, const char * s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Value * lookupWith(Env * env, Sym name)
|
static Value * lookupWith(Env * env, const Sym & name)
|
||||||
{
|
{
|
||||||
if (!env) return 0;
|
if (!env) return 0;
|
||||||
Value * v = lookupWith(env->up, name);
|
Value * v = lookupWith(env->up, name);
|
||||||
if (v) return v;
|
if (v) return v;
|
||||||
Bindings::iterator i = env->bindings.find(sWith);
|
Bindings::iterator i = env->bindings.find("<with>");
|
||||||
if (i == env->bindings.end()) return 0;
|
if (i == env->bindings.end()) return 0;
|
||||||
Bindings::iterator j = i->second.attrs->find(name);
|
Bindings::iterator j = i->second.attrs->find(name);
|
||||||
if (j != i->second.attrs->end()) return &j->second;
|
if (j != i->second.attrs->end()) return &j->second;
|
||||||
|
@ -225,7 +222,7 @@ static Value * lookupWith(Env * env, Sym name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Value * lookupVar(Env * env, Sym name)
|
static Value * lookupVar(Env * env, const Sym & name)
|
||||||
{
|
{
|
||||||
/* First look for a regular variable binding for `name'. */
|
/* First look for a regular variable binding for `name'. */
|
||||||
for (Env * env2 = env; env2; env2 = env2->up) {
|
for (Env * env2 = env; env2; env2 = env2->up) {
|
||||||
|
@ -251,7 +248,7 @@ static Value * lookupVar(Env * env, Sym name)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
throwEvalError("undefined variable `%1%'", aterm2String(name));
|
throwEvalError("undefined variable `%1%'", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -284,7 +281,7 @@ void EvalState::mkAttrs(Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::mkThunk_(Value & v, Expr expr)
|
void EvalState::mkThunk_(Value & v, Expr * expr)
|
||||||
{
|
{
|
||||||
mkThunk(v, baseEnv, expr);
|
mkThunk(v, baseEnv, expr);
|
||||||
}
|
}
|
||||||
|
@ -302,11 +299,11 @@ void EvalState::evalFile(const Path & path, Value & v)
|
||||||
{
|
{
|
||||||
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
|
startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
|
||||||
|
|
||||||
Expr e = parseTrees.get(toATerm(path));
|
Expr * e = parseTrees[path];
|
||||||
|
|
||||||
if (!e) {
|
if (!e) {
|
||||||
e = parseExprFromFile(*this, path);
|
e = parseExprFromFile(path);
|
||||||
parseTrees.set(toATerm(path), e);
|
parseTrees[path] = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -334,7 +331,7 @@ struct RecursionCounter
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void EvalState::eval(Env & env, Expr e, Value & v)
|
void EvalState::eval(Env & env, Expr * e, Value & v)
|
||||||
{
|
{
|
||||||
/* When changing this function, make sure that you don't cause a
|
/* When changing this function, make sure that you don't cause a
|
||||||
(large) increase in stack consumption! */
|
(large) increase in stack consumption! */
|
||||||
|
@ -350,6 +347,9 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
|
|
||||||
nrEvaluated++;
|
nrEvaluated++;
|
||||||
|
|
||||||
|
e->eval(*this, env, v);
|
||||||
|
|
||||||
|
#if 0
|
||||||
Sym name;
|
Sym name;
|
||||||
int n;
|
int n;
|
||||||
ATerm s; ATermList context, es;
|
ATerm s; ATermList context, es;
|
||||||
|
@ -357,138 +357,6 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
Expr e1, e2, e3, fun, arg, attrs;
|
Expr e1, e2, e3, fun, arg, attrs;
|
||||||
Pattern pat; Expr body; Pos pos;
|
Pattern pat; Expr body; Pos pos;
|
||||||
|
|
||||||
if (matchVar(e, name)) {
|
|
||||||
Value * v2 = lookupVar(&env, name);
|
|
||||||
forceValue(*v2);
|
|
||||||
v = *v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchInt(e, n))
|
|
||||||
mkInt(v, n);
|
|
||||||
|
|
||||||
else if (matchStr(e, s, context)) {
|
|
||||||
assert(context == ATempty);
|
|
||||||
mkString(v, ATgetName(ATgetAFun(s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchPath(e, s))
|
|
||||||
mkPath(v, ATgetName(ATgetAFun(s)));
|
|
||||||
|
|
||||||
else if (matchAttrs(e, es)) {
|
|
||||||
mkAttrs(v);
|
|
||||||
ATerm e2, pos;
|
|
||||||
for (ATermIterator i(es); i; ++i) {
|
|
||||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
|
||||||
Value & v2 = (*v.attrs)[name];
|
|
||||||
nrValues++;
|
|
||||||
mkThunk(v2, env, e2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchRec(e, rbnds, nrbnds)) {
|
|
||||||
/* Create a new environment that contains the attributes in
|
|
||||||
this `rec'. */
|
|
||||||
Env & env2(allocEnv());
|
|
||||||
env2.up = &env;
|
|
||||||
|
|
||||||
v.type = tAttrs;
|
|
||||||
v.attrs = &env2.bindings;
|
|
||||||
|
|
||||||
/* The recursive attributes are evaluated in the new
|
|
||||||
environment. */
|
|
||||||
ATerm name, e2, pos;
|
|
||||||
for (ATermIterator i(rbnds); i; ++i) {
|
|
||||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
|
||||||
Value & v2 = env2.bindings[name];
|
|
||||||
nrValues++;
|
|
||||||
mkThunk(v2, env2, e2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The non-recursive attributes, on the other hand, are
|
|
||||||
evaluated in the original environment. */
|
|
||||||
for (ATermIterator i(nrbnds); i; ++i) {
|
|
||||||
if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
|
|
||||||
Value & v2 = env2.bindings[name];
|
|
||||||
nrValues++;
|
|
||||||
mkThunk(v2, env, e2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchSelect(e, e2, name)) {
|
|
||||||
Value v2;
|
|
||||||
eval(env, e2, v2);
|
|
||||||
forceAttrs(v2); // !!! eval followed by force is slightly inefficient
|
|
||||||
Bindings::iterator i = v2.attrs->find(name);
|
|
||||||
if (i == v2.attrs->end())
|
|
||||||
throwEvalError("attribute `%1%' missing", aterm2String(name));
|
|
||||||
try {
|
|
||||||
forceValue(i->second);
|
|
||||||
} catch (Error & e) {
|
|
||||||
addErrorPrefix(e, "while evaluating the attribute `%1%':\n", aterm2String(name));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
v = i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchFunction(e, pat, body, pos)) {
|
|
||||||
v.type = tLambda;
|
|
||||||
v.lambda.env = &env;
|
|
||||||
v.lambda.pat = pat;
|
|
||||||
v.lambda.body = body;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchCall(e, fun, arg)) {
|
|
||||||
Value vFun;
|
|
||||||
eval(env, fun, vFun);
|
|
||||||
Value vArg;
|
|
||||||
mkThunk(vArg, env, arg); // !!! should this be on the heap?
|
|
||||||
callFunction(vFun, vArg, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchWith(e, attrs, body, pos)) {
|
|
||||||
Env & env2(allocEnv());
|
|
||||||
env2.up = &env;
|
|
||||||
|
|
||||||
Value & vAttrs = env2.bindings[sWith];
|
|
||||||
nrValues++;
|
|
||||||
eval(env, attrs, vAttrs);
|
|
||||||
forceAttrs(vAttrs);
|
|
||||||
|
|
||||||
eval(env2, body, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchList(e, es)) {
|
|
||||||
mkList(v, ATgetLength(es));
|
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n, es = ATgetNext(es))
|
|
||||||
mkThunk(v.list.elems[n], env, ATgetFirst(es));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchOpEq(e, e1, e2)) {
|
|
||||||
Value v1; eval(env, e1, v1);
|
|
||||||
Value v2; eval(env, e2, v2);
|
|
||||||
mkBool(v, eqValues(v1, v2));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchOpNEq(e, e1, e2)) {
|
|
||||||
Value v1; eval(env, e1, v1);
|
|
||||||
Value v2; eval(env, e2, v2);
|
|
||||||
mkBool(v, !eqValues(v1, v2));
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchOpConcat(e, e1, e2)) {
|
|
||||||
Value v1; eval(env, e1, v1);
|
|
||||||
forceList(v1);
|
|
||||||
Value v2; eval(env, e2, v2);
|
|
||||||
forceList(v2);
|
|
||||||
mkList(v, v1.list.length + v2.list.length);
|
|
||||||
/* !!! This loses sharing with the original lists. We could
|
|
||||||
use a tCopy node, but that would use more memory. */
|
|
||||||
for (unsigned int n = 0; n < v1.list.length; ++n)
|
|
||||||
v.list.elems[n] = v1.list.elems[n];
|
|
||||||
for (unsigned int n = 0; n < v2.list.length; ++n)
|
|
||||||
v.list.elems[n + v1.list.length] = v2.list.elems[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (matchConcatStrings(e, es)) {
|
else if (matchConcatStrings(e, es)) {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
|
@ -521,10 +389,6 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
mkString(v, s.str(), context);
|
mkString(v, s.str(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Conditionals. */
|
|
||||||
else if (matchIf(e, e1, e2, e3))
|
|
||||||
eval(env, evalBool(env, e1) ? e2 : e3, v);
|
|
||||||
|
|
||||||
/* Assertions. */
|
/* Assertions. */
|
||||||
else if (matchAssert(e, e1, e2, pos)) {
|
else if (matchAssert(e, e1, e2, pos)) {
|
||||||
if (!evalBool(env, e1))
|
if (!evalBool(env, e1))
|
||||||
|
@ -536,30 +400,6 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
else if (matchOpNot(e, e1))
|
else if (matchOpNot(e, e1))
|
||||||
mkBool(v, !evalBool(env, e1));
|
mkBool(v, !evalBool(env, e1));
|
||||||
|
|
||||||
/* Implication. */
|
|
||||||
else if (matchOpImpl(e, e1, e2))
|
|
||||||
return mkBool(v, !evalBool(env, e1) || evalBool(env, e2));
|
|
||||||
|
|
||||||
/* Conjunction (logical AND). */
|
|
||||||
else if (matchOpAnd(e, e1, e2))
|
|
||||||
mkBool(v, evalBool(env, e1) && evalBool(env, e2));
|
|
||||||
|
|
||||||
/* Disjunction (logical OR). */
|
|
||||||
else if (matchOpOr(e, e1, e2))
|
|
||||||
mkBool(v, evalBool(env, e1) || evalBool(env, e2));
|
|
||||||
|
|
||||||
/* Attribute set update (//). */
|
|
||||||
else if (matchOpUpdate(e, e1, e2)) {
|
|
||||||
Value v2;
|
|
||||||
eval(env, e1, v2);
|
|
||||||
|
|
||||||
cloneAttrs(v2, v);
|
|
||||||
|
|
||||||
eval(env, e2, v2);
|
|
||||||
foreach (Bindings::iterator, i, *v2.attrs)
|
|
||||||
(*v.attrs)[i->first] = i->second; // !!! sharing
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attribute existence test (?). */
|
/* Attribute existence test (?). */
|
||||||
else if (matchOpHasAttr(e, e1, name)) {
|
else if (matchOpHasAttr(e, e1, name)) {
|
||||||
Value vAttrs;
|
Value vAttrs;
|
||||||
|
@ -567,8 +407,130 @@ void EvalState::eval(Env & env, Expr e, Value & v)
|
||||||
forceAttrs(vAttrs);
|
forceAttrs(vAttrs);
|
||||||
mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
|
mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
else abort();
|
|
||||||
|
void EvalState::eval(Expr * e, Value & v)
|
||||||
|
{
|
||||||
|
eval(baseEnv, e, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool EvalState::evalBool(Env & env, Expr * e)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
eval(env, e, v);
|
||||||
|
if (v.type != tBool)
|
||||||
|
throwTypeError("value is %1% while a Boolean was expected", showType(v));
|
||||||
|
return v.boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprInt::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
mkInt(v, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprString::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
mkString(v, s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprPath::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
mkPath(v, s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
if (recursive) {
|
||||||
|
|
||||||
|
/* Create a new environment that contains the attributes in
|
||||||
|
this `rec'. */
|
||||||
|
Env & env2(state.allocEnv());
|
||||||
|
env2.up = &env;
|
||||||
|
|
||||||
|
v.type = tAttrs;
|
||||||
|
v.attrs = &env2.bindings;
|
||||||
|
|
||||||
|
/* The recursive attributes are evaluated in the new
|
||||||
|
environment. */
|
||||||
|
foreach (Attrs::iterator, i, attrs) {
|
||||||
|
Value & v2 = env2.bindings[i->first];
|
||||||
|
mkThunk(v2, env2, i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The inherited attributes, on the other hand, are
|
||||||
|
evaluated in the original environment. */
|
||||||
|
foreach (list<string>::iterator, i, inherited) {
|
||||||
|
Value & v2 = env2.bindings[*i];
|
||||||
|
mkCopy(v2, *lookupVar(&env, *i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
state.mkAttrs(v);
|
||||||
|
foreach (Attrs::iterator, i, attrs) {
|
||||||
|
Value & v2 = (*v.attrs)[i->first];
|
||||||
|
mkThunk(v2, env, i->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprList::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
state.mkList(v, elems.size());
|
||||||
|
for (unsigned int n = 0; n < v.list.length; ++n)
|
||||||
|
mkThunk(v.list.elems[n], env, elems[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprVar::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value * v2 = lookupVar(&env, name);
|
||||||
|
state.forceValue(*v2);
|
||||||
|
v = *v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value v2;
|
||||||
|
state.eval(env, e, v2);
|
||||||
|
state.forceAttrs(v2); // !!! eval followed by force is slightly inefficient
|
||||||
|
Bindings::iterator i = v2.attrs->find(name);
|
||||||
|
if (i == v2.attrs->end())
|
||||||
|
throwEvalError("attribute `%1%' missing", name);
|
||||||
|
try {
|
||||||
|
state.forceValue(i->second);
|
||||||
|
} catch (Error & e) {
|
||||||
|
addErrorPrefix(e, "while evaluating the attribute `%1%':\n", name);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
v = i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprLambda::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
v.type = tLambda;
|
||||||
|
v.lambda.env = &env;
|
||||||
|
v.lambda.fun = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprApp::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value vFun;
|
||||||
|
state.eval(env, e1, vFun);
|
||||||
|
Value vArg;
|
||||||
|
mkThunk(vArg, env, e2); // !!! should this be on the heap?
|
||||||
|
state.callFunction(vFun, vArg, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -613,19 +575,17 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
Env & env2(allocEnv());
|
Env & env2(allocEnv());
|
||||||
env2.up = fun.lambda.env;
|
env2.up = fun.lambda.env;
|
||||||
|
|
||||||
ATermList formals; ATerm ellipsis, name;
|
if (!fun.lambda.fun->matchAttrs) {
|
||||||
|
Value & vArg = env2.bindings[fun.lambda.fun->arg];
|
||||||
if (matchVarPat(fun.lambda.pat, name)) {
|
|
||||||
Value & vArg = env2.bindings[name];
|
|
||||||
nrValues++;
|
nrValues++;
|
||||||
vArg = arg;
|
vArg = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) {
|
else {
|
||||||
forceAttrs(arg);
|
forceAttrs(arg);
|
||||||
|
|
||||||
if (name != sNoAlias) {
|
if (!fun.lambda.fun->arg.empty()) {
|
||||||
env2.bindings[name] = arg;
|
env2.bindings[fun.lambda.fun->arg] = arg;
|
||||||
nrValues++;
|
nrValues++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,21 +593,15 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
there is no matching actual argument but the formal
|
there is no matching actual argument but the formal
|
||||||
argument has a default, use the default. */
|
argument has a default, use the default. */
|
||||||
unsigned int attrsUsed = 0;
|
unsigned int attrsUsed = 0;
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
||||||
Expr def; Sym name;
|
Bindings::iterator j = arg.attrs->find(i->name);
|
||||||
DefaultValue def2;
|
|
||||||
if (!matchFormal(*i, name, def2)) abort(); /* can't happen */
|
|
||||||
|
|
||||||
Bindings::iterator j = arg.attrs->find(name);
|
|
||||||
|
|
||||||
Value & v = env2.bindings[name];
|
Value & v = env2.bindings[i->name];
|
||||||
nrValues++;
|
nrValues++;
|
||||||
|
|
||||||
if (j == arg.attrs->end()) {
|
if (j == arg.attrs->end()) {
|
||||||
if (!matchDefaultValue(def2, def)) def = 0;
|
if (!i->def) throwTypeError("the argument named `%1%' required by the function is missing", i->name);
|
||||||
if (def == 0) throwTypeError("the argument named `%1%' required by the function is missing",
|
mkThunk(v, env2, i->def);
|
||||||
aterm2String(name));
|
|
||||||
mkThunk(v, env2, def);
|
|
||||||
} else {
|
} else {
|
||||||
attrsUsed++;
|
attrsUsed++;
|
||||||
mkCopy(v, j->second);
|
mkCopy(v, j->second);
|
||||||
|
@ -658,13 +612,11 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
argument (unless the attribute match specifies a `...').
|
argument (unless the attribute match specifies a `...').
|
||||||
TODO: show the names of the expected/unexpected
|
TODO: show the names of the expected/unexpected
|
||||||
arguments. */
|
arguments. */
|
||||||
if (ellipsis == eFalse && attrsUsed != arg.attrs->size())
|
if (!fun.lambda.fun->formals->ellipsis && attrsUsed != arg.attrs->size())
|
||||||
throwTypeError("function called with unexpected argument");
|
throwTypeError("function called with unexpected argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
else abort();
|
eval(env2, fun.lambda.fun->body, v);
|
||||||
|
|
||||||
eval(env2, fun.lambda.body, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -672,45 +624,114 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
|
||||||
{
|
{
|
||||||
forceValue(fun);
|
forceValue(fun);
|
||||||
|
|
||||||
ATerm name;
|
if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) {
|
||||||
ATermList formals;
|
|
||||||
ATermBool ellipsis;
|
|
||||||
|
|
||||||
if (fun.type != tLambda || !matchAttrsPat(fun.lambda.pat, formals, ellipsis, name)) {
|
|
||||||
res = fun;
|
res = fun;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value actualArgs;
|
Value actualArgs;
|
||||||
mkAttrs(actualArgs);
|
mkAttrs(actualArgs);
|
||||||
|
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
|
||||||
Expr name, def; ATerm def2;
|
Bindings::const_iterator j = args.find(i->name);
|
||||||
if (!matchFormal(*i, name, def2)) abort();
|
|
||||||
Bindings::const_iterator j = args.find(name);
|
|
||||||
if (j != args.end())
|
if (j != args.end())
|
||||||
(*actualArgs.attrs)[name] = j->second;
|
(*actualArgs.attrs)[i->name] = j->second;
|
||||||
else if (!matchDefaultValue(def2, def))
|
else if (!i->def)
|
||||||
throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", aterm2String(name));
|
throwTypeError("cannot auto-call a function that has an argument without a default value (`%1%')", i->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
callFunction(fun, actualArgs, res);
|
callFunction(fun, actualArgs, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::eval(Expr e, Value & v)
|
void ExprWith::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
eval(baseEnv, e, v);
|
Env & env2(state.allocEnv());
|
||||||
|
env2.up = &env;
|
||||||
|
|
||||||
|
Value & vAttrs = env2.bindings["<with>"];
|
||||||
|
state.eval(env, attrs, vAttrs);
|
||||||
|
state.forceAttrs(vAttrs);
|
||||||
|
|
||||||
|
state.eval(env2, body, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EvalState::evalBool(Env & env, Expr e)
|
void ExprIf::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
Value v;
|
state.eval(env, state.evalBool(env, cond) ? then : else_, v);
|
||||||
eval(env, e, v);
|
}
|
||||||
if (v.type != tBool)
|
|
||||||
throwTypeError("value is %1% while a Boolean was expected", showType(v));
|
|
||||||
return v.boolean;
|
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value v1; state.eval(env, e1, v1);
|
||||||
|
Value v2; state.eval(env, e2, v2);
|
||||||
|
mkBool(v, state.eqValues(v1, v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value v1; state.eval(env, e1, v1);
|
||||||
|
Value v2; state.eval(env, e2, v2);
|
||||||
|
mkBool(v, !state.eqValues(v1, v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpAnd::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
mkBool(v, state.evalBool(env, e1) && state.evalBool(env, e2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpOr::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
mkBool(v, state.evalBool(env, e1) || state.evalBool(env, e2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
mkBool(v, !state.evalBool(env, e1) || state.evalBool(env, e2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value v2;
|
||||||
|
state.eval(env, e1, v2);
|
||||||
|
state.forceAttrs(v2);
|
||||||
|
|
||||||
|
state.cloneAttrs(v2, v);
|
||||||
|
|
||||||
|
state.eval(env, e2, v2);
|
||||||
|
state.forceAttrs(v2);
|
||||||
|
|
||||||
|
foreach (Bindings::iterator, i, *v2.attrs)
|
||||||
|
(*v.attrs)[i->first] = i->second; // !!! sharing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
Value v1; state.eval(env, e1, v1);
|
||||||
|
state.forceList(v1);
|
||||||
|
Value v2; state.eval(env, e2, v2);
|
||||||
|
state.forceList(v2);
|
||||||
|
state.mkList(v, v1.list.length + v2.list.length);
|
||||||
|
/* !!! This loses sharing with the original lists. We could use a
|
||||||
|
tCopy node, but that would use more memory. */
|
||||||
|
for (unsigned int n = 0; n < v1.list.length; ++n)
|
||||||
|
v.list.elems[n] = v1.list.elems[n];
|
||||||
|
for (unsigned int n = 0; n < v2.list.length; ++n)
|
||||||
|
v.list.elems[n + v1.list.length] = v2.list.elems[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -827,7 +848,7 @@ string EvalState::forceStringNoCtx(Value & v)
|
||||||
bool EvalState::isDerivation(Value & v)
|
bool EvalState::isDerivation(Value & v)
|
||||||
{
|
{
|
||||||
if (v.type != tAttrs) return false;
|
if (v.type != tAttrs) return false;
|
||||||
Bindings::iterator i = v.attrs->find(toATerm("type"));
|
Bindings::iterator i = v.attrs->find("type");
|
||||||
return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation";
|
return i != v.attrs->end() && forceStringNoCtx(i->second) == "derivation";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,7 +892,7 @@ string EvalState::coerceToString(Value & v, PathSet & context,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.type == tAttrs) {
|
if (v.type == tAttrs) {
|
||||||
Bindings::iterator i = v.attrs->find(toATerm("outPath"));
|
Bindings::iterator i = v.attrs->find("outPath");
|
||||||
if (i == v.attrs->end())
|
if (i == v.attrs->end())
|
||||||
throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
|
throwTypeError("cannot coerce an attribute set (except a derivation) to a string");
|
||||||
return coerceToString(i->second, context, coerceMore, copyToStore);
|
return coerceToString(i->second, context, coerceMore, copyToStore);
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "aterm.hh"
|
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ class EvalState;
|
||||||
struct Env;
|
struct Env;
|
||||||
struct Value;
|
struct Value;
|
||||||
|
|
||||||
typedef ATerm Sym;
|
typedef string Sym;
|
||||||
|
|
||||||
typedef std::map<Sym, Value> Bindings;
|
typedef std::map<Sym, Value> Bindings;
|
||||||
|
|
||||||
|
@ -55,10 +54,32 @@ struct Value
|
||||||
{
|
{
|
||||||
int integer;
|
int integer;
|
||||||
bool boolean;
|
bool boolean;
|
||||||
|
|
||||||
|
/* Strings in the evaluator carry a so-called `context' (the
|
||||||
|
ATermList) which is a list of strings representing store
|
||||||
|
paths. This is to allow users to write things like
|
||||||
|
|
||||||
|
"--with-freetype2-library=" + freetype + "/lib"
|
||||||
|
|
||||||
|
where `freetype' is a derivation (or a source to be copied
|
||||||
|
to the store). If we just concatenated the strings without
|
||||||
|
keeping track of the referenced store paths, then if the
|
||||||
|
string is used as a derivation attribute, the derivation
|
||||||
|
will not have the correct dependencies in its inputDrvs and
|
||||||
|
inputSrcs.
|
||||||
|
|
||||||
|
The semantics of the context is as follows: when a string
|
||||||
|
with context C is used as a derivation attribute, then the
|
||||||
|
derivations in C will be added to the inputDrvs of the
|
||||||
|
derivation, and the other store paths in C will be added to
|
||||||
|
the inputSrcs of the derivations.
|
||||||
|
|
||||||
|
For canonicity, the store paths should be in sorted order. */
|
||||||
struct {
|
struct {
|
||||||
const char * s;
|
const char * s;
|
||||||
const char * * context;
|
const char * * context;
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
const char * path;
|
const char * path;
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
struct {
|
struct {
|
||||||
|
@ -67,15 +88,14 @@ struct Value
|
||||||
} list;
|
} list;
|
||||||
struct {
|
struct {
|
||||||
Env * env;
|
Env * env;
|
||||||
Expr expr;
|
Expr * expr;
|
||||||
} thunk;
|
} thunk;
|
||||||
struct {
|
struct {
|
||||||
Value * left, * right;
|
Value * left, * right;
|
||||||
} app;
|
} app;
|
||||||
struct {
|
struct {
|
||||||
Env * env;
|
Env * env;
|
||||||
Pattern pat;
|
ExprLambda * fun;
|
||||||
Expr body;
|
|
||||||
} lambda;
|
} lambda;
|
||||||
Value * val;
|
Value * val;
|
||||||
struct {
|
struct {
|
||||||
|
@ -104,7 +124,7 @@ static inline void mkBool(Value & v, bool b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void mkThunk(Value & v, Env & env, Expr expr)
|
static inline void mkThunk(Value & v, Env & env, Expr * expr)
|
||||||
{
|
{
|
||||||
v.type = tThunk;
|
v.type = tThunk;
|
||||||
v.thunk.env = &env;
|
v.thunk.env = &env;
|
||||||
|
@ -146,7 +166,7 @@ private:
|
||||||
|
|
||||||
bool allowUnsafeEquality;
|
bool allowUnsafeEquality;
|
||||||
|
|
||||||
ATermMap parseTrees;
|
std::map<Path, Expr *> parseTrees;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -159,12 +179,12 @@ public:
|
||||||
|
|
||||||
/* Evaluate an expression to normal form, storing the result in
|
/* Evaluate an expression to normal form, storing the result in
|
||||||
value `v'. */
|
value `v'. */
|
||||||
void eval(Expr e, Value & v);
|
void eval(Expr * e, Value & v);
|
||||||
void eval(Env & env, Expr e, Value & v);
|
void eval(Env & env, Expr * e, Value & v);
|
||||||
|
|
||||||
/* Evaluation the expression, then verify that it has the expected
|
/* Evaluation the expression, then verify that it has the expected
|
||||||
type. */
|
type. */
|
||||||
bool evalBool(Env & env, Expr e);
|
bool evalBool(Env & env, Expr * e);
|
||||||
|
|
||||||
/* If `v' is a thunk, enter it and overwrite `v' with the result
|
/* If `v' is a thunk, enter it and overwrite `v' with the result
|
||||||
of the evaluation of the thunk. If `v' is a delayed function
|
of the evaluation of the thunk. If `v' is a delayed function
|
||||||
|
@ -215,12 +235,12 @@ private:
|
||||||
void addPrimOp(const string & name,
|
void addPrimOp(const string & name,
|
||||||
unsigned int arity, PrimOp primOp);
|
unsigned int arity, PrimOp primOp);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
/* Do a deep equality test between two values. That is, list
|
/* Do a deep equality test between two values. That is, list
|
||||||
elements and attributes are compared recursively. */
|
elements and attributes are compared recursively. */
|
||||||
bool eqValues(Value & v1, Value & v2);
|
bool eqValues(Value & v1, Value & v2);
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void callFunction(Value & fun, Value & arg, Value & v);
|
void callFunction(Value & fun, Value & arg, Value & v);
|
||||||
|
|
||||||
/* Automatically call a function for which each argument has a
|
/* Automatically call a function for which each argument has a
|
||||||
|
@ -233,7 +253,7 @@ public:
|
||||||
|
|
||||||
void mkList(Value & v, unsigned int length);
|
void mkList(Value & v, unsigned int length);
|
||||||
void mkAttrs(Value & v);
|
void mkAttrs(Value & v);
|
||||||
void mkThunk_(Value & v, Expr expr);
|
void mkThunk_(Value & v, Expr * expr);
|
||||||
|
|
||||||
void cloneAttrs(Value & src, Value & dst);
|
void cloneAttrs(Value & src, Value & dst);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "get-drvs.hh"
|
#include "get-drvs.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ namespace nix {
|
||||||
string DrvInfo::queryDrvPath(EvalState & state) const
|
string DrvInfo::queryDrvPath(EvalState & state) const
|
||||||
{
|
{
|
||||||
if (drvPath == "") {
|
if (drvPath == "") {
|
||||||
Bindings::iterator i = attrs->find(toATerm("drvPath"));
|
Bindings::iterator i = attrs->find("drvPath");
|
||||||
PathSet context;
|
PathSet context;
|
||||||
(string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
|
(string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
|
||||||
}
|
}
|
||||||
|
@ -20,7 +19,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const
|
||||||
string DrvInfo::queryOutPath(EvalState & state) const
|
string DrvInfo::queryOutPath(EvalState & state) const
|
||||||
{
|
{
|
||||||
if (outPath == "") {
|
if (outPath == "") {
|
||||||
Bindings::iterator i = attrs->find(toATerm("outPath"));
|
Bindings::iterator i = attrs->find("outPath");
|
||||||
PathSet context;
|
PathSet context;
|
||||||
(string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
|
(string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : "";
|
||||||
}
|
}
|
||||||
|
@ -32,7 +31,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||||
{
|
{
|
||||||
MetaInfo meta;
|
MetaInfo meta;
|
||||||
|
|
||||||
Bindings::iterator a = attrs->find(toATerm("meta"));
|
Bindings::iterator a = attrs->find("meta");
|
||||||
if (a == attrs->end()) return meta; /* fine, empty meta information */
|
if (a == attrs->end()) return meta; /* fine, empty meta information */
|
||||||
|
|
||||||
state.forceAttrs(a->second);
|
state.forceAttrs(a->second);
|
||||||
|
@ -51,7 +50,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
|
||||||
for (unsigned int j = 0; j < i->second.list.length; ++j)
|
for (unsigned int j = 0; j < i->second.list.length; ++j)
|
||||||
value.stringValues.push_back(state.forceStringNoCtx(i->second.list.elems[j]));
|
value.stringValues.push_back(state.forceStringNoCtx(i->second.list.elems[j]));
|
||||||
} else continue;
|
} else continue;
|
||||||
meta[aterm2String(i->first)] = value;
|
meta[i->first] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta;
|
return meta;
|
||||||
|
@ -114,12 +113,12 @@ static bool getDerivation(EvalState & state, Value & v,
|
||||||
|
|
||||||
DrvInfo drv;
|
DrvInfo drv;
|
||||||
|
|
||||||
Bindings::iterator i = v.attrs->find(toATerm("name"));
|
Bindings::iterator i = v.attrs->find("name");
|
||||||
/* !!! We really would like to have a decent back trace here. */
|
/* !!! We really would like to have a decent back trace here. */
|
||||||
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
||||||
drv.name = state.forceStringNoCtx(i->second);
|
drv.name = state.forceStringNoCtx(i->second);
|
||||||
|
|
||||||
i = v.attrs->find(toATerm("system"));
|
i = v.attrs->find("system");
|
||||||
if (i == v.attrs->end())
|
if (i == v.attrs->end())
|
||||||
drv.system = "unknown";
|
drv.system = "unknown";
|
||||||
else
|
else
|
||||||
|
@ -171,7 +170,7 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
|
|
||||||
/* !!! undocumented hackery to support combining channels in
|
/* !!! undocumented hackery to support combining channels in
|
||||||
nix-env.cc. */
|
nix-env.cc. */
|
||||||
bool combineChannels = v.attrs->find(toATerm("_combineChannels")) != v.attrs->end();
|
bool combineChannels = v.attrs->find("_combineChannels") != v.attrs->end();
|
||||||
|
|
||||||
/* Consider the attributes in sorted order to get more
|
/* Consider the attributes in sorted order to get more
|
||||||
deterministic behaviour in nix-env operations (e.g. when
|
deterministic behaviour in nix-env operations (e.g. when
|
||||||
|
@ -180,12 +179,12 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
precedence). */
|
precedence). */
|
||||||
StringSet attrs;
|
StringSet attrs;
|
||||||
foreach (Bindings::iterator, i, *v.attrs)
|
foreach (Bindings::iterator, i, *v.attrs)
|
||||||
attrs.insert(aterm2String(i->first));
|
attrs.insert(i->first);
|
||||||
|
|
||||||
foreach (StringSet::iterator, i, attrs) {
|
foreach (StringSet::iterator, i, attrs) {
|
||||||
startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i);
|
startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % *i);
|
||||||
string pathPrefix2 = addToPath(pathPrefix, *i);
|
string pathPrefix2 = addToPath(pathPrefix, *i);
|
||||||
Value & v2((*v.attrs)[toATerm(*i)]);
|
Value & v2((*v.attrs)[*i]);
|
||||||
if (combineChannels)
|
if (combineChannels)
|
||||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
||||||
else if (getDerivation(state, v2, pathPrefix2, drvs, done)) {
|
else if (getDerivation(state, v2, pathPrefix2, drvs, done)) {
|
||||||
|
@ -194,7 +193,7 @@ static void getDerivations(EvalState & state, Value & vIn,
|
||||||
if it has a `recurseForDerivations = true'
|
if it has a `recurseForDerivations = true'
|
||||||
attribute. */
|
attribute. */
|
||||||
if (v2.type == tAttrs) {
|
if (v2.type == tAttrs) {
|
||||||
Bindings::iterator j = v2.attrs->find(toATerm("recurseForDerivations"));
|
Bindings::iterator j = v2.attrs->find("recurseForDerivations");
|
||||||
if (j != v2.attrs->end() && state.forceBool(j->second))
|
if (j != v2.attrs->end() && state.forceBool(j->second))
|
||||||
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
#include "aterm.hh"
|
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#define BISON_HEADER_HACK
|
#define BISON_HEADER_HACK
|
||||||
#include "parser-tab.hh"
|
#include "parser-tab.hh"
|
||||||
|
|
||||||
|
@ -45,8 +43,9 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr unescapeStr(const char * s)
|
static Expr * unescapeStr(const char * s)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
string t;
|
string t;
|
||||||
char c;
|
char c;
|
||||||
while ((c = *s++)) {
|
while ((c = *s++)) {
|
||||||
|
@ -66,6 +65,7 @@ static Expr unescapeStr(const char * s)
|
||||||
else t += c;
|
else t += c;
|
||||||
}
|
}
|
||||||
return makeStr(toATerm(t), ATempty);
|
return makeStr(toATerm(t), ATempty);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ inherit { return INHERIT; }
|
||||||
\/\/ { return UPDATE; }
|
\/\/ { return UPDATE; }
|
||||||
\+\+ { return CONCAT; }
|
\+\+ { return CONCAT; }
|
||||||
|
|
||||||
{ID} { yylval->t = toATerm(yytext); return ID; /* !!! alloc */ }
|
{ID} { yylval->id = strdup(yytext); return ID; }
|
||||||
{INT} { int n = atoi(yytext); /* !!! overflow */
|
{INT} { int n = atoi(yytext); /* !!! overflow */
|
||||||
yylval->n = n;
|
yylval->n = n;
|
||||||
return INT;
|
return INT;
|
||||||
|
@ -117,7 +117,7 @@ inherit { return INHERIT; }
|
||||||
shouldn't be followed by a "{". Right now "$\"" will be consumed
|
shouldn't be followed by a "{". Right now "$\"" will be consumed
|
||||||
as part of a string, rather than a "$" followed by the string
|
as part of a string, rather than a "$" followed by the string
|
||||||
terminator. Disallow "$\"" for now. */
|
terminator. Disallow "$\"" for now. */
|
||||||
yylval->t = unescapeStr(yytext); /* !!! alloc */
|
yylval->e = unescapeStr(yytext);
|
||||||
return STR;
|
return STR;
|
||||||
}
|
}
|
||||||
<STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
<STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
||||||
|
@ -126,31 +126,31 @@ inherit { return INHERIT; }
|
||||||
|
|
||||||
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
|
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
|
||||||
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
|
||||||
yylval->t = makeIndStr(toATerm(yytext));
|
//yylval->t = makeIndStr(toATerm(yytext));
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\'\'\$ {
|
<IND_STRING>\'\'\$ {
|
||||||
yylval->t = makeIndStr(toATerm("$"));
|
//yylval->t = makeIndStr(toATerm("$"));
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\'\'\' {
|
<IND_STRING>\'\'\' {
|
||||||
yylval->t = makeIndStr(toATerm("''"));
|
//yylval->t = makeIndStr(toATerm("''"));
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\'\'\\. {
|
<IND_STRING>\'\'\\. {
|
||||||
yylval->t = unescapeStr(yytext + 2);
|
//yylval->t = unescapeStr(yytext + 2);
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
|
||||||
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
|
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
|
||||||
<IND_STRING>\' {
|
<IND_STRING>\' {
|
||||||
yylval->t = makeIndStr(toATerm("'"));
|
//yylval->t = makeIndStr(toATerm("'"));
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
|
||||||
|
|
||||||
{PATH} { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ }
|
{PATH} { yylval->path = strdup(yytext); return PATH; }
|
||||||
{URI} { yylval->t = toATerm(yytext); return URI; /* !!! alloc */ }
|
{URI} { yylval->uri = strdup(yytext); return URI; }
|
||||||
|
|
||||||
[ \t\r\n]+ /* eat up whitespace */
|
[ \t\r\n]+ /* eat up whitespace */
|
||||||
\#[^\r\n]* /* single-line comments */
|
\#[^\r\n]* /* single-line comments */
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
init initNixExprHelpers
|
|
||||||
|
|
||||||
Pos | string int int | Pos |
|
|
||||||
NoPos | | Pos |
|
|
||||||
|
|
||||||
Function | Pattern Expr Pos | Expr |
|
|
||||||
Assert | Expr Expr Pos | Expr |
|
|
||||||
With | Expr Expr Pos | Expr |
|
|
||||||
If | Expr Expr Expr | Expr |
|
|
||||||
OpNot | Expr | Expr |
|
|
||||||
OpEq | Expr Expr | Expr |
|
|
||||||
OpNEq | Expr Expr | Expr |
|
|
||||||
OpAnd | Expr Expr | Expr |
|
|
||||||
OpOr | Expr Expr | Expr |
|
|
||||||
OpImpl | Expr Expr | Expr |
|
|
||||||
OpUpdate | Expr Expr | Expr |
|
|
||||||
OpHasAttr | Expr string | Expr |
|
|
||||||
OpPlus | Expr Expr | Expr |
|
|
||||||
OpConcat | Expr Expr | Expr |
|
|
||||||
ConcatStrings | ATermList | Expr |
|
|
||||||
Call | Expr Expr | Expr |
|
|
||||||
Select | Expr string | Expr |
|
|
||||||
Var | string | Expr |
|
|
||||||
Int | int | Expr |
|
|
||||||
|
|
||||||
# Strings in the evaluator carry a so-called `context' (the ATermList)
|
|
||||||
# which is a list of strings representing store paths. This is to
|
|
||||||
# allow users to write things like
|
|
||||||
#
|
|
||||||
# "--with-freetype2-library=" + freetype + "/lib"
|
|
||||||
#
|
|
||||||
# where `freetype' is a derivation (or a source to be copied to the
|
|
||||||
# store). If we just concatenated the strings without keeping track
|
|
||||||
# of the referenced store paths, then if the string is used as a
|
|
||||||
# derivation attribute, the derivation will not have the correct
|
|
||||||
# dependencies in its inputDrvs and inputSrcs.
|
|
||||||
#
|
|
||||||
# The semantics of the context is as follows: when a string with
|
|
||||||
# context C is used as a derivation attribute, then the derivations in
|
|
||||||
# C will be added to the inputDrvs of the derivation, and the other
|
|
||||||
# store paths in C will be added to the inputSrcs of the derivations.
|
|
||||||
#
|
|
||||||
# For canonicity, the store paths should be in sorted order.
|
|
||||||
Str | string ATermList | Expr |
|
|
||||||
Str | string | Expr | ObsoleteStr
|
|
||||||
|
|
||||||
# Internal to the parser, doesn't occur in ASTs.
|
|
||||||
IndStr | string | Expr |
|
|
||||||
|
|
||||||
# A path is a reference to a file system object that is to be copied
|
|
||||||
# to the Nix store when used as a derivation attribute. When it is
|
|
||||||
# concatenated to a string (i.e., `str + path'), it is also copied and
|
|
||||||
# the resulting store path is concatenated to the string (with the
|
|
||||||
# store path in the context). If a string or path is concatenated to
|
|
||||||
# a path (i.e., `path + str' or `path + path'), the result is a new
|
|
||||||
# path (if the right-hand side is a string, the context must be
|
|
||||||
# empty).
|
|
||||||
Path | string | Expr |
|
|
||||||
|
|
||||||
List | ATermList | Expr |
|
|
||||||
BlackHole | | Expr |
|
|
||||||
Undefined | | Expr |
|
|
||||||
Removed | | Expr |
|
|
||||||
PrimOp | int ATermBlob ATermList | Expr |
|
|
||||||
Attrs | ATermList | Expr |
|
|
||||||
Closed | Expr | Expr |
|
|
||||||
Rec | ATermList ATermList | Expr |
|
|
||||||
Bool | ATermBool | Expr |
|
|
||||||
Null | | Expr |
|
|
||||||
|
|
||||||
Bind | string Expr Pos | ATerm |
|
|
||||||
BindAttrPath | ATermList Expr Pos | ATerm | # desugared during parsing
|
|
||||||
Bind | string Expr | ATerm | ObsoleteBind
|
|
||||||
Inherit | Expr ATermList Pos | ATerm |
|
|
||||||
|
|
||||||
Scope | | Expr |
|
|
||||||
|
|
||||||
VarPat | string | Pattern |
|
|
||||||
AttrsPat | ATermList ATermBool string | Pattern | # bool = `...'
|
|
||||||
|
|
||||||
Formal | string DefaultValue | ATerm |
|
|
||||||
|
|
||||||
DefaultValue | Expr | DefaultValue |
|
|
||||||
NoDefaultValue | | DefaultValue |
|
|
||||||
|
|
||||||
True | | ATermBool |
|
|
||||||
False | | ATermBool |
|
|
||||||
|
|
||||||
PrimOpDef | int ATermBlob | ATerm |
|
|
||||||
|
|
||||||
AttrRHS | Expr Pos | ATerm |
|
|
||||||
|
|
||||||
eTrue = makeBool(makeTrue())
|
|
||||||
eFalse = makeBool(makeFalse())
|
|
||||||
sOverrides = toATerm("__overrides")
|
|
||||||
sNoAlias = toATerm("")
|
|
||||||
sWith = toATerm("<with>")
|
|
|
@ -1,17 +1,94 @@
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "aterm.hh"
|
|
||||||
|
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "nixexpr-ast.cc"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream & operator << (std::ostream & str, Expr & e)
|
||||||
|
{
|
||||||
|
e.show(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExprInt::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprString::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "\"" << s << "\""; // !!! escaping
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprPath::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprVar::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprSelect::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "(" << *e << ")." << name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprAttrs::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
if (recursive) str << "rec ";
|
||||||
|
str << "{ ";
|
||||||
|
foreach (list<string>::iterator, i, inherited)
|
||||||
|
str << "inherited " << *i << "; ";
|
||||||
|
foreach (Attrs::iterator, i, attrs)
|
||||||
|
str << i->first << " = " << *i->second << "; ";
|
||||||
|
str << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprList::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "[ ";
|
||||||
|
foreach (vector<Expr *>::iterator, i, elems)
|
||||||
|
str << "(" << **i << ") ";
|
||||||
|
str << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprLambda::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "(";
|
||||||
|
if (matchAttrs) {
|
||||||
|
str << "{ ";
|
||||||
|
bool first = true;
|
||||||
|
foreach (Formals::Formals_::iterator, i, formals->formals) {
|
||||||
|
if (first) first = false; else str << ", ";
|
||||||
|
str << i->name;
|
||||||
|
if (i->def) str << " ? " << *i->def;
|
||||||
|
}
|
||||||
|
str << " }";
|
||||||
|
if (arg != "") str << " @ ";
|
||||||
|
}
|
||||||
|
if (arg != "") str << arg;
|
||||||
|
str << ": " << *body << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprWith::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "with " << *attrs << "; " << *body;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprIf::show(std::ostream & str)
|
||||||
|
{
|
||||||
|
str << "if " << *cond << " then " << *then << " else " << *else_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
string showPos(ATerm pos)
|
string showPos(ATerm pos)
|
||||||
{
|
{
|
||||||
ATerm path;
|
ATerm path;
|
||||||
|
@ -159,28 +236,7 @@ void checkVarDefs(const ATermMap & defs, Expr e)
|
||||||
set<Expr> done;
|
set<Expr> done;
|
||||||
checkVarDefs2(done, defs, e);
|
checkVarDefs2(done, defs, e);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool matchStr(Expr e, string & s, PathSet & context)
|
|
||||||
{
|
|
||||||
ATermList l;
|
|
||||||
ATerm s_;
|
|
||||||
|
|
||||||
if (!matchStr(e, s_, l)) return false;
|
|
||||||
|
|
||||||
s = aterm2String(s_);
|
|
||||||
|
|
||||||
for (ATermIterator i(l); i; ++i)
|
|
||||||
context.insert(aterm2String(*i));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Expr makeStr(const string & s, const PathSet & context)
|
|
||||||
{
|
|
||||||
return makeStr(toATerm(s), toATermList(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "aterm-map.hh"
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,22 +17,152 @@ MakeError(Abort, EvalError)
|
||||||
MakeError(TypeError, EvalError)
|
MakeError(TypeError, EvalError)
|
||||||
|
|
||||||
|
|
||||||
/* Nix expressions are represented as ATerms. The maximal sharing
|
struct Pos
|
||||||
property of the ATerm library allows us to implement caching of
|
{
|
||||||
normals forms efficiently. */
|
string file;
|
||||||
typedef ATerm Expr;
|
unsigned int line, column;
|
||||||
typedef ATerm DefaultValue;
|
};
|
||||||
typedef ATerm Pos;
|
|
||||||
typedef ATerm Pattern;
|
|
||||||
typedef ATerm ATermBool;
|
|
||||||
|
|
||||||
|
|
||||||
/* A STL vector of ATerms. Should be used with great care since it's
|
/* Abstract syntax of Nix expressions. */
|
||||||
stored on the heap, and the elements are therefore not roots to the
|
|
||||||
ATerm garbage collector. */
|
struct Env;
|
||||||
typedef vector<ATerm> ATermVector;
|
struct Value;
|
||||||
|
struct EvalState;
|
||||||
|
|
||||||
|
struct Expr
|
||||||
|
{
|
||||||
|
virtual void show(std::ostream & str) = 0;
|
||||||
|
virtual void eval(EvalState & state, Env & env, Value & v)
|
||||||
|
{
|
||||||
|
throw Error("not implemented");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream & operator << (std::ostream & str, Expr & e);
|
||||||
|
|
||||||
|
#define COMMON_METHODS \
|
||||||
|
void show(std::ostream & str); \
|
||||||
|
void eval(EvalState & state, Env & env, Value & v);
|
||||||
|
|
||||||
|
struct ExprInt : Expr
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
ExprInt(int n) : n(n) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprString : Expr
|
||||||
|
{
|
||||||
|
string s;
|
||||||
|
ExprString(const string & s) : s(s) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprPath : Expr
|
||||||
|
{
|
||||||
|
string s;
|
||||||
|
ExprPath(const string & s) : s(s) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprVar : Expr
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
ExprVar(const string & name) : name(name) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprSelect : Expr
|
||||||
|
{
|
||||||
|
Expr * e;
|
||||||
|
string name;
|
||||||
|
ExprSelect(Expr * e, const string & name) : e(e), name(name) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprAttrs : Expr
|
||||||
|
{
|
||||||
|
bool recursive;
|
||||||
|
typedef std::map<string, Expr *> Attrs;
|
||||||
|
Attrs attrs;
|
||||||
|
list<string> inherited;
|
||||||
|
ExprAttrs() : recursive(false) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprList : Expr
|
||||||
|
{
|
||||||
|
std::vector<Expr *> elems;
|
||||||
|
ExprList() { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Formal
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
Expr * def;
|
||||||
|
Formal(const string & name, Expr * def) : name(name), def(def) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Formals
|
||||||
|
{
|
||||||
|
typedef std::list<Formal> Formals_;
|
||||||
|
Formals_ formals;
|
||||||
|
bool ellipsis;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprLambda : Expr
|
||||||
|
{
|
||||||
|
Pos pos;
|
||||||
|
string arg;
|
||||||
|
bool matchAttrs;
|
||||||
|
Formals * formals;
|
||||||
|
Expr * body;
|
||||||
|
ExprLambda(const Pos & pos, const string & arg, bool matchAttrs, Formals * formals, Expr * body)
|
||||||
|
: pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprWith : Expr
|
||||||
|
{
|
||||||
|
Pos pos;
|
||||||
|
Expr * attrs, * body;
|
||||||
|
ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprIf : Expr
|
||||||
|
{
|
||||||
|
Expr * cond, * then, * else_;
|
||||||
|
ExprIf(Expr * cond, Expr * then, Expr * else_) : cond(cond), then(then), else_(else_) { };
|
||||||
|
COMMON_METHODS
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MakeBinOp(name, s) \
|
||||||
|
struct Expr##name : Expr \
|
||||||
|
{ \
|
||||||
|
Expr * e1, * e2; \
|
||||||
|
Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
|
||||||
|
void show(std::ostream & str) \
|
||||||
|
{ \
|
||||||
|
str << *e1 << " " s " " << *e2; \
|
||||||
|
} \
|
||||||
|
void eval(EvalState & state, Env & env, Value & v); \
|
||||||
|
};
|
||||||
|
|
||||||
|
MakeBinOp(App, "")
|
||||||
|
MakeBinOp(OpEq, "==")
|
||||||
|
MakeBinOp(OpNEq, "!=")
|
||||||
|
MakeBinOp(OpAnd, "&&")
|
||||||
|
MakeBinOp(OpOr, "||")
|
||||||
|
MakeBinOp(OpImpl, "->")
|
||||||
|
MakeBinOp(OpUpdate, "//")
|
||||||
|
MakeBinOp(OpConcatStrings, "+")
|
||||||
|
MakeBinOp(OpConcatLists, "++")
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* Show a position. */
|
/* Show a position. */
|
||||||
string showPos(ATerm pos);
|
string showPos(ATerm pos);
|
||||||
|
|
||||||
|
@ -56,13 +185,7 @@ Expr makeAttrs(const ATermMap & attrs);
|
||||||
/* Check whether all variables are defined in the given expression.
|
/* Check whether all variables are defined in the given expression.
|
||||||
Throw an exception if this isn't the case. */
|
Throw an exception if this isn't the case. */
|
||||||
void checkVarDefs(const ATermMap & def, Expr e);
|
void checkVarDefs(const ATermMap & def, Expr e);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Manipulation of Str() nodes. Note: matchStr() does not clear
|
|
||||||
context! */
|
|
||||||
bool matchStr(Expr e, string & s, PathSet & context);
|
|
||||||
|
|
||||||
Expr makeStr(const string & s, const PathSet & context = PathSet());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,10 @@ namespace nix {
|
||||||
|
|
||||||
/* Parse a Nix expression from the specified file. If `path' refers
|
/* Parse a Nix expression from the specified file. If `path' refers
|
||||||
to a directory, then "/default.nix" is appended. */
|
to a directory, then "/default.nix" is appended. */
|
||||||
Expr parseExprFromFile(EvalState & state, Path path);
|
Expr * parseExprFromFile(Path path);
|
||||||
|
|
||||||
/* Parse a Nix expression from the specified string. */
|
/* Parse a Nix expression from the specified string. */
|
||||||
Expr parseExprFromString(EvalState & state, const string & s,
|
Expr * parseExprFromString(const string & s, const Path & basePath);
|
||||||
const Path & basePath);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,12 @@
|
||||||
#include "aterm.hh"
|
#include "aterm.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
|
#include "nixexpr.hh"
|
||||||
|
|
||||||
#include "parser-tab.hh"
|
#include "parser-tab.hh"
|
||||||
#include "lexer-tab.hh"
|
#include "lexer-tab.hh"
|
||||||
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
|
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
|
||||||
|
|
||||||
#include "nixexpr.hh"
|
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
|
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
|
@ -39,13 +38,14 @@ namespace nix {
|
||||||
|
|
||||||
struct ParseData
|
struct ParseData
|
||||||
{
|
{
|
||||||
Expr result;
|
Expr * result;
|
||||||
Path basePath;
|
Path basePath;
|
||||||
Path path;
|
Path path;
|
||||||
string error;
|
string error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
static string showAttrPath(ATermList attrPath)
|
static string showAttrPath(ATermList attrPath)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
|
@ -79,10 +79,12 @@ static ATermList buildAttrs(const Tree & t, ATermList & nonrec)
|
||||||
: makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos()));
|
: makeBind(i->first, makeAttrs(buildAttrs(i->second, nonrec)), makeNoPos()));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static Expr fixAttrs(bool recursive, ATermList as)
|
static void fixAttrs(ExprAttrs & attrs)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
Tree attrs;
|
Tree attrs;
|
||||||
|
|
||||||
/* This ATermMap is needed to ensure that the `leaf' fields in the
|
/* This ATermMap is needed to ensure that the `leaf' fields in the
|
||||||
|
@ -135,9 +137,11 @@ static Expr fixAttrs(bool recursive, ATermList as)
|
||||||
ATermList rec = buildAttrs(attrs, nonrec);
|
ATermList rec = buildAttrs(attrs, nonrec);
|
||||||
|
|
||||||
return recursive ? makeRec(rec, nonrec) : makeAttrs(rec);
|
return recursive ? makeRec(rec, nonrec) : makeAttrs(rec);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat)
|
static void checkPatternVars(ATerm pos, ATermMap & map, Pattern pat)
|
||||||
{
|
{
|
||||||
ATerm name = sNoAlias;
|
ATerm name = sNoAlias;
|
||||||
|
@ -261,6 +265,7 @@ static Expr stripIndentation(ATermList es)
|
||||||
|
|
||||||
return makeConcatStrings(ATreverse(es2));
|
return makeConcatStrings(ATreverse(es2));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void backToString(yyscan_t scanner);
|
void backToString(yyscan_t scanner);
|
||||||
|
@ -269,8 +274,11 @@ void backToIndString(yyscan_t scanner);
|
||||||
|
|
||||||
static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
|
static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
|
||||||
{
|
{
|
||||||
return makePos(toATerm(data->path),
|
Pos pos;
|
||||||
loc->first_line, loc->first_column);
|
pos.file = data->path;
|
||||||
|
pos.line = loc->first_line;
|
||||||
|
pos.column = loc->first_column;
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CUR_POS makeCurPos(yylocp, data)
|
#define CUR_POS makeCurPos(yylocp, data)
|
||||||
|
@ -311,22 +319,31 @@ static void freeAndUnprotect(void * p)
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
ATerm t;
|
nix::Expr * e;
|
||||||
ATermList ts;
|
nix::ExprList * list;
|
||||||
struct {
|
nix::ExprAttrs * attrs;
|
||||||
ATermList formals;
|
nix::Formals * formals;
|
||||||
bool ellipsis;
|
nix::Formal * formal;
|
||||||
} formals;
|
|
||||||
int n;
|
int n;
|
||||||
|
char * id;
|
||||||
|
char * path;
|
||||||
|
char * uri;
|
||||||
|
std::list<std::string> * ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
%type <t> start expr expr_function expr_if expr_op
|
%type <e> start expr expr_function expr_if expr_op
|
||||||
%type <t> expr_app expr_select expr_simple bind inheritsrc formal
|
%type <e> expr_app expr_select expr_simple
|
||||||
%type <t> pattern
|
%type <list> expr_list
|
||||||
%type <ts> binds ids attrpath expr_list string_parts ind_string_parts
|
%type <attrs> binds
|
||||||
|
%type <ts> attrpath string_parts ind_string_parts
|
||||||
%type <formals> formals
|
%type <formals> formals
|
||||||
%token <t> ID STR IND_STR PATH URI
|
%type <formal> formal
|
||||||
|
%type <ids> ids
|
||||||
|
%token <id> ID ATTRPATH
|
||||||
|
%token <t> STR IND_STR
|
||||||
%token <n> INT
|
%token <n> INT
|
||||||
|
%token <path> PATH
|
||||||
|
%token <uri> URI
|
||||||
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
|
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
|
||||||
%token DOLLAR_CURLY /* == ${ */
|
%token DOLLAR_CURLY /* == ${ */
|
||||||
%token IND_STRING_OPEN IND_STRING_CLOSE
|
%token IND_STRING_OPEN IND_STRING_CLOSE
|
||||||
|
@ -350,54 +367,63 @@ start: expr { data->result = $1; };
|
||||||
expr: expr_function;
|
expr: expr_function;
|
||||||
|
|
||||||
expr_function
|
expr_function
|
||||||
: pattern ':' expr_function
|
: ID ':' expr_function
|
||||||
{ checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); }
|
{ $$ = new ExprLambda(CUR_POS, $1, false, 0, $3); /* checkPatternVars(CUR_POS, $1); $$ = makeFunction($1, $3, CUR_POS); */ }
|
||||||
| ASSERT expr ';' expr_function
|
| '{' formals '}' ':' expr_function
|
||||||
|
{ $$ = new ExprLambda(CUR_POS, "", true, $2, $5); }
|
||||||
|
| '{' formals '}' '@' ID ':' expr_function
|
||||||
|
{ $$ = new ExprLambda(CUR_POS, $5, true, $2, $7); }
|
||||||
|
| ID '@' '{' formals '}' ':' expr_function
|
||||||
|
{ $$ = new ExprLambda(CUR_POS, $1, true, $4, $7); }
|
||||||
|
/* | ASSERT expr ';' expr_function
|
||||||
{ $$ = makeAssert($2, $4, CUR_POS); }
|
{ $$ = makeAssert($2, $4, CUR_POS); }
|
||||||
|
*/
|
||||||
| WITH expr ';' expr_function
|
| WITH expr ';' expr_function
|
||||||
{ $$ = makeWith($2, $4, CUR_POS); }
|
{ $$ = new ExprWith(CUR_POS, $2, $4); }
|
||||||
| LET binds IN expr_function
|
| LET binds IN expr_function
|
||||||
{ $$ = makeSelect(fixAttrs(true, ATinsert($2, makeBindAttrPath(ATmakeList1(toATerm("<let-body>")), $4, CUR_POS))), toATerm("<let-body>")); }
|
{ $2->attrs["<let-body>"] = $4; $2->recursive = true; fixAttrs(*$2); $$ = new ExprSelect($2, "<let-body>"); }
|
||||||
| expr_if
|
| expr_if
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_if
|
expr_if
|
||||||
: IF expr THEN expr ELSE expr
|
: IF expr THEN expr ELSE expr { $$ = new ExprIf($2, $4, $6); }
|
||||||
{ $$ = makeIf($2, $4, $6); }
|
|
||||||
| expr_op
|
| expr_op
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_op
|
expr_op
|
||||||
: '!' expr_op %prec NEG { $$ = makeOpNot($2); }
|
: /* '!' expr_op %prec NEG { $$ = makeOpNot($2); }
|
||||||
| expr_op EQ expr_op { $$ = makeOpEq($1, $3); }
|
| */
|
||||||
| expr_op NEQ expr_op { $$ = makeOpNEq($1, $3); }
|
expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
|
||||||
| expr_op AND expr_op { $$ = makeOpAnd($1, $3); }
|
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
|
||||||
| expr_op OR expr_op { $$ = makeOpOr($1, $3); }
|
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
|
||||||
| expr_op IMPL expr_op { $$ = makeOpImpl($1, $3); }
|
| expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
|
||||||
| expr_op UPDATE expr_op { $$ = makeOpUpdate($1, $3); }
|
| expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
|
||||||
|
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); }
|
||||||
|
/*
|
||||||
| expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
|
| expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
|
||||||
| expr_op '+' expr_op { $$ = makeConcatStrings(ATmakeList2($1, $3)); }
|
*/
|
||||||
| expr_op CONCAT expr_op { $$ = makeOpConcat($1, $3); }
|
| expr_op '+' expr_op { $$ = new ExprOpConcatStrings($1, $3); }
|
||||||
|
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
|
||||||
| expr_app
|
| expr_app
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_app
|
expr_app
|
||||||
: expr_app expr_select
|
: expr_app expr_select
|
||||||
{ $$ = makeCall($1, $2); }
|
{ $$ = new ExprApp($1, $2); }
|
||||||
| expr_select { $$ = $1; }
|
| expr_select { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_select
|
expr_select
|
||||||
: expr_select '.' ID
|
: expr_select '.' ID
|
||||||
{ $$ = makeSelect($1, $3); }
|
{ $$ = new ExprSelect($1, $3); }
|
||||||
| expr_simple { $$ = $1; }
|
| expr_simple { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_simple
|
expr_simple
|
||||||
: ID { $$ = makeVar($1); }
|
: ID { $$ = new ExprVar($1); }
|
||||||
| INT { $$ = makeInt($1); }
|
| INT { $$ = new ExprInt($1); } /*
|
||||||
| '"' string_parts '"' {
|
| '"' string_parts '"' {
|
||||||
/* For efficiency, and to simplify parse trees a bit. */
|
/* For efficiency, and to simplify parse trees a bit. * /
|
||||||
if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
|
if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
|
||||||
else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
|
else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
|
||||||
else $$ = makeConcatStrings(ATreverse($2));
|
else $$ = makeConcatStrings(ATreverse($2));
|
||||||
|
@ -405,18 +431,21 @@ expr_simple
|
||||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||||
$$ = stripIndentation(ATreverse($2));
|
$$ = stripIndentation(ATreverse($2));
|
||||||
}
|
}
|
||||||
| PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); }
|
*/
|
||||||
| URI { $$ = makeStr($1, ATempty); }
|
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
|
||||||
|
| URI { $$ = new ExprString($1); }
|
||||||
| '(' expr ')' { $$ = $2; }
|
| '(' expr ')' { $$ = $2; }
|
||||||
|
/*
|
||||||
/* Let expressions `let {..., body = ...}' are just desugared
|
/* Let expressions `let {..., body = ...}' are just desugared
|
||||||
into `(rec {..., body = ...}).body'. */
|
into `(rec {..., body = ...}).body'. * /
|
||||||
| LET '{' binds '}'
|
| LET '{' binds '}'
|
||||||
{ $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); }
|
{ $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); }
|
||||||
|
*/
|
||||||
| REC '{' binds '}'
|
| REC '{' binds '}'
|
||||||
{ $$ = fixAttrs(true, $3); }
|
{ fixAttrs(*$3); $3->recursive = true; $$ = $3; }
|
||||||
| '{' binds '}'
|
| '{' binds '}'
|
||||||
{ $$ = fixAttrs(false, $2); }
|
{ fixAttrs(*$2); $$ = $2; }
|
||||||
| '[' expr_list ']' { $$ = makeList(ATreverse($2)); }
|
| '[' expr_list ']' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
string_parts
|
string_parts
|
||||||
|
@ -431,63 +460,56 @@ ind_string_parts
|
||||||
| { $$ = ATempty; }
|
| { $$ = ATempty; }
|
||||||
;
|
;
|
||||||
|
|
||||||
pattern
|
|
||||||
: ID { $$ = makeVarPat($1); }
|
|
||||||
| '{' formals '}' { $$ = makeAttrsPat($2.formals, $2.ellipsis ? eTrue : eFalse, sNoAlias); }
|
|
||||||
| '{' formals '}' '@' ID { $$ = makeAttrsPat($2.formals, $2.ellipsis ? eTrue : eFalse, $5); }
|
|
||||||
| ID '@' '{' formals '}' { $$ = makeAttrsPat($4.formals, $4.ellipsis ? eTrue : eFalse, $1); }
|
|
||||||
;
|
|
||||||
|
|
||||||
binds
|
binds
|
||||||
: binds bind { $$ = ATinsert($1, $2); }
|
: binds ID '=' expr ';' { $$ = $1; $$->attrs[$2] = $4; }
|
||||||
| { $$ = ATempty; }
|
| binds INHERIT ids ';'
|
||||||
|
{ $$ = $1;
|
||||||
|
foreach (list<string>::iterator, i, *$3)
|
||||||
|
$$->inherited.push_back(*i);
|
||||||
|
}
|
||||||
|
| binds INHERIT '(' expr ')' ids ';'
|
||||||
|
{ $$ = $1;
|
||||||
|
/* !!! Should ensure sharing of the expression in $4. */
|
||||||
|
foreach (list<string>::iterator, i, *$6)
|
||||||
|
$$->attrs[*i] = new ExprSelect($4, *i);
|
||||||
|
}
|
||||||
|
| { $$ = new ExprAttrs; }
|
||||||
;
|
;
|
||||||
|
|
||||||
bind
|
ids
|
||||||
: attrpath '=' expr ';'
|
: ids ID { $$ = $1; $1->push_back($2); /* !!! dangerous */ }
|
||||||
{ $$ = makeBindAttrPath(ATreverse($1), $3, CUR_POS); }
|
| { $$ = new list<string>; }
|
||||||
| INHERIT inheritsrc ids ';'
|
|
||||||
{ $$ = makeInherit($2, $3, CUR_POS); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
inheritsrc
|
|
||||||
: '(' expr ')' { $$ = $2; }
|
|
||||||
| { $$ = makeScope(); }
|
|
||||||
;
|
|
||||||
|
|
||||||
ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; };
|
|
||||||
|
|
||||||
attrpath
|
attrpath
|
||||||
: attrpath '.' ID { $$ = ATinsert($1, $3); }
|
: attrpath '.' ID { $$ = ATinsert($1, $3); }
|
||||||
| ID { $$ = ATmakeList1($1); }
|
| ID { $$ = ATmakeList1($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_list
|
expr_list
|
||||||
: expr_list expr_select { $$ = ATinsert($1, $2); }
|
: expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ }
|
||||||
| { $$ = ATempty; }
|
| { $$ = new ExprList; }
|
||||||
;
|
;
|
||||||
|
|
||||||
formals
|
formals
|
||||||
: formal ',' formals /* !!! right recursive */
|
: formal ',' formals
|
||||||
{ $$.formals = ATinsert($3.formals, $1); $$.ellipsis = $3.ellipsis; }
|
{ $$ = $3; $$->formals.push_front(*$1); /* !!! dangerous */ }
|
||||||
| formal
|
| formal
|
||||||
{ $$.formals = ATinsert(ATempty, $1); $$.ellipsis = false; }
|
{ $$ = new Formals; $$->formals.push_back(*$1); $$->ellipsis = false; }
|
||||||
|
|
|
|
||||||
{ $$.formals = ATempty; $$.ellipsis = false; }
|
{ $$ = new Formals; $$->ellipsis = false; }
|
||||||
| ELLIPSIS
|
| ELLIPSIS
|
||||||
{ $$.formals = ATempty; $$.ellipsis = true; }
|
{ $$ = new Formals; $$->ellipsis = true; }
|
||||||
;
|
;
|
||||||
|
|
||||||
formal
|
formal
|
||||||
: ID { $$ = makeFormal($1, makeNoDefaultValue()); }
|
: ID { $$ = new Formal($1, 0); }
|
||||||
| ID '?' expr { $$ = makeFormal($1, makeDefaultValue($3)); }
|
| ID '?' expr { $$ = new Formal($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
#include "eval.hh"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -497,9 +519,7 @@ formal
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
static Expr parse(EvalState & state,
|
static Expr * parse(const char * text, const Path & path, const Path & basePath)
|
||||||
const char * text, const Path & path,
|
|
||||||
const Path & basePath)
|
|
||||||
{
|
{
|
||||||
yyscan_t scanner;
|
yyscan_t scanner;
|
||||||
ParseData data;
|
ParseData data;
|
||||||
|
@ -523,7 +543,7 @@ static Expr parse(EvalState & state,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr parseExprFromFile(EvalState & state, Path path)
|
Expr * parseExprFromFile(Path path)
|
||||||
{
|
{
|
||||||
assert(path[0] == '/');
|
assert(path[0] == '/');
|
||||||
|
|
||||||
|
@ -544,14 +564,13 @@ Expr parseExprFromFile(EvalState & state, Path path)
|
||||||
path = canonPath(path + "/default.nix");
|
path = canonPath(path + "/default.nix");
|
||||||
|
|
||||||
/* Read and parse the input file. */
|
/* Read and parse the input file. */
|
||||||
return parse(state, readFile(path).c_str(), path, dirOf(path));
|
return parse(readFile(path).c_str(), path, dirOf(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr parseExprFromString(EvalState & state,
|
Expr * parseExprFromString(const string & s, const Path & basePath)
|
||||||
const string & s, const Path & basePath)
|
|
||||||
{
|
{
|
||||||
return parse(state, s.c_str(), "(string)", basePath);
|
return parse(s.c_str(), "(string)", basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "value-to-xml.hh"
|
#include "value-to-xml.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
#include "names.hh"
|
#include "names.hh"
|
||||||
|
|
||||||
|
@ -281,7 +280,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||||
state.forceAttrs(*args[0]);
|
state.forceAttrs(*args[0]);
|
||||||
|
|
||||||
/* Figure out the name first (for stack backtraces). */
|
/* Figure out the name first (for stack backtraces). */
|
||||||
Bindings::iterator attr = args[0]->attrs->find(toATerm("name"));
|
Bindings::iterator attr = args[0]->attrs->find("name");
|
||||||
if (attr == args[0]->attrs->end())
|
if (attr == args[0]->attrs->end())
|
||||||
throw EvalError("required attribute `name' missing");
|
throw EvalError("required attribute `name' missing");
|
||||||
string drvName;
|
string drvName;
|
||||||
|
@ -302,7 +301,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||||
bool outputHashRecursive = false;
|
bool outputHashRecursive = false;
|
||||||
|
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
foreach (Bindings::iterator, i, *args[0]->attrs) {
|
||||||
string key = aterm2String(i->first);
|
string key = i->first;
|
||||||
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
|
startNest(nest, lvlVomit, format("processing attribute `%1%'") % key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -449,8 +448,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||||
|
|
||||||
/* !!! assumes a single output */
|
/* !!! assumes a single output */
|
||||||
state.mkAttrs(v);
|
state.mkAttrs(v);
|
||||||
mkString((*v.attrs)[toATerm("outPath")], outPath, singleton<PathSet>(drvPath));
|
mkString((*v.attrs)["outPath"], outPath, singleton<PathSet>(drvPath));
|
||||||
mkString((*v.attrs)[toATerm("drvPath")], drvPath, singleton<PathSet>("=" + drvPath));
|
mkString((*v.attrs)["drvPath"], drvPath, singleton<PathSet>("=" + drvPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -655,7 +654,7 @@ static void prim_attrNames(EvalState & state, Value * * args, Value & v)
|
||||||
|
|
||||||
StringSet names;
|
StringSet names;
|
||||||
foreach (Bindings::iterator, i, *args[0]->attrs)
|
foreach (Bindings::iterator, i, *args[0]->attrs)
|
||||||
names.insert(aterm2String(i->first));
|
names.insert(i->first);
|
||||||
|
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
foreach (StringSet::iterator, i, names)
|
foreach (StringSet::iterator, i, names)
|
||||||
|
@ -668,7 +667,7 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = state.forceStringNoCtx(*args[0]);
|
string attr = state.forceStringNoCtx(*args[0]);
|
||||||
state.forceAttrs(*args[1]);
|
state.forceAttrs(*args[1]);
|
||||||
Bindings::iterator i = args[1]->attrs->find(toATerm(attr));
|
Bindings::iterator i = args[1]->attrs->find(attr);
|
||||||
if (i == args[1]->attrs->end())
|
if (i == args[1]->attrs->end())
|
||||||
throw EvalError(format("attribute `%1%' missing") % attr);
|
throw EvalError(format("attribute `%1%' missing") % attr);
|
||||||
state.forceValue(i->second);
|
state.forceValue(i->second);
|
||||||
|
@ -681,7 +680,7 @@ static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string attr = state.forceStringNoCtx(*args[0]);
|
string attr = state.forceStringNoCtx(*args[0]);
|
||||||
state.forceAttrs(*args[1]);
|
state.forceAttrs(*args[1]);
|
||||||
mkBool(v, args[1]->attrs->find(toATerm(attr)) != args[1]->attrs->end());
|
mkBool(v, args[1]->attrs->find(attr) != args[1]->attrs->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -702,7 +701,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
|
||||||
|
|
||||||
for (unsigned int i = 0; i < args[1]->list.length; ++i) {
|
for (unsigned int i = 0; i < args[1]->list.length; ++i) {
|
||||||
state.forceStringNoCtx(args[1]->list.elems[i]);
|
state.forceStringNoCtx(args[1]->list.elems[i]);
|
||||||
v.attrs->erase(toATerm(args[1]->list.elems[i].string.s));
|
v.attrs->erase(args[1]->list.elems[i].string.s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,16 +720,16 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
|
||||||
Value & v2(args[0]->list.elems[i]);
|
Value & v2(args[0]->list.elems[i]);
|
||||||
state.forceAttrs(v2);
|
state.forceAttrs(v2);
|
||||||
|
|
||||||
Bindings::iterator j = v2.attrs->find(toATerm("name"));
|
Bindings::iterator j = v2.attrs->find("name");
|
||||||
if (j == v2.attrs->end())
|
if (j == v2.attrs->end())
|
||||||
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
|
throw TypeError("`name' attribute missing in a call to `listToAttrs'");
|
||||||
string name = state.forceStringNoCtx(j->second);
|
string name = state.forceStringNoCtx(j->second);
|
||||||
|
|
||||||
j = v2.attrs->find(toATerm("value"));
|
j = v2.attrs->find("value");
|
||||||
if (j == v2.attrs->end())
|
if (j == v2.attrs->end())
|
||||||
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
throw TypeError("`value' attribute missing in a call to `listToAttrs'");
|
||||||
|
|
||||||
(*v.attrs)[toATerm(name)] = j->second; // !!! sharing?
|
(*v.attrs)[name] = j->second; // !!! sharing?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,8 +976,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v)
|
||||||
string name = state.forceStringNoCtx(*args[0]);
|
string name = state.forceStringNoCtx(*args[0]);
|
||||||
DrvName parsed(name);
|
DrvName parsed(name);
|
||||||
state.mkAttrs(v);
|
state.mkAttrs(v);
|
||||||
mkString((*v.attrs)[toATerm("name")], parsed.name);
|
mkString((*v.attrs)["name"], parsed.name);
|
||||||
mkString((*v.attrs)[toATerm("version")], parsed.version);
|
mkString((*v.attrs)["version"], parsed.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -999,10 +998,9 @@ void EvalState::createBaseEnv()
|
||||||
{
|
{
|
||||||
baseEnv.up = 0;
|
baseEnv.up = 0;
|
||||||
|
|
||||||
{ Value & v = baseEnv.bindings[toATerm("builtins")];
|
Value & builtins = baseEnv.bindings["builtins"];
|
||||||
v.type = tAttrs;
|
builtins.type = tAttrs;
|
||||||
v.attrs = new Bindings;
|
builtins.attrs = new Bindings;
|
||||||
}
|
|
||||||
|
|
||||||
/* Add global constants such as `true' to the base environment. */
|
/* Add global constants such as `true' to the base environment. */
|
||||||
Value v;
|
Value v;
|
||||||
|
@ -1025,8 +1023,8 @@ void EvalState::createBaseEnv()
|
||||||
/* Add a wrapper around the derivation primop that computes the
|
/* Add a wrapper around the derivation primop that computes the
|
||||||
`drvPath' and `outPath' attributes lazily. */
|
`drvPath' and `outPath' attributes lazily. */
|
||||||
string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }";
|
string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }";
|
||||||
mkThunk(v, baseEnv, parseExprFromString(*this, s, "/"));
|
//mkThunk(v, baseEnv, parseExprFromString(s, "/"));
|
||||||
addConstant("derivation", v);
|
//addConstant("derivation", v);
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
addPrimOp("import", 1, prim_import);
|
addPrimOp("import", 1, prim_import);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#include "value-to-xml.hh"
|
#include "value-to-xml.hh"
|
||||||
#include "xml-writer.hh"
|
#include "xml-writer.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "aterm.hh"
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -27,31 +25,10 @@ static void showAttrs(EvalState & state, bool strict, Bindings & attrs,
|
||||||
{
|
{
|
||||||
StringSet names;
|
StringSet names;
|
||||||
foreach (Bindings::iterator, i, attrs)
|
foreach (Bindings::iterator, i, attrs)
|
||||||
names.insert(aterm2String(i->first));
|
names.insert(i->first);
|
||||||
foreach (StringSet::iterator, i, names) {
|
foreach (StringSet::iterator, i, names) {
|
||||||
XMLOpenElement _(doc, "attr", singletonAttrs("name", *i));
|
XMLOpenElement _(doc, "attr", singletonAttrs("name", *i));
|
||||||
printValueAsXML(state, strict, attrs[toATerm(*i)], doc, context, drvsSeen);
|
printValueAsXML(state, strict, attrs[*i], doc, context, drvsSeen);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void printPatternAsXML(Pattern pat, XMLWriter & doc)
|
|
||||||
{
|
|
||||||
ATerm name;
|
|
||||||
ATermList formals;
|
|
||||||
ATermBool ellipsis;
|
|
||||||
if (matchVarPat(pat, name))
|
|
||||||
doc.writeEmptyElement("varpat", singletonAttrs("name", aterm2String(name)));
|
|
||||||
else if (matchAttrsPat(pat, formals, ellipsis, name)) {
|
|
||||||
XMLAttrs attrs;
|
|
||||||
if (name != sNoAlias) attrs["name"] = aterm2String(name);
|
|
||||||
if (ellipsis == eTrue) attrs["ellipsis"] = "1";
|
|
||||||
XMLOpenElement _(doc, "attrspat", attrs);
|
|
||||||
for (ATermIterator i(formals); i; ++i) {
|
|
||||||
Expr name; ATerm dummy;
|
|
||||||
if (!matchFormal(*i, name, dummy)) abort();
|
|
||||||
doc.writeEmptyElement("attr", singletonAttrs("name", aterm2String(name)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,14 +67,14 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v,
|
||||||
if (state.isDerivation(v)) {
|
if (state.isDerivation(v)) {
|
||||||
XMLAttrs xmlAttrs;
|
XMLAttrs xmlAttrs;
|
||||||
|
|
||||||
Bindings::iterator a = v.attrs->find(toATerm("derivation"));
|
Bindings::iterator a = v.attrs->find("derivation");
|
||||||
|
|
||||||
Path drvPath;
|
Path drvPath;
|
||||||
a = v.attrs->find(toATerm("drvPath"));
|
a = v.attrs->find("drvPath");
|
||||||
if (a != v.attrs->end() && a->second.type == tString)
|
if (a != v.attrs->end() && a->second.type == tString)
|
||||||
xmlAttrs["drvPath"] = drvPath = a->second.string.s;
|
xmlAttrs["drvPath"] = drvPath = a->second.string.s;
|
||||||
|
|
||||||
a = v.attrs->find(toATerm("outPath"));
|
a = v.attrs->find("outPath");
|
||||||
if (a != v.attrs->end() && a->second.type == tString)
|
if (a != v.attrs->end() && a->second.type == tString)
|
||||||
xmlAttrs["outPath"] = a->second.string.s;
|
xmlAttrs["outPath"] = a->second.string.s;
|
||||||
|
|
||||||
|
@ -126,7 +103,15 @@ static void printValueAsXML(EvalState & state, bool strict, Value & v,
|
||||||
|
|
||||||
case tLambda: {
|
case tLambda: {
|
||||||
XMLOpenElement _(doc, "function");
|
XMLOpenElement _(doc, "function");
|
||||||
printPatternAsXML(v.lambda.pat, doc);
|
if (v.lambda.fun->matchAttrs) {
|
||||||
|
XMLAttrs attrs;
|
||||||
|
if (!v.lambda.fun->arg.empty()) attrs["name"] = v.lambda.fun->arg;
|
||||||
|
if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1";
|
||||||
|
XMLOpenElement _(doc, "attrspat", attrs);
|
||||||
|
foreach (Formals::Formals_::iterator, i, v.lambda.fun->formals->formals)
|
||||||
|
doc.writeEmptyElement("attr", singletonAttrs("name", i->name));
|
||||||
|
} else
|
||||||
|
doc.writeEmptyElement("varpat", singletonAttrs("name", v.lambda.fun->arg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ static void initAndRun(int argc, char * * argv)
|
||||||
if (lt != "") setLogType(lt);
|
if (lt != "") setLogType(lt);
|
||||||
|
|
||||||
/* ATerm stuff. !!! find a better place to put this */
|
/* ATerm stuff. !!! find a better place to put this */
|
||||||
initDerivationsHelpers();
|
//initDerivationsHelpers();
|
||||||
|
|
||||||
/* Put the arguments in a vector. */
|
/* Put the arguments in a vector. */
|
||||||
Strings args, remaining;
|
Strings args, remaining;
|
||||||
|
@ -335,7 +335,7 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
/* ATerm setup. */
|
/* ATerm setup. */
|
||||||
ATerm bottomOfStack;
|
ATerm bottomOfStack;
|
||||||
ATinit(argc, argv, &bottomOfStack);
|
//ATinit(argc, argv, &bottomOfStack);
|
||||||
|
|
||||||
/* Turn on buffering for cerr. */
|
/* Turn on buffering for cerr. */
|
||||||
#if HAVE_PUBSETBUF
|
#if HAVE_PUBSETBUF
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "help.txt.hh"
|
#include "help.txt.hh"
|
||||||
#include "nixexpr-ast.hh"
|
|
||||||
#include "get-drvs.hh"
|
#include "get-drvs.hh"
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
#include "pathlocks.hh"
|
#include "pathlocks.hh"
|
||||||
|
@ -143,9 +142,9 @@ static void getAllExprs(EvalState & state,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr loadSourceExpr(EvalState & state, const Path & path)
|
static Expr * loadSourceExpr(EvalState & state, const Path & path)
|
||||||
{
|
{
|
||||||
if (isNixExpr(path)) return parseExprFromFile(state, absPath(path));
|
if (isNixExpr(path)) return parseExprFromFile(absPath(path));
|
||||||
|
|
||||||
/* The path is a directory. Put the Nix expressions in the
|
/* The path is a directory. Put the Nix expressions in the
|
||||||
directory in an attribute set, with the file name of each
|
directory in an attribute set, with the file name of each
|
||||||
|
|
|
@ -23,12 +23,12 @@ void printHelp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr parseStdin(EvalState & state)
|
static Expr * parseStdin(EvalState & state)
|
||||||
{
|
{
|
||||||
startNest(nest, lvlTalkative, format("parsing standard input"));
|
startNest(nest, lvlTalkative, format("parsing standard input"));
|
||||||
string s, s2;
|
string s, s2;
|
||||||
while (getline(std::cin, s2)) s += s2 + "\n";
|
while (getline(std::cin, s2)) s += s2 + "\n";
|
||||||
return parseExprFromString(state, s, absPath("."));
|
return parseExprFromString(s, absPath("."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ static bool indirectRoot = false;
|
||||||
|
|
||||||
void processExpr(EvalState & state, const Strings & attrPaths,
|
void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
bool parseOnly, bool strict, const Bindings & autoArgs,
|
bool parseOnly, bool strict, const Bindings & autoArgs,
|
||||||
bool evalOnly, bool xmlOutput, Expr e)
|
bool evalOnly, bool xmlOutput, Expr * e)
|
||||||
{
|
{
|
||||||
if (parseOnly)
|
if (parseOnly)
|
||||||
std::cout << format("%1%\n");
|
std::cout << format("%1%\n");
|
||||||
|
@ -129,14 +129,14 @@ void run(Strings args)
|
||||||
store = openStore();
|
store = openStore();
|
||||||
|
|
||||||
if (readStdin) {
|
if (readStdin) {
|
||||||
Expr e = parseStdin(state);
|
Expr * e = parseStdin(state);
|
||||||
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, xmlOutput, e);
|
evalOnly, xmlOutput, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Strings::iterator, i, files) {
|
foreach (Strings::iterator, i, files) {
|
||||||
Path path = absPath(*i);
|
Path path = absPath(*i);
|
||||||
Expr e = parseExprFromFile(state, path);
|
Expr * e = parseExprFromFile(path);
|
||||||
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, xmlOutput, e);
|
evalOnly, xmlOutput, e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue