| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
1
|
|
|
1
|
|
97579
|
BEGIN { require 5.006 } |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package WWW::Scripter::Plugin::JavaScript::SpiderMonkey; |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
use# |
|
6
|
1
|
|
|
1
|
|
8
|
strict; use# |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
33
|
|
|
7
|
1
|
|
|
1
|
|
4
|
warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
75
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
5
|
use Carp 'croak'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
102
|
|
|
10
|
1
|
|
|
1
|
|
4
|
use Hash::Util::FieldHash::Compat 'fieldhash'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
12
|
|
|
11
|
1
|
|
|
1
|
|
58
|
use HTML::DOM::Interface ':all'; # for the constants |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
263
|
|
|
12
|
1
|
|
|
1
|
|
785
|
use JavaScript 1.12; # PerlSub type |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use Scalar::Util qw'weaken blessed '; |
|
14
|
|
|
|
|
|
|
use WWW'Scripter'Plugin'JavaScript 0.005; # back_end |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.003'; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
no constant 1.03 (); |
|
19
|
|
|
|
|
|
|
use constant::lexical { |
|
20
|
|
|
|
|
|
|
wndw => 0, |
|
21
|
|
|
|
|
|
|
cntx => 1, |
|
22
|
|
|
|
|
|
|
setr => 2, |
|
23
|
|
|
|
|
|
|
exst => 3, |
|
24
|
|
|
|
|
|
|
hash => 4, # whether a particular package needs a hash wrapper |
|
25
|
|
|
|
|
|
|
isam => 5, |
|
26
|
|
|
|
|
|
|
wrap => 6, # hash wrappers |
|
27
|
|
|
|
|
|
|
defs => 7, |
|
28
|
|
|
|
|
|
|
defg => 8, |
|
29
|
|
|
|
|
|
|
defm => 9, |
|
30
|
|
|
|
|
|
|
getr =>10, |
|
31
|
|
|
|
|
|
|
}; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $rt; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
fieldhash my %destructibles; |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub new { |
|
38
|
|
|
|
|
|
|
$rt ||= new JavaScript::Runtime; |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $class = shift; |
|
41
|
|
|
|
|
|
|
my $self = bless[], $class; |
|
42
|
|
|
|
|
|
|
$self->[wndw] = my $parathi = shift, |
|
43
|
|
|
|
|
|
|
$self->[cntx] = my $cx = $rt->create_context; |
|
44
|
|
|
|
|
|
|
$self->[hash] = {}; |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Weaken the reference to the WWW::Scripter object. Otherwise we |
|
47
|
|
|
|
|
|
|
# have a reference loop: |
|
48
|
|
|
|
|
|
|
# window -> js plugin -> sm back end -> window |
|
49
|
|
|
|
|
|
|
weaken $parathi; |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# cache $self so we can purge it in an END block |
|
52
|
|
|
|
|
|
|
weaken(my $weak_self = $self); |
|
53
|
|
|
|
|
|
|
$destructibles{$self} = \$weak_self; |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my @wrappers; |
|
56
|
|
|
|
|
|
|
@wrappers[BOOL,STR,OBJ] = @{ $cx->eval(' 0,function() { |
|
57
|
|
|
|
|
|
|
// for speed: |
|
58
|
|
|
|
|
|
|
frames = self = window = this |
|
59
|
|
|
|
|
|
|
return [ |
|
60
|
|
|
|
|
|
|
function(func_name) { |
|
61
|
|
|
|
|
|
|
var f = this[func_name] |
|
62
|
|
|
|
|
|
|
func_name = function() { |
|
63
|
|
|
|
|
|
|
return Boolean( |
|
64
|
|
|
|
|
|
|
f.apply(this, arguments) |
|
65
|
|
|
|
|
|
|
) |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
}, |
|
68
|
|
|
|
|
|
|
function(func_name) { |
|
69
|
|
|
|
|
|
|
var f = this[func_name] |
|
70
|
|
|
|
|
|
|
func_name = function() { |
|
71
|
|
|
|
|
|
|
var r = f.apply(this, arguments) |
|
72
|
|
|
|
|
|
|
return r === null || r === void 0 |
|
73
|
|
|
|
|
|
|
? null : Object(r) |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
}, |
|
76
|
|
|
|
|
|
|
function(func_name) { |
|
77
|
|
|
|
|
|
|
var f = this[func_name] |
|
78
|
|
|
|
|
|
|
func_name = function() { |
|
79
|
|
|
|
|
|
|
var r = f.apply(this, arguments) |
|
80
|
|
|
|
|
|
|
return r === null || r === void 0 |
|
81
|
|
|
|
|
|
|
? null : ""+r |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
}, |
|
84
|
|
|
|
|
|
|
] |
|
85
|
|
|
|
|
|
|
}() ') }; |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
my $i = \%WWW'Scripter'WindowInterface; |
|
89
|
|
|
|
|
|
|
my %methods; |
|
90
|
|
|
|
|
|
|
@methods{ grep !/^_/ && $$i{$_} & METHOD, =>=> keys %$i } = (); |
|
91
|
|
|
|
|
|
|
for(keys %methods) { |
|
92
|
|
|
|
|
|
|
my $method = $_; |
|
93
|
|
|
|
|
|
|
my $type = $$i{$_}&TYPE; |
|
94
|
|
|
|
|
|
|
if($type == NUM) { |
|
95
|
|
|
|
|
|
|
$cx->bind_function($_ => sub { |
|
96
|
|
|
|
|
|
|
0+$parathi->$method(@_); |
|
97
|
|
|
|
|
|
|
}); |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
else { |
|
100
|
|
|
|
|
|
|
$cx->bind_function($_ => sub { |
|
101
|
|
|
|
|
|
|
$parathi->$method(@_); |
|
102
|
|
|
|
|
|
|
}); |
|
103
|
|
|
|
|
|
|
$wrappers[$type]($_); |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
my $fetch = $cx->eval(' |
|
109
|
|
|
|
|
|
|
0,function(p,f){__defineGetter__(p, function(){return f()})} |
|
110
|
|
|
|
|
|
|
'); |
|
111
|
|
|
|
|
|
|
my $store = $cx->eval(' |
|
112
|
|
|
|
|
|
|
0,function(p,f){__defineSetter__(p, function(v){f(v)})} |
|
113
|
|
|
|
|
|
|
'); |
|
114
|
|
|
|
|
|
|
weaken(my $cself = $self); # for closures (not foreclosures) |
|
115
|
|
|
|
|
|
|
# ~~~ We still need to deal with type conversion. |
|
116
|
|
|
|
|
|
|
my %props; |
|
117
|
|
|
|
|
|
|
@props{ grep !/^_/ && !($$i{$_}&METHOD) =>=> keys %$i } = (); |
|
118
|
|
|
|
|
|
|
for(keys %props) { |
|
119
|
|
|
|
|
|
|
my $name = $_; |
|
120
|
|
|
|
|
|
|
next if $name =~ /^(?:frames|window|self)\z/; # for |
|
121
|
|
|
|
|
|
|
my $type = $$i{$_}&TYPE; # efficiency |
|
122
|
|
|
|
|
|
|
&$store($_ => sub { |
|
123
|
|
|
|
|
|
|
#my $self = shift; |
|
124
|
|
|
|
|
|
|
#$self->_cast( |
|
125
|
|
|
|
|
|
|
# scalar |
|
126
|
|
|
|
|
|
|
$self->[wndw]->$name, |
|
127
|
|
|
|
|
|
|
# $types[$type&TYPE] |
|
128
|
|
|
|
|
|
|
#); |
|
129
|
|
|
|
|
|
|
}); |
|
130
|
|
|
|
|
|
|
unless($type & READONLY) { |
|
131
|
|
|
|
|
|
|
&$fetch( $_ => sub { |
|
132
|
|
|
|
|
|
|
#my $self = shift; |
|
133
|
|
|
|
|
|
|
#$self->_cast( |
|
134
|
|
|
|
|
|
|
# scalar |
|
135
|
|
|
|
|
|
|
my $ret = $cself->[wndw]->$name; |
|
136
|
|
|
|
|
|
|
exists $cself->[hash]{ref $ret} |
|
137
|
|
|
|
|
|
|
? $cself->hash_wrapper($ret) |
|
138
|
|
|
|
|
|
|
: $ret; |
|
139
|
|
|
|
|
|
|
# $types[$type&TYPE] |
|
140
|
|
|
|
|
|
|
#); |
|
141
|
|
|
|
|
|
|
} ); |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
$self |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
END { # Empty any $selves *before* global destruction, to ensure that any |
|
149
|
|
|
|
|
|
|
for(values %destructibles) { # SM objects we reference go away before the |
|
150
|
|
|
|
|
|
|
# This line causes a crash in perl 5.8.8. It seems # runtime is freed. |
|
151
|
|
|
|
|
|
|
# that 5.8.8 has some bug in av_clear in that it can end |
|
152
|
|
|
|
|
|
|
# up trying to write to the xpvav struct after the array has |
|
153
|
|
|
|
|
|
|
# been freed. Since, when the array is freed, the sv_any pointer |
|
154
|
|
|
|
|
|
|
# (which usually points to the xpvav struct) points to another freed |
|
155
|
|
|
|
|
|
|
# sv, it causes a crash if that sv is used again. Or something like that. |
|
156
|
|
|
|
|
|
|
# I never did finish getting to the bottom of it. |
|
157
|
|
|
|
|
|
|
#@$$_ = (); |
|
158
|
|
|
|
|
|
|
undef $_ for @$$_; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub eval { |
|
163
|
|
|
|
|
|
|
my ($self,$code,$url,$line) = @_; |
|
164
|
|
|
|
|
|
|
defined $line and substr $code, 0, 0 =>= "\n" x ($line-1); |
|
165
|
|
|
|
|
|
|
$self->[cntx]->eval($code,$url) |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub set { |
|
169
|
|
|
|
|
|
|
croak "Not enough arguments for W:M:P:JS:SM->set" unless @_ > 2; |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
my $self = shift; |
|
172
|
|
|
|
|
|
|
my @args = @_; |
|
173
|
|
|
|
|
|
|
if(my $h = $self->[hash]) { |
|
174
|
|
|
|
|
|
|
for(@args){ |
|
175
|
|
|
|
|
|
|
defined blessed $_ or next; |
|
176
|
|
|
|
|
|
|
exists $$h{ref $_} and $_ = $self->hash_wrapper($_), |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
( $$self[setr] ||= $self->[cntx]->eval('0,function() { |
|
180
|
|
|
|
|
|
|
var a = arguments; |
|
181
|
|
|
|
|
|
|
var $obj = this; |
|
182
|
|
|
|
|
|
|
var $val = a[a.length-1]; |
|
183
|
|
|
|
|
|
|
var $prop = a[a.length-2]; |
|
184
|
|
|
|
|
|
|
for (var i = 0; i < a.length-2; ++i) { |
|
185
|
|
|
|
|
|
|
var $_ = a[i] |
|
186
|
|
|
|
|
|
|
$_ in $obj || ($obj[$_] = {}); |
|
187
|
|
|
|
|
|
|
$obj = $obj[$_]; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
$obj[$prop] = $val; |
|
190
|
|
|
|
|
|
|
}') ) |
|
191
|
|
|
|
|
|
|
->(@args); |
|
192
|
|
|
|
|
|
|
return; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub bind_classes { |
|
196
|
|
|
|
|
|
|
# ~~~ We still need to deal with type conversion and read-only props. |
|
197
|
|
|
|
|
|
|
my($self, $classes) = @_; |
|
198
|
|
|
|
|
|
|
weaken(my $cself = $self); # self for closures |
|
199
|
|
|
|
|
|
|
my $cx = $self->[cntx]; |
|
200
|
|
|
|
|
|
|
my $exists = $self->[exst] ||= $cx->eval('0,function(prop) { |
|
201
|
|
|
|
|
|
|
return prop in this |
|
202
|
|
|
|
|
|
|
}'); |
|
203
|
|
|
|
|
|
|
my @defer; |
|
204
|
|
|
|
|
|
|
my $isa_maker = $self->[isam] ||= $cx->eval(' |
|
205
|
|
|
|
|
|
|
0,function(class,super) { |
|
206
|
|
|
|
|
|
|
this[class].__proto__ = this[super] |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
'); |
|
209
|
|
|
|
|
|
|
my $define_setter = $self->[defs] ||= $cx->eval(' |
|
210
|
|
|
|
|
|
|
0,function(class,prop,sub) { |
|
211
|
|
|
|
|
|
|
this[class].prototype.__defineSetter__( |
|
212
|
|
|
|
|
|
|
prop, |
|
213
|
|
|
|
|
|
|
function(v) { |
|
214
|
|
|
|
|
|
|
sub(this, v) |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
) |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
'); |
|
219
|
|
|
|
|
|
|
my $define_string_getter = $self->[defg] ||= $cx->eval(' |
|
220
|
|
|
|
|
|
|
0,function(class,prop,sub) { |
|
221
|
|
|
|
|
|
|
this[class].prototype.__defineGetter__( |
|
222
|
|
|
|
|
|
|
prop, |
|
223
|
|
|
|
|
|
|
function() { |
|
224
|
|
|
|
|
|
|
var ret = sub(this) |
|
225
|
|
|
|
|
|
|
return( |
|
226
|
|
|
|
|
|
|
typeof ret == "undefined" ? null : String(ret) |
|
227
|
|
|
|
|
|
|
); |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
) |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
'); |
|
232
|
|
|
|
|
|
|
my $define_string_meth = $self->[defm] ||= $cx->eval(' |
|
233
|
|
|
|
|
|
|
0,function(class,prop,sub) { |
|
234
|
|
|
|
|
|
|
this[class].prototype[prop] = function() { |
|
235
|
|
|
|
|
|
|
var ret = sub.apply(this,arguments); |
|
236
|
|
|
|
|
|
|
return( |
|
237
|
|
|
|
|
|
|
typeof ret == "undefined" ? null : String(ret) |
|
238
|
|
|
|
|
|
|
); |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
'); |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
for (grep /::/, keys %$classes) { |
|
245
|
|
|
|
|
|
|
my $i = $$classes{$$classes{$_}}; # interface info |
|
246
|
|
|
|
|
|
|
if($$i{_hash} || $$i{_array}) { # **Shudder!** |
|
247
|
|
|
|
|
|
|
my %props; |
|
248
|
|
|
|
|
|
|
my %methods; |
|
249
|
|
|
|
|
|
|
{ |
|
250
|
|
|
|
|
|
|
my $i = $i; |
|
251
|
|
|
|
|
|
|
while() { |
|
252
|
|
|
|
|
|
|
$props{$_} = undef |
|
253
|
|
|
|
|
|
|
for grep !/^_/ && !($$i{$_} & METHOD),keys %$i; |
|
254
|
|
|
|
|
|
|
$methods{$_} = undef |
|
255
|
|
|
|
|
|
|
for grep !/^_/ && $$i{$_} & METHOD, keys %$i; |
|
256
|
|
|
|
|
|
|
exists $$i{_isa} || last; |
|
257
|
|
|
|
|
|
|
$i = $$classes{$$i{_isa}}; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
$self->[hash]{$_} = [ |
|
261
|
|
|
|
|
|
|
@$i{'_array','_hash'},\%props,\%methods |
|
262
|
|
|
|
|
|
|
]; |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
else { |
|
265
|
|
|
|
|
|
|
my @props = grep !/^_/ && !($$i{$_} & METHOD), keys %$i; |
|
266
|
|
|
|
|
|
|
my @str_props; |
|
267
|
|
|
|
|
|
|
my @str_meths; |
|
268
|
|
|
|
|
|
|
$cx->bind_class( |
|
269
|
|
|
|
|
|
|
package => $_, |
|
270
|
|
|
|
|
|
|
name => $$classes{$_}, |
|
271
|
|
|
|
|
|
|
methods => { map { |
|
272
|
|
|
|
|
|
|
if(($$i{$_} & TYPE) == STR) { |
|
273
|
|
|
|
|
|
|
push @str_meths, $_; |
|
274
|
|
|
|
|
|
|
() |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
else { |
|
277
|
|
|
|
|
|
|
my $method = $_; |
|
278
|
|
|
|
|
|
|
$_ => sub { |
|
279
|
|
|
|
|
|
|
my $self = shift; |
|
280
|
|
|
|
|
|
|
my $ret = $self->$method(@_); |
|
281
|
|
|
|
|
|
|
exists $cself->[hash]{ref $ret} |
|
282
|
|
|
|
|
|
|
? $cself->hash_wrapper($ret) |
|
283
|
|
|
|
|
|
|
: $ret |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
} grep !/^_/ && $$i{$_} & METHOD, keys %$i }, |
|
287
|
|
|
|
|
|
|
properties => { map { |
|
288
|
|
|
|
|
|
|
if(($$i{$_} & TYPE) == STR) { |
|
289
|
|
|
|
|
|
|
push @str_props, $_; |
|
290
|
|
|
|
|
|
|
() |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
else { |
|
293
|
|
|
|
|
|
|
my $prop = $_; |
|
294
|
|
|
|
|
|
|
$_ => [ |
|
295
|
|
|
|
|
|
|
sub { |
|
296
|
|
|
|
|
|
|
my $self = shift; |
|
297
|
|
|
|
|
|
|
my $ret = $self->$prop; |
|
298
|
|
|
|
|
|
|
exists $cself->[hash]{ref $ret} |
|
299
|
|
|
|
|
|
|
? $cself->hash_wrapper($ret) |
|
300
|
|
|
|
|
|
|
: $ret |
|
301
|
|
|
|
|
|
|
}, |
|
302
|
|
|
|
|
|
|
sub { |
|
303
|
|
|
|
|
|
|
# my $self = shift; |
|
304
|
|
|
|
|
|
|
# my $ret = $self->$prop(@_); |
|
305
|
|
|
|
|
|
|
# return; |
|
306
|
|
|
|
|
|
|
}, |
|
307
|
|
|
|
|
|
|
] |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
} @props }, |
|
310
|
|
|
|
|
|
|
exists $$i{_constructor} |
|
311
|
|
|
|
|
|
|
? (constructor => $$i{_constructor}) |
|
312
|
|
|
|
|
|
|
: (flags => JS_CLASS_NO_INSTANCE), |
|
313
|
|
|
|
|
|
|
); |
|
314
|
|
|
|
|
|
|
for my $p(@props) { |
|
315
|
|
|
|
|
|
|
&$define_setter($$classes{$_}, $p, sub { |
|
316
|
|
|
|
|
|
|
shift->$p(@_); return |
|
317
|
|
|
|
|
|
|
}); |
|
318
|
|
|
|
|
|
|
} |
|
319
|
|
|
|
|
|
|
for my $p(@str_props) { |
|
320
|
|
|
|
|
|
|
&$define_string_getter($$classes{$_}, $p, sub { |
|
321
|
|
|
|
|
|
|
shift->$p(@_); |
|
322
|
|
|
|
|
|
|
}); |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
for my $p(@str_meths) { |
|
325
|
|
|
|
|
|
|
&$define_string_meth($$classes{$_}, $p, sub { |
|
326
|
|
|
|
|
|
|
shift->$p(@_); |
|
327
|
|
|
|
|
|
|
}); |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
if(exists $$i{_constants}){ |
|
332
|
|
|
|
|
|
|
my $p = $_; |
|
333
|
|
|
|
|
|
|
for(@{$$i{_constants}}){ |
|
334
|
|
|
|
|
|
|
/([^:]+\z)/; |
|
335
|
|
|
|
|
|
|
$self->set($$classes{$p}, $1, eval); |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
} |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
if (exists $$i{_isa}) { |
|
340
|
|
|
|
|
|
|
if(!&$exists($$i{_isa})) { |
|
341
|
|
|
|
|
|
|
push @defer, [$$classes{$_}, $$i{_isa}] |
|
342
|
|
|
|
|
|
|
} else { |
|
343
|
|
|
|
|
|
|
$isa_maker->($$classes{$_}, $$i{_isa}); |
|
344
|
|
|
|
|
|
|
} |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
while(@defer) { |
|
348
|
|
|
|
|
|
|
my @copy = @defer; |
|
349
|
|
|
|
|
|
|
@defer = (); |
|
350
|
|
|
|
|
|
|
for (@copy) { |
|
351
|
|
|
|
|
|
|
if(&$exists($$_[1])) { # $$_[1] == superclass |
|
352
|
|
|
|
|
|
|
$isa_maker->(@$_); |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
else { |
|
355
|
|
|
|
|
|
|
push @defer, $_; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
} |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
return; |
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub event2sub { |
|
364
|
|
|
|
|
|
|
my ($self, $code, $elem, $url, $line) = @_; |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# We create a function with a specific scope chain by generating |
|
367
|
|
|
|
|
|
|
# and calling code like this: |
|
368
|
|
|
|
|
|
|
# (function() { |
|
369
|
|
|
|
|
|
|
# with(arguments[0])with(arguments[1])with(arguments[2]) |
|
370
|
|
|
|
|
|
|
# return function() { ... } |
|
371
|
|
|
|
|
|
|
# }) |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# The global object is automatically in the scope, so we don’t need |
|
374
|
|
|
|
|
|
|
# to add it explicitly. |
|
375
|
|
|
|
|
|
|
my @scope = ( |
|
376
|
|
|
|
|
|
|
$elem->can('form') ? $elem->form : (), |
|
377
|
|
|
|
|
|
|
$elem |
|
378
|
|
|
|
|
|
|
); |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# We need the line break after $code, because there may be a sin- |
|
381
|
|
|
|
|
|
|
# gle-line comment at the end, and no line break. ("foo //bar" |
|
382
|
|
|
|
|
|
|
# would fail without this, because the closing }}) would be com- |
|
383
|
|
|
|
|
|
|
# mented out too.) |
|
384
|
|
|
|
|
|
|
($self->[cntx]->eval( |
|
385
|
|
|
|
|
|
|
"\n" x($line-1) . "(function(){" |
|
386
|
|
|
|
|
|
|
. (join '', map "with(arguments[$_])", 0..$#scope) |
|
387
|
|
|
|
|
|
|
. "return function() { $code\n } })", |
|
388
|
|
|
|
|
|
|
$url |
|
389
|
|
|
|
|
|
|
)||return) -> ( @scope ); |
|
390
|
|
|
|
|
|
|
} |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub new_function { |
|
393
|
|
|
|
|
|
|
my($self, $name, $sub) = @_; |
|
394
|
|
|
|
|
|
|
$self->set($name,$sub); |
|
395
|
|
|
|
|
|
|
return; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
sub hash_wrapper { |
|
399
|
|
|
|
|
|
|
my $self = shift; |
|
400
|
|
|
|
|
|
|
my $w = $self->[wrap] ||= &fieldhash({}); |
|
401
|
|
|
|
|
|
|
my $obj = shift; |
|
402
|
|
|
|
|
|
|
$w->{$obj} ||= do { |
|
403
|
|
|
|
|
|
|
my $wrapper = new JavaScript::PerlHash; |
|
404
|
|
|
|
|
|
|
# WWW::Scripter is the special case |
|
405
|
|
|
|
|
|
|
if(ref $obj eq 'WWW::Scripter') { |
|
406
|
|
|
|
|
|
|
tie |
|
407
|
|
|
|
|
|
|
%{get_ref $wrapper}, |
|
408
|
|
|
|
|
|
|
__PACKAGE__.'::WindowProxy', |
|
409
|
|
|
|
|
|
|
$obj; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
else { |
|
412
|
|
|
|
|
|
|
my $binding_info = $self->[hash]{ref $obj}; |
|
413
|
|
|
|
|
|
|
tie |
|
414
|
|
|
|
|
|
|
%{$wrapper->get_ref}, |
|
415
|
|
|
|
|
|
|
__PACKAGE__.'::Hash', |
|
416
|
|
|
|
|
|
|
$obj, @$binding_info, $self; |
|
417
|
|
|
|
|
|
|
} |
|
418
|
|
|
|
|
|
|
$wrapper; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
sub _hash_classes { shift->[hash] } |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
package WWW::Scripter::Plugin::JavaScript::SpiderMonkey::WindowProxy; |
|
426
|
|
|
|
|
|
|
# Is this package name long enough? |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
sub TIEHASH { |
|
429
|
|
|
|
|
|
|
# Slot 0 is the WWW::Scripter object. Slot 1 is used to catch the |
|
430
|
|
|
|
|
|
|
# fetching function. |
|
431
|
|
|
|
|
|
|
bless [pop], shift; |
|
432
|
|
|
|
|
|
|
} |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
sub STORE { |
|
435
|
|
|
|
|
|
|
my $w = ${;shift}[0]; |
|
436
|
|
|
|
|
|
|
$w->plugin("JavaScript")->back_end($w)->set(shift, shift); |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub CLEAR{} |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub FETCH { |
|
442
|
|
|
|
|
|
|
my $self = shift; |
|
443
|
|
|
|
|
|
|
my $w = $$self[0]; |
|
444
|
|
|
|
|
|
|
( |
|
445
|
|
|
|
|
|
|
$$self[1] |
|
446
|
|
|
|
|
|
|
||= $w->plugin("JavaScript")->back_end($w)->eval( |
|
447
|
|
|
|
|
|
|
'0,function(k){ return this[k] }' |
|
448
|
|
|
|
|
|
|
) |
|
449
|
|
|
|
|
|
|
)->(shift) |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
package WWW::Scripter::Plugin::JavaScript::SpiderMonkey::Hash; |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
use constant::lexical { |
|
456
|
|
|
|
|
|
|
obje => 0, arry => 1, hash => 2, prop => 3, meth => 4, jsbe => 5, |
|
457
|
|
|
|
|
|
|
}; |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub TIEHASH { |
|
460
|
|
|
|
|
|
|
# args: 0) object to wrap |
|
461
|
|
|
|
|
|
|
# 1) array? |
|
462
|
|
|
|
|
|
|
# 2) hash? |
|
463
|
|
|
|
|
|
|
# 3) { props } |
|
464
|
|
|
|
|
|
|
# 4) { methods } |
|
465
|
|
|
|
|
|
|
# 5) JavaScript back end (wspjssm object) |
|
466
|
|
|
|
|
|
|
my $ret = bless \@_, shift; |
|
467
|
|
|
|
|
|
|
# warn "wrapping up a " . ref($obj) . " object with props [ @{$ret->[prop]} ]"; |
|
468
|
|
|
|
|
|
|
Scalar::Util'weaken($ret->[jsbe]); |
|
469
|
|
|
|
|
|
|
$ret; |
|
470
|
|
|
|
|
|
|
} |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub STORE { |
|
473
|
|
|
|
|
|
|
my $self = shift; |
|
474
|
|
|
|
|
|
|
my $name = shift; |
|
475
|
|
|
|
|
|
|
exists $self->[prop]{$name} and $self->[obje]->$name(shift), return; |
|
476
|
|
|
|
|
|
|
exists $self->[meth]{$name} and return; |
|
477
|
|
|
|
|
|
|
$self->[arry] && $name =~ /^(?:0|[1-9]\d*)\z/ && $name < 4294967295 |
|
478
|
|
|
|
|
|
|
? $self->[obje][$name]=shift |
|
479
|
|
|
|
|
|
|
:($self->[obje]{$name}=shift); |
|
480
|
|
|
|
|
|
|
} |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub CLEAR{} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
sub FETCH { |
|
485
|
|
|
|
|
|
|
my $self = shift; |
|
486
|
|
|
|
|
|
|
my $name = shift; |
|
487
|
|
|
|
|
|
|
my $ret = |
|
488
|
|
|
|
|
|
|
exists $self->[prop]{$name} ? $self->[obje]->$name : |
|
489
|
|
|
|
|
|
|
exists $self->[meth]{$name} ? return sub { $self->[obje]->$name(@_) } : |
|
490
|
|
|
|
|
|
|
$self->[arry] && $name =~ /^(?:0|[1-9]\d*)\z/ && $name < 4294967295 |
|
491
|
|
|
|
|
|
|
? $self->[obje][$name] |
|
492
|
|
|
|
|
|
|
: $self->[obje]{$name}; |
|
493
|
|
|
|
|
|
|
exists $self->[jsbe]->_hash_classes->{ref $ret} |
|
494
|
|
|
|
|
|
|
? $self->[jsbe]->hash_wrapper($ret) |
|
495
|
|
|
|
|
|
|
: $ret; |
|
496
|
|
|
|
|
|
|
} |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
exit exit exit exit exit exit exit exit exit exit exit exit exit return 1; |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# ------------------ DOCS --------------------# |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=head1 NAME |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
WWW::Scripter::Plugin::JavaScript::SpiderMonkey - SpiderMonkey backend for wspjs |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=head1 VERSION |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
0.003 (alpha) |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
use WWW::Scripter; |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
my $w = new WWW::Scripter; |
|
518
|
|
|
|
|
|
|
$w->use_plugin('JavaScript', engine => 'SpiderMonkey'); |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
$w->get("http://..."); |
|
521
|
|
|
|
|
|
|
# etc. |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
This little module is a bit of duct tape to connect the JavaScript plugin |
|
526
|
|
|
|
|
|
|
for L to the SpiderMonkey JavaScript engine via |
|
527
|
|
|
|
|
|
|
L. Don't use this module |
|
528
|
|
|
|
|
|
|
directly. For usage, see |
|
529
|
|
|
|
|
|
|
L. |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=head1 BUGS |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
There are too many to list! This thing is currently very unstable, to put |
|
534
|
|
|
|
|
|
|
it mildly. |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
If you find any bugs, please report them via L |
|
537
|
|
|
|
|
|
|
or |
|
538
|
|
|
|
|
|
|
L (long e-mail |
|
539
|
|
|
|
|
|
|
address, isn't it?). |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head1 SINE QUIBUS NON |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
perl 5.8.3 or higher (5.8.6 or higher recommended) |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
HTML::DOM 0.008 or later |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
JavaScript.pm 1.12 or later |
|
548
|
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
Hash::Util::FieldHash::Compat |
|
550
|
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
constant::lexical |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=head1 AUTHOR & COPYRIGHT |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
Copyright (C) 2010-11, Father Chrysostomos (org.cpan@sprout backwards) |
|
556
|
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
This program is free software; you may redistribute it, modify it or |
|
558
|
|
|
|
|
|
|
both under the same terms as perl. |
|
559
|
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=over 4 |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=item - |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
L |
|
567
|
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=item - |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
L |