Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
9999years committed Jan 22, 2024
1 parent 7453482 commit 0161461
Show file tree
Hide file tree
Showing 22 changed files with 350 additions and 298 deletions.
2 changes: 2 additions & 0 deletions src/libexpr/attr-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin

if (v->type() != nAttrs)
throw TypeError(
state,
"the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath,
showType(*v));
Expand All @@ -89,6 +90,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin

if (!v->isList())
throw TypeError(
state,
"the expression selected by the selection path '%1%' should be a list but is %2%",
attrPath,
showType(*v));
Expand Down
26 changes: 13 additions & 13 deletions src/libexpr/eval-cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
if (forceErrors)
debug("reevaluating failed cached attribute '%s'", getAttrPathStr(name));
else
throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name));
throw CachedEvalError(root->state, "cached failure of attribute '%s'", getAttrPathStr(name));
} else
return std::make_shared<AttrCursor>(root,
std::make_pair(shared_from_this(), name), nullptr, std::move(attr));
Expand Down Expand Up @@ -574,14 +574,14 @@ std::string AttrCursor::getString()
debug("using cached string attribute '%s'", getAttrPathStr());
return s->first;
} else
root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not a string", getAttrPathStr()).debugThrow();
}
}

auto & v = forceValue();

if (v.type() != nString && v.type() != nPath)
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not a string but %s", getAttrPathStr()).debugThrow();

return v.type() == nString ? v.c_str() : v.path().to_string();
}
Expand Down Expand Up @@ -616,7 +616,7 @@ string_t AttrCursor::getStringWithContext()
return *s;
}
} else
root->state.error("'%s' is not a string", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not a string", getAttrPathStr()).debugThrow();
}
}

Expand All @@ -630,7 +630,7 @@ string_t AttrCursor::getStringWithContext()
else if (v.type() == nPath)
return {v.path().to_string(), {}};
else
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not a string but %s", getAttrPathStr()).debugThrow();
}

bool AttrCursor::getBool()
Expand All @@ -643,14 +643,14 @@ bool AttrCursor::getBool()
debug("using cached Boolean attribute '%s'", getAttrPathStr());
return *b;
} else
root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not a Boolean", getAttrPathStr()).debugThrow();
}
}

auto & v = forceValue();

if (v.type() != nBool)
root->state.error("'%s' is not a Boolean", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not a Boolean", getAttrPathStr()).debugThrow();

return v.boolean;
}
Expand All @@ -665,14 +665,14 @@ NixInt AttrCursor::getInt()
debug("using cached integer attribute '%s'", getAttrPathStr());
return i->x;
} else
throw TypeError("'%s' is not an integer", getAttrPathStr());
throw TypeError(root->state, "'%s' is not an integer", getAttrPathStr());
}
}

auto & v = forceValue();

if (v.type() != nInt)
throw TypeError("'%s' is not an integer", getAttrPathStr());
throw TypeError(root->state, "'%s' is not an integer", getAttrPathStr());

return v.integer;
}
Expand All @@ -687,7 +687,7 @@ std::vector<std::string> AttrCursor::getListOfStrings()
debug("using cached list of strings attribute '%s'", getAttrPathStr());
return *l;
} else
throw TypeError("'%s' is not a list of strings", getAttrPathStr());
throw TypeError(root->state, "'%s' is not a list of strings", getAttrPathStr());
}
}

Expand All @@ -697,7 +697,7 @@ std::vector<std::string> AttrCursor::getListOfStrings()
root->state.forceValue(v, noPos);

if (v.type() != nList)
throw TypeError("'%s' is not a list", getAttrPathStr());
throw TypeError(root->state, "'%s' is not a list", getAttrPathStr());

std::vector<std::string> res;

Expand All @@ -720,14 +720,14 @@ std::vector<Symbol> AttrCursor::getAttrs()
debug("using cached attrset attribute '%s'", getAttrPathStr());
return *attrs;
} else
root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not an attribute set", getAttrPathStr()).debugThrow();
}
}

auto & v = forceValue();

if (v.type() != nAttrs)
root->state.error("'%s' is not an attribute set", getAttrPathStr()).debugThrow<TypeError>();
TypeError(root->state, "'%s' is not an attribute set", getAttrPathStr()).debugThrow();

std::vector<Symbol> attrs;
for (auto & attr : *getValue().attrs)
Expand Down
64 changes: 64 additions & 0 deletions src/libexpr/eval-error.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "eval-error.hh"
#include "eval.hh"

