Skip to content

Commit

Permalink
libnixt/Serialize: use unified position
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Dec 23, 2023
1 parent 5a6e45f commit 48badb2
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 91 deletions.
14 changes: 2 additions & 12 deletions libnixt/include/nixt/Serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,7 @@ struct ASTHeader {
uint32_t Version;
};

struct ASTData {
std::ostringstream Exprs;
std::ostringstream Pos;
StringTable Strings;
};

/// Traverse the AST, flatten all nodes into "ASTData".
ASTData collect(const nix::SymbolTable &STable, const nix::PosTable &PTable,
const nix::Expr *E);

/// Emit ASTData into ostream.
std::ostream &write(std::ostream &OS, const ASTData &Data);
std::ostream &write(std::ostream &OS, const nix::SymbolTable &STable,
const nix::PosTable &PTable, const nix::Expr *E);

} // namespace nixt::serialize
29 changes: 10 additions & 19 deletions libnixt/include/nixt/SerializeSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@

namespace nixt::serialize {

/// "Plain Old Type". They are safe to be memcpied.
template <class T>
concept pod = std::is_standard_layout_v<T> && std::is_trivial_v<T>;

/// Basic primitives. Trivial data types are just written to a stream.
template <class T>
requires pod<T>
requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
std::ostream &write(std::ostream &OS, const T &Data) {
OS.write(reinterpret_cast<const char *>(&Data), sizeof(Data));
return OS;
Expand All @@ -29,35 +25,30 @@ std::ostream &write(std::ostream &OS, const std::vector<T> &Data) {
return OS;
}

/// Place an element into Indexed Vector
/// 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::ostringstream &Self, T Elt) {
template <class T> std::size_t place(std::ostream &Self, T Elt) {
std::size_t Loc = Self.tellp();
write(Self, Elt);
return Loc;
}

/// 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);

/// 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);

friend std::ostream &write(std::ostream &OS, const StringTable &Data) {
for (const auto &E : Data.Strings)
write(OS, E);
return OS;
}
StringTable(std::ostream &OS) : OS(OS) {}

private:
std::map<std::string, std::size_t> Map;
std::vector<std::string> Strings;
uint32_t Length = 0;
std::ostream &OS;
};

} // namespace nixt::serialize
120 changes: 63 additions & 57 deletions libnixt/lib/Serialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,74 +8,80 @@
#include <cstring>
#include <type_traits>

using nix::SourcePath;

namespace nixt::serialize {

ASTData collect(const nix::SymbolTable &STable, const nix::PosTable &PTable,
const nix::Expr *E) {
ASTData Data;
struct Visitor : public RecursiveASTVisitor<Visitor> {
ASTData &Data;
const nix::SymbolTable &STable;
const nix::PosTable &PTable;
std::map<const nix::Expr *, std::size_t> ExprMap;
namespace {

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

SerializeVisitor(std::ostream &OS, const nix::SymbolTable &STable,
const nix::PosTable &PTable)
: OS(OS), STable(STable), PTable(PTable) {}

Position getPos(nix::PosIdx P);
bool visitExprAttrs(const nix::ExprAttrs *E);
bool visitExprVar(const nix::ExprVar *E);
};

Visitor(ASTData &Data, const nix::SymbolTable &STable,
const nix::PosTable &PTable)
: Data(Data), STable(STable), PTable(PTable) {}
Position SerializeVisitor::getPos(nix::PosIdx P) {
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;
}

Position getPos(const nix::PosIdx P) {
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(Data.Strings,
std::get<nix::SourcePath>(Pos.origin).to_string());
return Ret;
}
bool visitExprAttrs(const nix::ExprAttrs *E) {
ExprAttrSet Expr;
Expr.Pos = place(Data.Pos, getPos(E->pos));
for (const auto &[K, V] : E->attrs) {
Expr.Attrs.emplace_back(
AttrDefEntry{place(Data.Strings, (STable[K])),
{V.inherited, ExprMap[V.e],
place(Data.Pos, (getPos(V.pos))), V.displ}});
}
ExprMap[E] = place(Data.Exprs, Expr);
return true;
}
bool 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(Data.Strings, STable[E->name]);
Expr.Body.Var.Pos = place(Data.Pos, getPos(E->pos));
ExprMap[E] = place(Data.Exprs, Expr);
return true;
}
bool SerializeVisitor::visitExprAttrs(const nix::ExprAttrs *E) {
ExprAttrSet Expr;
Expr.Pos = place(OS, getPos(E->pos));
for (const auto &[K, V] : E->attrs) {
Expr.Attrs.emplace_back(AttrDefEntry{
place(OS, std::string(STable[K])),
{V.inherited, ExprMap[V.e], place(OS, getPos(V.pos)), V.displ}});
}
ExprMap[E] = place(OS, Expr);
return true;
}

} Writer(Data, STable, PTable);
Writer.traverseExpr(E);
return Data;
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(E->pos));
ExprMap[E] = place(OS, Expr);
return true;
}

std::ostream &write(std::ostream &OS, const ASTData &Data) {
} // namespace

std::ostream &write(std::ostream &OS, const nix::SymbolTable &STable,
const nix::PosTable &PTable, const nix::Expr *E) {
SerializeVisitor Visitor(OS, STable, PTable);
// Write the header, metadata stuff like a magic number and a version number.
ASTHeader Header;
strcpy(Header.Magic, "\x7fNixAST");
Header.Version = 1;
write(OS, Header);
write(OS, Data.Exprs);
write(OS, Data.Pos);
write(OS, Data.Strings);

// Then traverse the AST
Visitor.traverseExpr(E);
return OS;
}

Expand Down
5 changes: 2 additions & 3 deletions libnixt/lib/SerializeSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ std::size_t place(StringTable &Self, std::string Str) {
if (Self.Map.contains(Str)) {
return Self.Map[std::move(Str)];
}
Self.Length += Str.size() + 1; // size of string + null terminator
std::size_t Ret = Self.Map[Str] = Self.Length;
Self.Strings.push_back(std::move(Str));
std::size_t Ret = Self.Map[Str] = Self.OS.tellp();
write(Self.OS, Str);
return Ret;
}

Expand Down

0 comments on commit 48badb2

Please sign in to comment.