forked from lix-project/lix
* Allow primops with more that 1 arguments.
This commit is contained in:
parent
e3a50f7e25
commit
bbfdd64741
|
@ -1,7 +1,7 @@
|
||||||
noinst_LIBRARIES = libexpr.a
|
noinst_LIBRARIES = libexpr.a
|
||||||
|
|
||||||
libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \
|
libexpr_a_SOURCES = nixexpr.cc nixexpr.hh parser.cc parser.hh \
|
||||||
eval.cc eval.hh primops.cc primops.hh \
|
eval.cc eval.hh primops.cc \
|
||||||
lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h
|
lexer-tab.c lexer-tab.h parser-tab.c parser-tab.h
|
||||||
|
|
||||||
EXTRA_DIST = lexer.l parser.y
|
EXTRA_DIST = lexer.l parser.y
|
||||||
|
|
|
@ -1,20 +1,5 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
#include "primops.hh"
|
|
||||||
|
|
||||||
|
|
||||||
static void addPrimOp(ATermMap & map, const string & name, void * f)
|
|
||||||
{
|
|
||||||
map.set(name, (ATerm) ATmakeBlob(0, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void * lookupPrimOp(ATermMap & map, ATerm name)
|
|
||||||
{
|
|
||||||
ATermBlob b = (ATermBlob) map.get(name);
|
|
||||||
if (!b) return 0;
|
|
||||||
return ATgetBlobData(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
EvalState::EvalState()
|
EvalState::EvalState()
|
||||||
|
@ -25,30 +10,15 @@ EvalState::EvalState()
|
||||||
|
|
||||||
nrEvaluated = nrCached = 0;
|
nrEvaluated = nrCached = 0;
|
||||||
|
|
||||||
addPrimOp0("true", primTrue);
|
addPrimOps();
|
||||||
addPrimOp0("false", primFalse);
|
|
||||||
addPrimOp0("null", primNull);
|
|
||||||
|
|
||||||
addPrimOp1("import", primImport);
|
|
||||||
addPrimOp1("derivation", primDerivation);
|
|
||||||
addPrimOp1("baseNameOf", primBaseNameOf);
|
|
||||||
addPrimOp1("toString", primToString);
|
|
||||||
addPrimOp1("isNull", primIsNull);
|
|
||||||
|
|
||||||
primOpsAll.add(primOps0);
|
|
||||||
primOpsAll.add(primOps1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::addPrimOp0(const string & name, PrimOp0 primOp)
|
void EvalState::addPrimOp(const string & name,
|
||||||
|
unsigned int arity, PrimOp primOp)
|
||||||
{
|
{
|
||||||
addPrimOp(primOps0, name, (void *) primOp);
|
primOps.set(name, ATmake("(<int>, <term>)",
|
||||||
}
|
arity, ATmakeBlob(0, (void *) primOp)));
|
||||||
|
|
||||||
|
|
||||||
void EvalState::addPrimOp1(const string & name, PrimOp1 primOp)
|
|
||||||
{
|
|
||||||
addPrimOp(primOps1, name, (void *) primOp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,7 +170,8 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||||
cons == "Function" ||
|
cons == "Function" ||
|
||||||
cons == "Function1" ||
|
cons == "Function1" ||
|
||||||
cons == "Attrs" ||
|
cons == "Attrs" ||
|
||||||
cons == "List"))
|
cons == "List" ||
|
||||||
|
cons == "PrimOp"))
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
/* The `Closed' constructor is just a way to prevent substitutions
|
/* The `Closed' constructor is just a way to prevent substitutions
|
||||||
|
@ -208,13 +179,21 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||||
if (atMatch(m, e) >> "Closed" >> e1)
|
if (atMatch(m, e) >> "Closed" >> e1)
|
||||||
return evalExpr(state, e1);
|
return evalExpr(state, e1);
|
||||||
|
|
||||||
/* Any encountered variables must be undeclared or primops. */
|
/* Any encountered variables must be primops (since undefined
|
||||||
|
variables are detected after parsing). */
|
||||||
if (atMatch(m, e) >> "Var" >> name) {
|
if (atMatch(m, e) >> "Var" >> name) {
|
||||||
PrimOp0 primOp = (PrimOp0) lookupPrimOp(state.primOps0, name);
|
ATerm primOp = state.primOps.get(name);
|
||||||
if (primOp)
|
if (!primOp)
|
||||||
return primOp(state);
|
throw Error(format("impossible: undefined variable `%1%'") % name);
|
||||||
|
int arity;
|
||||||
|
ATerm fun;
|
||||||
|
if (!(atMatch(m, primOp) >> "" >> arity >> fun)) abort();
|
||||||
|
if (arity == 0)
|
||||||
|
return ((PrimOp) ATgetBlobData((ATermBlob) fun))
|
||||||
|
(state, ATermVector());
|
||||||
else
|
else
|
||||||
return e;
|
return ATmake("PrimOp(<int>, <term>, <term>)",
|
||||||
|
arity, fun, ATempty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function application. */
|
/* Function application. */
|
||||||
|
@ -227,9 +206,23 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||||
e1 = evalExpr(state, e1);
|
e1 = evalExpr(state, e1);
|
||||||
|
|
||||||
/* Is it a primop or a function? */
|
/* Is it a primop or a function? */
|
||||||
if (atMatch(m, e1) >> "Var" >> name) {
|
int arity;
|
||||||
PrimOp1 primOp = (PrimOp1) lookupPrimOp(state.primOps1, name);
|
ATerm fun;
|
||||||
if (primOp) return primOp(state, e2); else abort();
|
ATermList args;
|
||||||
|
if (atMatch(m, e1) >> "PrimOp" >> arity >> fun >> args) {
|
||||||
|
args = ATinsert(args, e2);
|
||||||
|
if (ATgetLength(args) == arity) {
|
||||||
|
/* Put the arguments in a vector in reverse (i.e.,
|
||||||
|
actual) order. */
|
||||||
|
ATermVector args2(arity);
|
||||||
|
for (ATermIterator i(args); i; ++i)
|
||||||
|
args2[--arity] = *i;
|
||||||
|
return ((PrimOp) ATgetBlobData((ATermBlob) fun))
|
||||||
|
(state, args2);
|
||||||
|
} else
|
||||||
|
/* Need more arguments, so propagate the primop. */
|
||||||
|
return ATmake("PrimOp(<int>, <term>, <list>)",
|
||||||
|
arity, fun, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) {
|
else if (atMatch(m, e1) >> "Function" >> formals >> e4 >> pos) {
|
||||||
|
|
|
@ -12,16 +12,16 @@ typedef map<Path, PathSet> DrvPaths;
|
||||||
typedef map<Path, Hash> DrvHashes;
|
typedef map<Path, Hash> DrvHashes;
|
||||||
|
|
||||||
struct EvalState;
|
struct EvalState;
|
||||||
typedef Expr (* PrimOp0) (EvalState &);
|
|
||||||
typedef Expr (* PrimOp1) (EvalState &, Expr arg);
|
/* Note: using a ATermVector is safe here, since when we call a primop
|
||||||
|
we also have an ATermList on the stack. */
|
||||||
|
typedef Expr (* PrimOp) (EvalState &, const ATermVector & args);
|
||||||
|
|
||||||
|
|
||||||
struct EvalState
|
struct EvalState
|
||||||
{
|
{
|
||||||
ATermMap normalForms;
|
ATermMap normalForms;
|
||||||
ATermMap primOps0; /* nullary primops */
|
ATermMap primOps;
|
||||||
ATermMap primOps1; /* unary primops */
|
|
||||||
ATermMap primOpsAll;
|
|
||||||
DrvPaths drvPaths;
|
DrvPaths drvPaths;
|
||||||
DrvHashes drvHashes; /* normalised derivation hashes */
|
DrvHashes drvHashes; /* normalised derivation hashes */
|
||||||
Expr blackHole;
|
Expr blackHole;
|
||||||
|
@ -31,8 +31,9 @@ struct EvalState
|
||||||
|
|
||||||
EvalState();
|
EvalState();
|
||||||
|
|
||||||
void addPrimOp0(const string & name, PrimOp0 primOp);
|
void addPrimOps();
|
||||||
void addPrimOp1(const string & name, PrimOp1 primOp);
|
void addPrimOp(const string & name,
|
||||||
|
unsigned int arity, PrimOp primOp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A STL vector of ATerms. Should be used with great care since it's
|
||||||
|
stored on the heap, and the elements are therefore not roots to the
|
||||||
|
ATerm garbage collector. */
|
||||||
|
typedef vector<ATerm> ATermVector;
|
||||||
|
|
||||||
|
|
||||||
/* Convert a string to an ATerm (i.e., a quoted nullary function
|
/* Convert a string to an ATerm (i.e., a quoted nullary function
|
||||||
applicaton). */
|
applicaton). */
|
||||||
ATerm string2ATerm(const string & s);
|
ATerm string2ATerm(const string & s);
|
||||||
|
|
|
@ -95,7 +95,7 @@ static Expr parse(EvalState & state,
|
||||||
if (res) throw Error(data.error);
|
if (res) throw Error(data.error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
checkVarDefs(state.primOpsAll, data.result);
|
checkVarDefs(state.primOps, data.result);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
throw Error(format("%1%, in `%2%'") % e.msg() % path);
|
throw Error(format("%1%, in `%2%'") % e.msg() % path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
#include "primops.hh"
|
|
||||||
#include "normalise.hh"
|
#include "normalise.hh"
|
||||||
|
#include "eval.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
|
|
||||||
|
|
||||||
Expr primImport(EvalState & state, Expr arg)
|
/* Load and evaluate an expression from path specified by the
|
||||||
|
argument. */
|
||||||
|
static Expr primImport(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
ATMatcher m;
|
ATMatcher m;
|
||||||
string path;
|
string path;
|
||||||
if (!(atMatch(m, arg) >> "Path" >> path))
|
if (!(atMatch(m, args[0]) >> "Path" >> path))
|
||||||
throw Error("path expected");
|
throw Error("path expected");
|
||||||
return evalFile(state, path);
|
return evalFile(state, path);
|
||||||
}
|
}
|
||||||
|
@ -158,11 +160,19 @@ static string concatStrings(const Strings & ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primDerivation(EvalState & state, Expr args)
|
/* Construct (as a unobservable side effect) a Nix derivation
|
||||||
|
expression that performs the derivation described by the argument
|
||||||
|
set. Returns the original set extended with the following
|
||||||
|
attributes: `outPath' containing the primary output path of the
|
||||||
|
derivation; `drvPath' containing the path of the Nix expression;
|
||||||
|
and `type' set to `derivation' to indicate that this is a
|
||||||
|
derivation. */
|
||||||
|
static Expr primDerivation(EvalState & state, const ATermVector & _args)
|
||||||
{
|
{
|
||||||
startNest(nest, lvlVomit, "evaluating derivation");
|
startNest(nest, lvlVomit, "evaluating derivation");
|
||||||
|
|
||||||
ATermMap attrs;
|
ATermMap attrs;
|
||||||
|
Expr args = _args[0];
|
||||||
args = evalExpr(state, args);
|
args = evalExpr(state, args);
|
||||||
queryAllAttrs(args, attrs, true);
|
queryAllAttrs(args, attrs, true);
|
||||||
|
|
||||||
|
@ -251,16 +261,19 @@ Expr primDerivation(EvalState & state, Expr args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primBaseNameOf(EvalState & state, Expr arg)
|
/* Return the base name of the given string, i.e., everything
|
||||||
|
following the last slash. */
|
||||||
|
static Expr primBaseNameOf(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
string s = evalString(state, arg);
|
string s = evalString(state, args[0]);
|
||||||
return ATmake("Str(<str>)", baseNameOf(s).c_str());
|
return ATmake("Str(<str>)", baseNameOf(s).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primToString(EvalState & state, Expr arg)
|
/* Convert the argument (which can be a path or a uri) to a string. */
|
||||||
|
static Expr primToString(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
arg = evalExpr(state, arg);
|
Expr arg = evalExpr(state, args[0]);
|
||||||
ATMatcher m;
|
ATMatcher m;
|
||||||
string s;
|
string s;
|
||||||
if (atMatch(m, arg) >> "Str" >> s ||
|
if (atMatch(m, arg) >> "Str" >> s ||
|
||||||
|
@ -271,27 +284,50 @@ Expr primToString(EvalState & state, Expr arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primTrue(EvalState & state)
|
/* Boolean constructors. */
|
||||||
|
static Expr primTrue(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
return ATmake("Bool(True)");
|
return ATmake("Bool(True)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primFalse(EvalState & state)
|
static Expr primFalse(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
return ATmake("Bool(False)");
|
return ATmake("Bool(False)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primNull(EvalState & state)
|
/* Return the null value. */
|
||||||
|
Expr primNull(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
return ATmake("Null");
|
return ATmake("Null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr primIsNull(EvalState & state, Expr arg)
|
/* Determine whether the argument is the null value. */
|
||||||
|
Expr primIsNull(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
arg = evalExpr(state, arg);
|
Expr arg = evalExpr(state, args[0]);
|
||||||
ATMatcher m;
|
ATMatcher m;
|
||||||
return makeBool(atMatch(m, arg) >> "Null");
|
return makeBool(atMatch(m, arg) >> "Null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Apply a function to every element of a list. */
|
||||||
|
Expr primMap(EvalState & state, Expr fun, Expr list)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EvalState::addPrimOps()
|
||||||
|
{
|
||||||
|
addPrimOp("true", 0, primTrue);
|
||||||
|
addPrimOp("false", 0, primFalse);
|
||||||
|
addPrimOp("null", 0, primNull);
|
||||||
|
|
||||||
|
addPrimOp("import", 1, primImport);
|
||||||
|
addPrimOp("derivation", 1, primDerivation);
|
||||||
|
addPrimOp("baseNameOf", 1, primBaseNameOf);
|
||||||
|
addPrimOp("toString", 1, primToString);
|
||||||
|
addPrimOp("isNull", 1, primIsNull);
|
||||||
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#ifndef __PRIMOPS_H
|
|
||||||
#define __PRIMOPS_H
|
|
||||||
|
|
||||||
#include "eval.hh"
|
|
||||||
|
|
||||||
|
|
||||||
/* Load and evaluate an expression from path specified by the
|
|
||||||
argument. */
|
|
||||||
Expr primImport(EvalState & state, Expr arg);
|
|
||||||
|
|
||||||
/* Construct (as a unobservable side effect) a Nix derivation
|
|
||||||
expression that performs the derivation described by the argument
|
|
||||||
set. Returns the original set extended with the following
|
|
||||||
attributes: `outPath' containing the primary output path of the
|
|
||||||
derivation; `drvPath' containing the path of the Nix expression;
|
|
||||||
and `type' set to `derivation' to indicate that this is a
|
|
||||||
derivation. */
|
|
||||||
Expr primDerivation(EvalState & state, Expr args);
|
|
||||||
|
|
||||||
/* Return the base name of the given string, i.e., everything
|
|
||||||
following the last slash. */
|
|
||||||
Expr primBaseNameOf(EvalState & state, Expr arg);
|
|
||||||
|
|
||||||
/* Convert the argument (which can be a path or a uri) to a string. */
|
|
||||||
Expr primToString(EvalState & state, Expr arg);
|
|
||||||
|
|
||||||
/* Boolean constructors. */
|
|
||||||
Expr primTrue(EvalState & state);
|
|
||||||
Expr primFalse(EvalState & state);
|
|
||||||
|
|
||||||
/* Return the null value. */
|
|
||||||
Expr primNull(EvalState & state);
|
|
||||||
|
|
||||||
/* Determine whether the argument is the null value. */
|
|
||||||
Expr primIsNull(EvalState & state, Expr arg);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__PRIMOPS_H */
|
|
Loading…
Reference in a new issue