opal 1.5.1 → 1.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +4 -0
  3. data/.github/workflows/build.yml +17 -3
  4. data/HACKING.md +23 -0
  5. data/README.md +3 -3
  6. data/UNRELEASED.md +47 -0
  7. data/benchmark/run.rb +1 -0
  8. data/docs/compiled_ruby.md +8 -0
  9. data/docs/compiler.md +1 -1
  10. data/docs/compiler_directives.md +1 -1
  11. data/docs/getting_started.md +17 -0
  12. data/docs/headless_chrome.md +1 -1
  13. data/docs/index.md +123 -0
  14. data/docs/jquery.md +5 -5
  15. data/docs/templates.md +37 -37
  16. data/docs/unsupported_features.md +0 -4
  17. data/lib/opal/builder.rb +59 -39
  18. data/lib/opal/builder_processors.rb +24 -0
  19. data/lib/opal/builder_scheduler/prefork.rb +262 -0
  20. data/lib/opal/builder_scheduler/sequential.rb +13 -0
  21. data/lib/opal/builder_scheduler.rb +29 -0
  22. data/lib/opal/cache/file_cache.rb +13 -2
  23. data/lib/opal/cli.rb +36 -19
  24. data/lib/opal/cli_options.rb +4 -0
  25. data/lib/opal/cli_runners/chrome.rb +17 -13
  26. data/lib/opal/cli_runners/chrome_cdp_interface.rb +19 -2
  27. data/lib/opal/cli_runners/compiler.rb +1 -1
  28. data/lib/opal/cli_runners/gjs.rb +3 -1
  29. data/lib/opal/cli_runners/mini_racer.rb +5 -3
  30. data/lib/opal/cli_runners/nodejs.rb +3 -3
  31. data/lib/opal/cli_runners/server.rb +13 -28
  32. data/lib/opal/cli_runners/system_runner.rb +5 -3
  33. data/lib/opal/cli_runners.rb +7 -6
  34. data/lib/opal/compiler.rb +25 -2
  35. data/lib/opal/config.rb +10 -0
  36. data/lib/opal/eof_content.rb +5 -2
  37. data/lib/opal/nodes/args/ensure_kwargs_are_kwargs.rb +2 -6
  38. data/lib/opal/nodes/args/extract_kwarg.rb +3 -4
  39. data/lib/opal/nodes/args/extract_kwargs.rb +3 -1
  40. data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -1
  41. data/lib/opal/nodes/args/extract_kwrestarg.rb +4 -1
  42. data/lib/opal/nodes/args/extract_optarg.rb +1 -1
  43. data/lib/opal/nodes/args/extract_post_arg.rb +1 -1
  44. data/lib/opal/nodes/args/extract_post_optarg.rb +1 -1
  45. data/lib/opal/nodes/args/extract_restarg.rb +2 -2
  46. data/lib/opal/nodes/args/initialize_iterarg.rb +1 -1
  47. data/lib/opal/nodes/args/initialize_shadowarg.rb +1 -1
  48. data/lib/opal/nodes/args/prepare_post_args.rb +4 -2
  49. data/lib/opal/nodes/base.rb +14 -3
  50. data/lib/opal/nodes/call.rb +13 -16
  51. data/lib/opal/nodes/class.rb +3 -1
  52. data/lib/opal/nodes/closure.rb +250 -0
  53. data/lib/opal/nodes/def.rb +7 -11
  54. data/lib/opal/nodes/definitions.rb +4 -2
  55. data/lib/opal/nodes/if.rb +12 -2
  56. data/lib/opal/nodes/iter.rb +11 -17
  57. data/lib/opal/nodes/logic.rb +15 -63
  58. data/lib/opal/nodes/module.rb +3 -1
  59. data/lib/opal/nodes/rescue.rb +23 -15
  60. data/lib/opal/nodes/scope.rb +7 -1
  61. data/lib/opal/nodes/top.rb +27 -4
  62. data/lib/opal/nodes/while.rb +42 -26
  63. data/lib/opal/nodes.rb +1 -0
  64. data/lib/opal/os.rb +59 -0
  65. data/lib/opal/rewriter.rb +2 -0
  66. data/lib/opal/rewriters/returnable_logic.rb +14 -0
  67. data/lib/opal/rewriters/thrower_finder.rb +90 -0
  68. data/lib/opal/simple_server.rb +12 -6
  69. data/lib/opal/source_map/file.rb +4 -3
  70. data/lib/opal/source_map/map.rb +9 -1
  71. data/lib/opal/util.rb +1 -1
  72. data/lib/opal/version.rb +1 -1
  73. data/opal/corelib/array.rb +68 -3
  74. data/opal/corelib/basic_object.rb +1 -0
  75. data/opal/corelib/comparable.rb +1 -1
  76. data/opal/corelib/complex.rb +1 -0
  77. data/opal/corelib/constants.rb +2 -2
  78. data/opal/corelib/enumerable.rb +4 -2
  79. data/opal/corelib/enumerator/chain.rb +4 -0
  80. data/opal/corelib/enumerator/generator.rb +5 -3
  81. data/opal/corelib/enumerator/lazy.rb +3 -1
  82. data/opal/corelib/enumerator/yielder.rb +2 -4
  83. data/opal/corelib/enumerator.rb +3 -1
  84. data/opal/corelib/error/errno.rb +3 -1
  85. data/opal/corelib/error.rb +13 -2
  86. data/opal/corelib/hash.rb +39 -1
  87. data/opal/corelib/io.rb +1 -1
  88. data/opal/corelib/kernel.rb +56 -5
  89. data/opal/corelib/module.rb +60 -4
  90. data/opal/corelib/proc.rb +8 -5
  91. data/opal/corelib/rational.rb +1 -0
  92. data/opal/corelib/regexp.rb +15 -1
  93. data/opal/corelib/runtime.js +307 -238
  94. data/opal/corelib/string/encoding.rb +0 -6
  95. data/opal/corelib/string.rb +28 -7
  96. data/opal/corelib/time.rb +5 -2
  97. data/opal/corelib/unsupported.rb +2 -14
  98. data/opal.gemspec +2 -2
  99. data/spec/filters/bugs/delegate.rb +11 -0
  100. data/spec/filters/bugs/kernel.rb +1 -3
  101. data/spec/filters/bugs/language.rb +3 -23
  102. data/spec/filters/bugs/method.rb +0 -1
  103. data/spec/filters/bugs/module.rb +0 -3
  104. data/spec/filters/bugs/proc.rb +0 -3
  105. data/spec/filters/bugs/set.rb +4 -16
  106. data/spec/filters/bugs/unboundmethod.rb +0 -2
  107. data/spec/filters/unsupported/array.rb +0 -58
  108. data/spec/filters/unsupported/freeze.rb +8 -192
  109. data/spec/filters/unsupported/hash.rb +0 -25
  110. data/spec/filters/unsupported/kernel.rb +0 -1
  111. data/spec/filters/unsupported/privacy.rb +17 -0
  112. data/spec/lib/builder_spec.rb +14 -0
  113. data/spec/lib/cli_runners/server_spec.rb +2 -3
  114. data/spec/lib/cli_spec.rb +15 -1
  115. data/spec/lib/compiler_spec.rb +1 -1
  116. data/spec/opal/core/language/DATA/characters_support_crlf_spec.rb +9 -0
  117. data/spec/opal/core/language/DATA/multiple___END___crlf_spec.rb +10 -0
  118. data/spec/opal/core/language/if_spec.rb +13 -0
  119. data/spec/opal/core/language/safe_navigator_spec.rb +10 -0
  120. data/spec/opal/core/module_spec.rb +8 -0
  121. data/spec/ruby_specs +2 -1
  122. data/stdlib/await.rb +44 -7
  123. data/stdlib/delegate.rb +427 -6
  124. data/stdlib/headless_chrome.rb +6 -2
  125. data/stdlib/nodejs/file.rb +2 -1
  126. data/stdlib/opal-parser.rb +1 -1
  127. data/stdlib/opal-platform.rb +1 -1
  128. data/stdlib/opal-replutils.rb +5 -3
  129. data/stdlib/promise.rb +3 -0
  130. data/stdlib/rbconfig.rb +4 -1
  131. data/stdlib/ruby2_keywords.rb +60 -0
  132. data/stdlib/set.rb +21 -0
  133. data/tasks/performance.rake +41 -35
  134. data/tasks/releasing.rake +1 -0
  135. data/tasks/testing/mspec_special_calls.rb +1 -0
  136. data/tasks/testing.rake +13 -12
  137. data/test/nodejs/test_await.rb +39 -1
  138. data/test/nodejs/test_file.rb +3 -2
  139. metadata +37 -22
  140. data/docs/faq.md +0 -17
  141. data/lib/opal/rewriters/break_finder.rb +0 -36
  142. data/spec/opal/core/kernel/freeze_spec.rb +0 -15
