Skip to content

Commit

Permalink
libnixt: add libnixt files
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Dec 16, 2023
1 parent 35c78f6 commit e62f2cd
Show file tree
Hide file tree
Showing 11 changed files with 366 additions and 0 deletions.
15 changes: 15 additions & 0 deletions libnixt/include/nixt/Displacement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <nix/nixexpr.hh>

namespace nixt {

nix::PosIdx displOf(const nix::Expr *E, nix::Displacement Displ);

nix::PosIdx displOf(const nix::ExprAttrs *E, nix::Displacement Displ);

nix::PosIdx displOf(const nix::ExprLet *E, nix::Displacement Displ);

nix::PosIdx displOf(const nix::ExprLambda *E, nix::Displacement Displ);

} // namespace nixt
10 changes: 10 additions & 0 deletions libnixt/include/nixt/Name.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <nix/nixexpr.hh>

namespace nixt {

// Get printable name of some expression
const char *nameOf(const nix::Expr *E);

} // namespace nixt
34 changes: 34 additions & 0 deletions libnixt/include/nixt/Nodes.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// Nodes.inc, nix expressions declaration.
/// \file
/// This record file provides NIX_EXPR macro that contains all names of
/// nix::Expr

#ifdef NIX_EXPR

NIX_EXPR(ExprAssert)
NIX_EXPR(ExprAttrs)
NIX_EXPR(ExprCall)
NIX_EXPR(ExprConcatStrings)
NIX_EXPR(ExprFloat)
NIX_EXPR(ExprIf)
NIX_EXPR(ExprInt)
NIX_EXPR(ExprLambda)
NIX_EXPR(ExprLet)
NIX_EXPR(ExprList)
NIX_EXPR(ExprOpAnd)
NIX_EXPR(ExprOpConcatLists)
NIX_EXPR(ExprOpEq)
NIX_EXPR(ExprOpHasAttr)
NIX_EXPR(ExprOpImpl)
NIX_EXPR(ExprOpNEq)
NIX_EXPR(ExprOpNot)
NIX_EXPR(ExprOpOr)
NIX_EXPR(ExprOpUpdate)
NIX_EXPR(ExprPath)
NIX_EXPR(ExprPos)
NIX_EXPR(ExprSelect)
NIX_EXPR(ExprString)
NIX_EXPR(ExprVar)
NIX_EXPR(ExprWith)

#endif // NIX_EXPR
11 changes: 11 additions & 0 deletions libnixt/include/nixt/ParentMap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "Visitor.h"

namespace nixt {

using ParentMap = std::map<const nix::Expr *, const nix::Expr *>;

ParentMap parentMap(const nix::Expr *Root);

} // namespace nixt
104 changes: 104 additions & 0 deletions libnixt/include/nixt/Traverse.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/// Traverse.inc, the file declares how to traverse nix::Expr
///
/// The file provides: DEF_TRAVERSE_TYPE(Name, Stmt)
/// Stmt defines how to traverse AST nodes (i.e. visit it's subnodes)
/// The subnodes is wrapped around with macro TRY_TO_TRAVERSE.

#ifdef DEF_TRAVERSE_TYPE

DEF_TRAVERSE_TYPE(ExprAssert, {
TRY_TO_TRAVERSE(T->cond);
TRY_TO_TRAVERSE(T->body);
})

DEF_TRAVERSE_TYPE(ExprAttrs, {
for (auto &[_, Elem] : T->attrs)
TRY_TO_TRAVERSE(Elem.e);
for (auto &DAD : T->dynamicAttrs) {
TRY_TO_TRAVERSE(DAD.nameExpr);
TRY_TO_TRAVERSE(DAD.valueExpr);
}
})

DEF_TRAVERSE_TYPE(ExprCall, {
for (auto &Arg : T->args)
TRY_TO_TRAVERSE(Arg);
TRY_TO_TRAVERSE(T->fun);
})

DEF_TRAVERSE_TYPE(ExprConcatStrings, {
for (auto &[_, E] : *T->es)
TRY_TO_TRAVERSE(E);
})

DEF_TRAVERSE_TYPE(ExprFloat, {})

DEF_TRAVERSE_TYPE(ExprIf, {
TRY_TO_TRAVERSE(T->cond);
TRY_TO_TRAVERSE(T->then);
TRY_TO_TRAVERSE(T->else_);
})

DEF_TRAVERSE_TYPE(ExprInt, {})

