write symbol check
This commit is contained in:
@ -4,15 +4,11 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include "../semantic/visitor.h"
|
||||
#include "scope.hpp"
|
||||
#include "tools.h"
|
||||
using IdentifierType = std::string;
|
||||
struct ArrayType {
|
||||
bool has_base_type;
|
||||
IdentifierType basetype;
|
||||
size_t level;
|
||||
};
|
||||
using ExprTypeInfo = std::variant<IdentifierType, ArrayType>;
|
||||
class ASTNodeVisitorBase {
|
||||
friend Visitor;
|
||||
|
||||
public:
|
||||
virtual ~ASTNodeVisitorBase() = default;
|
||||
virtual void visit(class ASTNodeBase *context) = 0;
|
||||
@ -20,6 +16,9 @@ class ASTNodeVisitorBase {
|
||||
|
||||
class ASTNodeBase {
|
||||
friend Visitor;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ScopeBase> current_scope;
|
||||
ASTNodeType type;
|
||||
// std::vector<std::shared_ptr<ASTNodeBase>> children;
|
||||
size_t start_line, start_char_pos, end_line, end_char_pos;
|
||||
|
165
include/ast/scope.hpp
Normal file
165
include/ast/scope.hpp
Normal file
@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "tools.h"
|
||||
class ScopeBase {
|
||||
friend class Visitor;
|
||||
friend class LocalScope;
|
||||
friend class MemberFunctionScope;
|
||||
friend class FunctionScope;
|
||||
friend class ClassDefScope;
|
||||
friend class GlobalScope;
|
||||
|
||||
protected:
|
||||
ScopeBase *parent; // cannot use std::shared_ptr<ScopeBase> because of circular dependency
|
||||
virtual bool VariableNameAvailable(const std::string &name, int ttl) = 0;
|
||||
virtual bool add_variable(const std::string &name, const ExprTypeInfo &type) = 0;
|
||||
static inline bool IsKeyWord(const std::string &name) {
|
||||
static const std::unordered_set<std::string> keywords = {"void", "bool", "int", "string", "new", "class",
|
||||
"null", "true", "false", "this", "if", "else",
|
||||
"for", "while", "break", "continue", "return"};
|
||||
return keywords.find(name) != keywords.end();
|
||||
}
|
||||
};
|
||||
class LocalScope : public ScopeBase {
|
||||
friend class Visitor;
|
||||
std::unordered_map<std::string, ExprTypeInfo> local_variables;
|
||||
bool add_variable(const std::string &name, const ExprTypeInfo &type) override {
|
||||
if (!VariableNameAvailable(name, 0)) {
|
||||
throw std::runtime_error("Variable name " + name + " is not available");
|
||||
}
|
||||
local_variables[name] = type;
|
||||
return true;
|
||||
}
|
||||
bool VariableNameAvailable(const std::string &name, int ttl) override {
|
||||
if (ttl == 0 && IsKeyWord(name)) {
|
||||
return false;
|
||||
}
|
||||
if (ttl == 0) {
|
||||
if (local_variables.find(name) != local_variables.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return parent->VariableNameAvailable(name, ttl + 1);
|
||||
}
|
||||
};
|
||||
struct FunctionSchema {
|
||||
friend class Visitor;
|
||||
ExprTypeInfo return_type;
|
||||
std::vector<std::pair<ExprTypeInfo, std::string>> arguments;
|
||||
};
|
||||
class FunctionScope : public ScopeBase {
|
||||
friend class Visitor;
|
||||
FunctionSchema schema;
|
||||
bool add_variable([[maybe_unused]] const std::string &name, [[maybe_unused]] const ExprTypeInfo &type) override {
|
||||
throw std::runtime_error("FunctionScope does not support add_variable");
|
||||
}
|
||||
bool VariableNameAvailable(const std::string &name, int ttl) override {
|
||||
if (ttl == 0 && IsKeyWord(name)) {
|
||||
return false;
|
||||
}
|
||||
if (ttl == 1) {
|
||||
for (const auto &arg : schema.arguments) {
|
||||
if (arg.second == name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent->VariableNameAvailable(name, ttl + 1);
|
||||
}
|
||||
};
|
||||
class ClassDefScope : public ScopeBase {
|
||||
friend class Visitor;
|
||||
std::unordered_map<std::string, ExprTypeInfo> member_variables;
|
||||
std::unordered_map<std::string, std::shared_ptr<FunctionScope>> member_functions;
|
||||
bool add_variable(const std::string &name, const ExprTypeInfo &type) override {
|
||||
if (!VariableNameAvailable(name, 0)) {
|
||||
throw std::runtime_error("Variable name " + name + " is not available");
|
||||
}
|
||||
member_variables[name] = type;
|
||||
return true;
|
||||
}
|
||||
bool add_function(const std::string &name, std::shared_ptr<FunctionScope> ptr) {
|
||||
if (IsKeyWord(name)) return false;
|
||||
if (member_variables.find(name) != member_variables.end()) {
|
||||
return false;
|
||||
}
|
||||
if (member_functions.find(name) != member_functions.end()) {
|
||||
return false;
|
||||
}
|
||||
member_functions[name] = ptr;
|
||||
return true;
|
||||
}
|
||||
bool VariableNameAvailable(const std::string &name, int ttl) override {
|
||||
if (ttl == 0 && IsKeyWord(name)) {
|
||||
return false;
|
||||
}
|
||||
if (member_functions.find(name) != member_functions.end()) {
|
||||
return false;
|
||||
}
|
||||
return parent->VariableNameAvailable(name, ttl + 1);
|
||||
}
|
||||
};
|
||||
class GlobalScope : public ScopeBase {
|
||||
friend class Visitor;
|
||||
std::unordered_map<std::string, ExprTypeInfo> global_variables;
|
||||
std::unordered_map<std::string, std::shared_ptr<FunctionScope>> global_functions;
|
||||
std::unordered_map<std::string, std::shared_ptr<ClassDefScope>> classes;
|
||||
bool add_class(const std::string &name, std::shared_ptr<ClassDefScope> ptr) {
|
||||
if (IsKeyWord(name)) return false;
|
||||
if (classes.find(name) != classes.end()) {
|
||||
return false;
|
||||
}
|
||||
if (global_functions.find(name) != global_functions.end()) {
|
||||
return false;
|
||||
}
|
||||
if (global_variables.find(name) != global_variables.end()) {
|
||||
return false;
|
||||
}
|
||||
classes[name] = ptr;
|
||||
return true;
|
||||
}
|
||||
bool add_function(const std::string &name, std::shared_ptr<FunctionScope> ptr) {
|
||||
if (IsKeyWord(name)) return false;
|
||||
if (classes.find(name) != classes.end()) {
|
||||
return false;
|
||||
}
|
||||
if (global_functions.find(name) != global_functions.end()) {
|
||||
return false;
|
||||
}
|
||||
if (global_variables.find(name) != global_variables.end()) {
|
||||
return false;
|
||||
}
|
||||
global_functions[name] = ptr;
|
||||
return true;
|
||||
}
|
||||
bool add_variable(const std::string &name, const ExprTypeInfo &type) override {
|
||||
if (!VariableNameAvailable(name, 0)) {
|
||||
throw std::runtime_error("Variable name " + name + " is not available");
|
||||
}
|
||||
global_variables[name] = type;
|
||||
return true;
|
||||
}
|
||||
bool VariableNameAvailable(const std::string &name, [[maybe_unused]] int ttl) override {
|
||||
if (ttl == 0 && IsKeyWord(name)) {
|
||||
return false;
|
||||
}
|
||||
if (global_variables.find(name) != global_variables.end()) {
|
||||
return false;
|
||||
}
|
||||
if (classes.find(name) != classes.end()) {
|
||||
return false;
|
||||
}
|
||||
if (classes.find(name) != classes.end()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
GlobalScope() { parent = nullptr; }
|
||||
};
|
@ -4,9 +4,10 @@
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include "MXParserVisitor.h"
|
||||
#include "ast/scope.hpp"
|
||||
#include "tools.h"
|
||||
class Visitor : public MXParserVisitor {
|
||||
std::vector<ASTNodeType> nodetype_stk;
|
||||
std::vector<std::pair<ASTNodeType, std::shared_ptr<ScopeBase>>> nodetype_stk;
|
||||
|
||||
public:
|
||||
std::any visitMxprog(MXParser::MxprogContext *context) override;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
enum class ASTNodeType {
|
||||
// Expression nodes
|
||||
NewArrayExpr,
|
||||
@ -58,4 +59,12 @@ class SemanticError : public std::exception {
|
||||
SemanticError(const std::string &msg, int error_code) : msg(msg), error_code(error_code) {}
|
||||
const char *what() const noexcept override { return msg.c_str(); }
|
||||
int GetErrorCode() const { return error_code; }
|
||||
};
|
||||
};
|
||||
|
||||
using IdentifierType = std::string;
|
||||
struct ArrayType {
|
||||
bool has_base_type;
|
||||
IdentifierType basetype;
|
||||
size_t level;
|
||||
};
|
||||
using ExprTypeInfo = std::variant<IdentifierType, ArrayType>;
|
Reference in New Issue
Block a user