Line | Branch | Exec | Source |
---|---|---|---|
1 | |||
2 | #include <gyoji-frontend.hpp> | ||
3 | #include <gyoji-frontend/function-scope.hpp> | ||
4 | #include <sstream> | ||
5 | |||
6 | using namespace Gyoji::frontend::lowering; | ||
7 | |||
8 | /////////////////////////////////////////////////// | ||
9 | // Graph-theoretic utilities just to walk graphs | ||
10 | // and find intersections, differences. | ||
11 | /////////////////////////////////////////////////// | ||
12 | 24 | static void walk_priors( | |
13 | const std::map<size_t, size_t> & backward_edges, | ||
14 | size_t start_point, | ||
15 | std::map<size_t, size_t> & priors) | ||
16 | { | ||
17 | 24 | size_t p = start_point; | |
18 | while (p >= 0) { | ||
19 | 110 | priors.insert(std::pair(p,p)); | |
20 | 110 | const auto & it = backward_edges.find(p); | |
21 |
2/2✓ Branch 2 taken 24 times.
✓ Branch 3 taken 86 times.
|
110 | if (it == backward_edges.end()) { |
22 | 24 | break; | |
23 | } | ||
24 | 86 | p = it->second; | |
25 | 86 | } | |
26 | 24 | } | |
27 | |||
28 | static void | ||
29 | 12 | evaluate_scope_changes( | |
30 | const std::vector<const ScopeOperation*> & flat, | ||
31 | const std::map<size_t, size_t> & prior_to_goto, | ||
32 | const std::map<size_t, size_t> & prior_to_label, | ||
33 | std::vector<const ScopeOperation*> & skipped_initializations, | ||
34 | std::vector<const ScopeOperation*> & unwind_variables | ||
35 | ) | ||
36 | { | ||
37 |
2/2✓ Branch 5 taken 56 times.
✓ Branch 6 taken 12 times.
|
68 | for (const auto & lp : prior_to_label) { |
38 |
2/2✓ Branch 3 taken 20 times.
✓ Branch 4 taken 36 times.
|
56 | if (prior_to_goto.find(lp.first) == prior_to_goto.end()) { |
39 | 20 | const ScopeOperation *op = flat.at(lp.first); | |
40 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
|
20 | if (op->get_type() == ScopeOperation::VAR_DECL) { |
41 | 10 | skipped_initializations.push_back(op); | |
42 | } | ||
43 | } | ||
44 | } | ||
45 |
2/2✓ Branch 5 taken 54 times.
✓ Branch 6 taken 12 times.
|
66 | for (const auto & gp : prior_to_goto) { |
46 |
2/2✓ Branch 3 taken 18 times.
✓ Branch 4 taken 36 times.
|
54 | if (prior_to_label.find(gp.first) == prior_to_label.end()) { |
47 | 18 | const ScopeOperation *op = flat.at(gp.first); | |
48 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
|
18 | if (op->get_type() == ScopeOperation::VAR_DECL) { |
49 | 8 | unwind_variables.push_back(op); | |
50 | } | ||
51 | } | ||
52 | } | ||
53 | // We reverse the list because | ||
54 | // we should unwind the variables | ||
55 | // in the reverse order they were declared in. | ||
56 | 12 | std::reverse(unwind_variables.begin(), unwind_variables.end()); | |
57 | 12 | } | |
58 | |||
59 | /////////////////////////////////////////////////// | ||
60 | // ScopeOperation | ||
61 | /////////////////////////////////////////////////// | ||
62 | 946 | ScopeOperation::ScopeOperation( | |
63 | ScopeOperationType _type, | ||
64 | const Gyoji::context::SourceReference & _source_ref | ||
65 | 946 | ) | |
66 | 946 | : type(_type) | |
67 | 946 | , source_ref(_source_ref) | |
68 | 946 | {} | |
69 | |||
70 | 946 | ScopeOperation::~ScopeOperation() | |
71 | 946 | {} | |
72 | |||
73 | const ScopeOperation::ScopeOperationType & | ||
74 | 86 | ScopeOperation::get_type() const | |
75 | 86 | { return type; } | |
76 | |||
77 | const std::string & | ||
78 | 18 | ScopeOperation::get_label_name() const | |
79 | 18 | { return label_name; } | |
80 | |||
81 | const std::string & | ||
82 | 40 | ScopeOperation::get_goto_label() const | |
83 | 40 | { return goto_label; } | |
84 | |||
85 | const FunctionPoint & | ||
86 | 4 | ScopeOperation::get_goto_point() const | |
87 | 4 | { return *goto_point; } | |
88 | |||
89 | const std::string & | ||
90 | 46 | ScopeOperation::get_variable_name() const | |
91 | 46 | { return variable_name; } | |
92 | |||
93 | Gyoji::owned<ScopeOperation> | ||
94 | 858 | ScopeOperation::create_variable( | |
95 | std::string _variable_name, | ||
96 | const Gyoji::mir::Type *_variable_type, | ||
97 | const Gyoji::context::SourceReference & _source_ref | ||
98 | ) | ||
99 | { | ||
100 | 858 | auto op = Gyoji::owned<ScopeOperation>(new ScopeOperation(ScopeOperation::VAR_DECL, _source_ref)); | |
101 | 858 | op->variable_name = _variable_name; | |
102 | 858 | op->variable_type = _variable_type; | |
103 | 858 | return op; | |
104 | } | ||
105 | Gyoji::owned<ScopeOperation> | ||
106 | 10 | ScopeOperation::create_label( | |
107 | std::string _label_name, | ||
108 | const Gyoji::context::SourceReference & _source_ref | ||
109 | ) | ||
110 | { | ||
111 | 10 | auto op = Gyoji::owned<ScopeOperation>(new ScopeOperation(ScopeOperation::LABEL_DEFINITION, _source_ref)); | |
112 | 10 | op->label_name = _label_name; | |
113 | 10 | return op; | |
114 | } | ||
115 | |||
116 | Gyoji::owned<ScopeOperation> | ||
117 | 12 | ScopeOperation::create_goto( | |
118 | std::string _goto_label, | ||
119 | Gyoji::owned<FunctionPoint> _goto_point, | ||
120 | const Gyoji::context::SourceReference & _source_ref | ||
121 | ) | ||
122 | { | ||
123 | 12 | auto op = Gyoji::owned<ScopeOperation>(new ScopeOperation(ScopeOperation::GOTO_DEFINITION, _source_ref)); | |
124 | 12 | op->goto_label = _goto_label; | |
125 | 12 | op->goto_point = std::move(_goto_point); | |
126 | 12 | return op; | |
127 | } | ||
128 | |||
129 | Gyoji::owned<ScopeOperation> | ||
130 | 66 | ScopeOperation::create_child( | |
131 | Gyoji::owned<Scope> _child, | ||
132 | const Gyoji::context::SourceReference & _source_ref | ||
133 | ) | ||
134 | { | ||
135 | 66 | auto op = Gyoji::owned<ScopeOperation>(new ScopeOperation(ScopeOperation::CHILD_SCOPE, _source_ref)); | |
136 | 66 | op->child = std::move(_child); | |
137 | 66 | return op; | |
138 | } | ||
139 | |||
140 | const Gyoji::context::SourceReference & | ||
141 | 12 | ScopeOperation::get_source_ref() const | |
142 | 12 | { return source_ref; } | |
143 | |||
144 | /////////////////////////////////////////////////// | ||
145 | // Scope | ||
146 | /////////////////////////////////////////////////// | ||
147 | 334 | Scope::Scope() | |
148 | 334 | : parent(nullptr) | |
149 | 334 | , scope_is_loop(false) | |
150 | 334 | , loop_break_blockid(0) | |
151 | 334 | , loop_continue_blockid(0) | |
152 | 334 | {} | |
153 | |||
154 | 4 | Scope::Scope( | |
155 | bool _is_loop, | ||
156 | size_t _loop_break_blockid, | ||
157 | size_t _loop_continue_blockid | ||
158 | 4 | ) | |
159 | 4 | : parent(nullptr) | |
160 | 4 | , scope_is_loop(_is_loop) | |
161 | 4 | , loop_break_blockid(_loop_break_blockid) | |
162 | 4 | , loop_continue_blockid(_loop_continue_blockid) | |
163 | 4 | {} | |
164 | |||
165 | 338 | Scope::~Scope() | |
166 | 338 | {} | |
167 | |||
168 | void | ||
169 | 946 | Scope::add_operation(Gyoji::owned<ScopeOperation> op) | |
170 | { | ||
171 | 946 | operations.push_back(std::move(op)); | |
172 | 946 | } | |
173 | |||
174 | #if 0 | ||
175 | void | ||
176 | Scope::add_variable(std::string name, const Gyoji::mir::Type *type, const Gyoji::context::SourceReference & source_ref) | ||
177 | { | ||
178 | } | ||
179 | #endif | ||
180 | |||
181 | const LocalVariable * | ||
182 | 2230 | Scope::get_variable(std::string name) const | |
183 | { | ||
184 | 2230 | const auto & it = variables.find(name); | |
185 |
2/2✓ Branch 2 taken 1052 times.
✓ Branch 3 taken 1178 times.
|
2230 | if (it == variables.end()) { |
186 | 1052 | return nullptr; | |
187 | } | ||
188 | 1178 | return it->second.get(); | |
189 | } | ||
190 | |||
191 | bool | ||
192 | 22 | Scope::is_loop() const | |
193 | { | ||
194 | 22 | return scope_is_loop; | |
195 | } | ||
196 | size_t | ||
197 | 2 | Scope::get_loop_break_blockid() const | |
198 | 2 | { return loop_break_blockid; } | |
199 | |||
200 | size_t | ||
201 | 2 | Scope::get_loop_continue_blockid() const | |
202 | 2 | { return loop_continue_blockid; } | |
203 | |||
204 | const std::map<std::string, Gyoji::owned<LocalVariable>> & | ||
205 | 334 | Scope::get_variables() const | |
206 | 334 | { return variables; } | |
207 | |||
208 | /////////////////////////////////////////////////// | ||
209 | // ScopeTracker | ||
210 | /////////////////////////////////////////////////// | ||
211 | 272 | ScopeTracker::ScopeTracker(const Gyoji::context::CompilerContext & _compiler_context) | |
212 | 272 | : root(std::make_unique<Scope>()) | |
213 | 272 | , compiler_context(_compiler_context) | |
214 | 272 | , tracker_prior_point() | |
215 | 272 | , tracker_backward_edges() | |
216 | 544 | , tracker_flat() | |
217 | { | ||
218 | 272 | tracker_prior_point.push_back((size_t)-1); | |
219 | 272 | current = root.get(); | |
220 | 272 | } | |
221 | |||
222 | 272 | ScopeTracker::~ScopeTracker() | |
223 | { | ||
224 | 272 | } | |
225 | |||
226 | |||
227 | void | ||
228 | 62 | ScopeTracker::scope_push(const Gyoji::context::SourceReference & _source_ref) | |
229 | { | ||
230 | 62 | auto child_scope = std::make_unique<Scope>(); | |
231 | 62 | Scope *new_current = child_scope.get(); | |
232 | 62 | child_scope->parent = current; | |
233 | 62 | auto child_op = ScopeOperation::create_child(std::move(child_scope), _source_ref); | |
234 | 62 | current->add_operation(std::move(child_op)); | |
235 | 62 | current = new_current; | |
236 | 62 | tracker_prior_point.push_back(tracker_prior_point.back()); | |
237 | 62 | } | |
238 | void | ||
239 | 4 | ScopeTracker::scope_push_loop(const Gyoji::context::SourceReference & _source_ref, size_t _loop_break_blockid, size_t _loop_continue_blockid) | |
240 | { | ||
241 | 4 | auto child_scope = std::make_unique<Scope>(true, _loop_break_blockid, _loop_continue_blockid); | |
242 | 4 | Scope *new_current = child_scope.get(); | |
243 | 4 | child_scope->parent = current; | |
244 | 4 | auto child_op = ScopeOperation::create_child(std::move(child_scope), _source_ref); | |
245 | 4 | current->add_operation(std::move(child_op)); | |
246 | 4 | current = new_current; | |
247 | 4 | tracker_prior_point.push_back(tracker_prior_point.back()); | |
248 | 4 | } | |
249 | |||
250 | |||
251 | void | ||
252 | 66 | ScopeTracker::scope_pop() | |
253 | { | ||
254 | 66 | current = current->parent; | |
255 | 66 | tracker_prior_point.pop_back(); | |
256 | 66 | } | |
257 | |||
258 | |||
259 | const FunctionLabel * | ||
260 | 16 | ScopeTracker::get_label(std::string name) const | |
261 | { | ||
262 | 16 | const auto & it_forward_declared = labels_forward_declared.find(name); | |
263 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
|
16 | if (it_forward_declared != labels_forward_declared.end()) { |
264 | ✗ | return it_forward_declared->second.get(); | |
265 | } | ||
266 | 16 | const auto & it = labels.find(name); | |
267 |
2/2✓ Branch 2 taken 14 times.
✓ Branch 3 taken 2 times.
|
16 | if (it != labels.end()) { |
268 | 14 | return it->second.get(); | |
269 | } | ||
270 | 2 | return nullptr; | |
271 | } | ||
272 | |||
273 | void | ||
274 | 2 | ScopeTracker::label_define( | |
275 | std::string label_name, | ||
276 | const Gyoji::context::SourceReference & _source_ref | ||
277 | ) | ||
278 | { | ||
279 | 2 | const auto & it_forward_declared = labels_forward_declared.find(label_name); | |
280 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (it_forward_declared == labels_forward_declared.end()) { |
281 | ✗ | fprintf(stderr, "Compiler Bug! We are attempting to resolve the definition of a forward-declared label, but it wasn't forward-declared.\n"); | |
282 | ✗ | exit(1); | |
283 | return; | ||
284 | } | ||
285 | 2 | it_forward_declared->second->resolve(_source_ref); | |
286 | 2 | labels.insert(std::pair(label_name, std::move(it_forward_declared->second))); | |
287 | 2 | labels_forward_declared.erase(it_forward_declared); | |
288 | |||
289 | 2 | auto op = ScopeOperation::create_label(label_name, _source_ref); | |
290 | 2 | tracker_label_locations.insert(std::pair(op->get_label_name(), tracker_flat.size())); | |
291 | 2 | add_flat_op(op.get()); | |
292 | |||
293 | 2 | add_operation(std::move(op)); | |
294 | 2 | } | |
295 | |||
296 | void | ||
297 | 8 | ScopeTracker::label_define( | |
298 | std::string label_name, | ||
299 | size_t label_blockid, | ||
300 | const Gyoji::context::SourceReference & _source_ref | ||
301 | ) | ||
302 | { | ||
303 | 8 | Gyoji::owned<FunctionLabel> new_label = std::make_unique<FunctionLabel>(label_blockid); | |
304 | 8 | new_label->resolve(_source_ref); | |
305 | 8 | labels.insert(std::pair(label_name, std::move(new_label))); | |
306 | |||
307 | 8 | auto op = ScopeOperation::create_label(label_name, _source_ref); | |
308 | 8 | tracker_label_locations.insert(std::pair(op->get_label_name(), tracker_flat.size())); | |
309 | 8 | add_flat_op(op.get()); | |
310 | 8 | add_operation(std::move(op)); | |
311 | 8 | } | |
312 | |||
313 | // Use this for 'goto' to say we want a label, but we | ||
314 | // don't yet know where it will live, so put it on the | ||
315 | // notfound labels list. | ||
316 | void | ||
317 | 2 | ScopeTracker::label_declare(std::string label_name, size_t label_blockid) | |
318 | { | ||
319 | 2 | Gyoji::owned<FunctionLabel> new_label = std::make_unique<FunctionLabel>(label_blockid); | |
320 | 2 | labels_forward_declared.insert(std::pair(label_name, std::move(new_label))); | |
321 | 2 | } | |
322 | |||
323 | void | ||
324 | 880 | ScopeTracker::add_flat_op(const ScopeOperation *op) | |
325 | { | ||
326 |
2/2✓ Branch 1 taken 610 times.
✓ Branch 2 taken 270 times.
|
880 | if (tracker_prior_point.back() != (size_t)-1) { |
327 | 610 | tracker_backward_edges.insert(std::pair(tracker_flat.size(), tracker_prior_point.back())); | |
328 | } | ||
329 | 880 | tracker_prior_point.back() = tracker_flat.size(); | |
330 | 880 | tracker_flat.push_back(op); | |
331 | 880 | } | |
332 | |||
333 | |||
334 | void | ||
335 | 12 | ScopeTracker::add_goto( | |
336 | std::string goto_label, | ||
337 | Gyoji::owned<FunctionPoint> goto_point, | ||
338 | const Gyoji::context::SourceReference & _source_ref | ||
339 | ) | ||
340 | { | ||
341 | // TODO: | ||
342 | // Check if this label exists and jump to that | ||
343 | // label if it does. If it doesn't, forward declare it. | ||
344 | // and put it in the 'forward declared' labels list. | ||
345 | 12 | auto op = ScopeOperation::create_goto(goto_label, std::move(goto_point), _source_ref); | |
346 | 12 | tracker_goto_labels_at.insert(std::pair(tracker_flat.size(), op->get_goto_label())); | |
347 | 12 | add_flat_op(op.get()); | |
348 | 12 | add_operation(std::move(op)); | |
349 | 12 | } | |
350 | |||
351 | const LocalVariable * | ||
352 | 2102 | ScopeTracker::get_variable(std::string variable_name) const | |
353 | { | ||
354 | // Walk up from the current scope up to the root and | ||
355 | // see if this variable is defined anywhere. | ||
356 | 2102 | const Scope *s = current; | |
357 |
2/2✓ Branch 0 taken 2230 times.
✓ Branch 1 taken 924 times.
|
3154 | while (s) { |
358 | 2230 | const LocalVariable *existing_local_variable = s->get_variable(variable_name); | |
359 |
2/2✓ Branch 0 taken 1178 times.
✓ Branch 1 taken 1052 times.
|
2230 | if (existing_local_variable != nullptr) { |
360 | 1178 | return existing_local_variable; | |
361 | } | ||
362 | 1052 | s = s->parent; | |
363 | } | ||
364 | 924 | return nullptr; | |
365 | } | ||
366 | |||
367 | std::vector<std::string> | ||
368 | 284 | ScopeTracker::get_variables_to_unwind_for_root() const | |
369 | { | ||
370 | 284 | std::vector<std::string> variables_to_unwind; | |
371 | 284 | const Scope *s = current; | |
372 |
2/2✓ Branch 0 taken 302 times.
✓ Branch 1 taken 284 times.
|
586 | while (s) { |
373 |
2/2✓ Branch 6 taken 888 times.
✓ Branch 7 taken 302 times.
|
1190 | for (const auto & it : s->get_variables()) { |
374 | 888 | variables_to_unwind.push_back(it.first); | |
375 | } | ||
376 | 302 | s = s->parent; | |
377 | } | ||
378 | 284 | return variables_to_unwind; | |
379 | } | ||
380 | |||
381 | std::vector<std::string> | ||
382 | 32 | ScopeTracker::get_variables_to_unwind_for_scope() const | |
383 | { | ||
384 | 32 | std::vector<std::string> variables_to_unwind; | |
385 | 32 | const Scope *s = current; | |
386 |
2/2✓ Branch 6 taken 14 times.
✓ Branch 7 taken 32 times.
|
46 | for (const auto & it : s->get_variables()) { |
387 | 14 | variables_to_unwind.push_back(it.first); | |
388 | } | ||
389 | 32 | return variables_to_unwind; | |
390 | } | ||
391 | |||
392 | std::vector<std::string> | ||
393 | 2 | ScopeTracker::get_variables_to_unwind_for_break() const | |
394 | { | ||
395 | 2 | std::vector<std::string> variables_to_unwind; | |
396 | 2 | const Scope *s = current; | |
397 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
|
2 | while (s && s->is_loop()) { |
398 | ✗ | for (const auto & it : s->get_variables()) { | |
399 | ✗ | variables_to_unwind.push_back(it.first); | |
400 | } | ||
401 | ✗ | s = s->parent; | |
402 | } | ||
403 | 2 | return variables_to_unwind; | |
404 | |||
405 | } | ||
406 | |||
407 | const Scope * | ||
408 | ✗ | ScopeTracker::get_current() const | |
409 | ✗ | { return current; } | |
410 | |||
411 | bool | ||
412 | 860 | ScopeTracker::add_variable(std::string variable_name, const Gyoji::mir::Type *mir_type, const Gyoji::context::SourceReference & source_ref) | |
413 | { | ||
414 | // Walk up from the current scope up to the root and | ||
415 | // see if this variable is defined anywhere. | ||
416 | 860 | const LocalVariable *maybe_existing = get_variable(variable_name); | |
417 | |||
418 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 858 times.
|
860 | if (maybe_existing != nullptr) { |
419 | 2 | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>("Duplicate Local Variable."); | |
420 | 4 | error->add_message(source_ref, | |
421 | 4 | std::string("Variable with name ") + variable_name + " is already in scope and cannot be duplicated."); | |
422 | 4 | error->add_message(maybe_existing->get_source_ref(), | |
423 | "First declared here."); | ||
424 | |||
425 | 2 | compiler_context | |
426 | 2 | .get_errors() | |
427 | 2 | .add_error(std::move(error)); | |
428 | 2 | return false; | |
429 | 2 | } | |
430 | |||
431 | |||
432 | // Variable was not declared earlier, so we add it to | ||
433 | // the current scope. | ||
434 | 858 | Gyoji::owned<LocalVariable> local_variable = std::make_unique<LocalVariable>(mir_type, source_ref); | |
435 | 858 | current->variables.insert(std::pair(variable_name, std::move(local_variable))); | |
436 | |||
437 | 858 | auto local_var_op = ScopeOperation::create_variable(variable_name, mir_type, source_ref); | |
438 | 858 | add_flat_op(local_var_op.get()); | |
439 | 858 | add_operation(std::move(local_var_op)); | |
440 | |||
441 | 858 | return true; | |
442 | 858 | } | |
443 | |||
444 | |||
445 | // TODO: We should give a better interface | ||
446 | // here so we can easily declare locals, labels, gotos. | ||
447 | void | ||
448 | 880 | ScopeTracker::add_operation(Gyoji::owned<ScopeOperation> op) | |
449 | { | ||
450 | 880 | current->add_operation(std::move(op)); | |
451 | 880 | } | |
452 | |||
453 | |||
454 | // Now from this, I can evaluate | ||
455 | // what's legal. We only need to add the 'SourceReference' | ||
456 | // stuff in order to produce good errors for this. | ||
457 | void | ||
458 | 6 | ScopeTracker::dump() const | |
459 | { | ||
460 | 6 | Scope *s = root.get(); | |
461 | 6 | fprintf(stderr, "{\n"); | |
462 | 6 | s->dump(0); | |
463 | 6 | fprintf(stderr, "}\n"); | |
464 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 6 times.
|
54 | for (size_t i = 0; i < tracker_flat.size(); i++) { |
465 | 48 | const auto & op = tracker_flat.at(i); | |
466 |
3/5✓ Branch 1 taken 30 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
48 | switch (op->get_type()) { |
467 | 30 | case ScopeOperation::VAR_DECL: | |
468 | 30 | fprintf(stderr, "%ld Var decl %s\n", i, op->get_variable_name().c_str()); | |
469 | 30 | break; | |
470 | 8 | case ScopeOperation::LABEL_DEFINITION: | |
471 | 8 | fprintf(stderr, "%ld label %s\n", i, op->get_label_name().c_str()); | |
472 | 8 | break; | |
473 | 10 | case ScopeOperation::GOTO_DEFINITION: | |
474 | 10 | fprintf(stderr, "%ld goto %s\n", i, op->get_goto_label().c_str()); | |
475 | 10 | break; | |
476 | ✗ | case ScopeOperation::CHILD_SCOPE: | |
477 | ✗ | fprintf(stderr, "This should not be here\n"); | |
478 | ✗ | exit(1); | |
479 | } | ||
480 | } | ||
481 | 6 | } | |
482 | |||
483 | bool | ||
484 | 4 | ScopeTracker::is_in_loop() const | |
485 | { | ||
486 | 4 | const Scope *s = current; | |
487 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | while (s) { |
488 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
|
10 | if (s->is_loop()) { |
489 | 4 | return true; | |
490 | } | ||
491 | 6 | s = s->parent; | |
492 | } | ||
493 | ✗ | return false; | |
494 | } | ||
495 | |||
496 | size_t | ||
497 | 2 | ScopeTracker::get_loop_break_blockid() const | |
498 | { | ||
499 | 2 | const Scope *s = current; | |
500 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | while (s) { |
501 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if (s->is_loop()) { |
502 | 2 | return s->get_loop_break_blockid(); | |
503 | } | ||
504 | 2 | s = s->parent; | |
505 | } | ||
506 | ✗ | return 0; | |
507 | } | ||
508 | |||
509 | size_t | ||
510 | 2 | ScopeTracker::get_loop_continue_blockid() const | |
511 | { | ||
512 | 2 | const Scope *s = current; | |
513 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | while (s) { |
514 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
|
6 | if (s->is_loop()) { |
515 | 2 | return s->get_loop_continue_blockid(); | |
516 | } | ||
517 | 4 | s = s->parent; | |
518 | } | ||
519 | ✗ | return 0; | |
520 | } | ||
521 | |||
522 | bool | ||
523 | 272 | ScopeTracker::check( | |
524 | std::vector<std::pair<const ScopeOperation*, std::vector<const ScopeOperation*>>> & goto_fixups | ||
525 | ) const | ||
526 | { | ||
527 | 272 | bool ok = true; | |
528 |
2/2✓ Branch 5 taken 12 times.
✓ Branch 6 taken 272 times.
|
284 | for (const auto & goto_point : tracker_goto_labels_at) { |
529 | 12 | const ScopeOperation *goto_operation = tracker_flat.at(goto_point.first); | |
530 | 12 | const FunctionLabel *function_label = get_label(goto_operation->get_goto_label()); | |
531 |
3/6✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
|
12 | if (function_label == nullptr || !function_label->is_resolved()) { |
532 | ✗ | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>("Goto for an un-defined label."); | |
533 | ✗ | error->add_message(goto_operation->get_source_ref(), | |
534 | ✗ | std::string("Goto label ") + goto_operation->get_goto_label() + " had an undefined destination."); | |
535 | ✗ | compiler_context | |
536 | ✗ | .get_errors() | |
537 | ✗ | .add_error(std::move(error)); | |
538 | ✗ | ok = false; | |
539 | ✗ | continue; | |
540 | ✗ | } | |
541 | |||
542 | 12 | std::map<size_t, size_t> prior_to_goto; | |
543 | 12 | walk_priors(tracker_backward_edges, goto_point.first, prior_to_goto); | |
544 | |||
545 | 12 | std::map<size_t, size_t> prior_to_label; | |
546 | 12 | const auto it = tracker_label_locations.find(goto_point.second); | |
547 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | if (it == tracker_label_locations.end()) { |
548 | ✗ | fprintf(stderr, "This is a bug, we have a defined label, but no location for it\n"); | |
549 | ✗ | exit(1); | |
550 | } | ||
551 | 12 | size_t label_point = it->second; | |
552 | |||
553 | 12 | walk_priors(tracker_backward_edges, label_point, prior_to_label); | |
554 | |||
555 | 12 | std::vector<const ScopeOperation*> skipped_initializations; | |
556 | 12 | std::vector<const ScopeOperation*> unwind_variables; | |
557 | |||
558 | 12 | evaluate_scope_changes(tracker_flat, prior_to_goto, prior_to_label, skipped_initializations, unwind_variables); | |
559 | |||
560 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
|
12 | if (skipped_initializations.size() > 0) { |
561 | 4 | std::unique_ptr<Gyoji::context::Error> error = std::make_unique<Gyoji::context::Error>("Goto would skip initialization."); | |
562 | 8 | error->add_message(goto_operation->get_source_ref(), | |
563 | 16 | std::string("Goto label ") + goto_operation->get_goto_label() + std::string(" would skip initialization of variables in destination scope.")); | |
564 | 8 | error->add_message(function_label->get_source_ref(), | |
565 | "Label declared here."); | ||
566 | 8 | error->add_message(skipped_initializations.at(0)->get_source_ref(), | |
567 | "Skipped initialization occurs here."); | ||
568 | 4 | compiler_context | |
569 | 4 | .get_errors() | |
570 | 4 | .add_error(std::move(error)); | |
571 | 4 | ok = false; | |
572 | 4 | } | |
573 | |||
574 | 12 | goto_fixups.push_back(std::pair(goto_operation, unwind_variables)); | |
575 |
2/2✓ Branch 5 taken 8 times.
✓ Branch 6 taken 12 times.
|
20 | for (const auto & s : unwind_variables) { |
576 | 8 | fprintf(stderr, "Unwind %s\n", s->get_variable_name().c_str()); | |
577 | } | ||
578 | 12 | } | |
579 | 272 | return ok; | |
580 | } | ||
581 | |||
582 | void | ||
583 | 64 | ScopeOperation::dump(int indent) const | |
584 | { | ||
585 | 64 | std::string pad(indent*8, ' '); | |
586 | |||
587 |
4/5✓ Branch 0 taken 30 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
|
64 | switch (type) { |
588 | 30 | case ScopeOperation::VAR_DECL: | |
589 | { | ||
590 | 60 | std::string var = pad + std::string("var ") + variable_name; | |
591 | 30 | fprintf(stderr, "%s\n", var.c_str()); | |
592 | 30 | } | |
593 | 30 | break; | |
594 | 8 | case ScopeOperation::LABEL_DEFINITION: | |
595 | { | ||
596 | 16 | std::string var = pad + std::string("label ") + label_name; | |
597 | 8 | fprintf(stderr, "%s\n", var.c_str()); | |
598 | 8 | } | |
599 | 8 | break; | |
600 | 10 | case ScopeOperation::GOTO_DEFINITION: | |
601 | { | ||
602 | 20 | std::string var = pad + std::string("goto ") + goto_label; | |
603 | 10 | fprintf(stderr, "%s\n", var.c_str()); | |
604 | 10 | } | |
605 | 10 | break; | |
606 | 16 | case ScopeOperation::CHILD_SCOPE: | |
607 | { | ||
608 | 16 | std::string open = pad + "{"; | |
609 | 16 | fprintf(stderr, "%s\n", open.c_str()); | |
610 | 16 | child->dump(indent+1); | |
611 | 16 | std::string close = pad + "}"; | |
612 | 16 | fprintf(stderr, "%s\n", close.c_str()); | |
613 | 16 | } | |
614 | 16 | break; | |
615 | } | ||
616 | 64 | } | |
617 | |||
618 | void | ||
619 | 22 | Scope::dump(int indent) const | |
620 | { | ||
621 | 22 | std::string pad(indent*8, ' '); | |
622 |
2/2✓ Branch 5 taken 64 times.
✓ Branch 6 taken 22 times.
|
86 | for (const auto & op : operations) { |
623 | 64 | op->dump(indent+1); | |
624 | } | ||
625 | 22 | } | |
626 | |||
627 | /////////////////////////////////////////// | ||
628 | 858 | LocalVariable::LocalVariable( | |
629 | const Gyoji::mir::Type *_type, | ||
630 | const Gyoji::context::SourceReference & _source_ref | ||
631 | 858 | ) | |
632 | 858 | : type(_type) | |
633 | 858 | , source_ref(_source_ref) | |
634 | 858 | {} | |
635 | |||
636 | 858 | LocalVariable::~LocalVariable() | |
637 | 858 | {} | |
638 | |||
639 | const Gyoji::mir::Type * | ||
640 | 2352 | LocalVariable::get_type() const | |
641 | 2352 | { return type; } | |
642 | |||
643 | const Gyoji::context::SourceReference & | ||
644 | 2 | LocalVariable::get_source_ref() const | |
645 | 2 | { return source_ref; } | |
646 | |||
647 | ///////////////////////////////////// | ||
648 | // FunctionLabel | ||
649 | ///////////////////////////////////// | ||
650 | 10 | FunctionLabel::FunctionLabel( | |
651 | size_t _block_id | ||
652 | 10 | ) | |
653 | 10 | : resolved(false) | |
654 | 10 | , block_id(_block_id) | |
655 | 10 | , src_ref(nullptr) | |
656 | 10 | {} | |
657 | 10 | FunctionLabel::~FunctionLabel() | |
658 | 10 | {} | |
659 | |||
660 | const Gyoji::context::SourceReference & | ||
661 | 4 | FunctionLabel::get_source_ref() const | |
662 | 4 | { return *src_ref; } | |
663 | |||
664 | size_t | ||
665 | 2 | FunctionLabel::get_block() const | |
666 | 2 | { return block_id; } | |
667 | |||
668 | bool | ||
669 | 12 | FunctionLabel::is_resolved() const | |
670 | 12 | { return resolved; } | |
671 | |||
672 | void | ||
673 | 10 | FunctionLabel::resolve(const Gyoji::context::SourceReference & _src_ref) | |
674 | { | ||
675 | 10 | resolved = true; | |
676 | 10 | src_ref = &_src_ref; | |
677 | 10 | } | |
678 | |||
679 | //////////////////////////////////////////////// | ||
680 | // FunctionPoint | ||
681 | //////////////////////////////////////////////// | ||
682 | 12 | FunctionPoint::FunctionPoint(size_t _basic_block_id, size_t _location) | |
683 | 12 | : basic_block_id(_basic_block_id) | |
684 | 12 | , location(_location) | |
685 | 12 | {} | |
686 | 12 | FunctionPoint::~FunctionPoint() | |
687 | 12 | {} | |
688 | |||
689 | size_t | ||
690 | 2 | FunctionPoint::get_basic_block_id() const | |
691 | 2 | { return basic_block_id; } | |
692 | |||
693 | size_t | ||
694 | 2 | FunctionPoint::get_location() const | |
695 | 2 | { return location; } | |
696 |