@@ -3,6 +3,7 @@
3
3
  require 'shellwords'
4
4
  require 'opal/paths'
5
5
  require 'opal/cli_runners/system_runner'
6
+ require 'opal/os'
6
7
 
7
8
  module Opal
8
9
  module CliRunners
@@ -39,10 +40,9 @@ module Opal
39
40
 
40
41
  # Ensure stdlib node_modules is among NODE_PATHs
41
42
  def self.node_modules
42
- npsep = Gem.win_platform? ? ';' : ':'
43
- ENV['NODE_PATH'].to_s.split(npsep).tap do |paths|
43
+ ENV['NODE_PATH'].to_s.split(OS.env_sep).tap do |paths|
44
44
  paths << NODE_PATH unless paths.include? NODE_PATH
45
- end.join(npsep)
45
+ end.join(OS.env_sep)
46
46
  end
47
47
 
48
48
  class MissingNodeJS < RunnerError
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'opal/simple_server'
4
+
3
5
  module Opal
4
6
  module CliRunners
5
7
  class Server
@@ -11,9 +13,8 @@ module Opal
11
13
 
12
14
  def initialize(data)
13
15
  options = data[:options] || {}
14
- builder = data[:builder]
16
+ @builder = data[:builder]
15
17
 
16
- @code = builder.to_s + "\n" + builder.source_map.to_data_uri_comment
17
18
  @argv = data[:argv] || []
