grading pass (though may be still buggy)
This commit is contained in:
parent
c5bbdde30b
commit
67cdb55125
@ -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();
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -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;}};
|
||||
|
||||
3
assignments/PA4/gen_debug_input.sh
Executable file
3
assignments/PA4/gen_debug_input.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
./lexer $* | ./parser $* > debug_input.in
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -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<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";
|
||||
}
|
||||
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);
|
||||
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<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) {
|
||||
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;
|
||||
<< ".\n";
|
||||
}
|
||||
else {
|
||||
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)) {
|
||||
if (this->type_name == SELF_TYPE){
|
||||
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";
|
||||
}
|
||||
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<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)
|
||||
<< "In call of method " << cur_method->get_name()
|
||||
<< ", 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();
|
||||
if (return_type == SELF_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<Symbol> _param_type;
|
||||
auto expr_type = expr->semant(cur_class, classtable); // T_0
|
||||
std::vector<Symbol> _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<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)
|
||||
<< "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;
|
||||
}
|
||||
|
||||
@ -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__class*>(class_item)->get_name(); }
|
||||
/* wrappers */
|
||||
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();
|
||||
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();
|
||||
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) {
|
||||
return _symtab_met[class_id];
|
||||
SymbolTable<Symbol, method_class>* 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; }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user