about summary refs log tree commit diff stats
path: root/cpp/018record
blob: 5818881333a2d583bcb69a7a388a0244ad0f2ecc (plain) (blame)
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
//: Records contain a fixed number of elements of different types.
:(before "End Mu Types Initialization")
//: We'll use this record as a running example, with two integer elements
int point = Type_number["point"] = Next_type_number++;
Type[point].size = 2;
Type[point].is_record = true;
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)
# Records 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 record, containing another record.
int point_integer = Type_number["point-integer"] = Next_type_number++;
Type[point_integer].size = 2;
Type[point_integer].is_record = true;
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_record_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.is_record) {
  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 record, 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 Globals")
const int GET = 18;
:(before "End Primitive Recipe Numbers")
Recipe_number["get"] = GET;
assert(Next_recipe_number == GET);
Next_recipe_number++;
:(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].is_record);
  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].is_record);
  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_record_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

:(before "End Globals")
// To write to fields of records, you need their address.
const int GET_ADDRESS = 19;
:(before "End Primitive Recipe Numbers")
Recipe_number["get-address"] = GET_ADDRESS;
assert(Next_recipe_number == GET_ADDRESS);
Next_recipe_number++;
:(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].is_record);
  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;
}

:(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