1 //: Distinguish between labels marking the start of a function, and labels
 2 //: inside functions.
 3 //:
 4 //: - Labels within functions start with a '$', and are only permitted in
 5 //:   'jump' instructions.
 6 //:
 7 //: - Labels marking the start of functions lack the '$' sigil, and are only
 8 //:   permitted in 'call' instructions.
 9 
10 :(before "Rewrite Labels(segment code)")
11 check_label_types(code);
12 if (trace_contains_errors()) return;
13 :(code)
14 void check_label_types(const segment& code) {
15   trace(99, "transform") << "-- check label types" << end();
16   for (int i = 0;  i < SIZE(code.lines);  ++i)
17     check_label_types(code.lines.at(i));
18 }
19 
20 void check_label_types(const line& inst) {
21   int idx = first_operand(inst);
22   if (idx >= SIZE(inst.words)) return;
23   const word& target = inst.words.at(idx);
24   if (is_number(target.data)) return;  // handled elsewhere
25   if (is_jump(inst) && target.data.at(0) != '$')
26     raise << "'" << inst.original << "': jumps should always be to internal labels starting with '$'\n" << end();
27   if (is_call(inst) && target.data.at(0) == '$')
28     raise << "'" << inst.original << "': calls should always be to function labels (not starting with '$')\n" << end();
29 }
30 
31 :(scenario catch_jump_to_function)
32 % Hide_errors = true;
33 == 0x1
34 main:
35 7e/jump-if foo/disp8
36 foo:
37 +error: '7e/jump-if foo/disp8': jumps should always be to internal labels starting with '$'
38 
39 :(scenario catch_call_to_internal_label)
40 % Hide_errors = true;
41 == 0x1
42 main:
43 e8/call $foo/disp32
44  $foo:  # indent to avoid looking like a trace_count command for this scenario
45 +error: 'e8/call $foo/disp32': calls should always be to function labels (not starting with '$')