opal 0.10.0.beta2 → 0.10.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/lib/opal/compiler.rb +15 -9
- data/lib/opal/fragment.rb +8 -1
- data/lib/opal/nodes/args/restarg.rb +6 -1
- data/lib/opal/nodes/base.rb +1 -1
- data/lib/opal/nodes/call.rb +4 -0
- data/lib/opal/nodes/def.rb +20 -25
- data/lib/opal/nodes/hash.rb +89 -17
- data/lib/opal/nodes/iter.rb +30 -2
- data/lib/opal/nodes/logic.rb +54 -4
- data/lib/opal/nodes/node_with_args.rb +72 -0
- data/lib/opal/parser.rb +16 -0
- data/lib/opal/parser/grammar.rb +2555 -2562
- data/lib/opal/parser/grammar.y +28 -20
- data/lib/opal/parser/lexer.rb +4 -4
- data/lib/opal/regexp_anchors.rb +13 -5
- data/lib/opal/source_map.rb +2 -1
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +4 -0
- data/opal/corelib/basic_object.rb +3 -1
- data/opal/corelib/constants.rb +1 -1
- data/opal/corelib/file.rb +196 -4
- data/opal/corelib/hash.rb +7 -7
- data/opal/corelib/kernel.rb +7 -4
- data/opal/corelib/marshal.rb +31 -0
- data/opal/corelib/marshal/read_buffer.rb +427 -0
- data/opal/corelib/marshal/write_buffer.rb +383 -0
- data/opal/corelib/method.rb +8 -0
- data/opal/corelib/module.rb +21 -0
- data/opal/corelib/number.rb +19 -5
- data/opal/corelib/proc.rb +33 -6
- data/opal/corelib/range.rb +6 -0
- data/opal/corelib/regexp.rb +5 -1
- data/opal/corelib/runtime.js +69 -17
- data/opal/corelib/string.rb +8 -0
- data/opal/corelib/string/inheritance.rb +4 -0
- data/opal/corelib/struct.rb +5 -0
- data/opal/corelib/unsupported.rb +0 -18
- data/opal/opal/full.rb +1 -0
- data/spec/filters/bugs/basicobject.rb +0 -2
- data/spec/filters/bugs/compiler_opal.rb +5 -0
- data/spec/filters/bugs/enumerable.rb +1 -0
- data/spec/filters/bugs/enumerator.rb +0 -2
- data/spec/filters/bugs/exception.rb +0 -1
- data/spec/filters/bugs/kernel.rb +0 -5
- data/spec/filters/bugs/language.rb +7 -27
- data/spec/filters/bugs/marshal.rb +43 -0
- data/spec/filters/bugs/method.rb +0 -56
- data/spec/filters/bugs/module.rb +0 -1
- data/spec/filters/bugs/proc.rb +0 -46
- data/spec/filters/bugs/regexp.rb +1 -0
- data/spec/filters/bugs/unboundmethod.rb +0 -13
- data/spec/filters/unsupported/bignum.rb +5 -0
- data/spec/filters/unsupported/freeze.rb +2 -0
- data/spec/filters/unsupported/marshal.rb +46 -0
- data/spec/filters/unsupported/symbol.rb +5 -0
- data/spec/lib/compiler/call_spec.rb +29 -29
- data/spec/lib/compiler_spec.rb +7 -1
- data/spec/opal/core/kernel/instance_variables_spec.rb +40 -0
- data/spec/opal/core/language/ternary_operator_spec.rb +6 -0
- data/spec/opal/core/marshal/dump_spec.rb +53 -0
- data/spec/opal/core/marshal/load_spec.rb +7 -0
- data/spec/opal/core/source_map_spec.rb +35 -1
- data/spec/opal/javascript_api_spec.rb +16 -0
- data/spec/opal/stdlib/source_map_spec.rb +8 -0
- data/spec/ruby_specs +7 -4
- data/spec/support/match_helpers.rb +57 -0
- data/spec/support/mspec_rspec_adapter.rb +1 -1
- data/stdlib/opal-parser.rb +3 -1
- data/stdlib/pathname.rb +105 -7
- data/stdlib/racc/parser.rb +551 -138
- data/stdlib/source_map/vlq.rb +3 -2
- data/tasks/testing.rake +4 -2
- metadata +22 -2
data/opal/corelib/kernel.rb
CHANGED
@@ -178,9 +178,10 @@ module Kernel
|
|
178
178
|
|
179
179
|
def exit(status = true)
|
180
180
|
$__at_exit__ ||= []
|
181
|
-
|
181
|
+
|
182
|
+
while $__at_exit__.size > 0
|
182
183
|
block = $__at_exit__.pop
|
183
|
-
block
|
184
|
+
block.call
|
184
185
|
end
|
185
186
|
|
186
187
|
status = 0 if `status === true` # it's in JS because it can be null/undef
|
@@ -968,10 +969,12 @@ module Kernel
|
|
968
969
|
`Opal.load(#{file})`
|
969
970
|
end
|
970
971
|
|
971
|
-
def loop
|
972
|
+
def loop
|
973
|
+
return enum_for :loop unless block_given?
|
974
|
+
|
972
975
|
%x{
|
973
976
|
while (true) {
|
974
|
-
|
977
|
+
#{yield}
|
975
978
|
}
|
976
979
|
}
|
977
980
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'corelib/marshal/read_buffer'
|
2
|
+
require 'corelib/marshal/write_buffer'
|
3
|
+
|
4
|
+
module Marshal
|
5
|
+
MAJOR_VERSION = 4
|
6
|
+
MINOR_VERSION = 8
|
7
|
+
|
8
|
+
# For simulating binary strings
|
9
|
+
#
|
10
|
+
class BinaryString < String
|
11
|
+
def encoding
|
12
|
+
Encoding::BINARY
|
13
|
+
end
|
14
|
+
|
15
|
+
def +(other)
|
16
|
+
BinaryString.new(super)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def dump(object)
|
22
|
+
WriteBuffer.new(object).write
|
23
|
+
end
|
24
|
+
|
25
|
+
def load(marshaled)
|
26
|
+
ReadBuffer.new(marshaled).read
|
27
|
+
end
|
28
|
+
|
29
|
+
alias restore load
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,427 @@
|
|
1
|
+
module Marshal
|
2
|
+
class ReadBuffer
|
3
|
+
%x{
|
4
|
+
function stringToBytes(string) {
|
5
|
+
var i,
|
6
|
+
singleByte,
|
7
|
+
l = string.length,
|
8
|
+
result = [];
|
9
|
+
|
10
|
+
for (i = 0; i < l; i++) {
|
11
|
+
singleByte = string.charCodeAt(i);
|
12
|
+
result.push(singleByte);
|
13
|
+
}
|
14
|
+
return result;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
attr_reader :version, :buffer, :index, :user_class, :extended, :object_cache, :symbols_cache
|
19
|
+
|
20
|
+
def initialize(input)
|
21
|
+
@buffer = `stringToBytes(#{input.to_s})`
|
22
|
+
@index = 0
|
23
|
+
major = read_byte
|
24
|
+
minor = read_byte
|
25
|
+
if major != MAJOR_VERSION || minor != MINOR_VERSION
|
26
|
+
raise TypeError, "incompatible marshal file format (can't be read)"
|
27
|
+
end
|
28
|
+
@version = "#{major}.#{minor}"
|
29
|
+
@object_cache = []
|
30
|
+
@symbols_cache = []
|
31
|
+
@extended = []
|
32
|
+
@ivars = []
|
33
|
+
end
|
34
|
+
|
35
|
+
def length
|
36
|
+
@buffer.length
|
37
|
+
end
|
38
|
+
|
39
|
+
def read(cache: true, ivar_index: nil)
|
40
|
+
code = read_char
|
41
|
+
# The first character indicates the type of the object
|
42
|
+
result = case code
|
43
|
+
when '0'
|
44
|
+
nil
|
45
|
+
when 'T'
|
46
|
+
true
|
47
|
+
when 'F'
|
48
|
+
false
|
49
|
+
when 'i'
|
50
|
+
read_fixnum
|
51
|
+
when 'e'
|
52
|
+
read_extended
|
53
|
+
object = read
|
54
|
+
apply_extends(object)
|
55
|
+
object
|
56
|
+
when 'C'
|
57
|
+
read_user_class
|
58
|
+
read
|
59
|
+
when 'o'
|
60
|
+
read_object
|
61
|
+
when 'd'
|
62
|
+
raise NotImplementedError, 'Data type cannot be demarshaled'
|
63
|
+
when 'u'
|
64
|
+
raise NotImplementedError, 'UserDef type cannot be demarshaled yet' # read_userdef
|
65
|
+
when 'U'
|
66
|
+
read_usrmarshal
|
67
|
+
when 'f'
|
68
|
+
read_float
|
69
|
+
when 'l'
|
70
|
+
read_bignum
|
71
|
+
when '"'
|
72
|
+
read_string(cache: cache)
|
73
|
+
when '/'
|
74
|
+
read_regexp
|
75
|
+
when '['
|
76
|
+
read_array
|
77
|
+
when '{'
|
78
|
+
read_hash
|
79
|
+
when '}'
|
80
|
+
raise NotImplementedError, 'Hashdef type cannot be demarshaled yet' # read_hashdef
|
81
|
+
when 'S'
|
82
|
+
read_struct
|
83
|
+
when 'M'
|
84
|
+
raise NotImplementedError, 'ModuleOld type cannot be demarshaled yet' # read_module_old
|
85
|
+
when 'c'
|
86
|
+
read_class
|
87
|
+
when 'm'
|
88
|
+
read_module
|
89
|
+
when ':'
|
90
|
+
read_symbol
|
91
|
+
when ';'
|
92
|
+
symbols_cache[read_fixnum]
|
93
|
+
when 'I'
|
94
|
+
ivar_index = @ivars.length
|
95
|
+
@ivars << true
|
96
|
+
object = read(cache: cache, ivar_index: ivar_index)
|
97
|
+
set_ivars(object) if @ivars.pop
|
98
|
+
object
|
99
|
+
when '@'
|
100
|
+
object_cache[read_fixnum]
|
101
|
+
else
|
102
|
+
raise ArgumentError, "dump format error"
|
103
|
+
end
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def read_byte
|
108
|
+
if @index >= length
|
109
|
+
raise ArgumentError, "marshal data too short"
|
110
|
+
end
|
111
|
+
result = @buffer[@index]
|
112
|
+
@index += 1
|
113
|
+
result
|
114
|
+
end
|
115
|
+
|
116
|
+
def read_char
|
117
|
+
`String.fromCharCode(#{read_byte})`
|
118
|
+
end
|
119
|
+
|
120
|
+
def set_ivars(obj)
|
121
|
+
data = read_hash(cache: false)
|
122
|
+
|
123
|
+
data.each do |ivar, value|
|
124
|
+
case ivar
|
125
|
+
when :E then # encodings are not supported
|
126
|
+
when :encoding # encodings are not supported
|
127
|
+
else
|
128
|
+
if ivar.start_with?('@')
|
129
|
+
obj.instance_variable_set(ivar, value)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
if obj.respond_to?(:marshal_load)
|
135
|
+
obj.marshal_load(data)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Reads and returns a fixnum from an input stream
|
140
|
+
#
|
141
|
+
def read_fixnum
|
142
|
+
%x{
|
143
|
+
var x, i, c = (#{read_byte} ^ 128) - 128;
|
144
|
+
if (c === 0) {
|
145
|
+
return 0;
|
146
|
+
}
|
147
|
+
|
148
|
+
if (c > 0) {
|
149
|
+
if (4 < c && c < 128) {
|
150
|
+
return c - 5;
|
151
|
+
}
|
152
|
+
x = 0;
|
153
|
+
for (i = 0; i < c; i++) {
|
154
|
+
x |= (#{read_byte} << (8*i));
|
155
|
+
}
|
156
|
+
} else {
|
157
|
+
if (-129 < c && c < -4) {
|
158
|
+
return c + 5;
|
159
|
+
}
|
160
|
+
|
161
|
+
c = -c;
|
162
|
+
x = -1;
|
163
|
+
|
164
|
+
for (i = 0; i < c; i++) {
|
165
|
+
x &= ~(0xff << (8*i));
|
166
|
+
x |= (#{read_byte} << (8*i));
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
return x;
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
# Reads and returns a string from an input stream
|
175
|
+
# Sometimes string shouldn't be cached using
|
176
|
+
# an internal object cache, for a:
|
177
|
+
# + class/module name
|
178
|
+
# + float
|
179
|
+
# + regexp
|
180
|
+
#
|
181
|
+
def read_string(cache: true)
|
182
|
+
length = read_fixnum
|
183
|
+
%x{
|
184
|
+
var i, result = '';
|
185
|
+
|
186
|
+
for (i = 0; i < length; i++) {
|
187
|
+
result += #{read_char};
|
188
|
+
}
|
189
|
+
|
190
|
+
if (cache) {
|
191
|
+
self.object_cache.push(result);
|
192
|
+
}
|
193
|
+
|
194
|
+
return result;
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
# Reads and returns a symbol from an input stream
|
199
|
+
#
|
200
|
+
def read_symbol
|
201
|
+
length = read_fixnum
|
202
|
+
%x{
|
203
|
+
var i, result = '';
|
204
|
+
|
205
|
+
for (i = 0; i < length; i++) {
|
206
|
+
result += #{read_char};
|
207
|
+
}
|
208
|
+
|
209
|
+
self.symbols_cache.push(result);
|
210
|
+
|
211
|
+
return result;
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
# Reads and returns an array from an input stream
|
216
|
+
#
|
217
|
+
def read_array
|
218
|
+
result = []
|
219
|
+
@object_cache << result
|
220
|
+
length = read_fixnum
|
221
|
+
%x{
|
222
|
+
if (length > 0) {
|
223
|
+
|
224
|
+
while (result.length < length) {
|
225
|
+
result.push(#{read});
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
return result;
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
# Reads and returns a hash from an input stream
|
234
|
+
# Sometimes hash shouldn't be cached using
|
235
|
+
# an internal object cache, for a:
|
236
|
+
# + hash of instance variables
|
237
|
+
# + hash of struct attributes
|
238
|
+
#
|
239
|
+
def read_hash(cache: true)
|
240
|
+
result = {}
|
241
|
+
|
242
|
+
if cache
|
243
|
+
@object_cache << result
|
244
|
+
end
|
245
|
+
|
246
|
+
length = read_fixnum
|
247
|
+
%x{
|
248
|
+
if (length > 0) {
|
249
|
+
var key, value, i;
|
250
|
+
for (i = 0; i < #{length}; i++) {
|
251
|
+
key = #{read};
|
252
|
+
value = #{read};
|
253
|
+
#{result[`key`] = `value`};
|
254
|
+
}
|
255
|
+
}
|
256
|
+
return result;
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
# Returns a constant by passed const_name,
|
261
|
+
# re-raises Marshal-specific error when it's missing
|
262
|
+
#
|
263
|
+
def safe_const_get(const_name)
|
264
|
+
begin
|
265
|
+
Object.const_get(const_name)
|
266
|
+
rescue NameError
|
267
|
+
raise ArgumentError, "undefined class/module #{const_name}"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Reads and saves a user class from an input stream
|
272
|
+
# Used for cases like String/Array subclasses
|
273
|
+
#
|
274
|
+
def read_user_class
|
275
|
+
@user_class = read(cache: false)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Constantizes and resets saved user class
|
279
|
+
#
|
280
|
+
def get_user_class
|
281
|
+
klass = safe_const_get(@user_class)
|
282
|
+
@user_class = nil
|
283
|
+
klass
|
284
|
+
end
|
285
|
+
|
286
|
+
# Reads and returns a Class from an input stream
|
287
|
+
#
|
288
|
+
def read_class
|
289
|
+
klass_name = read_string(cache: false)
|
290
|
+
result = safe_const_get(klass_name)
|
291
|
+
unless result.class == Class
|
292
|
+
raise ArgumentError, "#{klass_name} does not refer to a Class"
|
293
|
+
end
|
294
|
+
@object_cache << result
|
295
|
+
result
|
296
|
+
end
|
297
|
+
|
298
|
+
# Reads and returns a Module from an input stream
|
299
|
+
#
|
300
|
+
def read_module
|
301
|
+
mod_name = read_string(cache: false)
|
302
|
+
result = safe_const_get(mod_name)
|
303
|
+
unless result.class == Module
|
304
|
+
raise ArgumentError, "#{mod_name} does not refer to a Module"
|
305
|
+
end
|
306
|
+
@object_cache << result
|
307
|
+
result
|
308
|
+
end
|
309
|
+
|
310
|
+
# Reads and returns an abstract object from an input stream
|
311
|
+
#
|
312
|
+
def read_object
|
313
|
+
klass_name = read(cache: false)
|
314
|
+
klass = safe_const_get(klass_name)
|
315
|
+
result = if @ivars.last
|
316
|
+
data = read_hash(cache: false)
|
317
|
+
load_object(klass, data)
|
318
|
+
else
|
319
|
+
object = klass.allocate
|
320
|
+
set_ivars(object)
|
321
|
+
object
|
322
|
+
end
|
323
|
+
@object_cache << result
|
324
|
+
result
|
325
|
+
end
|
326
|
+
|
327
|
+
# Loads an instance of passed klass using
|
328
|
+
# default marshal hooks
|
329
|
+
#
|
330
|
+
def load_object(klass, args)
|
331
|
+
return klass._load(args) if klass.respond_to?(:_load)
|
332
|
+
instance = klass.allocate
|
333
|
+
instance.marshal_load(args) if instance.respond_to?(:marshal_load)
|
334
|
+
instance
|
335
|
+
end
|
336
|
+
|
337
|
+
# Reads and returns a Struct from an input stream
|
338
|
+
#
|
339
|
+
def read_struct
|
340
|
+
klass_name = read(cache: false)
|
341
|
+
klass = safe_const_get(klass_name)
|
342
|
+
args = read_hash(cache: false)
|
343
|
+
result = load_object(klass, args)
|
344
|
+
@object_cache << result
|
345
|
+
result
|
346
|
+
end
|
347
|
+
|
348
|
+
# Reads and saves a Module from an input stream
|
349
|
+
# that was extending marshalled object
|
350
|
+
#
|
351
|
+
def read_extended
|
352
|
+
@extended << read
|
353
|
+
end
|
354
|
+
|
355
|
+
# Applies all saved extending modules
|
356
|
+
# on the passed object
|
357
|
+
#
|
358
|
+
def apply_extends(object)
|
359
|
+
@extended.each do |e|
|
360
|
+
mod = safe_const_get(e)
|
361
|
+
object.extend(mod)
|
362
|
+
end
|
363
|
+
@extended = []
|
364
|
+
end
|
365
|
+
|
366
|
+
# Reads and returns Bignum from an input stream
|
367
|
+
#
|
368
|
+
def read_bignum
|
369
|
+
sign = read_char == '-' ? -1 : 1
|
370
|
+
size = read_fixnum * 2
|
371
|
+
result = 0
|
372
|
+
(0...size).each do |exp|
|
373
|
+
result += (read_char.ord) * 2 ** (exp * 8)
|
374
|
+
end
|
375
|
+
result = result.to_i * sign
|
376
|
+
@object_cache << result
|
377
|
+
result
|
378
|
+
end
|
379
|
+
|
380
|
+
# Reads and returns Float from an input stream
|
381
|
+
#
|
382
|
+
def read_float
|
383
|
+
s = read_string(cache: false)
|
384
|
+
result = if s == "nan"
|
385
|
+
0.0 / 0
|
386
|
+
elsif s == "inf"
|
387
|
+
1.0 / 0
|
388
|
+
elsif s == "-inf"
|
389
|
+
-1.0 / 0
|
390
|
+
else
|
391
|
+
s.to_f
|
392
|
+
end
|
393
|
+
@object_cache << result
|
394
|
+
result
|
395
|
+
end
|
396
|
+
|
397
|
+
# Reads and returns Regexp from an input stream
|
398
|
+
#
|
399
|
+
def read_regexp
|
400
|
+
args = [read_string(cache: false), read_byte]
|
401
|
+
|
402
|
+
result = if @user_class
|
403
|
+
load_object(get_user_class, args)
|
404
|
+
else
|
405
|
+
load_object(Regexp, args)
|
406
|
+
end
|
407
|
+
@object_cache << result
|
408
|
+
result
|
409
|
+
end
|
410
|
+
|
411
|
+
# Reads and returns an abstract object from an input stream
|
412
|
+
# when the class of this object has custom marshalling rules
|
413
|
+
#
|
414
|
+
def read_usrmarshal
|
415
|
+
klass_name = read
|
416
|
+
klass = safe_const_get(klass_name)
|
417
|
+
result = klass.allocate
|
418
|
+
@object_cache << result
|
419
|
+
data = read
|
420
|
+
unless result.respond_to?(:marshal_load)
|
421
|
+
raise TypeError, "instance of #{klass} needs to have method `marshal_load'"
|
422
|
+
end
|
423
|
+
result.marshal_load(data)
|
424
|
+
result
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|