Skip to content

Commit

Permalink
[!WIP] libnixt: unify serialize in visitor
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Dec 27, 2023
1 parent 2cbeb87 commit 64a98bd
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 175 deletions.
95 changes: 3 additions & 92 deletions libnixt/include/nixt/Serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,53 +16,10 @@

namespace nixt::serialize {

using StringIdx = std::size_t;
using PosIdx = std::size_t;
using ExprIdx = std::size_t;

struct Position {
uint32_t Line, Column;
enum OriginKind {
OK_None,
OK_Stdin,
OK_String,
OK_SourcePath,
} Kind;
// For "Source Path"
StringIdx Source;
};

struct AttrPath {
uint32_t Size;
StringIdx Name;
};

struct AttrDef {
bool Inherited;
ExprIdx E;
PosIdx Pos;
uint32_t Displ;
};

struct AttrDefEntry {
StringIdx Name;
AttrDef Def;
};

struct DynamicAttrDef {
ExprIdx NameExpr, ValueExpr;
PosIdx Pos;
};

enum class ExprKind : uint32_t {
EK_Int,
EK_Float,
EK_String,
EK_Path,
EK_Var,

// Needs custom encoding & decoding
EK_AttrSet,
#define NIX_EXPR(EXPR) EXPR,
#include "Nodes.inc"
#undef NIX_EXPR
};

using nix::NixFloat;
Expand All @@ -74,52 +31,6 @@ using nix::NixInt;
static_assert(std::is_same_v<nix::NixFloat, double>);
static_assert(std::is_same_v<nix::NixInt, std::int64_t>);

struct SimpleExpr {
ExprKind Kind;

struct Variable {
PosIdx Pos;
StringIdx Name;

bool FromWidth;

uint32_t Level;
uint32_t Displ;
};

struct Select {
PosIdx Pos;
AttrPath Path;
ExprIdx E;
ExprIdx Def;
};

struct OpHasAttr {
ExprIdx E;
AttrPath Path;
};

union {
NixInt Int;
NixFloat Float;
StringIdx String;
StringIdx Path;
Variable Var;
struct Select Select;
} Body;
};

struct ExprAttrSet {
ExprKind Kind = ExprKind::EK_AttrSet;
PosIdx Pos;
std::vector<AttrDefEntry> Attrs;
std::vector<DynamicAttrDef> DynamicAttrs;
};

inline std::ostream &write(std::ostream &OS, const ExprAttrSet &E) {
return OS;
}

struct ASTHeader {
char Magic[8];
uint32_t Version;
Expand Down
36 changes: 9 additions & 27 deletions libnixt/include/nixt/SerializeSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,25 @@ namespace nixt::serialize {
/// Basic primitives. Trivial data types are just written to a stream.
template <class T>
requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
std::ostream &write(std::ostream &OS, const T &Data) {
std::size_t write(std::ostream &OS, const T &Data) {
std::size_t Ret = OS.tellp();
OS.write(reinterpret_cast<const char *>(&Data), sizeof(Data));
return OS;
}

/// Vector. Write each element.
template <class T>
std::ostream &write(std::ostream &OS, const std::vector<T> &Data) {
for (const auto &E : Data)
write(OS, E);
return OS;
}

/// String. Write the string and a null terminator.
std::ostream &write(std::ostream &OS, const std::string &Data);

std::ostream &write(std::ostream &OS, const std::ostringstream &Data);

/// Place an element into a stream and return the position.
/// \returns the position for further element references
template <class T> std::size_t place(std::ostream &Self, T Elt) {
std::size_t Loc = Self.tellp();
write(Self, Elt);
return Loc;
return Ret;
}

/// The string table. This is actually a vector of strings, but de-duplicate
/// while construction.
class StringTable {
public:
friend std::size_t place(StringTable &Self, std::string Str);

StringTable(std::ostream &OS) : OS(OS) {}
friend std::size_t write(std::ostream &OS, StringTable &Self,
std::string Str);

private:
std::map<std::string, std::size_t> Map;
std::ostream &OS;

static std::size_t write(std::ostream &OS, const std::string &Data);

static std::size_t write(std::ostream &OS, const std::ostringstream &Data);
};

} // namespace nixt::serialize
195 changes: 148 additions & 47 deletions libnixt/lib/Serialize.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "nixt/Serialize.h"
#include "nixt/SerializeSupport.h"
#include "nixt/Visitor.h"

#include <nix/input-accessor.hh>
Expand All @@ -7,69 +8,169 @@

#include <cstring>
#include <type_traits>

using nix::SourcePath;
#include <utility>

namespace nixt::serialize {

namespace {

struct SerializeVisitor : public RecursiveASTVisitor<SerializeVisitor> {
class SerializeVisitor : public RecursiveASTVisitor<SerializeVisitor> {
std::ostream &OS;
const nix::SymbolTable &STable;
const nix::PosTable &PTable;
std::map<const nix::Expr *, std::size_t> ExprMap;
StringTable ST;

std::size_t writePosIdx(nix::PosIdx P) {
if (P == nix::noPos)
return write(OS, -1);
const auto &Pos = PTable[P];
std::size_t Ret = write(OS, Pos.line);
write(OS, Pos.column);
write(OS, Pos.origin.index());
if (std::get_if<nix::SourcePath>(&Pos.origin)) {
std::string Path = std::get<nix::SourcePath>(Pos.origin).to_string();
write(OS, ST, std::move(Path));
}
return Ret;
}

std::size_t writeSymbol(const nix::Symbol &S) {
return write(OS, ST, STable[S]);
}

std::size_t writeAttrName(const nix::AttrName &AN) {
std::size_t Ret = writeSymbol(AN.symbol);
write(OS, write(OS, ExprMap[AN.expr]));
return Ret;
}

std::size_t writeAttrPath(const nix::AttrPath &AP) {
std::size_t Ret = write(OS, AP.size());
for (const auto &AN : AP)
writeAttrName(AN);
return Ret;
}

std::size_t writeAttrDef(const nix::ExprAttrs::AttrDef &AD) {
std::size_t Ret = write(OS, AD.inherited);
write(OS, ExprMap[AD.e]);
writePosIdx(AD.pos);
write(OS, AD.displ);
return Ret;
}

std::size_t writeAttrDefs(const nix::ExprAttrs::AttrDefs &ADs) {
std::size_t Ret = write(OS, ADs.size());
for (const auto &[Symbol, AD] : ADs) {
writeSymbol(Symbol);
writeAttrDef(AD);
}
return Ret;
}

std::size_t writeDynamicAttrDef(const nix::ExprAttrs::DynamicAttrDef &DAD) {
std::size_t Ret = write(OS, ExprMap[DAD.nameExpr]);
write(OS, ExprMap[DAD.valueExpr]);
writePosIdx(DAD.pos);
return Ret;
}

std::size_t
writeDynamicAttrDefs(const nix::ExprAttrs::DynamicAttrDefs &DADs) {
std::size_t Ret = write(OS, DADs.size());
for (const auto &DAD : DADs)
writeDynamicAttrDef(DAD);
return Ret;
}

public:
SerializeVisitor(std::ostream &OS, const nix::SymbolTable &STable,
const nix::PosTable &PTable)
: OS(OS), STable(STable), PTable(PTable) {}
: OS(OS), STable(STable), PTable(PTable) {
ExprMap[nullptr] = 0;
}

bool visitExprAttrs(const nix::ExprAttrs *E);
bool visitExprVar(const nix::ExprVar *E);
};
/// Serializer should traverse the AST in post-order, so that we can reference
/// written nodes by tellp().
static bool shouldTraversePostOrder() { return true; }

Position getPos(std::ostream &OS, nix::PosIdx P, const nix::PosTable &PTable) {
if (P == nix::noPos)
return Position{};
const auto &Pos = PTable[P];
Position Ret;
Ret.Column = Pos.column;
Ret.Line = Pos.line;
Position::OriginKind KindTable[] = {Position::OK_None, Position::OK_Stdin,
Position::OK_String,
Position::OK_SourcePath};
Ret.Kind = KindTable[Pos.origin.index()];
if (Ret.Kind == Position::OK_SourcePath)
Ret.Source = place(OS, std::get<SourcePath>(Pos.origin).to_string());
return Ret;
}
bool visitExprInt(const nix::ExprInt *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprInt);
write(OS, E->n);
return true;
}

bool SerializeVisitor::visitExprAttrs(const nix::ExprAttrs *E) {
ExprAttrSet Expr;
Expr.Pos = place(OS, getPos(OS, E->pos, PTable));
for (const auto &[K, V] : E->attrs) {
AttrDefEntry Entry;
Entry.Name = place(OS, std::string(STable[K]));
Entry.Def.Inherited = V.inherited;
Entry.Def.E = ExprMap[V.e];
Entry.Def.Pos = place(OS, getPos(OS, V.pos, PTable));
Entry.Def.Displ = V.displ;
Expr.Attrs.emplace_back(Entry);
}
ExprMap[E] = place(OS, Expr);
return true;
}
bool visitExprFloat(const nix::ExprFloat *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprFloat);
write(OS, E->nf);
return true;
}

bool SerializeVisitor::visitExprVar(const nix::ExprVar *E) {
SimpleExpr Expr;
Expr.Kind = ExprKind::EK_Var;
Expr.Body.Var.Displ = E->displ;
Expr.Body.Var.FromWidth = E->fromWith;
Expr.Body.Var.Name = place(OS, std::string(STable[E->name]));
Expr.Body.Var.Pos = place(OS, getPos(OS, E->pos, PTable));
ExprMap[E] = place(OS, Expr);
return true;
}
bool visitExprString(const nix::ExprString *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprString);
write(OS, ST, E->s);
return true;
}

bool visitExprPath(const nix::ExprPath *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprPath);
write(OS, ST, E->s);
return true;
}

bool visitExprVar(const nix::ExprVar *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprVar);
writePosIdx(E->pos);
writeSymbol(E->name);
write(OS, E->fromWith);
write(OS, E->level);
write(OS, E->displ);
return true;
}

bool visitExprSelect(const nix::ExprSelect *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprSelect);
write(OS, writePosIdx(E->pos));
write(OS, ExprMap[E->def]);
write(OS, ExprMap[E->e]);
writeAttrPath(E->attrPath);
return true;
}

bool visitExprOpHasAttr(const nix::ExprOpHasAttr *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprOpHasAttr);
write(OS, ExprMap[E->e]);
writeAttrPath(E->attrPath);
return true;
}

bool visitExprAttrs(const nix::ExprAttrs *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprAttrs);
write(OS, E->recursive);
writePosIdx(E->pos);
writeAttrDefs(E->attrs);
writeDynamicAttrDefs(E->dynamicAttrs);
return true;
}

bool visitExprList(const nix::ExprList *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprList);
write(OS, E->elems.size());
for (const auto &Elem : E->elems)
write(OS, ExprMap[Elem]);
return true;
}
};

} // namespace

Expand Down
Loading

0 comments on commit 64a98bd

Please sign in to comment.