aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2021-04-11 12:14:05 +0200
committerMaximilian Bosch <maximilian@mbosch.me>2021-04-13 23:12:38 +0200
commitf60473a07752fa409cec2c3ed818af99327a571c (patch)
treee04052e9c97effa3f23811f3c0e12278ebe89649 /src
parent7c76964daa0d1ca07fd609f5eb28b51afd1246b7 (diff)
libexpr/primops: Move attr name extraction into its own function
This now takes care of providing positioning for both the faulting value and the faulting function call in case of an error.
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/primops.cc86
1 files changed, 54 insertions, 32 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index c7bbfc050..7f3c298ba 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -547,18 +547,42 @@ typedef list<Value *> ValueList;
#endif
+static Bindings::iterator extractAttrNameFromPrimopCall(
+ EvalState &state,
+ string funcName,
+ string attrName,
+ Bindings *attrSet,
+ const Pos &pos
+) {
+ Bindings::iterator value = attrSet->find(state.symbols.create(attrName));
+ if (value == attrSet->end()) {
+ auto e = TypeError({
+ .msg = hintfmt("attribute '%s' missing for call to '%s'", attrName, funcName),
+ .errPos = *attrSet->pos,
+ });
+
+ // Adding another trace for the function name to make it clear
+ // which call received wrong arguments.
+ e.addTrace(pos, hintfmt("while invoking '%s'", funcName));
+ throw e;
+ }
+
+ return value;
+}
+
static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
/* Get the start set. */
- Bindings::iterator startSet =
- args[0]->attrs->find(state.symbols.create("startSet"));
- if (startSet == args[0]->attrs->end())
- throw EvalError({
- .msg = hintfmt("attribute 'startSet' required"),
- .errPos = pos
- });
+ Bindings::iterator startSet = extractAttrNameFromPrimopCall(
+ state,
+ "genericClosure",
+ "startSet",
+ args[0]->attrs,
+ pos
+ );
+
state.forceList(*startSet->value, pos);
ValueList workSet;
@@ -566,13 +590,14 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
workSet.push_back(startSet->value->listElems()[n]);
/* Get the operator. */
- Bindings::iterator op =
- args[0]->attrs->find(state.symbols.create("operator"));
- if (op == args[0]->attrs->end())
- throw EvalError({
- .msg = hintfmt("attribute 'operator' required"),
- .errPos = pos
- });
+ Bindings::iterator op = extractAttrNameFromPrimopCall(
+ state,
+ "genericClosure",
+ "operator",
+ args[0]->attrs,
+ pos
+ );
+
state.forceValue(*op->value, pos);
/* Construct the closure by applying the operator to element of
@@ -2148,28 +2173,25 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
Value & v2(*args[0]->listElems()[i]);
state.forceAttrs(v2, pos);
- Bindings::iterator j = v2.attrs->find(state.sName);
- if (j == v2.attrs->end()) {
- auto e = TypeError({
- .msg = hintfmt("'name' attribute missing for 'listToAttrs'"),
- .errPos = *v2.attrs->pos
- });
- e.addTrace(pos, hintfmt("while invoking '%s'", "listToAttrs"));
- throw e;
- }
+ Bindings::iterator j = extractAttrNameFromPrimopCall(
+ state,
+ "listToAttrs",
+ state.sName,
+ v2.attrs,
+ pos
+ );
+
string name = state.forceStringNoCtx(*j->value, *j->pos);
Symbol sym = state.symbols.create(name);
if (seen.insert(sym).second) {
- Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
- if (j2 == v2.attrs->end()) {
- auto e = TypeError({
- .msg = hintfmt("'value' attribute missing for 'listToAttrs'"),
- .errPos = *v2.attrs->pos
- });
- e.addTrace(pos, hintfmt("while invoking '%s'", "listToAttrs"));
- throw e;
- }
+ Bindings::iterator j2 = extractAttrNameFromPrimopCall(
+ state,
+ "listToAttrs",
+ state.sValue,
+ v2.attrs,
+ pos
+ );
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
}
}