File Coverage

blib/lib/Anarres/Mud/Driver/Efun/Core.pm
Criterion Covered Total %
statement 27 80 33.7
branch 0 20 0.0
condition n/a
subroutine 9 41 21.9
pod n/a
total 36 141 25.5


line stmt bran cond sub pod time code
1             package Anarres::Mud::Driver::Efun::Core;
2              
3 2     2   2096 use strict;
  2         3  
  2         68  
4 2     2   9 use warnings;
  2         3  
  2         61  
5 2     2   8 use vars qw($VERSION @ISA);
  2         3  
  2         106  
6              
7             # XXX Where should I be requiring these: before or after bootstrap?
8              
9 2     2   609 use Anarres::Mud::Driver::Compiler::Type qw(:all); # We do this twice?!
  2         5  
  2         1246  
10              
11             # Efuns need to be normal functions in a program symbol table but
12             # will not inherit or issue a warning if redefined.
13              
14             # Note that we don't actually register all available efuns. We
15             # register only those which are visible as efuns to the LPC code.
16             # We may have more efuns, an individual efun typecheck_call method
17             # may decide to rebless the node into a different efun class.
18             # For example, map => map_array or map_mapping. In this way we
19             # can use the Perl object oriented dispatch mechanism to speed up
20             # many operations where a pure Perl conditional would be slower.
21              
22             require DynaLoader;
23              
24             $VERSION = 0.10;
25             @ISA = qw(DynaLoader);
26              
27             bootstrap Anarres::Mud::Driver::Efun::Core;
28              
29 2     2   10 use Anarres::Mud::Driver::Compiler::Type qw(:all); # We do this twice?!
  2         3  
  2         388  
30 2     2   523 use Anarres::Mud::Driver::Program::Efun qw(register);
  2         4  
  2         97  
31 2     2   9 use Anarres::Mud::Driver::Program::Method;
  2         2  
  2         9181  
