opal 1.3.2 → 1.4.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (222) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +1 -0
  3. data/.github/workflows/build.yml +0 -3
  4. data/.rubocop.yml +5 -1
  5. data/UNRELEASED.md +66 -2
  6. data/benchmark-ips/bm_truthy.rb +30 -0
  7. data/bin/opal-mspec +1 -3
  8. data/bin/opal-repl +1 -2
  9. data/bin/remove-filters +1 -4
  10. data/docs/compiled_ruby.md +10 -6
  11. data/exe/opal-repl +1 -3
  12. data/lib/opal/ast/builder.rb +1 -1
  13. data/lib/opal/cli.rb +2 -2
  14. data/lib/opal/cli_runners/nodejs.rb +9 -2
  15. data/lib/opal/cli_runners/source-map-support-browser.js +80 -216
  16. data/lib/opal/cli_runners/source-map-support-node.js +80 -216
  17. data/lib/opal/cli_runners/source-map-support.js +5 -1
  18. data/lib/opal/cli_runners/system_runner.rb +10 -4
  19. data/lib/opal/compiler.rb +3 -5
  20. data/lib/opal/fragment.rb +5 -1
  21. data/lib/opal/nodes/args/extract_block_arg.rb +1 -8
  22. data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -3
  23. data/lib/opal/nodes/args/extract_optarg.rb +1 -3
  24. data/lib/opal/nodes/args/extract_post_arg.rb +2 -5
  25. data/lib/opal/nodes/args/extract_post_optarg.rb +2 -7
  26. data/lib/opal/nodes/args/initialize_iterarg.rb +1 -3
  27. data/lib/opal/nodes/args/prepare_post_args.rb +5 -1
  28. data/lib/opal/nodes/base.rb +3 -2
  29. data/lib/opal/nodes/call.rb +20 -9
  30. data/lib/opal/nodes/call_special.rb +50 -0
  31. data/lib/opal/nodes/class.rb +24 -15
  32. data/lib/opal/nodes/constants.rb +23 -5
  33. data/lib/opal/nodes/def.rb +20 -23
  34. data/lib/opal/nodes/defined.rb +5 -5
  35. data/lib/opal/nodes/definitions.rb +2 -2
  36. data/lib/opal/nodes/defs.rb +2 -5
  37. data/lib/opal/nodes/helpers.rb +48 -18
  38. data/lib/opal/nodes/if.rb +109 -8
  39. data/lib/opal/nodes/iter.rb +23 -16
  40. data/lib/opal/nodes/literal.rb +18 -4
  41. data/lib/opal/nodes/logic.rb +2 -1
  42. data/lib/opal/nodes/masgn.rb +4 -9
  43. data/lib/opal/nodes/module.rb +29 -19
  44. data/lib/opal/nodes/node_with_args.rb +1 -7
  45. data/lib/opal/nodes/scope.rb +54 -15
  46. data/lib/opal/nodes/singleton_class.rb +5 -3
  47. data/lib/opal/nodes/super.rb +3 -3
  48. data/lib/opal/nodes/top.rb +34 -31
  49. data/lib/opal/nodes/variables.rb +2 -2
  50. data/lib/opal/nodes/x_string.rb +3 -0
  51. data/lib/opal/nodes.rb +0 -1
  52. data/lib/opal/parser/patch.rb +75 -0
  53. data/lib/opal/parser/with_ruby_lexer.rb +1 -1
  54. data/lib/opal/regexp_anchors.rb +7 -7
  55. data/lib/opal/requires.rb +19 -0
  56. data/lib/opal/rewriters/pattern_matching.rb +1 -1
  57. data/lib/opal/rewriters/returnable_logic.rb +102 -4
  58. data/lib/opal/util.rb +2 -2
  59. data/lib/opal/version.rb +1 -1
  60. data/lib/opal.rb +1 -17
  61. data/opal/corelib/array/pack.rb +11 -11
  62. data/opal/corelib/array.rb +193 -152
  63. data/opal/corelib/basic_object.rb +14 -14
  64. data/opal/corelib/binding.rb +7 -7
  65. data/opal/corelib/boolean.rb +12 -15
  66. data/opal/corelib/class.rb +23 -1
  67. data/opal/corelib/comparable.rb +8 -8
  68. data/opal/corelib/complex/base.rb +2 -2
  69. data/opal/corelib/complex.rb +79 -88
  70. data/opal/corelib/constants.rb +9 -9
  71. data/opal/corelib/dir.rb +4 -3
  72. data/opal/corelib/enumerable.rb +140 -127
  73. data/opal/corelib/enumerator/arithmetic_sequence.rb +177 -0
  74. data/opal/corelib/enumerator/chain.rb +42 -0
  75. data/opal/corelib/enumerator/generator.rb +35 -0
  76. data/opal/corelib/enumerator/lazy.rb +243 -0
  77. data/opal/corelib/enumerator/yielder.rb +36 -0
  78. data/opal/corelib/enumerator.rb +45 -300
  79. data/opal/corelib/error/errno.rb +47 -0
  80. data/opal/corelib/error.rb +62 -60
  81. data/opal/corelib/file.rb +26 -12
  82. data/opal/corelib/hash.rb +98 -107
  83. data/opal/corelib/helpers.rb +62 -13
  84. data/opal/corelib/io.rb +47 -34
  85. data/opal/corelib/kernel/format.rb +29 -29
  86. data/opal/corelib/kernel.rb +86 -83
  87. data/opal/corelib/main.rb +14 -12
  88. data/opal/corelib/marshal/read_buffer.rb +15 -15
  89. data/opal/corelib/marshal/write_buffer.rb +45 -44
  90. data/opal/corelib/marshal.rb +3 -3
  91. data/opal/corelib/math.rb +50 -50
  92. data/opal/corelib/method.rb +12 -8
  93. data/opal/corelib/module.rb +96 -79
  94. data/opal/corelib/nil.rb +9 -11
  95. data/opal/corelib/number.rb +113 -118
  96. data/opal/corelib/numeric.rb +37 -33
  97. data/opal/corelib/object_space.rb +11 -10
  98. data/opal/corelib/pack_unpack/format_string_parser.rb +3 -3
  99. data/opal/corelib/pattern_matching/base.rb +7 -7
  100. data/opal/corelib/pattern_matching.rb +1 -1
  101. data/opal/corelib/proc.rb +15 -16
  102. data/opal/corelib/process/base.rb +2 -2
  103. data/opal/corelib/process/status.rb +21 -0
  104. data/opal/corelib/process.rb +5 -5
  105. data/opal/corelib/random/formatter.rb +11 -11
  106. data/opal/corelib/random/math_random.js.rb +1 -1
  107. data/opal/corelib/random/mersenne_twister.rb +3 -3
  108. data/opal/corelib/random/seedrandom.js.rb +3 -3
  109. data/opal/corelib/random.rb +17 -17
  110. data/opal/corelib/range.rb +51 -35
  111. data/opal/corelib/rational/base.rb +4 -4
  112. data/opal/corelib/rational.rb +61 -62
  113. data/opal/corelib/regexp.rb +47 -38
  114. data/opal/corelib/runtime.js +245 -139
  115. data/opal/corelib/string/encoding.rb +21 -21
  116. data/opal/corelib/string/unpack.rb +19 -14
  117. data/opal/corelib/string.rb +135 -128
  118. data/opal/corelib/struct.rb +59 -46
  119. data/opal/corelib/time.rb +47 -57
  120. data/opal/corelib/trace_point.rb +2 -2
  121. data/opal/corelib/unsupported.rb +31 -120
  122. data/opal/corelib/variables.rb +3 -3
  123. data/opal/opal/base.rb +9 -8
  124. data/opal/opal/full.rb +8 -8
  125. data/opal/opal/mini.rb +17 -17
  126. data/opal/opal.rb +17 -18
  127. data/opal.gemspec +1 -1
  128. data/spec/filters/bugs/array.rb +4 -24
  129. data/spec/filters/bugs/bigdecimal.rb +0 -23
  130. data/spec/filters/bugs/binding.rb +0 -1
  131. data/spec/filters/bugs/boolean.rb +3 -0
  132. data/spec/filters/bugs/class.rb +2 -0
  133. data/spec/filters/bugs/date.rb +0 -5
  134. data/spec/filters/bugs/encoding.rb +8 -50
  135. data/spec/filters/bugs/enumerable.rb +4 -1
  136. data/spec/filters/bugs/enumerator.rb +3 -36
  137. data/spec/filters/bugs/exception.rb +0 -2
  138. data/spec/filters/bugs/file.rb +0 -2
  139. data/spec/filters/bugs/float.rb +0 -3
  140. data/spec/filters/bugs/hash.rb +5 -3
  141. data/spec/filters/bugs/integer.rb +2 -3
  142. data/spec/filters/bugs/kernel.rb +2 -31
  143. data/spec/filters/bugs/language.rb +29 -49
  144. data/spec/filters/bugs/main.rb +0 -2
  145. data/spec/filters/bugs/marshal.rb +2 -3
  146. data/spec/filters/bugs/matrix.rb +0 -36
  147. data/spec/filters/bugs/module.rb +7 -61
  148. data/spec/filters/bugs/numeric.rb +0 -7
  149. data/spec/filters/bugs/objectspace.rb +1 -1
  150. data/spec/filters/bugs/pack_unpack.rb +0 -4
  151. data/spec/filters/bugs/proc.rb +0 -9
  152. data/spec/filters/bugs/random.rb +0 -5
  153. data/spec/filters/bugs/range.rb +1 -6
  154. data/spec/filters/bugs/regexp.rb +0 -3
  155. data/spec/filters/bugs/set.rb +8 -1
  156. data/spec/filters/bugs/string.rb +9 -34
  157. data/spec/filters/bugs/stringscanner.rb +8 -7
  158. data/spec/filters/bugs/struct.rb +2 -3
  159. data/spec/filters/bugs/symbol.rb +0 -1
  160. data/spec/filters/bugs/time.rb +0 -8
  161. data/spec/filters/bugs/unboundmethod.rb +0 -8
  162. data/spec/filters/bugs/warnings.rb +1 -7
  163. data/spec/filters/unsupported/freeze.rb +24 -0
  164. data/spec/filters/unsupported/integer.rb +1 -0
  165. data/spec/filters/unsupported/kernel.rb +12 -0
  166. data/spec/filters/unsupported/privacy.rb +3 -0
  167. data/spec/filters/unsupported/string.rb +2 -0
  168. data/spec/lib/builder_spec.rb +2 -2
  169. data/spec/lib/cli_spec.rb +1 -1
  170. data/spec/lib/compiler_spec.rb +37 -37
  171. data/spec/lib/simple_server_spec.rb +2 -2
  172. data/spec/lib/source_map/file_spec.rb +1 -1
  173. data/spec/opal/compiler/irb_spec.rb +2 -2
  174. data/spec/opal/core/kernel/puts_spec.rb +90 -0
  175. data/spec/opal/core/language/super_spec.rb +24 -0
  176. data/spec/ruby_specs +4 -2
  177. data/spec/support/rewriters_helper.rb +1 -1
  178. data/stdlib/bigdecimal.rb +7 -11
  179. data/stdlib/buffer/view.rb +2 -2
  180. data/stdlib/buffer.rb +2 -2
  181. data/stdlib/date.rb +5 -6
  182. data/stdlib/erb.rb +1 -0
  183. data/stdlib/js.rb +2 -1
  184. data/stdlib/native.rb +7 -8
  185. data/stdlib/nodejs/argf.rb +4 -4
  186. data/stdlib/nodejs/base.rb +29 -0
  187. data/stdlib/nodejs/dir.rb +1 -1
  188. data/stdlib/nodejs/env.rb +6 -9
  189. data/stdlib/nodejs/file.rb +23 -17
  190. data/stdlib/nodejs/fileutils.rb +3 -3
  191. data/stdlib/nodejs/io.rb +2 -20
  192. data/stdlib/nodejs/irb.rb +0 -0
  193. data/stdlib/nodejs/kernel.rb +2 -37
  194. data/stdlib/nodejs.rb +1 -3
  195. data/stdlib/opal/miniracer.rb +2 -0
  196. data/stdlib/opal/platform.rb +6 -13
  197. data/stdlib/opal/replutils.rb +16 -5
  198. data/stdlib/opal-parser.rb +2 -2
  199. data/stdlib/optparse/ac.rb +54 -0
  200. data/stdlib/optparse/date.rb +14 -0
  201. data/stdlib/optparse/kwargs.rb +22 -0
  202. data/stdlib/optparse/shellwords.rb +7 -0
  203. data/stdlib/optparse/time.rb +15 -0
  204. data/stdlib/optparse/uri.rb +7 -0
  205. data/stdlib/optparse/version.rb +69 -0
  206. data/stdlib/optparse.rb +2279 -0
  207. data/stdlib/pathname.rb +5 -6
  208. data/stdlib/pp.rb +18 -2
  209. data/stdlib/promise/v2.rb +18 -22
  210. data/stdlib/promise.rb +15 -21
  211. data/stdlib/set.rb +32 -32
  212. data/stdlib/shellwords.rb +240 -0
  213. data/stdlib/stringio.rb +3 -6
  214. data/stdlib/strscan.rb +5 -8
  215. data/stdlib/template.rb +2 -2
  216. data/stdlib/thread.rb +7 -9
  217. data/tasks/performance.rake +5 -2
  218. data/tasks/testing/mspec_special_calls.rb +0 -12
  219. data/tasks/testing.rake +55 -37
  220. data/test/nodejs/test_file.rb +11 -0
  221. metadata +55 -10
  222. data/lib/opal/nodes/case.rb +0 -114
