diff --git a/assignments/PA4/bad_expr.cl b/assignments/PA4/bad_expr.cl index 6dbf808..73b75e0 100644 --- a/assignments/PA4/bad_expr.cl +++ b/assignments/PA4/bad_expr.cl @@ -1,15 +1,31 @@ +class Ok1{}; +class Ok2_1 inherits Ok1 {}; +class Ok2_2 inherits Ok1 {}; + class ErrTest { errCase(): Bool { { case (new NOEXIST) of - x1: Bool => true; - x2: Int => x2 <- 10; - x3: NOEXIST => x3 + 10; - x3: NOEXIST => new Object; - x4: Int => x4 + true; - x4: Object => 111; - x5: SELF_TYPE => self; - x5: SELF_TYPE => self; + x1: + Bool => true; + x2: + Int => x2 <- 10; + x3: + NOEXIST => x3 + 10; + x3: + NOEXIST => new Object; + x4: + Int => x4 + true; + x4: + Object => 111; + x5: + SELF_TYPE => self; + x5: + SELF_TYPE => self; + esac; + 1 + case (new Ok2_2) of + x1 : Ok2_1 => new Ok2_1; + x2 : Ok2_2 => new Ok2_2; esac; } }; @@ -28,6 +44,7 @@ class ErrTest { errLet(): Object { let x1:NOEXIST, x2:Int<-10, x3:NOEXIST <- x1, x4:Bool <- 10 in { x1 <- attr1 + x1; + 10 + (self <- 10 + false); } }; attr1: NOEXIST; @@ -46,12 +63,17 @@ class Main { attr1: Bool <- (new Err5).hello(); attr2: Int <- (new Err5).bye(); self(): SELF_TYPE { new SELF_TYPE }; + attr3: NOEXIST <- 10; main(): Object { { - let x:Int in { + attr3.hello(1 + false) + 10; + let x:Int, y:NOEXIST in { x1 <- x + 1; x <- false; x <- x1; + attr3 * 10; + y * 10; + if (y) then y else attr3 fi; }; while (1 + 1) loop x1 <- true @@ -60,7 +82,8 @@ class Main { (new ErrMethods).errMethod(true + false); (new ErrMethods).errMethod2(false, false); (new ErrMethods).errMethod2(true + false); - attr2@Main.hello(); + attr2@SELF_TYPE.hello(); + self@Main.self(); } }; }; \ No newline at end of file diff --git a/assignments/PA4/bad_inherit.cl b/assignments/PA4/bad_inherit.cl index a4409b3..f4c9579 100644 --- a/assignments/PA4/bad_inherit.cl +++ b/assignments/PA4/bad_inherit.cl @@ -88,6 +88,10 @@ class Main inherits DummyMain { main: Bool <- true + false; }; +class SELF_TYPE { + +}; + class Err5 { ala: Bool <- 20; -- hello() : Object {{ala <- ala + 1;}}; diff --git a/assignments/PA4/gen_debug_input.sh b/assignments/PA4/gen_debug_input.sh new file mode 100755 index 0000000..4b11592 --- /dev/null +++ b/assignments/PA4/gen_debug_input.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -ex +./lexer $* | ./parser $* > debug_input.in \ No newline at end of file diff --git a/assignments/PA4/good.cl b/assignments/PA4/good.cl index b210046..027b206 100644 --- a/assignments/PA4/good.cl +++ b/assignments/PA4/good.cl @@ -1,7 +1,7 @@ class C { a : Int; b : Bool; - init(x : Int, y : Bool) : C { + init(x : Int, y : Bool) : SELF_TYPE { { a <- x; b <- y; @@ -11,7 +11,15 @@ class C { }; Class Main { + good() : Bool { true }; + self_method() : SELF_TYPE { self }; main():C { - (new C).init(1,true) + { + new SELF_TYPE.good(); + (new C).init(1,true); + isvoid true; + isvoid false; + isvoid x; + } }; }; diff --git a/assignments/PA4/semant.cc b/assignments/PA4/semant.cc index 0277865..0ed2e91 100644 --- a/assignments/PA4/semant.cc +++ b/assignments/PA4/semant.cc @@ -100,7 +100,10 @@ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) /* first scan: de-duplicate class definitions*/ for (auto i = classes->first(); classes->more(i); i = classes->next(i)) { auto class_i = static_cast(classes->nth(i)); - if (name_to_node.find(class_i->get_name()) != name_to_node.end()) { + if (class_i->get_name() == SELF_TYPE) { + semant_error(class_i) << "Redefinition of basic class SELF_TYPE.\n"; + } + else if (name_to_node.find(class_i->get_name()) != name_to_node.end()) { semant_error(class_i) << "Class " << class_i->get_name() << " was previously defined.\n"; } else { @@ -161,12 +164,16 @@ void ClassTable::symtab_dump(Symbol class_name) { std::cerr << "--------\n\n"; } -Symbol ClassTable::symtab_object_lookup_parent(Symbol class_name, Symbol object_name) { +Symbol ClassTable::symtab_object_lookup_parent(Class_ class_i, Symbol object_name) const { + return symtab_object_lookup_parent(class_to_name(class_i), object_name); +} + +Symbol ClassTable::symtab_object_lookup_parent(Symbol class_name, Symbol object_name) const { assert(name_to_node.find(class_name) != name_to_node.end()); - auto class_node = name_to_node[class_name]; - auto parent_node= class_node->parent; + auto class_node = name_to_node.find(class_name)->second; + auto parent_node= class_node; while (parent_node) { - auto result = _symtab_obj[parent_node->get_class()->get_name()]->probe(object_name); + auto result = _symtab_obj.find(parent_node->get_class()->get_name())->second->lookup(object_name); // only need to lookup in the top scope, because attributes all reside in top scope if (result) return result; parent_node = parent_node->parent; @@ -174,12 +181,16 @@ Symbol ClassTable::symtab_object_lookup_parent(Symbol class_name, Symbol object_ return nullptr; } -method_class* ClassTable::symtab_method_lookup_parent(Symbol class_name, Symbol method_name) { +method_class* ClassTable::symtab_method_lookup_parent(Class_ class_i, Symbol method_name) const { + return symtab_method_lookup_parent(class_to_name(class_i), method_name); +} + +method_class* ClassTable::symtab_method_lookup_parent(Symbol class_name, Symbol method_name) const { assert(name_to_node.find(class_name) != name_to_node.end()); - auto class_node = name_to_node[class_name]; - auto parent_node= class_node->parent; + auto class_node = name_to_node.find(class_name)->second; + auto parent_node= class_node; while (parent_node) { - auto result = _symtab_met[parent_node->get_class()->get_name()]->probe(method_name); + auto result = _symtab_met.find(parent_node->get_class()->get_name())->second->lookup(method_name); // only need to lookup in the top scope, because attributes all reside in top scope if (result) return result; parent_node = parent_node->parent; @@ -256,7 +267,7 @@ void ClassTable::install_all_features() { << "In redefined method " << cur_method->get_name() << ", return type " << cur_method->get_return_type() << " is different from original return type" << overridden_method->get_return_type() - << "\n"; + << ".\n"; _error_flag = true; } else if (cur_method->get_formals()->len() != overridden_method->get_formals()->len()) { @@ -281,7 +292,7 @@ void ClassTable::install_all_features() { << "In redefined method " << cur_method->get_name() << ", parameter type " << cur_formal->get_type_decl() << " is different from original type" << overridden_formal->get_type_decl() - << "\n"; + << ".\n"; _error_flag = true; break; } @@ -473,12 +484,21 @@ ostream& ClassTable::semant_error() /* * Query the Inheritance Graph if T1 <= T0 +* * Note: if T1 inherits from(or is) T0, then T1 <= T0 +* +* Warning: if the type doesn't exist, by default return `TRUE` to stop +* error cascading */ bool ClassTable::conform(Symbol T1, Symbol T0) const { if (T1 == T0) return true; + if (!class_exist(T0) || !class_exist(T1)) + return true; auto cur_node_itr = name_to_node.find(T1); - assert(cur_node_itr != name_to_node.end()); + if (cur_node_itr == name_to_node.end()){ + std::cerr << "Comform: Escaping type T1 = " << T1 << "\n"; + assert(cur_node_itr != name_to_node.end()); + } auto cur_node = cur_node_itr->second; while (cur_node) { if (cur_node->get_class()->get_name() == T0) { @@ -489,17 +509,52 @@ bool ClassTable::conform(Symbol T1, Symbol T0) const { return false; } +bool ClassTable::conform_self(Symbol T1, Symbol T0, Symbol env_class) const { + if (T1 == T0) return true; + /* + * Add a special rule for SELF_TYPE: SELF_TYPE_c <= T0 if C <= T0 + */ + if (T1 == SELF_TYPE) { + return conform(env_class, T0); + } + if (T0 == SELF_TYPE) { + return false; + } + else { + return conform(T1, T0); + } +} + +bool ClassTable::conform_self(Symbol T1, Symbol T0, Class_ env_class) const { + return conform_self(T1, T0, class_to_name(env_class)); +} + bool ClassTable::class_exist(Symbol class_id) const { - if (class_id == SELF_TYPE) return true; return name_to_node.find(class_id) != name_to_node.end(); } +/* +* Check Class existence allowing `SELF_TYPE` to be a valid type name +* `SELF_TYPE` may be used in the following places: No other uses are permitted. +* - new SELF TYPE +* - return type of a method, +* - declared type of a let variable +* - declared type of an attribute +*/ +bool ClassTable::class_exist_self(Symbol class_id) const { + if (class_id == SELF_TYPE) return true; + else return class_exist(class_id); +} + Symbol ClassTable::lub(Symbol T1, Symbol T2) const { if (T1 == T2) return T1; auto node1_iter = name_to_node.find(T1); auto node2_iter = name_to_node.find(T2); - assert(node1_iter != name_to_node.end()); - assert(node2_iter != name_to_node.end()); + // assert(node1_iter != name_to_node.end()); + // assert(node2_iter != name_to_node.end()); + if (node1_iter == name_to_node.end() || node2_iter == name_to_node.end()) { + return Object; + } auto node1 = node1_iter->second; auto node2 = node2_iter->second; ClassGraphNode* node_lower = nullptr; @@ -530,6 +585,11 @@ Symbol ClassTable::lub(Symbol T1, Symbol T2) const { return node_lower->get_class()->get_name(); } +Symbol ClassTable::lub(Symbol T1, Symbol T2, Symbol env_class) const { + if (T1 == SELF_TYPE) T1 = env_class; + if (T2 == SELF_TYPE) T2 = env_class; + return lub(T1, T2); +} /* This is the entry point to the semantic checker. Your checker should do the following two things: @@ -589,12 +649,11 @@ void attr_class::semant(Class_ cur_class, ClassTable * classtable) * Check if Declared Type is defined, if so, do nothing because already * in AST; else, error report and set its type to Object */ - if (!classtable->class_exist(type_decl)) { + if (!classtable->class_exist_self(type_decl)) { classtable->semant_error(cur_class->get_filename(), this) << "Class " << type_decl << " of attribute " << name << " is undefined.\n"; - this->type_decl = Object; } /* * Attr-Init: @@ -603,13 +662,13 @@ void attr_class::semant(Class_ cur_class, ClassTable * classtable) */ if (typeid(*init) != typeid(no_expr_class)) { auto rhs_type = init->semant(cur_class, classtable); - std::cerr << "attr init rhs type=" << rhs_type << "\n"; - if (!classtable->conform(rhs_type, type_decl)) { + // std::cerr << "attr init rhs type=" << rhs_type << "\n"; + if (!classtable->conform_self(rhs_type, type_decl, cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "Inferred type " << rhs_type << " of initialization of attribute " << name << " does not conform to declared type " << type_decl - << " .\n"; + << ".\n"; this->type_decl = Object; } } @@ -623,7 +682,11 @@ void method_class::semant(Class_ cur_class, ClassTable * classtable) auto formal_i = static_cast(formals->nth(i)); auto formal_i_name = formal_i->get_name(); auto formal_i_type = formal_i->get_type_decl(); - if (symtab_obj->probe(formal_i_name) == nullptr) { + if (formal_i_name == self) { + classtable->semant_error(cur_class->get_filename(), formal_i) + << "\'self\' cannot be the name of a formal parameter.\n"; + } + else if (symtab_obj->probe(formal_i_name) == nullptr) { symtab_obj->addid(formal_i_name, formal_i_type); } else { @@ -639,8 +702,14 @@ void method_class::semant(Class_ cur_class, ClassTable * classtable) } } auto expr_type = this->expr->semant(cur_class, classtable); + if (!classtable->class_exist_self(this->return_type)) { + classtable->semant_error(cur_class->get_filename(), this) + << "Undefined return type " << this->return_type + << " in method " << this->name + << ".\n"; + } symtab_obj->exitscope(); - if (!classtable->conform(expr_type, this->return_type)) { + if (!classtable->conform_self(expr_type, this->return_type, cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "Inferred return type " << expr_type << " of method " << this->name @@ -656,24 +725,26 @@ void method_class::semant(Class_ cur_class, ClassTable * classtable) */ Symbol assign_class::semant(Class_ cur_class, ClassTable* classtable) { - auto lhs_type = classtable->symtab_obj(cur_class)->lookup(name); + // auto lhs_type = classtable->symtab_obj(cur_class)->lookup(name); + if (this->name == self) { + classtable->semant_error(cur_class->get_filename(), this) + << "Cannot assign to 'self'.\n"; + } + auto lhs_type = classtable->symtab_object_lookup_parent(cur_class, name); if (lhs_type == nullptr) { classtable->semant_error(cur_class->get_filename(), this) - << "Assignment to undeclared variable " << name << "\n"; + << "Assignment to undeclared variable " << name << ".\n"; lhs_type = Object; } auto rhs_type = this->expr->semant(cur_class, classtable); - if (!classtable->conform(rhs_type, lhs_type)) { + if (!classtable->conform_self(rhs_type, lhs_type, cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "Type " << rhs_type << " of assigned expression does not conform to declared type " << lhs_type << " of identifier " << name - << " .\n"; - this->type = Object; - } - else { - this->type = rhs_type; + << ".\n"; } + this->type = rhs_type; return this->type; } @@ -687,13 +758,19 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable) _param_type.push_back(param_i_type); } if (!classtable->class_exist(this->type_name)) { - classtable->semant_error(cur_class->get_filename(), this) - << "Static dispatch to undefined class " << this->type_name - << ".\n"; + if (this->type_name == SELF_TYPE){ + classtable->semant_error(cur_class->get_filename(), this) + << "Static dispatch to SELF_TYPE.\n"; + } + else { + classtable->semant_error(cur_class->get_filename(), this) + << "Static dispatch on undefined class " << this->type_name + << ".\n"; + } this->type = Object; return this->type; } - if (!classtable->conform(expr_type, this->type_name)) { + if (!classtable->conform_self(expr_type, this->type_name, cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "Expression type " << expr_type << " does not conform to declared static dispatch type " << this->type_name @@ -701,18 +778,19 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable) this->type = Object; return this->type; } - auto symtab_method = classtable->symtab_met(this->type_name); - auto cur_method = symtab_method->lookup(name); + // auto symtab_method = classtable->symtab_met(this->type_name); + // auto cur_method = symtab_method->lookup(name); + auto cur_method = classtable->symtab_method_lookup_parent(this->type_name, this->name); if (cur_method == nullptr) { classtable->semant_error(cur_class->get_filename(), this) - << " Dispatch to undefined method " << name + << "Static dispatch to undefined method " << name << ".\n"; this->type = Object; return Object; } if (actual->len() != cur_method->get_formals()->len()) { classtable->semant_error(cur_class->get_filename(), this) - << " Method " << name + << "Method " << name << " called with wrong number of arguments.\n"; this->type = Object; return Object; @@ -721,7 +799,7 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable) auto _param_type_iter = _param_type.begin(); for (auto i = formals->first(); formals->more(i); i = formals->next(i)) { auto formal_i = static_cast(formals->nth(i)); - if (!classtable->conform(*_param_type_iter, formal_i->get_type_decl())) { + if (!classtable->conform_self(*_param_type_iter, formal_i->get_type_decl(), cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "In call of method " << cur_method->get_name() << ", type " << *_param_type_iter @@ -733,7 +811,8 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable) } auto return_type = cur_method->get_return_type(); if (return_type == SELF_TYPE) { - return_type = expr_type; + return_type = expr_type; + // if expr_type (T_0) is SELF_TYPE, then dispath type just keep it } this->type = return_type; return this->type; @@ -747,35 +826,53 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable) */ Symbol dispatch_class::semant(Class_ cur_class, ClassTable* classtable) { - auto expr_type = expr->semant(cur_class, classtable); - std::vector _param_type; + auto expr_type = expr->semant(cur_class, classtable); // T_0 + std::vector _param_type; // T_i for (auto i = actual->first(); actual->more(i); i = actual->next(i)) { auto param_i = actual->nth(i); auto param_i_type = param_i->semant(cur_class, classtable); _param_type.push_back(param_i_type); } - auto symtab_method = classtable->symtab_met(expr_type); - assert(symtab_method); - auto cur_method = symtab_method->lookup(name); - if (cur_method == nullptr) { + Symbol method_env_class = expr_type; // T_0' + if (expr_type == SELF_TYPE) { + method_env_class = classtable->class_to_name(cur_class); + } + if (!classtable->class_exist(method_env_class)) { classtable->semant_error(cur_class->get_filename(), this) - << " Dispatch to undefined method " << name + << "Dispatch on undefined class " << method_env_class + << ".\n"; + this->type = Object; + return this->type; + } + // auto symtab_method = classtable->symtab_met(method_env_class); + // auto cur_method = symtab_method->lookup(name); + auto cur_method = classtable->symtab_method_lookup_parent(method_env_class, this->name); + if (cur_method == nullptr) { + if (semant_debug) { + std::cerr << "lookup method " << this->name << " in class " << method_env_class << "\n"; + } + classtable->semant_error(cur_class->get_filename(), this) + << "Dispatch to undefined method " << name << ".\n"; this->type = Object; return Object; } if (actual->len() != cur_method->get_formals()->len()) { classtable->semant_error(cur_class->get_filename(), this) - << " Method " << name + << "Method " << name << " called with wrong number of arguments.\n"; this->type = Object; return Object; } - auto formals = cur_method->get_formals(); + auto formals = cur_method->get_formals(); // T_i' auto _param_type_iter = _param_type.begin(); - for (auto i = formals->first(); formals->more(i); i = formals->next(i)) { + for (auto i = formals->first(); + formals->more(i); + i = formals->next(i), ++_param_type_iter) + { auto formal_i = static_cast(formals->nth(i)); - if (!classtable->conform(*_param_type_iter, formal_i->get_type_decl())) { + auto formal_i_type = formal_i->get_type_decl(); + if (!classtable->conform_self(*_param_type_iter, formal_i_type, cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "In call of method " << cur_method->get_name() << ", type " << *_param_type_iter @@ -783,9 +880,9 @@ Symbol dispatch_class::semant(Class_ cur_class, ClassTable* classtable) << " does not conform to declared type " << formal_i->get_type_decl() << ".\n"; } - ++_param_type_iter; + } - auto return_type = cur_method->get_return_type(); + auto return_type = cur_method->get_return_type(); // T_n+1 if (return_type == SELF_TYPE) { return_type = expr_type; } @@ -851,7 +948,7 @@ Symbol typcase_class::semant(Class_ cur_class, ClassTable* classtable) _existed_type.insert(type_decl_i); } else { - classtable->semant_error(cur_class->get_filename(), this) + classtable->semant_error(cur_class->get_filename(), branch_i) << "Duplicate branch " << type_decl_i << " in case statement.\n"; } @@ -861,12 +958,12 @@ Symbol typcase_class::semant(Class_ cur_class, ClassTable* classtable) for later expr typing */ if (type_decl_i == SELF_TYPE) { - classtable->semant_error(cur_class->get_filename(), this) + classtable->semant_error(cur_class->get_filename(), branch_i) << "Identifier " << name_i << " declared with type SELF_TYPE in case branch.\n"; } else if (!classtable->class_exist(type_decl_i)) { - classtable->semant_error(cur_class->get_filename(), this) + classtable->semant_error(cur_class->get_filename(), branch_i) << "Class " << type_decl_i << " of case branch is undefined.\n"; } @@ -911,16 +1008,19 @@ Symbol block_class::semant(Class_ cur_class, ClassTable* classtable) */ Symbol let_class::semant(Class_ cur_class, ClassTable* classtable) { - if (!classtable->class_exist(type_decl)) { + if (this->identifier == self) { + classtable->semant_error(cur_class->get_filename(), this) + << "\'self\' cannot be bound in a \'let\' expression.\n"; + } + if (!classtable->class_exist_self(type_decl)) { classtable->semant_error(cur_class->get_filename(), this) << "Class " << type_decl - << " of attribute " << identifier + << " of let-bound identifier " << identifier << " is undefined.\n"; - this->type_decl = Object; } if (typeid(*init) != typeid(no_expr_class)) { auto init_type = init->semant(cur_class, classtable); - if (!classtable->conform(init_type, type_decl)) { + if (!classtable->conform_self(init_type, type_decl, cur_class)) { classtable->semant_error(cur_class->get_filename(), this) << "Inferred type " << init_type << " of initialization of " << identifier @@ -1148,13 +1248,13 @@ Symbol string_const_class::semant(Class_ cur_class, ClassTable* classtable) */ Symbol new__class::semant(Class_ cur_class, ClassTable* classtable) { - if (classtable->class_exist(this->type_name)) { + if (classtable->class_exist_self(this->type_name)) { this->type = this->type_name; } else { classtable->semant_error(cur_class->get_filename(), this) << "\'new\' used with undefined class " << this->type_name - << "\n"; + << ".\n"; this->type = Object; } return this->type; @@ -1167,14 +1267,18 @@ Symbol new__class::semant(Class_ cur_class, ClassTable* classtable) Symbol isvoid_class::semant(Class_ cur_class, ClassTable* classtable) { auto _ = this->e1->semant(cur_class, classtable); + this->type = Bool; return Bool; } /* +* NoExpr: * `no_expr` always has type `_no_type` +* However, this class should never be visited during type checking */ Symbol no_expr_class::semant(Class_ cur_class, ClassTable* classtable) { + assert(0); return No_type; } @@ -1185,14 +1289,19 @@ Symbol no_expr_class::semant(Class_ cur_class, ClassTable* classtable) */ Symbol object_class::semant(Class_ cur_class, ClassTable* classtable) { - auto object_type = classtable->symtab_obj(cur_class)->lookup(name); + auto object_type = classtable->symtab_object_lookup_parent(cur_class, name); if (object_type != nullptr) { this->type = object_type; return object_type; } else { + if (semant_debug) { + std::cerr << "Cannot find " << name << " in Class " << classtable->class_to_name(cur_class) << "\n"; + classtable->symtab_obj(cur_class)->dump(); + std::cerr << "-------------------\n"; + } classtable->semant_error(cur_class->get_filename(), this) - << "Undeclared identifier " << name<< "\n"; + << "Undeclared identifier " << name<< ".\n"; this->type = Object; return Object; } diff --git a/assignments/PA4/semant.h b/assignments/PA4/semant.h index e807d36..fc54562 100644 --- a/assignments/PA4/semant.h +++ b/assignments/PA4/semant.h @@ -156,23 +156,36 @@ public: /* helpers */ void install_all_features(); void symtab_dump(Symbol); - Symbol symtab_object_lookup_parent(Symbol, Symbol); - method_class* symtab_method_lookup_parent(Symbol, Symbol); + Symbol symtab_object_lookup_parent(Symbol, Symbol) const; + Symbol symtab_object_lookup_parent(Class_, Symbol) const; + method_class* symtab_method_lookup_parent(Symbol, Symbol) const; + method_class* symtab_method_lookup_parent(Class_, Symbol) const; bool conform(Symbol, Symbol) const; + bool conform_self(Symbol, Symbol, Symbol) const; + bool conform_self(Symbol, Symbol, Class_) const; bool class_exist(Symbol) const; + bool class_exist_self(Symbol) const; Symbol lub(Symbol, Symbol) const; + Symbol lub(Symbol, Symbol, Symbol) const; + static Symbol class_to_name(Class_ class_item) { return static_cast(class_item)->get_name(); } /* wrappers */ std::vector& class_vec() { return _class_vec; } - SymbolTable* symtab_obj(Class_ class_i) { + SymbolTable* symtab_obj(Class_ class_i) const { auto class_id = static_cast(class_i)->get_name(); - return _symtab_obj[class_id]; + auto _iter = _symtab_obj.find(class_id); + if (_iter == _symtab_obj.end()) return nullptr; + return _iter->second; }; - SymbolTable* symtab_met(Class_ class_i) { + SymbolTable* symtab_met(Class_ class_i) const { auto class_id = static_cast(class_i)->get_name(); - return _symtab_met[class_id]; + auto _iter = _symtab_met.find(class_id); + if (_iter == _symtab_met.end()) return nullptr; + return _iter->second; }; - SymbolTable* symtab_met(Symbol class_id) { - return _symtab_met[class_id]; + SymbolTable* symtab_met(Symbol class_id) const { + auto _iter = _symtab_met.find(class_id); + if (_iter == _symtab_met.end()) return nullptr; + return _iter->second; }; int errors() { return semant_errors; }