18
19
 
19
20
  @output = data[:output] || $stdout
@@ -25,7 +26,7 @@ module Opal
25
26
  @static_folder = File.expand_path(@static_folder) if @static_folder
26
27
  end
27
28
 
28
- attr_reader :output, :port, :server, :static_folder, :code, :argv
29
+ attr_reader :output, :port, :server, :static_folder, :builder, :argv
29
30
 
30
31
  def run
31
32
  unless argv.empty?
@@ -35,7 +36,7 @@ module Opal
35
36
  require 'rack'
36
37
  require 'logger'
37
38
 
38
- app = build_app(code)
39
+ app = build_app(builder)
39
40
 
40
41
  @server = Rack::Server.start(
41
42
  app: app,
@@ -49,8 +50,8 @@ module Opal
49
50
  nil
50
51
  end
51
52
 
52
- def build_app(source)
53
- app = App.new(source)
53
+ def build_app(builder)
54
+ app = App.new(builder: builder, main: 'cli-runner')
54
55
 
55
56
  if static_folder
56
57
  not_found = [404, {}, []]
@@ -65,30 +66,14 @@ module Opal
65
66
  app
66
67
  end
67
68
 
68
- class App
69
- def initialize(source)
70
- @source = source
69
+ class App < SimpleServer
70
+ def initialize(options = {})
71
+ @builder = options.fetch(:builder)
72
+ super
71
73
  end
72
74
 
73
- BODY = <<-HTML
74
- <!doctype html>
75
- <html>
76
- <head>
77
- <meta charset="utf-8"/>
78
- <script src="/cli_runner.js"></script>
79
- </head>
80
- </html>
81
- HTML
82
-
83
- def call(env)
84
- case env['PATH_INFO']
85
- when '/'
86
- [200, { 'Content-Type' => 'text/html' }, [BODY]]
87
- when '/cli_runner.js'
88
- [200, { 'Content-Type' => 'text/javascript' }, [@source]]
89
- else
90
- [404, {}, ['not found']]
91
- end
75
+ def builder(_)
76
+ @builder.call
92
77
  end
93
78
  end
94
79
  end
@@ -13,7 +13,7 @@ require 'tempfile'
13
13
  # @yieldreturn command [Array<String>] the command to be used in the system call
14
14
  SystemRunner = ->(data, &block) {
15
15
  options = data[:options] || {}
16
- builder = data.fetch(:builder)
16
+ builder = data.fetch(:builder).call
17
17
  output = data.fetch(:output)
18
18
 
19
19
  env = options.fetch(:env, {})
@@ -23,11 +23,13 @@ SystemRunner = ->(data, &block) {
23
23
  # Temporary issue with UTF-8, Base64 and source maps
24
24
  code += "\n" + builder.source_map.to_data_uri_comment unless RUBY_ENGINE == 'opal'
25
25
 
26
+ ext = builder.output_extension
27
+
26
28
  tempfile =
27
29
  if debug
28
- File.new('opal-nodejs-runner.js', 'w')
30
+ File.new("opal-nodejs-runner.#{ext}", 'wb')
29
31
  else
30
- Tempfile.new('opal-system-runner-')
32
+ Tempfile.new(['opal-system-runner', ".#{ext}"], mode: File::BINARY)
31
33
  end
32
34
 
33
35
  tempfile.write code
@@ -10,7 +10,8 @@ module Opal
10
10
  # - `output`: an IO-like object responding to `#write` and `#puts`
11
11
  # - `argv`: is the arguments vector coming from the CLI that is being
12
12
  # forwarded to the program
13
- # - `builder`: the current instance of Opal::Builder
13
+ # - `builder`: a proc returning a new instance of Opal::Builder so it
14
+ # can be re-created and pick up the most up-to-date sources
14
15
  #
15
16
  # Runners can be registered using `#register_runner(name, runner)`.
16
17
  #
@@ -21,7 +22,7 @@ module Opal
21
22
  @register = {}
22
23
 
23
24
  def self.[](name)
24
- @register[name.to_sym]
25
+ @register[name.to_sym]&.call
25
26
  end
26
27
 
27
28
  # @private
@@ -44,10 +45,10 @@ module Opal
44
45
  def self.register_runner(name, runner, path = nil)
45
46
  autoload runner, path if path
46
47
 
47
- if runner.respond_to?(:call)
48
- self[name] = runner
48
+ if runner.respond_to? :call
49
+ self[name] = -> { runner }
49
50
  else
50
- self[name] = ->(data) { const_get(runner).call(data) }
51
+ self[name] = -> { const_get(runner) }
51
52
  end
52
53
 
53
54
  nil
@@ -55,7 +56,7 @@ module Opal
55
56
 
56
57
  # Alias a runner name
57
58
  def self.alias_runner(new_name, old_name)
58
- self[new_name.to_sym] = self[old_name.to_sym]
59
+ self[new_name.to_sym] = -> { self[old_name.to_sym] }
59
60
 
60
61
  nil
61
62
  end
data/lib/opal/compiler.rb CHANGED
@@ -7,6 +7,7 @@ require 'opal/nodes'
7
7
  require 'opal/eof_content'
8
8
  require 'opal/errors'
9
9
  require 'opal/magic_comments'
10
+ require 'opal/nodes/closure'
10
11
 
11
12
  module Opal
12
13
  # Compile a string of ruby code into javascript.
@@ -46,6 +47,8 @@ module Opal
46
47
  # compiler.source_map # => #<SourceMap:>
47
48
  #
48
49
  class Compiler
50
+ include Nodes::Closure::CompilerSupport
51
+
49
52
  # Generated code gets indented with two spaces on each scope
50
53
  INDENT = ' '
51
54
 
@@ -137,11 +140,23 @@ module Opal
137
140
  # Prepare the code for future requires
138
141
  compiler_option :requirable, default: false, as: :requirable?
139
142
 
143
+ # @!method load?
144
+ #
145
+ # Instantly load a requirable module
146
+ compiler_option :load, default: false, as: :load?
147
+
140
148
  # @!method esm?
141
149
  #
142
- # Wrap compiler result as self contained ES6 module
150
+ # Encourage ESM semantics, eg. exporting run result
143
151
  compiler_option :esm, default: false, as: :esm?
144
152
 
153
+ # @!method no_export?
154
+ #
155
+ # Don't export this compile, even if ESM mode is enabled. We use
156
+ # this internally in CLI, so that even if ESM output is desired,
157
+ # we would only have one default export.
158
+ compiler_option :no_export, default: false, as: :no_export?
159
+
145
160
  # @!method inline_operators?
146
161
  #
147
162
  # are operators compiled inline
@@ -154,6 +169,11 @@ module Opal
154
169
  # Adds source_location for every method definition
155
170
  compiler_option :enable_source_location, default: false, as: :enable_source_location?
156
171
 
172
+ # @!method enable_file_source_embed?
173
+ #
174
+ # Embeds source code along compiled files
175
+ compiler_option :enable_file_source_embed, default: false, as: :enable_file_source_embed?
176
+
157
177
  # @!method use_strict?
158
178
  #
159
179
  # Enables JavaScript's strict mode (i.e., adds 'use strict'; statement)
@@ -223,6 +243,9 @@ module Opal
223
243
  # Magic comment flags extracted from the leading comments
224
244
  attr_reader :magic_comments
225
245
 
246
+ # Access the source code currently processed
247
+ attr_reader :source
248
+
226
249
  # Set if some rewritter caused a dynamic cache result, meaning it's not
227
250
  # fit to be cached
228
251
  attr_accessor :dynamic_cache_result
@@ -558,7 +581,7 @@ module Opal
558
581
  returns(true_body),
559
582
  returns(false_body)
560
583
  ]
561
- )
584
+ ).tap { |s| s.meta[:returning] = true }
562
585
  else