data/lib/opal/compiler.rb CHANGED
@@ -205,6 +205,9 @@ module Opal
205
205
  # Current scope
206
206
  attr_accessor :scope
207
207
 
208
+ # Top scope
209
+ attr_accessor :top_scope
210
+
208
211
  # Current case_stmt
209
212
  attr_reader :case_stmt
210
213
 
@@ -284,11 +287,6 @@ module Opal
284
287
  )
285
288
  end
286
289
 
287
- # Operator helpers
288
- def operator_helpers
289
- @operator_helpers ||= Set.new
290
- end
291
-
292
290
  # Method calls made in this file
293
291
  def method_calls
294
292
  @method_calls ||= Set.new
data/lib/opal/fragment.rb CHANGED
@@ -106,7 +106,11 @@ module Opal
106
106
  @sexp
107
107
  end
108
108
  when @sexp.type == :iter
109
- @sexp.loc.begin # [1,2].each >{ }
109
+ if loc.respond_to? :begin
110
+ @sexp.loc.begin # [1,2].each >{ }
111
+ else
112
+ @sexp
113
+ end
110
114
  else
111
115
  @sexp
112
116
  end
@@ -18,15 +18,8 @@ module Opal
18
18
  def compile
19
19
  scope.uses_block!
20
20
  scope.add_arg name
