|
1 | 1 | #! nqp
|
2 | 2 |
|
3 |
| -my @vms := nqp::list('parrot', 'jvm', 'moar'); |
4 |
| -my %documented_ops := nqp::hash(); |
5 |
| -for @vms -> $vm { |
6 |
| - %documented_ops{$vm} := nqp::hash(); |
7 |
| -} |
| 3 | +my @*vms := nqp::list('parrot', 'jvm', 'moar'); |
8 | 4 |
|
9 |
| -my @doc_lines := nqp::split("\n", nqp::readallfh(nqp::open("docs/ops.markdown","r"))); |
10 |
| -my @opcode_vms := nqp::list(); |
11 |
| -for @doc_lines -> $line { |
12 |
| - my $match := $line ~~ /^ '##' \s* <[a..zA..Z0..9_]>+ \s* ('`' .* '`')? /; |
13 |
| - if (?$match) { |
14 |
| - if (!?$match[0]) { |
15 |
| - @opcode_vms := nqp::clone(@vms); |
16 |
| - } else { |
17 |
| - @opcode_vms := nqp::list(); |
18 |
| - if $match[0] ~~ /jvm/ { |
19 |
| - nqp::push(@opcode_vms,"jvm"); |
20 |
| - } |
21 |
| - if $match[0] ~~ /parrot/ { |
22 |
| - nqp::push(@opcode_vms,"parrot"); |
23 |
| - } |
24 |
| - if $match[0] ~~ /moar/ { |
25 |
| - nqp::push(@opcode_vms,"moar"); |
26 |
| - } |
27 |
| - } |
28 |
| - } |
29 |
| - next unless $line ~~ / ^ '* ' .* '(' /; |
30 |
| - $line := nqp::substr2($line, 3); |
31 |
| - $line := nqp::split("(", $line)[0]; |
32 |
| - for @opcode_vms -> $vm { |
33 |
| - %documented_ops{$vm}{$line} := 1 ; |
34 |
| - } |
| 5 | +my %documented_ops := find_documented_opcodes(); |
35 | 6 |
|
36 |
| -} |
| 7 | +my %ops := hash_of_vms(); |
37 | 8 |
|
38 |
| -my %jvm_ops := nqp::hash(); |
39 |
| -my @jvm_lines := nqp::split("\n", nqp::readallfh(nqp::open("src/vm/jvm/QAST/Compiler.nqp","r"))); |
40 |
| -for @jvm_lines -> $line { |
41 |
| - next unless $line ~~ / 'map_classlib_core_op' | 'add_core_op' | 'map_jvm_core_op' /; |
42 |
| - $line := nqp::split("'", $line)[1]; |
43 |
| - next unless nqp::chars($line); |
44 |
| - %jvm_ops{$line} := 1; |
45 |
| -} |
46 |
| - |
47 |
| -# These are harder to tease out of the definitions in java, so add them manually |
48 |
| -for <if unless while until repeat_while repeat_until> -> $op_name { |
49 |
| - %jvm_ops{$op_name} := 1; |
50 |
| -} |
| 9 | +%ops<jvm> := find_opcodes( |
| 10 | + :file("src/vm/jvm/QAST/Compiler.nqp"), |
| 11 | + :keywords(<map_classlib_core_op add_core_op map_jvm_core_op>) |
| 12 | +); |
51 | 13 |
|
52 |
| -# All the jvm ops must be documented |
| 14 | +%ops<parrot> := find_opcodes( |
| 15 | + :file("src/vm/parrot/QAST/Operations.nqp"), |
| 16 | + :keywords(<add_core_op add_core_pirop_mapping>) |
| 17 | +); |
53 | 18 |
|
54 |
| -for %jvm_ops -> $jvm_op { |
55 |
| - ok(%documented_ops<jvm>{$jvm_op}, "JVM op '$jvm_op' is documented"); |
56 |
| -} |
57 |
| - |
58 |
| -for %documented_ops<jvm> -> $doc_op { |
59 |
| - ok(%jvm_ops{$doc_op}, "documented op '$doc_op' exists in the JVM"); |
60 |
| -} |
| 19 | +%ops<moar> := find_opcodes( |
| 20 | + :file("src/vm/moar/QAST/QASTOperationsMAST.nqp"), |
| 21 | + :keywords(<add_core_op add_core_moarop_mapping>) |
| 22 | +); |
61 | 23 |
|
62 |
| -my %pvm_ops := nqp::hash(); |
63 |
| -my @pvm_lines := nqp::split("\n", nqp::readallfh(nqp::open("src/vm/parrot/QAST/Operations.nqp","r"))); |
64 |
| -for @pvm_lines -> $line { |
65 |
| - next unless $line ~~ / 'add_core_op' | 'add_core_pirop_mapping' /; |
66 |
| - $line := nqp::split("'", $line)[1]; |
67 |
| - next unless nqp::chars($line); |
68 |
| - %pvm_ops{$line} := 1; |
69 |
| -} |
70 |
| - |
71 |
| -# These are harder to tease out of the definitions in java, so add them manually |
| 24 | +# Most backends programmatically add these ops - to keep our cheating simple, |
| 25 | +# add them to each of the backends manually |
72 | 26 | for <if unless while until repeat_while repeat_until> -> $op_name {
|
73 |
| - %pvm_ops{$op_name} := 1; |
| 27 | + for @*vms -> $vm { |
| 28 | + %ops{$vm}{$op_name} := 1; |
| 29 | + } |
74 | 30 | }
|
75 | 31 |
|
76 |
| -# All the pvm ops must be documented |
77 |
| - |
78 |
| -for %pvm_ops -> $pvm_op { |
79 |
| - ok(%documented_ops<parrot>{$pvm_op}, "PVM op '$pvm_op' is documented"); |
| 32 | +# Are ops that are implemented documented? Fail once per opcode |
| 33 | +my %combined_ops := nqp::hash(); |
| 34 | +for @*vms -> $vm { |
| 35 | + for %ops{$vm} -> $op { |
| 36 | + if !%combined_ops{$op} { |
| 37 | + %combined_ops{$op} := nqp::list($vm); |
| 38 | + } else { |
| 39 | + nqp::push(%combined_ops{$op}, $vm); |
| 40 | + } |
| 41 | + } |
80 | 42 | }
|
81 | 43 |
|
82 |
| -for %documented_ops<parrot> -> $doc_op { |
83 |
| - ok(%pvm_ops{$doc_op}, "documented op '$doc_op' exists in the PVM"); |
| 44 | +for %combined_ops -> $opcode { |
| 45 | + my $vms := nqp::join(";", %combined_ops{$opcode}); |
| 46 | + ok(%documented_ops<any>{$opcode}, "Opcode '$opcode' ($vms) is documented"); |
84 | 47 | }
|
85 | 48 |
|
86 |
| -my %mvm_ops := nqp::hash(); |
87 |
| -my @mvm_lines := nqp::split("\n", nqp::readallfh(nqp::open("src/vm/moar/QAST/QASTOperationsMAST.nqp","r"))); |
88 |
| -for @mvm_lines -> $line { |
89 |
| - next unless $line ~~ / 'add_core_op' | 'add_core_moarop_mapping' /; |
90 |
| - $line := nqp::split("'", $line)[1]; |
91 |
| - next unless nqp::chars($line); |
92 |
| - %mvm_ops{$line} := 1; |
| 49 | +# Do documented opcodes actually exist? Fail once per vm if not. |
| 50 | +for @*vms -> $vm { |
| 51 | + for %documented_ops{$vm} -> $doc_op { |
| 52 | + ok(%ops{$vm}{$doc_op}, "documented op '$doc_op' exists in $vm"); |
| 53 | + } |
93 | 54 | }
|
94 | 55 |
|
95 |
| -# These are harder to tease out of the definitions in moar, so add them manually |
96 |
| -for <if unless while until repeat_while repeat_until> -> $op_name { |
97 |
| - %mvm_ops{$op_name} := 1; |
| 56 | +sub find_opcodes(:$file, :@keywords) { |
| 57 | + my %ops := nqp::hash(); |
| 58 | + my @lines := nqp::split("\n", nqp::readallfh(nqp::open($file,"r"))); |
| 59 | + for @lines -> $line { |
| 60 | + next unless $line ~~ / @keywords /; |
| 61 | + $line := nqp::split("'", $line)[1]; |
| 62 | + next unless nqp::chars($line); |
| 63 | + %ops{$line} := 1; |
| 64 | + } |
| 65 | + return %ops; |
98 | 66 | }
|
99 | 67 |
|
100 |
| - |
101 |
| -# All the mvm ops must be documented |
102 |
| - |
103 |
| -for %mvm_ops -> $mvm_op { |
104 |
| - ok(%documented_ops<moar>{$mvm_op}, "MOAR op '$mvm_op' is documented"); |
| 68 | +sub hash_of_vms() { |
| 69 | + my %hash := nqp::hash(); |
| 70 | + for @*vms -> $vm { |
| 71 | + %hash{$vm} := nqp::hash(); |
| 72 | + } |
| 73 | + return %hash; |
105 | 74 | }
|
106 | 75 |
|
107 |
| -for %documented_ops<moar> -> $doc_op { |
108 |
| - ok(%mvm_ops{$doc_op}, "documented op '$doc_op' exists in MOAR"); |
| 76 | +sub find_documented_opcodes() { |
| 77 | + my %documented_ops := hash_of_vms(); |
| 78 | + %documented_ops<any> := nqp::hash(); |
| 79 | + |
| 80 | + my @doc_lines := nqp::split("\n", nqp::readallfh(nqp::open("docs/ops.markdown","r"))); |
| 81 | + my @opcode_vms := nqp::list(); |
| 82 | + for @doc_lines -> $line { |
| 83 | + my $match := $line ~~ /^ '##' \s* <[a..zA..Z0..9_]>+ \s* ('`' .* '`')? /; |
| 84 | + if (?$match) { |
| 85 | + if (!?$match[0]) { |
| 86 | + @opcode_vms := nqp::clone(@*vms); |
| 87 | + } else { |
| 88 | + @opcode_vms := nqp::list(); |
| 89 | + if $match[0] ~~ /jvm/ { |
| 90 | + nqp::push(@opcode_vms,"jvm"); |
| 91 | + } |
| 92 | + if $match[0] ~~ /parrot/ { |
| 93 | + nqp::push(@opcode_vms,"parrot"); |
| 94 | + } |
| 95 | + if $match[0] ~~ /moar/ { |
| 96 | + nqp::push(@opcode_vms,"moar"); |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + next unless $line ~~ / ^ '* ' .* '(' /; |
| 101 | + $line := nqp::substr2($line, 3); |
| 102 | + $line := nqp::split("(", $line)[0]; |
| 103 | + for @opcode_vms -> $vm { |
| 104 | + %documented_ops{$vm}{$line} := 1 ; |
| 105 | + } |
| 106 | + %documented_ops<any>{$line} := 1 ; |
| 107 | + |
| 108 | + } |
| 109 | + return %documented_ops; |
109 | 110 | }
|
0 commit comments