Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Commit

Permalink
Implement LHS template traversal and matching
Browse files Browse the repository at this point in the history
Rewrite LHS matches
Add some example transformations
  • Loading branch information
ROpdebee committed May 25, 2017
1 parent f470b59 commit 1cb8c61
Show file tree
Hide file tree
Showing 42 changed files with 1,348 additions and 163 deletions.
30 changes: 24 additions & 6 deletions Framework X.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
4500F5AE1ECF23C9005BEC95 /* ASTTraversalState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4500F5AC1ECF23C9005BEC95 /* ASTTraversalState.cpp */; };
4500F5B01ED0AABA005BEC95 /* libjson-schema-validator.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4500F5AF1ED0AABA005BEC95 /* libjson-schema-validator.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
4500F5B31ED46D49005BEC95 /* LHSComparators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4500F5B11ED46D49005BEC95 /* LHSComparators.cpp */; };
451E25291EBF35EE005B9B26 /* LHSTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 451E25271EBF35EE005B9B26 /* LHSTemplate.cpp */; };
453F52AE1EBE1B0200C524A2 /* SourceReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 453F52AC1EBE1B0200C524A2 /* SourceReader.cpp */; };
454874071EBF3E7B0084B711 /* LHSTemplateParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 454874061EBF3E7B0084B711 /* LHSTemplateParser.cpp */; };
Expand All @@ -24,23 +27,29 @@
dstPath = "";
dstSubfolderSpec = 6;
files = (
4500F5B01ED0AABA005BEC95 /* libjson-schema-validator.dylib in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
4500F5A91ECF1F89005BEC95 /* LHSMatching.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LHSMatching.cpp; path = LHS/LHSMatching.cpp; sourceTree = "<group>"; };
4500F5AA1ECF1F89005BEC95 /* LHSMatching.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LHSMatching.hpp; path = LHS/LHSMatching.hpp; sourceTree = "<group>"; };
4500F5AC1ECF23C9005BEC95 /* ASTTraversalState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTTraversalState.cpp; path = LHS/ASTTraversalState.cpp; sourceTree = "<group>"; };
4500F5AD1ECF23C9005BEC95 /* ASTTraversalState.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ASTTraversalState.hpp; path = LHS/ASTTraversalState.hpp; sourceTree = "<group>"; };
4500F5AF1ED0AABA005BEC95 /* libjson-schema-validator.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libjson-schema-validator.dylib"; path = "Framework X/3rd/json-schema-validator/build/libjson-schema-validator.dylib"; sourceTree = "<group>"; };
4500F5B11ED46D49005BEC95 /* LHSComparators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LHSComparators.cpp; path = LHS/LHSComparators.cpp; sourceTree = "<group>"; };
4500F5B21ED46D49005BEC95 /* LHSComparators.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LHSComparators.hpp; path = LHS/LHSComparators.hpp; sourceTree = "<group>"; };
451E25271EBF35EE005B9B26 /* LHSTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LHSTemplate.cpp; path = "Framework X/LHS/LHSTemplate.cpp"; sourceTree = "<group>"; };
451E25281EBF35EE005B9B26 /* LHSTemplate.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LHSTemplate.hpp; path = "Framework X/LHS/LHSTemplate.hpp"; sourceTree = "<group>"; };
453F52A71EBE12EA00C524A2 /* test2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test2.cpp; sourceTree = "<group>"; };
453F52AC1EBE1B0200C524A2 /* SourceReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SourceReader.cpp; path = "Framework X/RHS/SourceReader.cpp"; sourceTree = "<group>"; };
454874061EBF3E7B0084B711 /* LHSTemplateParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LHSTemplateParser.cpp; path = "Framework X/LHS/LHSTemplateParser.cpp"; sourceTree = "<group>"; };
454874081EC13D000084B711 /* Lexer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Lexer.cpp; path = "Framework X/common/Lexer.cpp"; sourceTree = "<group>"; };
456360961E9CF21D00A31D00 /* Framework X */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Framework X"; sourceTree = BUILT_PRODUCTS_DIR; };
456360991E9CF21D00A31D00 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
456360A01E9CF23D00A31D00 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
456360A11E9CF34D00A31D00 /* templ.tmpl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = templ.tmpl; sourceTree = "<group>"; };
456360A31E9CF35000A31D00 /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test.cpp; sourceTree = "<group>"; };
457173161EBA3D35008B3DB2 /* 3rd */ = {isa = PBXFileReference; lastKnownFileType = folder; path = 3rd; sourceTree = "<group>"; };
4571731A1EBA746C008B3DB2 /* config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = config.json; sourceTree = "<group>"; };
4571731F1EBA827C008B3DB2 /* common */ = {isa = PBXFileReference; lastKnownFileType = folder; path = common; sourceTree = "<group>"; };
Expand All @@ -66,6 +75,7 @@
4563608D1E9CF21D00A31D00 = {
isa = PBXGroup;
children = (
4500F5AF1ED0AABA005BEC95 /* libjson-schema-validator.dylib */,
454874081EC13D000084B711 /* Lexer.cpp */,
454874061EBF3E7B0084B711 /* LHSTemplateParser.cpp */,
453F52AC1EBE1B0200C524A2 /* SourceReader.cpp */,
Expand Down Expand Up @@ -97,10 +107,14 @@
457173231EBA82DF008B3DB2 /* RHS */,
456360A01E9CF23D00A31D00 /* CMakeLists.txt */,
456360A11E9CF34D00A31D00 /* templ.tmpl */,
456360A31E9CF35000A31D00 /* test.cpp */,
453F52A71EBE12EA00C524A2 /* test2.cpp */,
457FA77F1EADFDFE001ABD05 /* README.md */,
4571731A1EBA746C008B3DB2 /* config.json */,
4500F5A91ECF1F89005BEC95 /* LHSMatching.cpp */,
4500F5AA1ECF1F89005BEC95 /* LHSMatching.hpp */,
4500F5AC1ECF23C9005BEC95 /* ASTTraversalState.cpp */,
4500F5AD1ECF23C9005BEC95 /* ASTTraversalState.hpp */,
4500F5B11ED46D49005BEC95 /* LHSComparators.cpp */,
4500F5B21ED46D49005BEC95 /* LHSComparators.hpp */,
);
path = "Framework X";
sourceTree = "<group>";
Expand Down Expand Up @@ -164,12 +178,14 @@
files = (
454874091EC13D000084B711 /* Lexer.cpp in Sources */,
454874071EBF3E7B0084B711 /* LHSTemplateParser.cpp in Sources */,
4500F5B31ED46D49005BEC95 /* LHSComparators.cpp in Sources */,
451E25291EBF35EE005B9B26 /* LHSTemplate.cpp in Sources */,
453F52AE1EBE1B0200C524A2 /* SourceReader.cpp in Sources */,
457173321EBA84F4008B3DB2 /* LHSConfiguration.cpp in Sources */,
457173331EBA84F4008B3DB2 /* RHSTemplate.cpp in Sources */,
4571732E1EBA84BD008B3DB2 /* X.cpp in Sources */,
4563609A1E9CF21D00A31D00 /* main.cpp in Sources */,
4500F5AE1ECF23C9005BEC95 /* ASTTraversalState.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -203,7 +219,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
EXCLUDED_SOURCE_FILE_NAMES = test.cpp;
EXCLUDED_SOURCE_FILE_NAMES = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
Expand Down Expand Up @@ -412,7 +428,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
EXCLUDED_SOURCE_FILE_NAMES = test.cpp;
EXCLUDED_SOURCE_FILE_NAMES = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand Down Expand Up @@ -591,6 +607,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
EXCLUDED_SOURCE_FILE_NAMES = "";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Framework\\ X/3rd/json-schema-validator/build",
Expand Down Expand Up @@ -764,6 +781,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
EXCLUDED_SOURCE_FILE_NAMES = "";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Framework\\ X/3rd/json-schema-validator/build",
Expand Down
4 changes: 2 additions & 2 deletions Framework X/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ llvm_config(LLVM_INCLUDE_DIR "--includedir")
llvm_config(LLVM_SYSTEM_LIBS "--system-libs")

add_definitions(${LLVM_CXXFLAGS})
add_definitions(-fno-rtti)
add_definitions(-fno-rtti -std=c++14 -O3)
include_directories(${LLVM_INCLUDE_DIR})
link_directories(${LLVM_LIBDIR} 3rd/json-schema-validator/build)

add_executable(framework-x main.cpp common/Lexer.cpp RHS/SourceReader.cpp common/X.cpp RHS/RHSTemplate.cpp LHS/LHSConfiguration.cpp LHS/LHSTemplateParser.cpp LHS/LHSTemplate.cpp)
add_executable(framework-x main.cpp common/Lexer.cpp RHS/SourceReader.cpp common/X.cpp RHS/RHSTemplate.cpp LHS/LHSConfiguration.cpp LHS/LHSTemplateParser.cpp LHS/LHSTemplate.cpp LHS/ASTTraversalState.cpp LHS/LHSComparators.cpp)

include_directories(SYSTEM 3rd/json 3rd/json-schema-validator/src)

Expand Down
193 changes: 193 additions & 0 deletions Framework X/LHS/ASTTraversalState.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
//
// ASTTraversalState.cpp
// Framework X
//
// Created by Ruben Opdebeeck on 19/05/2017.
// Copyright © 2017 Ruben Opdebeeck. All rights reserved.
//

#include "ASTTraversalState.hpp"

using namespace X;

long ASTNode::nextID = 0;
ASTNodeKind ASTNode::StmtKind = ASTNodeKind::getFromNodeKind<Stmt>();
ASTNodeKind ASTNode::DeclKind = ASTNodeKind::getFromNodeKind<Decl>();
ASTNodeKind ASTNode::DeclStmtKind = ASTNodeKind::getFromNodeKind<DeclStmt>();
ASTNodeKind ASTNode::FunctionDeclKind = ASTNodeKind::getFromNodeKind<FunctionDecl>();
ASTNodeKind ASTNode::VarDeclKind = ASTNodeKind::getFromNodeKind<VarDecl>();
ASTNodeKind ASTNode::FieldDeclKind = ASTNodeKind::getFromNodeKind<FieldDecl>();

vector<ASTNode> &ASTNode::getChildren() {
// If the child list has been instantiated, just return it
if (childrenAdded) return children;

ASTNodeKind nodeKind(node.getNodeKind());

// We still need to instantiate the child list
// Depending on the type of the underlying node, children are accessed in different ways
if (StmtKind.isBaseOf(nodeKind)) {
// For Stmts, in the general case the children are accessed using its children() range.
// However, for DeclStmts, we need to access them by its decls() range.
if (DeclStmtKind.isBaseOf(nodeKind)) {
for (const Decl *D : node.get<DeclStmt>()->decls()) {
children.push_back(ASTNode(DynTypedNode::create(*D)));
}
} else {
for (const Stmt *child : node.get<Stmt>()->children()) {
if (child) children.push_back(ASTNode(DynTypedNode::create(*child)));
else children.push_back(ASTNode());
}
}
} else {
// For Decls, in the general case, children are accessed using the decls() range of DeclContext, if that Decl derives it.
// For FunctionDecls and its derivations, we need to create two children, one for its parameter list (virtual child) and one for its body.
// For VarDecls and its derivations and FieldDecls, the only possible child is a Stmt, namely its initializer.
// For any other Decl that does not derive a DeclContext, there are no children.

// FunctionDecls
if (FunctionDeclKind.isBaseOf(nodeKind)) {
// Parameter list
vector<ASTNode> params;
const FunctionDecl *FD(node.get<FunctionDecl>());
for (ParmVarDecl *P : FD->parameters()) {
params.push_back(ASTNode(DynTypedNode::create(*P)));
}
children.push_back(ASTNode(params)); // Virtual ASTNode

// Body if there is one (declaration with definition)
if (FD->isThisDeclarationADefinition()) {
children.push_back(ASTNode(DynTypedNode::create(*FD->getBody())));
}
}

// VarDecl/FieldDecl/ParmVarDecl
// The only child is the initializer
else if (VarDeclKind.isBaseOf(nodeKind) && node.get<VarDecl>()->hasInit()) { // Also works for ParmVarDecl
children.push_back(ASTNode(DynTypedNode::create(*node.get<VarDecl>()->getInit())));
} else if (FieldDeclKind.isBaseOf(nodeKind) && node.get<FieldDecl>()->hasInClassInitializer()) {
children.push_back(ASTNode(DynTypedNode::create(*node.get<FieldDecl>()->getInClassInitializer())));
}

// DeclContext
else if (llvm::isa<DeclContext>(node.get<Decl>())) {
for (Decl *child : cast<DeclContext>(node.get<Decl>())->decls()) {
children.push_back(ASTNode(DynTypedNode::create(*child)));
}
}

// Anything else does not have children
}

childrenAdded = true;
return children;
}

vector<ASTNode> ASTNode::fromParentAndChild(DynTypedNode &parent, DynTypedNode &child) {
// Create an ASTNode from the parent and get its children
ASTNode parentASTNode(parent);
auto children(parentASTNode.getChildren());

// Find the child we want
auto childIt(children.end());
for (auto it = children.begin(); it != children.end(); it++) {
if (it->getNode() == child) {
childIt = it;
break;
}
}

// Add the relevant children, i.e. the ones starting from the child we want, to a vector
vector<ASTNode> relevantChildren;
vector<ASTNode> results;
for (; childIt < children.end(); childIt++) {
relevantChildren.push_back(*childIt);
results.push_back(ASTNode(relevantChildren)); // Use the vector copy to our advantage
}

// Create a virtual ASTNode and return it
return results;
}

bool ASTTraversalState::isLastChild() {
return currNodeIdx + 1 == parents.top().getChildren().size();
}

bool ASTTraversalState::astProcessed() {
return parents.empty();
}

bool ASTTraversalState::hasChildren() {
return parents.top().getChildren()[currNodeIdx].getChildren().size() != 0;
}

bool ASTTraversalState::childrenAccessed() {
return parents.top().getChildren()[currNodeIdx].areChildrenAccessed();
}

DynTypedNode &ASTTraversalState::getCurrent() {
return parents.top().getChildren()[currNodeIdx].getNode();
}

DynTypedNode &ASTTraversalState::backtrackToParent() {
ASTNode parent(parents.top());
parents.pop();

// Search the parent in its parent, set the new currNodeIdx to its index
// Only if there are parents left
if (!parents.empty()) {
auto siblings(parents.top().getChildren());
for (unsigned i = 0; i < siblings.size(); i++) {
if (siblings[i] == parent) {
currNodeIdx = i;
break;
}
}
}

return parent.getNode();
}

DynTypedNode &ASTTraversalState::nextSibling() {
if (isLastChild()) throw runtime_error("No more siblings");

return parents.top().getChildren()[++currNodeIdx].getNode();
}

DynTypedNode &ASTTraversalState::descendToChild() {
if (!hasChildren()) throw runtime_error("No children");

auto &curr(parents.top().getChildren()[currNodeIdx]);
curr.setChildrenAccessed(true);
parents.push(curr);
currNodeIdx = 0;
return curr.getChildren()[0].getNode();
}

vector<DynTypedNode> PotentialMatch::getMatchRoot() {
vector<DynTypedNode> rootList;
vector<ASTNode> &subtrees(root.getChildren());
for (ASTNode &node : subtrees) {
rootList.push_back(node.getNode());
}
return rootList;
}

void PotentialMatch::instantiateCurrentAsMetavariable(Metavariable &meta) {
metavarInstantiations.insert(pair<Metavariable, ASTNode>(meta, parents.top().getChildren()[currNodeIdx]));
}

void PotentialMatch::extendForMetavariable(Metavariable &meta, vector<PotentialMatch> &potentials) {
auto &siblings(parents.top().getChildren());
vector<ASTNode> instanceNodes;
// The vector passed to the constructor of ASTNode is passed by value, i.e. copied, so we can
// destructively modify it at each step and give a copy to each new potential match that is created
for (unsigned i = currNodeIdx; i < siblings.size(); i++) {
instanceNodes.push_back(siblings[i]);
PotentialMatch newMatch(*this);
ASTNode instance(instanceNodes);
newMatch.metavarInstantiations.insert(pair<Metavariable, ASTNode>(meta, instance));
newMatch.currNodeIdx = i; // Set the current node to the last node in the instantiation
potentials.push_back(newMatch);
}
}
Loading

0 comments on commit 1cb8c61

Please sign in to comment.