563
586
  if sexp.type == :send && sexp.children[1] == :debugger
564
587
  # debugger is a statement, so it doesn't return a value
data/lib/opal/config.rb CHANGED
@@ -139,6 +139,16 @@ module Opal
139
139
  # @return [true, false]
140
140
  config_option :source_map_enabled, true
141
141
 
142
+ # Enable source location embedded for methods and procs.
143
+ #
144
+ # @return [true, false]
145
+ config_option :enable_source_location, false, compiler_option: :enable_source_location
146
+
147
+ # Enable embedding source code to be read by applications.
148
+ #
149
+ # @return [true, false]
150
+ config_option :enable_file_source_embed, false, compiler_option: :enable_file_source_embed
151
+
142
152
  # A set of stubbed files that will be marked as loaded and skipped during
143
153
  # compilation. The value is expected to be mutated but it's ok to replace
144
154
  # it.
@@ -15,9 +15,12 @@ module Opal
15
15
  eof_content = @source[last_token_position..-1]
16
16
  return nil unless eof_content
17
17
 
18
- eof_content = eof_content.lines.drop_while { |line| line == "\n" }
18
+ # On Windows token position is off a bit, because Parser does not seem to compensate for \r\n
19
+ # The first eof_content line on Windows may be for example "end\r\n"
20
+ # Must match for it and \r\n and \n
21
+ eof_content = eof_content.lines.drop_while { |line| /\A.*\r?\n?\z/.match?(line) && !line.start_with?('__END__') }
19
22
 