DEF_TRAVERSE_TYPE(ExprLambda, {
if (T->hasFormals())
for (auto &F : T->formals->formals)
TRY_TO_TRAVERSE(F.def);
TRY_TO_TRAVERSE(T->body);
})

DEF_TRAVERSE_TYPE(ExprLet, {
TRY_TO_TRAVERSE(T->attrs);
TRY_TO_TRAVERSE(T->body);
})

DEF_TRAVERSE_TYPE(ExprList, {
for (auto &E : T->elems)
TRY_TO_TRAVERSE(E);
})

#define DEF_TRAVERSE_BINARY_EXPR(BIN_OP) \
DEF_TRAVERSE_TYPE(BIN_OP, { \
TRY_TO_TRAVERSE(T->e1); \
TRY_TO_TRAVERSE(T->e2); \
})

DEF_TRAVERSE_BINARY_EXPR(ExprOpAnd)
DEF_TRAVERSE_BINARY_EXPR(ExprOpConcatLists)
DEF_TRAVERSE_BINARY_EXPR(ExprOpEq)
DEF_TRAVERSE_BINARY_EXPR(ExprOpImpl)
DEF_TRAVERSE_BINARY_EXPR(ExprOpNEq)
DEF_TRAVERSE_BINARY_EXPR(ExprOpOr)
DEF_TRAVERSE_BINARY_EXPR(ExprOpUpdate)

#undef DEF_TRAVERSE_BINARY_EXPR

DEF_TRAVERSE_TYPE(ExprOpHasAttr, {
TRY_TO_TRAVERSE(T->e);
for (auto &E : T->attrPath)
if (!E.symbol)
TRY_TO_TRAVERSE(E.expr);
})

DEF_TRAVERSE_TYPE(ExprOpNot, { TRY_TO_TRAVERSE(T->e); })

DEF_TRAVERSE_TYPE(ExprPath, {})
DEF_TRAVERSE_TYPE(ExprPos, {})
DEF_TRAVERSE_TYPE(ExprSelect, {
TRY_TO_TRAVERSE(T->def);
TRY_TO_TRAVERSE(T->e);
for (auto &E : T->attrPath) {
if (!E.symbol)
TRY_TO_TRAVERSE(E.expr);
}
})

DEF_TRAVERSE_TYPE(ExprString, {})
DEF_TRAVERSE_TYPE(ExprVar, {})
DEF_TRAVERSE_TYPE(ExprWith, {
TRY_TO_TRAVERSE(T->attrs);
TRY_TO_TRAVERSE(T->body);
})

#endif // DEF_TRAVERSE_TYPE
62 changes: 62 additions & 0 deletions libnixt/include/nixt/Visitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/// Visitor.h, describe how to traverse upon nix::Expr * nodes.
#pragma once

#include <nix/nixexpr.hh>
#include <nix/symbol-table.hh>

