buggy prototype

This commit is contained in:
ridethepig 2023-03-26 15:41:09 +00:00
parent 1b3f14ab34
commit c5bbdde30b
5 changed files with 619 additions and 38 deletions

View File

@ -0,0 +1,66 @@
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;
esac;
}
};
errArith(): Object {
{
new NOEXIST;
true + 1;
1 + true;
(1 * false) + (true * 2);
1 + "" + true * true;
(~(not 2)) + 2;
1 = false;
not(~(not 2)<(not (true * true))) ;
}
};
errLet(): Object {
let x1:NOEXIST, x2:Int<-10, x3:NOEXIST <- x1, x4:Bool <- 10 in {
x1 <- attr1 + x1;
}
};
attr1: NOEXIST;
};
class ErrMethods {
errMethod(x1:Int, x1:Bool) : Bool {
x1
};
errMethod2(x1:Int, x2:NOEXIST) : Bool {
x2 + x1
};
};
class Main {
attr1: Bool <- (new Err5).hello();
attr2: Int <- (new Err5).bye();
self(): SELF_TYPE { new SELF_TYPE };
main(): Object {
{
let x:Int in {
x1 <- x + 1;
x <- false;
x <- x1;
};
while (1 + 1) loop
x1 <- true
pool;
if (1 + 1) then 2 else 3 fi;
(new ErrMethods).errMethod(true + false);
(new ErrMethods).errMethod2(false, false);
(new ErrMethods).errMethod2(true + false);
attr2@Main.hello();
}
};
};

View File

