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]
This commit is contained in:
parent
2998527462
commit
f79add5633
@ -1,5 +1,6 @@
|
|||||||
CXX = clang++
|
CXX = clang++
|
||||||
CXXFLAGS = -std=c++1y
|
CXXFLAGS = -std=c++1y
|
||||||
|
# CXXFLAGS = -std=c++1y -g # DEBUG CXXFLAGS
|
||||||
INC = -I../
|
INC = -I../
|
||||||
|
|
||||||
parser: parser.o cypher.o
|
parser: parser.o cypher.o
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
#include "relationship.hpp"
|
#include "relationship.hpp"
|
||||||
#include "node.hpp"
|
#include "node.hpp"
|
||||||
|
#include "distinct.hpp"
|
||||||
#include "return.hpp"
|
#include "return.hpp"
|
||||||
#include "pattern.hpp"
|
#include "pattern.hpp"
|
||||||
#include "return.hpp"
|
#include "return.hpp"
|
||||||
|
@ -44,6 +44,7 @@ struct Pattern;
|
|||||||
|
|
||||||
struct Return;
|
struct Return;
|
||||||
struct ReturnList;
|
struct ReturnList;
|
||||||
|
struct Distinct;
|
||||||
|
|
||||||
struct Match;
|
struct Match;
|
||||||
struct Where;
|
struct Where;
|
||||||
@ -58,6 +59,6 @@ struct AstVisitor : public Visitor<Accessor, Boolean, Float, Identifier,
|
|||||||
Integer, String, Property, And, Or, Lt, Gt, Ge, Le, Eq, Ne, Plus, Minus,
|
Integer, String, Property, And, Or, Lt, Gt, Ge, Le, Eq, Ne, Plus, Minus,
|
||||||
Star, Slash, Rem, PropertyList, RelationshipList, Relationship, Node,
|
Star, Slash, Rem, PropertyList, RelationshipList, Relationship, Node,
|
||||||
RelationshipSpecs, LabelList, ReturnList, Pattern, Match, ReadQuery,
|
RelationshipSpecs, LabelList, ReturnList, Pattern, Match, ReadQuery,
|
||||||
Start, Where, WriteQuery, Create, Return> {};
|
Start, Where, WriteQuery, Create, Return, Distinct> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
17
cypher/ast/distinct.hpp
Normal file
17
cypher/ast/distinct.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ast_node.hpp"
|
||||||
|
#include "identifier.hpp"
|
||||||
|
|
||||||
|
namespace ast
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Distinct : public AstNode<Distinct>
|
||||||
|
{
|
||||||
|
Distinct(Identifier* identifier)
|
||||||
|
: identifier(identifier) {}
|
||||||
|
|
||||||
|
Identifier* identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,9 @@
|
|||||||
namespace ast
|
namespace ast
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Expr : public AstVisitable {};
|
struct Expr : public AstVisitable
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
struct VisitableExpr : public Crtp<Derived>, public Expr
|
struct VisitableExpr : public Crtp<Derived>, public Expr
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "list.hpp"
|
#include "list.hpp"
|
||||||
#include "identifier.hpp"
|
#include "identifier.hpp"
|
||||||
|
#include "distinct.hpp"
|
||||||
|
|
||||||
namespace ast
|
namespace ast
|
||||||
{
|
{
|
||||||
@ -14,9 +15,17 @@ struct ReturnList : public List<Identifier, ReturnList>
|
|||||||
struct Return : public AstNode<Return>
|
struct Return : public AstNode<Return>
|
||||||
{
|
{
|
||||||
Return(ReturnList* return_list)
|
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;
|
ReturnList* return_list;
|
||||||
|
Distinct* distinct;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,14 @@
|
|||||||
|
|
||||||
%syntax_error
|
%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
|
%stack_overflow
|
||||||
@ -68,7 +75,7 @@ write_query(WQ) ::= create_clause(C). {
|
|||||||
%type create_clause {ast::Create*}
|
%type create_clause {ast::Create*}
|
||||||
|
|
||||||
create_clause(C) ::= CREATE pattern(P). {
|
create_clause(C) ::= CREATE pattern(P). {
|
||||||
C = ast->create<ast::Create>(P);
|
C = ast->create<ast::Create>(P);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read query structure
|
// read query structure
|
||||||
@ -112,7 +119,7 @@ rel(R) ::= MINUS rel_spec(S) MINUS GT. { // right
|
|||||||
%type rel_spec {ast::RelationshipSpecs*}
|
%type rel_spec {ast::RelationshipSpecs*}
|
||||||
|
|
||||||
rel_spec(R) ::= LSP rel_idn(I) rel_type(T) properties(P) RSP. {
|
rel_spec(R) ::= LSP rel_idn(I) rel_type(T) properties(P) RSP. {
|
||||||
R = ast->create<ast::RelationshipSpecs>(I, T, P);
|
R = ast->create<ast::RelationshipSpecs>(I, T, P);
|
||||||
}
|
}
|
||||||
|
|
||||||
rel_spec(R) ::= . {
|
rel_spec(R) ::= . {
|
||||||
@ -195,11 +202,14 @@ where_clause(W) ::= . {
|
|||||||
|
|
||||||
%type return_clause {ast::Return*}
|
%type return_clause {ast::Return*}
|
||||||
|
|
||||||
// return clause (return ORDER BY, SKIP, LIMIT)
|
|
||||||
return_clause(R) ::= RETURN return_list(L). {
|
return_clause(R) ::= RETURN return_list(L). {
|
||||||
R = ast->create<ast::Return>(L);
|
R = ast->create<ast::Return>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return_clause(R) ::= RETURN distinct(D). {
|
||||||
|
R = ast->create<ast::Return>(D);
|
||||||
|
}
|
||||||
|
|
||||||
%type return_list {ast::ReturnList*}
|
%type return_list {ast::ReturnList*}
|
||||||
|
|
||||||
return_list(R) ::= return_list(N) COMMA idn(I). {
|
return_list(R) ::= return_list(N) COMMA idn(I). {
|
||||||
@ -210,6 +220,12 @@ return_list(R) ::= idn(I). {
|
|||||||
R = ast->create<ast::ReturnList>(I, nullptr);
|
R = ast->create<ast::ReturnList>(I, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%type distinct {ast::Distinct*}
|
||||||
|
|
||||||
|
distinct(R) ::= DISTINCT idn(I). {
|
||||||
|
R = ast->create<ast::Distinct>(I);
|
||||||
|
}
|
||||||
|
|
||||||
%type properties {ast::PropertyList*}
|
%type properties {ast::PropertyList*}
|
||||||
|
|
||||||
// '{' <property_list> '}'
|
// '{' <property_list> '}'
|
||||||
|
@ -12,7 +12,7 @@ public:
|
|||||||
{
|
{
|
||||||
// whitespace
|
// whitespace
|
||||||
rule("\\s+", sm.skip());
|
rule("\\s+", sm.skip());
|
||||||
|
|
||||||
// special characters
|
// special characters
|
||||||
rule("\\.", TK_DOT);
|
rule("\\.", TK_DOT);
|
||||||
rule(",", TK_COMMA);
|
rule(",", TK_COMMA);
|
||||||
@ -41,23 +41,24 @@ public:
|
|||||||
|
|
||||||
// constants
|
// constants
|
||||||
rule("(?i:TRUE)", TK_BOOL);
|
rule("(?i:TRUE)", TK_BOOL);
|
||||||
rule("(?i:FALSE)", TK_BOOL);
|
rule("(?i:FALSE)", TK_BOOL);
|
||||||
|
|
||||||
// keywords
|
// keywords
|
||||||
rule("(?i:MATCH)", TK_MATCH);
|
rule("(?i:MATCH)", TK_MATCH);
|
||||||
rule("(?i:WHERE)", TK_WHERE);
|
rule("(?i:WHERE)", TK_WHERE);
|
||||||
rule("(?i:RETURN)", TK_RETURN);
|
rule("(?i:RETURN)", TK_RETURN);
|
||||||
rule("(?i:CREATE)", TK_CREATE);
|
rule("(?i:CREATE)", TK_CREATE);
|
||||||
|
rule("(?i:DISTINCT)", TK_DISTINCT);
|
||||||
|
|
||||||
rule("(?i:AND)", TK_AND);
|
rule("(?i:AND)", TK_AND);
|
||||||
rule("(?i:OR)", TK_OR);
|
rule("(?i:OR)", TK_OR);
|
||||||
|
|
||||||
// string literal TODO single quote escape
|
// string literal TODO single quote escape
|
||||||
rule("'(.*?)'", TK_STR);
|
rule("'(.*?)'", TK_STR);
|
||||||
|
|
||||||
// string literal TODO double quote escape
|
// string literal TODO double quote escape
|
||||||
rule("\\\"(.*?)\\\"", TK_STR);
|
rule("\\\"(.*?)\\\"", TK_STR);
|
||||||
|
|
||||||
// number
|
// number
|
||||||
rule("\\d+", TK_INT);
|
rule("\\d+", TK_INT);
|
||||||
rule("\\d*[.]?\\d+", TK_FLOAT);
|
rule("\\d*[.]?\\d+", TK_FLOAT);
|
||||||
|
@ -124,6 +124,12 @@ public:
|
|||||||
Traverser::visit(return_clause);
|
Traverser::visit(return_clause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(ast::Distinct& distinct) override
|
||||||
|
{
|
||||||
|
auto entry = printer.advance("Distinct");
|
||||||
|
Traverser::visit(distinct);
|
||||||
|
}
|
||||||
|
|
||||||
void visit(ast::Accessor& accessor) override
|
void visit(ast::Accessor& accessor) override
|
||||||
{
|
{
|
||||||
auto entry = printer.advance("Accessor");
|
auto entry = printer.advance("Accessor");
|
||||||
|
@ -8,14 +8,11 @@
|
|||||||
#include "utils/command_line/arguments.hpp"
|
#include "utils/command_line/arguments.hpp"
|
||||||
#include "utils/string/filereader.hpp"
|
#include "utils/string/filereader.hpp"
|
||||||
|
|
||||||
|
#include "utils/terminate_handler.hpp"
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
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 *
|
// * INPUT ARGUMENTS *
|
||||||
// -q -> query
|
// -q -> query
|
||||||
// -v -> visitor
|
// -v -> visitor
|
||||||
@ -33,11 +30,14 @@ std::string extract_query(const vector_str& arguments)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
std::set_terminate(&terminate_handler);
|
||||||
|
|
||||||
// arguments parsing
|
// arguments parsing
|
||||||
auto arguments = all_arguments(argc, argv);
|
auto arguments = all_arguments(argc, argv);
|
||||||
|
|
||||||
// query extraction
|
// query extraction
|
||||||
auto cypher_query = extract_query(arguments);
|
auto cypher_query = extract_query(arguments);
|
||||||
|
cout << "QUERY: " << cypher_query << endl;
|
||||||
|
|
||||||
// traversers
|
// traversers
|
||||||
auto traverser = get_argument(arguments, "-t", "code");
|
auto traverser = get_argument(arguments, "-t", "code");
|
||||||
|
@ -35,7 +35,7 @@ public:
|
|||||||
{
|
{
|
||||||
tokens.emplace_back(tokenizer.lookup());
|
tokens.emplace_back(tokenizer.lookup());
|
||||||
auto& token = tokens.back();
|
auto& token = tokens.back();
|
||||||
// std::cout << token << std::endl;
|
std::cout << token << std::endl;
|
||||||
cypher_parser(parser, token.id, &token, &tree);
|
cypher_parser(parser, token.id, &token, &tree);
|
||||||
|
|
||||||
} while(tokens.back().id != 0);
|
} while(tokens.back().id != 0);
|
||||||
|
1
cypher/query/read/match/match-custom1.cypher
Normal file
1
cypher/query/read/match/match-custom1.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
MATCH (user:User { name: 'Dominik', age: 8 + 4})-[has:HAS|IS|CAN { duration: 'PERMANENT'}]->(item:Item)--(shop)
|
1
cypher/query/read/match/match-custom2.cypher
Normal file
1
cypher/query/read/match/match-custom2.cypher
Normal file
@ -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
|
1
cypher/query/read/return/return-alias.cypher
Normal file
1
cypher/query/read/return/return-alias.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
MATCH (n) RETURN n AS columnName
|
1
cypher/query/read/return/return-all.cypher
Normal file
1
cypher/query/read/return/return-all.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
MATCH (n) RETURN n
|
1
cypher/query/read/return/return-count.cypher
Normal file
1
cypher/query/read/return/return-count.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
RETURN count(*)
|
1
cypher/query/read/return/return-distinct.cypher
Normal file
1
cypher/query/read/return/return-distinct.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
MATCH (n) RETURN DISTINCT n
|
1
cypher/query/read/return/return-limit.cypher
Normal file
1
cypher/query/read/return/return-limit.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
LIMIT 10
|
1
cypher/query/read/return/return-order-asc.cypher
Normal file
1
cypher/query/read/return/return-order-asc.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
ORDER BY n.property
|
1
cypher/query/read/return/return-order-desc.cypher
Normal file
1
cypher/query/read/return/return-order-desc.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
ORDER BY n.property DESC
|
1
cypher/query/read/return/return-skip-limit.cypher
Normal file
1
cypher/query/read/return/return-skip-limit.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
SKIP 2 LIMIT 3
|
1
cypher/query/read/return/return-skip.cypher
Normal file
1
cypher/query/read/return/return-skip.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
SKIP 10
|
1
cypher/query/read/union/union-all.cypher
Normal file
1
cypher/query/read/union/union-all.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
MATCH (a)-[:KNOWS]->(b) RETURN b.name UNION ALL MATCH (a)-[:LOVES]->(b) RETURN b.name
|
1
cypher/query/read/union/union.cypher
Normal file
1
cypher/query/read/union/union.cypher
Normal file
@ -0,0 +1 @@
|
|||||||
|
MATCH (a)-[:KNOWS]->(b) RETURN b.name UNION MATCH (a)-[:LOVES]->(b) RETURN b.name
|
@ -1 +1 @@
|
|||||||
WHERE n.property <> {value}
|
MATCH n WHERE n.property <> "100"
|
||||||
|
@ -1 +1 @@
|
|||||||
CREATE (n {name: 'Domko', age: 24}) RETURN n
|
CREATE (n {name: 'Domko', age: 26}) RETURN n
|
||||||
|
@ -44,7 +44,10 @@ public:
|
|||||||
|
|
||||||
void visit(ast::Return& return_clause) override
|
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
|
void visit(ast::Accessor& accessor) override
|
||||||
@ -188,6 +191,11 @@ public:
|
|||||||
accept(create.pattern);
|
accept(create.pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visit(ast::Distinct& distinct) override
|
||||||
|
{
|
||||||
|
accept(distinct.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template<class T>
|
template<class T>
|
||||||
void accept(T* node)
|
void accept(T* node)
|
||||||
|
@ -23,8 +23,8 @@ int main()
|
|||||||
container.singleton<Db>();
|
container.singleton<Db>();
|
||||||
|
|
||||||
auto loop = container.singleton<uv::UvLoop>();
|
auto loop = container.singleton<uv::UvLoop>();
|
||||||
auto app = container.singleton<sp::Speedy, uv::UvLoop>("/db/data");
|
|
||||||
|
|
||||||
|
auto app = container.singleton<sp::Speedy, uv::UvLoop>("/db/data");
|
||||||
container.singleton<Pool>(4);
|
container.singleton<Pool>(4);
|
||||||
container.singleton<Task, uv::UvLoop, Pool>();
|
container.singleton<Task, uv::UvLoop, Pool>();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user