envjs 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/envjsrb +0 -1
- data/lib/envjs/env.js +1240 -24047
- data/lib/envjs/event_loop.js +204 -0
- data/lib/envjs/runtime.rb +123 -45
- data/lib/envjs/static.js +22482 -0
- data/lib/envjs.rb +10 -0
- data/test/unit/iframe.js +1 -1
- data/test/unit/parser.js +2 -1
- metadata +24 -11
- data/test/call-load-test.js.smp +0 -14
@@ -0,0 +1,204 @@
|
|
1
|
+
(function(){
|
2
|
+
if ($master.eventLoop) {
|
3
|
+
throw new Error("event loop multiply defined");
|
4
|
+
}
|
5
|
+
var el = $master.eventLoop = {};
|
6
|
+
|
7
|
+
var $env = {};
|
8
|
+
$env.sync = function(f){return f;};
|
9
|
+
$env.error = function(s){
|
10
|
+
print("timer error: "+s);
|
11
|
+
if (s.stack) {
|
12
|
+
print("timer error: "+s.stack);
|
13
|
+
}
|
14
|
+
};
|
15
|
+
$env.sleep = function(t){ Ruby.sleep(t/1000.); };
|
16
|
+
|
17
|
+
var $timers = [];
|
18
|
+
var $event_loop_running = false;
|
19
|
+
$timers.lock = $env.sync(function(fn){fn();});
|
20
|
+
|
21
|
+
var $timer = function(w, fn, interval){
|
22
|
+
this.w = w;
|
23
|
+
this.fn = fn;
|
24
|
+
this.interval = interval;
|
25
|
+
this.at = Date.now() + interval;
|
26
|
+
this.running = false; // allows for calling wait() from callbacks
|
27
|
+
};
|
28
|
+
|
29
|
+
var convert_time = function(time) {
|
30
|
+
time = time*1;
|
31
|
+
if ( isNaN(time) || time < 0 ) {
|
32
|
+
time = 0;
|
33
|
+
}
|
34
|
+
// html5 says this should be at least 4, but the parser is using a setTimeout for the SAX stuff
|
35
|
+
// which messes up the world
|
36
|
+
var min = /* 4 */ 0;
|
37
|
+
if ( $event_loop_running && time < min ) {
|
38
|
+
time = min;
|
39
|
+
}
|
40
|
+
return time;
|
41
|
+
};
|
42
|
+
|
43
|
+
var enter_and_exec = function(w,fn) {
|
44
|
+
|
45
|
+
};
|
46
|
+
|
47
|
+
el.setTimeout = function(w, fn, time){
|
48
|
+
var num;
|
49
|
+
time = convert_time(time);
|
50
|
+
$timers.lock(function(){
|
51
|
+
num = $timers.length+1;
|
52
|
+
var tfn;
|
53
|
+
if (typeof fn == 'string') {
|
54
|
+
tfn = function() {
|
55
|
+
try {
|
56
|
+
eval(fn);
|
57
|
+
} catch (e) {
|
58
|
+
$env.error(e);
|
59
|
+
} finally {
|
60
|
+
el.clearInterval(num);
|
61
|
+
}
|
62
|
+
};
|
63
|
+
} else {
|
64
|
+
tfn = function() {
|
65
|
+
try {
|
66
|
+
fn();
|
67
|
+
} catch (e) {
|
68
|
+
$env.error(e);
|
69
|
+
} finally {
|
70
|
+
el.clearInterval(num);
|
71
|
+
}
|
72
|
+
};
|
73
|
+
}
|
74
|
+
$timers[num] = new $timer(w, tfn, time);
|
75
|
+
});
|
76
|
+
return num;
|
77
|
+
};
|
78
|
+
|
79
|
+
el.setInterval = function(w, fn, time){
|
80
|
+
time = convert_time(time);
|
81
|
+
if ( time < 10 ) {
|
82
|
+
time = 10;
|
83
|
+
}
|
84
|
+
if (typeof fn == 'string') {
|
85
|
+
var fnstr = fn;
|
86
|
+
fn = function() {
|
87
|
+
eval(fnstr);
|
88
|
+
};
|
89
|
+
}
|
90
|
+
var num;
|
91
|
+
$timers.lock(function(){
|
92
|
+
num = $timers.length+1;
|
93
|
+
$timers[num] = new $timer(w, fn, time);
|
94
|
+
});
|
95
|
+
return num;
|
96
|
+
};
|
97
|
+
|
98
|
+
el.clear = el.clearInterval = el.clearTimeout = function(num){
|
99
|
+
//$log("clearing interval "+num);
|
100
|
+
$timers.lock(function(){
|
101
|
+
if ( $timers[num] ) {
|
102
|
+
delete $timers[num];
|
103
|
+
}
|
104
|
+
});
|
105
|
+
};
|
106
|
+
|
107
|
+
// wait === null/undefined: execute any timers as they fire, waiting until there are none left
|
108
|
+
// wait(n) (n > 0): execute any timers as they fire until there are none left waiting at least n ms
|
109
|
+
// but no more, even if there are future events/current threads
|
110
|
+
// wait(0): execute any immediately runnable timers and return
|
111
|
+
// wait(-n): keep sleeping until the next event is more than n ms in the future
|
112
|
+
|
113
|
+
// FIX: make a priority queue ...
|
114
|
+
|
115
|
+
el.wait = function(wait) {
|
116
|
+
// print("wait",wait,$event_loop_running);
|
117
|
+
var fired = false;
|
118
|
+
var delta_wait;
|
119
|
+
if (wait < 0) {
|
120
|
+
delta_wait = -wait;
|
121
|
+
wait = 0;
|
122
|
+
}
|
123
|
+
var start = Date.now();
|
124
|
+
var old_loop_running = $event_loop_running;
|
125
|
+
$event_loop_running = true;
|
126
|
+
if (wait !== 0 && wait !== null && wait !== undefined){
|
127
|
+
wait += Date.now();
|
128
|
+
}
|
129
|
+
for (;;) {
|
130
|
+
var earliest;
|
131
|
+
$timers.lock(function(){
|
132
|
+
earliest = undefined;
|
133
|
+
for(var i in $timers){
|
134
|
+
if( isNaN(i*0) ) {
|
135
|
+
continue;
|
136
|
+
}
|
137
|
+
var timer = $timers[i];
|
138
|
+
if( !timer.running && ( !earliest || timer.at < earliest.at) ) {
|
139
|
+
earliest = timer;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
});
|
143
|
+
var sleep = earliest && earliest.at - Date.now();
|
144
|
+
if ( earliest && sleep <= 0 ) {
|
145
|
+
var f = earliest.fn;
|
146
|
+
var previous = $master.first_script_window;
|
147
|
+
fired = true;
|
148
|
+
try {
|
149
|
+
earliest.running = true;
|
150
|
+
$master.first_script_window = earliest.w;
|
151
|
+
f();
|
152
|
+
} catch (e) {
|
153
|
+
$env.error(e);
|
154
|
+
} finally {
|
155
|
+
earliest.running = false;
|
156
|
+
$master.first_script_window = previous;
|
157
|
+
}
|
158
|
+
var goal = earliest.at + earliest.interval;
|
159
|
+
var now = Date.now();
|
160
|
+
if ( goal < now ) {
|
161
|
+
earliest.at = now;
|
162
|
+
} else {
|
163
|
+
earliest.at = goal;
|
164
|
+
}
|
165
|
+
continue;
|
166
|
+
}
|
167
|
+
|
168
|
+
// bunch of subtle cases here ...
|
169
|
+
if ( !earliest ) {
|
170
|
+
// no events in the queue (but maybe XHR will bring in events, so ...
|
171
|
+
if ( !wait || wait < Date.now() ) {
|
172
|
+
// Loop ends if there are no events and a wait hasn't been requested or has expired
|
173
|
+
break;
|
174
|
+
}
|
175
|
+
// no events, but a wait requested: fall through to sleep
|
176
|
+
} else {
|
177
|
+
// there are events in the queue, but they aren't firable now
|
178
|
+
// print(delta_wait,sleep);
|
179
|
+
if ( delta_wait && sleep <= delta_wait ) {
|
180
|
+
// if they will happen within the next delta, fall through to sleep
|
181
|
+
} else if ( wait === 0 || ( wait > 0 && wait < Date.now () ) ) {
|
182
|
+
// loop ends even if there are events but the user specifcally asked not to wait too long
|
183
|
+
break;
|
184
|
+
}
|
185
|
+
// there are events and the user wants to wait: fall through to sleep
|
186
|
+
}
|
187
|
+
|
188
|
+
// Related to ajax threads ... hopefully can go away ..
|
189
|
+
var interval = el.wait.interval || 100;
|
190
|
+
if ( !sleep || sleep > interval ) {
|
191
|
+
sleep = interval;
|
192
|
+
}
|
193
|
+
// the parser sets the timeout at 1 ... the chances of us getting back through this loop in that amount of time
|
194
|
+
// are small, no need to both the driver for something so small; just spin
|
195
|
+
if (sleep>1) {
|
196
|
+
$env.sleep(sleep);
|
197
|
+
}
|
198
|
+
}
|
199
|
+
$event_loop_running = old_loop_running;
|
200
|
+
// print("unwait",earliest,sleep);
|
201
|
+
return [ fired, earliest && sleep ];
|
202
|
+
};
|
203
|
+
|
204
|
+
}());
|
data/lib/envjs/runtime.rb
CHANGED
@@ -11,7 +11,59 @@ module Envjs::Runtime
|
|
11
11
|
def self.extended object
|
12
12
|
object.instance_eval do
|
13
13
|
|
14
|
-
|
14
|
+
outer = nil
|
15
|
+
scripts = {}
|
16
|
+
|
17
|
+
master = global["$master"] = evaluate("new Object", nil, nil, nil, global)
|
18
|
+
|
19
|
+
( class << self; self; end ).send :define_method, :master do
|
20
|
+
master
|
21
|
+
end
|
22
|
+
|
23
|
+
( class << self; self; end ).send :define_method, :evaluate do |*args|
|
24
|
+
( script, file, line, global, scope, fn ) = *args
|
25
|
+
scope ||= outer["$inner"]
|
26
|
+
raise "cannot evaluate nil script" if script.nil?
|
27
|
+
raise "cannot evaluate without a scope" if scope.nil?
|
28
|
+
raise "outer given when inner needed" if !scope == global and !scope["isInner"]
|
29
|
+
# print "eval in " + script[0,50].inspect + scope.inspect + " " + ( scope ? scope.isInner.inspect : "none" ) + "\n"
|
30
|
+
global = nil
|
31
|
+
# scope ||= inner
|
32
|
+
if fn
|
33
|
+
compiled_script = scripts[fn]
|
34
|
+
end
|
35
|
+
compiled_script ||= compile(script, file, line, global)
|
36
|
+
raise "hell" if !compiled_script
|
37
|
+
if fn && !scripts[fn]
|
38
|
+
scripts[fn] = compiled_script
|
39
|
+
end
|
40
|
+
save = master["first_script_window"]
|
41
|
+
if false
|
42
|
+
p scope
|
43
|
+
if master["first_script_window"]
|
44
|
+
print "ignored: " + ( scope["location"] ? scope["location"]["href"] : "nil" ) + " using " + ( master["first_script_window"]["location"] ? master["first_script_window"]["location"]["href"] : "nil" ) + "\n"
|
45
|
+
else
|
46
|
+
print "pushing into " + ( scope["location"] ? scope["location"]["href"] : "nil" ) + "\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
master["first_script_window"] ||= scope
|
51
|
+
raise "hell" if !master["first_script_window"]["isInner"] && master["first_script_window"] != self.global
|
52
|
+
v = nil
|
53
|
+
begin
|
54
|
+
v = evaluate_compiled_script(compiled_script,scope)
|
55
|
+
# p "pe", v, compiled_script, scope
|
56
|
+
rescue Exception => e
|
57
|
+
# p "oopsrt", e
|
58
|
+
raise e
|
59
|
+
ensure
|
60
|
+
master["first_script_window"] = save
|
61
|
+
end
|
62
|
+
# print "done\n"
|
63
|
+
v
|
64
|
+
end
|
65
|
+
|
66
|
+
evaluate( <<'EOJS', nil, nil, nil, global )
|
15
67
|
print = function() {
|
16
68
|
var l = arguments.length
|
17
69
|
for( var i = 0; i < l; i++ ) {
|
@@ -33,7 +85,7 @@ print = function() {
|
|
33
85
|
};
|
34
86
|
EOJS
|
35
87
|
|
36
|
-
evaluate <<'EOJS'
|
88
|
+
evaluate <<'EOJS', nil, nil, nil, global
|
37
89
|
debug = function() {
|
38
90
|
var l = arguments.length
|
39
91
|
for( var i = 0; i < l; i++ ) {
|
@@ -54,7 +106,7 @@ debug = function() {
|
|
54
106
|
};
|
55
107
|
EOJS
|
56
108
|
|
57
|
-
evaluate <<'EOJS'
|
109
|
+
evaluate <<'EOJS', nil, nil, nil, global
|
58
110
|
puts = function() {
|
59
111
|
var l = arguments.length
|
60
112
|
for( var i = 0; i < l; i++ ) {
|
@@ -72,10 +124,15 @@ puts = function() {
|
|
72
124
|
};
|
73
125
|
EOJS
|
74
126
|
|
75
|
-
master = global["$master"] = evaluate("new Object")
|
76
127
|
master["runtime"] = self
|
77
|
-
|
128
|
+
window_index = -1
|
129
|
+
master["next_window_index"] = lambda { window_index += 1 }
|
130
|
+
master.symbols = [ "Johnson", "Ruby", "print", "debug", "puts", "load", "reload", "whichInterpreter", "multiwindow", "seal" ]
|
78
131
|
master.symbols.each { |symbol| master[symbol] = global[symbol] }
|
132
|
+
master["seal"] = lambda do |*args|
|
133
|
+
object, deep = *args
|
134
|
+
seal object, deep
|
135
|
+
end
|
79
136
|
|
80
137
|
master.whichInterpreter = "Johnson"
|
81
138
|
|
@@ -180,8 +237,10 @@ EOJS
|
|
180
237
|
|
181
238
|
master.load = lambda { |*files|
|
182
239
|
if files.length == 2 && !(String === files[1])
|
240
|
+
# now = Time.now
|
183
241
|
f = files[0]
|
184
242
|
w = files[1]
|
243
|
+
# p "load", f, w
|
185
244
|
|
186
245
|
# Hmmm ...
|
187
246
|
uri = URI.parse f
|
@@ -206,6 +265,7 @@ EOJS
|
|
206
265
|
loc = nil
|
207
266
|
add_dep.call w, f
|
208
267
|
evaluate(v, f, 1, w, w, f)
|
268
|
+
# print "load #{uri_s}: #{Time.now-now}\n"
|
209
269
|
else
|
210
270
|
load *files
|
211
271
|
end
|
@@ -265,63 +325,43 @@ EOJS
|
|
265
325
|
# create an proto window object and proxy
|
266
326
|
|
267
327
|
outer = new_split_global_outer
|
268
|
-
|
328
|
+
inner = new_split_global_inner( outer )
|
269
329
|
|
270
330
|
master.symbols.each do |symbol|
|
271
|
-
|
331
|
+
inner[symbol] = master[symbol]
|
272
332
|
end
|
273
333
|
|
274
|
-
|
334
|
+
inner["$inner"] = inner
|
335
|
+
inner["$master"] = master
|
336
|
+
inner["$options"] = evaluate("new Object", nil, nil, nil, inner);
|
337
|
+
inner["$options"].proxy = outer
|
275
338
|
|
276
|
-
|
277
|
-
|
278
|
-
window["$options"] = evaluate("new Object");
|
279
|
-
window["$options"].proxy = outer
|
280
|
-
|
281
|
-
window.evaluate = lambda { |s|
|
282
|
-
return master.evaluate.call(s,window);
|
339
|
+
inner.evaluate = lambda { |s|
|
340
|
+
return master.evaluate.call(s,inner);
|
283
341
|
}
|
284
342
|
|
285
|
-
|
343
|
+
inner.load = lambda { |*files|
|
286
344
|
files.each do |f|
|
287
|
-
master.load.call f,
|
345
|
+
master.load.call f, inner
|
288
346
|
end
|
289
347
|
}
|
290
348
|
|
291
|
-
|
349
|
+
inner.reload = lambda { |*files|
|
292
350
|
files.each do |f|
|
293
|
-
master.reload.call f,
|
351
|
+
master.reload.call f, inner
|
294
352
|
end
|
295
353
|
}
|
296
354
|
|
297
355
|
( class << self; self; end ).send :define_method, :wait do
|
298
356
|
master["finalize"] && master.finalize.call
|
299
|
-
master.
|
357
|
+
master.eventLoop && master.eventLoop.wait
|
300
358
|
end
|
301
359
|
|
302
|
-
|
303
|
-
|
304
|
-
( class << self; self; end ).send :define_method, :become_first_script_window do
|
360
|
+
( class << self; self; end ).send :define_method, :_become_first_script_window do
|
305
361
|
# p "heh ++++++++++++++++++++++++++++", inner, master.first_script_window
|
306
362
|
inner = master.first_script_window
|
307
363
|
end
|
308
364
|
|
309
|
-
( class << self; self; end ).send :define_method, :evaluate do |*args|
|
310
|
-
( script, file, line, global, scope, fn ) = *args
|
311
|
-
raise "cannot evaluate nil script" if script.nil?
|
312
|
-
# print "eval in " + script[0,50].inspect + scope.inspect + " " + ( scope ? scope.isInner.inspect : "none" ) + "\n"
|
313
|
-
global = nil
|
314
|
-
scope ||= inner
|
315
|
-
if fn
|
316
|
-
compiled_script = scripts[fn]
|
317
|
-
end
|
318
|
-
compiled_script ||= compile(script, file, line, global)
|
319
|
-
if fn && !scripts[fn]
|
320
|
-
scripts[fn] = compiled_script
|
321
|
-
end
|
322
|
-
evaluate_compiled_script(compiled_script,scope)
|
323
|
-
end
|
324
|
-
|
325
365
|
( class << self; self; end ).send :define_method, :reevaluate do |*args|
|
326
366
|
( script, file, line, global, scope, fn ) = *args
|
327
367
|
raise "cannot evaluate nil script" if script.nil?
|
@@ -332,20 +372,58 @@ EOJS
|
|
332
372
|
if fn
|
333
373
|
scripts[fn] = compiled_script
|
334
374
|
end
|
335
|
-
|
375
|
+
begin
|
376
|
+
evaluate_compiled_script(compiled_script,scope)
|
377
|
+
rescue Exception => e
|
378
|
+
p e
|
379
|
+
raise e
|
380
|
+
end
|
336
381
|
end
|
337
382
|
|
338
|
-
@envjs = inner
|
339
|
-
|
340
383
|
( class << self; self; end ).send :define_method, :"[]" do |key|
|
341
|
-
key == "this" && evaluate("this") || @envjs[key]
|
384
|
+
# key == "this" && evaluate("this", nil, nil, nil, inner) || @envjs[key]
|
385
|
+
key == "this" && outer || outer[key]
|
342
386
|
end
|
343
387
|
|
344
388
|
( class << self; self; end ).send :define_method, :"[]=" do |k,v|
|
345
|
-
|
389
|
+
# inner[k] = v
|
390
|
+
outer[k] = v
|
391
|
+
end
|
392
|
+
|
393
|
+
master.load.call Envjs::EVENT_LOOP, global
|
394
|
+
|
395
|
+
if false
|
396
|
+
static_outer = new_split_global_outer
|
397
|
+
static_inner = new_split_global_inner static_outer
|
398
|
+
|
399
|
+
master.symbols.each do |symbol|
|
400
|
+
static_inner[symbol] = master[symbol]
|
401
|
+
end
|
402
|
+
|
403
|
+
static_inner["$inner"] = static_inner
|
404
|
+
static_inner["$master"] = master
|
405
|
+
|
406
|
+
master.load.call Envjs::STATIC, static_inner
|
407
|
+
|
408
|
+
master["static"] = static_inner
|
409
|
+
end
|
410
|
+
if true
|
411
|
+
static = new_global
|
412
|
+
|
413
|
+
master.symbols.each do |symbol|
|
414
|
+
static[symbol] = master[symbol]
|
346
415
|
end
|
347
416
|
|
348
|
-
|
417
|
+
static["$master"] = master
|
418
|
+
|
419
|
+
master.load.call Envjs::STATIC, static
|
420
|
+
|
421
|
+
master["static"] = static
|
422
|
+
end
|
423
|
+
|
424
|
+
master.load.call Envjs::ENVJS, inner
|
425
|
+
|
426
|
+
inner = nil
|
349
427
|
end
|
350
428
|
end
|
351
429
|
|