diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index 2f52d575..c3833fed 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -40,7 +40,7 @@ public: private: int m_importantValue; char m_importanterValue; - float m_importantestValue; + const float m_importantestValue; }; A globalA(' '); @@ -52,6 +52,13 @@ public: : A('b') { } + + virtual ~B() + { + } + +protected: + virtual float getNumber() = 0; }; class C @@ -61,13 +68,20 @@ public: : m_valuable(0) { globalA.doImportantStuff(); + s_count++; } ~C() { + s_count--; } - void solveAllProblems() + static int getCount() + { + return s_count; + } + + void solveAllProblems() const { A aInstance('a'); aInstance.doImportantStuff(); @@ -75,6 +89,7 @@ public: } private: + static int s_count; int m_valuable; }; diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index bceb96cf..c16782cc 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -71,6 +71,12 @@ add_files( data/access/GraphAccessProxy.cpp data/access/GraphAccessProxy.h + data/graph/filter/GraphFilter.cpp + data/graph/filter/GraphFilter.h + data/graph/filter/GraphFilterConductor.cpp + data/graph/filter/GraphFilterConductor.h + data/graph/filter/GraphFilterImplementations.h + data/graph/token_component/TokenComponent.cpp data/graph/token_component/TokenComponent.h data/graph/token_component/TokenComponentAbstraction.cpp @@ -88,10 +94,14 @@ add_files( data/graph/Edge.cpp data/graph/Edge.h + data/graph/FilterableGraph.cpp + data/graph/FilterableGraph.h data/graph/Graph.cpp data/graph/Graph.h data/graph/Node.cpp data/graph/Node.h + data/graph/SubGraph.cpp + data/graph/SubGraph.h data/graph/Token.cpp data/graph/Token.h @@ -117,6 +127,17 @@ add_files( data/parser/ParseVariable.cpp data/parser/ParseVariable.h + data/query/QueryCommand.cpp + data/query/QueryCommand.h + data/query/QueryNode.cpp + data/query/QueryNode.h + data/query/QueryOperator.cpp + data/query/QueryOperator.h + data/query/QueryToken.cpp + data/query/QueryToken.h + data/query/QueryTree.cpp + data/query/QueryTree.h + data/type/modifier/DataTypeModifier.cpp data/type/modifier/DataTypeModifier.h data/type/modifier/DataTypeModifierArray.cpp diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index d7e901e6..6b9a14c8 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -18,14 +18,13 @@ CodeController::~CodeController() { } -void CodeController::setActiveTokenId(Id id) +void CodeController::setActiveTokenIds(const std::vector& ids) { const uint lineRadius = 2; getView()->clearCodeSnippets(); - std::vector activeTokenIds = m_graphAccess->getActiveTokenIdsForId(id); - std::vector locationIds = m_graphAccess->getLocationIdsForTokenIds(activeTokenIds); + std::vector locationIds = m_graphAccess->getLocationIdsForTokenIds(ids); TokenLocationCollection collection = m_locationAccess->getTokenLocationsForLocationIds(locationIds); collection.forEachTokenLocationFile( @@ -49,7 +48,7 @@ void CodeController::setActiveTokenId(Id id) params.startLineNumber = firstLineNumber; params.locationFile = m_locationAccess->getTokenLocationsForLinesInFile(filePath, firstLineNumber, lastLineNumber); - params.activeTokenIds = activeTokenIds; + params.activeTokenIds = ids; getView()->addCodeSnippet(params); } @@ -59,7 +58,21 @@ void CodeController::setActiveTokenId(Id id) void CodeController::handleMessage(MessageActivateToken* message) { - setActiveTokenId(message->tokenId); + std::vector activeTokenIds = m_graphAccess->getActiveTokenIdsForId(message->tokenId); + setActiveTokenIds(activeTokenIds); +} + +void CodeController::handleMessage(MessageActivateTokens* message) +{ + if (message->tokenIds.size() == 1) + { + std::vector activeTokenIds = m_graphAccess->getActiveTokenIdsForId(message->tokenIds[0]); + setActiveTokenIds(activeTokenIds); + } + else + { + setActiveTokenIds(message->tokenIds); + } } void CodeController::handleMessage(MessageRefresh* message) diff --git a/src/lib/component/controller/CodeController.h b/src/lib/component/controller/CodeController.h index 98fbef60..a5838a95 100644 --- a/src/lib/component/controller/CodeController.h +++ b/src/lib/component/controller/CodeController.h @@ -6,6 +6,7 @@ #include "component/controller/Controller.h" #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateToken.h" +#include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageRefresh.h" #include "utility/messaging/type/MessageShowFile.h" #include "utility/types.h" @@ -24,6 +25,7 @@ struct AnnotatedText class CodeController : public Controller , public MessageListener + , public MessageListener , public MessageListener , public MessageListener { @@ -31,10 +33,11 @@ public: CodeController(GraphAccess* graphAccess, LocationAccess* locationAccess); ~CodeController(); - void setActiveTokenId(Id id); + void setActiveTokenIds(const std::vector& ids); private: virtual void handleMessage(MessageActivateToken* message); + virtual void handleMessage(MessageActivateTokens* message); virtual void handleMessage(MessageRefresh* message); virtual void handleMessage(MessageShowFile* message); diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 062232f3..76a04873 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -22,6 +22,11 @@ void GraphController::handleMessage(MessageActivateToken* message) createDummyGraph(message->tokenId, &GraphLayouter::layoutSimpleRing); } +void GraphController::handleMessage(MessageActivateTokens* message) +{ + createDummyGraph(message->tokenIds[0], &GraphLayouter::layoutSimpleRing); +} + GraphView* GraphController::getView() { return Controller::getView(); diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 97eed694..911879a1 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -8,6 +8,7 @@ #include "component/controller/GraphLayouter.h" #include "utility/messaging/MessageListener.h" #include "utility/messaging/type/MessageActivateToken.h" +#include "utility/messaging/type/MessageActivateTokens.h" struct DummyNode; struct DummyEdge; @@ -17,6 +18,7 @@ class GraphAccess; class GraphController : public Controller , public MessageListener + , public MessageListener { public: GraphController(GraphAccess* graphAccess); @@ -24,6 +26,8 @@ public: private: virtual void handleMessage(MessageActivateToken* message); + virtual void handleMessage(MessageActivateTokens* message); + GraphView* getView(); void createDummyGraph(const Id activeId, const LayoutFunction layoutFunction); diff --git a/src/lib/component/controller/SearchController.cpp b/src/lib/component/controller/SearchController.cpp index db271dca..dfe90018 100644 --- a/src/lib/component/controller/SearchController.cpp +++ b/src/lib/component/controller/SearchController.cpp @@ -2,6 +2,7 @@ #include "component/view/SearchView.h" #include "data/access/GraphAccess.h" +#include "utility/messaging/type/MessageActivateTokens.h" SearchController::SearchController(GraphAccess* graphAccess) : m_graphAccess(graphAccess) @@ -15,6 +16,14 @@ SearchController::~SearchController() void SearchController::search(const std::string& s) { LOG_INFO("searching string: \"" + s + "\""); + + std::vector ids = m_graphAccess->getTokenIdsForQuery(s); + if (ids.size()) + { + MessageActivateTokens(ids).dispatch(); + return; + } + Id nodeId = m_graphAccess->getIdForNodeWithName(s); if (nodeId > 0) { diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index c0bd601c..67699429 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -1,8 +1,10 @@ #include "data/Storage.h" +#include "data/graph/filter/GraphFilterConductor.h" #include "data/graph/token_component/TokenComponentConst.h" #include "data/graph/token_component/TokenComponentDataType.h" #include "data/graph/token_component/TokenComponentStatic.h" +#include "data/graph/SubGraph.h" #include "data/location/TokenLocation.h" #include "data/location/TokenLocationFile.h" #include "data/location/TokenLocationLine.h" @@ -10,6 +12,7 @@ #include "data/parser/ParseLocation.h" #include "data/parser/ParseTypeUsage.h" #include "data/parser/ParseVariable.h" +#include "data/query/QueryTree.h" #include "data/type/DataType.h" #include "utility/logging/logging.h" #include "utility/utilityString.h" @@ -525,6 +528,19 @@ std::vector Storage::getLocationIdsForTokenIds(const std::vector& tokenI return ret; } +std::vector Storage::getTokenIdsForQuery(std::string query) const +{ + QueryTree tree(query); + GraphFilterConductor conductor; + SubGraph outGraph; + + conductor.filter(&tree, &m_graph, &outGraph); + + LOG_INFO_STREAM(<< '\n' << tree << '\n' << outGraph); + + return outGraph.getTokenIds(); +} + TokenLocationCollection Storage::getTokenLocationsForLocationIds(const std::vector& locationIds) const { TokenLocationCollection ret; diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 59bd6ccc..ccfba144 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -84,6 +84,8 @@ public: virtual std::vector getActiveTokenIdsForId(Id tokenId) const; virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const; + virtual std::vector getTokenIdsForQuery(std::string query) const; + // LocationAccess implementation virtual TokenLocationCollection getTokenLocationsForLocationIds(const std::vector& locationIds) const; virtual TokenLocationFile getTokenLocationsForFile(const std::string& filePath) const; diff --git a/src/lib/data/access/GraphAccess.h b/src/lib/data/access/GraphAccess.h index 04f27c01..cea69920 100644 --- a/src/lib/data/access/GraphAccess.h +++ b/src/lib/data/access/GraphAccess.h @@ -33,6 +33,8 @@ public: virtual std::vector getActiveTokenIdsForId(Id tokenId) const = 0; virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const = 0; + + virtual std::vector getTokenIdsForQuery(std::string query) const = 0; }; #endif // GRAPH_ACCESS_H diff --git a/src/lib/data/access/GraphAccessProxy.cpp b/src/lib/data/access/GraphAccessProxy.cpp index e005c634..102ba168 100644 --- a/src/lib/data/access/GraphAccessProxy.cpp +++ b/src/lib/data/access/GraphAccessProxy.cpp @@ -186,3 +186,13 @@ std::vector GraphAccessProxy::getLocationIdsForTokenIds(const std::vector(); } + +std::vector GraphAccessProxy::getTokenIdsForQuery(std::string query) const +{ + if (hasSubject()) + { + return m_subject->getTokenIdsForQuery(query); + } + + return std::vector(); +} diff --git a/src/lib/data/access/GraphAccessProxy.h b/src/lib/data/access/GraphAccessProxy.h index 48a32d53..fe5e20e5 100644 --- a/src/lib/data/access/GraphAccessProxy.h +++ b/src/lib/data/access/GraphAccessProxy.h @@ -33,6 +33,8 @@ public: virtual std::vector getActiveTokenIdsForId(Id tokenId) const; virtual std::vector getLocationIdsForTokenIds(const std::vector& tokenIds) const; + virtual std::vector getTokenIdsForQuery(std::string query) const; + private: GraphAccess* m_subject; }; diff --git a/src/lib/data/graph/FilterableGraph.cpp b/src/lib/data/graph/FilterableGraph.cpp new file mode 100644 index 00000000..326416f7 --- /dev/null +++ b/src/lib/data/graph/FilterableGraph.cpp @@ -0,0 +1,32 @@ +#include "data/graph/FilterableGraph.h" + +#include "data/graph/Edge.h" +#include "data/graph/Node.h" + +FilterableGraph::FilterableGraph() +{ +} + +FilterableGraph::~FilterableGraph() +{ +} + +void FilterableGraph::print(std::ostream& ostream) const +{ + ostream << "Graph:\n"; + ostream << "nodes (" << getNodeCount() << ")\n"; + forEachNode( + [&ostream](Node* n) + { + ostream << *n << '\n'; + } + ); + + ostream << "edges (" << getEdgeCount() << ")\n"; + forEachEdge( + [&ostream](Edge* e) + { + ostream << *e << '\n'; + } + ); +} diff --git a/src/lib/data/graph/FilterableGraph.h b/src/lib/data/graph/FilterableGraph.h new file mode 100644 index 00000000..473a0984 --- /dev/null +++ b/src/lib/data/graph/FilterableGraph.h @@ -0,0 +1,35 @@ +#ifndef FILTERABLE_GRAPH_H +#define FILTERABLE_GRAPH_H + +#include +#include + +class Edge; +class Node; +class Token; + +class FilterableGraph +{ +public: + FilterableGraph(); + virtual ~FilterableGraph(); + + virtual void copy(const FilterableGraph* other) = 0; + virtual void clear() = 0; + + virtual void add(const FilterableGraph* other) = 0; + + virtual void forEachNode(std::function func) const = 0; + virtual void forEachEdge(std::function func) const = 0; + virtual void forEachToken(std::function func) const = 0; + + virtual void addNode(Node* node) = 0; + virtual void addEdge(Edge* edge) = 0; + + virtual size_t getNodeCount() const = 0; + virtual size_t getEdgeCount() const = 0; + + void print(std::ostream& ostream) const; +}; + +#endif // FILTERABLE_GRAPH_H diff --git a/src/lib/data/graph/Graph.cpp b/src/lib/data/graph/Graph.cpp index 70127b21..4aa9bc1f 100644 --- a/src/lib/data/graph/Graph.cpp +++ b/src/lib/data/graph/Graph.cpp @@ -14,6 +14,79 @@ Graph::~Graph() m_nodes.clear(); } +void Graph::copy(const FilterableGraph* other) +{ + clear(); + add(other); +} + +void Graph::clear() +{ + m_edges.clear(); + m_nodes.clear(); +} + +void Graph::add(const FilterableGraph* other) +{ + other->forEachNode(std::bind(&Graph::addNode, this, std::placeholders::_1)); + other->forEachEdge(std::bind(&Graph::addEdge, this, std::placeholders::_1)); +} + +void Graph::forEachNode(std::function func) const +{ + for (const std::pair>& node : m_nodes) + { + func(node.second.get()); + } +} + +void Graph::forEachEdge(std::function func) const +{ + for (const std::pair>& edge : m_edges) + { + func(edge.second.get()); + } +} + +void Graph::forEachToken(std::function func) const +{ + forEachNode(func); + forEachEdge(func); +} + +void Graph::addNode(Node* node) +{ + addNodeAsPlainCopy(node); +} + +void Graph::addEdge(Edge* edge) +{ + if (getNodeById(edge->getFrom()->getId()) && getNodeById(edge->getTo()->getId())) + { + addEdgeAsPlainCopy(edge); + } +} + +size_t Graph::getNodeCount() const +{ + return m_nodes.size(); +} + +size_t Graph::getEdgeCount() const +{ + return m_edges.size(); +} + +const std::map>& Graph::getNodes() const +{ + return m_nodes; +} + +const std::map>& Graph::getEdges() const +{ + return m_edges; +} + Node* Graph::getNode(const std::string& fullName) const { std::deque names = utility::split>(fullName, DELIMITER); @@ -256,44 +329,6 @@ Token* Graph::findToken(std::function func) const return nullptr; } -void Graph::forEachNode(std::function func) const -{ - for (const std::pair>& node : m_nodes) - { - func(node.second.get()); - } -} - -void Graph::forEachEdge(std::function func) const -{ - for (const std::pair>& edge : m_edges) - { - func(edge.second.get()); - } -} - -void Graph::forEachToken(std::function func) const -{ - forEachNode(func); - forEachEdge(func); -} - -void Graph::clear() -{ - m_edges.clear(); - m_nodes.clear(); -} - -const std::map >& Graph::getNodes() const -{ - return m_nodes; -} - -const std::map >& Graph::getEdges() const -{ - return m_edges; -} - Node* Graph::addNodeAsPlainCopy(Node* node) { Node* n = getNodeById(node->getId()); @@ -410,22 +445,6 @@ void Graph::removeEdgeInternal(Edge* edge) std::ostream& operator<<(std::ostream& ostream, const Graph& graph) { - ostream << "Graph:\n"; - ostream << "nodes (" << graph.getNodes().size() << ")\n"; - graph.forEachNode( - [&ostream](Node* n) - { - ostream << *n << '\n'; - } - ); - - ostream << "edges (" << graph.getEdges().size() << ")\n"; - graph.forEachEdge( - [&ostream](Edge* e) - { - ostream << *e << '\n'; - } - ); - + graph.print(ostream); return ostream; } diff --git a/src/lib/data/graph/Graph.h b/src/lib/data/graph/Graph.h index 2a687e91..79176e8c 100644 --- a/src/lib/data/graph/Graph.h +++ b/src/lib/data/graph/Graph.h @@ -3,18 +3,38 @@ #include #include -#include #include #include "data/graph/Edge.h" +#include "data/graph/FilterableGraph.h" #include "data/graph/Node.h" class Graph + : public FilterableGraph { public: Graph(); virtual ~Graph(); + // FilterableGraph implementation + virtual void copy(const FilterableGraph* other); + virtual void clear(); + + virtual void add(const FilterableGraph* other); + + virtual void forEachNode(std::function func) const; + virtual void forEachEdge(std::function func) const; + virtual void forEachToken(std::function func) const; + + virtual void addNode(Node* node); + virtual void addEdge(Edge* edge); + + virtual size_t getNodeCount() const; + virtual size_t getEdgeCount() const; + + const std::map>& getNodes() const; + const std::map>& getEdges() const; + Node* getNode(const std::string& fullName) const; Edge* getEdge(Edge::EdgeType type, Node* from, Node* to) const; @@ -39,19 +59,9 @@ public: Edge* findEdge(std::function func) const; Token* findToken(std::function func) const; - void forEachNode(std::function func) const; - void forEachEdge(std::function func) const; - void forEachToken(std::function func) const; - Node* addNodeAsPlainCopy(Node* node); Edge* addEdgeAsPlainCopy(Edge* edge); - void clear(); - -protected: - const std::map>& getNodes() const; - const std::map>& getEdges() const; - private: static const std::string DELIMITER; @@ -65,8 +75,6 @@ private: std::map> m_nodes; std::map> m_edges; - - friend std::ostream& operator<<(std::ostream& ostream, const Graph& graph); }; std::ostream& operator<<(std::ostream& ostream, const Graph& graph); diff --git a/src/lib/data/graph/SubGraph.cpp b/src/lib/data/graph/SubGraph.cpp new file mode 100644 index 00000000..c7ee0104 --- /dev/null +++ b/src/lib/data/graph/SubGraph.cpp @@ -0,0 +1,106 @@ +#include "data/graph/SubGraph.h" + +#include "data/graph/Edge.h" +#include "data/graph/Node.h" + +SubGraph::SubGraph() +{ +} + +SubGraph::~SubGraph() +{ +} + +void SubGraph::copy(const FilterableGraph* other) +{ + clear(); + add(other); +} + +void SubGraph::clear() +{ + m_edges.clear(); + m_nodes.clear(); +} + +void SubGraph::add(const FilterableGraph* other) +{ + other->forEachNode(std::bind(&SubGraph::addNode, this, std::placeholders::_1)); + other->forEachEdge(std::bind(&SubGraph::addEdge, this, std::placeholders::_1)); +} + +void SubGraph::forEachNode(std::function func) const +{ + for (const std::pair& node : m_nodes) + { + func(node.second); + } +} + +void SubGraph::forEachEdge(std::function func) const +{ + for (const std::pair& edge : m_edges) + { + func(edge.second); + } +} + +void SubGraph::forEachToken(std::function func) const +{ + forEachNode(func); + forEachEdge(func); +} + +void SubGraph::addNode(Node* node) +{ + m_nodes.emplace(node->getId(), node); +} + +void SubGraph::addEdge(Edge* edge) +{ + m_edges.emplace(edge->getId(), edge); +} + +size_t SubGraph::getNodeCount() const +{ + return m_nodes.size(); +} + +size_t SubGraph::getEdgeCount() const +{ + return m_edges.size(); +} + +std::vector SubGraph::getTokenIds() const +{ + std::vector ids; + for (const std::pair& node : m_nodes) + { + ids.push_back(node.first); + } + + for (const std::pair& edge : m_edges) + { + ids.push_back(edge.first); + } + return ids; +} + +void SubGraph::subtract(const SubGraph& other) +{ + for (const std::pair& node : other.m_nodes) + { + m_nodes.erase(node.first); + } + + for (const std::pair& edge : other.m_edges) + { + m_edges.erase(edge.first); + } +} + +std::ostream& operator<<(std::ostream& ostream, const SubGraph& graph) +{ + graph.print(ostream); + return ostream; +} diff --git a/src/lib/data/graph/SubGraph.h b/src/lib/data/graph/SubGraph.h new file mode 100644 index 00000000..8358f9c2 --- /dev/null +++ b/src/lib/data/graph/SubGraph.h @@ -0,0 +1,49 @@ +#ifndef SUB_GRAPH_H +#define SUB_GRAPH_H + +#include +#include +#include + +#include "data/graph/FilterableGraph.h" +#include "utility/types.h" + +class Edge; +class Node; +class Token; + +class SubGraph + : public FilterableGraph +{ +public: + SubGraph(); + virtual ~SubGraph(); + + // FilterableGraph implementation + virtual void copy(const FilterableGraph* other); + virtual void clear(); + + virtual void add(const FilterableGraph* other); + + virtual void forEachNode(std::function func) const; + virtual void forEachEdge(std::function func) const; + virtual void forEachToken(std::function func) const; + + virtual void addNode(Node* node); + virtual void addEdge(Edge* edge); + + virtual size_t getNodeCount() const; + virtual size_t getEdgeCount() const; + + std::vector getTokenIds() const; + + void subtract(const SubGraph& other); + +private: + std::map m_nodes; + std::map m_edges; +}; + +std::ostream& operator<<(std::ostream& ostream, const SubGraph& graph); + +#endif // SUB_GRAPH_H diff --git a/src/lib/data/graph/filter/GraphFilter.cpp b/src/lib/data/graph/filter/GraphFilter.cpp new file mode 100644 index 00000000..41187d42 --- /dev/null +++ b/src/lib/data/graph/filter/GraphFilter.cpp @@ -0,0 +1,66 @@ +#include "data/graph/filter/GraphFilter.h" + +#include "data/graph/Edge.h" +#include "data/graph/FilterableGraph.h" +#include "utility/logging/logging.h" + +GraphFilter::GraphFilter() + : m_outGraph(nullptr) +{ +} + +GraphFilter::~GraphFilter() +{ +} + +void GraphFilter::apply(const FilterableGraph* in, FilterableGraph* out) +{ + if (!in || !out) + { + LOG_ERROR("GraphFilter not called with correct pointers."); + return; + } + else if (in == out) + { + LOG_ERROR("In and out graphs are the same."); + return; + } + + m_outGraph = out; + + in->forEachNode( + [this](Node* node) + { + visitNode(node); + } + ); + + // in->forEachEdge( + // [this](Edge* edge) + // { + // visitEdge(edge); + // } + // ); + + m_outGraph = nullptr; +} + +void GraphFilter::visitNode(Node* node) +{ +} + +// void GraphFilter::visitEdge(Edge* edge) +// { +// } + +void GraphFilter::addNode(Node* node) +{ + m_outGraph->addNode(node); +} + +void GraphFilter::addEdge(Edge* edge) +{ + m_outGraph->addNode(edge->getFrom()); + m_outGraph->addNode(edge->getTo()); + m_outGraph->addEdge(edge); +} diff --git a/src/lib/data/graph/filter/GraphFilter.h b/src/lib/data/graph/filter/GraphFilter.h new file mode 100644 index 00000000..b0c31072 --- /dev/null +++ b/src/lib/data/graph/filter/GraphFilter.h @@ -0,0 +1,27 @@ +#ifndef GRAPH_FILTER_H +#define GRAPH_FILTER_H + +class Edge; +class FilterableGraph; +class Node; + +class GraphFilter +{ +public: + GraphFilter(); + virtual ~GraphFilter(); + + void apply(const FilterableGraph* in, FilterableGraph* out); + +protected: + virtual void visitNode(Node* node); + // virtual void visitEdge(Edge* edge); + + void addNode(Node* node); + void addEdge(Edge* edge); + +private: + FilterableGraph* m_outGraph; +}; + +#endif // GRAPH_FILTER_H diff --git a/src/lib/data/graph/filter/GraphFilterConductor.cpp b/src/lib/data/graph/filter/GraphFilterConductor.cpp new file mode 100644 index 00000000..e4fe7653 --- /dev/null +++ b/src/lib/data/graph/filter/GraphFilterConductor.cpp @@ -0,0 +1,178 @@ +#include "data/graph/filter/GraphFilterConductor.h" + +#include "data/graph/filter/GraphFilter.h" +#include "data/graph/filter/GraphFilterImplementations.h" +#include "data/graph/SubGraph.h" +#include "data/query/QueryCommand.h" +#include "data/query/QueryNode.h" +#include "data/query/QueryOperator.h" +#include "data/query/QueryToken.h" +#include "data/query/QueryTree.h" +#include "utility/logging/logging.h" + +GraphFilterConductor::GraphFilterConductor() +{ +} + +GraphFilterConductor::~GraphFilterConductor() +{ +} + +void GraphFilterConductor::filter(const QueryTree* tree, const FilterableGraph* in, FilterableGraph* out) const +{ + if (tree->isValid()) + { + filterRecursively(tree->getRoot().get(), in, out); + } +} + +void GraphFilterConductor::filterRecursively(const QueryNode* node, const FilterableGraph* in, FilterableGraph* out) const +{ + if (node->isOperator()) + { + filterOperatorNode(dynamic_cast(node), in, out); + } + else if (node->isCommand()) + { + filterCommandNode(dynamic_cast(node), in, out); + } + else if (node->isToken()) + { + filterTokenNode(dynamic_cast(node), in, out); + } +} + +void GraphFilterConductor::filterOperatorNode(const QueryOperator* node, const FilterableGraph* in, FilterableGraph* out) const +{ + switch (node->getType()) + { + case QueryOperator::OPERATOR_NOT: + { + SubGraph sub, sub2; + filterRecursively(node->getRight().get(), in, &sub); + + sub2.copy(in); + sub2.subtract(sub); + out->add(&sub2); + } + break; + + case QueryOperator::OPERATOR_SUB: + case QueryOperator::OPERATOR_AND: + { + SubGraph sub; + filterRecursively(node->getLeft().get(), in, &sub); + filterRecursively(node->getRight().get(), &sub, out); + } + break; + + case QueryOperator::OPERATOR_HAS: + { + SubGraph sub, sub2; + filterRecursively(node->getLeft().get(), in, &sub); + GraphFilterCommandMember().apply(&sub, &sub2); + filterRecursively(node->getRight().get(), &sub2, out); + } + break; + + case QueryOperator::OPERATOR_OR: + filterRecursively(node->getLeft().get(), in, out); + filterRecursively(node->getRight().get(), in, out); + break; + + default: + break; + } +} + +void GraphFilterConductor::filterCommandNode(const QueryCommand* node, const FilterableGraph* in, FilterableGraph* out) const +{ + switch (node->getType()) + { + case QueryCommand::COMMAND_MEMBER: + GraphFilterCommandMember().apply(in, out); + break; + case QueryCommand::COMMAND_PARENT: + GraphFilterCommandParent().apply(in, out); + break; + case QueryCommand::COMMAND_FUNCTION: + GraphFilterCommandNodeType(Node::NODE_FUNCTION).apply(in, out); + break; + case QueryCommand::COMMAND_GLOBAL_VARIABLE: + GraphFilterCommandNodeType(Node::NODE_GLOBAL_VARIABLE).apply(in, out); + break; + case QueryCommand::COMMAND_CLASS: + GraphFilterCommandNodeType(Node::NODE_CLASS).apply(in, out); + break; + case QueryCommand::COMMAND_METHOD: + GraphFilterCommandNodeType(Node::NODE_METHOD).apply(in, out); + break; + case QueryCommand::COMMAND_FIELD: + GraphFilterCommandNodeType(Node::NODE_FIELD).apply(in, out); + break; + case QueryCommand::COMMAND_NAMESPACE: + GraphFilterCommandNodeType(Node::NODE_NAMESPACE).apply(in, out); + break; + case QueryCommand::COMMAND_STRUCT: + GraphFilterCommandNodeType(Node::NODE_STRUCT).apply(in, out); + break; + case QueryCommand::COMMAND_ENUM: + GraphFilterCommandNodeType(Node::NODE_ENUM).apply(in, out); + break; + case QueryCommand::COMMAND_TYPEDEF: + GraphFilterCommandNodeType(Node::NODE_TYPEDEF).apply(in, out); + break; + + case QueryCommand::COMMAND_CONST: + GraphFilterCommandConst().apply(in, out); + break; + case QueryCommand::COMMAND_STATIC: + GraphFilterCommandStatic().apply(in, out); + break; + + case QueryCommand::COMMAND_VIRTUAL: + GraphFilterCommandAbstractionType(TokenComponentAbstraction::ABSTRACTION_VIRTUAL).apply(in, out); + break; + case QueryCommand::COMMAND_PURE_VIRTUAL: + GraphFilterCommandAbstractionType(TokenComponentAbstraction::ABSTRACTION_PURE_VIRTUAL).apply(in, out); + break; + + case QueryCommand::COMMAND_PUBLIC: + GraphFilterCommandAccessType(TokenComponentAccess::ACCESS_PUBLIC).apply(in, out); + break; + case QueryCommand::COMMAND_PROTECTED: + GraphFilterCommandAccessType(TokenComponentAccess::ACCESS_PROTECTED).apply(in, out); + break; + case QueryCommand::COMMAND_PRIVATE: + GraphFilterCommandAccessType(TokenComponentAccess::ACCESS_PRIVATE).apply(in, out); + break; + + case QueryCommand::COMMAND_CALLER: + GraphFilterCommandCall(true).apply(in, out); + break; + case QueryCommand::COMMAND_CALLEE: + GraphFilterCommandCall(false).apply(in, out); + break; + + case QueryCommand::COMMAND_USAGE: + GraphFilterCommandUsage().apply(in, out); + break; + + case QueryCommand::COMMAND_SUPER_CLASS: + GraphFilterCommandInheritance(true).apply(in, out); + break; + case QueryCommand::COMMAND_SUB_CLASS: + GraphFilterCommandInheritance(false).apply(in, out); + break; + + default: + LOG_ERROR_STREAM(<< "QueryCommand not supported: " << node->getType()); + GraphFilter().apply(in, out); + break; + } +} + +void GraphFilterConductor::filterTokenNode(const QueryToken* node, const FilterableGraph* in, FilterableGraph* out) const +{ + GraphFilterToken(node->getName()).apply(in, out); +} diff --git a/src/lib/data/graph/filter/GraphFilterConductor.h b/src/lib/data/graph/filter/GraphFilterConductor.h new file mode 100644 index 00000000..ee84285e --- /dev/null +++ b/src/lib/data/graph/filter/GraphFilterConductor.h @@ -0,0 +1,26 @@ +#ifndef GRAPH_FILTER_CONDUCTOR_H +#define GRAPH_FILTER_CONDUCTOR_H + +class FilterableGraph; +class QueryCommand; +class QueryNode; +class QueryOperator; +class QueryToken; +class QueryTree; + +class GraphFilterConductor +{ +public: + GraphFilterConductor(); + ~GraphFilterConductor(); + + void filter(const QueryTree* tree, const FilterableGraph* in, FilterableGraph* out) const; + +private: + void filterRecursively(const QueryNode* node, const FilterableGraph* in, FilterableGraph* out) const; + void filterOperatorNode(const QueryOperator* node, const FilterableGraph* in, FilterableGraph* out) const; + void filterCommandNode(const QueryCommand* node, const FilterableGraph* in, FilterableGraph* out) const; + void filterTokenNode(const QueryToken* node, const FilterableGraph* in, FilterableGraph* out) const; +}; + +#endif // GRAPH_FILTER_CONDUCTOR_H diff --git a/src/lib/data/graph/filter/GraphFilterImplementations.h b/src/lib/data/graph/filter/GraphFilterImplementations.h new file mode 100644 index 00000000..8011fed3 --- /dev/null +++ b/src/lib/data/graph/filter/GraphFilterImplementations.h @@ -0,0 +1,280 @@ +#ifndef GRAPH_FILTER_IMPLEMENTATIONS_H +#define GRAPH_FILTER_IMPLEMENTATIONS_H + +#include "data/graph/Edge.h" +#include "data/graph/filter/GraphFilter.h" +#include "data/graph/Node.h" +#include "data/graph/token_component/TokenComponentAbstraction.h" +#include "data/graph/token_component/TokenComponentAccess.h" +#include "data/graph/token_component/TokenComponentConst.h" +#include "data/graph/token_component/TokenComponentDataType.h" +#include "data/graph/token_component/TokenComponentStatic.h" + +/* + * empty GraphFilterImplementation for copy-pasting + * + +class GraphFilter: public GraphFilter +{ +protected: + virtual void visitNode(Node* node) + { + } +}; +*/ + +class GraphFilterCommandMember + : public GraphFilter +{ +protected: + virtual void visitNode(Node* node) + { + node->forEachChildNode( + [this](Node* n) + { + addNode(n); + } + ); + } +}; + +class GraphFilterCommandParent + : public GraphFilter +{ +protected: + virtual void visitNode(Node* node) + { + Node* parent = node->getParentNode(); + if (parent) + { + addNode(parent); + } + } +}; + +class GraphFilterCommandNodeType + : public GraphFilter +{ +public: + GraphFilterCommandNodeType(Node::NodeType type) + : m_type(type) + { + } + +protected: + virtual void visitNode(Node* node) + { + if (node->getType() == m_type) + { + addNode(node); + } + } + +private: + const Node::NodeType m_type; +}; + +class GraphFilterCommandConst + : public GraphFilter +{ +protected: + virtual void visitNode(Node* node) + { + if (node->getType() == Node::NODE_METHOD && node->getComponent()) + { + addNode(node); + } + + Edge* edge = node->findEdgeOfType(Edge::EDGE_TYPE_OF); + if (!edge) + { + return; + } + + TokenComponentDataType* type = edge->getComponent(); + if (type && type->isConstQualified()) + { + addNode(node); + } + } +}; + +class GraphFilterCommandStatic + : public GraphFilter +{ +protected: + virtual void visitNode(Node* node) + { + if (node->getComponent()) + { + addNode(node); + } + } +}; + +class GraphFilterCommandAccessType + : public GraphFilter +{ +public: + GraphFilterCommandAccessType(TokenComponentAccess::AccessType type) + : m_type(type) + { + } + +protected: + virtual void visitNode(Node* node) + { + Edge* edge = node->getMemberEdge(); + if (!edge) + { + return; + } + + TokenComponentAccess* access = edge->getComponent(); + if (access && access->getAccess() == m_type) + { + addNode(edge->getTo()); + } + } + +private: + const TokenComponentAccess::AccessType m_type; +}; + +class GraphFilterCommandAbstractionType + : public GraphFilter +{ +public: + GraphFilterCommandAbstractionType(TokenComponentAbstraction::AbstractionType type) + : m_type(type) + { + } + +protected: + virtual void visitNode(Node* node) + { + TokenComponentAbstraction* abstraction = node->getComponent(); + if (abstraction && abstraction->getAbstraction() == m_type) + { + addNode(node); + } + } + +private: + const TokenComponentAbstraction::AbstractionType m_type; +}; + +class GraphFilterCommandCall + : public GraphFilter +{ +public: + GraphFilterCommandCall(bool callers) + : m_callers(callers) + { + } + +protected: + virtual void visitNode(Node* node) + { + node->forEachEdgeOfType(Edge::EDGE_CALL, + [this, node](Edge* edge) + { + Node* from = edge->getFrom(); + Node* to = edge->getTo(); + + if (m_callers && node == to) + { + addNode(from); + } + else if (!m_callers && node == from) + { + addNode(to); + } + } + ); + } + +private: + const bool m_callers; +}; + +class GraphFilterCommandUsage + : public GraphFilter +{ +protected: + virtual void visitNode(Node* node) + { + Edge::EdgeTypeMask mask; + mask = Edge::EDGE_TYPE_OF | Edge::EDGE_RETURN_TYPE_OF | Edge::EDGE_PARAMETER_TYPE_OF; + mask = Edge::EDGE_TYPE_USAGE | Edge::EDGE_USAGE | Edge::EDGE_TYPEDEF_OF | mask; + + node->forEachEdge( + [this, node, mask](Edge* edge) + { + if (node == edge->getTo() && edge->isType(mask)) + { + addNode(edge->getFrom()); + } + } + ); + } +}; + +class GraphFilterCommandInheritance + : public GraphFilter +{ +public: + GraphFilterCommandInheritance(bool super) + : m_super(super) + { + } + +protected: + virtual void visitNode(Node* node) + { + node->forEachEdgeOfType(Edge::EDGE_INHERITANCE, + [this, node](Edge* edge) + { + Node* from = edge->getFrom(); + Node* to = edge->getTo(); + + if (m_super && node == from) + { + addNode(to); + } + else if (!m_super && node == to) + { + addNode(from); + } + } + ); + } + +private: + const bool m_super; +}; + + +class GraphFilterToken + : public GraphFilter +{ +public: + GraphFilterToken(const std::string& name) + : m_name(name) + { + } + +protected: + virtual void visitNode(Node* node) + { + if (node->getName() == m_name) + { + addNode(node); + } + } + +private: + const std::string& m_name; +}; + +#endif // GRAPH_FILTER_IMPLEMENTATIONS_H diff --git a/src/lib/data/graph/token_component/TokenComponentDataType.cpp b/src/lib/data/graph/token_component/TokenComponentDataType.cpp index 7800dc99..addfc457 100644 --- a/src/lib/data/graph/token_component/TokenComponentDataType.cpp +++ b/src/lib/data/graph/token_component/TokenComponentDataType.cpp @@ -28,3 +28,8 @@ std::string TokenComponentDataType::getQualifiedTypeName(const std::string& type { return m_modifierStack.applyTo(m_qualifierList.applyTo(typeName)); } + +bool TokenComponentDataType::isConstQualified() const +{ + return m_qualifierList.hasQualifier(DataTypeQualifierList::QUALIFIER_CONST); +} diff --git a/src/lib/data/graph/token_component/TokenComponentDataType.h b/src/lib/data/graph/token_component/TokenComponentDataType.h index 46c46e36..fc142714 100644 --- a/src/lib/data/graph/token_component/TokenComponentDataType.h +++ b/src/lib/data/graph/token_component/TokenComponentDataType.h @@ -19,6 +19,8 @@ public: DataType getDataType(const std::string& typeName) const; std::string getQualifiedTypeName(const std::string& typeName) const; + bool isConstQualified() const; + private: const DataTypeQualifierList m_qualifierList; const DataTypeModifierStack m_modifierStack; diff --git a/src/lib/data/query/QueryCommand.cpp b/src/lib/data/query/QueryCommand.cpp new file mode 100644 index 00000000..b7a530ad --- /dev/null +++ b/src/lib/data/query/QueryCommand.cpp @@ -0,0 +1,101 @@ +#include "data/query/QueryCommand.h" + +QueryCommand::QueryCommand(const std::string& name) + : m_type(COMMAND_INVALID) + , m_name(name) +{ + std::map commandMap = getCommandTypeMap(); + std::map::iterator it = commandMap.find(name); + + if (it != commandMap.end()) + { + m_type = it->second; + } +} + +QueryCommand::~QueryCommand() +{ +} + +bool QueryCommand::isCommand() const +{ + return true; +} + +bool QueryCommand::isOperator() const +{ + return false; +} + +bool QueryCommand::isToken() const +{ + return false; +} + +bool QueryCommand::isComplete() const +{ + return m_type != COMMAND_INVALID; +} + +void QueryCommand::print(std::ostream& ostream) const +{ + ostream << m_name; + + if (!isComplete()) + { + ostream << " INVALID"; + } +} + +QueryCommand::CommandType QueryCommand::getType() const +{ + return m_type; +} + +std::map QueryCommand::getCommandTypeMap() +{ + static std::map commandMap; + + if (commandMap.size()) + { + return commandMap; + } + + commandMap.emplace("member", COMMAND_MEMBER); + commandMap.emplace("child", COMMAND_MEMBER); + + commandMap.emplace("parent", COMMAND_PARENT); + + commandMap.emplace("function", COMMAND_FUNCTION); + commandMap.emplace("variable", COMMAND_GLOBAL_VARIABLE); + commandMap.emplace("global", COMMAND_GLOBAL_VARIABLE); + commandMap.emplace("class", COMMAND_CLASS); + commandMap.emplace("method", COMMAND_METHOD); + commandMap.emplace("field", COMMAND_FIELD); + commandMap.emplace("namespace", COMMAND_NAMESPACE); + commandMap.emplace("struct", COMMAND_STRUCT); + commandMap.emplace("enum", COMMAND_ENUM); + commandMap.emplace("typedef", COMMAND_TYPEDEF); + + commandMap.emplace("const", COMMAND_CONST); + commandMap.emplace("static", COMMAND_STATIC); + commandMap.emplace("virtual", COMMAND_VIRTUAL); + commandMap.emplace("abstract", COMMAND_PURE_VIRTUAL); + commandMap.emplace("pure-virtual", COMMAND_PURE_VIRTUAL); + + commandMap.emplace("public", COMMAND_PUBLIC); + commandMap.emplace("protected", COMMAND_PROTECTED); + commandMap.emplace("private", COMMAND_PRIVATE); + + commandMap.emplace("caller", COMMAND_CALLER); + commandMap.emplace("callee", COMMAND_CALLEE); + + commandMap.emplace("usage", COMMAND_USAGE); + + commandMap.emplace("base", COMMAND_SUPER_CLASS); + commandMap.emplace("super", COMMAND_SUPER_CLASS); + commandMap.emplace("derived", COMMAND_SUB_CLASS); + commandMap.emplace("subclass", COMMAND_SUB_CLASS); + + return commandMap; +} diff --git a/src/lib/data/query/QueryCommand.h b/src/lib/data/query/QueryCommand.h new file mode 100644 index 00000000..6e069d6a --- /dev/null +++ b/src/lib/data/query/QueryCommand.h @@ -0,0 +1,67 @@ +#ifndef QUERY_COMMAND_H +#define QUERY_COMMAND_H + +#include +#include + +#include "data/query/QueryNode.h" + +class QueryCommand + : public QueryNode +{ +public: + enum CommandType + { + COMMAND_INVALID, + + COMMAND_MEMBER, + COMMAND_PARENT, + COMMAND_FUNCTION, + COMMAND_GLOBAL_VARIABLE, + COMMAND_CLASS, + COMMAND_METHOD, + COMMAND_FIELD, + COMMAND_NAMESPACE, + COMMAND_STRUCT, + COMMAND_ENUM, + COMMAND_TYPEDEF, + + COMMAND_CONST, + COMMAND_STATIC, + COMMAND_VIRTUAL, + COMMAND_PURE_VIRTUAL, + + COMMAND_PUBLIC, + COMMAND_PROTECTED, + COMMAND_PRIVATE, + + COMMAND_CALLER, + COMMAND_CALLEE, + + COMMAND_USAGE, + + COMMAND_SUPER_CLASS, + COMMAND_SUB_CLASS + }; + + QueryCommand(const std::string& name); + ~QueryCommand(); + + virtual bool isCommand() const; + virtual bool isOperator() const; + virtual bool isToken() const; + + virtual bool isComplete() const; + + virtual void print(std::ostream& ostream) const; + + CommandType getType() const; + +private: + static std::map getCommandTypeMap(); + + CommandType m_type; + const std::string m_name; +}; + +#endif // QUERY_COMMAND_H diff --git a/src/lib/data/query/QueryNode.cpp b/src/lib/data/query/QueryNode.cpp new file mode 100644 index 00000000..9546de01 --- /dev/null +++ b/src/lib/data/query/QueryNode.cpp @@ -0,0 +1,42 @@ +#include "data/query/QueryNode.h" + +QueryNode::QueryNode() + : m_isGroup(false) +{ +} + +QueryNode::~QueryNode() +{ +} + +void QueryNode::print(std::ostream& ostream, int n) const +{ + for (int i = 0; i < n; i++) + { + ostream << '\t'; + } + + if (isGroup()) + { + ostream << '('; + } + + print(ostream); + + if (isGroup()) + { + ostream << ')'; + } + + ostream << '\n'; +} + +bool QueryNode::isGroup() const +{ + return m_isGroup; +} + +void QueryNode::setIsGroup(bool isGroup) +{ + m_isGroup = isGroup; +} diff --git a/src/lib/data/query/QueryNode.h b/src/lib/data/query/QueryNode.h new file mode 100644 index 00000000..c0344039 --- /dev/null +++ b/src/lib/data/query/QueryNode.h @@ -0,0 +1,28 @@ +#ifndef QUERY_NODE_H +#define QUERY_NODE_H + +#include + +class QueryNode +{ +public: + QueryNode(); + virtual ~QueryNode(); + + virtual bool isCommand() const = 0; + virtual bool isOperator() const = 0; + virtual bool isToken() const = 0; + + virtual bool isComplete() const = 0; + + virtual void print(std::ostream& ostream) const = 0; + virtual void print(std::ostream& ostream, int n) const; + + bool isGroup() const; + void setIsGroup(bool isGroup); + +private: + bool m_isGroup; +}; + +#endif // QUERY_NODE_H diff --git a/src/lib/data/query/QueryOperator.cpp b/src/lib/data/query/QueryOperator.cpp new file mode 100644 index 00000000..67e74cae --- /dev/null +++ b/src/lib/data/query/QueryOperator.cpp @@ -0,0 +1,135 @@ +#include "data/query/QueryOperator.h" + +const std::map& QueryOperator::getOperatorTypeMap() +{ + static std::map operatorMap; + + if (operatorMap.size()) + { + return operatorMap; + } + + operatorMap.emplace(' ', OPERATOR_NONE); + + operatorMap.emplace('!', OPERATOR_NOT); + operatorMap.emplace('.', OPERATOR_SUB); + operatorMap.emplace(':', OPERATOR_HAS); + operatorMap.emplace('&', OPERATOR_AND); + operatorMap.emplace('|', OPERATOR_OR); + + operatorMap.emplace('"', OPERATOR_NAME); + operatorMap.emplace('(', OPERATOR_GROUP_OPEN); + operatorMap.emplace(')', OPERATOR_GROUP_CLOSE); + + return operatorMap; +} + +QueryOperator::OperatorType QueryOperator::getOperatorType(char c) +{ + const std::map& operatorMap = getOperatorTypeMap(); + std::map::const_iterator it = operatorMap.find(c); + + if (it != operatorMap.end()) + { + return it->second; + } + + return OPERATOR_NONE; +} + +char QueryOperator::getOperator(OperatorType t) +{ + for (const std::pair& p : getOperatorTypeMap()) + { + if (p.second == t) + { + return p.first; + } + } + + return '\0'; +} + +QueryOperator::QueryOperator(OperatorType type) + : m_type(type) +{ +} + +QueryOperator::~QueryOperator() +{ +} + +bool QueryOperator::isCommand() const +{ + return false; +} + +bool QueryOperator::isOperator() const +{ + return true; +} + +bool QueryOperator::isToken() const +{ + return false; +} + +bool QueryOperator::isComplete() const +{ + if (m_type == OPERATOR_NOT) + { + return bool(getRight()); + } + + return getLeft() && getRight(); +} + +void QueryOperator::print(std::ostream& ostream) const +{ + ostream << m_type; +} + +void QueryOperator::print(std::ostream& ostream, int n) const +{ + if (m_left) + { + m_left->print(ostream, n + 1); + } + + QueryNode::print(ostream, n); + + if (m_right) + { + m_right->print(ostream, n + 1); + } +} + +std::shared_ptr QueryOperator::getLeft() const +{ + return m_left; +} + +void QueryOperator::setLeft(std::shared_ptr node) +{ + m_left = node; +} + +std::shared_ptr QueryOperator::getRight() const +{ + return m_right; +} + +void QueryOperator::setRight(std::shared_ptr node) +{ + m_right = node; +} + +QueryOperator::OperatorType QueryOperator::getType() const +{ + return m_type; +} + +bool QueryOperator::lowerPrecedence(const QueryOperator& other) +{ + return m_type < other.m_type; +} diff --git a/src/lib/data/query/QueryOperator.h b/src/lib/data/query/QueryOperator.h new file mode 100644 index 00000000..506971d0 --- /dev/null +++ b/src/lib/data/query/QueryOperator.h @@ -0,0 +1,61 @@ +#ifndef QUERY_OPERATOR_H +#define QUERY_OPERATOR_H + +#include +#include + +#include "data/query/QueryNode.h" + +class QueryOperator + : public QueryNode +{ +public: + enum OperatorType + { + OPERATOR_NONE, + + OPERATOR_NOT, + OPERATOR_SUB, + OPERATOR_HAS, + OPERATOR_AND, + OPERATOR_OR, + + OPERATOR_NAME, + OPERATOR_GROUP_OPEN, + OPERATOR_GROUP_CLOSE + }; + + static const std::map& getOperatorTypeMap(); + static OperatorType getOperatorType(char c); + static char getOperator(OperatorType t); + + QueryOperator(OperatorType type); + ~QueryOperator(); + + virtual bool isCommand() const; + virtual bool isOperator() const; + virtual bool isToken() const; + + virtual bool isComplete() const; + + virtual void print(std::ostream& ostream) const; + virtual void print(std::ostream& ostream, int n) const; + + std::shared_ptr getLeft() const; + void setLeft(std::shared_ptr node); + + std::shared_ptr getRight() const; + void setRight(std::shared_ptr node); + + OperatorType getType() const; + + bool lowerPrecedence(const QueryOperator& other); + +private: + std::shared_ptr m_left; + std::shared_ptr m_right; + + const OperatorType m_type; +}; + +#endif // QUERY_OPERATOR_H diff --git a/src/lib/data/query/QueryToken.cpp b/src/lib/data/query/QueryToken.cpp new file mode 100644 index 00000000..95a7f35e --- /dev/null +++ b/src/lib/data/query/QueryToken.cpp @@ -0,0 +1,40 @@ +#include "data/query/QueryToken.h" + +QueryToken::QueryToken(const std::string& name) + : m_name(name) +{ +} + +QueryToken::~QueryToken() +{ +} + +bool QueryToken::isCommand() const +{ + return false; +} + +bool QueryToken::isOperator() const +{ + return false; +} + +bool QueryToken::isToken() const +{ + return true; +} + +bool QueryToken::isComplete() const +{ + return true; +} + +void QueryToken::print(std::ostream& ostream) const +{ + ostream << '"' << m_name << '"'; +} + +const std::string& QueryToken::getName() const +{ + return m_name; +} diff --git a/src/lib/data/query/QueryToken.h b/src/lib/data/query/QueryToken.h new file mode 100644 index 00000000..206b52e3 --- /dev/null +++ b/src/lib/data/query/QueryToken.h @@ -0,0 +1,28 @@ +#ifndef QUERY_TOKEN_H +#define QUERY_TOKEN_H + +#include + +#include "data/query/QueryNode.h" + +class QueryToken + : public QueryNode +{ +public: + QueryToken(const std::string& name); + ~QueryToken(); + + virtual bool isCommand() const; + virtual bool isOperator() const; + virtual bool isToken() const; + virtual bool isComplete() const; + + virtual void print(std::ostream& ostream) const; + + const std::string& getName() const; + +private: + const std::string m_name; +}; + +#endif // QUERY_TOKEN_H diff --git a/src/lib/data/query/QueryTree.cpp b/src/lib/data/query/QueryTree.cpp new file mode 100644 index 00000000..caafc29f --- /dev/null +++ b/src/lib/data/query/QueryTree.cpp @@ -0,0 +1,207 @@ +#include "data/query/QueryTree.h" + +#include "data/query/QueryCommand.h" +#include "data/query/QueryNode.h" +#include "data/query/QueryOperator.h" +#include "data/query/QueryToken.h" +#include "utility/utilityString.h" + +QueryTree::QueryTree(std::string query) + : m_valid(true) +{ + std::deque tokens = + utility::split>(query, QueryOperator::getOperator(QueryOperator::OPERATOR_NONE)); + + for (const std::pair& p : QueryOperator::getOperatorTypeMap()) + { + tokens = utility::tokenize>(tokens, p.first); + } + + for (std::string str : tokens) + { + m_query += str + ' '; + } + + m_root = buildTree(tokens, nullptr); +} + +QueryTree::~QueryTree() +{ +} + +std::shared_ptr QueryTree::getRoot() const +{ + return m_root; +} + +bool QueryTree::isValid() const +{ + return m_valid; +} + +void QueryTree::print(std::ostream& ostream) const +{ + ostream << m_query; + + if (!m_valid) + { + ostream << " INVALID"; + } + + ostream << '\n'; + + if (m_root) + { + m_root->print(ostream, 0); + } +} + +std::shared_ptr QueryTree::buildTree(std::deque& tokens, std::shared_ptr frontNode) +{ + std::shared_ptr node = getNextNode(tokens); + std::shared_ptr operatorNode = std::dynamic_pointer_cast(node); + + if (frontNode) + { + if (node->isComplete()) + { + std::shared_ptr subNode = std::make_shared(QueryOperator::OPERATOR_SUB); + subNode->setLeft(frontNode); + subNode->setRight(node); + node = subNode; + } + else if (node->isOperator() && operatorNode) + { + operatorNode->setLeft(frontNode); + } + else + { + m_valid = false; + } + } + + if (tokens.size()) + { + if (node->isComplete()) + { + node = buildTree(tokens, node); + } + else if (node->isOperator() && operatorNode) + { + std::shared_ptr rightNode = buildTree(tokens, nullptr); + std::shared_ptr rightOperatorNode = std::dynamic_pointer_cast(rightNode); + + if (rightNode->isOperator() && !rightNode->isGroup() && + operatorNode->lowerPrecedence(*rightOperatorNode.get())) + { + operatorNode->setRight(rightOperatorNode->getLeft()); + rightOperatorNode->setLeft(operatorNode); + node = rightNode; + } + else + { + operatorNode->setRight(rightNode); + } + } + else + { + m_valid = false; + } + } + + if (!node->isComplete()) + { + m_valid = false; + } + + return node; +} + +std::shared_ptr QueryTree::buildGroup(std::deque& tokens, QueryOperator::OperatorType closeType) +{ + std::deque group; + std::string name; + char delimiter = QueryOperator::getOperator(closeType); + while (tokens.front() != std::string(1, delimiter) && tokens.size()) + { + group.push_back(tokens.front()); + name += tokens.front(); + tokens.pop_front(); + } + + if (tokens.size()) + { + tokens.pop_front(); + } + else + { + m_valid = false; + } + + if (!group.size()) + { + return nullptr; + } + + if (closeType == QueryOperator::OPERATOR_NAME) + { + return std::make_shared(name); + } + + std::shared_ptr groupNode = buildTree(group, nullptr); + groupNode->setIsGroup(true); + + return groupNode; +} + +std::shared_ptr QueryTree::getNextNode(std::deque& tokens) +{ + while (tokens.size()) + { + std::string token = tokens.front(); + tokens.pop_front(); + + QueryOperator::OperatorType type = QueryOperator::getOperatorType(token[0]); + + switch (type) + { + case QueryOperator::OPERATOR_NOT: + case QueryOperator::OPERATOR_SUB: + case QueryOperator::OPERATOR_HAS: + case QueryOperator::OPERATOR_AND: + case QueryOperator::OPERATOR_OR: + return std::make_shared(type); + + case QueryOperator::OPERATOR_NAME: + return buildGroup(tokens, QueryOperator::OPERATOR_NAME); + case QueryOperator::OPERATOR_GROUP_OPEN: + return buildGroup(tokens, QueryOperator::OPERATOR_GROUP_CLOSE); + case QueryOperator::OPERATOR_GROUP_CLOSE: + m_valid = false; + break; + + case QueryOperator::OPERATOR_NONE: + return createCommand(token); + } + } + + return nullptr; +} + +std::shared_ptr QueryTree::createCommand(std::string name) +{ + std::shared_ptr node = std::make_shared(name); + + if (node->getType() == QueryCommand::COMMAND_INVALID) + { + m_valid = false; + } + + return node; +} + +std::ostream& operator<<(std::ostream& ostream, const QueryTree& tree) +{ + tree.print(ostream); + return ostream; +} diff --git a/src/lib/data/query/QueryTree.h b/src/lib/data/query/QueryTree.h new file mode 100644 index 00000000..b99dea9c --- /dev/null +++ b/src/lib/data/query/QueryTree.h @@ -0,0 +1,38 @@ +#ifndef QUERY_TREE_H +#define QUERY_TREE_H + +#include +#include +#include +#include + +#include "data/query/QueryOperator.h" + +class QueryNode; + +class QueryTree +{ +public: + QueryTree(std::string query); + ~QueryTree(); + + std::shared_ptr getRoot() const; + + bool isValid() const; + + void print(std::ostream& ostream) const; + +private: + std::shared_ptr buildTree(std::deque& tokens, std::shared_ptr frontNode); + std::shared_ptr buildGroup(std::deque& tokens, QueryOperator::OperatorType closeType); + std::shared_ptr getNextNode(std::deque& tokens); + std::shared_ptr createCommand(std::string name); + + std::shared_ptr m_root; + std::string m_query; + bool m_valid; +}; + +std::ostream& operator<<(std::ostream& ostream, const QueryTree& tree); + +#endif // QUERY_TREE_H diff --git a/src/lib/data/type/DataType.cpp b/src/lib/data/type/DataType.cpp index 66781309..c7109d90 100644 --- a/src/lib/data/type/DataType.cpp +++ b/src/lib/data/type/DataType.cpp @@ -12,7 +12,7 @@ DataType::DataType(const std::string& typeName, const DataTypeQualifierList& qua } DataType::DataType( - const std::string& typeName, const DataTypeQualifierList& qualifierList, const DataTypeModifierStack& modifierStack + const std::string& typeName, const DataTypeQualifierList& qualifierList, const DataTypeModifierStack& modifierStack ) : m_typeName(typeName) , m_qualifierList(qualifierList) diff --git a/src/lib/utility/messaging/type/MessageActivateToken.h b/src/lib/utility/messaging/type/MessageActivateToken.h index 4bf6d18e..5f74068e 100644 --- a/src/lib/utility/messaging/type/MessageActivateToken.h +++ b/src/lib/utility/messaging/type/MessageActivateToken.h @@ -20,4 +20,4 @@ public: const Id tokenId; }; -#endif // MESSAGE_ACTIVATE_TOKEN_LOCATION_H +#endif // MESSAGE_ACTIVATE_TOKEN_H diff --git a/src/lib/utility/messaging/type/MessageActivateTokens.h b/src/lib/utility/messaging/type/MessageActivateTokens.h new file mode 100644 index 00000000..147a7370 --- /dev/null +++ b/src/lib/utility/messaging/type/MessageActivateTokens.h @@ -0,0 +1,23 @@ +#ifndef MESSAGE_ACTIVATE_TOKENS_H +#define MESSAGE_ACTIVATE_TOKENS_H + +#include "utility/messaging/Message.h" +#include "utility/types.h" + +class MessageActivateTokens: public Message +{ +public: + MessageActivateTokens(const std::vector& tokenIds) + : tokenIds(tokenIds) + { + } + + static const std::string getStaticType() + { + return "MessageActivateTokens"; + } + + const std::vector tokenIds; +}; + +#endif // MESSAGE_ACTIVATE_TOKENS_H diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 426251c7..ace4c972 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -12,6 +12,18 @@ namespace utility template ContainerType split(const std::string& str, const std::string& delimiter); + template + ContainerType tokenize(const std::string& str, char delimiter); + + template + ContainerType tokenize(const std::string& str, const std::string& delimiter); + + template + ContainerType tokenize(const ContainerType& list, char delimiter); + + template + ContainerType tokenize(const ContainerType& list, const std::string& delimiter); + std::string substrAfter(const std::string& str, char delimiter); bool isPrefix(const std::string& prefix, const std::string& text); @@ -41,4 +53,58 @@ ContainerType utility::split(const std::string& str, const std::string& delimite return c; } +template +ContainerType utility::tokenize(const std::string& str, char delimiter) +{ + return tokenize(str, std::string(1, delimiter)); +} + +template +ContainerType utility::tokenize(const std::string& str, const std::string& delimiter) +{ + size_t pos = 0; + size_t oldPos = 0; + ContainerType c; + + do + { + pos = str.find(delimiter, oldPos); + + if (pos != oldPos) + { + c.push_back(str.substr(oldPos, pos - oldPos)); + } + + if (pos != std::string::npos) + { + c.push_back(str.substr(pos, delimiter.size())); + } + + oldPos = pos + delimiter.size(); + } + while (pos != std::string::npos && oldPos < str.size()); + + return c; +} + +template +ContainerType utility::tokenize(const ContainerType& list, char delimiter) +{ + return tokenize(list, std::string(1, delimiter)); +} + +template +ContainerType utility::tokenize(const ContainerType& list, const std::string& delimiter) +{ + ContainerType c; + + for (std::string str : list) + { + ContainerType c2 = tokenize(str, delimiter); + c.insert(c.end(), c2.begin(), c2.end()); + } + + return c; +} + #endif // UTILITY_STRING_H diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index c751f0ab..96267776 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,6 +1,9 @@ add_files( TEST_FILES + TestSuiteFixture.cpp + TestSuiteFixture.h + ConfigManagerTestSuite.h CxxParserTestSuite.h DataTypeTestSuite.h @@ -10,8 +13,6 @@ add_files( MessageQueueTestSuite.h SettingsTestSuite.h StorageTestSuite.h - TestSuiteFixture.cpp - TestSuiteFixture.h TextAccessTestSuite.h TokenLocationCollectionTestSuite.h UtilityStringTestSuite.h diff --git a/src/test/UtilityStringTestSuite.h b/src/test/UtilityStringTestSuite.h index 94a048d5..e6123931 100644 --- a/src/test/UtilityStringTestSuite.h +++ b/src/test/UtilityStringTestSuite.h @@ -51,6 +51,71 @@ public: TS_ASSERT_EQUALS(result[3], "C"); } + void test_split_with_delimiter_at_start() + { + std::vector result = utility::split >(":B:C", ':'); + + TS_ASSERT_EQUALS(result.size(), 3); + TS_ASSERT_EQUALS(result[0], ""); + TS_ASSERT_EQUALS(result[1], "B"); + TS_ASSERT_EQUALS(result[2], "C"); + } + + void test_split_with_delimiter_at_end() + { + std::vector result = utility::split >("B:C:", ':'); + + TS_ASSERT_EQUALS(result.size(), 3); + TS_ASSERT_EQUALS(result[0], "B"); + TS_ASSERT_EQUALS(result[1], "C"); + TS_ASSERT_EQUALS(result[2], ""); + } + + void test_tokenize_with_string() + { + std::vector result = utility::tokenize >("A->B->C", "->"); + + TS_ASSERT_EQUALS(result.size(), 5); + TS_ASSERT_EQUALS(result[0], "A"); + TS_ASSERT_EQUALS(result[1], "->"); + TS_ASSERT_EQUALS(result[2], "B"); + TS_ASSERT_EQUALS(result[3], "->"); + TS_ASSERT_EQUALS(result[4], "C"); + } + + void test_tokenize_with_string_and_delimiter_at_start() + { + std::vector result = utility::tokenize >("->B", "->"); + + TS_ASSERT_EQUALS(result.size(), 2); + TS_ASSERT_EQUALS(result[0], "->"); + TS_ASSERT_EQUALS(result[1], "B"); + } + + void test_tokenize_with_string_and_delimiter_at_end() + { + std::vector result = utility::tokenize >("C+", '+'); + + TS_ASSERT_EQUALS(result.size(), 2); + TS_ASSERT_EQUALS(result[0], "C"); + TS_ASSERT_EQUALS(result[1], "+"); + } + + void test_tokenize_with_vector() + { + std::vector result = utility::tokenize >("A->B=C->D", "->"); + result = utility::tokenize>(result, "="); + + TS_ASSERT_EQUALS(result.size(), 7); + TS_ASSERT_EQUALS(result[0], "A"); + TS_ASSERT_EQUALS(result[1], "->"); + TS_ASSERT_EQUALS(result[2], "B"); + TS_ASSERT_EQUALS(result[3], "="); + TS_ASSERT_EQUALS(result[4], "C"); + TS_ASSERT_EQUALS(result[5], "->"); + TS_ASSERT_EQUALS(result[6], "D"); + } + void test_substr_after_with_single_delimiter_occurence() { TS_ASSERT_EQUALS(utility::substrAfter("foo bar", ' '), "bar");