line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package JE::Object; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# This has to come before any pragmas and sub declarations. |
4
|
181
|
|
|
181
|
0
|
243
|
sub evall { my $global = shift; my $r = eval 'local *_;' . shift; |
|
181
|
|
|
|
|
15287
|
|
5
|
181
|
50
|
|
|
|
728
|
$@ and die; $r } |
|
181
|
|
|
|
|
519
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.064'; |
8
|
|
|
|
|
|
|
|
9
|
101
|
|
|
101
|
|
45638
|
use strict; |
|
101
|
|
|
|
|
148
|
|
|
101
|
|
|
|
|
3221
|
|
10
|
101
|
|
|
101
|
|
390
|
use warnings; |
|
101
|
|
|
|
|
695
|
|
|
101
|
|
|
|
|
5979
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use overload fallback => 1, |
13
|
|
|
|
|
|
|
'%{}'=> \&_get_tie, |
14
|
|
|
|
|
|
|
'""' => 'to_string', |
15
|
|
|
|
|
|
|
'0+' => 'to_number', |
16
|
|
|
|
|
|
|
# cmp => sub { "$_[0]" cmp $_[1] }, |
17
|
101
|
|
|
101
|
|
46902
|
bool => sub { 1 }; |
|
101
|
|
|
74141
|
|
75878
|
|
|
101
|
|
|
|
|
1130
|
|
|
74141
|
|
|
|
|
162845
|
|
18
|
|
|
|
|
|
|
|
19
|
101
|
|
|
101
|
|
9606
|
use Scalar::Util qw'refaddr blessed'; |
|
101
|
|
|
|
|
129
|
|
|
101
|
|
|
|
|
5551
|
|
20
|
101
|
|
|
101
|
|
482
|
use List::Util 'first'; |
|
101
|
|
|
|
|
121
|
|
|
101
|
|
|
|
|
5020
|
|
21
|
101
|
|
|
101
|
|
415
|
use B 'svref_2object'; |
|
101
|
|
|
|
|
122
|
|
|
101
|
|
|
|
|
231884
|
|
22
|
|
|
|
|
|
|
#use Data::Dumper; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
require JE::Code; |
26
|
|
|
|
|
|
|
require JE::Object::Error::TypeError; |
27
|
|
|
|
|
|
|
require JE::Object::Function; |
28
|
|
|
|
|
|
|
require JE::Boolean; |
29
|
|
|
|
|
|
|
require JE::String; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
import JE::Code 'add_line_number'; |
32
|
|
|
|
|
|
|
sub add_line_number; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub in_list { |
35
|
231
|
|
|
231
|
0
|
289
|
my $str = shift; |
36
|
231
|
|
100
|
|
|
1714
|
shift eq $str and return 1 while @_; |
37
|
219
|
|
|
|
|
896
|
!1; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 NAME |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
JE::Object - Base class for all JavaScript objects |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head1 SYNOPSIS |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
use JE; |
48
|
|
|
|
|
|
|
use JE::Object; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
$j = new JE; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
$obj = new JE::Object $j; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
$obj->prop('property1', $new_value); # sets the property |
55
|
|
|
|
|
|
|
$obj->prop('property1'); # returns $new_value; |
56
|
|
|
|
|
|
|
$obj->{property1} = $new_value; # or use it as a hash |
57
|
|
|
|
|
|
|
$obj->{property1}; # ref like this |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
$obj->keys; # returns a list of the names of enumerable property |
60
|
|
|
|
|
|
|
keys %$obj; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
$obj->delete('property_name'); |
63
|
|
|
|
|
|
|
delete $obj->{property_name}; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
$obj->method('method_name', 'arg1', 'arg2'); |
66
|
|
|
|
|
|
|
# calls a method with the given arguments |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
$obj->value ; # returns a value useful in Perl (a hashref) |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
"$obj"; # "[object Object]" -- same as $obj->to_string->value |
71
|
|
|
|
|
|
|
0+$obj"; # nan -- same as $obj->to_number->value |
72
|
|
|
|
|
|
|
# etc. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 DESCRIPTION |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
This module implements JavaScript objects for JE. It serves as a base |
77
|
|
|
|
|
|
|
class |
78
|
|
|
|
|
|
|
for all other JavaScript objects. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
A JavaScript object is an associative array, the elements of which are |
81
|
|
|
|
|
|
|
its properties. A method is a property that happens to be an instance |
82
|
|
|
|
|
|
|
of the |
83
|
|
|
|
|
|
|
C class (C). |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
JE::Object objects can be used in Perl as a number, string or boolean. The |
86
|
|
|
|
|
|
|
result will be the same as in JavaScript. The C<%{}> (hashref) operator is |
87
|
|
|
|
|
|
|
also overloaded and returns a hash that can be used to modify the object. |
88
|
|
|
|
|
|
|
See L<"USING AN OBJECT AS A HASH">. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
See also L for descriptions of most of the methods. Only what |
91
|
|
|
|
|
|
|
is specific to JE::Object is explained here. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 METHODS |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=over 4 |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=item $obj = JE::Object->new( $global_obj ) |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item $obj = JE::Object->new( $global_obj, $value ) |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item $obj = JE::Object->new( $global_obj, \%options ) |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
This class method constructs and returns a new JavaScript object, unless |
104
|
|
|
|
|
|
|
C<$value> is |
105
|
|
|
|
|
|
|
already a JS object, in which case it just returns it. The behaviour is |
106
|
|
|
|
|
|
|
the |
107
|
|
|
|
|
|
|
same as the C |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
The C<%options> are as follows: |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
prototype the object to be used as the prototype for this |
112
|
|
|
|
|
|
|
object (Object.prototype is the default) |
113
|
|
|
|
|
|
|
value the value to be turned into an object |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
C only applies when C is omitted, undef, undefined |
116
|
|
|
|
|
|
|
or null. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
To convert a hash into an object, you can use the hash ref syntax like |
119
|
|
|
|
|
|
|
this: |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
new JE::Object $j, { value => \%hash } |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Though it may be easier to write: |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
$j->upgrade(\%hash) |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
The former is what C itself uses. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=cut |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# ~~~ Perhaps I should eliminate the hash ref syntax and have new() |
132
|
|
|
|
|
|
|
# check to see if $j->exists($class->class), and use that as the |
133
|
|
|
|
|
|
|
# prototype. That would make the other constructors simpler, but would |
134
|
|
|
|
|
|
|
# it make it harder to control JE and customise host objects? |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub new { |
137
|
19491
|
|
|
19491
|
1
|
24416
|
my($class, $global, $value) = @_; |
138
|
|
|
|
|
|
|
|
139
|
19491
|
100
|
100
|
|
|
52148
|
if (defined blessed $value |
140
|
|
|
|
|
|
|
and can $value 'to_object') { |
141
|
9
|
|
|
|
|
24
|
return to_object $value; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
19482
|
|
|
|
|
16497
|
my $p; |
145
|
|
|
|
|
|
|
my %hash; |
146
|
0
|
|
|
|
|
0
|
my %opts; |
147
|
|
|
|
|
|
|
|
148
|
19482
|
100
|
|
|
|
62421
|
ref $value eq 'HASH' and (%opts = %$value), $value = $opts{value}; |
149
|
|
|
|
|
|
|
|
150
|
19482
|
|
|
|
|
21295
|
local $@; |
151
|
19482
|
100
|
66
|
|
|
45093
|
if (!defined $value || !defined eval{$value->value} && $@ eq '') { |
|
7
|
50
|
66
|
|
|
54
|
|
152
|
19479
|
100
|
|
|
|
47814
|
$p = exists $opts{prototype} ? $opts{prototype} |
153
|
|
|
|
|
|
|
: $global->prototype_for("Object"); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
elsif(ref $value eq 'HASH') { |
156
|
3
|
|
|
|
|
8
|
%hash = %$value; |
157
|
3
|
|
|
|
|
10
|
$p = $global->prototype_for("Object"); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
else { |
160
|
0
|
|
|
|
|
0
|
return $global->upgrade($value); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
19482
|
|
|
|
|
99506
|
my $self = |
164
|
|
|
|
|
|
|
bless \{ prototype => $p, |
165
|
|
|
|
|
|
|
global => $global, |
166
|
|
|
|
|
|
|
props => \%hash, |
167
|
|
|
|
|
|
|
keys => [keys %hash] }, $class; |
168
|
|
|
|
|
|
|
|
169
|
19482
|
50
|
|
|
|
35436
|
$JE::Destroyer && JE::Destroyer'register($self); |
170
|
|
|
|
|
|
|
|
171
|
19482
|
|
|
|
|
52646
|
$self; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub destroy { # not DESTROY; called by JE::Destroyer |
175
|
0
|
|
|
0
|
0
|
0
|
undef ${$_[0]}; |
|
0
|
|
|
|
|
0
|
|
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=item $obj->new_function($name, sub { ... }) |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=item $obj->new_function(sub { ... }) |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
This creates and returns a new function object. If $name is given, |
184
|
|
|
|
|
|
|
it will become a property of the object. The function is enumerable, like |
185
|
|
|
|
|
|
|
C I in web browsers. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
For more ways to create functions, see L. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=cut |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub new_function { |
192
|
707
|
|
|
707
|
1
|
4064
|
my $self = shift; |
193
|
707
|
50
|
|
|
|
1234
|
my $f = JE::Object::Function->new({ |
194
|
|
|
|
|
|
|
scope => $self->global, |
195
|
|
|
|
|
|
|
function => pop, |
196
|
|
|
|
|
|
|
function_args => ['args'], |
197
|
|
|
|
|
|
|
@_ ? (name => $_[0]) : () |
198
|
|
|
|
|
|
|
}); |
199
|
707
|
50
|
|
|
|
3172
|
@_ and $self->prop({ |
200
|
|
|
|
|
|
|
name => shift, |
201
|
|
|
|
|
|
|
value=>$f, |
202
|
|
|
|
|
|
|
}); |
203
|
707
|
|
|
|
|
1741
|
$f; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=item $obj->new_method($name, sub { ... }) |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=item $obj->new_method(sub { ... }) |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
This is the same as C, except that the subroutine's first |
214
|
|
|
|
|
|
|
argument will be the object with which the function is called, and that the |
215
|
|
|
|
|
|
|
property created will not be enumerable. This allows one to add methods to |
216
|
|
|
|
|
|
|
C, for instance, without making every for-in loop list |
217
|
|
|
|
|
|
|
that method. |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
For more ways to create functions, see L. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub new_method { |
224
|
24
|
|
|
24
|
1
|
34
|
my $self = shift; |
225
|
24
|
50
|
|
|
|
46
|
my $f = JE::Object::Function->new({ |
226
|
|
|
|
|
|
|
scope => $self->global, |
227
|
|
|
|
|
|
|
function => pop, |
228
|
|
|
|
|
|
|
function_args => ['this','args'], |
229
|
|
|
|
|
|
|
@_ ? (name => $_[0]) : () |
230
|
|
|
|
|
|
|
}); |
231
|
24
|
50
|
|
|
|
140
|
@_ and $self->prop({ |
232
|
|
|
|
|
|
|
name => shift, |
233
|
|
|
|
|
|
|
value=>$f, |
234
|
|
|
|
|
|
|
dontenum=>1 |
235
|
|
|
|
|
|
|
}); |
236
|
24
|
|
|
|
|
106
|
$f; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=item $obj->prop( $name ) |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=item $obj->prop( $name => $value ) |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=item $obj->prop({ ... }) |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
See C for the first two uses. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
When the C method is called with a hash ref as its argument, the |
248
|
|
|
|
|
|
|
prototype chain is I searched. |
249
|
|
|
|
|
|
|
The elements of the hash are as follows: |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
name property name |
252
|
|
|
|
|
|
|
value new value |
253
|
|
|
|
|
|
|
dontenum whether this property is unenumerable |
254
|
|
|
|
|
|
|
dontdel whether this property is undeletable |
255
|
|
|
|
|
|
|
readonly whether this property is read-only |
256
|
|
|
|
|
|
|
fetch subroutine called when the property is fetched |
257
|
|
|
|
|
|
|
store subroutine called when the property is set |
258
|
|
|
|
|
|
|
autoload see below |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
If C, C or C is given, the attribute in |
261
|
|
|
|
|
|
|
question will be set. |
262
|
|
|
|
|
|
|
If C is given, the value of the property will be set, regardless of |
263
|
|
|
|
|
|
|
the attributes. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
C and C, if specified, must be subroutines for |
266
|
|
|
|
|
|
|
fetching/setting the value of the property. The 'fetch' subroutine will be |
267
|
|
|
|
|
|
|
called with ($object, $storage_space) as the arguments, where |
268
|
|
|
|
|
|
|
C<$storage_space> is a hash key inside the object that the two subroutines |
269
|
|
|
|
|
|
|
can use for storing the value (they can ignore it if they like). The |
270
|
|
|
|
|
|
|
'store' subroutine will be call with |
271
|
|
|
|
|
|
|
($object, $new_value, $storage_space) as |
272
|
|
|
|
|
|
|
the arguments. Values assigned to the storage space from within these |
273
|
|
|
|
|
|
|
routines are I |
274
|
|
|
|
|
|
|
upgraded, neither is the return value of C. C and C do |
275
|
|
|
|
|
|
|
not necessarily have to go |
276
|
|
|
|
|
|
|
together. If you only specify C, then the value will be set as |
277
|
|
|
|
|
|
|
usual, but C will be able to mangle the value when it is retrieved. |
278
|
|
|
|
|
|
|
Likewise, if you only specify C, the value will be retrieved the |
279
|
|
|
|
|
|
|
usual way, so you can use this for validating or normalising the assigned |
280
|
|
|
|
|
|
|
value, for |
281
|
|
|
|
|
|
|
instance. B Currently, a simple scalar or unblessed coderef in the |
282
|
|
|
|
|
|
|
storage space will cause autoloading, but that is subject to change. |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
C can be a string or a coderef. It will be called/evalled the |
285
|
|
|
|
|
|
|
first time the property is accessed (accessing it with a hash ref as |
286
|
|
|
|
|
|
|
described here does not count). If it is a string, it will be |
287
|
|
|
|
|
|
|
evaluated in the calling package (see warning below), in a scope that has a |
288
|
|
|
|
|
|
|
variable named |
289
|
|
|
|
|
|
|
C<$global> that refers to the global object. The result will become the |
290
|
|
|
|
|
|
|
property's value. The value returned is not currently upgraded. The behaviour when a simple scalar or unblessed reference is returned is |
291
|
|
|
|
|
|
|
undefined. C will be |
292
|
|
|
|
|
|
|
ignored completely if C or C is also given. B The |
293
|
|
|
|
|
|
|
'calling package' may not be what you think it is if a subclass overrides |
294
|
|
|
|
|
|
|
C. It may be the subclass in such cases. To be on the safe side, |
295
|
|
|
|
|
|
|
always begin the string of code with an explicit C statement. (If |
296
|
|
|
|
|
|
|
anyone knows of a clean solution to this, please let the author know.) |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
This hash ref calling convention does not work on Array |
299
|
|
|
|
|
|
|
objects when the property name is C or an array index (a |
300
|
|
|
|
|
|
|
non-negative integer |
301
|
|
|
|
|
|
|
below |
302
|
|
|
|
|
|
|
4294967295). It does not work on String objects if the |
303
|
|
|
|
|
|
|
property name is C. |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=cut |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub prop { |
308
|
164303
|
|
|
164303
|
1
|
222956
|
my ($self, $opts) = (shift, shift); |
309
|
164303
|
|
|
|
|
204334
|
my $guts = $$self; |
310
|
|
|
|
|
|
|
|
311
|
164303
|
100
|
|
|
|
271228
|
if(ref $opts eq 'HASH') { # special use |
312
|
34097
|
|
|
|
|
38778
|
my $name = $$opts{name}; |
313
|
34097
|
|
|
|
|
44417
|
for (qw< dontdel readonly >) { |
314
|
68194
|
100
|
|
|
|
163474
|
exists $$opts{$_} |
315
|
|
|
|
|
|
|
and $$guts{"prop_$_"}{$name} = $$opts{$_}; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
34097
|
|
|
|
|
39794
|
my $props = $$guts{props}; |
319
|
|
|
|
|
|
|
|
320
|
34097
|
|
|
|
|
25700
|
my $dontenum; |
321
|
34097
|
100
|
|
|
|
54816
|
if(exists $$opts{dontenum}) { |
|
|
100
|
|
|
|
|
|
322
|
27255
|
50
|
|
|
|
36744
|
if($$opts{dontenum}) { |
323
|
27255
|
|
|
|
|
39808
|
@{$$guts{keys}} = |
|
27255
|
|
|
|
|
35045
|
|
324
|
27255
|
|
|
|
|
21813
|
grep $_ ne $name, @{$$guts{keys}}; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
else { |
327
|
0
|
|
|
0
|
|
0
|
push @{ $$guts{keys} }, $name |
|
0
|
|
|
|
|
0
|
|
328
|
0
|
0
|
|
|
|
0
|
unless first {$_ eq $name} @{$$guts{keys}}; |
|
0
|
|
|
|
|
0
|
|
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
elsif(!exists $$props{$name}) { # new property |
332
|
6474
|
|
|
|
|
5305
|
push @{ $$guts{keys} }, $name |
|
6474
|
|
|
|
|
11055
|
|
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
34097
|
100
|
|
|
|
58467
|
if(exists $$opts{fetch}) { |
336
|
111
|
|
|
|
|
188
|
$$guts{fetch_handler}{$name} = $$opts{fetch}; |
337
|
111
|
50
|
|
|
|
257
|
$$props{$name} = undef if !exists $$props{$name}; |
338
|
|
|
|
|
|
|
} |
339
|
34097
|
100
|
|
|
|
51704
|
if(exists $$opts{store}) { |
340
|
104
|
|
|
|
|
163
|
$$guts{store_handler}{$name} = $$opts{store}; |
341
|
104
|
100
|
|
|
|
200
|
$$props{$name} = undef if !exists $$props{$name}; |
342
|
|
|
|
|
|
|
} |
343
|
34097
|
100
|
100
|
|
|
53470
|
if(exists $$opts{value}) { |
|
|
100
|
|
|
|
|
|
344
|
31393
|
|
|
|
|
94774
|
return $$props{$name} = $$opts{value}; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
elsif(!exists $$opts{fetch} && exists $$opts{autoload}) { |
347
|
2051
|
|
|
|
|
1975
|
my $auto = $$opts{autoload}; |
348
|
2051
|
100
|
|
|
|
7130
|
$$props{$name} = ref $auto eq 'CODE' ? $auto : |
349
|
|
|
|
|
|
|
"package " . caller() . "; $auto"; |
350
|
|
|
|
|
|
|
return # ~~~ Figure out what this should |
351
|
|
|
|
|
|
|
# return, if anything |
352
|
2051
|
|
|
|
|
4080
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# ~~~ what should we return if fetch is given, |
355
|
|
|
|
|
|
|
# but not value? |
356
|
|
|
|
|
|
|
|
357
|
653
|
100
|
|
|
|
3124
|
return exists $$opts{fetch} ? () : |
|
|
100
|
|
|
|
|
|
358
|
|
|
|
|
|
|
exists $$props{$name} ? $$props{$name} : undef; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
else { # normal use |
362
|
130206
|
|
|
|
|
129256
|
my $name = $opts; |
363
|
130206
|
|
|
|
|
156260
|
my $props = $$guts{props}; |
364
|
130206
|
100
|
|
|
|
318610
|
if (@_) { # we is doing a assignment |
|
|
100
|
|
|
|
|
|
365
|
23506
|
|
|
|
|
25240
|
my($new_val) = shift; |
366
|
|
|
|
|
|
|
|
367
|
23506
|
100
|
|
|
|
37263
|
return $new_val if $self->is_readonly($name); |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Make sure we don't change attributes if the |
370
|
|
|
|
|
|
|
# property already exists |
371
|
23384
|
|
100
|
|
|
78143
|
my $exists = exists $$props{$name} && |
372
|
|
|
|
|
|
|
defined $$props{$name}; |
373
|
|
|
|
|
|
|
|
374
|
23384
|
100
|
|
|
|
53205
|
exists $$guts{store_handler}{$name} |
375
|
|
|
|
|
|
|
? $$guts{store_handler}{$name}->( |
376
|
|
|
|
|
|
|
$self, $new_val, $$props{$name}) |
377
|
|
|
|
|
|
|
: ($$props{$name} = $new_val); |
378
|
|
|
|
|
|
|
|
379
|
23384
|
100
|
|
|
|
44897
|
push @{ $$guts{keys} }, $name |
|
2100
|
|
|
|
|
3348
|
|
380
|
|
|
|
|
|
|
unless $exists; |
381
|
|
|
|
|
|
|
|
382
|
23384
|
|
|
|
|
76564
|
return $new_val; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
elsif (exists $$props{$name}) { |
385
|
99123
|
100
|
|
|
|
202499
|
if(exists $$guts{fetch_handler}{$name}) { |
386
|
68
|
|
|
|
|
215
|
return $$guts{fetch_handler}{$name}-> ( |
387
|
|
|
|
|
|
|
$self, $$props{$name} |
388
|
|
|
|
|
|
|
); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
99055
|
|
|
|
|
122401
|
my $val = $$props{$name}; |
392
|
99055
|
100
|
66
|
|
|
425895
|
ref $val eq 'CODE' ? |
393
|
|
|
|
|
|
|
$val = $$props{$name} = &$val() : |
394
|
|
|
|
|
|
|
defined $val && ref $val eq '' && |
395
|
|
|
|
|
|
|
($val = $$props{$name} = |
396
|
|
|
|
|
|
|
evall $$guts{global}, $val |
397
|
|
|
|
|
|
|
); |
398
|
99055
|
|
|
|
|
247899
|
return $val; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
else { |
401
|
7577
|
|
|
|
|
12385
|
my $proto = $self->prototype; |
402
|
7577
|
100
|
|
|
|
16434
|
return $proto ? |
403
|
|
|
|
|
|
|
$proto->prop($name) : |
404
|
|
|
|
|
|
|
undef; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub exists { # = hasOwnProperty |
412
|
100125
|
|
|
100125
|
0
|
102064
|
my($self,$name) = @_; |
413
|
100125
|
|
|
|
|
404480
|
return exists $$$self{props}{$name} |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
sub is_readonly { # See JE::Types for a description of this. |
418
|
26621
|
|
|
26621
|
0
|
31607
|
my ($self,$name) = (shift,@_); # leave $name in @_ |
419
|
|
|
|
|
|
|
|
420
|
26621
|
|
|
|
|
27805
|
my $guts = $$self; |
421
|
|
|
|
|
|
|
|
422
|
26621
|
|
|
|
|
26318
|
my $props = $$guts{props}; |
423
|
26621
|
100
|
|
|
|
55156
|
if( exists $$props{$name}) { |
424
|
21460
|
|
|
|
|
24589
|
my $read_only_list = $$guts{prop_readonly}; |
425
|
21460
|
100
|
|
|
|
74717
|
return exists $$read_only_list{$name} ? |
426
|
|
|
|
|
|
|
$$read_only_list{$name} : !1; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
5161
|
100
|
|
|
|
6333
|
if(my $proto = $self->prototype) { |
430
|
3097
|
|
|
|
|
4865
|
return $proto->is_readonly(@_); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
2064
|
|
|
|
|
6694
|
return !1; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub is_enum { |
440
|
231
|
|
|
231
|
0
|
363
|
my ($self, $name) = @_; |
441
|
231
|
|
|
|
|
363
|
$self = $$self; |
442
|
231
|
|
|
|
|
255
|
in_list $name, @{ $$self{keys} }; |
|
231
|
|
|
|
|
800
|
|
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
sub keys { |
449
|
255
|
|
|
255
|
0
|
496
|
my $self = shift; |
450
|
255
|
|
|
|
|
546
|
my $proto = $self->prototype; |
451
|
255
|
100
|
|
|
|
238
|
@{ $$self->{keys} }, defined $proto ? $proto->keys : (); |
|
255
|
|
|
|
|
1379
|
|
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=item $obj->delete($property_name, $even_if_it's_undeletable) |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Deletes the property named $name, if it is deletable. If the property did |
460
|
|
|
|
|
|
|
not exist or it was deletable, then |
461
|
|
|
|
|
|
|
true is returned. If the property exists and could not be deleted, false |
462
|
|
|
|
|
|
|
is returned. |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
If the second argument is given and is true, the property will be deleted |
465
|
|
|
|
|
|
|
even if it is marked is undeletable. A subclass may override this, |
466
|
|
|
|
|
|
|
however. |
467
|
|
|
|
|
|
|
For instance, Array and String objects always have a 'length' property |
468
|
|
|
|
|
|
|
which cannot be deleted. |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=cut |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub delete { |
473
|
291
|
|
|
291
|
1
|
498
|
my ($self, $name) = @_; |
474
|
291
|
|
|
|
|
437
|
my $guts = $$self; |
475
|
|
|
|
|
|
|
|
476
|
291
|
100
|
|
|
|
689
|
unless($_[2]) { # second arg means always delete |
477
|
176
|
|
|
|
|
309
|
my $dontdel_list = $$guts{prop_dontdel}; |
478
|
176
|
100
|
66
|
|
|
1415
|
exists $$dontdel_list{$name} and $$dontdel_list{$name} |
479
|
|
|
|
|
|
|
and return !1; |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
145
|
|
|
|
|
353
|
delete $$guts{prop_dontdel }{$name}; |
483
|
145
|
|
|
|
|
216
|
delete $$guts{prop_dontenum}{$name}; |
484
|
145
|
|
|
|
|
222
|
delete $$guts{prop_readonly}{$name}; |
485
|
145
|
|
|
|
|
301
|
delete $$guts{props}{$name}; |
486
|
145
|
|
|
|
|
175
|
$$guts{keys} = [ grep $_ ne $name, @{$$guts{keys}} ]; |
|
145
|
|
|
|
|
1134
|
|
487
|
145
|
|
|
|
|
450
|
return 1; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
sub method { |
494
|
28
|
|
|
28
|
0
|
68
|
my($self,$method) = (shift,shift); |
495
|
|
|
|
|
|
|
|
496
|
28
|
|
|
|
|
65
|
$self->prop($method)->apply($self, $self->global->upgrade(@_)); |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=item $obj->typeof |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
This returns the string 'object'. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=cut |
504
|
|
|
|
|
|
|
|
505
|
112
|
|
|
112
|
1
|
311
|
sub typeof { 'object' } |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=item $obj->class |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Returns the string 'Object'. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=cut |
515
|
|
|
|
|
|
|
|
516
|
440
|
|
|
440
|
1
|
1737
|
sub class { 'Object' } |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=item $obj->value |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
This returns a hash ref of the object's enumerable properties. This is a |
524
|
|
|
|
|
|
|
copy of the object's properties. Modifying it does not modify the object |
525
|
|
|
|
|
|
|
itself. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=cut |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
sub value { |
530
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
531
|
1
|
|
|
|
|
4
|
+{ map +($_ => $self->prop($_)), $self->keys }; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
*TO_JSON=*value; |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub id { |
540
|
145523
|
|
|
145523
|
0
|
308147
|
refaddr shift; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
1359
|
|
|
1359
|
0
|
4414
|
sub primitive { !1 }; |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
sub prototype { |
546
|
15840
|
100
|
|
15840
|
0
|
22295
|
@_ > 1 ? (${+shift}->{prototype} = $_[1]) : ${+shift}->{prototype}; |
|
469
|
|
|
|
|
3912
|
|
|
15371
|
|
|
|
|
32979
|
|
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
sub to_primitive { |
553
|
985
|
|
|
985
|
0
|
1425
|
my($self, $hint) = @_; |
554
|
|
|
|
|
|
|
|
555
|
985
|
|
|
|
|
1853
|
my @methods = ('valueOf','toString'); |
556
|
985
|
100
|
100
|
|
|
3940
|
defined $hint && $hint eq 'string' and @methods = reverse @methods; |
557
|
|
|
|
|
|
|
|
558
|
985
|
|
|
|
|
1022
|
my $method; my $prim; |
559
|
985
|
|
|
|
|
1527
|
for (@methods) { |
560
|
1325
|
100
|
|
|
|
2462
|
defined($method = $self->prop($_)) || next; |
561
|
1313
|
100
|
|
|
|
3774
|
($prim = $method->apply($self))->primitive || next; |
562
|
971
|
|
|
|
|
3530
|
return $prim; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
die new JE::Object::Error::TypeError $self->global, |
566
|
|
|
|
|
|
|
add_line_number "An object of type " . |
567
|
8
|
|
33
|
|
|
14
|
(eval {$self->class} || ref $self) . |
568
|
|
|
|
|
|
|
" cannot be converted to a primitive"; |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
sub to_boolean { |
575
|
42
|
|
|
42
|
0
|
582
|
JE::Boolean->new( $${+shift}{global}, 1 ); |
|
42
|
|
|
|
|
177
|
|
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
sub to_string { |
579
|
324
|
|
|
324
|
0
|
7343
|
shift->to_primitive('string')->to_string; |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
sub to_number { |
584
|
406
|
|
|
406
|
0
|
1921
|
shift->to_primitive('number')->to_number; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
1902
|
|
|
1902
|
0
|
6993
|
sub to_object { $_[0] } |
588
|
|
|
|
|
|
|
|
589
|
1644
|
|
|
1644
|
0
|
1399
|
sub global { ${+shift}->{global} } |
|
1644
|
|
|
|
|
6280
|
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=back |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=cut |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
#----------- PRIIVATE ROUTIES ---------------# |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
# _init_proto takes the Object prototype (Object.prototype) as its sole |
601
|
|
|
|
|
|
|
# arg and adds all the default properties thereto. |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
sub _init_proto { |
604
|
106
|
|
|
106
|
|
180
|
my $proto = shift; |
605
|
106
|
|
|
|
|
247
|
my $global = $$proto->{global}; |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# E 15.2.4 |
608
|
|
|
|
|
|
|
|
609
|
106
|
|
|
|
|
354
|
$proto->prop({ |
610
|
|
|
|
|
|
|
dontenum => 1, |
611
|
|
|
|
|
|
|
name => 'constructor', |
612
|
|
|
|
|
|
|
value => $global->prop('Object'), |
613
|
|
|
|
|
|
|
}); |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
my $toString_sub = sub { |
616
|
566
|
|
|
566
|
|
744
|
my $self = shift; |
617
|
566
|
|
|
|
|
1693
|
JE::String->new($global, |
618
|
|
|
|
|
|
|
'[object ' . $self->class . ']'); |
619
|
106
|
|
|
|
|
557
|
}; |
620
|
|
|
|
|
|
|
|
621
|
106
|
|
|
|
|
1263
|
$proto->prop({ |
622
|
|
|
|
|
|
|
name => 'toString', |
623
|
|
|
|
|
|
|
value => JE::Object::Function->new({ |
624
|
|
|
|
|
|
|
scope => $global, |
625
|
|
|
|
|
|
|
name => 'toString', |
626
|
|
|
|
|
|
|
length => 0, |
627
|
|
|
|
|
|
|
function_args => ['this'], |
628
|
|
|
|
|
|
|
function => $toString_sub, |
629
|
|
|
|
|
|
|
no_proto => 1, |
630
|
|
|
|
|
|
|
}), |
631
|
|
|
|
|
|
|
dontenum => 1, |
632
|
|
|
|
|
|
|
}); |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
$proto->prop({ |
635
|
|
|
|
|
|
|
name => 'toLocaleString', |
636
|
|
|
|
|
|
|
value => JE::Object::Function->new({ |
637
|
|
|
|
|
|
|
scope => $global, |
638
|
|
|
|
|
|
|
name => 'toLocaleString', |
639
|
|
|
|
|
|
|
length => 0, |
640
|
|
|
|
|
|
|
function_args => ['this'], |
641
|
7
|
|
|
7
|
|
36
|
function => sub { shift->method('toString') }, |
642
|
106
|
|
|
|
|
1236
|
no_proto => 1, |
643
|
|
|
|
|
|
|
}), |
644
|
|
|
|
|
|
|
dontenum => 1, |
645
|
|
|
|
|
|
|
}); |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
$proto->prop({ |
648
|
|
|
|
|
|
|
name => 'valueOf', |
649
|
|
|
|
|
|
|
value => JE::Object::Function->new({ |
650
|
|
|
|
|
|
|
scope => $global, |
651
|
|
|
|
|
|
|
name => 'valueOf', |
652
|
|
|
|
|
|
|
length => 0, |
653
|
|
|
|
|
|
|
function_args => ['this'], |
654
|
325
|
|
|
325
|
|
1010
|
function => sub { $_[0] }, |
655
|
106
|
|
|
|
|
1221
|
no_proto => 1, |
656
|
|
|
|
|
|
|
}), |
657
|
|
|
|
|
|
|
dontenum => 1, |
658
|
|
|
|
|
|
|
}); |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
$proto->prop({ |
661
|
|
|
|
|
|
|
name => 'hasOwnProperty', |
662
|
|
|
|
|
|
|
value => JE::Object::Function->new({ |
663
|
|
|
|
|
|
|
scope => $global, |
664
|
|
|
|
|
|
|
name => 'hasOwnProperty', |
665
|
|
|
|
|
|
|
argnames => ['V'], |
666
|
|
|
|
|
|
|
function_args => ['this', 'args'], |
667
|
|
|
|
|
|
|
function => sub { |
668
|
24
|
100
|
|
24
|
|
147
|
JE::Boolean->new($global, |
669
|
|
|
|
|
|
|
shift->exists( |
670
|
|
|
|
|
|
|
defined $_[0] ? $_[0] : 'undefined' |
671
|
|
|
|
|
|
|
) |
672
|
|
|
|
|
|
|
); |
673
|
|
|
|
|
|
|
}, |
674
|
106
|
|
|
|
|
1318
|
no_proto => 1, |
675
|
|
|
|
|
|
|
}), |
676
|
|
|
|
|
|
|
dontenum => 1, |
677
|
|
|
|
|
|
|
}); |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
$proto->prop({ |
680
|
|
|
|
|
|
|
name => 'isPrototypeOf', |
681
|
|
|
|
|
|
|
value => JE::Object::Function->new({ |
682
|
|
|
|
|
|
|
scope => $global, |
683
|
|
|
|
|
|
|
name => 'isPrototypeOf', |
684
|
|
|
|
|
|
|
argnames => ['V'], |
685
|
|
|
|
|
|
|
function_args => ['this', 'args'], |
686
|
|
|
|
|
|
|
function => sub { |
687
|
15
|
|
|
15
|
|
33
|
my ($self, $obj) = @_; |
688
|
|
|
|
|
|
|
|
689
|
15
|
100
|
100
|
|
|
102
|
!defined $obj || $obj->primitive and return |
690
|
|
|
|
|
|
|
JE::Boolean->new($global, 0); |
691
|
|
|
|
|
|
|
|
692
|
13
|
|
|
|
|
33
|
my $id = $self->id; |
693
|
13
|
|
|
|
|
31
|
my $proto = $obj; |
694
|
|
|
|
|
|
|
|
695
|
13
|
|
|
|
|
29
|
while (defined($proto = $proto->prototype)) |
696
|
|
|
|
|
|
|
{ |
697
|
13
|
100
|
|
|
|
28
|
$proto->id eq $id and return |
698
|
|
|
|
|
|
|
JE::Boolean->new($global, 1); |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
1
|
|
|
|
|
5
|
return JE::Boolean->new($global, 0); |
702
|
|
|
|
|
|
|
}, |
703
|
106
|
|
|
|
|
1576
|
no_proto => 1, |
704
|
|
|
|
|
|
|
}), |
705
|
|
|
|
|
|
|
dontenum => 1, |
706
|
|
|
|
|
|
|
}); |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
$proto->prop({ |
709
|
|
|
|
|
|
|
name => 'propertyIsEnumerable', |
710
|
|
|
|
|
|
|
value => JE::Object::Function->new({ |
711
|
|
|
|
|
|
|
scope => $global, |
712
|
|
|
|
|
|
|
name => 'propertyIsEnumerable', |
713
|
|
|
|
|
|
|
argnames => ['V'], |
714
|
|
|
|
|
|
|
function_args => ['this', 'args'], |
715
|
|
|
|
|
|
|
function => sub { |
716
|
222
|
100
|
|
222
|
|
1078
|
return JE::Boolean->new($global, |
717
|
|
|
|
|
|
|
shift->is_enum( |
718
|
|
|
|
|
|
|
defined $_[0] ? $_[0] : 'undefined' |
719
|
|
|
|
|
|
|
) |
720
|
|
|
|
|
|
|
); |
721
|
|
|
|
|
|
|
}, |
722
|
106
|
|
|
|
|
1337
|
no_proto => 1, |
723
|
|
|
|
|
|
|
}), |
724
|
|
|
|
|
|
|
dontenum => 1, |
725
|
|
|
|
|
|
|
}); |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
#----------- TYING MAGIC ---------------# |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
# I'm putting the object itself behind the tied hash, so that no new object |
733
|
|
|
|
|
|
|
# has to be created. |
734
|
|
|
|
|
|
|
# That means that tied %$obj returns $obj. |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
sub _get_tie { |
738
|
893
|
|
|
893
|
|
3886
|
my $self = shift; |
739
|
893
|
|
|
|
|
1010
|
my $guts = $$self; |
740
|
893
|
100
|
|
|
|
1747
|
$$guts{tie} or tie %{ $$guts{tie} }, __PACKAGE__, $self; |
|
761
|
|
|
|
|
2584
|
|
741
|
893
|
|
|
|
|
3600
|
$$guts{tie}; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
764
|
|
|
764
|
|
1380
|
sub TIEHASH { $_[1] } |
745
|
885
|
|
|
885
|
|
4914
|
sub FETCH { $_[0]->prop($_[1]) } |
746
|
|
|
|
|
|
|
sub STORE { |
747
|
735
|
|
|
735
|
|
1724
|
my($self, $key, $val) = @_; |
748
|
735
|
|
|
|
|
1195
|
my $global = $self->global; |
749
|
735
|
100
|
66
|
|
|
3861
|
if(ref $val eq 'HASH' && !blessed $val |
|
|
100
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
750
|
|
|
|
|
|
|
&& !%$val && svref_2object($val)->REFCNT == 2) { |
751
|
3
|
|
|
|
|
11
|
$val = tie %$val, __PACKAGE__, __PACKAGE__->new( |
752
|
|
|
|
|
|
|
$global); |
753
|
|
|
|
|
|
|
} elsif (ref $val eq 'ARRAY' && !blessed $val && !@$val && |
754
|
|
|
|
|
|
|
svref_2object($val)->REFCNT == 2) { |
755
|
3
|
|
|
|
|
21
|
require JE::Object::Array; |
756
|
3
|
|
|
|
|
19
|
$val = tie @$val, 'JE::Object::Array', |
757
|
|
|
|
|
|
|
JE::Object::Array->new($global); |
758
|
|
|
|
|
|
|
} |
759
|
735
|
|
|
|
|
1767
|
$self->prop($key => $global->upgrade($val)) |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
#sub CLEAR { } |
762
|
|
|
|
|
|
|
# ~~~ have yet to implement this |
763
|
|
|
|
|
|
|
sub DELETE { |
764
|
18
|
|
|
18
|
|
54
|
my $val = $_[0]->prop($_[1]); |
765
|
18
|
|
|
|
|
60
|
$_[0]->delete($_[1]); |
766
|
18
|
|
|
|
|
48
|
$val; |
767
|
|
|
|
|
|
|
} |
768
|
12
|
|
|
12
|
|
40
|
sub EXISTS { $_[0]->exists($_[1]) } |
769
|
11
|
|
|
11
|
|
40
|
sub FIRSTKEY { ($_[0]->keys)[0] } |
770
|
|
|
|
|
|
|
sub NEXTKEY { |
771
|
29
|
|
|
29
|
|
57
|
my @keys = $_[0]->keys; |
772
|
29
|
|
|
|
|
37
|
my $last = $_[1]; |
773
|
29
|
|
|
|
|
54
|
for (0..$#keys) { |
774
|
58
|
100
|
|
|
|
116
|
if ($last eq $keys[$_]) { |
775
|
29
|
|
|
|
|
141
|
return $keys[$_+1] |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
# ~~~ What *should* we do if the property has been |
780
|
|
|
|
|
|
|
# deleted? |
781
|
|
|
|
|
|
|
# I think this means the iterator should have been reset (from the |
782
|
|
|
|
|
|
|
# user's point of view), so we'll start from the beginning. |
783
|
|
|
|
|
|
|
|
784
|
0
|
|
|
|
|
|
return $keys[0]; |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
|
787
|
0
|
|
|
0
|
0
|
|
sub DDS_freeze { my $self = shift; delete $$$self{tie}; $self } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
#----------- THE REST OF THE DOCUMENTATION ---------------# |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
=head1 USING AN OBJECT AS A HASH |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
Note first of all that C<\%$obj> is I the same as C<< $obj->value >>. |
795
|
|
|
|
|
|
|
The C method creates a new hash containing just the enumerable |
796
|
|
|
|
|
|
|
properties of the object and its prototypes. It's just a plain hash--no |
797
|
|
|
|
|
|
|
ties, no magic. C<%$obj>, on the other hand, is another creature... |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
C<%$obj> returns a magic hash which only lists enumerable properties |
800
|
|
|
|
|
|
|
when you write C, but still provides access to the rest. |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
Using C on this hash will check to see whether it is the object's |
803
|
|
|
|
|
|
|
I property, and not a prototype's. |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
Assignment to the hash itself currently |
806
|
|
|
|
|
|
|
throws an error: |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
%$obj = (); # no good! |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
This is simply because I have not yet figured out what it should do. If |
811
|
|
|
|
|
|
|
anyone has any ideas, please let me know. |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
Autovivification works, so you can write |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
$obj->{a}{b} = 3; |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
and the 'a' element will be created if did not already exist. Note that, |
818
|
|
|
|
|
|
|
if the property C exist but was undefined (from JS's point of view), |
819
|
|
|
|
|
|
|
this throws an error. |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=begin paranoia |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
One potential problem with this is that, when perl autovivifies in the |
824
|
|
|
|
|
|
|
example |
825
|
|
|
|
|
|
|
above, it first calls C and, when it sees that the result is not |
826
|
|
|
|
|
|
|
defined, then calls C with C<{}> as the value. It then uses that |
827
|
|
|
|
|
|
|
same hash that it passed to C, and does I make a second call to |
828
|
|
|
|
|
|
|
C. This means that, for autovivification to work, the empty hash |
829
|
|
|
|
|
|
|
that perl automatically assigns has to be tied to the new JE::Object that |
830
|
|
|
|
|
|
|
is created. Now, the same sequence of calls to tie |
831
|
|
|
|
|
|
|
handlers can be triggered by the following lines: |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
my %h; |
834
|
|
|
|
|
|
|
$obj->{a}; |
835
|
|
|
|
|
|
|
$h{b} = 3; |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
And, of course, you don't want your %h hash transmogrified and tied to a |
838
|
|
|
|
|
|
|
JE::Object, do you? (Normally |
839
|
|
|
|
|
|
|
hashes and arrays are copied by STORE.) So the only feasible way (I can |
840
|
|
|
|
|
|
|
think of) to |
841
|
|
|
|
|
|
|
make the distinction is to use reference counts (which is what I'm using), |
842
|
|
|
|
|
|
|
but I don't know whether they will change |
843
|
|
|
|
|
|
|
between versions of Perl. |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
=end paranoia |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=head1 INNARDS |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
Each C instance is a blessed reference to a hash ref. The |
850
|
|
|
|
|
|
|
contents of the hash |
851
|
|
|
|
|
|
|
are as follows: |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
$$self->{global} a reference to the global object |
854
|
|
|
|
|
|
|
$$self->{props} a hash ref of properties, the values being |
855
|
|
|
|
|
|
|
JavaScript objects |
856
|
|
|
|
|
|
|
$$self->{prop_readonly} a hash ref with property names for the keys |
857
|
|
|
|
|
|
|
and booleans (that indicate whether prop- |
858
|
|
|
|
|
|
|
erties are read-only) for the values |
859
|
|
|
|
|
|
|
$$self->{prop_dontdel} a hash ref in the same format as |
860
|
|
|
|
|
|
|
prop_readonly that indicates whether proper- |
861
|
|
|
|
|
|
|
ties are undeletable |
862
|
|
|
|
|
|
|
$$self->{keys} an array of the names of enumerable |
863
|
|
|
|
|
|
|
properties |
864
|
|
|
|
|
|
|
$$self->{prototype} a reference to this object's prototype |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
In derived classes, if you need to store extra information, begin the hash |
867
|
|
|
|
|
|
|
keys with an underscore or use at least one capital letter in each key. |
868
|
|
|
|
|
|
|
Such keys |
869
|
|
|
|
|
|
|
will never be used by the |
870
|
|
|
|
|
|
|
classes that come with the JE distribution. |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=head1 SEE ALSO |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
L |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
L |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=cut |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
1; |
882
|
|
|
|
|
|
|
|