20
- if eof_content[0] == "__END__\n"
23
+ if /\A__END__\r?\n?\z/.match?(eof_content[0])
21
24
  eof_content = eof_content[1..-1] || []
22
25
  eof_content.join
23
26
  elsif eof_content == ['__END__']
@@ -14,13 +14,9 @@ module Opal
14
14
  handle :ensure_kwargs_are_kwargs
15
15
 
16
16
  def compile
17
- helper :hash2
17
+ helper :ensure_kwargs
18
18
 
19
- line 'if ($kwargs == null) {'
20
- line ' $kwargs = $hash2([], {});'
21
- line '} else if (!$kwargs.$$is_hash) {'
22
- line " throw Opal.ArgumentError.$new('expected kwargs');"
23
- line '}'
19
+ push '$kwargs = $ensure_kwargs($kwargs)'
24
20
  end
25
21
  end
26
22
  end
@@ -21,10 +21,9 @@ module Opal
21
21
 
22
22
  add_temp lvar_name
23
23
 
24
- line "if (!Opal.hasOwnProperty.call($kwargs.$$smap, '#{key_name}')) {"
25
- line " throw Opal.ArgumentError.$new('missing keyword: #{key_name}');"
26
- line '}'
27
- line "#{lvar_name} = $kwargs.$$smap[#{key_name.to_s.inspect}];"
24
+ helper :get_kwarg
25
+
26
+ push "#{lvar_name} = $get_kwarg($kwargs, #{key_name.to_s.inspect})"
28
27
  end
29
28
  end
30
29
  end
@@ -20,7 +20,9 @@ module Opal
20
20
  def compile
21
21
  add_temp '$kwargs'
22
22
 