namespace nix {

EvalError & EvalError::atPos(PosIdx pos)
{
err.errPos = state.positions[pos];
return *this;
}

EvalError & EvalError::withTrace(PosIdx pos, const std::string_view text)
{
err.traces.push_front(Trace{.pos = state.positions[pos], .hint = hintformat(std::string(text)), .frame = false});
return *this;
}

EvalError & EvalError::withFrameTrace(PosIdx pos, const std::string_view text)
{
err.traces.push_front(Trace{.pos = state.positions[pos], .hint = hintformat(std::string(text)), .frame = true});
return *this;
}

EvalError & EvalError::withSuggestions(Suggestions & s)
{
err.suggestions = s;
return *this;
}

EvalError & EvalError::withFrame(const Env & env, const Expr & expr)
{
// NOTE: This is abusing side-effects.
// TODO: check compatibility with nested debugger calls.
// TODO: What side-effects??
state.debugTraces.push_front(DebugTrace{
.pos = nullptr,
.expr = expr,
.env = env,
.hint = hintformat("Fake frame for debugging purposes"),
.isError = true});
return *this;
}

EvalError & EvalError::addTrace(PosIdx pos, hintformat hint, bool frame)
{
BaseError::addTrace(state.positions[pos], hint, frame);
return *this;
}

template<typename... Args>
EvalError & EvalError::addTrace(PosIdx pos, std::string_view formatString, const Args &... formatArgs)
{

addTrace(state.positions[pos], hintfmt(std::string(formatString), formatArgs...));
return *this;
}

void EvalError::debugThrow()
{
// NOTE: We always use the -LastTrace version as we push the new trace in withFrame()
state.debugThrowLastTrace(this);
}

}
64 changes: 64 additions & 0 deletions src/libexpr/eval-error.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include "error.hh"

namespace nix {

class PosIdx;
struct Env;
struct Expr;

class EvalState;

class EvalError : public Error
{
public:
EvalState & state;

EvalError(EvalState & state, ErrorInfo && errorInfo)
: Error(errorInfo)
, state(state)
{
}

template<typename... Args>
explicit EvalError(EvalState & state, const std::string & formatString, const Args &... formatArgs)
: Error(formatString, formatArgs...)
, state(state)
{
}

[[nodiscard, gnu::noinline]] EvalError & atPos(PosIdx pos);

[[nodiscard, gnu::noinline]] EvalError & withTrace(PosIdx pos, const std::string_view text);

[[nodiscard, gnu::noinline]] EvalError & withFrameTrace(PosIdx pos, const std::string_view text);

[[nodiscard, gnu::noinline]] EvalError & withSuggestions(Suggestions & s);

[[nodiscard, gnu::noinline]] EvalError & withFrame(const Env & e, const Expr & ex);

[[nodiscard, gnu::noinline]] EvalError & addTrace(PosIdx pos, hintformat hint, bool frame = false);

template<typename... Args>
EvalError & addTrace(PosIdx pos, std::string_view formatString, const Args &... formatArgs);

[[gnu::noinline, gnu::noreturn]] void debugThrow();
};

MakeError(ParseError, Error);
MakeError(AssertionError, EvalError);
MakeError(ThrownError, AssertionError);
MakeError(Abort, EvalError);
MakeError(TypeError, EvalError);
MakeError(UndefinedVarError, EvalError);
MakeError(MissingArgumentError, EvalError);

class InfiniteRecursionError : public EvalError
{
friend class EvalState;
public:
using EvalError::EvalError;
};

}
5 changes: 3 additions & 2 deletions src/libexpr/eval-inline.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
///@file

#include "eval.hh"
#include "eval-error.hh"

namespace nix {

Expand Down Expand Up @@ -114,7 +115,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos, std::string_view e
PosIdx pos = getPos();
forceValue(v, pos);
if (v.type() != nAttrs) {
error("value is %1% while a set was expected", showType(v)).withTrace(pos, errorCtx).debugThrow<TypeError>();
TypeError(*this, "value is %1% while a set was expected", showType(v)).withTrace(pos, errorCtx).debugThrow();
}
}

Expand All @@ -124,7 +125,7 @@ inline void EvalState::forceList(Value & v, const PosIdx pos, std::string_view e
{
forceValue(v, pos);
if (!v.isList()) {
error("value is %1% while a list was expected", showType(v)).withTrace(pos, errorCtx).debugThrow<TypeError>();
TypeError(*this, "value is %1% while a list was expected", showType(v)).withTrace(pos, errorCtx).debugThrow();
}
}

Expand Down
Loading

0 comments on commit 0161461

Please sign in to comment.