21
- scope.block_name = name
22
21
 
23
- scope_name = scope.identity
24
- yielder = scope.block_name
25
-
26
- add_temp "$iter = #{scope_name}.$$p"
27
- add_temp "#{yielder} = $iter || nil"
28
-
29
- line "if ($iter) #{scope_name}.$$p = null;"
22
+ scope.prepare_block(name)
30
23
  end
31
24
  end
32
25
  end
@@ -25,9 +25,7 @@ module Opal
25
25
 
26
26
  return if default_value.children[1] == :undefined
27
27
 
28
- line "if (#{lvar_name} == null) {"
29
- line " #{lvar_name} = ", expr(default_value)
30
- line "}"
28
+ line "if (#{lvar_name} == null) #{lvar_name} = ", expr(default_value)
31
29
  end
32
30
  end
33
31
  end
@@ -25,9 +25,7 @@ module Opal
25
25
  def compile
26
26
  return if default_value.children[1] == :undefined
27
27
 
28
- line "if (#{name} == null) {"
29
- line " #{name} = ", expr(default_value), ";"
30
- line "}"
28
+ line "if (#{name} == null) #{name} = ", expr(default_value), ";"
31
29
  end
32
30
  end
33
31
  end
@@ -15,12 +15,9 @@ module Opal
15
15
  def compile
