line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Generate; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
1616
|
use strict; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
122
|
|
4
|
3
|
|
|
3
|
|
15
|
use Carp qw(:DEFAULT cluck); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
467
|
|
5
|
3
|
|
|
3
|
|
15
|
use Exporter; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
88
|
|
6
|
3
|
|
|
3
|
|
16
|
use Data::Dumper; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
128
|
|
7
|
3
|
|
|
3
|
|
15
|
use String::Escape qw(quote printable); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
128
|
|
8
|
3
|
|
|
3
|
|
17
|
use Anarres::Mud::Driver::Compiler::Type; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
106
|
|
9
|
3
|
|
|
3
|
|
15
|
use Anarres::Mud::Driver::Compiler::Node qw(@NODETYPES); |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
244
|
|
10
|
3
|
|
|
3
|
|
16
|
use Anarres::Mud::Driver::Compiler::Check qw(:flags); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
2151
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
push(@Anarres::Mud::Driver::Compiler::Node::ISA, __PACKAGE__); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my %ASSERTTABLE = ( |
15
|
|
|
|
|
|
|
IntAssert => '+do { my ($__a) = ((A)); ' . |
16
|
|
|
|
|
|
|
'die "Not integer at XXX" if ref($__a); ' . |
17
|
|
|
|
|
|
|
'$__a; }', |
18
|
|
|
|
|
|
|
StrAssert => '+do { my ($__a) = ((A)); ' . |
19
|
|
|
|
|
|
|
'die "Not string at XXX" if ref($__a); ' . |
20
|
|
|
|
|
|
|
'$__a; }', |
21
|
|
|
|
|
|
|
ArrAssert => '+do { my ($__a) = ((A)); ' . |
22
|
|
|
|
|
|
|
'die "Not array at XXX" if ref($__a) ne "ARRAY"; '. |
23
|
|
|
|
|
|
|
'$__a; }', |
24
|
|
|
|
|
|
|
MapAssert => '+do { my ($__a) = ((A)); ' . |
25
|
|
|
|
|
|
|
'die "Not mapping at XXX" if ref($__a) ne "HASH"; '. |
26
|
|
|
|
|
|
|
'$__a; }', |
27
|
|
|
|
|
|
|
ClsAssert => '+do { my ($__a) = ((A)); ' . |
28
|
|
|
|
|
|
|
'die "Not closure at XXX" if ref($__a) ne "CODE"; '. |
29
|
|
|
|
|
|
|
'$__a; }', |
30
|
|
|
|
|
|
|
ObjAssert => '+do { my ($__a) = ((A)); ' . # XXX Fixme |
31
|
|
|
|
|
|
|
'die "Not object at XXX" if ref($__a) !~ /::/; ' . |
32
|
|
|
|
|
|
|
'$__a; }', |
33
|
|
|
|
|
|
|
); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# If we trap the relevant error messages from Perl and accept that |
36
|
|
|
|
|
|
|
# we are not going to get an error message on (array + 1) - we |
37
|
|
|
|
|
|
|
# just get a pointer increment, then we can just do this. |
38
|
|
|
|
|
|
|
my %ASSERTTABLE_NOOP = ( |
39
|
|
|
|
|
|
|
IntAssert => 'A', |
40
|
|
|
|
|
|
|
StrAssert => 'A', |
41
|
|
|
|
|
|
|
ArrAssert => 'A', |
42
|
|
|
|
|
|
|
MapAssert => 'A', |
43
|
|
|
|
|
|
|
ClsAssert => 'A', |
44
|
|
|
|
|
|
|
ObjAssert => 'A', |
45
|
|
|
|
|
|
|
); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my %OPCODETABLE = ( |
48
|
|
|
|
|
|
|
# Can we tell the difference between strings and ints here? |
49
|
|
|
|
|
|
|
# DConway says this tells us if it's an int: |
50
|
|
|
|
|
|
|
# ($s_ref eq "" && defined $s_val && (~$s_val&$s_val) eq 0) |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
StmtNull => '', |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Nil => 'undef', |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
%ASSERTTABLE_NOOP, |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
Postinc => '(A)++', |
59
|
|
|
|
|
|
|
Postdec => '(A)--', |
60
|
|
|
|
|
|
|
Preinc => '++(A)', |
61
|
|
|
|
|
|
|
Predec => '--(A)', |
62
|
|
|
|
|
|
|
Unot => '!(A)', |
63
|
|
|
|
|
|
|
Tilde => '~(A)', |
64
|
|
|
|
|
|
|
Plus => '+(A)', |
65
|
|
|
|
|
|
|
Minus => '-(A)', |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
IntAdd => '(A) + (B)', |
68
|
|
|
|
|
|
|
IntSub => '(A) - (B)', |
69
|
|
|
|
|
|
|
IntMul => '(A) * (B)', |
70
|
|
|
|
|
|
|
IntDiv => '(A) / (B)', |
71
|
|
|
|
|
|
|
IntMod => '(A) % (B)', |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
IntLsh => '(A) << (B)', |
74
|
|
|
|
|
|
|
IntRsh => '(A) >> (B)', |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
IntOr => '(A) | (B)', |
77
|
|
|
|
|
|
|
IntAnd => '(A) & (B)', |
78
|
|
|
|
|
|
|
IntXor => '(A) ^ (B)', |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
IntAddEq => '(A) += (B)', |
81
|
|
|
|
|
|
|
IntSubEq => '(A) -= (B)', |
82
|
|
|
|
|
|
|
IntMulEq => '(A) *= (B)', |
83
|
|
|
|
|
|
|
IntDivEq => '(A) /= (B)', |
84
|
|
|
|
|
|
|
IntModEq => '(A) %= (B)', |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
IntLshEq => '(A) <<= (B)', |
87
|
|
|
|
|
|
|
IntRshEq => '(A) >>= (B)', |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
IntOrEq => '(A) |= (B)', |
90
|
|
|
|
|
|
|
IntAndEq => '(A) &= (B)', |
91
|
|
|
|
|
|
|
IntXorEq => '(A) ^= (B)', |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
StrAdd => '(A) . (B)', |
94
|
|
|
|
|
|
|
StrMul => '(A) x (B)', |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
StrAddEq => '(A) .= (B)', |
97
|
|
|
|
|
|
|
StrMulEq => '(A) x= (B)', |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
IntEq => '(A) == (B)', |
100
|
|
|
|
|
|
|
IntNe => '(A) != (B)', |
101
|
|
|
|
|
|
|
IntLt => '(A) < (B)', |
102
|
|
|
|
|
|
|
IntGt => '(A) > (B)', |
103
|
|
|
|
|
|
|
IntLe => '(A) <= (B)', |
104
|
|
|
|
|
|
|
IntGe => '(A) >= (B)', |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
StrEq => '(A) eq (B)', |
107
|
|
|
|
|
|
|
StrNe => '(A) ne (B)', |
108
|
|
|
|
|
|
|
StrLt => '(A) lt (B)', |
109
|
|
|
|
|
|
|
StrGt => '(A) gt (B)', |
110
|
|
|
|
|
|
|
StrLe => '(A) le (B)', |
111
|
|
|
|
|
|
|
StrGe => '(A) ge (B)', |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
ArrEq => '(A) == (B)', |
114
|
|
|
|
|
|
|
ArrNe => '(A) != (B)', |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
MapEq => '(A) == (B)', |
117
|
|
|
|
|
|
|
MapNe => '(A) != (B)', |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
ObjEq => '(A) == (B)', |
120
|
|
|
|
|
|
|
ObjNe => '(A) != (B)', |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
LogOr => '(A) || (B)', |
123
|
|
|
|
|
|
|
LogAnd => '(A) && (B)', |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
LogOrEq => '(A) ||= (B)', |
126
|
|
|
|
|
|
|
LogAndEq => '(A) &&= (B)', |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
ExpComma => '(A), (B)', # XXX Wrong? |
129
|
|
|
|
|
|
|
ExpCond => '(A) ? (B) : (C)', |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
New => '{ }', # XXX Initialise to class? |
132
|
|
|
|
|
|
|
Member => '(A)->{_B_}', |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
ArrIndex => '(A)->[B]', |
135
|
|
|
|
|
|
|
MapIndex => '(A)->{B}', |
136
|
|
|
|
|
|
|
StrIndex => 'substr((A), (B), 1)', # XXX Wrong! Use Core XSUB |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
ArrRangeLL => '[ (A)->[(B)..(C)] ]', |
139
|
|
|
|
|
|
|
ArrRangeRL => '[ splice(@{[ @{A}, undef ]}, -(B), (C)) ]', |
140
|
|
|
|
|
|
|
ArrRangeLR => '[ splice(@{[ @{A}, undef ]}, (B), -(C)) ]', |
141
|
|
|
|
|
|
|
ArrRangeRR => '[ splice(@{[ @{A}, undef ]}, -(B), -(C)) ]', |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# eval the args once outside scope of $__* vars |
144
|
|
|
|
|
|
|
# XXX Use the XSUB in Core |
145
|
|
|
|
|
|
|
StrRangeCstLL => 'substr(A, B, (C) - (B))', |
146
|
|
|
|
|
|
|
StrRangeCstLR => 'substr(A, B, (B) - (C))', |
147
|
|
|
|
|
|
|
StrRangeCstRL => 'substr(A, -(B), (C) - (B))', |
148
|
|
|
|
|
|
|
StrRangeCstRR => 'substr(A, -(B), (B) - (C))', |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
StrRangeVarLL => 'do { my ($__a, $__b, $__c) = ((A), (B), (C)); '. |
151
|
|
|
|
|
|
|
'substr($__a, $__b, ($__c - $__b)) }', |
152
|
|
|
|
|
|
|
StrRangeVarLR => 'do { my ($__a, $__b, $__c) = ((A), (B), (C)); '. |
153
|
|
|
|
|
|
|
'substr($__a, $__b, ($__b - $__c)) }', |
154
|
|
|
|
|
|
|
StrRangeVarRL => 'do { my ($__a, $__b, $__c) = ((A), (B), (C)); '. |
155
|
|
|
|
|
|
|
'substr($__a, - $__b, ($__c - $__b)) }', |
156
|
|
|
|
|
|
|
StrRangeVarRR => 'do { my ($__a, $__b, $__c) = ((A), (B), (C)); '. |
157
|
|
|
|
|
|
|
'substr($__a, - $__b, ($__b - $__c)) }', |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
ArrAdd => '[ @{A}, @{B} ]', |
160
|
|
|
|
|
|
|
ArrSub => 'do { my %__a = map { $_ => 1 } @{B}; ' . |
161
|
|
|
|
|
|
|
'[ grep { ! $__a{$_} } @{ A } ] }', |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
MapAdd => '{ %{A}, %{B} }', |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Assign => 'A = B', |
166
|
|
|
|
|
|
|
Catch => 'do { eval { A; }, $@; }', |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
StmtReturn => 'return A;', |
169
|
|
|
|
|
|
|
StmtContinue => 'next;', |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# We can add extra braces around statement|block tokens |
172
|
|
|
|
|
|
|
# This lot are all strictly cheating anyway! If this works ... |
173
|
|
|
|
|
|
|
StmtExp => 'A;', |
174
|
|
|
|
|
|
|
# Should we promote_to_block() B in these statements? |
175
|
|
|
|
|
|
|
# Bear in mind what happens if we do an empty block...? |
176
|
|
|
|
|
|
|
StmtDo => 'do { B } while (A);', |
177
|
|
|
|
|
|
|
StmtWhile => 'while (A) { B }', |
178
|
|
|
|
|
|
|
StmtFor => 'for (A; B; C) D', |
179
|
|
|
|
|
|
|
StmtForeachArr => 'foreach my A (@{ C }) D', |
180
|
|
|
|
|
|
|
StmtForeachMap => 'foreach my A (keys %{ C }) D', # XXX FIXME: B |
181
|
|
|
|
|
|
|
StmtTry => 'eval A; if ($@) { my B = $@; C; }', |
182
|
|
|
|
|
|
|
# This uses blocks |
183
|
|
|
|
|
|
|
StmtCatch => 'eval A ;', # A MudOS hack |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# This NOGEN business is really developer support and can be removed |
186
|
|
|
|
|
|
|
map { $_ => 'NOGEN' } qw( |
187
|
|
|
|
|
|
|
Variable |
188
|
|
|
|
|
|
|
Index Range |
189
|
|
|
|
|
|
|
Lsh Rsh |
190
|
|
|
|
|
|
|
Add Sub Mul Div Mod |
191
|
|
|
|
|
|
|
Eq Ne Lt Gt Le Ge Or |
192
|
|
|
|
|
|
|
And Xor |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
AddEq SubEq DivEq MulEq ModEq |
195
|
|
|
|
|
|
|
AndEq OrEq XorEq |
196
|
|
|
|
|
|
|
LshEq RshEq |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
StmtForeach |
199
|
|
|
|
|
|
|
), |
200
|
|
|
|
|
|
|
); |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# XXX For the purposes of things like Member, I need to be able to |
203
|
|
|
|
|
|
|
# insert both expanded and nonexpanded versions of tokens. |
204
|
|
|
|
|
|
|
# So I need to be able to insert "A", _A_ and @A@ tokens, for example. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub gensub { |
207
|
4
|
|
|
4
|
0
|
10
|
my ($self, $name, $code) = @_; |
208
|
|
|
|
|
|
|
|
209
|
4
|
50
|
|
|
|
19
|
confess "No code template for opcode '$name'" unless defined $code; |
210
|
|
|
|
|
|
|
|
211
|
4
|
|
|
|
|
18
|
foreach ('A'..'F') { # Say ... |
212
|
24
|
|
|
|
|
36
|
my $arg = ord($_) - ord('A'); |
213
|
|
|
|
|
|
|
# XXX This 'quote' routine doesn't necessarily quote |
214
|
|
|
|
|
|
|
# appropriately. |
215
|
24
|
|
|
|
|
186
|
$code =~ s/"$_"/' . quote(\$self->value($arg)) . '/g; |
216
|
24
|
|
|
|
|
142
|
$code =~ s/\b_$_\_\b/' . \$self->value($arg) . '/g; |
217
|
24
|
|
|
|
|
221
|
$code =~ s/\b$_\b/' . \$self->value($arg)->generate(\@_) . '/g; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
4
|
|
|
|
|
16
|
$code = qq{ sub (\$) { my \$self = shift; return '$code'; } }; |
221
|
|
|
|
|
|
|
# Remove empty concatenations - careful with the templates |
222
|
4
|
|
|
|
|
12
|
$code =~ s/'' \. //g; |
223
|
4
|
|
|
|
|
9
|
$code =~ s/ \. ''//g; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# print "$name becomes $code\n"; |
226
|
4
|
|
|
0
|
|
1807
|
my $subref = eval $code; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
7
|
|
227
|
4
|
50
|
|
|
|
17
|
die $@ if $@; |
228
|
4
|
|
|
|
|
20
|
return $subref; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# "Refactor", I hear you say? |
232
|
|
|
|
|
|
|
# This needs a magic token for line number... |
233
|
|
|
|
|
|
|
sub generate ($) { |
234
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
235
|
|
|
|
|
|
|
|
236
|
1
|
|
|
|
|
4
|
my $name = $self->opcode; |
237
|
|
|
|
|
|
|
# print "Finding code for $name\n"; |
238
|
1
|
|
|
|
|
4
|
my $code = $OPCODETABLE{$name}; |
239
|
1
|
50
|
|
|
|
5
|
return "GEN($name)" unless defined $code; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# This is mostly for debugging. It can be safely removed. |
242
|
1
|
50
|
|
|
|
4
|
if ($code eq 'NOGEN') { |
243
|
0
|
|
|
|
|
0
|
print "XXX Attempt to generate NOGEN opcode $name\n"; |
244
|
0
|
|
|
|
|
0
|
return "GEN($name)"; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
1
|
|
|
|
|
9
|
my $subref = $self->gensub($name, $code); |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
{ |
250
|
|
|
|
|
|
|
# Backpatch our original package. |
251
|
3
|
|
|
3
|
|
18
|
no strict qw(refs); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
246
|
|
|
1
|
|
|
|
|
3
|
|
252
|
1
|
|
|
|
|
3
|
*{ ref($self) . '::generate' } = $subref; |
|
1
|
|
|
|
|
8
|
|
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
1
|
|
|
|
|
31
|
return $subref->($self, @_); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
{ |
259
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::String; |
260
|
3
|
|
|
3
|
|
17
|
use String::Escape qw(quote printable); |
|
3
|
|
|
|
|
18
|
|
|
3
|
|
|
|
|
2672
|
|
261
|
|
|
|
|
|
|
sub generate { |
262
|
0
|
|
|
0
|
|
|
my $str = printable($_[0]->value(0)); |
263
|
0
|
|
|
|
|
|
$str =~ s/([\$\@\%])/\\$1/g; |
264
|
0
|
|
|
|
|
|
return quote $str; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
{ |
269
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Integer; |
270
|
0
|
|
|
0
|
|
|
sub generate { $_[0]->value(0) } |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
{ |
274
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Array; |
275
|
|
|
|
|
|
|
sub generate { |
276
|
0
|
|
|
0
|
|
|
my ($self, $indent, @rest) = @_; |
277
|
0
|
|
|
|
|
|
$indent++; |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
my @vals = map { $_->generate($indent, @rest) } $self->values; |
|
0
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
|
281
|
0
|
0
|
|
|
|
|
return "[ ]" unless @vals; |
282
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
$indent--; |
284
|
0
|
|
|
|
|
|
my $isep = "\n" . ("\t" x $indent); |
285
|
0
|
|
|
|
|
|
my $sep = "," . $isep . "\t"; |
286
|
0
|
|
|
|
|
|
return "[" . $isep . "\t" . join($sep, @vals) . $isep . "]"; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
{ |
291
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Mapping; |
292
|
|
|
|
|
|
|
sub generate { |
293
|
0
|
|
|
0
|
|
|
my ($self, $indent, @rest) = @_; |
294
|
0
|
|
|
|
|
|
$indent++; |
295
|
|
|
|
|
|
|
|
296
|
0
|
|
|
|
|
|
my @vals = map { $_->generate($indent, @rest) } $self->values; |
|
0
|
|
|
|
|
|
|
297
|
0
|
0
|
|
|
|
|
return "{ }" unless @vals; |
298
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
my @out = (); |
300
|
0
|
|
|
|
|
|
while (my @tmp = splice(@vals, 0, 2)) { |
301
|
0
|
|
|
|
|
|
push(@out, $tmp[0] . "\t=> " . $tmp[1] . ","); |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
0
|
|
|
|
|
|
$indent--; |
305
|
0
|
|
|
|
|
|
my $isep = "\n" . ("\t" x $indent); |
306
|
0
|
|
|
|
|
|
my $sep = $isep . "\t"; |
307
|
0
|
|
|
|
|
|
return "{$isep\t" . join($sep, @out) . "$isep}"; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
{ |
312
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Closure; |
313
|
|
|
|
|
|
|
# XXX This needs to store the owner object so we can emulate the |
314
|
|
|
|
|
|
|
# LPC behaviour of function_owner. Something like [ $self, sub {} ] |
315
|
|
|
|
|
|
|
sub generate { |
316
|
0
|
|
|
0
|
|
|
my $self = shift; |
317
|
|
|
|
|
|
|
# return "sub { " . $self->value(0)->generate(@_) . " }"; |
318
|
0
|
|
|
|
|
|
return '$self->{Closures}->[' . $self->value(1) . ']'; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
{ |
323
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::VarLocal; |
324
|
|
|
|
|
|
|
sub generate { |
325
|
0
|
|
|
0
|
|
|
return '$_L_' . $_[0]->value(0); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
{ |
330
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::VarGlobal; |
331
|
|
|
|
|
|
|
sub generate { |
332
|
0
|
|
|
0
|
|
|
my $self = shift; |
333
|
0
|
|
|
|
|
|
my $name = $self->value(0); |
334
|
0
|
|
|
|
|
|
return '$self->{Variables}->{_G_' . $name . '}'; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
{ |
339
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::VarStatic; |
340
|
|
|
|
|
|
|
sub generate { |
341
|
0
|
|
|
0
|
|
|
return '$_S_' . $_[0]->value(0); |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
{ |
346
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Parameter; |
347
|
0
|
|
|
0
|
|
|
sub generate { '$_[' . $_[0]->value(0) . ']' } |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
{ |
351
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Funcall; |
352
|
|
|
|
|
|
|
sub generate { |
353
|
0
|
|
|
0
|
|
|
my $self = shift; |
354
|
0
|
|
|
|
|
|
my @args = $self->values; |
355
|
0
|
|
|
|
|
|
my $method = shift @args; |
356
|
0
|
|
|
|
|
|
@args = map { $_->generate(@_) } @args; |
|
0
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
|
return $method->generate_call(@args); |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
{ |
362
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::CallOther; |
363
|
|
|
|
|
|
|
sub generate { |
364
|
0
|
|
|
0
|
|
|
my $self = shift; |
365
|
0
|
|
|
|
|
|
my @values = $self->values; |
366
|
0
|
|
|
|
|
|
my $exp = shift @values; |
367
|
0
|
|
|
|
|
|
my $name = shift @values; |
368
|
0
|
|
|
|
|
|
@values = map { $_->generate(@_) } @values; |
|
0
|
|
|
|
|
|
|
369
|
0
|
|
|
|
|
|
return '(' . $exp->generate(@_) . ')->' . $name . '(' . |
370
|
|
|
|
|
|
|
join(", ", @values) . ')'; |
371
|
0
|
|
|
|
|
|
q[ |
372
|
|
|
|
|
|
|
do { |
373
|
|
|
|
|
|
|
my ($exp, @vals) = (....); |
374
|
|
|
|
|
|
|
ref($exp) && ! $exp->{Flags}->{Destructed} |
375
|
|
|
|
|
|
|
or die "Call into destructed or nonobject."; |
376
|
|
|
|
|
|
|
$exp->func(@vals); |
377
|
|
|
|
|
|
|
] if 0; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
{ |
382
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StrIndex; |
383
|
|
|
|
|
|
|
# XXX Use the core subchar efun |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
{ |
387
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StrRange; |
388
|
|
|
|
|
|
|
# XXX Use the core substr efun |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
{ |
391
|
|
|
|
|
|
|
*generate_cst_ll = __PACKAGE__->gensub('StrRangeLL (constant)', |
392
|
|
|
|
|
|
|
$OPCODETABLE{'StrRangeCstLL'}); |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
# Don't do this! |
395
|
|
|
|
|
|
|
sub generate_cst ($) { |
396
|
3
|
|
|
3
|
|
35
|
no warnings qw(redefine); |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
303
|
|
397
|
0
|
0
|
|
0
|
|
|
return undef unless $]; # Defeat inlining |
398
|
0
|
|
|
|
|
|
my $self = shift; |
399
|
0
|
|
|
|
|
|
*generate_cst = $self->gensub('StrRange (constant LL)', |
400
|
|
|
|
|
|
|
$OPCODETABLE{'StrRangeCstLL'}); |
401
|
0
|
|
|
|
|
|
return $self->generate_cst(@_); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
sub generate_var ($) { |
404
|
3
|
|
|
3
|
|
13
|
no warnings qw(redefine); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
586
|
|
405
|
0
|
0
|
|
0
|
|
|
return undef unless $]; # Defeat inlining |
406
|
0
|
|
|
|
|
|
my $self = shift; |
407
|
0
|
|
|
|
|
|
*generate_var = $self->gensub('StrRange (variable)', |
408
|
|
|
|
|
|
|
$OPCODETABLE{'StrRangeVarLL'}); |
409
|
0
|
|
|
|
|
|
return $self->generate_var(@_); |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
# XXX We need to check for lvalues around here. :-( |
412
|
|
|
|
|
|
|
sub generate { |
413
|
0
|
|
|
0
|
|
|
my $self = shift; |
414
|
0
|
|
|
|
|
|
my $val = $self->value(1); |
415
|
|
|
|
|
|
|
# Variables are unchanged across this operation. |
416
|
|
|
|
|
|
|
# What we really mean here is, "Is it pure?" |
417
|
|
|
|
|
|
|
# But that would not necessarily amount to an optimisation. |
418
|
|
|
|
|
|
|
# A better question might be, "Is it elementary?" |
419
|
|
|
|
|
|
|
# (VarLocal or VarGlobal) |
420
|
0
|
0
|
0
|
|
|
|
if (ref($val) =~ /::Var(Local|Global|Static)$/ || ($val->flags)&F_CONST) { |
421
|
0
|
|
|
|
|
|
return $self->generate_cst(@_); |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
else { |
424
|
0
|
|
|
|
|
|
return $self->generate_var(@_); |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
{ |
430
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::ArrRange; |
431
|
|
|
|
|
|
|
sub generate_ll ($) { |
432
|
3
|
|
|
3
|
|
17
|
no warnings qw(redefine); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
340
|
|
433
|
0
|
0
|
|
0
|
|
|
return undef unless $]; # Defeat inlining |
434
|
0
|
|
|
|
|
|
my $self = shift; |
435
|
0
|
|
|
|
|
|
*generate_var = $self->gensub('ArrRange (LL)', |
436
|
|
|
|
|
|
|
$OPCODETABLE{'ArrRangeLL'}); |
437
|
0
|
|
|
|
|
|
return $self->generate_var(@_); |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
sub generate { |
440
|
0
|
|
|
0
|
|
|
my $self = shift; |
441
|
0
|
|
|
|
|
|
return $self->generate_ll(@_); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
{ |
446
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Scanf; |
447
|
3
|
|
|
3
|
|
2516
|
use String::Scanf; |
|
3
|
|
|
|
|
5183
|
|
|
3
|
|
|
|
|
4667
|
|
448
|
|
|
|
|
|
|
*invoke = \&String::Scanf::sscanf; # For consistency. |
449
|
|
|
|
|
|
|
sub generate { |
450
|
0
|
|
|
0
|
|
|
my $self = shift; |
451
|
0
|
|
|
|
|
|
my ($exp, $fmt, @values) = $self->values; |
452
|
0
|
|
|
|
|
|
@values = map { $_->generate(@_) } @values; |
|
0
|
|
|
|
|
|
|
453
|
0
|
|
|
|
|
|
return __PACKAGE__ . '::invoke((' . $exp->generate(@_) . '), ('. |
454
|
|
|
|
|
|
|
$fmt->generate(@_) . '), (' . |
455
|
|
|
|
|
|
|
join('), (', @values) . '))'; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
{ |
460
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::ArrOr; |
461
|
|
|
|
|
|
|
# XXX Generate this inline like ArrSub. |
462
|
|
|
|
|
|
|
sub invoke { |
463
|
0
|
|
|
0
|
|
|
my @left = @{ $_[0] }; |
|
0
|
|
|
|
|
|
|
464
|
0
|
|
|
|
|
|
my %table = map { $_ => 1 } @left; |
|
0
|
|
|
|
|
|
|
465
|
0
|
|
|
|
|
|
foreach (@{ $_[1] }) { |
|
0
|
|
|
|
|
|
|
466
|
0
|
0
|
|
|
|
|
push(@left, $_) unless $table{$_}++; # Is the ++ right? |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
# () | (1, 1) = (1) or (1, 1) ? |
469
|
0
|
|
|
|
|
|
return \@left; |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
sub generate { |
472
|
0
|
|
|
0
|
|
|
my $self = shift; |
473
|
0
|
|
|
|
|
|
return __PACKAGE__ . '::invoke(('. |
474
|
|
|
|
|
|
|
$self->value(0)->generate(@_) . '), (' . |
475
|
|
|
|
|
|
|
$self->value(1)->generate(@_) . '))'; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
{ |
480
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::ArrAnd; |
481
|
|
|
|
|
|
|
# XXX Generate this inline like ArrSub. |
482
|
|
|
|
|
|
|
# sub infer { $_[1]->arrayp ? $_[0] : undef } |
483
|
|
|
|
|
|
|
sub invoke { |
484
|
0
|
|
|
0
|
|
|
my @out = (); |
485
|
0
|
|
|
|
|
|
my %table = map { $_ => 1 } @{ $_[1] }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
|
foreach (@{ $_[0] }) { |
|
0
|
|
|
|
|
|
|
487
|
0
|
0
|
|
|
|
|
push(@out, $_) if $table{$_}; |
488
|
|
|
|
|
|
|
} |
489
|
0
|
|
|
|
|
|
return \@out; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
sub generate { |
492
|
0
|
|
|
0
|
|
|
my $self = shift; |
493
|
0
|
|
|
|
|
|
return 'Anarres::Mud::Driver::Compiler::Node::ArrIsect::invoke('. |
494
|
|
|
|
|
|
|
$self->value(0)->generate(@_) . ', ' . |
495
|
|
|
|
|
|
|
$self->value(1)->generate(@_) . ')'; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
{ |
500
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::Block; |
501
|
|
|
|
|
|
|
sub generate { |
502
|
0
|
|
|
0
|
|
|
my ($self, $indent, @rest) = @_; |
503
|
0
|
|
|
|
|
|
$indent++; |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
|
my @args = map { $_->name } @{ $self->value(0) }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
506
|
0
|
|
|
|
|
|
my @vals = map { $_->generate($indent, @rest) } |
|
0
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
|
@{ $self->value(1) }; |
508
|
|
|
|
|
|
|
# We can't even return a comment in here in case we get |
509
|
|
|
|
|
|
|
# do { # comment } while (undef) in various places. |
510
|
|
|
|
|
|
|
# We have to have _something_ here in case we compile |
511
|
|
|
|
|
|
|
# if (x) { } and we promote_to_block the second arg. |
512
|
0
|
0
|
|
|
|
|
return '{ undef; }' unless @vals; |
513
|
|
|
|
|
|
|
|
514
|
0
|
|
|
|
|
|
$indent--; |
515
|
0
|
|
|
|
|
|
my $isep = "\n" . ("\t" x $indent); |
516
|
0
|
|
|
|
|
|
my $sep = $isep . "\t"; |
517
|
0
|
0
|
|
|
|
|
my $args = @args |
518
|
|
|
|
|
|
|
? 'my ($_L_' . join(', $_L_', @args) . ');' . $sep |
519
|
|
|
|
|
|
|
: ''; # '# no locals in block' |
520
|
0
|
|
|
|
|
|
return '{' . $sep . $args . join($sep, @vals) . $isep . "}"; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
{ |
525
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StmtSwitch; |
526
|
|
|
|
|
|
|
sub generate { |
527
|
0
|
|
|
0
|
|
|
my $self = shift; |
528
|
0
|
|
|
|
|
|
my $indent = shift; |
529
|
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
|
my $isep = "\n" . ("\t" x $indent); |
531
|
0
|
|
|
|
|
|
my $sep = $isep . "\t"; |
532
|
|
|
|
|
|
|
|
533
|
0
|
|
|
|
|
|
$indent++; |
534
|
|
|
|
|
|
|
|
535
|
0
|
|
|
|
|
|
my ($exp, $block) = $self->values; |
536
|
0
|
|
|
|
|
|
my $dump = $exp->dump; |
537
|
0
|
|
|
|
|
|
$dump =~ s/\s+/ /g; |
538
|
0
|
|
|
|
|
|
my $labels = $self->value(3); |
539
|
|
|
|
|
|
|
# default label or end of switch |
540
|
0
|
|
0
|
|
|
|
my $default = $self->value(4) || $self->value(2); |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
# Put this n program header? |
543
|
0
|
|
|
|
|
|
my @hashdata = |
544
|
0
|
|
|
|
|
|
map { $sep . "\t\t" . |
545
|
|
|
|
|
|
|
$labels->{$_}->generate($indent, @_) . |
546
|
|
|
|
|
|
|
"\t=> '" . $_ . "'," } |
547
|
0
|
|
|
|
|
|
keys %{ $labels }; |
548
|
0
|
|
|
|
|
|
my $hashdata = join('', @hashdata); |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
return '{' . |
551
|
|
|
|
|
|
|
$sep . '# ([v] switch ' . $dump . ')' . |
552
|
|
|
|
|
|
|
$sep . 'my %__LABELS = (' . $hashdata . $sep . "\t\t" . ');' |
553
|
|
|
|
|
|
|
. |
554
|
|
|
|
|
|
|
# $sep . '# ' . join(", ", keys %{ $labels }) . |
555
|
|
|
|
|
|
|
$sep . 'my $__a = ' . $exp->generate($indent, @_) . ';' . |
556
|
|
|
|
|
|
|
$sep . 'exists $__LABELS{$__a} ' . |
557
|
|
|
|
|
|
|
'? goto $__LABELS{$__a} ' . |
558
|
|
|
|
|
|
|
': goto ' . $default . ';' . |
559
|
|
|
|
|
|
|
$sep . $block->generate($indent, @_) . |
560
|
|
|
|
|
|
|
$sep . $self->value(2) . ':' . |
561
|
|
|
|
|
|
|
$isep . '}'; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
{ |
566
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StmtCase; |
567
|
|
|
|
|
|
|
sub generate { |
568
|
0
|
|
|
0
|
|
|
my $self = shift; |
569
|
0
|
|
|
|
|
|
my $indent = shift; |
570
|
0
|
|
|
|
|
|
my $sep = "\n" . ("\t" x $indent); |
571
|
0
|
|
|
|
|
|
my $dump = $self->dump; |
572
|
0
|
|
|
|
|
|
$dump =~ s/\s+/ /g; |
573
|
|
|
|
|
|
|
return |
574
|
0
|
|
|
|
|
|
'# ' . $dump . $sep . |
575
|
|
|
|
|
|
|
# This goto makes sure that a preceding label has at |
576
|
|
|
|
|
|
|
# least one statement. |
577
|
|
|
|
|
|
|
# 'goto ' . $self->value(2) . '; ' . $self->value(2) . ':'; |
578
|
|
|
|
|
|
|
'; ' . $self->value(2) . ':'; # Will this do? |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
{ |
583
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StmtDefault; |
584
|
|
|
|
|
|
|
sub generate { |
585
|
0
|
|
|
0
|
|
|
my $self = shift; |
586
|
0
|
|
|
|
|
|
return $self->value(0) . ': # default'; |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
{ |
591
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StmtBreak; |
592
|
|
|
|
|
|
|
sub generate { |
593
|
0
|
|
|
0
|
|
|
my $self = shift; |
594
|
0
|
|
|
|
|
|
my $val = $self->value(0); |
595
|
0
|
0
|
|
|
|
|
return 'next; # break' unless $val; |
596
|
0
|
|
|
|
|
|
return 'goto ' . $val . '; # break'; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
{ |
601
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StmtRlimits; |
602
|
|
|
|
|
|
|
sub generate { |
603
|
0
|
|
|
0
|
|
|
my $self = shift; |
604
|
0
|
|
|
|
|
|
return $self->value(3)->generate(@_) . ';'; |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
{ |
609
|
|
|
|
|
|
|
package Anarres::Mud::Driver::Compiler::Node::StmtIf; |
610
|
|
|
|
|
|
|
sub generate { |
611
|
0
|
|
|
0
|
|
|
my ($self, $indent, @args) = @_; |
612
|
0
|
|
|
|
|
|
my $sep = "\t" x $indent; |
613
|
0
|
|
|
|
|
|
my $out = |
614
|
|
|
|
|
|
|
"if (" . |
615
|
|
|
|
|
|
|
$self->value(0)->generate($indent + 2, @args) . ") " . |
616
|
|
|
|
|
|
|
$self->value(1)->generate($indent, @args); |
617
|
0
|
|
|
|
|
|
my $else = $self->value(2); |
618
|
0
|
0
|
|
|
|
|
if ($else) { |
619
|
0
|
0
|
|
|
|
|
if (ref($else) =~ /::StmtIf$/) { |
620
|
|
|
|
|
|
|
# Get an 'elsif' |
621
|
0
|
|
|
|
|
|
$out .= "\n" . $sep . "els" . |
622
|
|
|
|
|
|
|
$else->generate($indent, @args); |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
else { |
625
|
0
|
|
|
|
|
|
$out .= |
626
|
|
|
|
|
|
|
"\n" . $sep . "else " . |
627
|
|
|
|
|
|
|
$else->generate($indent, @args); |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
} |
630
|
0
|
|
|
|
|
|
return $out; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
# XXX Hack! |
633
|
|
|
|
|
|
|
*Anarres::Mud::Driver::Compiler::Node::StmtIfElse::generate = |
634
|
|
|
|
|
|
|
\&Anarres::Mud::Driver::Compiler::Node::StmtIf::generate; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
if (1) { |
638
|
|
|
|
|
|
|
my $package = __PACKAGE__; |
639
|
|
|
|
|
|
|
$package =~ s/::Generate$/::Node/; |
640
|
3
|
|
|
3
|
|
30
|
no strict qw(refs); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
659
|
|
641
|
|
|
|
|
|
|
my @missing; |
642
|
|
|
|
|
|
|
foreach (@NODETYPES) { |
643
|
|
|
|
|
|
|
next if defined $OPCODETABLE{$_}; |
644
|
|
|
|
|
|
|
next if defined &{ "$package\::$_\::generate" }; |
645
|
|
|
|
|
|
|
push(@missing, $_); |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
print "No generate in @missing\n" if @missing; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
1; |