ready to debug
This commit is contained in:
@ -57,6 +57,7 @@ class ASTNodeVirturalVisitor : public ASTNodeVisitorBase {
|
|||||||
class ASTSemanticCheckVisitor : public ASTNodeVirturalVisitor {
|
class ASTSemanticCheckVisitor : public ASTNodeVirturalVisitor {
|
||||||
bool is_in_func;
|
bool is_in_func;
|
||||||
FunctionSchema cur_func_schema;
|
FunctionSchema cur_func_schema;
|
||||||
|
std::string cur_class_name;
|
||||||
size_t loop_level;
|
size_t loop_level;
|
||||||
std::shared_ptr<GlobalScope> global_scope;
|
std::shared_ptr<GlobalScope> global_scope;
|
||||||
friend std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNode> src);
|
friend std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNode> src);
|
||||||
|
@ -71,6 +71,7 @@ class FunctionScope : public ScopeBase {
|
|||||||
friend std::shared_ptr<class Program_ASTNode> CheckAndDecorate(std::shared_ptr<class Program_ASTNode> src);
|
friend std::shared_ptr<class Program_ASTNode> CheckAndDecorate(std::shared_ptr<class Program_ASTNode> src);
|
||||||
friend class Visitor;
|
friend class Visitor;
|
||||||
friend class ASTSemanticCheckVisitor;
|
friend class ASTSemanticCheckVisitor;
|
||||||
|
friend class GlobalScope;
|
||||||
FunctionSchema schema;
|
FunctionSchema schema;
|
||||||
bool add_variable([[maybe_unused]] const std::string &name, [[maybe_unused]] const ExprTypeInfo &type) override {
|
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");
|
throw std::runtime_error("FunctionScope does not support add_variable");
|
||||||
@ -99,6 +100,8 @@ class FunctionScope : public ScopeBase {
|
|||||||
};
|
};
|
||||||
class ClassDefScope : public ScopeBase {
|
class ClassDefScope : public ScopeBase {
|
||||||
friend class Visitor;
|
friend class Visitor;
|
||||||
|
friend class GlobalScope;
|
||||||
|
friend std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNode> src);
|
||||||
std::unordered_map<std::string, ExprTypeInfo> member_variables;
|
std::unordered_map<std::string, ExprTypeInfo> member_variables;
|
||||||
std::unordered_map<std::string, std::shared_ptr<FunctionScope>> member_functions;
|
std::unordered_map<std::string, std::shared_ptr<FunctionScope>> member_functions;
|
||||||
bool add_variable(const std::string &name, const ExprTypeInfo &type) override {
|
bool add_variable(const std::string &name, const ExprTypeInfo &type) override {
|
||||||
@ -156,6 +159,32 @@ class GlobalScope : public ScopeBase {
|
|||||||
std::unordered_map<std::string, ExprTypeInfo> global_variables;
|
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<FunctionScope>> global_functions;
|
||||||
std::unordered_map<std::string, std::shared_ptr<ClassDefScope>> classes;
|
std::unordered_map<std::string, std::shared_ptr<ClassDefScope>> classes;
|
||||||
|
ExprTypeInfo FetchClassMemberVariable(const std::string &class_name, const std::string &var_name) {
|
||||||
|
if (classes.find(class_name) == classes.end()) {
|
||||||
|
throw SemanticError("Class " + class_name + " not found", 1);
|
||||||
|
}
|
||||||
|
auto ptr = classes[class_name];
|
||||||
|
if (ptr->member_variables.find(var_name) == ptr->member_variables.end()) {
|
||||||
|
throw SemanticError("Variable " + var_name + " not found in class " + class_name, 1);
|
||||||
|
}
|
||||||
|
return ptr->member_variables[var_name];
|
||||||
|
}
|
||||||
|
FunctionSchema FetchClassMemberFunction(const std::string &class_name, const std::string &func_name) {
|
||||||
|
if (classes.find(class_name) == classes.end()) {
|
||||||
|
throw SemanticError("Class " + class_name + " not found", 1);
|
||||||
|
}
|
||||||
|
auto ptr = classes[class_name];
|
||||||
|
if (ptr->member_functions.find(func_name) == ptr->member_functions.end()) {
|
||||||
|
throw SemanticError("Function " + func_name + " not found in class " + class_name, 1);
|
||||||
|
}
|
||||||
|
return ptr->member_functions[func_name]->schema;
|
||||||
|
}
|
||||||
|
FunctionSchema FetchFunction(const std::string &name) {
|
||||||
|
if (global_functions.find(name) == global_functions.end()) {
|
||||||
|
throw SemanticError("Function " + name + " not found", 1);
|
||||||
|
}
|
||||||
|
return global_functions[name]->schema;
|
||||||
|
}
|
||||||
bool add_class(const std::string &name, std::shared_ptr<ClassDefScope> ptr) {
|
bool add_class(const std::string &name, std::shared_ptr<ClassDefScope> ptr) {
|
||||||
if (IsKeyWord(name)) return false;
|
if (IsKeyWord(name)) return false;
|
||||||
if (classes.find(name) != classes.end()) {
|
if (classes.find(name) != classes.end()) {
|
||||||
|
@ -67,4 +67,28 @@ struct ArrayType {
|
|||||||
IdentifierType basetype;
|
IdentifierType basetype;
|
||||||
size_t level;
|
size_t level;
|
||||||
};
|
};
|
||||||
|
inline bool operator==(const ArrayType &l, const ArrayType &r) {
|
||||||
|
return l.has_base_type == r.has_base_type && l.basetype == r.basetype && l.level == r.level;
|
||||||
|
}
|
||||||
using ExprTypeInfo = std::variant<IdentifierType, ArrayType>;
|
using ExprTypeInfo = std::variant<IdentifierType, ArrayType>;
|
||||||
|
|
||||||
|
inline bool operator==(const ExprTypeInfo &l, const ExprTypeInfo &r) {
|
||||||
|
if (std::holds_alternative<IdentifierType>(r) && std::get<IdentifierType>(r) == "null") {
|
||||||
|
if (std::holds_alternative<IdentifierType>(l)) {
|
||||||
|
std::string l_type = std::get<IdentifierType>(l);
|
||||||
|
if (l_type == "int" || l_type == "bool" || l_type == "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<IdentifierType>(l)) {
|
||||||
|
return std::holds_alternative<IdentifierType>(r) && std::get<IdentifierType>(l) == std::get<IdentifierType>(r);
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ArrayType>(l)) {
|
||||||
|
return std::holds_alternative<ArrayType>(r) && std::get<ArrayType>(l) == std::get<ArrayType>(r);
|
||||||
|
}
|
||||||
|
throw std::runtime_error("something strange happened");
|
||||||
|
}
|
||||||
|
inline bool operator!=(const ExprTypeInfo &l, const ExprTypeInfo &r) { return !(l == r); }
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "astnode_visitor.h"
|
#include "astnode_visitor.h"
|
||||||
#include "scope.hpp"
|
#include "scope.hpp"
|
||||||
@ -17,6 +18,7 @@ void ASTSemanticCheckVisitor::ActuralVisit(ClassDef_ASTNode *node) {
|
|||||||
for (auto var : node->member_variables) {
|
for (auto var : node->member_variables) {
|
||||||
var->accept(this);
|
var->accept(this);
|
||||||
}
|
}
|
||||||
|
cur_class_name = node->class_name;
|
||||||
for (auto ch : node->sorted_children) {
|
for (auto ch : node->sorted_children) {
|
||||||
if (std::dynamic_pointer_cast<DefinitionStatement_ASTNode>(ch) == nullptr) {
|
if (std::dynamic_pointer_cast<DefinitionStatement_ASTNode>(ch) == nullptr) {
|
||||||
ch->accept(this);
|
ch->accept(this);
|
||||||
@ -59,7 +61,10 @@ void ASTSemanticCheckVisitor::ActuralVisit(ExprStatement_ASTNode *node) { node->
|
|||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(IfStatement_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(IfStatement_ASTNode *node) {
|
||||||
node->condition->accept(this);
|
node->condition->accept(this);
|
||||||
// TODO type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
|
if (node->condition->expr_type_info != standard) {
|
||||||
|
throw SemanticError("If condition must be bool", 1);
|
||||||
|
}
|
||||||
node->if_clause->accept(this);
|
node->if_clause->accept(this);
|
||||||
if (node->has_else_clause) {
|
if (node->has_else_clause) {
|
||||||
node->else_clause->accept(this);
|
node->else_clause->accept(this);
|
||||||
@ -68,7 +73,10 @@ void ASTSemanticCheckVisitor::ActuralVisit(IfStatement_ASTNode *node) {
|
|||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(WhileStatement_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(WhileStatement_ASTNode *node) {
|
||||||
node->condition->accept(this);
|
node->condition->accept(this);
|
||||||
// TODO type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
|
if (node->condition->expr_type_info != standard) {
|
||||||
|
throw SemanticError("While condition must be bool", 1);
|
||||||
|
}
|
||||||
loop_level++;
|
loop_level++;
|
||||||
node->loop_body->accept(this);
|
node->loop_body->accept(this);
|
||||||
loop_level--;
|
loop_level--;
|
||||||
@ -80,7 +88,10 @@ void ASTSemanticCheckVisitor::ActuralVisit(ForStatement_ASTNode *node) {
|
|||||||
}
|
}
|
||||||
if (node->condition) {
|
if (node->condition) {
|
||||||
node->condition->accept(this);
|
node->condition->accept(this);
|
||||||
// TODO type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
|
if (node->condition->expr_type_info != standard) {
|
||||||
|
throw SemanticError("For condition must be bool", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (node->update) {
|
if (node->update) {
|
||||||
node->update->accept(this);
|
node->update->accept(this);
|
||||||
@ -93,7 +104,16 @@ void ASTSemanticCheckVisitor::ActuralVisit(ForStatement_ASTNode *node) {
|
|||||||
void ASTSemanticCheckVisitor::ActuralVisit(JmpStatement_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(JmpStatement_ASTNode *node) {
|
||||||
if (loop_level == 0 && node->jmp_type > 0) throw SemanticError("Jump statement outside loop", 1);
|
if (loop_level == 0 && node->jmp_type > 0) throw SemanticError("Jump statement outside loop", 1);
|
||||||
if (node->jmp_type == 0) {
|
if (node->jmp_type == 0) {
|
||||||
// TODO : return type check
|
if (node->return_value) {
|
||||||
|
node->return_value->accept(this);
|
||||||
|
if (node->return_value->expr_type_info != cur_func_schema.return_type) {
|
||||||
|
throw SemanticError("Return type mismatch", 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cur_func_schema.return_type != "void") {
|
||||||
|
throw SemanticError("Return type mismatch", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,16 +125,20 @@ void ASTSemanticCheckVisitor::ActuralVisit(SuiteStatement_ASTNode *node) {
|
|||||||
|
|
||||||
// Expression AST Nodes
|
// Expression AST Nodes
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(NewArrayExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(NewArrayExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
|
||||||
for (size_t i = 0; i < node->dim_size.size(); i++) {
|
for (size_t i = 0; i < node->dim_size.size(); i++) {
|
||||||
if (node->dim_size[i]) {
|
if (node->dim_size[i]) {
|
||||||
node->dim_size[i]->accept(this);
|
node->dim_size[i]->accept(this);
|
||||||
// TODO type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->dim_size[i]->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Array dimension must be int", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node->has_initial_value) {
|
if (node->has_initial_value) {
|
||||||
node->initial_value->accept(this);
|
node->initial_value->accept(this);
|
||||||
// TODO type check
|
if (node->expr_type_info != node->initial_value->expr_type_info) {
|
||||||
|
throw SemanticError("Array type mismatch", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,82 +149,161 @@ void ASTSemanticCheckVisitor::ActuralVisit(NewExpr_ASTNode *node) {}
|
|||||||
void ASTSemanticCheckVisitor::ActuralVisit(AccessExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(AccessExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: member check
|
if (std::holds_alternative<ArrayType>(node->base->expr_type_info)) {
|
||||||
if (node->is_function) {
|
if (node->is_function && node->member == "size" && node->arguments.size() == 0) {
|
||||||
// TODO arg number check
|
node->expr_type_info = "int";
|
||||||
for (auto arg : node->arguments) {
|
return;
|
||||||
arg->accept(this);
|
|
||||||
// TODO type check
|
|
||||||
}
|
}
|
||||||
|
throw SemanticError("Access on non-class", 1);
|
||||||
|
}
|
||||||
|
std::string base_type;
|
||||||
|
try {
|
||||||
|
base_type = std::get<IdentifierType>(node->base->expr_type_info);
|
||||||
|
} catch (...) {
|
||||||
|
throw SemanticError("Access on non-class", 1);
|
||||||
|
}
|
||||||
|
if (node->is_function) {
|
||||||
|
auto schema = global_scope->FetchClassMemberFunction(base_type, node->member);
|
||||||
|
if (schema.arguments.size() != node->arguments.size()) {
|
||||||
|
throw SemanticError("Argument number mismatch", 1);
|
||||||
|
}
|
||||||
|
for (auto &arg : node->arguments) {
|
||||||
|
arg->accept(this);
|
||||||
|
if (arg->expr_type_info != schema.arguments[&arg - &node->arguments[0]].first) {
|
||||||
|
throw SemanticError("Argument type mismatch", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node->expr_type_info = global_scope->FetchClassMemberVariable(base_type, node->member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(IndexExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(IndexExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: dimension check
|
if (std::holds_alternative<IdentifierType>(node->base->expr_type_info)) {
|
||||||
|
throw SemanticError("Indexing on non-array", 1);
|
||||||
|
}
|
||||||
|
const auto &tp = std::get<ArrayType>(node->base->expr_type_info);
|
||||||
|
if (tp.level < node->indices.size()) {
|
||||||
|
throw SemanticError("Indexing on non-array", 1);
|
||||||
|
}
|
||||||
for (auto idx : node->indices) {
|
for (auto idx : node->indices) {
|
||||||
idx->accept(this);
|
idx->accept(this);
|
||||||
// TODO type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (idx->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Index must be int", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tp.level == node->indices.size()) {
|
||||||
|
node->expr_type_info = tp.basetype;
|
||||||
|
} else {
|
||||||
|
node->expr_type_info = ArrayType{true, tp.basetype, tp.level - node->indices.size()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(SuffixExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(SuffixExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->base->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Suffix operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(PrefixExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(PrefixExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->base->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Prefix operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(OppositeExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(OppositeExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->base->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Opposite operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(LNotExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(LNotExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
|
if (node->base->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Logical not operation on non-bool", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(BNotExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(BNotExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->base->accept(this);
|
node->base->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->base->expr_type_info != standard) {
|
||||||
|
throw SemanticError("Bitwise not operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(MDMExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(MDMExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("MDM operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(PMExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(PMExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo STRING = "string";
|
||||||
|
if (node->left->expr_type_info == STRING && node->right->expr_type_info == STRING) {
|
||||||
|
node->expr_type_info = STRING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("PM operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(RLExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(RLExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("RL operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(GGLLExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(GGLLExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo STRING = "string";
|
||||||
|
if (node->left->expr_type_info == STRING && node->right->expr_type_info == STRING) {
|
||||||
|
node->expr_type_info = "bool";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("GGLL operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = "bool";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(NEExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(NEExpr_ASTNode *node) {
|
||||||
@ -208,63 +311,91 @@ void ASTSemanticCheckVisitor::ActuralVisit(NEExpr_ASTNode *node) {
|
|||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
// TODO: type check
|
||||||
|
node->expr_type_info = "bool";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(BAndExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(BAndExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("BAnd operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(BXorExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(BXorExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("BXor operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(BOrExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(BOrExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "int";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("BOr operation on non-int", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(LAndExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(LAndExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("LAnd operation on non-bool", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(LOrExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(LOrExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->left->accept(this);
|
node->left->accept(this);
|
||||||
node->right->accept(this);
|
node->right->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
|
if (node->left->expr_type_info != standard || node->right->expr_type_info != standard) {
|
||||||
|
throw SemanticError("LOr operation on non-bool", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = standard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(TernaryExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(TernaryExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->condition->accept(this);
|
node->condition->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo standard = "bool";
|
||||||
node->src1->accept(this);
|
node->src1->accept(this);
|
||||||
node->src2->accept(this);
|
node->src2->accept(this);
|
||||||
// TODO: type check
|
if (node->src1->expr_type_info != node->src2->expr_type_info) {
|
||||||
|
throw SemanticError("Ternary operation on different type", 1);
|
||||||
|
}
|
||||||
|
node->expr_type_info = node->src1->expr_type_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(AssignExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(AssignExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
node->dest->accept(this);
|
node->dest->accept(this);
|
||||||
node->src->accept(this);
|
node->src->accept(this);
|
||||||
// TODO: check type and assignability
|
if (node->dest->expr_type_info != node->src->expr_type_info) {
|
||||||
|
throw SemanticError("Assign operation on different type", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(ThisExpr_ASTNode *node) {}
|
void ASTSemanticCheckVisitor::ActuralVisit(ThisExpr_ASTNode *node) {
|
||||||
|
// TODO
|
||||||
|
node->expr_type_info = cur_class_name;
|
||||||
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(ParenExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(ParenExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
|
||||||
node->expr->accept(this);
|
node->expr->accept(this);
|
||||||
node->expr_type_info = node->expr->expr_type_info;
|
node->expr_type_info = node->expr->expr_type_info;
|
||||||
}
|
}
|
||||||
@ -278,19 +409,33 @@ void ASTSemanticCheckVisitor::ActuralVisit(IDExpr_ASTNode *node) {
|
|||||||
void ASTSemanticCheckVisitor::ActuralVisit(FunctionCallExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(FunctionCallExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
// TODO: check function existence and arg number
|
// TODO: check function existence and arg number
|
||||||
for (auto arg : node->arguments) {
|
auto schema = global_scope->FetchFunction(node->func_name);
|
||||||
arg->accept(this);
|
std::cerr << "function to call is " << node->func_name << std::endl;
|
||||||
// TODO: type check
|
if (schema.arguments.size() != node->arguments.size()) {
|
||||||
|
throw SemanticError("Argument number mismatch", 1);
|
||||||
}
|
}
|
||||||
|
for (auto &arg : node->arguments) {
|
||||||
|
arg->accept(this);
|
||||||
|
int idx = &arg - &node->arguments[0]; // for debug;
|
||||||
|
if (arg->expr_type_info != schema.arguments[&arg - &node->arguments[0]].first) {
|
||||||
|
throw SemanticError("Argument type mismatch", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node->expr_type_info = schema.return_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(FormattedStringExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(FormattedStringExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
for (auto arg : node->exprs) {
|
for (auto arg : node->exprs) {
|
||||||
arg->accept(this);
|
arg->accept(this);
|
||||||
// TODO: type check
|
const static ExprTypeInfo valid_types[] = {"int", "bool", "string"};
|
||||||
|
if (arg->expr_type_info != valid_types[0] && arg->expr_type_info != valid_types[1] &&
|
||||||
|
arg->expr_type_info != valid_types[2]) {
|
||||||
|
throw SemanticError("Invalid type in formatted string", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
node->expr_type_info = "string";
|
||||||
|
}
|
||||||
|
|
||||||
void ASTSemanticCheckVisitor::ActuralVisit(ConstantExpr_ASTNode *node) {
|
void ASTSemanticCheckVisitor::ActuralVisit(ConstantExpr_ASTNode *node) {
|
||||||
// TODO: Implement this method
|
// TODO: Implement this method
|
||||||
@ -298,6 +443,28 @@ void ASTSemanticCheckVisitor::ActuralVisit(ConstantExpr_ASTNode *node) {
|
|||||||
if (std::holds_alternative<IdentifierType>(node->expr_type_info)) {
|
if (std::holds_alternative<IdentifierType>(node->expr_type_info)) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
;
|
std::string base_type;
|
||||||
|
bool found_base_type = false;
|
||||||
|
size_t found_level = 0;
|
||||||
|
std::function<void(ConstantExpr_ASTNode *, int)> search = [&](ConstantExpr_ASTNode *node, int depth) {
|
||||||
|
if (std::holds_alternative<IdentifierType>(node->expr_type_info)) {
|
||||||
|
if (!found_base_type) {
|
||||||
|
found_base_type = true;
|
||||||
|
base_type = std::get<IdentifierType>(node->expr_type_info);
|
||||||
|
found_level = depth;
|
||||||
|
} else {
|
||||||
|
if (base_type != std::get<IdentifierType>(node->expr_type_info) || found_level != depth) {
|
||||||
|
throw SemanticError("Invalid const array type", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const auto &sub_nodes = std::get<std::vector<std::shared_ptr<ConstantExpr_ASTNode>>>(node->value);
|
||||||
|
for (auto sub_node : sub_nodes) {
|
||||||
|
search(sub_node.get(), depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
search(node, 0);
|
||||||
|
node->expr_type_info = ArrayType{true, base_type, found_level};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,37 @@ std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNod
|
|||||||
}
|
}
|
||||||
ASTSemanticCheckVisitor visitor;
|
ASTSemanticCheckVisitor visitor;
|
||||||
visitor.global_scope = global_scope;
|
visitor.global_scope = global_scope;
|
||||||
global_scope->classes["string"] = nullptr; // TODO: add string class
|
global_scope->classes["string"] = std::make_shared<ClassDefScope>();
|
||||||
|
global_scope->classes["string"]->member_functions["length"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->classes["string"]->member_functions["length"]->schema.return_type = "int";
|
||||||
|
global_scope->classes["string"]->member_functions["substring"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->classes["string"]->member_functions["substring"]->schema.return_type = "string";
|
||||||
|
global_scope->classes["string"]->member_functions["substring"]->schema.arguments = {{"int", "left"},
|
||||||
|
{"int", "right"}};
|
||||||
|
global_scope->classes["string"]->member_functions["parseInt"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->classes["string"]->member_functions["parseInt"]->schema.return_type = "int";
|
||||||
|
global_scope->classes["string"]->member_functions["ord"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->classes["string"]->member_functions["ord"]->schema.return_type = "int";
|
||||||
|
global_scope->classes["string"]->member_functions["ord"]->schema.arguments = {{"int", "pos"}};
|
||||||
|
global_scope->global_functions["print"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["print"]->schema.return_type = "void";
|
||||||
|
global_scope->global_functions["print"]->schema.arguments = {{"string", "str"}};
|
||||||
|
global_scope->global_functions["println"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["println"]->schema.return_type = "void";
|
||||||
|
global_scope->global_functions["println"]->schema.arguments = {{"string", "str"}};
|
||||||
|
global_scope->global_functions["printInt"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["printInt"]->schema.return_type = "void";
|
||||||
|
global_scope->global_functions["printInt"]->schema.arguments = {{"int", "n"}};
|
||||||
|
global_scope->global_functions["printlnInt"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["printlnInt"]->schema.return_type = "void";
|
||||||
|
global_scope->global_functions["printlnInt"]->schema.arguments = {{"int", "n"}};
|
||||||
|
global_scope->global_functions["getString"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["getString"]->schema.return_type = "string";
|
||||||
|
global_scope->global_functions["getInt"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["getInt"]->schema.return_type = "int";
|
||||||
|
global_scope->global_functions["toString"] = std::make_shared<FunctionScope>();
|
||||||
|
global_scope->global_functions["toString"]->schema.return_type = "string";
|
||||||
|
global_scope->global_functions["toString"]->schema.arguments = {{"int", "n"}};
|
||||||
visitor.visit(src.get());
|
visitor.visit(src.get());
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ std::any Visitor::visitClass_constructor(MXParser::Class_constructorContext *con
|
|||||||
auto cur_scope = std::make_shared<FunctionScope>();
|
auto cur_scope = std::make_shared<FunctionScope>();
|
||||||
cur_scope->parent = nodetype_stk.back().second.get();
|
cur_scope->parent = nodetype_stk.back().second.get();
|
||||||
construct_func->current_scope = cur_scope;
|
construct_func->current_scope = cur_scope;
|
||||||
cur_scope->schema.return_type = "null";
|
cur_scope->schema.return_type = "void";
|
||||||
nodetype_stk.push_back({ASTNodeType::Constructor, construct_func->current_scope});
|
nodetype_stk.push_back({ASTNodeType::Constructor, construct_func->current_scope});
|
||||||
|
|
||||||
construct_func->func_body = std::dynamic_pointer_cast<SuiteStatement_ASTNode>(
|
construct_func->func_body = std::dynamic_pointer_cast<SuiteStatement_ASTNode>(
|
||||||
|
Reference in New Issue
Block a user