16
16
  add_temp name
17
17
 
18
- line "#{name} = $post_args[0];"
19
- line "$post_args.splice(0, 1);"
18
+ line "#{name} = $post_args.shift();"
20
19
 
21
- line "if (#{name} == null) {"
22
- line " #{name} = nil"
23
- line "}"
20
+ line "if (#{name} == null) #{name} = nil;"
24
21
  end
25
22
  end
26
23
  end
@@ -24,16 +24,11 @@ module Opal
24
24
  def compile
25
25
  add_temp name
26
26
 
27
- line "if ($post_args.length > #{args_to_keep}) {"
28
- line " #{name} = $post_args[0];"
29
- line " $post_args.splice(0, 1);"
30
- line "}"
27
+ line "if ($post_args.length > #{args_to_keep}) #{name} = $post_args.shift();"
31
28
 
32
29
  return if default_value.children[1] == :undefined
33
30
 
34
- line "if (#{name} == null) {"
35
- line " #{name} = ", expr(default_value), ";"
36
- line "}"
31
+ line "if (#{name} == null) #{name} = ", expr(default_value), ";"
37
32
  end
38
33
  end
39
34
  end
@@ -18,9 +18,7 @@ module Opal
18
18
  children :name
19
19
 
20
20
  def compile
21
- line "if (#{name} == null) {"
22
- line " #{name} = nil;"
23
- line "}"
21
+ line "if (#{name} == null) #{name} = nil;"
24
22
  end
25
23
  end
26
24
  end
@@ -14,7 +14,11 @@ module Opal
14
14
  def compile
15
15
  add_temp '$post_args'
16
16
 
17
- line "$post_args = Opal.slice.call(arguments, #{offset}, arguments.length)"
17
+ if offset == 0
18
+ line "$post_args = Opal.slice.call(arguments)"
19
+ else
20
+ line "$post_args = Opal.slice.call(arguments, #{offset})"
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -36,6 +36,7 @@ module Opal
36
36
  @type = sexp.type
37
37
  @level = level
38
38
  @compiler = compiler
39
+ @compiler.top_scope ||= self
39
40
  end
40
41
 
41
42
  def children
@@ -86,7 +87,7 @@ module Opal
86
87
  end
87
88
 
88
89
  def top_scope
89
- scope.top_scope
90
+ @compiler.top_scope
90
91
  end
91
92
 
92
93
  def s(type, *children)
@@ -199,7 +200,7 @@ module Opal
199
200
 
200
201
  def class_variable_owner
201
202
  if scope
202
- "$nesting[#{class_variable_owner_nesting_level}]"
203
+ "#{scope.nesting}[#{class_variable_owner_nesting_level}]"
203
204
  else
204
205
  'Opal.Object'
205
206
  end
@@ -252,9 +252,11 @@ module Opal
252
252
 
253
253
  OPERATORS.each do |operator, name|
254
254
  add_special(operator.to_sym) do |compile_default|
