diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 78b9c5572..39e5f1665 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -35,6 +35,7 @@ EvalState::EvalState() addPrimOp1("baseNameOf", primBaseNameOf); addPrimOp1("toString", primToString); addPrimOp1("isNull", primIsNull); + addPrimOp1("map", primMap); primOpsAll.add(primOps0); primOpsAll.add(primOps1); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 91636ea7b..be0c9faba 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -329,3 +329,35 @@ Expr primCurTime(EvalState & state) { return ATmake("Int()", time(0)); } + + +Expr primMap(EvalState & state, Expr arg) +{ + arg = evalExpr(state, arg); + + ATMatcher m; + ATermList es; + if (!(atMatch(m, arg) >> "Attrs" >> es)) + throw Error("function `map' expects an attribute set"); + + Expr function = queryAttr(arg, "function"); + if (!function) + throw Error("function `map' expects an attribute `function'"); + + Expr list = queryAttr(arg, "list"); + if (!list) + throw Error("function `map' expects an attribute `list'"); + + list = evalExpr(state, list); + + ATermList es2; + if (!(atMatch(m, list) >> "List" >> es2)) + throw Error("attribute `list' in call to `map' must be a list"); + + ATermList res = ATempty; + for (ATermIterator i(es2); i; ++i) + res = ATinsert(res, + ATmake("Call(, )", function, *i)); + + return ATmake("List()", ATreverse(res)); +} diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh index 5af9cafc0..fba000197 100644 --- a/src/libexpr/primops.hh +++ b/src/libexpr/primops.hh @@ -39,5 +39,8 @@ Expr primIsNull(EvalState & state, Expr arg); value for a particular run of the program. */ Expr primCurTime(EvalState & state); +/* Apply a function to each element of a list. */ +Expr primMap(EvalState & state, Expr arg); + #endif /* !__PRIMOPS_H */