Add SET conversion from low to highlevel ast

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D192
This commit is contained in:
Mislav Bradac 2017-03-28 10:20:20 +02:00
parent 7c36529aec
commit e40bd83636
6 changed files with 157 additions and 21 deletions

View File

@ -593,6 +593,7 @@ class SetProperties : public Clause {
}
Identifier *identifier_ = nullptr;
Expression *expression_ = nullptr;
bool update_ = false;
protected:
SetProperties(int uid) : Clause(uid) {}

View File

@ -22,7 +22,14 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery(
CypherParser::SingleQueryContext *ctx) {
query_ = storage_.query();
for (auto *child : ctx->clause()) {
query_->clauses_.push_back(child->accept(this));
antlrcpp::Any got = child->accept(this);
if (got.is<Clause *>()) {
query_->clauses_.push_back(got.as<Clause *>());
} else {
auto child_clauses = got.as<std::vector<Clause *>>();
query_->clauses_.insert(query_->clauses_.end(), child_clauses.begin(),
child_clauses.end());
}
}
// Construct unique names for anonymous identifiers;
int id = 1;
@ -54,6 +61,10 @@ antlrcpp::Any CypherMainVisitor::visitClause(CypherParser::ClauseContext *ctx) {
return static_cast<Clause *>(
ctx->cypherDelete()->accept(this).as<Delete *>());
}
if (ctx->set()) {
// Different return type!!!
return ctx->set()->accept(this).as<std::vector<Clause *>>();
}
// TODO: implement other clauses.
throw NotYetImplemented();
return 0;
@ -690,5 +701,57 @@ antlrcpp::Any CypherMainVisitor::visitWhere(CypherParser::WhereContext *ctx) {
where->expression_ = ctx->expression()->accept(this);
return where;
}
antlrcpp::Any CypherMainVisitor::visitSet(CypherParser::SetContext *ctx) {
std::vector<Clause *> set_items;
for (auto *set_item : ctx->setItem()) {
set_items.push_back(set_item->accept(this));
}
return set_items;
}
antlrcpp::Any CypherMainVisitor::visitSetItem(
CypherParser::SetItemContext *ctx) {
// SetProperty
if (ctx->propertyExpression()) {
auto *set_property = storage_.Create<SetProperty>();
set_property->property_lookup_ = ctx->propertyExpression()->accept(this);
set_property->expression_ = ctx->expression()->accept(this);
return static_cast<Clause *>(set_property);
}
// SetProperties either assignment or update
if (ctx->getTokens(kPropertyAssignmentTokenId).size() ||
ctx->getTokens(kPropertyUpdateTokenId).size()) {
auto *set_properties = storage_.Create<SetProperties>();
set_properties->identifier_ = storage_.Create<Identifier>(
ctx->variable()->accept(this).as<std::string>());
set_properties->expression_ = ctx->expression()->accept(this);
if (ctx->getTokens(kPropertyUpdateTokenId).size()) {
set_properties->update_ = true;
}
return static_cast<Clause *>(set_properties);
}
// SetLabels
auto *set_labels = storage_.Create<SetLabels>();
set_labels->identifier_ = storage_.Create<Identifier>(
ctx->variable()->accept(this).as<std::string>());
set_labels->labels_ =
ctx->nodeLabels()->accept(this).as<std::vector<GraphDb::Label>>();
return static_cast<Clause *>(set_labels);
}
antlrcpp::Any CypherMainVisitor::visitPropertyExpression(
CypherParser::PropertyExpressionContext *ctx) {
Expression *expression = ctx->atom()->accept(this);
for (auto *lookup : ctx->propertyLookup()) {
auto property_lookup =
storage_.Create<PropertyLookup>(expression, lookup->accept(this));
expression = property_lookup;
}
// It is guaranteed by grammar that there is at least one propertyLookup.
return dynamic_cast<PropertyLookup *>(expression);
}
}
}

View File