32              
33             {
34             # As traditional, [ flags, return type, argtype .... ]
35             my $pflags = M_PURE | M_NOMASK; # This just lets me format nicely.
36             my %efuns = (
37             # Common stuff
38              
39             copy => [ 0, T_UNKNOWN, T_UNKNOWN, ],
40              
41             # Object stuff
42              
43             this_object => [ 0, T_OBJECT, ],
44             previous_object => [ 0, T_OBJECT, T_INTEGER, ],
45             all_previous_objects=> [ 0, T_OBJECT->array ],
46             file_name => [ 0, T_STRING, T_OBJECT, ],
47             find_object => [ 0, T_OBJECT, T_STRING, ],
48             load_object => [ 0, T_OBJECT, T_STRING, ],
49             clone_object => [ 0, T_OBJECT, T_STRING, ],
50             destruct => [ 0, T_INTEGER, T_OBJECT, ],
51             children => [ 0, T_OBJECT->array, T_STRING, ],
52             objects => [ 0, T_OBJECT->array, ],
53              
54             # String stuff
55              
56             implode => [ M_PURE, T_STRING, T_STRING->array, T_STRING ],
57             explode => [ M_PURE, T_STRING->array, T_STRING, T_STRING ],
58             lower_case => [ M_PURE, T_STRING, T_STRING, ],
59             upper_case => [ M_PURE, T_STRING, T_STRING, ],
60             strlen => [ M_PURE, T_INTEGER, T_STRING, ],
61             replace_string => [ M_PURE, T_STRING, T_STRING, T_STRING, T_STRING, ],
62             substr => [ M_PURE, T_STRING,
63             T_STRING,
64             T_INTEGER, T_INTEGER, # off
65             T_INTEGER, T_INTEGER, ],# end
66             subchar => [ M_PURE, T_INTEGER,
67             T_STRING, # offset
68             T_INTEGER, ], # from end?
69             capitalize => [ M_PURE, T_STRING, T_STRING, ],
70             strsrch => [ M_PURE, T_INTEGER, T_STRING, T_STRING, ],
71             regexp => [ M_PURE, T_INTEGER, T_STRING, T_STRING, ],
72              
73             # XXX varargs
74             sprintf => [ M_PURE, T_STRING, T_STRING, T_ARRAY, ],
75             sscanf => [ M_PURE, T_STRING, T_STRING, T_ARRAY, ],
76              
77             # Array stuff
78              
79             member_array => [ M_PURE, T_INTEGER, T_UNKNOWN, T_ARRAY, ],
80             unique_array => [ M_PURE, T_ARRAY->array, T_ARRAY, T_CLOSURE],
81             # XXX We can map mappings. :-(
82             map => [ 0, T_ARRAY, T_ARRAY, T_CLOSURE, ],
83             filter => [ 0, T_ARRAY, T_ARRAY, T_CLOSURE, ],
84             allocate => [ 0, T_ARRAY, T_INTEGER, T_UNKNOWN, ],
85              
86             # Mapping stuff
87              
88             keys => [ M_PURE, T_STRING->array, T_MAPPING, ],
89             values => [ M_PURE, T_ARRAY, T_MAPPING, ],
90             map_delete => [ 0, T_UNKNOWN, T_MAPPING,T_STRING,],
91              
92             # Type stuff
93              
94             to_int => [ M_PURE, T_INTEGER, T_STRING, ],
95             to_string => [ M_PURE, T_STRING, T_INTEGER, ],
96             typeof => [ M_PURE, T_STRING, T_UNKNOWN, ],
97             sizeof => [ M_PURE, T_INTEGER, T_UNKNOWN, ],
98              
99             intp => [ $pflags, T_BOOL, T_UNKNOWN, ],
100             stringp => [ $pflags, T_BOOL, T_UNKNOWN, ],
101             arrayp => [ $pflags, T_BOOL, T_UNKNOWN, ],
102             mapp => [ $pflags, T_BOOL, T_UNKNOWN, ],
103             functionp => [ $pflags, T_BOOL, T_UNKNOWN, ],
104             classp => [ $pflags, T_BOOL, T_UNKNOWN, ],
105             objectp => [ $pflags, T_BOOL, T_UNKNOWN, ],
106             clonep => [ M_PURE, T_BOOL, T_UNKNOWN, ],
107             undefinedp => [ M_PURE, T_BOOL, T_UNKNOWN, ],
108              
109             # Closure stuff
110              
111             # XXX varargs
112             evaluate => [ 0, T_UNKNOWN, T_CLOSURE, T_ARRAY, ],
113              
114             # Reflection
115              
116             function_exists => [ 0, T_OBJECT, T_STRING, T_INTEGER, ],
117             functions => [ 0, T_OBJECT, T_INTEGER, ],
118             variables => [ 0, T_OBJECT, T_INTEGER, ],
119             inherits => [ M_PURE, T_INTEGER, T_STRING, T_OBJECT, ],
120             call_stack => [ 0, T_STRING->array, T_INTEGER, ],
121              
122             # File stuff
123              
124             file_size => [ 0, T_INTEGER, T_STRING, ],
125             read_file => [ 0, T_STRING, T_STRING, ],
126             write_file => [ 0, T_INTEGER, T_STRING, T_STRING, ],
127              
128             # System stuff
129              
130             time => [ 0, T_INTEGER, ],
131              
132             debug_message => [ 0, T_STRING, T_STRING, ],
133             error => [ 0, T_INTEGER, T_STRING, ],
134             catch => [ 0, T_STRING, T_UNKNOWN, ],
135             shutdown => [ 0, T_INTEGER, ],
136              
137             trace => [ 0, T_INTEGER, T_INTEGER, ],
138             );
139              
140             # We call this as an exported function since ISA isn't yet set up.
141             foreach (keys %efuns) {
142             register(__PACKAGE__ . "::" . $_, @{ $efuns{$_} });
143             }
144             }
145              
146             {
147             package Anarres::Mud::Driver::Efun::Core::time;
148 0     0     sub generate_call { "time()" }
149             }
150              
151             {
152             package Anarres::Mud::Driver::Efun::Core::debug_message;
153 0     0     sub generate_call { "print STDERR $_[1], '\\n'" }
154             }
155              
156             {
157             package Anarres::Mud::Driver::Efun::Core::previous_object;
158 0     0     sub invoke { undef }
159             }
160              
161             {
162             package Anarres::Mud::Driver::Efun::Core::file_name;
163             sub generate_call {
164 0     0     "Anarres::Mud::Driver::Program::package_to_path(ref($_[1]))"
165             }
166             }
167              
168             {
169             package Anarres::Mud::Driver::Efun::Core::find_object;
170             # sub generate_call { "undef" }
171 0     0     sub invoke { undef }
172             }
173              
174             {
175             package Anarres::Mud::Driver::Efun::Core::to_string;
176             # XXX This only works for CONSTANT integers, of course.
177             # sub generate_call { '"' . $_[1] . '"' }
178             # This works for any integer which is about to be evaluated as
179             # a string by Perl. 6 . 7 == "67";
180 0     0     sub generate_call { ('' . $_[1]) }
181             }
182              
183             {
184             package Anarres::Mud::Driver::Efun::Core::strlen;
185 0     0     sub generate_call { "length($_[1])" }
186             }
187              
188             {
189             package Anarres::Mud::Driver::Efun::Core::error;
190 0     0     sub generate_call { "die('LPC: ' . $_[1])" }
191             }
192              
193             {
194             package Anarres::Mud::Driver::Efun::Core::catch;
195 0     0     sub generate_call { "do { eval { $_[1] }; $@; }"; }
196             }
197              
198             {
199             package Anarres::Mud::Driver::Efun::Core::implode;
200 0     0     sub generate_call { "join($_[2], \@{ $_[1] })" }
201             }
202              
203             {
204             package Anarres::Mud::Driver::Efun::Core::explode;
205             # invoke is an XSUB
206             }
207              
208             {
209             package Anarres::Mud::Driver::Efun::Core::replace_string;
210             # invoke is an XSUB
211             }
212              
213             {
214             package Anarres::Mud::Driver::Efun::Core::intp;
215             # sub generate_call { "(defined($_[1]) && !ref($_[1]))" }
216             # invoke is an XSUB
217             }
218              
219             {
220             package Anarres::Mud::Driver::Efun::Core::stringp;
221             # sub generate_call { "(defined($_[1]) && !ref($_[1]))" }
222             # invoke is an XSUB
223             }
224              
225             {
226             package Anarres::Mud::Driver::Efun::Core::arrayp;
227 0     0     sub generate_call { "ref($_[1]) eq 'ARRAY'" }
228             }
229              
230             {
231             package Anarres::Mud::Driver::Efun::Core::mapp;
232 0     0     sub generate_call { "ref($_[1]) eq 'HASH'" }
233             }
234              
235             {
236             package Anarres::Mud::Driver::Efun::Core::objectp;
237 0     0     sub generate_call { "ref($_[1]) =~ /::/" } # XXX
238             }
239              
240             {
241             package Anarres::Mud::Driver::Efun::Core::clonep;
242 0     0     sub generate_call { "ref($_[1]) =~ /::/" } # XXX
243             }
244              
245             {
246             package Anarres::Mud::Driver::Efun::Core::undefinedp;
247 0     0     sub generate_call { "defined($_[1])" }
248             }
249              
250             {
251             package Anarres::Mud::Driver::Efun::Core::keys;
252 0     0     sub generate_call { "keys(\%{$_[1]})" }
253             }
254              
255             {
256             package Anarres::Mud::Driver::Efun::Core::values;
257 0     0     sub generate_call { "values(\%{$_[1]})" }
258             }
259              
260             {
261             package Anarres::Mud::Driver::Efun::Core::map_delete;
262 0     0     sub generate_call { "delete(\${$_[1]}->{$_[2]})" }
263             }
264              
265             {
266             package Anarres::Mud::Driver::Efun::Core::regexp;
267 0     0     sub generate_call { "XXX($_[1] =~ m/$_[2]/)" }
268             }
269              
270             {
271             package Anarres::Mud::Driver::Efun::Core::clone_object;
272 0     0     sub generate_call { "$_[1]\->new()" }
273             }
274              
275             {
276             package Anarres::Mud::Driver::Efun::Core::this_object;
277 0     0     sub generate_call { '$self' }
278             }
279              
280             {
281             package Anarres::Mud::Driver::Efun::Core::strsrch;
282 0     0     sub generate_call { "index($_[1], $_[2])" }
283             }
284              
285             {
286             package Anarres::Mud::Driver::Efun::Core::lower_case;
287 0     0     sub generate_call { "lc($_[1])" }
288             }
289              
290             {
291             package Anarres::Mud::Driver::Efun::Core::upper_case;
292 0     0     sub generate_call { "uc($_[1])" }
293             }
294              
295             {
296             package Anarres::Mud::Driver::Efun::Core::substr;
297             # invoke is an XSUB
298             }
299              
300             {
301             package Anarres::Mud::Driver::Efun::Core::subchar;
302             # invoke is an XSUB
303             }
304              
305             {
306             package Anarres::Mud::Driver::Efun::Core::capitalize;
307 0     0     sub generate_call { "ucfirst($_[1])" }
308             }
309              
310             {
311             package Anarres::Mud::Driver::Efun::Core::allocate;
312             sub generate_call {
313 0 0   0     my $val = defined $_[2] ? $_[2] : 'undef';
314 0           return "[ ($val) x $_[1] ]"
315             }
316             }
317              
318             {
319             package Anarres::Mud::Driver::Efun::Core::to_int;
320 0     0     sub generate_call { "(0 + ($_[1]))" }
321             }
322              
323             {
324             package Anarres::Mud::Driver::Efun::Core::copy;
325 0     0     sub invoke { $_[1] } # XXX dclone - but not for objects.
326             }
327              
328             {
329             package Anarres::Mud::Driver::Efun::Core::inherits;
330 0     0     sub generate_call { "($_[2])->isa(XXX_to_package($_[1]))" }
331             }
332              
333             {
334             package Anarres::Mud::Driver::Efun::Core::sizeof;
335             sub generate_call {
336             # XXX Arse - use typechecking info!
337             # XXX Deal with ints
338 0     0     'do { my $__a = ' . $_[1] . '; my $__r = ref($__a); ' .
339             # ($#$__a + 1) ?
340             '$__r eq "ARRAY" ? scalar(@{$__a}) : ' .
341             '$__r eq "HASH" ? scalar(keys %{$__a}) : ' .
342             '$__r eq "" ? length($__a) : ' .
343             'die "Cannot take sizeof($__r)"; }';
344             }
345             }
346              
347             {
348             package Anarres::Mud::Driver::Efun::Core::file_size;
349 2     2   13 use Fcntl qw(:mode);
  2         4  
  2         863  
350             sub invoke {
351 0     0     my @stat = stat($_[1]);
352 0 0         return -1 unless @stat;
353 0 0         return -2 if ($stat[2] & S_IFDIR);
354 0           return $stat[2];
355             }
356             }
357              
358             {
359             package Anarres::Mud::Driver::Efun::Core::map;
360 2     2   39 use Anarres::Mud::Driver::Compiler::Type qw(:all);
  2         4  
  2         1036  
361             sub typecheck_call {
362 0     0     my ($self, $program, $values, @rest) = @_;
363 0           my $val = $values->[1];
364 0           my $func = $values->[2];
365              
366 0           $func = $func->infer(T_CLOSURE);
367 0 0         unless ($func) {
368 0           $program->error("Argument 2 to map must be a closure.");
369             }
370              
371 0 0         if (my $arr = $val->infer(T_ARRAY)) {
    0          
    0          
372             # $values->[0] = "(pointer to map_array)";
373 0           $values->[1] = $arr;
374 0 0         $arr->typecheck($program, undef, @rest) unless $arr == $val;
375 0           return $arr->type;
376             }
377             elsif (my $map = $val->infer(T_MAPPING)) {
378             # $values->[0] = "(pointer to map_mapping)";
379 0           $values->[1] = $map;
380 0 0         $map->typecheck($program, undef, @rest) unless $map == $val;
381 0           return $map->type;
382             }
383             elsif (my $str = $val->infer(T_STRING)) {
384 0           $values->[1] = $str;
385 0 0         $str->typecheck($program, undef, @rest) unless $str == $val;
386 0           return $str->type;
387             }
388             else {
389 0           $program->error("Argument 1 to map must be a mapping " .
390             "or an array.");
391 0           return undef;
392             }
393             }
394             }
395              
396             1;