2015-07-14 17:18:56 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "nixexpr.hh"
|
|
|
|
#include "symbol-table.hh"
|
|
|
|
|
|
|
|
#include <algorithm>
|
2018-11-26 18:57:20 +00:00
|
|
|
#include <optional>
|
2015-07-14 17:18:56 +00:00
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
|
|
|
|
class EvalState;
|
|
|
|
struct Value;
|
|
|
|
|
|
|
|
/* Map one attribute name to its value. */
|
|
|
|
struct Attr
|
|
|
|
{
|
|
|
|
Symbol name;
|
|
|
|
Value * value;
|
2021-08-29 16:09:13 +00:00
|
|
|
ptr<Pos> pos;
|
|
|
|
Attr(Symbol name, Value * value, ptr<Pos> pos = ptr(&noPos))
|
2015-07-14 17:18:56 +00:00
|
|
|
: name(name), value(value), pos(pos) { };
|
|
|
|
Attr() : pos(&noPos) { };
|
|
|
|
bool operator < (const Attr & a) const
|
|
|
|
{
|
|
|
|
return name < a.name;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Bindings contains all the attributes of an attribute set. It is defined
|
|
|
|
by its size and its capacity, the capacity being the number of Attr
|
|
|
|
elements allocated after this structure, while the size corresponds to
|
|
|
|
the number of elements already inserted in this structure. */
|
|
|
|
class Bindings
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef uint32_t size_t;
|
2021-08-29 16:09:13 +00:00
|
|
|
ptr<Pos> pos;
|
2015-07-14 17:18:56 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
size_t size_, capacity_;
|
|
|
|
Attr attrs[0];
|
|
|
|
|
2021-08-29 16:09:13 +00:00
|
|
|
Bindings(size_t capacity) : pos(&noPos), size_(0), capacity_(capacity) { }
|
2015-07-14 17:18:56 +00:00
|
|
|
Bindings(const Bindings & bindings) = delete;
|
|
|
|
|
|
|
|
public:
|
|
|
|
size_t size() const { return size_; }
|
|
|
|
|
|
|
|
bool empty() const { return !size_; }
|
|
|
|
|
|
|
|
typedef Attr * iterator;
|
|
|
|
|
|
|
|
void push_back(const Attr & attr)
|
|
|
|
{
|
|
|
|
assert(size_ < capacity_);
|
|
|
|
attrs[size_++] = attr;
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator find(const Symbol & name)
|
|
|
|
{
|
|
|
|
Attr key(name, 0);
|
|
|
|
iterator i = std::lower_bound(begin(), end(), key);
|
|
|
|
if (i != end() && i->name == name) return i;
|
|
|
|
return end();
|
|
|
|
}
|
|
|
|
|
2020-02-13 16:15:05 +00:00
|
|
|
Attr * get(const Symbol & name)
|
2018-11-26 18:57:20 +00:00
|
|
|
{
|
|
|
|
Attr key(name, 0);
|
|
|
|
iterator i = std::lower_bound(begin(), end(), key);
|
|
|
|
if (i != end() && i->name == name) return &*i;
|
2020-02-13 16:15:05 +00:00
|
|
|
return nullptr;
|
2018-11-26 18:57:20 +00:00
|
|
|
}
|
|
|
|
|
2019-05-31 21:44:42 +00:00
|
|
|
Attr & need(const Symbol & name, const Pos & pos = noPos)
|
|
|
|
{
|
|
|
|
auto a = get(name);
|
|
|
|
if (!a)
|
2020-06-15 12:06:58 +00:00
|
|
|
throw Error({
|
2021-01-20 23:27:36 +00:00
|
|
|
.msg = hintfmt("attribute '%s' missing", name),
|
2020-06-23 21:30:13 +00:00
|
|
|
.errPos = pos
|
2020-06-15 12:06:58 +00:00
|
|
|
});
|
2020-05-09 00:18:28 +00:00
|
|
|
|
2020-02-13 16:15:05 +00:00
|
|
|
return *a;
|
2019-05-31 21:44:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-14 17:18:56 +00:00
|
|
|
iterator begin() { return &attrs[0]; }
|
|
|
|
iterator end() { return &attrs[size_]; }
|
|
|
|
|
|
|
|
Attr & operator[](size_t pos)
|
|
|
|
{
|
|
|
|
return attrs[pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
void sort();
|
|
|
|
|
|
|
|
size_t capacity() { return capacity_; }
|
|
|
|
|
2017-01-25 15:06:50 +00:00
|
|
|
/* Returns the attributes in lexicographically sorted order. */
|
|
|
|
std::vector<const Attr *> lexicographicOrder() const
|
|
|
|
{
|
|
|
|
std::vector<const Attr *> res;
|
|
|
|
res.reserve(size_);
|
|
|
|
for (size_t n = 0; n < size_; n++)
|
|
|
|
res.emplace_back(&attrs[n]);
|
|
|
|
std::sort(res.begin(), res.end(), [](const Attr * a, const Attr * b) {
|
2022-02-25 15:00:00 +00:00
|
|
|
return (const std::string &) a->name < (const std::string &) b->name;
|
2017-01-25 15:06:50 +00:00
|
|
|
});
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-07-14 17:18:56 +00:00
|
|
|
friend class EvalState;
|
|
|
|
};
|
|
|
|
|
2022-01-04 16:39:16 +00:00
|
|
|
/* A wrapper around Bindings that ensures that its always in sorted
|
|
|
|
order at the end. The only way to consume a BindingsBuilder is to
|
|
|
|
call finish(), which sorts the bindings. */
|
|
|
|
class BindingsBuilder
|
|
|
|
{
|
|
|
|
Bindings * bindings;
|
|
|
|
|
|
|
|
public:
|
2022-01-01 23:41:21 +00:00
|
|
|
// needed by std::back_inserter
|
|
|
|
using value_type = Attr;
|
2022-01-04 16:39:16 +00:00
|
|
|
|
2022-01-04 19:29:17 +00:00
|
|
|
EvalState & state;
|
|
|
|
|
2022-01-04 16:39:16 +00:00
|
|
|
BindingsBuilder(EvalState & state, Bindings * bindings)
|
2022-01-04 19:29:17 +00:00
|
|
|
: bindings(bindings), state(state)
|
2022-01-04 16:39:16 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
void insert(Symbol name, Value * value, ptr<Pos> pos = ptr(&noPos))
|
|
|
|
{
|
|
|
|
insert(Attr(name, value, pos));
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert(const Attr & attr)
|
2022-01-01 23:41:21 +00:00
|
|
|
{
|
|
|
|
push_back(attr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void push_back(const Attr & attr)
|
2022-01-04 16:39:16 +00:00
|
|
|
{
|
|
|
|
bindings->push_back(attr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Value & alloc(const Symbol & name, ptr<Pos> pos = ptr(&noPos));
|
|
|
|
|
|
|
|
Value & alloc(std::string_view name, ptr<Pos> pos = ptr(&noPos));
|
|
|
|
|
|
|
|
Bindings * finish()
|
|
|
|
{
|
|
|
|
bindings->sort();
|
|
|
|
return bindings;
|
|
|
|
}
|
2022-01-04 19:29:17 +00:00
|
|
|
|
|
|
|
Bindings * alreadySorted()
|
|
|
|
{
|
|
|
|
return bindings;
|
|
|
|
}
|
2022-01-04 16:39:16 +00:00
|
|
|
};
|
2015-07-14 17:18:56 +00:00
|
|
|
|
|
|
|
}
|