forked from lix-project/lix
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.
This commit is contained in:
parent
7c76964daa
commit
f60473a077
1 changed files with 54 additions and 32 deletions
|
@ -547,18 +547,42 @@ typedef list<Value *> ValueList;
|
||||||
#endif
|
#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)
|
static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.forceAttrs(*args[0], pos);
|
state.forceAttrs(*args[0], pos);
|
||||||
|
|
||||||
/* Get the start set. */
|
/* Get the start set. */
|
||||||
Bindings::iterator startSet =
|
Bindings::iterator startSet = extractAttrNameFromPrimopCall(
|
||||||
args[0]->attrs->find(state.symbols.create("startSet"));
|
state,
|
||||||
if (startSet == args[0]->attrs->end())
|
"genericClosure",
|
||||||
throw EvalError({
|
"startSet",
|
||||||
.msg = hintfmt("attribute 'startSet' required"),
|
args[0]->attrs,
|
||||||
.errPos = pos
|
pos
|
||||||
});
|
);
|
||||||
|
|
||||||
state.forceList(*startSet->value, pos);
|
state.forceList(*startSet->value, pos);
|
||||||
|
|
||||||
ValueList workSet;
|
ValueList workSet;
|
||||||
|
@ -566,13 +590,14 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
|
||||||
workSet.push_back(startSet->value->listElems()[n]);
|
workSet.push_back(startSet->value->listElems()[n]);
|
||||||
|
|
||||||
/* Get the operator. */
|
/* Get the operator. */
|
||||||
Bindings::iterator op =
|
Bindings::iterator op = extractAttrNameFromPrimopCall(
|
||||||
args[0]->attrs->find(state.symbols.create("operator"));
|
state,
|
||||||
if (op == args[0]->attrs->end())
|
"genericClosure",
|
||||||
throw EvalError({
|
"operator",
|
||||||
.msg = hintfmt("attribute 'operator' required"),
|
args[0]->attrs,
|
||||||
.errPos = pos
|
pos
|
||||||
});
|
);
|
||||||
|
|
||||||
state.forceValue(*op->value, pos);
|
state.forceValue(*op->value, pos);
|
||||||
|
|
||||||
/* Construct the closure by applying the operator to element of
|
/* 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]);
|
Value & v2(*args[0]->listElems()[i]);
|
||||||
state.forceAttrs(v2, pos);
|
state.forceAttrs(v2, pos);
|
||||||
|
|
||||||
Bindings::iterator j = v2.attrs->find(state.sName);
|
Bindings::iterator j = extractAttrNameFromPrimopCall(
|
||||||
if (j == v2.attrs->end()) {
|
state,
|
||||||
auto e = TypeError({
|
"listToAttrs",
|
||||||
.msg = hintfmt("'name' attribute missing for 'listToAttrs'"),
|
state.sName,
|
||||||
.errPos = *v2.attrs->pos
|
v2.attrs,
|
||||||
});
|
pos
|
||||||
e.addTrace(pos, hintfmt("while invoking '%s'", "listToAttrs"));
|
);
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
string name = state.forceStringNoCtx(*j->value, *j->pos);
|
string name = state.forceStringNoCtx(*j->value, *j->pos);
|
||||||
|
|
||||||
Symbol sym = state.symbols.create(name);
|
Symbol sym = state.symbols.create(name);
|
||||||
if (seen.insert(sym).second) {
|
if (seen.insert(sym).second) {
|
||||||
Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
|
Bindings::iterator j2 = extractAttrNameFromPrimopCall(
|
||||||
if (j2 == v2.attrs->end()) {
|
state,
|
||||||
auto e = TypeError({
|
"listToAttrs",
|
||||||
.msg = hintfmt("'value' attribute missing for 'listToAttrs'"),
|
state.sValue,
|
||||||
.errPos = *v2.attrs->pos
|
v2.attrs,
|
||||||
});
|
pos
|
||||||
e.addTrace(pos, hintfmt("while invoking '%s'", "listToAttrs"));
|
);
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
|
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue