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.
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