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 {
|
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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -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;}};
|
||||||
|
|||||||
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 {
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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,8 +662,8 @@ 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
|
||||||
@ -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,11 +778,12 @@ 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;
|
||||||
@ -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,17 +826,31 @@ 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 (!classtable->class_exist(method_env_class)) {
|
||||||
|
classtable->semant_error(cur_class->get_filename(), this)
|
||||||
|
<< "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 (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)
|
classtable->semant_error(cur_class->get_filename(), this)
|
||||||
<< "Dispatch to undefined method " << name
|
<< "Dispatch to undefined method " << name
|
||||||
<< ".\n";
|
<< ".\n";
|
||||||
@ -771,11 +864,15 @@ Symbol dispatch_class::semant(Class_ cur_class, ClassTable* classtable)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user