| 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; |