-
Notifications
You must be signed in to change notification settings - Fork 10
/
list.cl
141 lines (108 loc) · 3.87 KB
/
list.cl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
(*
* This file shows how to implement a list data type for lists of integers.
* It makes use of INHERITANCE and DYNAMIC DISPATCH.
*
* The List class has 4 operations defined on List objects. If 'l' is
* a list, then the methods dispatched on 'l' have the following effects:
*
* isNil() : Bool Returns true if 'l' is empty, false otherwise.
* head() : Int Returns the integer at the head of 'l'.
* If 'l' is empty, execution aborts.
* tail() : List Returns the remainder of the 'l',
* i.e. without the first element.
* cons(i : Int) : List Return a new list containing i as the
* first element, followed by the
* elements in 'l'.
*
* There are 2 kinds of lists, the empty list and a non-empty
* list. We can think of the non-empty list as a specialization of
* the empty list.
* The class List defines the operations on empty list. The class
* Cons inherits from List and redefines things to handle non-empty
* lists.
*)
class List {
-- Define operations on empty lists.
isNil() : Bool { true };
-- Since abort() has return type Object and head() has return type
-- Int, we need to have an Int as the result of the method body,
-- even though abort() never returns.
head() : Int { { abort(); 0; } };
-- As for head(), the self is just to make sure the return type of
-- tail() is correct.
tail() : List { { abort(); self; } };
-- When we cons and element onto the empty list we get a non-empty
-- list. The (new Cons) expression creates a new list cell of class
-- Cons, which is initialized by a dispatch to init().
-- The result of init() is an element of class Cons, but it
-- conforms to the return type List, because Cons is a subclass of
-- List.
cons(i : Int) : List {
(new Cons).init(i, self)
};
};
(*
* Cons inherits all operations from List. We can reuse only the cons
* method though, because adding an element to the front of an emtpy
* list is the same as adding it to the front of a non empty
* list. All other methods have to be redefined, since the behaviour
* for them is different from the empty list.
*
* Cons needs two attributes to hold the integer of this list
* cell and to hold the rest of the list.
*
* The init() method is used by the cons() method to initialize the
* cell.
*)
class Cons inherits List {
car : Int; -- The element in this list cell
cdr : List; -- The rest of the list
isNil() : Bool { false };
head() : Int { car };
tail() : List { cdr };
init(i : Int, rest : List) : List {
{
car <- i;
cdr <- rest;
self;
}
};
};
(*
* The Main class shows how to use the List class. It creates a small
* list and then repeatedly prints out its elements and takes off the
* first element of the list.
*)
class Main inherits IO {
mylist : List;
-- Print all elements of the list. Calls itself recursively with
-- the tail of the list, until the end of the list is reached.
print_list(l : List) : Object {
if l.isNil() then out_string("\n")
else {
out_int(l.head());
out_string(" ");
print_list(l.tail());
}
fi
};
-- Note how the dynamic dispatch mechanism is responsible to end
-- the while loop. As long as mylist is bound to an object of
-- dynamic type Cons, the dispatch to isNil calls the isNil method of
-- the Cons class, which returns false. However when we reach the
-- end of the list, mylist gets bound to the object that was
-- created by the (new List) expression. This object is of dynamic type
-- List, and thus the method isNil in the List class is called and
-- returns true.
main() : Object {
{
mylist <- new List.cons(1).cons(2).cons(3).cons(4).cons(5);
while (not mylist.isNil()) loop
{
print_list(mylist);
mylist <- mylist.tail();
}
pool;
}
};
};