https://github.com/akkartik/mu1/blob/master/019type_abbreviations.cc
1
2
3 :(scenarios transform)
4 :(scenario type_abbreviations)
5 type foo = number
6 def main [
7 a:foo <- copy 34
8 ]
9 +transform: product type after expanding abbreviations: "number"
10
11 :(before "End Globals")
12 map<string, type_tree*> Type_abbreviations, Type_abbreviations_snapshot;
13
14
15
16 :(before "End Command Handlers")
17 else if (command == "type") {
18 load_type_abbreviations(in);
19 }
20
21 :(code)
22 void load_type_abbreviations(istream& in) {
23 string new_type_name = next_word(in);
24 assert(has_data(in) || !new_type_name.empty());
25 if (!has_data(in) || new_type_name.empty()) {
26 raise << "incomplete 'type' statement; must be of the form 'type <new type name> = <type expression>'\n" << end();
27 return;
28 }
29 string arrow = next_word(in);
30 assert(has_data(in) || !arrow.empty());
31 if (arrow.empty()) {
32 raise << "incomplete 'type' statement 'type " << new_type_name << "'\n" << end();
33 return;
34 }
35 if (arrow != "=") {
36 raise << "'type' statements must be of the form 'type <new type name> = <type expression>' but got 'type " << new_type_name << ' ' << arrow << "'\n" << end();
37 return;
38 }
39 if (!has_data(in)) {
40 raise << "incomplete 'type' statement 'type " << new_type_name << " ='\n" << end();
41 return;
42 }
43 string old = next_word(in);
44 if (old.empty()) {
45 raise << "incomplete 'type' statement 'type " << new_type_name << " ='\n" << end();
46 raise << "'type' statements must be of the form 'type <new type name> = <type expression>' but got 'type " << new_type_name << ' ' << arrow << "'\n" << end();
47 return;
48 }
49 if (contains_key(Type_abbreviations, new_type_name)) {
50 raise << "'type' conflict: '" << new_type_name << "' defined as both '" << names_to_string_without_quotes(get(Type_abbreviations, new_type_name)) << "' and '" << old << "'\n" << end();
51 return;
52 }
53 trace(9990, "type") << "alias " << new_type_name << " = " << old << end();
54 type_tree* old_type = new_type_tree(old);
55 put(Type_abbreviations, new_type_name, old_type);
56 }
57
58 type_tree* new_type_tree(const string& x) {
59 string_tree* type_names = starts_with(x, "(") ? parse_string_tree(x) : parse_string_list(x);
60 type_tree* result = new_type_tree(type_names);
61 delete type_names;
62 expand_type_abbreviations(result);
63 return result;
64 }
65
66 string_tree* parse_string_list(const string& s) {
67 istringstream in(s);
68 in >> std::noskipws;
69 return parse_property_list(in);
70 }
71
72 :(scenario type_error1)
73 % Hide_errors = true;
74 type foo
75 +error: incomplete 'type' statement 'type foo'
76
77 :(scenario type_error2)
78 % Hide_errors = true;
79 type foo =
80 +error: incomplete 'type' statement 'type foo ='
81
82 :(scenario type_error3)
83 % Hide_errors = true;
84 type foo bar baz
85 +error: 'type' statements must be of the form 'type <new type name> = <type expression>' but got 'type foo bar'
86
87 :(scenario type_conflict_error)
88 % Hide_errors = true;
89 type foo = bar
90 type foo = baz
91 +error: 'type' conflict: 'foo' defined as both 'bar' and 'baz'
92
93 :(scenario type_abbreviation_for_compound)
94 type foo = address:number
95 def main [
96 1:foo <- copy null
97 ]
98 +transform: product type after expanding abbreviations: ("address" "number")
99
100
101
102 :(before "End save_snapshots")
103 Type_abbreviations_snapshot = Type_abbreviations;
104 :(before "End restore_snapshots")
105 restore_type_abbreviations();
106 :(before "End One-time Setup")
107 atexit(clear_type_abbreviations);
108 :(code)
109 void restore_type_abbreviations() {
110 for (map<string, type_tree*>::iterator p = Type_abbreviations.begin(); p != Type_abbreviations.end(); ++p) {
111 if (!contains_key(Type_abbreviations_snapshot, p->first))
112 delete p->second;
113 }
114 Type_abbreviations.clear();
115 Type_abbreviations = Type_abbreviations_snapshot;
116 }
117 void clear_type_abbreviations() {
118 for (map<string, type_tree*>::iterator p = Type_abbreviations.begin(); p != Type_abbreviations.end(); ++p)
119 delete p->second;
120 Type_abbreviations.clear();
121 }
122
123
124
125 :(before "End Mu Types Initialization")
126 put(Type_abbreviations, "&", new_type_tree("address"));
127 put(Type_abbreviations, "@", new_type_tree("array"));
128 put(Type_abbreviations, "num", new_type_tree("number"));
129 put(Type_abbreviations, "bool", new_type_tree("boolean"));
130 put(Type_abbreviations, "char", new_type_tree("character"));
131
132 :(scenario use_type_abbreviations_when_declaring_type_abbreviations)
133 type foo = &:num
134 def main [
135 1:foo <- copy null
136 ]
137 +transform: product type after expanding abbreviations: ("address" "number")
138
139
140
141
142
143 :(scenario abbreviations_for_address_and_array)
144 def main [
145 f 1:&:num
146 f 2:@:num
147 f 3:&:@:num
148 f 4:&:&:@:&:@:num
149 f {5: (array (& num) 3)}
150 ]
151 def f [
152 ]
153 +transform: --- expand type abbreviations in recipe 'main'
154 +transform: ingredient type after expanding abbreviations: ("address" "number")
155 +transform: ingredient type after expanding abbreviations: ("array" "number")
156 +transform: ingredient type after expanding abbreviations: ("address" "array" "number")
157 +transform: ingredient type after expanding abbreviations: ("address" "address" "array" "address" "array" "number")
158 +transform: ingredient type after expanding abbreviations: ("array" ("address" "number") "3")
159
160 :(before "Transform.push_back(update_instruction_operations)")
161 Transform.push_back(expand_type_abbreviations);
162
163
164
165 :(code)
166 void expand_type_abbreviations(const recipe_ordinal r) {
167 expand_type_abbreviations(get(Recipe, r));
168 }
169
170 void expand_type_abbreviations(const recipe& caller) {
171 trace(9991, "transform") << "--- expand type abbreviations in recipe '" << caller.name << "'" << end();
172 for (int i = 0; i < SIZE(caller.steps); ++i) {
173 const instruction& inst = caller.steps.at(i);
174 trace(9991, "transform") << "instruction '" << to_original_string(inst) << end();
175 for (long int i = 0; i < SIZE(inst.ingredients); ++i) {
176 expand_type_abbreviations(inst.ingredients.at(i).type);
177 trace(9992, "transform") << "ingredient type after expanding abbreviations: " << names_to_string(inst.ingredients.at(i).type) << end();
178 }
179 for (long int i = 0; i < SIZE(inst.products); ++i) {
180 expand_type_abbreviations(inst.products.at(i).type);
181 trace(9992, "transform") << "product type after expanding abbreviations: " << names_to_string(inst.products.at(i).type) << end();
182 }
183 }
184
185 }
186
187 void expand_type_abbreviations(type_tree* type) {
188 if (!type) return;
189 if (!type->atom) {
190 expand_type_abbreviations(type->left);
191 expand_type_abbreviations(type->right);
192 return;
193 }
194 if (contains_key(Type_abbreviations, type->name))
195 *type = type_tree(*get(Type_abbreviations, type->name));
196 }