aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval-test.cc8
-rw-r--r--src/libexpr/eval.cc128
-rw-r--r--src/libexpr/lexer.l4
-rw-r--r--src/libexpr/nixexpr.cc39
-rw-r--r--src/libexpr/nixexpr.hh38
-rw-r--r--src/libexpr/parser.y80
6 files changed, 160 insertions, 137 deletions
diff --git a/src/libexpr/eval-test.cc b/src/libexpr/eval-test.cc
index 32f4940df..dd8ead04a 100644
--- a/src/libexpr/eval-test.cc
+++ b/src/libexpr/eval-test.cc
@@ -45,6 +45,7 @@ void run(Strings args)
doTest(state, "({x, y, ...}@args: args.z) { x = 1; y = 2; z = 3; }");
//doTest(state, "({x ? y, y ? x}: y) { }");
doTest(state, "let x = 1; in x");
+ doTest(state, "let { x = 1; body = x; }");
doTest(state, "with { x = 1; }; x");
doTest(state, "let x = 2; in with { x = 1; }; x"); // => 2
doTest(state, "with { x = 1; }; with { x = 2; }; x"); // => 1
@@ -65,18 +66,19 @@ void run(Strings args)
doTest(state, "__head [ 1 2 3 ]");
doTest(state, "__add 1 2");
doTest(state, "null");
- //doTest(state, "\"foo\"");
- //doTest(state, "let s = \"bar\"; in \"foo${s}\"");
+ doTest(state, "\"foo\"");
+ doTest(state, "let s = \"bar\"; in \"foo${s}\"");
doTest(state, "if true then 1 else 2");
doTest(state, "if false then 1 else 2");
doTest(state, "if false || true then 1 else 2");
+ doTest(state, "!(true || false)");
doTest(state, "let x = x; in if true || x then 1 else 2");
doTest(state, "http://nixos.org/");
doTest(state, "/etc/passwd");
//doTest(state, "import ./foo.nix");
doTest(state, "map (x: __add 1 x) [ 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 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");
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 8ead986b8..21c22333b 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -160,9 +160,9 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
throw TypeError(format(s) % s2);
}
-LocalNoInlineNoReturn(void throwAssertionError(const char * s, const string & s2))
+LocalNoInlineNoReturn(void throwAssertionError(const char * s, const Pos & pos))
{
- throw AssertionError(format(s) % s2);
+ throw AssertionError(format(s) % pos);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s))
@@ -341,73 +341,13 @@ void EvalState::eval(Env & env, Expr * e, Value & v)
char x;
if (&x < deepestStack) deepestStack = &x;
- //debug(format("eval: %1%") % e);
+ //debug(format("eval: %1%") % *e);
checkInterrupt();
nrEvaluated++;
e->eval(*this, env, v);
-
-#if 0
- Sym name;
- int n;
- ATerm s; ATermList context, es;
- ATermList rbnds, nrbnds;
- Expr e1, e2, e3, fun, arg, attrs;
- Pattern pat; Expr body; Pos pos;
-
- else if (matchConcatStrings(e, es)) {
- PathSet context;
- std::ostringstream s;
-
- bool first = true, isPath = false;
- Value vStr;
-
- for (ATermIterator i(es); i; ++i) {
- eval(env, *i, vStr);
-
- /* If the first element is a path, then the result will
- also be a path, we don't copy anything (yet - that's
- done later, since paths are copied when they are used
- in a derivation), and none of the strings are allowed
- to have contexts. */
- if (first) {
- isPath = vStr.type == tPath;
- first = false;
- }
-
- s << coerceToString(vStr, context, false, !isPath);
- }
-
- if (isPath && !context.empty())
- throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
-
- if (isPath)
- mkPath(v, s.str().c_str());
- else
- mkString(v, s.str(), context);
- }
-
- /* Assertions. */
- else if (matchAssert(e, e1, e2, pos)) {
- if (!evalBool(env, e1))
- throwAssertionError("assertion failed at %1%", showPos(pos));
- eval(env, e2, v);
- }
-
- /* Negation. */
- else if (matchOpNot(e, e1))
- mkBool(v, !evalBool(env, e1));
-
- /* Attribute existence test (?). */
- else if (matchOpHasAttr(e, e1, name)) {
- Value vAttrs;
- eval(env, e1, vAttrs);
- forceAttrs(vAttrs);
- mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
- }
-#endif
}
@@ -516,6 +456,15 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
}
+void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
+{
+ Value vAttrs;
+ state.eval(env, e, vAttrs);
+ state.forceAttrs(vAttrs);
+ mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
+}
+
+
void ExprLambda::eval(EvalState & state, Env & env, Value & v)
{
v.type = tLambda;
@@ -663,6 +612,20 @@ void ExprIf::eval(EvalState & state, Env & env, Value & v)
}
+void ExprAssert::eval(EvalState & state, Env & env, Value & v)
+{
+ if (!state.evalBool(env, cond))
+ throwAssertionError("assertion failed at %1%", pos);
+ state.eval(env, body, v);
+}
+
+
+void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
+{
+ mkBool(v, !state.evalBool(env, e));
+}
+
+
void ExprOpEq::eval(EvalState & state, Env & env, Value & v)
{
Value v1; state.eval(env, e1, v1);
@@ -713,12 +676,6 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
}
-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);
@@ -735,6 +692,39 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
}
+void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
+{
+ PathSet context;
+ std::ostringstream s;
+
+ bool first = true, isPath = false;
+ Value vStr;
+
+ foreach (vector<Expr *>::iterator, i, *es) {
+ state.eval(env, *i, vStr);
+
+ /* If the first element is a path, then the result will also
+ be a path, we don't copy anything (yet - that's done later,
+ since paths are copied when they are used in a derivation),
+ and none of the strings are allowed to have contexts. */
+ if (first) {
+ isPath = vStr.type == tPath;
+ first = false;
+ }
+
+ s << state.coerceToString(vStr, context, false, !isPath);
+ }
+
+ if (isPath && !context.empty())
+ throwEvalError("a string that refers to a store path cannot be appended to a path, in `%1%'", s.str());
+
+ if (isPath)
+ mkPath(v, s.str().c_str());
+ else
+ mkString(v, s.str(), context);
+}
+
+
void EvalState::forceValue(Value & v)
{
if (v.type == tThunk) {
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index f750cfd02..e905700fd 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -45,7 +45,6 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
static Expr * unescapeStr(const char * s)
{
-#if 0
string t;
char c;
while ((c = *s++)) {
@@ -64,8 +63,7 @@ static Expr * unescapeStr(const char * s)
}
else t += c;
}
- return makeStr(toATerm(t), ATempty);
-#endif
+ return new ExprString(t);
}
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 05dfbd322..b044aaa94 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -40,6 +40,11 @@ void ExprSelect::show(std::ostream & str)
str << "(" << *e << ")." << name;
}
+void ExprOpHasAttr::show(std::ostream & str)
+{
+ str << "(" << *e << ") ? " << name;
+}
+
void ExprAttrs::show(std::ostream & str)
{
if (recursive) str << "rec ";
@@ -87,19 +92,37 @@ void ExprIf::show(std::ostream & str)
str << "if " << *cond << " then " << *then << " else " << *else_;
}
+void ExprAssert::show(std::ostream & str)
+{
+ str << "assert " << *cond << "; " << *body;
+}
-#if 0
-string showPos(ATerm pos)
+void ExprOpNot::show(std::ostream & str)
+{
+ str << "! " << *e;
+}
+
+void ExprConcatStrings::show(std::ostream & str)
+{
+ bool first = true;
+ foreach (vector<Expr *>::iterator, i, *es) {
+ if (first) first = false; else str << " + ";
+ str << **i;
+ }
+}
+
+
+std::ostream & operator << (std::ostream & str, const Pos & pos)
{
- ATerm path;
- int line, column;
- if (matchNoPos(pos)) return "undefined position";
- if (!matchPos(pos, path, line, column))
- throw badTerm("position expected", pos);
- return (format("`%1%:%2%:%3%'") % aterm2String(path) % line % column).str();
+ if (!pos.line)
+ str << "undefined position";
+ else
+ str << (format("`%1%:%2%:%3%'") % pos.file % pos.line % pos.column).str();
+ return str;
}
+#if 0
ATerm bottomupRewrite(TermFun & f, ATerm e)
{
checkInterrupt();
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index ebdfd0a15..d6e088c41 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -24,6 +24,9 @@ struct Pos
};
+std::ostream & operator << (std::ostream & str, const Pos & pos);
+
+
/* Abstract syntax of Nix expressions. */
struct Env;
@@ -81,6 +84,14 @@ struct ExprSelect : Expr
COMMON_METHODS
};
+struct ExprOpHasAttr : Expr
+{
+ Expr * e;
+ string name;
+ ExprOpHasAttr(Expr * e, const string & name) : e(e), name(name) { };
+ COMMON_METHODS
+};
+
struct ExprAttrs : Expr
{
bool recursive;
@@ -139,6 +150,21 @@ struct ExprIf : Expr
COMMON_METHODS
};
+struct ExprAssert : Expr
+{
+ Pos pos;
+ Expr * cond, * body;
+ ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
+ COMMON_METHODS
+};
+
+struct ExprOpNot : Expr
+{
+ Expr * e;
+ ExprOpNot(Expr * e) : e(e) { };
+ COMMON_METHODS
+};
+
#define MakeBinOp(name, s) \
struct Expr##name : Expr \
{ \
@@ -158,15 +184,17 @@ MakeBinOp(OpAnd, "&&")
MakeBinOp(OpOr, "||")
MakeBinOp(OpImpl, "->")
MakeBinOp(OpUpdate, "//")
-MakeBinOp(OpConcatStrings, "+")
MakeBinOp(OpConcatLists, "++")
-
-#if 0
-/* Show a position. */
-string showPos(ATerm pos);
+struct ExprConcatStrings : Expr
+{
+ vector<Expr *> * es;
+ ExprConcatStrings(vector<Expr *> * es) : es(es) { };
+ COMMON_METHODS
+};
+#if 0
/* Generic bottomup traversal over ATerms. The traversal first
recursively descends into subterms, and then applies the given term
function to the resulting term. */
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 96fbe2cb4..83f454845 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -20,7 +20,6 @@
#include <stdlib.h>
#include <string.h>
-#include "aterm.hh"
#include "util.hh"
#include "nixexpr.hh"
@@ -116,13 +115,13 @@ static void fixAttrs(ExprAttrs & attrs)
for (ATermIterator j(attrPath); j; ) {
name = *j; ++j;
if (t->leaf) throw ParseError(format("attribute set containing `%1%' at %2% already defined at %3%")
- % showAttrPath(attrPath) % showPos(pos) % showPos (t->pos));
+ % showAttrPath(attrPath) % showPos(pos) % showPos(t->pos));
t = &(t->children[name]);
}
if (t->leaf)
throw ParseError(format("duplicate definition of attribute `%1%' at %2% and %3%")
- % showAttrPath(attrPath) % showPos(pos) % showPos (t->pos));
+ % showAttrPath(attrPath) % showPos(pos) % showPos(t->pos));
if (!t->children.empty())
throw ParseError(format("duplicate definition of attribute `%1%' at %2%")
% showAttrPath(attrPath) % showPos(pos));
@@ -289,30 +288,11 @@ static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error)
{
- data->error = (format("%1%, at `%2%':%3%:%4%")
- % error % data->path % loc->first_line % loc->first_column).str();
+ data->error = (format("%1%, at %2%")
+ % error % makeCurPos(loc, data)).str();
}
-/* Make sure that the parse stack is scanned by the ATerm garbage
- collector. */
-static void * mallocAndProtect(size_t size)
-{
- void * p = malloc(size);
- if (p) ATprotectMemory(p, size);
- return p;
-}
-
-static void freeAndUnprotect(void * p)
-{
- ATunprotectMemory(p);
- free(p);
-}
-
-#define YYMALLOC mallocAndProtect
-#define YYFREE freeAndUnprotect
-
-
#endif
@@ -329,18 +309,20 @@ static void freeAndUnprotect(void * p)
char * path;
char * uri;
std::list<std::string> * ids;
+ std::vector<nix::Expr *> * string_parts;
}
%type <e> start expr expr_function expr_if expr_op
%type <e> expr_app expr_select expr_simple
%type <list> expr_list
%type <attrs> binds
-%type <ts> attrpath string_parts ind_string_parts
+%type <ts> attrpath ind_string_parts
%type <formals> formals
%type <formal> formal
%type <ids> ids
+%type <string_parts> string_parts
%token <id> ID ATTRPATH
-%token <t> STR IND_STR
+%token <e> STR IND_STR
%token <n> INT
%token <path> PATH
%token <uri> URI
@@ -375,9 +357,8 @@ 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); }
- */
+ | ASSERT expr ';' expr_function
+ { $$ = new ExprAssert(CUR_POS, $2, $4); }
| WITH expr ';' expr_function
{ $$ = new ExprWith(CUR_POS, $2, $4); }
| LET binds IN expr_function
@@ -391,18 +372,20 @@ expr_if
;
expr_op
- : /* '!' expr_op %prec NEG { $$ = makeOpNot($2); }
- | */
- expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
+ : '!' expr_op %prec NEG { $$ = new ExprOpNot($2); }
+ | expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
| expr_op AND expr_op { $$ = new ExprOpAnd($1, $3); }
| expr_op OR expr_op { $$ = new ExprOpOr($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 '+' expr_op { $$ = new ExprOpConcatStrings($1, $3); }
+ | expr_op '?' ID { $$ = new ExprOpHasAttr($1, $3); }
+ | expr_op '+' expr_op
+ { vector<Expr *> * l = new vector<Expr *>;
+ l->push_back($1);
+ l->push_back($3);
+ $$ = new ExprConcatStrings(l);
+ }
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists($1, $3); }
| expr_app
;
@@ -421,26 +404,25 @@ expr_select
expr_simple
: ID { $$ = new ExprVar($1); }
- | INT { $$ = new ExprInt($1); } /*
+ | INT { $$ = new ExprInt($1); }
| '"' string_parts '"' {
- /* For efficiency, and to simplify parse trees a bit. * /
- if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
- else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
- else $$ = makeConcatStrings(ATreverse($2));
+ /* For efficiency, and to simplify parse trees a bit. */
+ if ($2->empty()) $$ = new ExprString("");
+ else if ($2->size() == 1) $$ = $2->front();
+ else $$ = new ExprConcatStrings($2);
}
+ /*
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = stripIndentation(ATreverse($2));
}
- */
+ */
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
| URI { $$ = new ExprString($1); }
| '(' expr ')' { $$ = $2; }
-/*
/* Let expressions `let {..., body = ...}' are just desugared
- into `(rec {..., body = ...}).body'. * /
+ into `(rec {..., body = ...}).body'. */
| LET '{' binds '}'
- { $$ = makeSelect(fixAttrs(true, $3), toATerm("body")); }
- */
+ { fixAttrs(*$3); $3->recursive = true; $$ = new ExprSelect($3, "body"); }
| REC '{' binds '}'
{ fixAttrs(*$3); $3->recursive = true; $$ = $3; }
| '{' binds '}'
@@ -449,9 +431,9 @@ expr_simple
;
string_parts
- : string_parts STR { $$ = ATinsert($1, $2); }
- | string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = ATinsert($1, $3); }
- | { $$ = ATempty; }
+ : string_parts STR { $$ = $1; $1->push_back($2); }
+ | string_parts DOLLAR_CURLY expr '}' { backToString(scanner); $$ = $1; $1->push_back($3); }
+ | { $$ = new vector<Expr *>; }
;
ind_string_parts