23
- line '$kwargs = Opal.extract_kwargs($post_args)'
23
+ helper :extract_kwargs
24
+
25
+ push '$kwargs = $extract_kwargs($post_args)'
24
26
  end
25
27
  end
26
28
  end
@@ -25,7 +25,7 @@ module Opal
25
25
 
26
26
  return if default_value.children[1] == :undefined
27
27
 
28
- line "if (#{lvar_name} == null) #{lvar_name} = ", expr(default_value)
28
+ push "if (#{lvar_name} == null) #{lvar_name} = ", expr(default_value)
29
29
  end
30
30
  end
31
31
  end
@@ -21,7 +21,10 @@ module Opal
21
21
  name = self.name || '$kw_rest_arg'
22
22
 
23
23
  add_temp name
24
- line "#{name} = Opal.kwrestargs($kwargs, #{used_kwargs});"
24
+
25
+ helper :kwrestargs
26
+
27
+ push "#{name} = $kwrestargs($kwargs, #{used_kwargs})"
25
28
  end
26
29
 
27
30
  def used_kwargs
@@ -25,7 +25,7 @@ module Opal
25
25
  def compile
26
26
  return if default_value.children[1] == :undefined
27
27
 
28
- line "if (#{name} == null) #{name} = ", expr(default_value), ";"
28
+ push "if (#{name} == null) #{name} = ", expr(default_value)
29
29
  end
30
30
  end
31
31
  end
@@ -17,7 +17,7 @@ module Opal
17
17
 
18
18
  line "#{name} = $post_args.shift();"
19
19
 
20
- line "if (#{name} == null) #{name} = nil;"
20
+ push "if (#{name} == null) #{name} = nil"
21
21
  end
22
22
  end
23
23
  end
@@ -28,7 +28,7 @@ module Opal
28
28
 
29
29
  return if default_value.children[1] == :undefined
30
30
 
31
- line "if (#{name} == null) #{name} = ", expr(default_value), ";"
31
+ push "if (#{name} == null) #{name} = ", expr(default_value)
32
32
  end
33
33
  end
34
34
  end
@@ -27,9 +27,9 @@ module Opal
27
27
 
28
28
  if args_to_keep == 0
29
29
  # no post-args, we are free to grab everything
30
- line "#{name} = $post_args;"
30
+ push "#{name} = $post_args"
31
31
  else
32
- line "#{name} = $post_args.splice(0, $post_args.length - #{args_to_keep});"
32
+ push "#{name} = $post_args.splice(0, $post_args.length - #{args_to_keep})"
33
33
  end
34
34
  end
35
35
  end
@@ -18,7 +18,7 @@ module Opal
18
18
  children :name
19
19
 
20
20
  def compile
21
- line "if (#{name} == null) #{name} = nil;"
21
+ push "if (#{name} == null) #{name} = nil"
22
22
  end
23
23
  end
24
24
  end
@@ -16,7 +16,7 @@ module Opal
16
16
  def compile
17
17
  scope.locals << name
18
18
  scope.add_arg(name)
19
- line "#{name} = nil;"
19
+ push "#{name} = nil"
20
20
  end
21
21
  end
22
22
  end
@@ -14,10 +14,12 @@ module Opal
14
14
  def compile
15
15
  add_temp '$post_args'
16
16
 
17
+ helper :slice
18
+
17
19
  if offset == 0
18
- line "$post_args = Opal.slice.call(arguments)"
20
+ push "$post_args = $slice.call(arguments)"
19
21
  else
20
- line "$post_args = Opal.slice.call(arguments, #{offset})"
22
+ push "$post_args = $slice.call(arguments, #{offset})"
21
23
  end
22
24
  end
23
25
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'opal/nodes/helpers'
4
+ require 'opal/nodes/closure'
4
5
 
5
6
  module Opal
6
7
  module Nodes
7
8
  class Base
8
9
  include Helpers
10
+ include Closure::NodeSupport
9
11
 
10
12
  def self.handlers
11
13
  @handlers ||= {}
@@ -126,6 +128,10 @@ module Opal
126
128
  sexp ? expr(sexp) : 'nil'
127
129
  end
128
130
 
131
+ def expr_or_empty(sexp)
132
+ sexp && sexp.type != :nil ? expr(sexp) : ''
133
+ end
134
+
129
135
  def add_local(name)
130
136
  scope.add_scope_local name.to_sym
131
137
  end