@ -137,7 +137,7 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
CypherParser::SingleQueryContext *ctx) override;
/**
* @return Clause*
* @return Clause* or vector<Clause*>!!!
*/
antlrcpp::Any visitClause(CypherParser::ClauseContext *ctx) override;
@ -389,8 +389,8 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
CypherParser::NumberLiteralContext *ctx) override;
/**
* @return int64_t
*/
* @return int64_t
*/
antlrcpp::Any visitIntegerLiteral(
CypherParser::IntegerLiteralContext *ctx) override;
@ -411,6 +411,22 @@ class CypherMainVisitor : public antlropencypher::CypherBaseVisitor {
*/
antlrcpp::Any visitWhere(CypherParser::WhereContext *ctx) override;
/**
* return vector<Clause*>
*/
antlrcpp::Any visitSet(CypherParser::SetContext *ctx) override;
/**
* @return Clause*
*/
antlrcpp::Any visitSetItem(CypherParser::SetItemContext *ctx) override;
/**
* @return PropertyLookup*
*/
antlrcpp::Any visitPropertyExpression(
CypherParser::PropertyExpressionContext *ctx) override;
public:
Query *query() { return query_; }
const static std::string kAnonPrefix;

View File

@ -7,19 +7,21 @@ using antlropencypher::CypherParser;
// List of unnamed tokens visitor needs to use. This should be reviewed on every
// grammar change since even changes in ordering of rules will cause antlr to
// generate different constants for unnamed tokens.
const auto kReturnAllTokenId = CypherParser::T__4; // *
const auto kDotsTokenId = CypherParser::T__11; // ..
const auto kEqTokenId = CypherParser::T__2; // =
const auto kNeTokenId1 = CypherParser::T__18; // <>
const auto kNeTokenId2 = CypherParser::T__19; // !=
const auto kLtTokenId = CypherParser::T__20; // <
const auto kGtTokenId = CypherParser::T__21; // >
const auto kLeTokenId = CypherParser::T__22; // <=
const auto kGeTokenId = CypherParser::T__23; // >=
const auto kPlusTokenId = CypherParser::T__12; // +
const auto kMinusTokenId = CypherParser::T__13; // -
const auto kMultTokenId = CypherParser::T__4; // *
const auto kDivTokenId = CypherParser::T__14; // /
const auto kModTokenId = CypherParser::T__15; // %
const auto kUnaryPlusTokenId = CypherParser::T__12; // +
const auto kUnaryMinusTokenId = CypherParser::T__13; // -
const auto kReturnAllTokenId = CypherParser::T__4; // *
const auto kDotsTokenId = CypherParser::T__11; // ..
const auto kEqTokenId = CypherParser::T__2; // =
const auto kNeTokenId1 = CypherParser::T__18; // <>
const auto kNeTokenId2 = CypherParser::T__19; // !=
const auto kLtTokenId = CypherParser::T__20; // <
const auto kGtTokenId = CypherParser::T__21; // >
const auto kLeTokenId = CypherParser::T__22; // <=
const auto kGeTokenId = CypherParser::T__23; // >=
const auto kPlusTokenId = CypherParser::T__12; // +
const auto kMinusTokenId = CypherParser::T__13; // -
const auto kMultTokenId = CypherParser::T__4; // *
const auto kDivTokenId = CypherParser::T__14; // /
const auto kModTokenId = CypherParser::T__15; // %
const auto kUnaryPlusTokenId = CypherParser::T__12; // +
const auto kUnaryMinusTokenId = CypherParser::T__13; // -
const auto kPropertyAssignmentTokenId = CypherParser::T__2; // =
const auto kPropertyUpdateTokenId = CypherParser::T__3; // +=

View File

@ -53,7 +53,7 @@ mergeAction : ( ON SP MATCH SP set )
create : CREATE SP? pattern ;
set : SET SP? setItem ( ',' setItem )* ;
set : SET SP? setItem ( SP? ',' SP? setItem )* ;
setItem : ( propertyExpression SP? '=' SP? expression )
| ( variable SP? '=' SP? expression )

View File

@ -615,4 +615,58 @@ TEST(Visitor, MatchWhere) {
ASSERT_TRUE(identifier);
ASSERT_EQ(identifier->name_, "n");
}
TEST(Visitor, Set) {
AstGenerator ast_generator("SET a.x = b, c = d, e += f, g : h : i ");
auto *query = ast_generator.query_;
ASSERT_EQ(query->clauses_.size(), 4U);
{
auto *set_property = dynamic_cast<SetProperty *>(query->clauses_[0]);
ASSERT_TRUE(set_property);
ASSERT_TRUE(set_property->property_lookup_);
auto *identifier1 =
dynamic_cast<Identifier *>(set_property->property_lookup_->expression_);
ASSERT_TRUE(identifier1);
ASSERT_EQ(identifier1->name_, "a");
ASSERT_EQ(set_property->property_lookup_->property_,
ast_generator.db_accessor_->property("x"));
auto *identifier2 = dynamic_cast<Identifier *>(set_property->expression_);
ASSERT_EQ(identifier2->name_, "b");
}
{
auto *set_properties_assignment =
dynamic_cast<SetProperties *>(query->clauses_[1]);
ASSERT_TRUE(set_properties_assignment);
ASSERT_FALSE(set_properties_assignment->update_);
ASSERT_TRUE(set_properties_assignment->identifier_);
ASSERT_EQ(set_properties_assignment->identifier_->name_, "c");
auto *identifier =
dynamic_cast<Identifier *>(set_properties_assignment->expression_);
ASSERT_EQ(identifier->name_, "d");
}
{
auto *set_properties_update =
dynamic_cast<SetProperties *>(query->clauses_[2]);
ASSERT_TRUE(set_properties_update);
ASSERT_TRUE(set_properties_update->update_);
ASSERT_TRUE(set_properties_update->identifier_);
ASSERT_EQ(set_properties_update->identifier_->name_, "e");
auto *identifier =
dynamic_cast<Identifier *>(set_properties_update->expression_);
ASSERT_EQ(identifier->name_, "f");
}
{
auto *set_labels = dynamic_cast<SetLabels *>(query->clauses_[3]);
ASSERT_TRUE(set_labels);
ASSERT_TRUE(set_labels->identifier_);
ASSERT_EQ(set_labels->identifier_->name_, "g");
ASSERT_THAT(set_labels->labels_,
UnorderedElementsAre(ast_generator.db_accessor_->label("h"),
ast_generator.db_accessor_->label("i")));
}
}
}