* Allow primops with more that 1 arguments.

This commit is contained in:
Eelco Dolstra 2004-08-04 10:59:20 +00:00
parent e3a50f7e25
commit bbfdd64741
7 changed files with 102 additions and 104 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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);
}; };

View file

@ -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);

View file

@ -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);
} }

View file

@ -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);
}

View file

@ -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 */