memgraph/include/query/language/cypher/cypher.y

590 lines
12 KiB
Plaintext

/*
** This file contains memgraph's grammar for Cypher. Process this file
** using the lemon parser generator to generate C code that runs
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
*/
%token_prefix TK_
%token_type {Token*}
%extra_argument {ast::Ast* ast}
%syntax_error
{
#ifndef NDEBUG
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 CypherSyntaxError(TOKEN->value);
#endif
}
%stack_overflow
{
throw CypherParsingError("Parser stack overflow");
}
%name cypher_parser
%include
{
#include <iostream>
#include <cassert>
#include <cstdlib>
#include "query/language/cypher/token.hpp"
#include "query/language/cypher/errors.hpp"
#include "query/language/cypher/ast/ast.hpp"
#include "query/language/cypher/ast/tree.hpp"
#define DEBUG(X) std::cout << "PARSER: " << X << std::endl
}
// define operator precedence
%left OR.
%left AND.
%right NOT.
%left IN IS_NULL IS_NOT_NULL NE EQ.
%left GT LE LT GE.
%left PLUS MINUS.
%left STAR SLASH REM.
// -- start structure
start ::= with_query(Q). {
ast->root = Q;
}
start ::= write_query(Q). {
ast->root = Q;
}
start ::= read_query(Q). {
ast->root = Q;
}
start ::= update_query(Q). {
ast->root = Q;
}
start ::= delete_query(Q). {
ast->root = Q;
}
start ::= read_write_query(Q). {
ast->root = Q;
}
start ::= merge_query(Q). {
ast->root = Q;
}
// -- merge query
%type merge_query {ast::MergeQuery*}
merge_query(MQ) ::= merge_clause(MC) set_clause(SC) return_clause(RC). {
MQ = ast->create<ast::MergeQuery>(MC, SC, RC);
}
merge_query(MQ) ::= merge_clause(MC) return_clause(RC). {
MQ = ast->create<ast::MergeQuery>(MC, nullptr, RC);
}
// -- with query
%type with_query {ast::WithQuery*}
with_query(WQ) ::= with_start_clause(SQ) with_list(WL) return_clause(RC). {
WQ = ast->create<ast::WithQuery>(SQ, WL, RC);
}
%type with_list {ast::WithList*}
with_list(L) ::= WITH with_clause(WC) with_list(N). {
L = ast->create<ast::WithList>(WC, N);
}
with_list(L) ::= . {
L = nullptr;
}
// TODO: replace Match with something that has Match, Create, etc.
%type with_start_clause {ast::Match*}
with_start_clause(WSC) ::= match_clause(MC). {
WSC = MC;
}
%type with_clause {ast::WithClause*}
with_clause(WC) ::= identifier_list(IL) with_match_clause(MC). {
WC = ast->create<ast::WithClause>(IL, MC);
}
%type with_match_clause {ast::Match*}
with_match_clause(WMC) ::= match_clause(M). {
WMC = M;
}
with_match_clause(WMC) ::= where_clause(WC). {
WMC = ast->create<ast::Match>(nullptr, WC);
}
// write query structure
%type write_query {ast::WriteQuery*}
write_query(WQ) ::= create_clause(C) return_clause(R). {
WQ = ast->create<ast::WriteQuery>(C, R);
}
write_query(WQ) ::= create_clause(C). {
WQ = ast->create<ast::WriteQuery>(C, nullptr);
}
// read query structure
%type read_query {ast::ReadQuery*}
read_query(RQ) ::= match_clause(M) return_clause(R). {
RQ = ast->create<ast::ReadQuery>(M, R);
}
// -- match create query
%type read_write_query {ast::ReadWriteQuery*}
read_write_query(Q) ::= match_clause(M) create_clause(C) return_clause(R). {
Q = ast->create<ast::ReadWriteQuery>(M, C, R);
}
read_write_query(Q) ::= match_clause(M) create_clause(C). {
Q = ast->create<ast::ReadWriteQuery>(M, C, nullptr);
}
// ---------------------
// update query structure
%type update_query {ast::UpdateQuery*}
update_query(UQ) ::= match_clause(M) set_clause(S) return_clause(R). {
UQ = ast->create<ast::UpdateQuery>(M, S, R);
}
update_query(UQ) ::= match_clause(M) set_clause(S). {
UQ = ast->create<ast::UpdateQuery>(M, S, nullptr);
}
// set clause
%type set_clause {ast::Set*}
set_clause(S) ::= SET set_list(L). {
S = ast->create<ast::Set>(L);
}
// delete query structure
%type delete_query {ast::DeleteQuery*}
delete_query(DQ) ::= match_clause(M) delete_clause(D). {
DQ = ast->create<ast::DeleteQuery>(M, D);
}
%type create_clause {ast::Create*}
create_clause(C) ::= CREATE pattern(P). {
C = ast->create<ast::Create>(P);
}
%type merge_clause {ast::Merge*}
merge_clause(M) ::= MERGE pattern(P). {
M = ast->create<ast::Merge>(P);
}
%type match_clause {ast::Match*}
match_clause(M) ::= MATCH pattern_list(P) where_clause(W). {
M = ast->create<ast::Match>(P, W);
}
%type delete_clause {ast::Delete*}
// TODO: expression list support
delete_clause(D) ::= DELETE idn(I). {
D = ast->create<ast::Delete>(I, false);
}
delete_clause(D) ::= DETACH DELETE idn(I). {
D = ast->create<ast::Delete>(I, true);
}
// ---- pattern list
%type pattern_list {ast::PatternList*}
pattern_list(L) ::= pattern(P) COMMA pattern_list(N). {
L = ast->create<ast::PatternList>(P, N);
}
pattern_list(L) ::= pattern(P). {
L = ast->create<ast::PatternList>(P, nullptr);
}
// ----
%type pattern {ast::Pattern*}
pattern(P) ::= node(N) rel(R) pattern(NEXT). {
P = ast->create<ast::Pattern>(N, R, NEXT);
}
pattern(P) ::= node(N). {
P = ast->create<ast::Pattern>(N, nullptr, nullptr);
}
// update query
// MATCH ... WITH ... SET ... RETURN
%type rel {ast::Relationship*}
rel(R) ::= MINUS rel_spec(S) MINUS. { // bidirectional
R = ast->create<ast::Relationship>(S, ast::Relationship::Both);
}
rel(R) ::= LT MINUS rel_spec(S) MINUS. { // left
R = ast->create<ast::Relationship>(S, ast::Relationship::Left);
}
rel(R) ::= MINUS rel_spec(S) MINUS GT. { // right
R = ast->create<ast::Relationship>(S, ast::Relationship::Right);
}
%type rel_spec {ast::RelationshipSpecs*}
rel_spec(R) ::= LSP rel_idn(I) rel_type(T) properties(P) RSP. {
R = ast->create<ast::RelationshipSpecs>(I, T, P);
}
rel_spec(R) ::= . {
R = nullptr;
}
%type rel_idn {ast::Identifier*}
rel_idn(R) ::= idn(I). {
R = I;
}
rel_idn(R) ::= . {
R = nullptr;
}
%type rel_type {ast::RelationshipTypeList*}
rel_type(L) ::= COLON rel_list(R). {
L = R;
}
rel_type(L) ::= . {
L = nullptr;
}
%type rel_list {ast::RelationshipTypeList*}
rel_list(L) ::= idn(I) PIPE rel_list(R). {
L = ast->create<ast::RelationshipTypeList>(I, R);
}
rel_list(L) ::= idn(I). {
L = ast->create<ast::RelationshipTypeList>(I, nullptr);
}
%type node {ast::Node*}
// node specification
node(N) ::= LP node_idn(I) label_idn(L) properties(P) RP. {
N = ast->create<ast::Node>(I, L, P);
}
%type node_idn {ast::Identifier*}
// a node identifier can be ommitted
node_idn(N) ::= idn(I). {
N = I;
}
node_idn(N) ::= . {
N = nullptr;
}
%type label_idn {ast::LabelList*}
// a label can be ommited or there can be more of them
label_idn(L) ::= COLON idn(I) label_idn(N). {
L = ast->create<ast::LabelList>(I, N);
}
label_idn(L) ::= . {
L = nullptr;
}
%type where_clause {ast::Where*}
// where clause
where_clause(W) ::= WHERE expr(E). {
W = ast->create<ast::Where>(E);
}
where_clause(W) ::= . {
W = nullptr;
}
%type return_clause {ast::Return*}
return_clause(R) ::= RETURN return_list(L). {
R = ast->create<ast::Return>(L);
}
return_clause(R) ::= RETURN distinct(D). {
R = ast->create<ast::Return>(D);
}
%type return_list {ast::ReturnList*}
return_list(R) ::= return_list(N) COMMA expr(E). {
R = ast->create<ast::ReturnList>(E, N);
}
return_list(R) ::= expr(E). {
R = ast->create<ast::ReturnList>(E, nullptr);
}
%type distinct {ast::Distinct*}
distinct(R) ::= DISTINCT idn(I). {
R = ast->create<ast::Distinct>(I);
}
// list of properties
// e.g. { name: "wayne", surname: "rooney"}
%type properties {ast::PropertyList*}
// '{' <property_list> '}'
properties(P) ::= LCP property_list(L) RCP. {
P = L;
}
properties(P) ::= . {
P = nullptr;
}
%type property_list {ast::PropertyList*}
// <property> [[',' <property>]]*
property_list(L) ::= property(P) COMMA property_list(N). {
L = ast->create<ast::PropertyList>(P, N);
}
property_list(L) ::= property(P). {
L = ast->create<ast::PropertyList>(P, nullptr);
}
%type property {ast::Property*}
// IDENTIFIER ':' <expression>
property(P) ::= idn(I) COLON value_expr(E). {
P = ast->create<ast::Property>(I, E);
}
%type value_expr {ast::Expr*}
value_expr(E) ::= value_expr(L) AND value_expr(R). {
E = ast->create<ast::And>(L, R);
}
value_expr(E) ::= value_expr(L) OR value_expr(R). {
E = ast->create<ast::Or>(L, R);
}
value_expr(E) ::= value_expr(L) LT value_expr(R). {
E = ast->create<ast::Lt>(L, R);
}
value_expr(E) ::= value_expr(L) GT value_expr(R). {
E = ast->create<ast::Gt>(L, R);
}
value_expr(E) ::= value_expr(L) GE value_expr(R). {
E = ast->create<ast::Ge>(L, R);
}
value_expr(E) ::= value_expr(L) LE value_expr(R). {
E = ast->create<ast::Le>(L, R);
}
value_expr(E) ::= value_expr(L) EQ value_expr(R). {
E = ast->create<ast::Eq>(L, R);
}
value_expr(E) ::= value_expr(L) NE value_expr(R). {
E = ast->create<ast::Ne>(L, R);
}
value_expr(E) ::= value_expr(L) PLUS value_expr(R). {
E = ast->create<ast::Plus>(L, R);
}
value_expr(E) ::= value_expr(L) MINUS value_expr(R). {
E = ast->create<ast::Minus>(L, R);
}
value_expr(E) ::= value_expr(L) STAR value_expr(R). {
E = ast->create<ast::Star>(L, R);
}
value_expr(E) ::= value_expr(L) SLASH value_expr(R). {
E = ast->create<ast::Slash>(L, R);
}
value_expr(E) ::= value_expr(L) REM value_expr(R). {
E = ast->create<ast::Rem>(L, R);
}
value_expr(E) ::= idn(I). {
E = ast->create<ast::Accessor>(I, nullptr);
}
value_expr(E) ::= idn(I) DOT idn(P). {
E = ast->create<ast::Accessor>(I, P);
}
value_expr(E) ::= ID LP idn(I) RP EQ LONG(V). {
auto value = std::stol(V->value);
E = ast->create<ast::InternalIdExpr>(I, ast->create<ast::Long>(value));
}
%type idn {ast::Identifier*}
idn(I) ::= IDN(X). {
I = ast->create<ast::Identifier>(X->value);
}
// ---- identifier list
%type identifier_list {ast::IdentifierList*}
identifier_list(L) ::= idn(I) COMMA identifier_list(N). {
L = ast->create<ast::IdentifierList>(I, N);
}
identifier_list(L) ::= idn(I). {
L = ast->create<ast::IdentifierList>(I, nullptr);
}
// ----
value_expr(E) ::= LONG(V). {
auto value = std::stol(V->value);
E = ast->create<ast::Long>(value);
}
value_expr(E) ::= FLOAT(V). {
auto value = std::stod(V->value);
E = ast->create<ast::Float>(value);
}
value_expr(E) ::= STR(V). {
auto value = V->value.substr(1, V->value.size() - 2);
E = ast->create<ast::String>(value);
}
value_expr(E) ::= BOOL(V). {
auto value = V->value[0] == 't' || V->value[0] == 'T' ? true : false;
E = ast->create<ast::Boolean>(value);
}
%type pattern_expr {ast::Expr*}
pattern_expr(E) ::= pattern(P). {
E = ast->create<ast::PatternExpr>(P);
}
%type function_expr {ast::Expr*}
function_expr(E) ::= COUNT LP IDN(A) RP. {
E = ast->create<ast::CountFunction>(A->value);
}
function_expr(E) ::= LABELS LP IDN(A) RP. {
E = ast->create<ast::LabelsFunction>(A->value);
}
%type expr {ast::Expr*}
expr(E) ::= value_expr(V). {
E = V;
}
expr(E) ::= pattern_expr(P). {
E = P;
}
expr(E) ::= function_expr(F). {
E = F;
}
//%type alias {ast::Alias*}
//
//alias(A) ::= IDN(X) AS IDN(Y). {
// A = ast->create<ast::Alias>(X->value, Y->value);
//}
// set list
// e.g. MATCH (n) SET n.name = "Ryan", n.surname = "Giggs" RETURN n
%type set_list {ast::SetList*}
set_list(L) ::= set_element(E) COMMA set_list(N). {
L = ast->create<ast::SetList>(E, N);
}
set_list(L) ::= set_element(E). {
L = ast->create<ast::SetList>(E, nullptr);
}
%type set_element {ast::SetElementBase*}
set_element(E) ::= accessor(A) EQ set_value(V). {
E = ast->create<ast::SetElement>(A, V);
}
set_element(E) ::= idn(I) label_idn(L). {
E = ast->create<ast::LabelSetElement>(I, L);
}
%type accessor {ast::Accessor*}
accessor(A) ::= idn(E) DOT idn(P). {
A = ast->create<ast::Accessor>(E, P);
}
%type set_value {ast::SetValue*}
set_value(V) ::= value_expr(E). {
V = ast->create<ast::SetValue>(E);
}