namespace nixt {

template <class Derived> struct RecursiveASTVisitor {

bool shouldTraversePostOrder() { return false; }

bool visitExpr(const nix::Expr *) { return true; }

#define NIX_EXPR(EXPR) bool traverse##EXPR(const nix::EXPR *E);
#include "Nodes.inc"
#undef NIX_EXPR

#define NIX_EXPR(EXPR) \
bool visit##EXPR(const nix::EXPR *E) { return getDerived().visitExpr(E); }
#include "Nodes.inc"
#undef NIX_EXPR

Derived &getDerived() { return *static_cast<Derived *>(this); }

bool traverseExpr(const nix::Expr *E) {
if (!E)
return true;
#define NIX_EXPR(EXPR) \
if (auto CE = dynamic_cast<const nix::EXPR *>(E)) { \
return getDerived().traverse##EXPR(CE); \
}
#include "Nodes.inc"
#undef NIX_EXPR
assert(false && "We are missing some nix AST Nodes!");
return true;
}
};

#define TRY_TO(CALL_EXPR) \
do { \
if (!getDerived().CALL_EXPR) \
return false; \
} while (false)

#define TRY_TO_TRAVERSE(EXPR) TRY_TO(traverseExpr(EXPR))

#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
template <typename Derived> \
bool RecursiveASTVisitor<Derived>::traverse##TYPE(const nix::TYPE *T) { \
if (!getDerived().shouldTraversePostOrder()) \
TRY_TO(visit##TYPE(T)); \
{ CODE; } \
if (getDerived().shouldTraversePostOrder()) \
TRY_TO(visit##TYPE(T)); \
return true; \
}
#include "Traverse.inc"
#undef DEF_TRAVERSE_TYPE
#undef TRY_TO_TRAVERSE

} // namespace nixt
45 changes: 45 additions & 0 deletions libnixt/lib/Displacement.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "nixt/Displacement.h"

namespace nixt {

nix::PosIdx displOf(const nix::Expr *E, nix::Displacement Displ) {
if (const auto *CE = dynamic_cast<const nix::ExprAttrs *>(E))
return displOf(CE, Displ);
if (const auto *CE = dynamic_cast<const nix::ExprLet *>(E))
return displOf(CE, Displ);
if (const auto *CE = dynamic_cast<const nix::ExprLambda *>(E))
return displOf(CE, Displ);

assert(false && "The requested expr is not an env creator");
return nix::noPos; // unreachable
}

nix::PosIdx displOf(const nix::ExprAttrs *E, nix::Displacement Displ) {
assert(E->recursive && "Only recursive ExprAttr has displacement values");

auto DefIt = E->attrs.begin();
std::advance(DefIt, Displ);

return DefIt->second.pos;
}

nix::PosIdx displOf(const nix::ExprLet *E, nix::Displacement Displ) {
auto DefIt = E->attrs->attrs.begin();
std::advance(DefIt, Displ);

return DefIt->second.pos;
}

nix::PosIdx displOf(const nix::ExprLambda *E, nix::Displacement Displ) {
if (E->arg) {
if (Displ == 0)
// It is just a symbol, so noPos.
return nix::noPos;
Displ--;
}

assert(E->hasFormals() && "Lambda must has formals to create displ");
return E->formals->formals[Displ].pos;
}

} // namespace nixt
17 changes: 17 additions & 0 deletions libnixt/lib/Name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "nixt/Name.h"

namespace nixt {

const char *nameOf(const nix::Expr *E) {
#define NIX_EXPR(EXPR) \
if (dynamic_cast<const nix::EXPR *>(E)) { \
return #EXPR; \
}
#include "nixt/Nodes.inc"
assert(false &&
"Cannot dynamic-cast to nix::Expr*, missing entries in Nodes.inc?");
return nullptr;
#undef NIX_EXPR
}

} // namespace nixt
36 changes: 36 additions & 0 deletions libnixt/lib/ParentMap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "nixt/ParentMap.h"

namespace nixt {

ParentMap parentMap(const nix::Expr *Root) {
ParentMap Ret;
struct VisitorClass : RecursiveASTVisitor<VisitorClass> {
/// The parent before traverseExpr
const nix::Expr *ParentExpr;
ParentMap *CapturedRet;

bool traverseExpr(const nix::Expr *E) {
CapturedRet->insert({E, ParentExpr});
const auto *OldParent = ParentExpr;
ParentExpr = E; // Set the parent into the visitor, it should be the
// parent when we are traversing child nodes.
if (!RecursiveASTVisitor<VisitorClass>::traverseExpr(E))
return false;

// After traversing on childrens finished, set parent expr to previous
// parent.
ParentExpr = OldParent;
return true;
}

} Visitor;

Visitor.ParentExpr = Root;
Visitor.CapturedRet = &Ret;

Visitor.traverseExpr(Root);

return Ret;
}

} // namespace nixt
29 changes: 29 additions & 0 deletions libnixt/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
nix_main = dependency('nix-main')
nix_expr = dependency('nix-expr')
nix_cmd = dependency('nix-cmd')

libnixtDeps = [ nix_expr, nix_main, nix_cmd, boost ]

libnixdInc = include_directories('include')

libnixt = library('nixt',
'lib/Displacement.cpp',
'lib/Name.cpp',
'lib/ParentMap.cpp',
include_directories: libnixdInc,
dependencies: libnixtDeps,
install: true
)

pkgconfig.generate(name: 'libnixt',
version: 'nightly',
description: 'nix tooling',
subdirs: [ 'nixt' ],
libraries: libnixt
)


nixt = declare_dependency(include_directories: libnixdInc,
dependencies: libnixtDeps,
link_with: libnixt
)
3 changes: 3 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@ backtrace = cpp.find_library('backtrace')

lit = find_program('lit', required: false)

pkgconfig = import('pkgconfig')

subdir('lspserver')
subdir('libnixt')
subdir('nixd')

0 comments on commit e62f2cd

Please sign in to comment.