From f79add56333ed73d2d72d54873a02b08e5b0b4f3 Mon Sep 17 00:00:00 2001 From: Marko Budiselic Date: Mon, 18 Jan 2016 00:41:54 +0100 Subject: [PATCH] DISTINCT is now inside AST; tradeoff: [Return object with return list and distinct pointers -> query executor is going to be more complex] OR [ReturnList object and ReturnDistinct object -> lemon / LARL(1) syntax will be much more complex] --- cypher/Makefile | 1 + cypher/ast/ast.hpp | 1 + cypher/ast/ast_visitor.hpp | 3 ++- cypher/ast/distinct.hpp | 17 +++++++++++++ cypher/ast/expr.hpp | 4 +++- cypher/ast/return.hpp | 11 ++++++++- cypher/cypher.y | 24 +++++++++++++++---- cypher/cypher_lexer.hpp | 9 +++---- cypher/debug/tree_print.hpp | 6 +++++ cypher/parser.cpp | 10 ++++---- cypher/parser.hpp | 2 +- cypher/query/read/match/match-custom1.cypher | 1 + cypher/query/read/match/match-custom2.cypher | 1 + cypher/query/read/return/return-alias.cypher | 1 + cypher/query/read/return/return-all.cypher | 1 + cypher/query/read/return/return-count.cypher | 1 + .../query/read/return/return-distinct.cypher | 1 + cypher/query/read/return/return-limit.cypher | 1 + .../query/read/return/return-order-asc.cypher | 1 + .../read/return/return-order-desc.cypher | 1 + .../read/return/return-skip-limit.cypher | 1 + cypher/query/read/return/return-skip.cypher | 1 + cypher/query/read/union/union-all.cypher | 1 + cypher/query/read/union/union.cypher | 1 + cypher/query/read/where/where.cypher | 2 +- cypher/query/write/create-return.cypher | 2 +- cypher/visitor/traverser.hpp | 10 +++++++- memgraph.cpp | 2 +- 28 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 cypher/ast/distinct.hpp create mode 100644 cypher/query/read/match/match-custom1.cypher create mode 100644 cypher/query/read/match/match-custom2.cypher create mode 100644 cypher/query/read/return/return-alias.cypher create mode 100644 cypher/query/read/return/return-all.cypher create mode 100644 cypher/query/read/return/return-count.cypher create mode 100644 cypher/query/read/return/return-distinct.cypher create mode 100644 cypher/query/read/return/return-limit.cypher create mode 100644 cypher/query/read/return/return-order-asc.cypher create mode 100644 cypher/query/read/return/return-order-desc.cypher create mode 100644 cypher/query/read/return/return-skip-limit.cypher create mode 100644 cypher/query/read/return/return-skip.cypher create mode 100644 cypher/query/read/union/union-all.cypher create mode 100644 cypher/query/read/union/union.cypher diff --git a/cypher/Makefile b/cypher/Makefile index cb291cdb5..a4017d6c9 100644 --- a/cypher/Makefile +++ b/cypher/Makefile @@ -1,5 +1,6 @@ CXX = clang++ CXXFLAGS = -std=c++1y +# CXXFLAGS = -std=c++1y -g # DEBUG CXXFLAGS INC = -I../ parser: parser.o cypher.o diff --git a/cypher/ast/ast.hpp b/cypher/ast/ast.hpp index 9e0d143c6..4d334ad07 100644 --- a/cypher/ast/ast.hpp +++ b/cypher/ast/ast.hpp @@ -7,6 +7,7 @@ #include "property.hpp" #include "relationship.hpp" #include "node.hpp" +#include "distinct.hpp" #include "return.hpp" #include "pattern.hpp" #include "return.hpp" diff --git a/cypher/ast/ast_visitor.hpp b/cypher/ast/ast_visitor.hpp index 7d0d86969..00a06ee27 100644 --- a/cypher/ast/ast_visitor.hpp +++ b/cypher/ast/ast_visitor.hpp @@ -44,6 +44,7 @@ struct Pattern; struct Return; struct ReturnList; +struct Distinct; struct Match; struct Where; @@ -58,6 +59,6 @@ struct AstVisitor : public Visitor {}; + Start, Where, WriteQuery, Create, Return, Distinct> {}; } diff --git a/cypher/ast/distinct.hpp b/cypher/ast/distinct.hpp new file mode 100644 index 000000000..61bc58fc2 --- /dev/null +++ b/cypher/ast/distinct.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "ast_node.hpp" +#include "identifier.hpp" + +namespace ast +{ + +struct Distinct : public AstNode +{ + Distinct(Identifier* identifier) + : identifier(identifier) {} + + Identifier* identifier; +}; + +} diff --git a/cypher/ast/expr.hpp b/cypher/ast/expr.hpp index 52d6ed24a..74569dad7 100644 --- a/cypher/ast/expr.hpp +++ b/cypher/ast/expr.hpp @@ -5,7 +5,9 @@ namespace ast { -struct Expr : public AstVisitable {}; +struct Expr : public AstVisitable +{ +}; template struct VisitableExpr : public Crtp, public Expr diff --git a/cypher/ast/return.hpp b/cypher/ast/return.hpp index 61e8ea49f..b7b64517f 100644 --- a/cypher/ast/return.hpp +++ b/cypher/ast/return.hpp @@ -2,6 +2,7 @@ #include "list.hpp" #include "identifier.hpp" +#include "distinct.hpp" namespace ast { @@ -14,9 +15,17 @@ struct ReturnList : public List struct Return : public AstNode { Return(ReturnList* return_list) - : return_list(return_list) {} + : return_list(return_list), distinct(nullptr) + { + } + + Return(Distinct* distinct) + : return_list(nullptr), distinct(distinct) + { + } ReturnList* return_list; + Distinct* distinct; }; }; diff --git a/cypher/cypher.y b/cypher/cypher.y index b8e1ff202..4034adc1e 100644 --- a/cypher/cypher.y +++ b/cypher/cypher.y @@ -13,7 +13,14 @@ %syntax_error { - throw SyntaxError(TOKEN->value); + int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]); + for (int i = 0; i < n; ++i) { + int a = yy_find_shift_action(yypParser, (YYCODETYPE)i); + if (a < YYNSTATE + YYNRULE) { + printf("possible token: %s\n", yyTokenName[i]); + } + } + // throw SyntaxError(TOKEN->value); } %stack_overflow @@ -68,7 +75,7 @@ write_query(WQ) ::= create_clause(C). { %type create_clause {ast::Create*} create_clause(C) ::= CREATE pattern(P). { - C = ast->create(P); + C = ast->create(P); } // read query structure @@ -112,7 +119,7 @@ rel(R) ::= MINUS rel_spec(S) MINUS GT. { // right %type rel_spec {ast::RelationshipSpecs*} rel_spec(R) ::= LSP rel_idn(I) rel_type(T) properties(P) RSP. { - R = ast->create(I, T, P); + R = ast->create(I, T, P); } rel_spec(R) ::= . { @@ -195,11 +202,14 @@ where_clause(W) ::= . { %type return_clause {ast::Return*} -// return clause (return ORDER BY, SKIP, LIMIT) return_clause(R) ::= RETURN return_list(L). { R = ast->create(L); } +return_clause(R) ::= RETURN distinct(D). { + R = ast->create(D); +} + %type return_list {ast::ReturnList*} return_list(R) ::= return_list(N) COMMA idn(I). { @@ -210,6 +220,12 @@ return_list(R) ::= idn(I). { R = ast->create(I, nullptr); } +%type distinct {ast::Distinct*} + +distinct(R) ::= DISTINCT idn(I). { + R = ast->create(I); +} + %type properties {ast::PropertyList*} // '{' '}' diff --git a/cypher/cypher_lexer.hpp b/cypher/cypher_lexer.hpp index a04912bc7..2f47729b1 100644 --- a/cypher/cypher_lexer.hpp +++ b/cypher/cypher_lexer.hpp @@ -12,7 +12,7 @@ public: { // whitespace rule("\\s+", sm.skip()); - + // special characters rule("\\.", TK_DOT); rule(",", TK_COMMA); @@ -41,23 +41,24 @@ public: // constants rule("(?i:TRUE)", TK_BOOL); - rule("(?i:FALSE)", TK_BOOL); + rule("(?i:FALSE)", TK_BOOL); // keywords rule("(?i:MATCH)", TK_MATCH); rule("(?i:WHERE)", TK_WHERE); rule("(?i:RETURN)", TK_RETURN); rule("(?i:CREATE)", TK_CREATE); + rule("(?i:DISTINCT)", TK_DISTINCT); rule("(?i:AND)", TK_AND); rule("(?i:OR)", TK_OR); // string literal TODO single quote escape rule("'(.*?)'", TK_STR); - + // string literal TODO double quote escape rule("\\\"(.*?)\\\"", TK_STR); - + // number rule("\\d+", TK_INT); rule("\\d*[.]?\\d+", TK_FLOAT); diff --git a/cypher/debug/tree_print.hpp b/cypher/debug/tree_print.hpp index 4211cecab..9e9620a18 100644 --- a/cypher/debug/tree_print.hpp +++ b/cypher/debug/tree_print.hpp @@ -124,6 +124,12 @@ public: Traverser::visit(return_clause); } + void visit(ast::Distinct& distinct) override + { + auto entry = printer.advance("Distinct"); + Traverser::visit(distinct); + } + void visit(ast::Accessor& accessor) override { auto entry = printer.advance("Accessor"); diff --git a/cypher/parser.cpp b/cypher/parser.cpp index 7af4d2cf9..22193f743 100644 --- a/cypher/parser.cpp +++ b/cypher/parser.cpp @@ -8,14 +8,11 @@ #include "utils/command_line/arguments.hpp" #include "utils/string/filereader.hpp" +#include "utils/terminate_handler.hpp" + using std::cout; using std::endl; -// * QUERY EXAMPLES * -// "CREATE (n { name: 'Dominik', age: 24, role: 'CEO' }) return n" -// "MATCH (user:User { name: 'Dominik', age: 8 + 4})-[has:HAS|IS|CAN { duration: 'PERMANENT'}]->(item:Item)--(shop)" -// "MATCH (user:User { name: 'Dominik', age: 24})-[has:HAS]->(item:Item) WHERE item.name = 'XPS 13' AND item.price = 11999.99 RETURN user, has, item" - // * INPUT ARGUMENTS * // -q -> query // -v -> visitor @@ -33,11 +30,14 @@ std::string extract_query(const vector_str& arguments) int main(int argc, char *argv[]) { + std::set_terminate(&terminate_handler); + // arguments parsing auto arguments = all_arguments(argc, argv); // query extraction auto cypher_query = extract_query(arguments); + cout << "QUERY: " << cypher_query << endl; // traversers auto traverser = get_argument(arguments, "-t", "code"); diff --git a/cypher/parser.hpp b/cypher/parser.hpp index 279b99ae6..3586079fd 100644 --- a/cypher/parser.hpp +++ b/cypher/parser.hpp @@ -35,7 +35,7 @@ public: { tokens.emplace_back(tokenizer.lookup()); auto& token = tokens.back(); - // std::cout << token << std::endl; + std::cout << token << std::endl; cypher_parser(parser, token.id, &token, &tree); } while(tokens.back().id != 0); diff --git a/cypher/query/read/match/match-custom1.cypher b/cypher/query/read/match/match-custom1.cypher new file mode 100644 index 000000000..90275b84b --- /dev/null +++ b/cypher/query/read/match/match-custom1.cypher @@ -0,0 +1 @@ +MATCH (user:User { name: 'Dominik', age: 8 + 4})-[has:HAS|IS|CAN { duration: 'PERMANENT'}]->(item:Item)--(shop) diff --git a/cypher/query/read/match/match-custom2.cypher b/cypher/query/read/match/match-custom2.cypher new file mode 100644 index 000000000..10f9b1f8d --- /dev/null +++ b/cypher/query/read/match/match-custom2.cypher @@ -0,0 +1 @@ +MATCH (user:User { name: 'Dominik', age: 24})-[has:HAS]->(item:Item) WHERE item.name = 'XPS 13' AND item.price = 11999.99 RETURN user, has, item diff --git a/cypher/query/read/return/return-alias.cypher b/cypher/query/read/return/return-alias.cypher new file mode 100644 index 000000000..512cb4531 --- /dev/null +++ b/cypher/query/read/return/return-alias.cypher @@ -0,0 +1 @@ +MATCH (n) RETURN n AS columnName diff --git a/cypher/query/read/return/return-all.cypher b/cypher/query/read/return/return-all.cypher new file mode 100644 index 000000000..218579589 --- /dev/null +++ b/cypher/query/read/return/return-all.cypher @@ -0,0 +1 @@ +MATCH (n) RETURN n diff --git a/cypher/query/read/return/return-count.cypher b/cypher/query/read/return/return-count.cypher new file mode 100644 index 000000000..0225101b7 --- /dev/null +++ b/cypher/query/read/return/return-count.cypher @@ -0,0 +1 @@ +RETURN count(*) diff --git a/cypher/query/read/return/return-distinct.cypher b/cypher/query/read/return/return-distinct.cypher new file mode 100644 index 000000000..07dad7cbe --- /dev/null +++ b/cypher/query/read/return/return-distinct.cypher @@ -0,0 +1 @@ +MATCH (n) RETURN DISTINCT n diff --git a/cypher/query/read/return/return-limit.cypher b/cypher/query/read/return/return-limit.cypher new file mode 100644 index 000000000..c51dda35f --- /dev/null +++ b/cypher/query/read/return/return-limit.cypher @@ -0,0 +1 @@ +LIMIT 10 diff --git a/cypher/query/read/return/return-order-asc.cypher b/cypher/query/read/return/return-order-asc.cypher new file mode 100644 index 000000000..9efeacc28 --- /dev/null +++ b/cypher/query/read/return/return-order-asc.cypher @@ -0,0 +1 @@ +ORDER BY n.property diff --git a/cypher/query/read/return/return-order-desc.cypher b/cypher/query/read/return/return-order-desc.cypher new file mode 100644 index 000000000..a6778406f --- /dev/null +++ b/cypher/query/read/return/return-order-desc.cypher @@ -0,0 +1 @@ +ORDER BY n.property DESC diff --git a/cypher/query/read/return/return-skip-limit.cypher b/cypher/query/read/return/return-skip-limit.cypher new file mode 100644 index 000000000..2c3b22eec --- /dev/null +++ b/cypher/query/read/return/return-skip-limit.cypher @@ -0,0 +1 @@ +SKIP 2 LIMIT 3 diff --git a/cypher/query/read/return/return-skip.cypher b/cypher/query/read/return/return-skip.cypher new file mode 100644 index 000000000..781eadcf5 --- /dev/null +++ b/cypher/query/read/return/return-skip.cypher @@ -0,0 +1 @@ +SKIP 10 diff --git a/cypher/query/read/union/union-all.cypher b/cypher/query/read/union/union-all.cypher new file mode 100644 index 000000000..7a7783cf7 --- /dev/null +++ b/cypher/query/read/union/union-all.cypher @@ -0,0 +1 @@ +MATCH (a)-[:KNOWS]->(b) RETURN b.name UNION ALL MATCH (a)-[:LOVES]->(b) RETURN b.name diff --git a/cypher/query/read/union/union.cypher b/cypher/query/read/union/union.cypher new file mode 100644 index 000000000..8855b73b4 --- /dev/null +++ b/cypher/query/read/union/union.cypher @@ -0,0 +1 @@ +MATCH (a)-[:KNOWS]->(b) RETURN b.name UNION MATCH (a)-[:LOVES]->(b) RETURN b.name diff --git a/cypher/query/read/where/where.cypher b/cypher/query/read/where/where.cypher index 41e1aadbe..12db0b199 100644 --- a/cypher/query/read/where/where.cypher +++ b/cypher/query/read/where/where.cypher @@ -1 +1 @@ -WHERE n.property <> {value} +MATCH n WHERE n.property <> "100" diff --git a/cypher/query/write/create-return.cypher b/cypher/query/write/create-return.cypher index 26b6308aa..160697fc5 100644 --- a/cypher/query/write/create-return.cypher +++ b/cypher/query/write/create-return.cypher @@ -1 +1 @@ -CREATE (n {name: 'Domko', age: 24}) RETURN n +CREATE (n {name: 'Domko', age: 26}) RETURN n diff --git a/cypher/visitor/traverser.hpp b/cypher/visitor/traverser.hpp index 1dac4620e..678001532 100644 --- a/cypher/visitor/traverser.hpp +++ b/cypher/visitor/traverser.hpp @@ -44,7 +44,10 @@ public: void visit(ast::Return& return_clause) override { - accept(return_clause.return_list); + if (return_clause.return_list != nullptr) + accept(return_clause.return_list); + if (return_clause.distinct != nullptr) + accept(return_clause.distinct); } void visit(ast::Accessor& accessor) override @@ -188,6 +191,11 @@ public: accept(create.pattern); } + void visit(ast::Distinct& distinct) override + { + accept(distinct.identifier); + } + protected: template void accept(T* node) diff --git a/memgraph.cpp b/memgraph.cpp index 7deb6df96..db3689edf 100644 --- a/memgraph.cpp +++ b/memgraph.cpp @@ -23,8 +23,8 @@ int main() container.singleton(); auto loop = container.singleton(); - auto app = container.singleton("/db/data"); + auto app = container.singleton("/db/data"); container.singleton(4); container.singleton();