Skip to content

Commit

Permalink
libnixf: add parent map (#391)
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc authored Apr 9, 2024
1 parent c217f09 commit a01bcc6
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
35 changes: 35 additions & 0 deletions libnixf/include/nixf/Sema/ParentMap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// \file
/// \brief ParentMap analysis.
///
/// This is used to construct upward edges. For each node, record it's direct
/// parent. (Abstract Syntax TREE only have one parent for each node).

#pragma once

#include "nixf/Basic/Nodes/Basic.h"

#include <map>

namespace nixf {

class ParentMapAnalysis {
std::map<const Node *, const Node *> ParentMap;

void dfs(const Node *N, const Node *Parent);

public:
void runOnAST(const Node &Root);

const Node *query(const Node &N);

static bool isRoot(const Node *Up, const Node &N);

/// \brief Search up until the node becomes a concrete expression.
/// a
/// ^<----- ID -> ExprVar
const Node *upExpr(const Node &N);

bool isRoot(const Node &N);
};

} // namespace nixf
2 changes: 2 additions & 0 deletions libnixf/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ libnixf = library(
'src/Parse/ParseSimple.cpp',
'src/Parse/ParseStrings.cpp',
'src/Parse/ParseSupport.cpp',
'src/Sema/ParentMap.cpp',
'src/Sema/SemaActions.cpp',
'src/Sema/VariableLookup.cpp',
include_directories: libnixf_inc,
Expand Down Expand Up @@ -68,6 +69,7 @@ test('unit/libnixf/Sema',
executable('unit-libnixf-sema',
'test/Sema/SemaActions.cpp',
'test/Sema/VariableLookup.cpp',
'test/Sema/ParentMap.cpp',
dependencies: [ nixf, gtest_main ],
include_directories: [ 'src/Sema' ] # Private headers
)
Expand Down
38 changes: 38 additions & 0 deletions libnixf/src/Sema/ParentMap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "nixf/Sema/ParentMap.h"

using namespace nixf;

void ParentMapAnalysis::dfs(const Node *N, const Node *Parent) {
if (!N)
return;
ParentMap.insert({N, Parent});
for (const Node *Ch : N->children())
dfs(Ch, N);
}

const Node *ParentMapAnalysis::query(const Node &N) {
return ParentMap.contains(&N) ? ParentMap.at(&N) : nullptr;
}

const Node *ParentMapAnalysis::upExpr(const Node &N) {

if (Expr::isExpr(N.kind()))
return &N;
const Node *Up = query(N);
if (isRoot(Up, N) || !Up)
return nullptr;
return upExpr(*Up);
}

void ParentMapAnalysis::runOnAST(const Node &Root) {
// Special case. Root node has itself as "parent".
dfs(&Root, &Root);
}

bool nixf::ParentMapAnalysis::isRoot(const Node *Up, const Node &N) {
return Up == &N;
}

bool nixf::ParentMapAnalysis::isRoot(const Node &N) {
return isRoot(query(N), N);
}
29 changes: 29 additions & 0 deletions libnixf/test/Sema/ParentMap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <gtest/gtest.h>

#include "nixf/Basic/Diagnostic.h"
#include "nixf/Parse/Parser.h"
#include "nixf/Sema/ParentMap.h"

using namespace nixf;

namespace {

struct ParentMapTest : testing::Test {
std::vector<Diagnostic> Diags;

ParentMapAnalysis PMA;
};

TEST_F(ParentMapTest, Basic) {
auto AST = nixf::parse(R"(a)", Diags);
PMA.runOnAST(*AST);

const Node *ID = AST->descend({{0, 0}, {0, 1}});
ASSERT_EQ(ID->kind(), Node::NK_Identifer);

const Node *Var = PMA.upExpr(*ID);

ASSERT_EQ(Var->kind(), Node::NK_ExprVar);
}

} // namespace

0 comments on commit a01bcc6

Please sign in to comment.