@ -57,7 +57,6 @@ class Err6Sub inherits Err6Base {
};
*)
class DummyMain {
la: Bool <- 20;
ala: Bool;
@ -74,7 +73,13 @@ class Main inherits DummyMain {
{
let x:Int in {
x1 <- x + 1;
x <- false;
x <- x1;
};
while (1 + 1) loop
x1 <- true
pool;
if (1 + 1) then 2 else 3 fi;
(new Err4).hello(true);
(new Err4).hello();
}

View File

@ -279,6 +279,10 @@ public:
Case copy_Case();
void dump(ostream& stream, int n);
Symbol get_name() const { return name; };
Symbol get_type_decl() const { return type_decl; };
Expression get_expr() const { return expr; };
#ifdef Case_SHARED_EXTRAS
Case_SHARED_EXTRAS
#endif

View File

@ -2,6 +2,7 @@
#include <cassert>
#include <iostream>
#include <set>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
@ -137,9 +138,9 @@ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr)
// Thus, we can start from object and mark all reachable nodes, error report those unreachable nodes
/* third scan: check cyclic inheritance */
class_root->traverse_reachable();
class_root->traverse_reachable(0);
for (auto i : name_to_node) {
if (!i.second->reachable) {
if (i.second->depth == 0) {
semant_error(i.second->get_class()) << "Class `" << i.first
<< "` or its ancestor, is involved in an inheritance cycle.\n";
}
@ -493,6 +494,42 @@ bool ClassTable::class_exist(Symbol class_id) const {
return name_to_node.find(class_id) != name_to_node.end();
}
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());
auto node1 = node1_iter->second;
auto node2 = node2_iter->second;
ClassGraphNode* node_lower = nullptr;
ClassGraphNode* node_upper = nullptr;
/* select the lower (further away to root) node */
if (node1->depth < node2->depth) {
node_lower = node2;
node_upper = node1;
node2 = node1 = nullptr;
}
else {
node_lower = node1;
node_upper = node2;
node2 = node1 = nullptr;
}
/* first let the lower node jump up to the same depth with the other node */
while (node_lower->depth > node_upper->depth) {
node_lower = node_lower->parent;
assert(node_lower != nullptr);
}
/* then jump together until they meet */
while (node_lower != node_upper) {
node_lower = node_lower->parent;
node_upper = node_upper->parent;
assert(node_lower != nullptr);
assert(node_upper != nullptr);
}
return node_lower->get_class()->get_name();
}
/* This is the entry point to the semantic checker.
Your checker should do the following two things:
@ -524,11 +561,11 @@ void program_class::semant()
for (auto class_i : classtable->class_vec()) {
// before we enter a class, add self:SELF_TYPE to its scope
// TODO: Maybe integrate this into last scan
classtable->symtab_obj(class_i->get_name())->enterscope();
classtable->symtab_obj(class_i->get_name())->addid(self, SELF_TYPE);
classtable->symtab_obj(class_i)->enterscope();
classtable->symtab_obj(class_i)->addid(self, SELF_TYPE);
class_i->semant(classtable);
// leave scope
classtable->symtab_obj(class_i->get_name())->exitscope();
classtable->symtab_obj(class_i)->exitscope();
}
if (classtable->errors()) {
@ -566,10 +603,11 @@ 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)) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Inferred type " << rhs_type
<< " of initialization of attribute " << name
<< " of initialization of attribute " << name
<< " does not conform to declared type " << type_decl
<< " .\n";
this->type_decl = Object;
@ -579,125 +617,583 @@ void attr_class::semant(Class_ cur_class, ClassTable * classtable)
void method_class::semant(Class_ cur_class, ClassTable * classtable)
{
auto symtab_obj = classtable->symtab_obj(cur_class);
symtab_obj->enterscope();
for (auto i = formals->first(); formals->more(i); i = formals->next(i)) {
auto formal_i = static_cast<formal_class*>(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) {
symtab_obj->addid(formal_i_name, formal_i_type);
}
else {
classtable->semant_error(cur_class->get_filename(), formal_i)
<< "Formal parameter " << formal_i_name
<< " is multiply defined.\n";
}
if (!classtable->class_exist(formal_i_type)) {
classtable->semant_error(cur_class->get_filename(), formal_i)
<< "Class " << formal_i_type
<< " of formal parameter " << formal_i_name
<< " is undefined.\n";
}
}
auto expr_type = this->expr->semant(cur_class, classtable);
symtab_obj->exitscope();
if (!classtable->conform(expr_type, this->return_type)) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Inferred return type " << expr_type
<< " of method " << this->name
<< " does not conform to declared return type " << this->return_type
<< ".\n";
}
}
/*
* ASSIGN:
* Given RHS:T' and Id:T, T is the declared type of Id in the env,
* there is T' <= T. Note that the type of the whole expression is T
*/
Symbol assign_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto lhs_type = classtable->symtab_obj(cur_class)->lookup(name);
if (lhs_type == nullptr) {
classtable->semant_error(cur_class->get_filename(), this)
<< "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)) {
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;
}
return this->type;
}
Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto expr_type = expr->semant(cur_class, classtable);
std::vector<Symbol> _param_type;
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);
}
if (!classtable->class_exist(this->type_name)) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Static dispatch to undefined class " << this->type_name
<< ".\n";
this->type = Object;
return this->type;
}
if (!classtable->conform(expr_type, this->type_name)) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Expression type " << expr_type
<< " does not conform to declared static dispatch type " << this->type_name
<< ".\n";
this->type = Object;
return this->type;
}
auto symtab_method = classtable->symtab_met(this->type_name);
auto cur_method = symtab_method->lookup(name);
if (cur_method == nullptr) {
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
<< " called with wrong number of arguments.\n";
this->type = Object;
return Object;
}
auto formals = cur_method->get_formals();
auto _param_type_iter = _param_type.begin();
for (auto i = formals->first(); formals->more(i); i = formals->next(i)) {
auto formal_i = static_cast<formal_class*>(formals->nth(i));
if (!classtable->conform(*_param_type_iter, formal_i->get_type_decl())) {
classtable->semant_error(cur_class->get_filename(), this)
<< "In call of method " << cur_method->get_name()
<< ", type " << *_param_type_iter
<< " of parameter " << formal_i->get_name()
<< " does not conform to declared type " << formal_i->get_type_decl()
<< ".\n";
}
++_param_type_iter;
}
auto return_type = cur_method->get_return_type();
if (return_type == SELF_TYPE) {
return_type = expr_type;
}
this->type = return_type;
return this->type;
}
/*
* Dispatch:
* Object type check
* Each of the param exprs get typed
* Check conformance of each param-formal pair
*/
Symbol dispatch_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto expr_type = expr->semant(cur_class, classtable);
std::vector<Symbol> _param_type;
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) {
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
<< " called with wrong number of arguments.\n";
this->type = Object;
return Object;
}
auto formals = cur_method->get_formals();
auto _param_type_iter = _param_type.begin();
for (auto i = formals->first(); formals->more(i); i = formals->next(i)) {
auto formal_i = static_cast<formal_class*>(formals->nth(i));
if (!classtable->conform(*_param_type_iter, formal_i->get_type_decl())) {
classtable->semant_error(cur_class->get_filename(), this)
<< "In call of method " << cur_method->get_name()
<< ", type " << *_param_type_iter
<< " of parameter " << formal_i->get_name()
<< " does not conform to declared type " << formal_i->get_type_decl()
<< ".\n";
}
++_param_type_iter;
}
auto return_type = cur_method->get_return_type();
if (return_type == SELF_TYPE) {
return_type = expr_type;
}
this->type = return_type;
return this->type;
}
/*
* If:
* Predicate must be Bool type
* Branches may have any static types
* Type of the whole expr is `lub(type(e1), type(e2))`
*/
Symbol cond_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto pred_type = this->pred->semant(cur_class, classtable);
if (pred_type != Bool) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Predicate of 'if' does not have type Bool.\n";
}
auto else_type = this->else_exp->semant(cur_class, classtable);
auto then_type = this->then_exp->semant(cur_class, classtable);
/* TODO: It seems unnecessary to check existence of else/then_type */
this->type = classtable->lub(else_type, then_type);
return this->type;
}
/*
* Loop:
* Predicate must be Bool
* Type of the entire loop is always Object
* Not care about loop body type, though still typing it
*/
Symbol loop_class::semant(Class_ cur_class, ClassTable* classtable)
{
auto pred_type = this->pred->semant(cur_class, classtable);
if (pred_type != Bool) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Loop condition does not have type Bool.\n";
}
auto _ = this->body->semant(cur_class, classtable);
this->type = Object;
return Object;
}
/*
* Case:
* For each branch, add xi:Ti to the env. Meanwhile they must have distinct types
* Type of the entire case is the join of its branches' types
* Note that SELF_TYPE is not allow here
*/
Symbol typcase_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto _ = this->expr->semant(cur_class, classtable);
std::set<Symbol> _existed_type;
Symbol entire_type = nullptr;
for (auto i = cases->first(); cases->more(i); i = cases->next(i)) {
auto branch_i = static_cast<branch_class*>(cases->nth(i));
auto type_decl_i = branch_i->get_type_decl();
auto name_i = branch_i->get_name();
// first check duplicated type
if (_existed_type.count(type_decl_i) == 0) {
_existed_type.insert(type_decl_i);
}
else {
classtable->semant_error(cur_class->get_filename(), this)
<< "Duplicate branch " << type_decl_i
<< " in case statement.\n";
}
/*then check existence of declared type
The reference semant program's behavior is quite strange here,
if the type does not exist, it continue to use the undefined type
for later expr typing
*/
if (type_decl_i == SELF_TYPE) {
classtable->semant_error(cur_class->get_filename(), this)
<< "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)
<< "Class " << type_decl_i
<< " of case branch is undefined.\n";
}
/* next add x[i]:T[i] to scope and type the rhs expr */
classtable->symtab_obj(cur_class)->enterscope();
classtable->symtab_obj(cur_class)->addid(name_i, type_decl_i);
auto branch_expr_type = branch_i->get_expr()->semant(cur_class, classtable);
classtable->symtab_obj(cur_class)->exitscope();
/* finally, remember to join expr types for the entire case's type*/
if (entire_type == nullptr) {
entire_type = branch_expr_type;
}
else {
entire_type = classtable->lub(entire_type, branch_expr_type);
}
}
this->type = entire_type;
return this->type;
}
/*
* Sequence:
* Iterate over the expr_list, type each expr and use the type of the last expr
*/
Symbol block_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
Symbol type_i;
for (auto i = body->first(); body->more(i); i = body->next(i)) {
type_i = body->nth(i)->semant(cur_class, classtable);
}
this->type = type_i;
return type_i;
}
/*
* Let:
* Since `let` exprs are nested in AST, we only need to handle only 1 identifier
* Check existence of declared type
* If there is an initializer, type it and check conformance with declared type
* Add the identifier to the scope and type the rhs expr
* Set the `let` expr's type to the type of rhs
*/
Symbol let_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
if (!classtable->class_exist(type_decl)) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Class " << type_decl
<< " of attribute " << 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)) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Inferred type " << init_type
<< " of initialization of " << identifier
<< " does not conform to identifier's declared type " << type_decl
<< ".\n";
}
}
classtable->symtab_obj(cur_class)->enterscope();
classtable->symtab_obj(cur_class)->addid(identifier, type_decl);
auto expr_type = this->body->semant(cur_class, classtable);
classtable->symtab_obj(cur_class)->exitscope();
this->type = expr_type;
return this->type;
}
/*
* Arith(+):
* Check type(e1) == Int == type(e2), and whatever the result, derive to Int
*/
Symbol plus_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if (e1_type != Int || e2_type != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "non-Int arguments: " << e1_type
<< " + " << e2_type
<< "\n";
}
this->type = Int;
return Int;
}
/*
* Arith(-):
* Check type(e1) == Int == type(e2), and whatever the result, derive to Int
*/
Symbol sub_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if (e1_type != Int || e2_type != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "non-Int arguments: " << e1_type
<< " - " << e2_type
<< "\n";
}
this->type = Int;
return Int;
}
/*
* Arith(*):
* Check type(e1) == Int == type(e2), and whatever the result, derive to Int
*/
Symbol mul_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if (e1_type != Int || e2_type != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "non-Int arguments: " << e1_type
<< " * " << e2_type
<< "\n";
}
this->type = Int;
return Int;
}
/*
* Arith(/):
* Check type(e1) == Int == type(e2), and whatever the result, derive to Int
*/
Symbol divide_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if (e1_type != Int || e2_type != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "non-Int arguments: " << e1_type
<< " / " << e2_type
<< "\n";
}
this->type = Int;
return Int;
}
/*
* Neg:
* Check type(e1) == Int, and whatever the result, derive to Int
*/
Symbol neg_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto type_subexpr = this->e1->semant(cur_class, classtable);
if (type_subexpr != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Argument of '~' has type " << type_subexpr
<< " instead of Int.\n";
}
this->type = Int;
return Int;
}
/*
* Compare(<):
* Check type(e1) == Int == type(e2), and whatever the result, derive to Bool
*/
Symbol lt_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if (e1_type != Int || e2_type != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "non-Int arguments: " << e1_type
<< " < " << e2_type
<< "\n";
}
this->type = Bool;
return Bool;
}
/*
* Equal:
* Any types may be freely compared (compare their Runtime addresses)
* except for Int, String, Bool. These 3 basic types can only be compared with
* exprs with the same type (compare their content values)
*/
Symbol eq_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if ((e1_type == Int || e2_type == Int
|| e1_type == Str || e2_type == Str
|| e1_type == Bool || e2_type == Bool)
&& e1_type != e2_type) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Illegal comparison with a basic type.\n";
}
this->type = Bool;
return Bool;
}
/*
* Compare(<=):
* Check type(e1) == Int == type(e2), and whatever the result, derive to Bool
*/
Symbol leq_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto e1_type = this->e1->semant(cur_class, classtable);
auto e2_type = this->e2->semant(cur_class, classtable);
if (e1_type != Int || e2_type != Int) {
classtable->semant_error(cur_class->get_filename(), this)
<< "non-Int arguments: " << e1_type
<< " <= " << e2_type
<< "\n";
}
this->type = Bool;
return Bool;
}
/*
* Not:
* Check type(e1) == Bool, and whatever the result, derive to Bool
*
* Note:
* I still cannot understand why operator `not` is named `comp` in AST
*/
Symbol comp_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto type_subexpr = this->e1->semant(cur_class, classtable);
/* It is safe to compare expr_type with Bool because neither Bool is inheritable
nor COOL support overloaded operator.
Thus we dont need to care about SELF_TYPE(self can never be Bool) and no
other type could use these operators.
*/
if (type_subexpr != Bool) {
classtable->semant_error(cur_class->get_filename(), this)
<< "Argument of 'not' has type " << type_subexpr
<< " instead of Bool.\n";
}
this->type = Bool;
return Bool;
}
/*
* Int:
* Integer constants derive to Int type
*/
Symbol int_const_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
this->type = Int;
return this->type;
}
/*
* True | False:
* true or false both derive to Bool type
*/
Symbol bool_const_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
this->type = Bool;
return this->type;
}
/*
* String
* String constants derive to String type
*/
Symbol string_const_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
this->type = Str;
return this->type;
}
/*
* New:
* Two cases for new, `SELF_TYPE` and any other
* But here we dont check `SELF_TYPE[C]` here, if encountered `SELF_TYPE`, just
* annotate it as `SELF_TYPE` and defer the type check to the conformance part
* The only check we do here is to make sure its `type_name` exists
*
* Warning:
* there is a static `Symbol` variable also called `type_name`, which conflicts
* with `new__class::type_name`
*/
Symbol new__class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
if (classtable->class_exist(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";
this->type = Object;
}
return this->type;
}
/*
* Isvoid:
* An `isvoid` test has type `Bool`, dont forget to eval its sub expr
*/
Symbol isvoid_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto _ = this->e1->semant(cur_class, classtable);
return Bool;
}
/*
* `no_expr` always has type `_no_type`
*/
Symbol no_expr_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
return No_type;
}
/*
* Var:
* If the env assigns an identifier ID type T, then ID has type T
* Otherwise, error report and set type Object
*/
Symbol object_class::semant(Class_ cur_class, ClassTable* classtable)
{
return Object;
auto object_type = classtable->symtab_obj(cur_class)->lookup(name);
if (object_type != nullptr) {
this->type = object_type;
return object_type;
}
else {
classtable->semant_error(cur_class->get_filename(), this)
<< "Undeclared identifier " << name<< "\n";
this->type = Object;
return Object;
}
}

