expression except case done
This commit is contained in:
parent
d279a73fb5
commit
7140f01bb0
@ -26,6 +26,7 @@
|
|||||||
#include "cgen_gc.h"
|
#include "cgen_gc.h"
|
||||||
#include "cool-tree.h"
|
#include "cool-tree.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -623,9 +624,9 @@ void CgenClassTable::code_dispatchTable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CgenClassTable::code_prototypeObject() {
|
void CgenClassTable::code_prototypeObject() {
|
||||||
auto int_default = inttable.lookup_string("0");
|
this->_int_default = inttable.lookup_string("0");
|
||||||
auto str_default = stringtable.lookup_string("");
|
this->_str_default = stringtable.lookup_string("");
|
||||||
auto bool_default = &falsebool;
|
this->_bool_default = &falsebool;
|
||||||
|
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
str << WORD << "-1\n"; // GC tag
|
str << WORD << "-1\n"; // GC tag
|
||||||
@ -636,15 +637,15 @@ void CgenClassTable::code_prototypeObject() {
|
|||||||
for (auto attr : *node->get_attributes()) {
|
for (auto attr : *node->get_attributes()) {
|
||||||
if (attr->type_decl == Int) {
|
if (attr->type_decl == Int) {
|
||||||
str << WORD;
|
str << WORD;
|
||||||
int_default->code_ref(str);
|
_int_default->code_ref(str);
|
||||||
str << endl;
|
str << endl;
|
||||||
} else if (attr->type_decl == Bool) {
|
} else if (attr->type_decl == Bool) {
|
||||||
str << WORD;
|
str << WORD;
|
||||||
bool_default->code_ref(str);
|
_bool_default->code_ref(str);
|
||||||
str << endl;
|
str << endl;
|
||||||
} else if (attr->type_decl == Str) {
|
} else if (attr->type_decl == Str) {
|
||||||
str << WORD;
|
str << WORD;
|
||||||
str_default->code_ref(str);
|
_str_default->code_ref(str);
|
||||||
str << endl;
|
str << endl;
|
||||||
} else {
|
} else {
|
||||||
// for other types(including _prim_slot type), set to void(null pointer)
|
// for other types(including _prim_slot type), set to void(null pointer)
|
||||||
@ -656,6 +657,14 @@ void CgenClassTable::code_prototypeObject() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CgenClassTable::code_objectTab() {
|
||||||
|
str << CLASSOBJTAB << LABEL;
|
||||||
|
for (auto node : nodes) {
|
||||||
|
str << WORD << node->get_name() << PROTOBJ_SUFFIX << endl;
|
||||||
|
str << WORD << node->get_name() << CLASSINIT_SUFFIX << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
|
CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
|
||||||
enterscope();
|
enterscope();
|
||||||
if (cgen_debug)
|
if (cgen_debug)
|
||||||
@ -665,6 +674,11 @@ CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
|
|||||||
build_inheritance_tree();
|
build_inheritance_tree();
|
||||||
if (cgen_debug)
|
if (cgen_debug)
|
||||||
dump_inheritance_tree();
|
dump_inheritance_tree();
|
||||||
|
root()->traverse_generate_object();
|
||||||
|
// nodes[0] is the Object class
|
||||||
|
stringclasstag = get_node(Str)->get_class_tag();
|
||||||
|
intclasstag = get_node(Int)->get_class_tag();
|
||||||
|
boolclasstag = get_node(Bool)->get_class_tag();
|
||||||
code();
|
code();
|
||||||
exitscope();
|
exitscope();
|
||||||
}
|
}
|
||||||
@ -787,10 +801,6 @@ void CgenClassTable::install_basic_classes() {
|
|||||||
Str, no_expr()))),
|
Str, no_expr()))),
|
||||||
filename),
|
filename),
|
||||||
Basic));
|
Basic));
|
||||||
|
|
||||||
stringclasstag = get_node(Str)->get_class_tag();
|
|
||||||
intclasstag = get_node(Int)->get_class_tag();
|
|
||||||
boolclasstag = get_node(Bool)->get_class_tag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CgenClassTable::install_class
|
// CgenClassTable::install_class
|
||||||
@ -861,6 +871,19 @@ CgenNode *CgenClassTable::get_node(Symbol class_name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CgenClassTable::get_method_index(Symbol class_name, Symbol method_name) {
|
||||||
|
auto class_node = get_node(class_name);
|
||||||
|
auto methods = class_node->get_methods();
|
||||||
|
for (size_t i = 0; i < methods->size(); ++i) {
|
||||||
|
auto method = (*methods)[i];
|
||||||
|
if (method.second->name == method_name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void CgenClassTable::code() {
|
void CgenClassTable::code() {
|
||||||
if (cgen_debug)
|
if (cgen_debug)
|
||||||
cout << "coding global data" << endl;
|
cout << "coding global data" << endl;
|
||||||
@ -878,10 +901,12 @@ void CgenClassTable::code() {
|
|||||||
cout << "coding class_nameTab" << endl;
|
cout << "coding class_nameTab" << endl;
|
||||||
code_class_nameTable();
|
code_class_nameTable();
|
||||||
|
|
||||||
|
if (cgen_debug)
|
||||||
|
cout << "coding object table" << endl;
|
||||||
|
code_objectTab();
|
||||||
|
|
||||||
if (cgen_debug)
|
if (cgen_debug)
|
||||||
cout << "coding dispatch tables" << endl;
|
cout << "coding dispatch tables" << endl;
|
||||||
nodes[0]->traverse_generate_object();
|
|
||||||
// nodes[0] is the Object class
|
|
||||||
code_dispatchTable();
|
code_dispatchTable();
|
||||||
|
|
||||||
if (cgen_debug)
|
if (cgen_debug)
|
||||||
@ -936,6 +961,7 @@ void CgenClassTable::code() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Add your code to emit
|
// Add your code to emit
|
||||||
// - object initializer
|
// - object initializer
|
||||||
// - the class methods
|
// - the class methods
|
||||||
@ -1045,11 +1071,104 @@ void CgenNode::traverse_generate_object() {
|
|||||||
|
|
||||||
#pragma region ExpressionCoding
|
#pragma region ExpressionCoding
|
||||||
|
|
||||||
void assign_class::code(ostream &s, CgenClassTable *classtab) {}
|
/*
|
||||||
|
Assignment actually does little. First evaluate its rhs. Then look up the lhs
|
||||||
|
identifier's location and simply store into the location.
|
||||||
|
*/
|
||||||
|
void assign_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->expr->code(s, classtab);
|
||||||
|
auto loc = classtab->loctab.lookup(this->name);
|
||||||
|
if (loc->location == Stack) {
|
||||||
|
emit_store(ACC, loc->offset, FP, s);
|
||||||
|
} else {
|
||||||
|
emit_store(ACC, loc->offset, SELF, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static dispatch is a little bit simpler than normal dispatch
|
||||||
|
Intuitively, first evaluate all the parameter expression and push stack. Note
|
||||||
|
that, by design, the caller doesn't clear up the params, the callee do the
|
||||||
|
clear up on return.
|
||||||
|
Then evaluate the expr before `.`, which serves as the self object when
|
||||||
|
invoking the method. Thus it resides in $a0.
|
||||||
|
Before the flow goes to the method, check whether the object is void. This is
|
||||||
|
mentioned near the end of section 13 in the manual. If void, set $t1 and $a0
|
||||||
|
and call _dispatch_abort.
|
||||||
|
Finally, invoke the method by looking up its address from the dispatch table
|
||||||
|
and jalr.
|
||||||
|
*/
|
||||||
|
void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
for (auto actual_i = this->actual->first(); this->actual->more(actual_i);
|
||||||
|
actual_i = this->actual->next(actual_i)) {
|
||||||
|
auto actual_expr = this->actual->nth(actual_i);
|
||||||
|
actual_expr->code(s, classtab);
|
||||||
|
emit_push(ACC, s); // push param to stack
|
||||||
|
}
|
||||||
|
this->expr->code(s, classtab);
|
||||||
|
auto label_index_dispatch = classtab->alloc_label_index();
|
||||||
|
// use bne to save a label, because we'll never come back if abort
|
||||||
|
emit_bne(ACC, ZERO, label_index_dispatch, s);
|
||||||
|
// Prints the line number, from $t1, and filename, from $a0, at which the
|
||||||
|
// dispatch occurred, and aborts.
|
||||||
|
emit_load_imm(T1, this->line_number, s);
|
||||||
|
emit_partial_load_address(ACC, s);
|
||||||
|
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
|
||||||
|
->code_ref(s);
|
||||||
|
s << endl;
|
||||||
|
emit_jal("_dispatch_abort", s);
|
||||||
|
// ready to call the method
|
||||||
|
emit_label_def(label_index_dispatch, s);
|
||||||
|
// load dispatch table
|
||||||
|
emit_partial_load_address(T1, s);
|
||||||
|
emit_disptable_ref(this->type_name, s);
|
||||||
|
s << endl;
|
||||||
|
// load method address
|
||||||
|
emit_load(T1, classtab->get_method_index(this->type_name, this->name), T1, s);
|
||||||
|
// call the method whose address is in $t1, with self object in $a0
|
||||||
|
emit_jalr(T1, s);
|
||||||
|
}
|
||||||
|
|
||||||
void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {}
|
/*
|
||||||
|
Normal dispatch is only different from static dispatch in deciding the
|
||||||
void dispatch_class::code(ostream &s, CgenClassTable *classtab) {}
|
dispatch table. Normal dispatch extract the dispatch table from the object's
|
||||||
|
dispTab feild(offset 8) instead of querying method address at compile time.
|
||||||
|
*/
|
||||||
|
void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
for (auto actual_i = this->actual->first(); this->actual->more(actual_i);
|
||||||
|
actual_i = this->actual->next(actual_i)) {
|
||||||
|
auto actual_expr = this->actual->nth(actual_i);
|
||||||
|
actual_expr->code(s, classtab);
|
||||||
|
emit_push(ACC, s); // push param to stack
|
||||||
|
}
|
||||||
|
this->expr->code(s, classtab);
|
||||||
|
auto label_index_dispatch = classtab->alloc_label_index();
|
||||||
|
// use bne to save a label, because we'll never come back if abort
|
||||||
|
emit_bne(ACC, ZERO, label_index_dispatch, s);
|
||||||
|
// Prints the line number, from $t1, and filename, from $a0, at which the
|
||||||
|
// dispatch occurred, and aborts.
|
||||||
|
emit_load_imm(T1, this->line_number, s);
|
||||||
|
emit_partial_load_address(ACC, s);
|
||||||
|
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
|
||||||
|
->code_ref(s);
|
||||||
|
s << endl;
|
||||||
|
emit_jal("_dispatch_abort", s);
|
||||||
|
// ready to call the method
|
||||||
|
emit_label_def(label_index_dispatch, s);
|
||||||
|
// load dispatch table
|
||||||
|
emit_load(T1, DISPTABLE_OFFSET, ACC, s);
|
||||||
|
// load method address
|
||||||
|
int method_index = -1;
|
||||||
|
if (this->expr->type == SELF_TYPE) {
|
||||||
|
method_index =
|
||||||
|
classtab->get_method_index(classtab->cur_class->name, this->name);
|
||||||
|
// if the expr is SELF_TYPE, look up the method from current classs
|
||||||
|
} else {
|
||||||
|
method_index = classtab->get_method_index(this->expr->type, this->name);
|
||||||
|
}
|
||||||
|
emit_load(T1, method_index, T1, s);
|
||||||
|
// call the method whose address is in $t1, with self object in $a0
|
||||||
|
emit_jalr(T1, s);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
There's nothing special for if-then-else. Write at your convenience.
|
There's nothing special for if-then-else. Write at your convenience.
|
||||||
@ -1102,9 +1221,18 @@ void block_class::code(ostream &s, CgenClassTable *classtab) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void let_class::code(ostream &s, CgenClassTable *classtab) {
|
void let_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
classtab->expr_type_decl = this->type_decl;
|
||||||
this->init->code(s, classtab);
|
this->init->code(s, classtab);
|
||||||
emit_push(ZERO, s); // make space for let's new object
|
emit_push(ZERO, s); // make space for let's new object
|
||||||
|
emit_store(ACC, -rel_stack_depth, FP, s);
|
||||||
|
// set initial value to the new ident
|
||||||
|
classtab->loctab.enterscope();
|
||||||
|
classtab->loctab.add(
|
||||||
|
LocationTableItem(this->identifier, Stack, -rel_stack_depth));
|
||||||
|
this->body->code(s, classtab);
|
||||||
|
classtab->loctab.exitscope();
|
||||||
|
emit_pop(s); // balacnce stack
|
||||||
|
// the value of let is body's value, so leave $a0 unmodified
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1332,7 +1460,59 @@ void bool_const_class::code(ostream &s, CgenClassTable *classtab) {
|
|||||||
emit_load_bool(ACC, BoolConst(val), s);
|
emit_load_bool(ACC, BoolConst(val), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void new__class::code(ostream &s, CgenClassTable *classtab) {}
|
/*
|
||||||
|
Create a normal type object is quite simple, which could be done by 3
|
||||||
|
instructions:
|
||||||
|
la $a0, T_protoObj
|
||||||
|
call Object.copy
|
||||||
|
call T_init
|
||||||
|
Create SELF_TYPE object is very very tricky, because the real type is decided
|
||||||
|
at run time. I managed to get this done by looking at the target code
|
||||||
|
generated by the reference compiler.
|
||||||
|
We need a table indexed by class tag, which contains T[i]_protoObj and
|
||||||
|
T[i]_init. When creating such objects, we look up the actual protoObj and
|
||||||
|
init method by the self object's class tag. This involves dereferencing
|
||||||
|
pointers for multiple times, which is hard to get right.
|
||||||
|
*/
|
||||||
|
void new__class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
if (this->type_name == SELF_TYPE) {
|
||||||
|
// first get the class tag at offset 0, $a0 <- 0($s0)
|
||||||
|
emit_load(ACC, 0, SELF, s);
|
||||||
|
// load the address of class_objTab, $t1 <- &class_objTab
|
||||||
|
emit_load_address(T1, CLASSOBJTAB, s);
|
||||||
|
// convert class tag to index, index = tag * 8, $a0 <- $a0 << 3
|
||||||
|
emit_sll(ACC, ACC, 3, s);
|
||||||
|
// get the address of so_protoObj, $a0 <- $t1 + $a0(base + index)
|
||||||
|
emit_addu(ACC, ACC, T1, s);
|
||||||
|
// save index on stack, we are to use $a0 for param
|
||||||
|
emit_push(ACC, s);
|
||||||
|
// get the so_protoObj, $a0 <- 0($a0)
|
||||||
|
emit_load(ACC, 0, ACC, s);
|
||||||
|
// call Object.copy
|
||||||
|
emit_jal("Object.copy", s);
|
||||||
|
// recover the addresss of so_protoObj, $t1 <- stack top
|
||||||
|
emit_load(T1, 1, SP, s);
|
||||||
|
emit_pop(s); // pop
|
||||||
|
// load address of so_init, $t1 <- 4($t1)
|
||||||
|
emit_load(T1, 1, T1, s);
|
||||||
|
// with $a0 storing the new object's ref, call so_init whose address is in
|
||||||
|
// $t1, which accepts $a0 as the parameter
|
||||||
|
emit_jalr(T1, s);
|
||||||
|
// initialized brand new object already has its ref in $a0
|
||||||
|
} else {
|
||||||
|
// load address: $a0 <- T_protObj
|
||||||
|
emit_partial_load_address(ACC, s);
|
||||||
|
emit_protobj_ref(this->type_name, s);
|
||||||
|
s << endl;
|
||||||
|
// call Object.copy
|
||||||
|
emit_jal("Object.copy", s);
|
||||||
|
// call T_init
|
||||||
|
s << JAL;
|
||||||
|
emit_init_ref(this->type_name, s);
|
||||||
|
s << endl;
|
||||||
|
// initialized brand new object already has its ref in $a0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
`isvoid` operation is quite simple and stack-operation free, since we only
|
`isvoid` operation is quite simple and stack-operation free, since we only
|
||||||
@ -1350,10 +1530,37 @@ void isvoid_class::code(ostream &s, CgenClassTable *classtab) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The control flow should not reach here by design
|
No_expr means the init expression is omitted. However, the object has to be
|
||||||
|
assigned to some value. CgenClassTable::expr_type_decl is set for this
|
||||||
|
method to generate a propriate default initial value.
|
||||||
*/
|
*/
|
||||||
void no_expr_class::code(ostream &s, CgenClassTable *classtab) { assert(0); }
|
void no_expr_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
if (classtab->expr_type_decl == Int) {
|
||||||
|
emit_load_int(ACC, classtab->int_default(), s);
|
||||||
|
} else if (classtab->expr_type_decl == Bool) {
|
||||||
|
emit_load_bool(ACC, *classtab->bool_default(), s);
|
||||||
|
} else if (classtab->expr_type_decl == Str) {
|
||||||
|
emit_load_string(ACC, classtab->str_default(), s);
|
||||||
|
} else {
|
||||||
|
assert(classtab->expr_type_decl);
|
||||||
|
emit_move(ACC, ZERO, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void object_class::code(ostream &s, CgenClassTable *classtab) {}
|
/*
|
||||||
|
ObjectID simply perform a load from store to $a0
|
||||||
|
Note that `self` is not in location table, add a special case and $a0<-$s0
|
||||||
|
*/
|
||||||
|
void object_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
if (this->name == self) {
|
||||||
|
emit_move(ACC, SELF, s);
|
||||||
|
} else {
|
||||||
|
auto loc = classtab->loctab.lookup(this->name);
|
||||||
|
if (loc->location == Stack)
|
||||||
|
emit_load(ACC, loc->offset, FP, s);
|
||||||
|
else
|
||||||
|
emit_load(ACC, loc->offset, SELF, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|||||||
@ -21,6 +21,8 @@ typedef CgenClassTable *CgenClassTableP;
|
|||||||
class CgenNode;
|
class CgenNode;
|
||||||
typedef CgenNode *CgenNodeP;
|
typedef CgenNode *CgenNodeP;
|
||||||
|
|
||||||
|
class BoolConst;
|
||||||
|
|
||||||
typedef std::vector<std::pair<class__class *, method_class *>> MethodListT;
|
typedef std::vector<std::pair<class__class *, method_class *>> MethodListT;
|
||||||
typedef std::vector<attr_class *> AttrListT;
|
typedef std::vector<attr_class *> AttrListT;
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ public:
|
|||||||
return &*itr;
|
return &*itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert(0);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
void add(LocationTableItem item) {
|
void add(LocationTableItem item) {
|
||||||
@ -76,6 +79,9 @@ private:
|
|||||||
int stringclasstag;
|
int stringclasstag;
|
||||||
int intclasstag;
|
int intclasstag;
|
||||||
int boolclasstag;
|
int boolclasstag;
|
||||||
|
IntEntry* _int_default = nullptr;
|
||||||
|
StringEntry* _str_default = nullptr;
|
||||||
|
BoolConst* _bool_default = nullptr;
|
||||||
int label_count = 0; // an incremental counter to avoid label conflicts
|
int label_count = 0; // an incremental counter to avoid label conflicts
|
||||||
|
|
||||||
// The following methods emit code for
|
// The following methods emit code for
|
||||||
@ -103,15 +109,22 @@ private:
|
|||||||
void code_dispatchTable();
|
void code_dispatchTable();
|
||||||
void code_prototypeObject();
|
void code_prototypeObject();
|
||||||
CgenNode *get_node(Symbol);
|
CgenNode *get_node(Symbol);
|
||||||
|
void code_objectTab();
|
||||||
void gen_init_code();
|
void gen_init_code();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LocationTable loctab;
|
LocationTable loctab;
|
||||||
|
Symbol expr_type_decl;
|
||||||
|
CgenNode* cur_class;
|
||||||
CgenClassTable(Classes, ostream &str);
|
CgenClassTable(Classes, ostream &str);
|
||||||
void code();
|
void code();
|
||||||
CgenNode* root() { return nodes[0]; }
|
CgenNode* root() { return nodes[0]; }
|
||||||
/* aquire an unused label index */
|
/* aquire an unused label index */
|
||||||
int alloc_label_index() { return label_count++; }
|
int alloc_label_index() { return label_count++; }
|
||||||
|
IntEntry* int_default() const { return _int_default; };
|
||||||
|
StringEntry* str_default() const { return _str_default; };
|
||||||
|
BoolConst* bool_default() const { return _bool_default; };
|
||||||
|
int get_method_index(Symbol class_name, Symbol method_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CgenNode : public class__class {
|
class CgenNode : public class__class {
|
||||||
|
|||||||
@ -53,6 +53,31 @@ class D inherits C {
|
|||||||
method_common(x1: Int) : SELF_TYPE {
|
method_common(x1: Int) : SELF_TYPE {
|
||||||
self
|
self
|
||||||
};
|
};
|
||||||
|
method_new() : D {
|
||||||
|
new D
|
||||||
|
};
|
||||||
|
method_new_SELF() : D {
|
||||||
|
new SELF_TYPE
|
||||||
|
};
|
||||||
|
method_new2() : Object {
|
||||||
|
(new SELF_TYPE).method_2(false, self)
|
||||||
|
};
|
||||||
|
method_staticdispath() : Object {
|
||||||
|
(new SELF_TYPE)@D.method_2(false, self)
|
||||||
|
};
|
||||||
|
method_case(x1 : Object) : Int {
|
||||||
|
case (x1) of
|
||||||
|
t1: Bool => 1;
|
||||||
|
t2: Int => 2;
|
||||||
|
t3: String => 3;
|
||||||
|
t4: Object => 4;
|
||||||
|
t5: A => 5;
|
||||||
|
t6: C => 6;
|
||||||
|
t7: B => 7;
|
||||||
|
t8: D => 8;
|
||||||
|
t9: E => 9;
|
||||||
|
esac
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class E {
|
class E {
|
||||||
@ -79,6 +104,18 @@ class E {
|
|||||||
let x2 : Int <- x1 in
|
let x2 : Int <- x1 in
|
||||||
x2 <- x1 + 100
|
x2 <- x1 + 100
|
||||||
};
|
};
|
||||||
|
method_2(x1: Bool, x2: C) : Object {
|
||||||
|
{
|
||||||
|
if (x1) then
|
||||||
|
x2 <- x2.method_common(20)
|
||||||
|
else
|
||||||
|
"hello world"
|
||||||
|
fi;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
method_SELF() : SELF_TYPE {
|
||||||
|
self
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Main inherits IO {
|
class Main inherits IO {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user