* Added a list concatenation operator:
[1 2 3] ++ [4 5 6] => [1 2 3 4 5 6]
This commit is contained in:
parent
e6899794ae
commit
991a130b1e
8 changed files with 29 additions and 12 deletions
|
@ -140,6 +140,15 @@ bool evalBool(EvalState & state, Expr e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ATermList evalList(EvalState & state, Expr e)
|
||||||
|
{
|
||||||
|
e = evalExpr(state, e);
|
||||||
|
ATermList list;
|
||||||
|
if (!matchList(e, list)) throw Error("list expected");
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Expr evalExpr2(EvalState & state, Expr e)
|
Expr evalExpr2(EvalState & state, Expr e)
|
||||||
{
|
{
|
||||||
Expr e1, e2, e3, e4;
|
Expr e1, e2, e3, e4;
|
||||||
|
@ -336,6 +345,13 @@ Expr evalExpr2(EvalState & state, Expr e)
|
||||||
else throw Error("wrong argument types in `+' operator");
|
else throw Error("wrong argument types in `+' operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* List concatenation. */
|
||||||
|
if (matchOpConcat(e, e1, e2)) {
|
||||||
|
ATermList l1 = evalList(state, e1);
|
||||||
|
ATermList l2 = evalList(state, e2);
|
||||||
|
return makeList(ATconcat(l1, l2));
|
||||||
|
}
|
||||||
|
|
||||||
/* Barf. */
|
/* Barf. */
|
||||||
throw badTerm("invalid expression", e);
|
throw badTerm("invalid expression", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ Expr evalFile(EvalState & state, const Path & path);
|
||||||
/* Specific results. */
|
/* Specific results. */
|
||||||
string evalString(EvalState & state, Expr e);
|
string evalString(EvalState & state, Expr e);
|
||||||
Path evalPath(EvalState & state, Expr e);
|
Path evalPath(EvalState & state, Expr e);
|
||||||
|
ATermList evalList(EvalState & state, Expr e);
|
||||||
|
|
||||||
/* Print statistics. */
|
/* Print statistics. */
|
||||||
void printEvalStats(EvalState & state);
|
void printEvalStats(EvalState & state);
|
||||||
|
|
|
@ -59,6 +59,7 @@ inherit { return INHERIT; }
|
||||||
\|\| { return OR; }
|
\|\| { return OR; }
|
||||||
\-\> { return IMPL; }
|
\-\> { return IMPL; }
|
||||||
\/\/ { return UPDATE; }
|
\/\/ { return UPDATE; }
|
||||||
|
\+\+ { return CONCAT; }
|
||||||
|
|
||||||
{ID} { yylval->t = ATmake("<str>", yytext); return ID; /* !!! alloc */ }
|
{ID} { yylval->t = ATmake("<str>", yytext); return ID; /* !!! alloc */ }
|
||||||
{INT} { int n = atoi(yytext); /* !!! overflow */
|
{INT} { int n = atoi(yytext); /* !!! overflow */
|
||||||
|
|
|
@ -18,6 +18,7 @@ OpUpdate | Expr Expr | Expr |
|
||||||
SubPath | Expr Expr | Expr |
|
SubPath | Expr Expr | Expr |
|
||||||
OpHasAttr | Expr string | Expr |
|
OpHasAttr | Expr string | Expr |
|
||||||
OpPlus | Expr Expr | Expr |
|
OpPlus | Expr Expr | Expr |
|
||||||
|
OpConcat | Expr Expr | Expr |
|
||||||
Call | Expr Expr | Expr |
|
Call | Expr Expr | Expr |
|
||||||
Select | Expr string | Expr |
|
Select | Expr string | Expr |
|
||||||
Var | string | Expr |
|
Var | string | Expr |
|
||||||
|
|
|
@ -64,6 +64,7 @@ static Pos makeCurPos(YYLTYPE * loc, void * data)
|
||||||
%right UPDATE
|
%right UPDATE
|
||||||
%left NEG
|
%left NEG
|
||||||
%left '+'
|
%left '+'
|
||||||
|
%left CONCAT
|
||||||
%nonassoc '?'
|
%nonassoc '?'
|
||||||
%nonassoc '~'
|
%nonassoc '~'
|
||||||
|
|
||||||
|
@ -102,6 +103,7 @@ expr_op
|
||||||
| expr_op '~' expr_op { $$ = makeSubPath($1, $3); }
|
| expr_op '~' expr_op { $$ = makeSubPath($1, $3); }
|
||||||
| expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
|
| expr_op '?' ID { $$ = makeOpHasAttr($1, $3); }
|
||||||
| expr_op '+' expr_op { $$ = makeOpPlus($1, $3); }
|
| expr_op '+' expr_op { $$ = makeOpPlus($1, $3); }
|
||||||
|
| expr_op CONCAT expr_op { $$ = makeOpConcat($1, $3); }
|
||||||
| expr_app
|
| expr_app
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -414,17 +414,13 @@ static Expr primIsNull(EvalState & state, const ATermVector & args)
|
||||||
static Expr primMap(EvalState & state, const ATermVector & args)
|
static Expr primMap(EvalState & state, const ATermVector & args)
|
||||||
{
|
{
|
||||||
Expr fun = evalExpr(state, args[0]);
|
Expr fun = evalExpr(state, args[0]);
|
||||||
Expr list = evalExpr(state, args[1]);
|
ATermList list = evalList(state, args[1]);
|
||||||
|
|
||||||
ATermList list2;
|
ATermList res = ATempty;
|
||||||
if (!matchList(list, list2))
|
for (ATermIterator i(list); i; ++i)
|
||||||
throw Error("`map' expects a list as its second argument");
|
res = ATinsert(res, makeCall(fun, *i));
|
||||||
|
|
||||||
ATermList list3 = ATempty;
|
return makeList(ATreverse(res));
|
||||||
for (ATermIterator i(list2); i; ++i)
|
|
||||||
list3 = ATinsert(list3, makeCall(fun, *i));
|
|
||||||
|
|
||||||
return makeList(ATreverse(list3));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,9 +445,7 @@ static Expr primRemoveAttrs(EvalState & state, const ATermVector & args)
|
||||||
ATermMap attrs;
|
ATermMap attrs;
|
||||||
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
|
queryAllAttrs(evalExpr(state, args[0]), attrs, true);
|
||||||
|
|
||||||
ATermList list;
|
ATermList list = evalList(state, args[1]);
|
||||||
if (!matchList(evalExpr(state, args[1]), list))
|
|
||||||
throw Error("`removeAttrs' expects a list as its second argument");
|
|
||||||
|
|
||||||
for (ATermIterator i(list); i; ++i)
|
for (ATermIterator i(list); i; ++i)
|
||||||
/* It's not an error for *i not to exist. */
|
/* It's not an error for *i not to exist. */
|
||||||
|
|
1
tests/lang/eval-okay-concat.exp
Normal file
1
tests/lang/eval-okay-concat.exp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
List([Int(1),Int(2),Int(3),Int(4),Int(5),Int(6),Int(7),Int(8),Int(9)])
|
1
tests/lang/eval-okay-concat.nix
Normal file
1
tests/lang/eval-okay-concat.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[1 2 3] ++ [4 5 6] ++ [7 8 9]
|
Loading…
Reference in a new issue