grading pass (though may be still buggy)

This commit is contained in:
ridethepig 2023-03-27 12:54:18 +08:00
parent c5bbdde30b
commit 67cdb55125
6 changed files with 244 additions and 84 deletions

View File

@ -1,15 +1,31 @@
class Ok1{};
class Ok2_1 inherits Ok1 {};
class Ok2_2 inherits Ok1 {};
class ErrTest { class ErrTest {
errCase(): Bool { errCase(): Bool {
{ {
case (new NOEXIST) of case (new NOEXIST) of
x1: Bool => true; x1:
x2: Int => x2 <- 10; Bool => true;
x3: NOEXIST => x3 + 10; x2:
x3: NOEXIST => new Object; Int => x2 <- 10;
x4: Int => x4 + true; x3:
x4: Object => 111; NOEXIST => x3 + 10;
x5: SELF_TYPE => self; x3:
x5: SELF_TYPE => self; 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; esac;
} }
}; };
@ -28,6 +44,7 @@ class ErrTest {
errLet(): Object { errLet(): Object {
let x1:NOEXIST, x2:Int<-10, x3:NOEXIST <- x1, x4:Bool <- 10 in { let x1:NOEXIST, x2:Int<-10, x3:NOEXIST <- x1, x4:Bool <- 10 in {
x1 <- attr1 + x1; x1 <- attr1 + x1;
10 + (self <- 10 + false);
} }
}; };
attr1: NOEXIST; attr1: NOEXIST;
@ -46,12 +63,17 @@ class Main {
attr1: Bool <- (new Err5).hello(); attr1: Bool <- (new Err5).hello();
attr2: Int <- (new Err5).bye(); attr2: Int <- (new Err5).bye();
self(): SELF_TYPE { new SELF_TYPE }; self(): SELF_TYPE { new SELF_TYPE };
attr3: NOEXIST <- 10;
main(): Object { main(): Object {
{ {
let x:Int in { attr3.hello(1 + false) + 10;
let x:Int, y:NOEXIST in {
x1 <- x + 1; x1 <- x + 1;
x <- false; x <- false;
x <- x1; x <- x1;
attr3 * 10;
y * 10;
if (y) then y else attr3 fi;
}; };
while (1 + 1) loop while (1 + 1) loop
x1 <- true x1 <- true
@ -60,7 +82,8 @@ class Main {
(new ErrMethods).errMethod(true + false); (new ErrMethods).errMethod(true + false);
(new ErrMethods).errMethod2(false, false); (new ErrMethods).errMethod2(false, false);
(new ErrMethods).errMethod2(true + false); (new ErrMethods).errMethod2(true + false);
attr2@Main.hello(); attr2@SELF_TYPE.hello();
self@Main.self();
} }
}; };
}; };

View File

@ -88,6 +88,10 @@ class Main inherits DummyMain {
main: Bool <- true + false; main: Bool <- true + false;
}; };
class SELF_TYPE {
};
class Err5 { class Err5 {
ala: Bool <- 20; ala: Bool <- 20;
-- hello() : Object {{ala <- ala + 1;}}; -- hello() : Object {{ala <- ala + 1;}};

View File

@ -0,0 +1,3 @@
#!/bin/bash
set -ex
./lexer $* | ./parser $* > debug_input.in

View File

@ -1,7 +1,7 @@
class C { class C {
a : Int; a : Int;
b : Bool; b : Bool;
init(x : Int, y : Bool) : C { init(x : Int, y : Bool) : SELF_TYPE {
{ {
a <- x; a <- x;
b <- y; b <- y;
@ -11,7 +11,15 @@ class C {
}; };
Class Main { Class Main {
good() : Bool { true };
self_method() : SELF_TYPE { self };
main():C { main():C {
(new C).init(1,true) {
new SELF_TYPE.good();
(new C).init(1,true);
isvoid true;
isvoid false;
isvoid x;
}
}; };
}; };

View File

@ -100,7 +100,10 @@ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr)
/* first scan: de-duplicate class definitions*/ /* first scan: de-duplicate class definitions*/
for (auto i = classes->first(); classes->more(i); i = classes->next(i)) { for (auto i = classes->first(); classes->more(i); i = classes->next(i)) {
auto class_i = static_cast<class__class*>(classes->nth(i)); auto class_i = static_cast<class__class*>(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"; semant_error(class_i) << "Class " << class_i->get_name() << " was previously defined.\n";
} }
else { else {
@ -161,12 +164,16 @@ void ClassTable::symtab_dump(Symbol class_name) {
std::cerr << "--------\n\n"; 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()); assert(name_to_node.find(class_name) != name_to_node.end());
auto class_node = name_to_node[class_name]; auto class_node = name_to_node.find(class_name)->second;
auto parent_node= class_node->parent; auto parent_node= class_node;
while (parent_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 // only need to lookup in the top scope, because attributes all reside in top scope
if (result) return result; if (result) return result;
parent_node = parent_node->parent; parent_node = parent_node->parent;
@ -174,12 +181,16 @@ Symbol ClassTable::symtab_object_lookup_parent(Symbol class_name, Symbol object_
return nullptr; 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()); assert(name_to_node.find(class_name) != name_to_node.end());
auto class_node = name_to_node[class_name]; auto class_node = name_to_node.find(class_name)->second;
auto parent_node= class_node->parent; auto parent_node= class_node;
while (parent_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 // only need to lookup in the top scope, because attributes all reside in top scope
if (result) return result; if (result) return result;
parent_node = parent_node->parent; parent_node = parent_node->parent;
@ -256,7 +267,7 @@ void ClassTable::install_all_features() {
<< "In redefined method " << cur_method->get_name() << "In redefined method " << cur_method->get_name()
<< ", return type " << cur_method->get_return_type() << ", return type " << cur_method->get_return_type()
<< " is different from original return type" << overridden_method->get_return_type() << " is different from original return type" << overridden_method->get_return_type()
<< "\n"; << ".\n";
_error_flag = true; _error_flag = true;
} }
else if (cur_method->get_formals()->len() != overridden_method->get_formals()->len()) { 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() << "In redefined method " << cur_method->get_name()
<< ", parameter type " << cur_formal->get_type_decl() << ", parameter type " << cur_formal->get_type_decl()
<< " is different from original type" << overridden_formal->get_type_decl() << " is different from original type" << overridden_formal->get_type_decl()
<< "\n"; << ".\n";
_error_flag = true; _error_flag = true;
break; break;
} }
@ -473,12 +484,21 @@ ostream& ClassTable::semant_error()
/* /*
* Query the Inheritance Graph if T1 <= T0 * Query the Inheritance Graph if T1 <= T0
*
* Note: if T1 inherits from(or is) T0, then 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 { bool ClassTable::conform(Symbol T1, Symbol T0) const {
if (T1 == T0) return true; if (T1 == T0) return true;
if (!class_exist(T0) || !class_exist(T1))
return true;
auto cur_node_itr = name_to_node.find(T1); auto cur_node_itr = name_to_node.find(T1);
if (cur_node_itr == name_to_node.end()){
std::cerr << "Comform: Escaping type T1 = " << T1 << "\n";
assert(cur_node_itr != name_to_node.end()); assert(cur_node_itr != name_to_node.end());
}
auto cur_node = cur_node_itr->second; auto cur_node = cur_node_itr->second;
while (cur_node) { while (cur_node) {
if (cur_node->get_class()->get_name() == T0) { if (cur_node->get_class()->get_name() == T0) {
@ -489,17 +509,52 @@ bool ClassTable::conform(Symbol T1, Symbol T0) const {
return false; 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 { 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(); 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 { Symbol ClassTable::lub(Symbol T1, Symbol T2) const {
if (T1 == T2) return T1; if (T1 == T2) return T1;
auto node1_iter = name_to_node.find(T1); auto node1_iter = name_to_node.find(T1);
auto node2_iter = name_to_node.find(T2); auto node2_iter = name_to_node.find(T2);
assert(node1_iter != name_to_node.end()); // assert(node1_iter != name_to_node.end());
assert(node2_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 node1 = node1_iter->second;
auto node2 = node2_iter->second; auto node2 = node2_iter->second;
ClassGraphNode* node_lower = nullptr; ClassGraphNode* node_lower = nullptr;
@ -530,6 +585,11 @@ Symbol ClassTable::lub(Symbol T1, Symbol T2) const {
return node_lower->get_class()->get_name(); 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. /* This is the entry point to the semantic checker.
Your checker should do the following two things: 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 * Check if Declared Type is defined, if so, do nothing because already
* in AST; else, error report and set its type to Object * 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Class " << type_decl << "Class " << type_decl
<< " of attribute " << name << " of attribute " << name
<< " is undefined.\n"; << " is undefined.\n";
this->type_decl = Object;
} }
/* /*
* Attr-Init: * Attr-Init:
@ -603,13 +662,13 @@ void attr_class::semant(Class_ cur_class, ClassTable * classtable)
*/ */
if (typeid(*init) != typeid(no_expr_class)) { if (typeid(*init) != typeid(no_expr_class)) {
auto rhs_type = init->semant(cur_class, classtable); auto rhs_type = init->semant(cur_class, classtable);
std::cerr << "attr init rhs type=" << rhs_type << "\n"; // std::cerr << "attr init rhs type=" << rhs_type << "\n";
if (!classtable->conform(rhs_type, type_decl)) { if (!classtable->conform_self(rhs_type, type_decl, cur_class)) {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< "Inferred type " << rhs_type << "Inferred type " << rhs_type
<< " of initialization of attribute " << name << " of initialization of attribute " << name
<< " does not conform to declared type " << type_decl << " does not conform to declared type " << type_decl
<< " .\n"; << ".\n";
this->type_decl = Object; this->type_decl = Object;
} }
} }
@ -623,7 +682,11 @@ void method_class::semant(Class_ cur_class, ClassTable * classtable)
auto formal_i = static_cast<formal_class*>(formals->nth(i)); auto formal_i = static_cast<formal_class*>(formals->nth(i));
auto formal_i_name = formal_i->get_name(); auto formal_i_name = formal_i->get_name();
auto formal_i_type = formal_i->get_type_decl(); 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); symtab_obj->addid(formal_i_name, formal_i_type);
} }
else { else {
@ -639,8 +702,14 @@ void method_class::semant(Class_ cur_class, ClassTable * classtable)
} }
} }
auto expr_type = this->expr->semant(cur_class, 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(); 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Inferred return type " << expr_type << "Inferred return type " << expr_type
<< " of method " << this->name << " 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) 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) { if (lhs_type == nullptr) {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< "Assignment to undeclared variable " << name << "\n"; << "Assignment to undeclared variable " << name << ".\n";
lhs_type = Object; lhs_type = Object;
} }
auto rhs_type = this->expr->semant(cur_class, classtable); 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Type " << rhs_type << "Type " << rhs_type
<< " of assigned expression does not conform to declared type " << lhs_type << " of assigned expression does not conform to declared type " << lhs_type
<< " of identifier " << name << " of identifier " << name
<< " .\n"; << ".\n";
this->type = Object;
} }
else {
this->type = rhs_type; this->type = rhs_type;
}
return this->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); _param_type.push_back(param_i_type);
} }
if (!classtable->class_exist(this->type_name)) { if (!classtable->class_exist(this->type_name)) {
if (this->type_name == SELF_TYPE){
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< "Static dispatch to undefined class " << this->type_name << "Static dispatch to SELF_TYPE.\n";
}
else {
classtable->semant_error(cur_class->get_filename(), this)
<< "Static dispatch on undefined class " << this->type_name
<< ".\n"; << ".\n";
}
this->type = Object; this->type = Object;
return this->type; 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Expression type " << expr_type << "Expression type " << expr_type
<< " does not conform to declared static dispatch type " << this->type_name << " 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; this->type = Object;
return this->type; return this->type;
} }
auto symtab_method = classtable->symtab_met(this->type_name); // auto symtab_method = classtable->symtab_met(this->type_name);
auto cur_method = symtab_method->lookup(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) { if (cur_method == nullptr) {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< " Dispatch to undefined method " << name << "Static dispatch to undefined method " << name
<< ".\n"; << ".\n";
this->type = Object; this->type = Object;
return Object; return Object;
} }
if (actual->len() != cur_method->get_formals()->len()) { if (actual->len() != cur_method->get_formals()->len()) {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< " Method " << name << "Method " << name
<< " called with wrong number of arguments.\n"; << " called with wrong number of arguments.\n";
this->type = Object; this->type = Object;
return Object; return Object;
@ -721,7 +799,7 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable)
auto _param_type_iter = _param_type.begin(); 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)) {
auto formal_i = static_cast<formal_class*>(formals->nth(i)); auto formal_i = static_cast<formal_class*>(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) classtable->semant_error(cur_class->get_filename(), this)
<< "In call of method " << cur_method->get_name() << "In call of method " << cur_method->get_name()
<< ", type " << *_param_type_iter << ", type " << *_param_type_iter
@ -734,6 +812,7 @@ Symbol static_dispatch_class::semant(Class_ cur_class, ClassTable* classtable)
auto return_type = cur_method->get_return_type(); auto return_type = cur_method->get_return_type();
if (return_type == SELF_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; this->type = return_type;
return this->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) Symbol dispatch_class::semant(Class_ cur_class, ClassTable* classtable)
{ {
auto expr_type = expr->semant(cur_class, classtable); auto expr_type = expr->semant(cur_class, classtable); // T_0
std::vector<Symbol> _param_type; std::vector<Symbol> _param_type; // T_i
for (auto i = actual->first(); actual->more(i); i = actual->next(i)) { for (auto i = actual->first(); actual->more(i); i = actual->next(i)) {
auto param_i = actual->nth(i); auto param_i = actual->nth(i);
auto param_i_type = param_i->semant(cur_class, classtable); auto param_i_type = param_i->semant(cur_class, classtable);
_param_type.push_back(param_i_type); _param_type.push_back(param_i_type);
} }
auto symtab_method = classtable->symtab_met(expr_type); Symbol method_env_class = expr_type; // T_0'
assert(symtab_method); if (expr_type == SELF_TYPE) {
auto cur_method = symtab_method->lookup(name); method_env_class = classtable->class_to_name(cur_class);
if (cur_method == nullptr) { }
if (!classtable->class_exist(method_env_class)) {
classtable->semant_error(cur_class->get_filename(), this) 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"; << ".\n";
this->type = Object; this->type = Object;
return Object; return Object;
} }
if (actual->len() != cur_method->get_formals()->len()) { if (actual->len() != cur_method->get_formals()->len()) {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< " Method " << name << "Method " << name
<< " called with wrong number of arguments.\n"; << " called with wrong number of arguments.\n";
this->type = Object; this->type = Object;
return Object; return Object;
} }
auto formals = cur_method->get_formals(); auto formals = cur_method->get_formals(); // T_i'
auto _param_type_iter = _param_type.begin(); 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<formal_class*>(formals->nth(i)); auto formal_i = static_cast<formal_class*>(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) classtable->semant_error(cur_class->get_filename(), this)
<< "In call of method " << cur_method->get_name() << "In call of method " << cur_method->get_name()
<< ", type " << *_param_type_iter << ", 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() << " does not conform to declared type " << formal_i->get_type_decl()
<< ".\n"; << ".\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) { if (return_type == SELF_TYPE) {
return_type = expr_type; return_type = expr_type;
} }
@ -851,7 +948,7 @@ Symbol typcase_class::semant(Class_ cur_class, ClassTable* classtable)
_existed_type.insert(type_decl_i); _existed_type.insert(type_decl_i);
} }
else { else {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), branch_i)
<< "Duplicate branch " << type_decl_i << "Duplicate branch " << type_decl_i
<< " in case statement.\n"; << " in case statement.\n";
} }
@ -861,12 +958,12 @@ Symbol typcase_class::semant(Class_ cur_class, ClassTable* classtable)
for later expr typing for later expr typing
*/ */
if (type_decl_i == SELF_TYPE) { 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 << "Identifier " << name_i
<< " declared with type SELF_TYPE in case branch.\n"; << " declared with type SELF_TYPE in case branch.\n";
} }
else if (!classtable->class_exist(type_decl_i)) { 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 << "Class " << type_decl_i
<< " of case branch is undefined.\n"; << " 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) 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Class " << type_decl << "Class " << type_decl
<< " of attribute " << identifier << " of let-bound identifier " << identifier
<< " is undefined.\n"; << " is undefined.\n";
this->type_decl = Object;
} }
if (typeid(*init) != typeid(no_expr_class)) { if (typeid(*init) != typeid(no_expr_class)) {
auto init_type = init->semant(cur_class, classtable); 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Inferred type " << init_type << "Inferred type " << init_type
<< " of initialization of " << identifier << " 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) 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; this->type = this->type_name;
} }
else { else {
classtable->semant_error(cur_class->get_filename(), this) classtable->semant_error(cur_class->get_filename(), this)
<< "\'new\' used with undefined class " << this->type_name << "\'new\' used with undefined class " << this->type_name
<< "\n"; << ".\n";
this->type = Object; this->type = Object;
} }
return this->type; 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) Symbol isvoid_class::semant(Class_ cur_class, ClassTable* classtable)
{ {
auto _ = this->e1->semant(cur_class, classtable); auto _ = this->e1->semant(cur_class, classtable);
this->type = Bool;
return Bool; return Bool;
} }
/* /*
* NoExpr:
* `no_expr` always has type `_no_type` * `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) Symbol no_expr_class::semant(Class_ cur_class, ClassTable* classtable)
{ {
assert(0);
return No_type; 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) 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) { if (object_type != nullptr) {
this->type = object_type; this->type = object_type;
return object_type; return object_type;
} }
else { 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) classtable->semant_error(cur_class->get_filename(), this)
<< "Undeclared identifier " << name<< "\n"; << "Undeclared identifier " << name<< ".\n";
this->type = Object; this->type = Object;
return Object; return Object;
} }

View File

@ -156,23 +156,36 @@ public:
/* helpers */ /* helpers */
void install_all_features(); void install_all_features();
void symtab_dump(Symbol); void symtab_dump(Symbol);
Symbol symtab_object_lookup_parent(Symbol, Symbol); Symbol symtab_object_lookup_parent(Symbol, Symbol) const;
method_class* symtab_method_lookup_parent(Symbol, Symbol); 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(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(Symbol) const;
bool class_exist_self(Symbol) const;
Symbol lub(Symbol, 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__class*>(class_item)->get_name(); }
/* wrappers */ /* wrappers */
std::vector<class__class*>& class_vec() { return _class_vec; } std::vector<class__class*>& class_vec() { return _class_vec; }
SymbolTable<Symbol, Entry>* symtab_obj(Class_ class_i) { SymbolTable<Symbol, Entry>* symtab_obj(Class_ class_i) const {
auto class_id = static_cast<class__class*>(class_i)->get_name(); auto class_id = static_cast<class__class*>(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<Symbol, method_class>* symtab_met(Class_ class_i) { SymbolTable<Symbol, method_class>* symtab_met(Class_ class_i) const {
auto class_id = static_cast<class__class*>(class_i)->get_name(); auto class_id = static_cast<class__class*>(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<Symbol, method_class>* symtab_met(Symbol class_id) { SymbolTable<Symbol, method_class>* symtab_met(Symbol class_id) const {
return _symtab_met[class_id]; auto _iter = _symtab_met.find(class_id);
if (_iter == _symtab_met.end()) return nullptr;
return _iter->second;
}; };
int errors() { return semant_errors; } int errors() { return semant_errors; }