@@ -211,9 +217,14 @@ module Opal
211
217
  end
212
218
 
213
219
  def source_location
214
- file = @sexp.loc.expression.source_buffer.name
215
- file = "<internal:#{file}>" if file.start_with?("corelib/")
216
- file = "<js:#{file}>" if file.end_with?(".js")
220
+ expr = @sexp.loc.expression
221
+ if expr.respond_to? :source_buffer
222
+ file = expr.source_buffer.name
223
+ file = "<internal:#{file}>" if file.start_with?("corelib/")
224
+ file = "<js:#{file}>" if file.end_with?(".js")
225
+ else
226
+ file = "(eval)"
227
+ end
217
228
  line = @sexp.loc.line
218
229
  "['#{file}', #{line}]"
219
230
  end
@@ -3,7 +3,6 @@
3
3
  require 'set'
4
4
  require 'pathname'
5
5
  require 'opal/nodes/base'
6
- require 'opal/rewriters/break_finder'
7
6
 
8
7
  module Opal
9
8
  module Nodes
@@ -64,9 +63,7 @@ module Opal
64
63
  def iter_has_break?
65
64
  return false unless iter
66
65
 
67
- finder = Opal::Rewriters::BreakFinder.new
68
- finder.process(iter)
69
- finder.found_break?
66
+ iter.meta[:has_break]
70
67
  end
71
68
 
72
69
  # Opal has a runtime helper 'Opal.send_method_name' that assigns
@@ -99,10 +96,11 @@ module Opal
99
96
 
100
97
  def default_compile
101
98
  if auto_await?
102
- push 'await '
99
+ push '(await '
103
100
  scope.await_encountered = true
104
101
  end
105
102
 
103
+ push_closure(Closure::SEND) if iter_has_break?
106
104
  if invoke_using_refinement?
107
105
  compile_using_refined_send
108
106
  elsif invoke_using_send?
@@ -110,8 +108,11 @@ module Opal
110
108
  else
111
109
  compile_simple_call_chain
112
110
  end
111
+ pop_closure if iter_has_break?
113
112
 
114
- compile_break_catcher
113
+ if auto_await?
114
+ push ')'
115
+ end
115
116
  end
116
117
 
117
118
  # Compiles method call using `Opal.send`
@@ -184,16 +185,9 @@ module Opal
184
185
  push expr(s(:array, *refinements)), ', '
185
186
  end
186
187
 
187
- def compile_break_catcher
188
- if iter_has_break?
189
- unshift 'return '
190
- unshift '(function(){var $brk = Opal.new_brk(); try {'
191
- line '} catch (err) { if (err === $brk) { return err.$v } else { throw err } }})()'
192
- end
193
- end
194
-
195
188
  def compile_simple_call_chain
196
- push recv(receiver_sexp), method_jsid, '(', expr(arglist), ')'
189
+ compile_receiver
190
+ push method_jsid, '(', expr(arglist), ')'
197
191
  end
198
192
 
199
193
  def splat?
@@ -398,6 +392,9 @@ module Opal
398
392
  # This can be refactored in terms of binding, but it would need 'corelib/binding'
399
393
  # to be required in existing code.
400
394
  add_special :eval do |compile_default|
395
+ # Catch the return throw coming from eval
396
+ thrower(:eval_return)
397
+
401
398
  next compile_default.call if arglist.children.length != 1 || ![s(:self), nil].include?(recvr)
402
399
 
403
400
  scope.nesting
@@ -473,7 +470,7 @@ module Opal
473
470
  def handle_conditional_send
474
471
  # temporary variable that stores method receiver
475
472
  receiver_temp = scope.new_temp
476
- push "#{receiver_temp} = ", expr(recvr)
473
+ push "#{receiver_temp} = ", expr(receiver_sexp)
477
474
 
478
475
  # execute the sexp only if the receiver isn't nil
479
476
  push ", (#{receiver_temp} === nil || #{receiver_temp} == null) ? nil : "
@@ -24,7 +24,9 @@ module Opal
24
24
  line " var self = $klass($base, $super, '#{name}');"
25
25
  in_scope do
26
26
  scope.name = name
27
- compile_body
27
+ in_closure(Closure::MODULE | Closure::JS_FUNCTION) do
28
+ compile_body
29
+ end
28
30
  end
29
31
 
30
32
  if await_encountered