From e62f2cd498921b87b78e720b4caecf7e3c8a44c3 Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Sat, 16 Dec 2023 18:00:23 +0800 Subject: [PATCH] libnixt: add libnixt files --- libnixt/include/nixt/Displacement.h | 15 ++++ libnixt/include/nixt/Name.h | 10 +++ libnixt/include/nixt/Nodes.inc | 34 +++++++++ libnixt/include/nixt/ParentMap.h | 11 +++ libnixt/include/nixt/Traverse.inc | 104 ++++++++++++++++++++++++++++ libnixt/include/nixt/Visitor.h | 62 +++++++++++++++++ libnixt/lib/Displacement.cpp | 45 ++++++++++++ libnixt/lib/Name.cpp | 17 +++++ libnixt/lib/ParentMap.cpp | 36 ++++++++++ libnixt/meson.build | 29 ++++++++ meson.build | 3 + 11 files changed, 366 insertions(+) create mode 100644 libnixt/include/nixt/Displacement.h create mode 100644 libnixt/include/nixt/Name.h create mode 100644 libnixt/include/nixt/Nodes.inc create mode 100644 libnixt/include/nixt/ParentMap.h create mode 100644 libnixt/include/nixt/Traverse.inc create mode 100644 libnixt/include/nixt/Visitor.h create mode 100644 libnixt/lib/Displacement.cpp create mode 100644 libnixt/lib/Name.cpp create mode 100644 libnixt/lib/ParentMap.cpp create mode 100644 libnixt/meson.build diff --git a/libnixt/include/nixt/Displacement.h b/libnixt/include/nixt/Displacement.h new file mode 100644 index 000000000..581bc1c9f --- /dev/null +++ b/libnixt/include/nixt/Displacement.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +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 diff --git a/libnixt/include/nixt/Name.h b/libnixt/include/nixt/Name.h new file mode 100644 index 000000000..ba136b938 --- /dev/null +++ b/libnixt/include/nixt/Name.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace nixt { + +// Get printable name of some expression +const char *nameOf(const nix::Expr *E); + +} // namespace nixt diff --git a/libnixt/include/nixt/Nodes.inc b/libnixt/include/nixt/Nodes.inc new file mode 100644 index 000000000..6da78294c --- /dev/null +++ b/libnixt/include/nixt/Nodes.inc @@ -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 diff --git a/libnixt/include/nixt/ParentMap.h b/libnixt/include/nixt/ParentMap.h new file mode 100644 index 000000000..78b2b36d2 --- /dev/null +++ b/libnixt/include/nixt/ParentMap.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Visitor.h" + +namespace nixt { + +using ParentMap = std::map; + +ParentMap parentMap(const nix::Expr *Root); + +} // namespace nixt diff --git a/libnixt/include/nixt/Traverse.inc b/libnixt/include/nixt/Traverse.inc new file mode 100644 index 000000000..45d7484f9 --- /dev/null +++ b/libnixt/include/nixt/Traverse.inc @@ -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 diff --git a/libnixt/include/nixt/Visitor.h b/libnixt/include/nixt/Visitor.h new file mode 100644 index 000000000..3640a817e --- /dev/null +++ b/libnixt/include/nixt/Visitor.h @@ -0,0 +1,62 @@ +/// Visitor.h, describe how to traverse upon nix::Expr * nodes. +#pragma once + +#include +#include + +namespace nixt { + +template 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(this); } + + bool traverseExpr(const nix::Expr *E) { + if (!E) + return true; +#define NIX_EXPR(EXPR) \ + if (auto CE = dynamic_cast(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 \ + bool RecursiveASTVisitor::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 diff --git a/libnixt/lib/Displacement.cpp b/libnixt/lib/Displacement.cpp new file mode 100644 index 000000000..dd740c83e --- /dev/null +++ b/libnixt/lib/Displacement.cpp @@ -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(E)) + return displOf(CE, Displ); + if (const auto *CE = dynamic_cast(E)) + return displOf(CE, Displ); + if (const auto *CE = dynamic_cast(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 diff --git a/libnixt/lib/Name.cpp b/libnixt/lib/Name.cpp new file mode 100644 index 000000000..b58817515 --- /dev/null +++ b/libnixt/lib/Name.cpp @@ -0,0 +1,17 @@ +#include "nixt/Name.h" + +namespace nixt { + +const char *nameOf(const nix::Expr *E) { +#define NIX_EXPR(EXPR) \ + if (dynamic_cast(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 diff --git a/libnixt/lib/ParentMap.cpp b/libnixt/lib/ParentMap.cpp new file mode 100644 index 000000000..e1aa07686 --- /dev/null +++ b/libnixt/lib/ParentMap.cpp @@ -0,0 +1,36 @@ +#include "nixt/ParentMap.h" + +namespace nixt { + +ParentMap parentMap(const nix::Expr *Root) { + ParentMap Ret; + struct VisitorClass : RecursiveASTVisitor { + /// 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::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 diff --git a/libnixt/meson.build b/libnixt/meson.build new file mode 100644 index 000000000..dbaac2db2 --- /dev/null +++ b/libnixt/meson.build @@ -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 +) diff --git a/meson.build b/meson.build index fd5d8c698..a66239380 100644 --- a/meson.build +++ b/meson.build @@ -37,5 +37,8 @@ backtrace = cpp.find_library('backtrace') lit = find_program('lit', required: false) +pkgconfig = import('pkgconfig') + subdir('lspserver') +subdir('libnixt') subdir('nixd')