summaryrefslogtreecommitdiffstats
path: root/arch/unicore32/.gitignore
AgeCommit message (Expand)Author
2011-03-17unicore32 core architecture: build infrastructureGuanXuetao
f='#n21'>21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#include "attr-path.hh"
#include "eval-inline.hh"
#include "util.hh"


namespace nix {


static Strings parseAttrPath(std::string_view s)
{
    Strings res;
    string cur;
    auto i = s.begin();
    while (i != s.end()) {
        if (*i == '.') {
            res.push_back(cur);
            cur.clear();
        } else if (*i == '"') {
            ++i;
            while (1) {
                if (i == s.end())
                    throw Error("missing closing quote in selection path '%1%'", s);
                if (*i == '"') break;
                cur.push_back(*i++);
            }
        } else
            cur.push_back(*i);
        ++i;
    }
    if (!cur.empty()) res.push_back(cur);
    return res;
}


std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
{
    std::vector<Symbol> res;
    for (auto & a : parseAttrPath(s))
        res.push_back(state.symbols.create(a));
    return res;
}


std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attrPath,
    Bindings & autoArgs, Value & vIn)
{
    Strings tokens = parseAttrPath(attrPath);

    Value * v = &vIn;
    Pos pos = noPos;

    for (auto & attr : tokens) {

        /* Is i an index (integer) or a normal attribute name? */
        enum { apAttr, apIndex } apType = apAttr;
        unsigned int attrIndex;
        if (string2Int(attr, attrIndex)) apType = apIndex;

        /* Evaluate the expression. */
        Value * vNew = state.allocValue();
        state.autoCallFunction(autoArgs, *v, *vNew);
        v = vNew;
        state.forceValue(*v);

        /* It should evaluate to either a set or an expression,
           according to what is specified in the attrPath. */

        if (apType == apAttr) {

            if (v->type != tAttrs)
                throw TypeError(
                    "the expression selected by the selection path '%1%' should be a set but is %2%",
                    attrPath,
                    showType(*v));
            if (attr.empty())
                throw Error("empty attribute name in selection path '%1%'", attrPath);

            Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
            if (a == v->attrs->end())
                throw AttrPathNotFound("attribute '%1%' in selection path '%2%' not found", attr, attrPath);
            v = &*a->value;
            pos = *a->pos;
        }

        else if (apType == apIndex) {

            if (!v->isList())
                throw TypeError(
                    "the expression selected by the selection path '%1%' should be a list but is %2%",
                    attrPath,
                    showType(*v));
            if (attrIndex >= v->listSize())
                throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", attrIndex, attrPath);

            v = v->listElems()[attrIndex];
            pos = noPos;
        }

    }

    return {v, pos};
}


Pos findDerivationFilename(EvalState & state, Value & v, std::string what)
{
    Value * v2;
    try {
        auto dummyArgs = state.allocBindings(0);
        v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v).first;
    } catch (Error &) {
        throw NoPositionInfo("package '%s' has no source location information", what);
    }

    // FIXME: is it possible to extract the Pos object instead of doing this
    //        toString + parsing?
    auto pos = state.forceString(*v2);

    auto colon = pos.rfind(':');
    if (colon == std::string::npos)
        throw Error("cannot parse meta.position attribute '%s'", pos);

    std::string filename(pos, 0, colon);
    unsigned int lineno;
    try {
        lineno = std::stoi(std::string(pos, colon + 1));
    } catch (std::invalid_argument & e) {
        throw Error("cannot parse line number '%s'", pos);
    }

    Symbol file = state.symbols.create(filename);

    return { foFile, file, lineno, 0 };
}


}