forked from lix-project/lix
* Don't create thunks for simple constants (integers, strings, paths)
and allocate them only once. * Move Value and related functions into value.hh.
This commit is contained in:
parent
d4e6b9f2d6
commit
9fe24c5a0d
|
@ -8,7 +8,7 @@ libexpr_la_SOURCES = \
|
||||||
pkginclude_HEADERS = \
|
pkginclude_HEADERS = \
|
||||||
nixexpr.hh eval.hh lexer-tab.hh parser-tab.hh \
|
nixexpr.hh eval.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 symbol-table.hh
|
names.hh symbol-table.hh value.hh
|
||||||
|
|
||||||
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
||||||
../boost/format/libformat.la @BDW_GC_LIBS@
|
../boost/format/libformat.la @BDW_GC_LIBS@
|
||||||
|
|
|
@ -283,9 +283,7 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2,
|
||||||
|
|
||||||
void mkString(Value & v, const char * s)
|
void mkString(Value & v, const char * s)
|
||||||
{
|
{
|
||||||
v.type = tString;
|
mkStringNoCopy(v, GC_STRDUP(s));
|
||||||
v.string.s = GC_STRDUP(s);
|
|
||||||
v.string.context = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -303,19 +301,9 @@ void mkString(Value & v, const string & s, const PathSet & context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void mkString(Value & v, const Symbol & s)
|
|
||||||
{
|
|
||||||
v.type = tString;
|
|
||||||
v.string.s = ((string) s).c_str();
|
|
||||||
v.string.context = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void mkPath(Value & v, const char * s)
|
void mkPath(Value & v, const char * s)
|
||||||
{
|
{
|
||||||
clearValue(v);
|
mkPathNoCopy(v, GC_STRDUP(s));
|
||||||
v.type = tPath;
|
|
||||||
v.path = GC_STRDUP(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -426,6 +414,26 @@ Value * ExprVar::maybeThunk(EvalState & state, Env & env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value * ExprString::maybeThunk(EvalState & state, Env & env)
|
||||||
|
{
|
||||||
|
nrAvoided++;
|
||||||
|
return &v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value * ExprInt::maybeThunk(EvalState & state, Env & env)
|
||||||
|
{
|
||||||
|
nrAvoided++;
|
||||||
|
return &v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value * ExprPath::maybeThunk(EvalState & state, Env & env)
|
||||||
|
{
|
||||||
|
nrAvoided++;
|
||||||
|
return &v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void EvalState::evalFile(const Path & path, Value & v)
|
void EvalState::evalFile(const Path & path, Value & v)
|
||||||
{
|
{
|
||||||
FileEvalCache::iterator i = fileEvalCache.find(path);
|
FileEvalCache::iterator i = fileEvalCache.find(path);
|
||||||
|
@ -512,19 +520,19 @@ void Expr::eval(EvalState & state, Env & env, Value & v)
|
||||||
|
|
||||||
void ExprInt::eval(EvalState & state, Env & env, Value & v)
|
void ExprInt::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
mkInt(v, n);
|
v = this->v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprString::eval(EvalState & state, Env & env, Value & v)
|
void ExprString::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
mkString(v, s);
|
v = this->v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExprPath::eval(EvalState & state, Env & env, Value & v)
|
void ExprPath::eval(EvalState & state, Env & env, Value & v)
|
||||||
{
|
{
|
||||||
mkPath(v, s.c_str());
|
v = this->v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef __EVAL_H
|
#ifndef __EVAL_H
|
||||||
#define __EVAL_H
|
#define __EVAL_H
|
||||||
|
|
||||||
|
#include "value.hh"
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
|
@ -16,8 +17,6 @@ namespace nix {
|
||||||
|
|
||||||
|
|
||||||
class EvalState;
|
class EvalState;
|
||||||
struct Env;
|
|
||||||
struct Value;
|
|
||||||
struct Attr;
|
struct Attr;
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,23 +37,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
tInt = 1,
|
|
||||||
tBool,
|
|
||||||
tString,
|
|
||||||
tPath,
|
|
||||||
tNull,
|
|
||||||
tAttrs,
|
|
||||||
tList,
|
|
||||||
tThunk,
|
|
||||||
tApp,
|
|
||||||
tLambda,
|
|
||||||
tBlackhole,
|
|
||||||
tPrimOp,
|
|
||||||
tPrimOpApp,
|
|
||||||
} ValueType;
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (* PrimOpFun) (EvalState & state, Value * * args, Value & v);
|
typedef void (* PrimOpFun) (EvalState & state, Value * * args, Value & v);
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,64 +50,6 @@ struct PrimOp
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Value
|
|
||||||
{
|
|
||||||
ValueType type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int integer;
|
|
||||||
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 {
|
|
||||||
const char * s;
|
|
||||||
const char * * context; // must be in sorted order
|
|
||||||
} string;
|
|
||||||
|
|
||||||
const char * path;
|
|
||||||
Bindings * attrs;
|
|
||||||
struct {
|
|
||||||
unsigned int length;
|
|
||||||
Value * * elems;
|
|
||||||
} list;
|
|
||||||
struct {
|
|
||||||
Env * env;
|
|
||||||
Expr * expr;
|
|
||||||
} thunk;
|
|
||||||
struct {
|
|
||||||
Value * left, * right;
|
|
||||||
} app;
|
|
||||||
struct {
|
|
||||||
Env * env;
|
|
||||||
ExprLambda * fun;
|
|
||||||
} lambda;
|
|
||||||
PrimOp * primOp;
|
|
||||||
struct {
|
|
||||||
Value * left, * right;
|
|
||||||
} primOpApp;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Env
|
struct Env
|
||||||
{
|
{
|
||||||
Env * up;
|
Env * up;
|
||||||
|
@ -149,41 +73,7 @@ struct Attr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* After overwriting an app node, be sure to clear pointers in the
|
|
||||||
Value to ensure that the target isn't kept alive unnecessarily. */
|
|
||||||
static inline void clearValue(Value & v)
|
|
||||||
{
|
|
||||||
v.app.right = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void mkInt(Value & v, int n)
|
|
||||||
{
|
|
||||||
clearValue(v);
|
|
||||||
v.type = tInt;
|
|
||||||
v.integer = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void mkBool(Value & v, bool b)
|
|
||||||
{
|
|
||||||
clearValue(v);
|
|
||||||
v.type = tBool;
|
|
||||||
v.boolean = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void mkApp(Value & v, Value & left, Value & right)
|
|
||||||
{
|
|
||||||
v.type = tApp;
|
|
||||||
v.app.left = &left;
|
|
||||||
v.app.right = &right;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void mkString(Value & v, const char * s);
|
|
||||||
void mkString(Value & v, const string & s, const PathSet & context = PathSet());
|
void mkString(Value & v, const string & s, const PathSet & context = PathSet());
|
||||||
void mkPath(Value & v, const char * s);
|
|
||||||
|
|
||||||
void copyContext(const Value & v, PathSet & context);
|
void copyContext(const Value & v, PathSet & context);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef __NIXEXPR_H
|
#ifndef __NIXEXPR_H
|
||||||
#define __NIXEXPR_H
|
#define __NIXEXPR_H
|
||||||
|
|
||||||
|
#include "value.hh"
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -66,15 +67,19 @@ std::ostream & operator << (std::ostream & str, Expr & e);
|
||||||
struct ExprInt : Expr
|
struct ExprInt : Expr
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
ExprInt(int n) : n(n) { };
|
Value v;
|
||||||
|
ExprInt(int n) : n(n) { mkInt(v, n); };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
|
Value * maybeThunk(EvalState & state, Env & env);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExprString : Expr
|
struct ExprString : Expr
|
||||||
{
|
{
|
||||||
Symbol s;
|
Symbol s;
|
||||||
ExprString(const Symbol & s) : s(s) { };
|
Value v;
|
||||||
|
ExprString(const Symbol & s) : s(s) { mkString(v, s); };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
|
Value * maybeThunk(EvalState & state, Env & env);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Temporary class used during parsing of indented strings. */
|
/* Temporary class used during parsing of indented strings. */
|
||||||
|
@ -87,8 +92,10 @@ struct ExprIndStr : Expr
|
||||||
struct ExprPath : Expr
|
struct ExprPath : Expr
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
ExprPath(const string & s) : s(s) { };
|
Value v;
|
||||||
|
ExprPath(const string & s) : s(s) { mkPathNoCopy(v, this->s.c_str()); };
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
|
Value * maybeThunk(EvalState & state, Env & env);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VarRef
|
struct VarRef
|
||||||
|
|
155
src/libexpr/value.hh
Normal file
155
src/libexpr/value.hh
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
#ifndef __VALUE_H
|
||||||
|
#define __VALUE_H
|
||||||
|
|
||||||
|
#include "symbol-table.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
tInt = 1,
|
||||||
|
tBool,
|
||||||
|
tString,
|
||||||
|
tPath,
|
||||||
|
tNull,
|
||||||
|
tAttrs,
|
||||||
|
tList,
|
||||||
|
tThunk,
|
||||||
|
tApp,
|
||||||
|
tLambda,
|
||||||
|
tBlackhole,
|
||||||
|
tPrimOp,
|
||||||
|
tPrimOpApp,
|
||||||
|
} ValueType;
|
||||||
|
|
||||||
|
|
||||||
|
struct Bindings;
|
||||||
|
struct Env;
|
||||||
|
struct Expr;
|
||||||
|
struct ExprLambda;
|
||||||
|
struct PrimOp;
|
||||||
|
struct PrimOp;
|
||||||
|
struct Symbol;
|
||||||
|
|
||||||
|
|
||||||
|
struct Value
|
||||||
|
{
|
||||||
|
ValueType type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
int integer;
|
||||||
|
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 {
|
||||||
|
const char * s;
|
||||||
|
const char * * context; // must be in sorted order
|
||||||
|
} string;
|
||||||
|
|
||||||
|
const char * path;
|
||||||
|
Bindings * attrs;
|
||||||
|
struct {
|
||||||
|
unsigned int length;
|
||||||
|
Value * * elems;
|
||||||
|
} list;
|
||||||
|
struct {
|
||||||
|
Env * env;
|
||||||
|
Expr * expr;
|
||||||
|
} thunk;
|
||||||
|
struct {
|
||||||
|
Value * left, * right;
|
||||||
|
} app;
|
||||||
|
struct {
|
||||||
|
Env * env;
|
||||||
|
ExprLambda * fun;
|
||||||
|
} lambda;
|
||||||
|
PrimOp * primOp;
|
||||||
|
struct {
|
||||||
|
Value * left, * right;
|
||||||
|
} primOpApp;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* After overwriting an app node, be sure to clear pointers in the
|
||||||
|
Value to ensure that the target isn't kept alive unnecessarily. */
|
||||||
|
static inline void clearValue(Value & v)
|
||||||
|
{
|
||||||
|
v.app.right = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkInt(Value & v, int n)
|
||||||
|
{
|
||||||
|
clearValue(v);
|
||||||
|
v.type = tInt;
|
||||||
|
v.integer = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkBool(Value & v, bool b)
|
||||||
|
{
|
||||||
|
clearValue(v);
|
||||||
|
v.type = tBool;
|
||||||
|
v.boolean = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkApp(Value & v, Value & left, Value & right)
|
||||||
|
{
|
||||||
|
v.type = tApp;
|
||||||
|
v.app.left = &left;
|
||||||
|
v.app.right = &right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkStringNoCopy(Value & v, const char * s)
|
||||||
|
{
|
||||||
|
v.type = tString;
|
||||||
|
v.string.s = s;
|
||||||
|
v.string.context = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkString(Value & v, const Symbol & s)
|
||||||
|
{
|
||||||
|
mkStringNoCopy(v, ((string) s).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mkString(Value & v, const char * s);
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkPathNoCopy(Value & v, const char * s)
|
||||||
|
{
|
||||||
|
clearValue(v);
|
||||||
|
v.type = tPath;
|
||||||
|
v.path = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mkPath(Value & v, const char * s);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !__VALUE_H */
|
Loading…
Reference in a new issue