View File

@ -32,7 +32,7 @@ public:
// the `class__class` object for which it builds graph
Class_ self;
// for cycle detection
int reachable = 0;
int depth = 0;
public:
// Note that, Class_ = Class__class*, itself is a ptr type, so just use it
@ -91,12 +91,12 @@ public:
}
/*
* traverse and mark all reachable children
* traverse and mark all reachable children, get their depth as well
*/
void traverse_reachable() {
reachable = 1;
void traverse_reachable(int depth) {
this->depth = depth + 1;
for (auto child : children) {
child->traverse_reachable();
child->traverse_reachable(depth + 1);
}
}
@ -160,10 +160,20 @@ public:
method_class* symtab_method_lookup_parent(Symbol, Symbol);
bool conform(Symbol, Symbol) const;
bool class_exist(Symbol) const;
Symbol lub(Symbol, Symbol) const;
/* wrappers */
std::vector<class__class*>& class_vec() { return _class_vec; }
SymbolTable<Symbol, Entry>* symtab_obj(Symbol class_id) { return _symtab_obj[class_id]; };
SymbolTable<Symbol, method_class>* symtab_met(Symbol class_id) { return _symtab_met[class_id]; };
SymbolTable<Symbol, Entry>* symtab_obj(Class_ class_i) {
auto class_id = static_cast<class__class*>(class_i)->get_name();
return _symtab_obj[class_id];
};
SymbolTable<Symbol, method_class>* symtab_met(Class_ class_i) {
auto class_id = static_cast<class__class*>(class_i)->get_name();
return _symtab_met[class_id];
};
SymbolTable<Symbol, method_class>* symtab_met(Symbol class_id) {
return _symtab_met[class_id];
};
int errors() { return semant_errors; }
ostream& semant_error();