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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
//: Containers contain a fixed number of elements of different types.
:(before "End Mu Types Initialization")
//: We'll use this container as a running example, with two integer elements.
int point = Type_number["point"] = Next_type_number++;
Type[point].size = 2;
Type[point].kind = container;
Type[point].name = "point";
vector<type_number> i;
i.push_back(integer);
Type[point].elements.push_back(i);
Type[point].elements.push_back(i);
:(scenario copy_multiple_locations)
# Containers can be copied around with a single instruction just like integers,
# no matter how large they are.
recipe main [
1:integer <- copy 34:literal
2:integer <- copy 35:literal
3:point <- copy 1:point
]
+run: ingredient 0 is 1
+mem: location 1 is 34
+mem: location 2 is 35
+mem: storing 34 in location 3
+mem: storing 35 in location 4
:(before "End Mu Types Initialization")
// A more complex container, containing another container as one of its
// elements.
int point_integer = Type_number["point-integer"] = Next_type_number++;
Type[point_integer].size = 2;
Type[point_integer].kind = container;
Type[point_integer].name = "point-integer";
vector<type_number> p2;
p2.push_back(point);
Type[point_integer].elements.push_back(p2);
vector<type_number> i2;
i2.push_back(integer);
Type[point_integer].elements.push_back(i2);
:(scenario "copy_handles_nested_container_elements")
recipe main [
12:integer <- copy 34:literal
13:integer <- copy 35:literal
14:integer <- copy 36:literal
15:point-integer <- copy 12:point-integer
]
+mem: storing 36 in location 17
:(before "End size_of(types) Cases")
type_info t = Type[types[0]];
if (t.kind == container) {
// size of a container is the sum of the sizes of its elements
size_t result = 0;
for (size_t i = 0; i < t.elements.size(); ++i) {
result += size_of(t.elements[i]);
}
return result;
}
//:: To access elements of a container, use 'get'
:(scenario "get")
recipe main [
12:integer <- copy 34:literal
13:integer <- copy 35:literal
15:integer <- get 12:point, 1:offset
]
+run: instruction main/2
+run: ingredient 0 is 12
+run: ingredient 1 is 1
+run: address to copy is 13
+run: its type is 1
+mem: location 13 is 35
+run: product 0 is 35
+mem: storing 35 in location 15
:(before "End Primitive Recipe Declarations")
GET,
:(before "End Primitive Recipe Numbers")
Recipe_number["get"] = GET;
:(before "End Primitive Recipe Implementations")
case GET: {
trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name;
reagent base = instructions[pc].ingredients[0];
int base_address = base.value;
int base_type = base.types[0];
assert(Type[base_type].kind == container);
trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name;
assert(isa_literal(instructions[pc].ingredients[1]));
size_t offset = instructions[pc].ingredients[1].value;
int src = base_address;
for (size_t i = 0; i < offset; ++i) {
src += size_of(Type[base_type].elements[i]);
}
trace("run") << "address to copy is " << src;
assert(Type[base_type].kind == container);
assert(Type[base_type].elements.size() > offset);
int src_type = Type[base_type].elements[offset][0];
trace("run") << "its type is " << src_type;
reagent tmp;
tmp.set_value(src);
tmp.types.push_back(src_type);
vector<int> result(read_memory(tmp));
trace("run") << "product 0 is " << result[0];
write_memory(instructions[pc].products[0], result);
break;
}
//: 'get' requires a literal in ingredient 1. We'll use a synonym called
//: 'offset'.
:(before "End Mu Types Initialization")
Type_number["offset"] = 0;
:(scenario "get_handles_nested_container_elements")
recipe main [
12:integer <- copy 34:literal
13:integer <- copy 35:literal
14:integer <- copy 36:literal
15:integer <- get 12:point-integer, 1:offset
]
+run: instruction main/2
+run: ingredient 0 is 12
+run: ingredient 1 is 1
+run: address to copy is 14
+run: its type is 1
+mem: location 14 is 36
+run: product 0 is 36
+mem: storing 36 in location 15
//:: To write to elements of containers, you need their address.
:(scenario "get_address")
recipe main [
12:integer <- copy 34:literal
13:integer <- copy 35:literal
15:address:integer <- get-address 12:point, 1:offset
]
+run: instruction main/2
+run: ingredient 0 is 12
+run: ingredient 1 is 1
+run: address to copy is 13
+mem: storing 13 in location 15
:(before "End Primitive Recipe Declarations")
GET_ADDRESS,
:(before "End Primitive Recipe Numbers")
Recipe_number["get-address"] = GET_ADDRESS;
:(before "End Primitive Recipe Implementations")
case GET_ADDRESS: {
trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name;
reagent base = instructions[pc].ingredients[0];
int base_address = base.value;
int base_type = base.types[0];
assert(Type[base_type].kind == container);
trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name;
assert(isa_literal(instructions[pc].ingredients[1]));
size_t offset = instructions[pc].ingredients[1].value;
int src = base_address;
for (size_t i = 0; i < offset; ++i) {
src += size_of(Type[base_type].elements[i]);
}
trace("run") << "address to copy is " << src;
vector<int> result;
result.push_back(src);
trace("run") << "product 0 is " << result[0];
write_memory(instructions[pc].products[0], result);
break;
}
|