255
- if compiler.inline_operators?
255
+ if invoke_using_refinement?
256
+ compile_default.call
257
+ elsif compiler.inline_operators?
256
258
  compiler.method_calls << operator.to_sym if record_method?
257
- compiler.operator_helpers << operator.to_sym
259
+ helper :"rb_#{name}"
258
260
  lhs, rhs = expr(recvr), expr(arglist)
259
261
 
260
262
  push fragment("$rb_#{name}(")
@@ -281,7 +283,7 @@ module Opal
281
283
  dir = File.dirname(file)
282
284
  compiler.requires << Pathname(dir).join(arg.children[0]).cleanpath.to_s
283
285
  end
284
- push fragment("self.$require(#{file.inspect}+ '/../' + ")
286
+ push fragment("#{scope.self}.$require(#{file.inspect}+ '/../' + ")
285
287
  push process(arglist)
286
288
  push fragment(')')
287
289
  end
@@ -351,9 +353,9 @@ module Opal
351
353
  def using_refinement(arg)
352
354
  prev, curr = *scope.refinements_temp
353
355
  if prev
354
- push "(#{curr} = #{prev}.slice(), #{curr}.push(", expr(arg), '), self)'
356
+ push "(#{curr} = #{prev}.slice(), #{curr}.push(", expr(arg), "), #{scope.self})"
355
357
  else
356
- push "(#{curr} = [", expr(arg), '], self)'
358
+ push "(#{curr} = [", expr(arg), "], #{scope.self})"
357
359
  end
358
360
  end
359
361
 
@@ -373,14 +375,14 @@ module Opal
373
375
 
374
376
  add_special :nesting do |compile_default|
375
377
  push_nesting = push_nesting?
376
- push '(Opal.Module.$$nesting = $nesting, ' if push_nesting
378
+ push "(Opal.Module.$$nesting = #{scope.nesting}, " if push_nesting
377
379
  compile_default.call
378
380
  push ')' if push_nesting
379
381
  end
380
382
 
381
383
  add_special :constants do |compile_default|
382
384
  push_nesting = push_nesting?
383
- push '(Opal.Module.$$nesting = $nesting, ' if push_nesting
385
+ push "(Opal.Module.$$nesting = #{scope.nesting}, " if push_nesting
384
386
  compile_default.call
385
387
  push ')' if push_nesting
386
388
  end
@@ -390,18 +392,27 @@ module Opal
390
392
  add_special :eval do |compile_default|
391
393
  next compile_default.call if arglist.children.length != 1 || ![s(:self), nil].include?(recvr)
392
394
 
395
+ scope.nesting
393
396
  temp = scope.new_temp
394
397
  scope_variables = scope.scope_locals.map(&:to_s).inspect
395
398
  push "(#{temp} = ", expr(arglist)
396
399
  push ", typeof Opal.compile === 'function' ? eval(Opal.compile(#{temp}"
397
400
  push ', {scope_variables: ', scope_variables
398
401
  push ", arity_check: #{compiler.arity_check?}, file: '(eval)', eval: true})) : "
399
- push "self.$eval(#{temp}))"
402
+ push "#{scope.self}.$eval(#{temp}))"
403
+ end
404
+
405
+ add_special :local_variables do |compile_default|
406
+ next compile_default.call unless [s(:self), nil].include?(recvr)
407
+
408
+ scope_variables = scope.scope_locals.map(&:to_s).inspect
409
+ push scope_variables
400
410
  end
401
411
 
402
412
  add_special :binding do |compile_default|
403
413
  next compile_default.call unless recvr.nil?
404
414
 
415
+ scope.nesting
405
416
  push "Opal.Binding.$new("
406
417
  push " function($code, $value) {"
407
418
  push " if (typeof $value === 'undefined') {"
@@ -412,7 +423,7 @@ module Opal
412
423
  push " }"
413
424
  push " },"
414
425
  push " ", scope.scope_locals.map(&:to_s).inspect, ","
415
- push " self,"
426
+ push " ", scope.self, ","
416
427
  push " ", source_location
417
428
  push ")"
418
429
  end
@@ -69,6 +69,56 @@ module Opal
69
69
 
70
70
  def compile
71
71
  sexp = s(:send, lhs, :=~, rhs)
