opal 0.10.0.beta2 → 0.10.0.beta3

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/lib/opal/compiler.rb +15 -9
  4. data/lib/opal/fragment.rb +8 -1
  5. data/lib/opal/nodes/args/restarg.rb +6 -1
  6. data/lib/opal/nodes/base.rb +1 -1
  7. data/lib/opal/nodes/call.rb +4 -0
  8. data/lib/opal/nodes/def.rb +20 -25
  9. data/lib/opal/nodes/hash.rb +89 -17
  10. data/lib/opal/nodes/iter.rb +30 -2
  11. data/lib/opal/nodes/logic.rb +54 -4
  12. data/lib/opal/nodes/node_with_args.rb +72 -0
  13. data/lib/opal/parser.rb +16 -0
  14. data/lib/opal/parser/grammar.rb +2555 -2562
  15. data/lib/opal/parser/grammar.y +28 -20
  16. data/lib/opal/parser/lexer.rb +4 -4
  17. data/lib/opal/regexp_anchors.rb +13 -5
  18. data/lib/opal/source_map.rb +2 -1
  19. data/lib/opal/version.rb +1 -1
  20. data/opal/corelib/array.rb +4 -0
  21. data/opal/corelib/basic_object.rb +3 -1
  22. data/opal/corelib/constants.rb +1 -1
  23. data/opal/corelib/file.rb +196 -4
  24. data/opal/corelib/hash.rb +7 -7
  25. data/opal/corelib/kernel.rb +7 -4
  26. data/opal/corelib/marshal.rb +31 -0
  27. data/opal/corelib/marshal/read_buffer.rb +427 -0
  28. data/opal/corelib/marshal/write_buffer.rb +383 -0
  29. data/opal/corelib/method.rb +8 -0
  30. data/opal/corelib/module.rb +21 -0
  31. data/opal/corelib/number.rb +19 -5
  32. data/opal/corelib/proc.rb +33 -6
  33. data/opal/corelib/range.rb +6 -0
  34. data/opal/corelib/regexp.rb +5 -1
  35. data/opal/corelib/runtime.js +69 -17
  36. data/opal/corelib/string.rb +8 -0
  37. data/opal/corelib/string/inheritance.rb +4 -0
  38. data/opal/corelib/struct.rb +5 -0
  39. data/opal/corelib/unsupported.rb +0 -18
  40. data/opal/opal/full.rb +1 -0
  41. data/spec/filters/bugs/basicobject.rb +0 -2
  42. data/spec/filters/bugs/compiler_opal.rb +5 -0
  43. data/spec/filters/bugs/enumerable.rb +1 -0
  44. data/spec/filters/bugs/enumerator.rb +0 -2
  45. data/spec/filters/bugs/exception.rb +0 -1
  46. data/spec/filters/bugs/kernel.rb +0 -5
  47. data/spec/filters/bugs/language.rb +7 -27
  48. data/spec/filters/bugs/marshal.rb +43 -0
  49. data/spec/filters/bugs/method.rb +0 -56
  50. data/spec/filters/bugs/module.rb +0 -1
  51. data/spec/filters/bugs/proc.rb +0 -46
  52. data/spec/filters/bugs/regexp.rb +1 -0
  53. data/spec/filters/bugs/unboundmethod.rb +0 -13
  54. data/spec/filters/unsupported/bignum.rb +5 -0
  55. data/spec/filters/unsupported/freeze.rb +2 -0
  56. data/spec/filters/unsupported/marshal.rb +46 -0
  57. data/spec/filters/unsupported/symbol.rb +5 -0
  58. data/spec/lib/compiler/call_spec.rb +29 -29
  59. data/spec/lib/compiler_spec.rb +7 -1
  60. data/spec/opal/core/kernel/instance_variables_spec.rb +40 -0
  61. data/spec/opal/core/language/ternary_operator_spec.rb +6 -0
  62. data/spec/opal/core/marshal/dump_spec.rb +53 -0
  63. data/spec/opal/core/marshal/load_spec.rb +7 -0
  64. data/spec/opal/core/source_map_spec.rb +35 -1
  65. data/spec/opal/javascript_api_spec.rb +16 -0
  66. data/spec/opal/stdlib/source_map_spec.rb +8 -0
  67. data/spec/ruby_specs +7 -4
  68. data/spec/support/match_helpers.rb +57 -0
  69. data/spec/support/mspec_rspec_adapter.rb +1 -1
  70. data/stdlib/opal-parser.rb +3 -1
  71. data/stdlib/pathname.rb +105 -7
  72. data/stdlib/racc/parser.rb +551 -138
  73. data/stdlib/source_map/vlq.rb +3 -2
  74. data/tasks/testing.rake +4 -2
  75. metadata +22 -2
@@ -178,9 +178,10 @@ module Kernel
178
178
 
179
179
  def exit(status = true)
180
180
  $__at_exit__ ||= []
181
- loop do
181
+
182
+ while $__at_exit__.size > 0
182
183
  block = $__at_exit__.pop
183
- block ? block.call : break
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(&block)
972
+ def loop
973
+ return enum_for :loop unless block_given?
974
+
972
975
  %x{
973
976
  while (true) {
974
- block()
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