Add type checker which fills symbols for Ident

This commit is contained in:
Teon Banek 2017-03-11 17:57:10 +01:00
parent 8d8a1cef6a
commit fbf70de089
4 changed files with 164 additions and 3 deletions

View File

@ -348,7 +348,7 @@ set(memgraph_src_files
${src_dir}/database/graph_db.cpp
${src_dir}/database/graph_db_accessor.cpp
${src_dir}/query/stripper.cpp
${src_dir}/query/backend/cpp/cypher_main_visitor.cpp
${src_dir}/query/frontend/ast/cypher_main_visitor.cpp
${src_dir}/query/backend/cpp/typed_value.cpp
${src_dir}/query/frontend/ast/ast.cpp
)

View File

@ -11,10 +11,49 @@ namespace query {
class Frame;
class SymbolTable;
// Forward declares for TreeVisitorBase
class Query;
class Ident;
class Match;
class Return;
class Pattern;
class NodePart;
class EdgePart;
class TreeVisitorBase {
public:
// Start of the tree is a Query.
virtual void PreVisit(Query& query) {}
virtual void Visit(Query& query) = 0;
virtual void PostVisit(Query& query) {}
// Expressions
virtual void PreVisit(Ident& ident) {}
virtual void Visit(Ident& ident) = 0;
virtual void PostVisit(Ident& ident) {}
// Clauses
virtual void PreVisit(Match& match) {}
virtual void Visit(Match& match) = 0;
virtual void PostVisit(Match& match) {}
virtual void PreVisit(Return& ret) {}
virtual void Visit(Return& ret) = 0;
virtual void PostVisit(Return& ret) {}
// Pattern and its subparts.
virtual void PreVisit(Pattern& pattern) {}
virtual void Visit(Pattern& pattern) = 0;
virtual void PostVisit(Pattern& pattern) {}
virtual void PreVisit(NodePart& node_part) {}
virtual void Visit(NodePart& node_part) = 0;
virtual void PostVisit(NodePart& node_part) {}
virtual void PreVisit(EdgePart& edge_part) {}
virtual void Visit(EdgePart& edge_part) = 0;
virtual void PostVisit(EdgePart& edge_part) {}
};
class Tree {
public:
Tree(const int uid) : uid_(uid) {}
int uid() const { return uid_; }
virtual void Accept(TreeVisitorBase& visitor) = 0;
private:
const int uid_;
@ -29,9 +68,14 @@ class Ident : public Expr {
public:
std::string identifier_;
TypedValue Evaluate(Frame &frame, SymbolTable &symbol_table) override;
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
class Part {};
class Part : public Tree {};
class NodePart : public Part {
public:
@ -39,12 +83,24 @@ public:
// TODO: Mislav call GraphDb::label(label_name) to populate labels_!
std::vector<GraphDb::Label> labels_;
// TODO: properties
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
identifier_.Accept(visitor);
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
class EdgePart : public Part {
public:
Ident identifier_;
// TODO: finish this: properties, types...
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
identifier_.Accept(visitor);
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
class Clause : public Tree {};
@ -52,20 +108,52 @@ class Clause : public Tree {};
class Pattern : public Tree {
public:
std::vector<std::unique_ptr<Part>> node_parts_;
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
for (auto& node_part : node_parts_) {
node_part->Accept(visitor);
}
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
class Query : public Tree {
public:
std::vector<std::unique_ptr<Clause>> clauses_;
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
for (auto& clause : clauses_) {
clause->Accept(visitor);
}
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
class Match : public Clause {
public:
std::vector<std::unique_ptr<Pattern>> patterns_;
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
for (auto& pattern : patterns_) {
pattern->Accept(visitor);
}
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
class Return : public Clause {
public:
std::vector<std::unique_ptr<Expr>> exprs_;
void Accept(TreeVisitorBase& visitor) override {
visitor.PreVisit(*this);
for (auto& expr : exprs_) {
expr->Accept(visitor);
}
visitor.Visit(*this);
visitor.PostVisit(*this);
}
};
}

View File

@ -1,4 +1,4 @@
#include "query/backend/cpp/cypher_main_visitor.hpp"
#include "query/frontend/ast/cypher_main_visitor.hpp"
#include <climits>
#include <string>

View File

@ -0,0 +1,73 @@
#pragma once
#include "utils/exceptions/basic_exception.hpp"
#include "query/frontend/ast/ast.hpp"
#include "query/frontend/typecheck/symbol_table.hpp"
namespace query {
class TypeCheckVisitor : public TreeVisitorBase {
public:
TypeCheckVisitor(SymbolTable& symbol_table) : symbol_table_(symbol_table_) {}
// Start of the tree is a Query.
void Visit(Query& query) override {}
// Expressions
void Visit(Ident& ident) override {
Symbol symbol;
} if (scope_.in_pattern) {
symbol = GetOrCreateSymbol(ident.identifier_);
} else {
if (!HasSymbol(ident.identifier_))
// TODO: Special exception for type check
throw BasicException("Unbound identifier: " + ident.identifier_);
symbol = scope_.variables[ident.identifier_];
}
symbol_table_[ident] = symbol;
}
// Clauses
void Visit(Match& match) override {}
void PreVisit(Return& ret) override {
scope_.in_return = true;
}
void PostVisit(Return& ret) override {
scope_.in_return = false;
}
void Visit(Return& ret) override {}
// Pattern and its subparts.
void PreVisit(Pattern& pattern) override {
scope_.in_pattern = true;
}
void PostVisit(Pattern& pattern) override {
scope_.in_pattern = false;
}
void Visit(Pattern& pattern) override {}
void Visit(NodePart& node_part) override {}
void Visit(EdgePart& edge_part) override {}
private:
struct Scope {
Scope() : in_pattern(false), in_return(false) {}
bool in_pattern;
bool in_return;
std::map<std::string, Symbol> variables;
};
bool HasSymbol(const std::string& name)
{
return scope_.variables.find(name) != scope_.variables.end();
}
Symbol GetOrCreateSymbol(const std::string& name)
{
auto search = scope_.variables.find(name)
if (search != scope_.variables.end()) {
return *search;
}
scope_.variables[name] = symbol_table_.CreateSymbol(name);
}
SymbolTable& symbol_table_;
Scope scope_;
};
}