72
+ # Handle named matches like: /(?<abc>b)/ =~ 'b'
73
+ if lhs.type == :regexp && lhs.children.first.type == :str
74
+ re = lhs.children.first.children.first
75
+ names = re.scan(/\(\?<([^>]*)>/).flatten.map(&:to_sym)
76
+ unless names.empty?
77
+ # $m3names = $~ ? $~.named_captures : {}
78
+ names_def = s(:lvasgn, :$m3names,
79
+ s(:if,
80
+ s(:gvar, :$~),
81
+ s(:send, s(:gvar, :$~), :named_captures),
82
+ s(:hash)
83
+ )
84
+ )
85
+
86
+ names = names.map do |name|
87
+ # abc = $m3names[:abc]
88
+ s(:lvasgn, name,
89
+ s(:send,
90
+ s(:lvar, :$m3names),
91
+ :[],
92
+ s(:sym, name)
93
+ )
94
+ )
95
+ end
96
+
97
+ if stmt?
98
+ # We don't care about a return value of this one, so we
99
+ # ignore it and just assign the local variables.
100
+ #
101
+ # (/(?<abc>b)/ =~ 'f')
102
+ # $m3names = $~ ? $~.named_captures : {}
103
+ # abc = $m3names[:abc]
104
+ sexp = s(:begin, sexp, names_def, *names)
105
+ else
106
+ # We actually do care about a return value, so we must
107
+ # keep it saved.
108
+ #
109
+ # $m3tmp = (/(?<abc>b)/ =~ 'f')
110
+ # $m3names = $~ ? $~.named_captures : {}
111
+ # abc = $m3names[:abc]
112
+ # $m3tmp
113
+ sexp = s(:begin,
114
+ s(:lvasgn, :$m3tmp, sexp),
115
+ names_def,
116
+ *names,
117
+ s(:lvar, :$m3tmp)
118
+ )
119
+ end
120
+ end
121
+ end
72
122
  push process(sexp, @level)
73
123
  end
74
124
  end
@@ -13,23 +13,32 @@ module Opal
13
13
  name, base = name_and_base
14
14
  helper :klass
15
15
 
16
- line " var self = $klass($base, $super, '#{name}');"
17
- in_scope do
18
- scope.name = name
19
- compile_body
20
- end
21
-
22
- if await_encountered
23
- await_begin = '(await '
24
- await_end = ')'
25
- async = 'async '
26
- parent.await_encountered = true
16
+ if body.nil?
17
+ # Simplified compile for empty body
18
+ if stmt?
19
+ unshift '$klass(', base, ', ', super_code, ", '#{name}')"
20
+ else
21
+ unshift '($klass(', base, ', ', super_code, ", '#{name}'), nil)"
22
+ end
27
23
  else
28
- await_begin, await_end, async = '', '', ''
24
+ line " var self = $klass($base, $super, '#{name}');"
25
+ in_scope do
26
+ scope.name = name
27
+ compile_body
28
+ end
29
+
30
+ if await_encountered
31
+ await_begin = '(await '
32
+ await_end = ')'
33
+ async = 'async '
34
+ parent.await_encountered = true
35
+ else
36
+ await_begin, await_end, async = '', '', ''
37
+ end
38
+
39
+ unshift "#{await_begin}(#{async}function($base, $super#{', $parent_nesting' if @define_nesting}) {"
40
+ line '})(', base, ', ', super_code, "#{', ' + scope.nesting if @define_nesting})#{await_end}"
29
41
  end
30
-
31
- unshift "#{await_begin}(#{async}function($base, $super, $parent_nesting) {"
32
- line '})(', base, ', ', super_code, ", $nesting)#{await_end}"
33
42
  end
34
43
 
35
44
  def super_code
@@ -12,12 +12,17 @@ module Opal
12
12
  def compile
13
13
  if magical_data_const?
14
14
  push('$__END__')
15
+ elsif optimized_access?
16
+ helper :"#{name}"
17
+ push "$#{name}"
18
+ elsif const_scope == s(:cbase)
19
+ push "#{top_scope.absolute_const}('#{name}')"
15
20
  elsif const_scope
16
- push '$$$(', recv(const_scope), ", '#{name}')"
21
+ push "#{top_scope.absolute_const}(", recv(const_scope), ", '#{name}')"
17
22
  elsif compiler.eval?
18
- push "$$($nesting, '#{name}')"
23
+ push "#{scope.relative_access}('#{name}')"
19
24
  else
20
- push "$$($nesting, '#{name}')"
25
+ push "#{scope.relative_access}('#{name}')"
21
26
  end
22
27
  end
23
28
 
@@ -30,6 +35,17 @@ module Opal
30
35
  def magical_data_const?
31
36
  const_scope.nil? && name == :DATA && compiler.eof_content
32
37
  end
38
+
39
+ OPTIMIZED_ACCESS_CONSTS = %i[
40
+ BasicObject Object Module Class Opal Kernel NilClass
41
+ ].freeze
42
+
43
+ # For a certain case of calls like `::Opal.coerce_to?` we can
44
+ # optimize the calls. We can be sure they are defined from the
45
+ # beginning.
46
+ def optimized_access?
47
+ const_scope == s(:cbase) && OPTIMIZED_ACCESS_CONSTS.include?(name)
48
+ end
33
49
  end
34
50
 
35
51
  # ::CONST
@@ -48,10 +64,12 @@ module Opal
48
64
  children :base, :name, :value
49
65
 
50
66
  def compile
67
+ helper :const_set
68
+
51
69
  if base
52
- push 'Opal.const_set(', expr(base), ", '#{name}', ", expr(value), ')'
70
+ push '$const_set(', expr(base), ", '#{name}', ", expr(value), ')'
53
71
  else
54
- push "Opal.const_set($nesting[0], '#{name}', ", expr(value), ')'
72
+ push "$const_set(#{scope.nesting}[0], '#{name}', ", expr(value), ')'
55
73
  end
56
74
  end
57
75
  end
@@ -29,7 +29,7 @@ module Opal
29
29
 
30
30
  compile_block_arg
31
31
 
32
- add_temp 'self = this'
32
+ add_temp 'self = this' if @define_self
33
33
 
34
34
  compile_arity_check
35
35
 
@@ -44,50 +44,47 @@ module Opal
44
44
  end
45
45
  end
46
46
 
47
- # There are some special utf8 chars that can be used as valid JS
48
- # identifiers, some examples:
49
- #
50
- # utf8_pond = 'ⵌ'
51
- # utf8_question = 'ʔ̣'
52
- # utf8_exclamation 'ǃ'
53
- #
54
- # For now we're just using $$, to maintain compatibility with older IEs.
55
- function_name = valid_name?(mid) ? " $$#{mid}" : ''
56
-
57
47
  unshift ') {'
58
48
  unshift(inline_params)
59
- unshift "function#{function_name}("
49
+ unshift "function #{scope_name}("
60
50
  if await_encountered
61
51
  unshift "async "
62
52
  end
63
- unshift "#{scope_name} = " if scope_name
64
53
  line '}'
65
54
 
66
- push ", #{scope_name}.$$arity = #{arity}"
55
+ blockopts = []
56
+
57
+ blockopts << "$$arity: #{arity}"
67
58
 
68
59
  if compiler.arity_check?
69
- push ", #{scope_name}.$$parameters = #{parameters_code}"
60
+ blockopts << "$$parameters: #{parameters_code}"
70
61
  end
71
62
 
72
63
  if compiler.parse_comments?
73
- push ", #{scope_name}.$$comments = #{comments_code}"
64
+ blockopts << "$$comments: #{comments_code}"
74
65
  end
75
66
 
76
67
  if compiler.enable_source_location?
77
- push ", #{scope_name}.$$source_location = #{source_location}"
68
+ blockopts << "$$source_location: #{source_location}"
69
+ end
70
+
71
+ if blockopts.length == 1
72
+ push ", #{arity}"
73
+ elsif blockopts.length > 1
74
+ push ', {', blockopts.join(', '), '}'
78
75
  end
79
76
 
80
77
  wrap_with_definition
78
+
79
+ scope.nesting if @define_nesting
80
+ scope.relative_access if @define_relative_access
81
81
  end
82
82
 
83
83
  def wrap_with_definition
84
- wrap "Opal.def(self, '$#{mid}', ", ')'
84
+ helper :def
85
+ wrap "$def(#{scope.self}, '$#{mid}', ", ')'
85
86
 
86
- if expr?
87
- wrap '(', ", nil) && '#{mid}'"
88
- else
89
- unshift "\n#{current_indent}"
90
- end
87
+ unshift "\n#{current_indent}" unless expr?
91
88
  end
92
89
 
93
90
  def comments_code
@@ -107,7 +107,7 @@ module Opal
107
107
  recv_tmp = scope.new_temp
108
108
  push "(#{recv_tmp} = ", recv_code, ", #{recv_tmp}) && "
109
109
  else
110
- recv_tmp = 'self'
110
+ recv_tmp = scope.self
111
111
  end
112
112
 
113
113
  recv_value_tmp = scope.new_temp
@@ -139,7 +139,7 @@ module Opal
139
139
  # we can't tell if it was the user that put nil and made the ivar #defined?
140
140
  # or not.
141
141
  tmp = scope.new_temp
142
- push "(#{tmp} = self['#{name}'], #{tmp} != null && #{tmp} !== nil)"
142
+ push "(#{tmp} = #{scope.self}['#{name}'], #{tmp} != null && #{tmp} !== nil)"
143
143
 
144
144
  tmp
145
145
  end
@@ -165,12 +165,12 @@ module Opal
165
165
  const_tmp = scope.new_temp
166
166
 
167
167
  if const_scope.nil?
168
- push "(#{const_tmp} = $$($nesting, '#{const_name}', 'skip_raise'))"
168
+ push "(#{const_tmp} = #{scope.relative_access}('#{const_name}', 'skip_raise'))"
169
169
  elsif const_scope == s(:cbase)
170
- push "(#{const_tmp} = $$$('::', '#{const_name}', 'skip_raise'))"
170
+ push "(#{const_tmp} = #{top_scope.absolute_const}('::', '#{const_name}', 'skip_raise'))"
171
171
  else
172
172
  const_scope_tmp = compile_defined(const_scope)
173
- push " && (#{const_tmp} = $$$(#{const_scope_tmp}, '#{const_name}', 'skip_raise'))"
173
+ push " && (#{const_tmp} = #{top_scope.absolute_const}(#{const_scope_tmp}, '#{const_name}', 'skip_raise'))"
174
174
  end
175
175
  const_tmp
176
176
  end
@@ -11,7 +11,7 @@ module Opal
11
11
 
12
12
  def compile
13
13
  children.each do |child|
14
- line "Opal.udef(self, '$' + ", expr(child), ');'
14
+ line "Opal.udef(#{scope.self}, '$' + ", expr(child), ');'
15
15
  end
16
16
  end
17
17
  end
@@ -31,7 +31,7 @@ module Opal
31
31
  push '$alias_gvar(', new_name_str, ', ', old_name_str, ')'
32
32
  when :dsym, :sym # This is a method alias: alias a b
33
33
  helper :alias
34
- push '$alias(self, ', expr(new_name), ', ', expr(old_name), ')'
34
+ push "$alias(#{scope.self}, ", expr(new_name), ', ', expr(old_name), ')'
35
35
  else # Nothing else is available, but just in case, drop an error
36
36
  error "Opal doesn't know yet how to alias with #{new_name.type}"
37
37
  end
@@ -9,12 +9,9 @@ module Opal
9
9
  children :recvr, :mid, :inline_args, :stmts
10
10
 
11
11
  def wrap_with_definition
12
- unshift 'Opal.defs(', expr(recvr), ", '$#{mid}', "
12
+ helper :defs
13
+ unshift '$defs(', expr(recvr), ", '$#{mid}', "
13
14
  push ')'
14
-
15
- if expr?
16
- wrap '(', ", nil) && '#{mid}'"
17
- end
18
15
  end
19
16
  end
20
17
  end
@@ -52,23 +52,11 @@ module Opal
52
52
  [fragment('$truthy('), expr(sexp), fragment(')')]
53
53
  end
54
54
 
55
- def js_falsy(sexp)
56
- if sexp.type == :send
57
- mid = sexp.children[1]
58
- if mid == :block_given?
59
- scope.uses_block!
60
- return "#{scope.block_name} === nil"
61
- end
62
- end
63
-
64
- helper :falsy
65
- [fragment('$falsy('), expr(sexp), fragment(')')]
66
- end
67
-
68
55
  def js_truthy_optimize(sexp)
69
- if sexp.type == :send
70
- mid = sexp.children[1]
71
- receiver_handler_class = (receiver = sexp.children[0]) && compiler.handlers[receiver.type]
56
+ case sexp.type
57
+ when :send
58
+ receiver, mid, *args = *sexp
59
+ receiver_handler_class = receiver && compiler.handlers[receiver.type]
72
60
 
73
61
  # Only operator calls on the truthy_optimize? node classes should be optimized.
74
62
  # Monkey patch method calls might return 'self'/aka a bridged instance and need
@@ -78,8 +66,50 @@ module Opal
78
66
  receiver_handler_class.truthy_optimize?
79
67
 
80
68
  if allow_optimization_on_type ||
81
- mid == :block_given? ||
82
- mid == :"=="
69
+ mid == :block_given?
70
+ expr(sexp)
71
+ elsif args.count == 1
72
+ case mid
73
+ when :==
74
+ helper :eqeq
75
+ compiler.method_calls << mid
76
+ [fragment('$eqeq('), expr(receiver), fragment(', '), expr(args.first), fragment(')')]
77
+ when :===
78
+ helper :eqeqeq
79
+ compiler.method_calls << mid
80
+ [fragment('$eqeqeq('), expr(receiver), fragment(', '), expr(args.first), fragment(')')]
81
+ when :!=
82
+ helper :neqeq
83
+ compiler.method_calls << mid
84
+ [fragment('$neqeq('), expr(receiver), fragment(', '), expr(args.first), fragment(')')]
85
+ end
86
+ elsif args.count == 0
87
+ case mid
88
+ when :!
89
+ helper :not
90
+ compiler.method_calls << mid
91
+ [fragment('$not('), expr(receiver), fragment(')')]
92
+ end
93
+ end
94
+ when :begin
95
+ if sexp.children.count == 1
96
+ js_truthy_optimize(sexp.children.first)
97
+ end
98
+ when :if
99
+ _test, true_body, false_body = *sexp
100
+ if true_body == s(:true)
101
+ # Ensure we recurse the js_truthy call on the `false_body` of the if `expr`.
102
+ # This transforms an expression like:
103
+ #
104
+ # $truthy($truthy(a) || b)
105
+ #
106
+ # Into:
107
+ #
108
+ # $truthy(a) || $truthy(b)
109
+ sexp.meta[:do_js_truthy_on_false_body] = true
110
+ expr(sexp)
111
+ elsif false_body == s(:false)
112
+ sexp.meta[:do_js_truthy_on_true_body] = true
83
113
  expr(sexp)
84
114
  end
85
115
  end