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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e7bea1b676089d0921e603acafc794fe81fb671
|
4
|
+
data.tar.gz: 798d0eef513a0f7a17eb283d810342ffddb64b03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c349f1c93f09a28b2e0c9285008901d985c4196548171318fadcd416e370e9dc2bcbc4d8b1e184b5e4646206e8c64efee28c58d8a4e11a0939eceb21f929912c
|
7
|
+
data.tar.gz: 5af01ed324f7c9f0eec062d465d34e051d47bca3e24e33c72e17e6634a7b87cab060f303b3408a5644763e838c3051d29964f8e6d461408f8a18cd2726ceacfa
|
data/CHANGELOG.md
CHANGED
@@ -26,6 +26,7 @@ Whitespace conventions:
|
|
26
26
|
|
27
27
|
### Added
|
28
28
|
|
29
|
+
- Source maps now include method names
|
29
30
|
- `Module#included_modules` works
|
30
31
|
- Internal runtime cleanup (#1241)
|
31
32
|
- Make it easier to add custom runners for the CLI (#1261)
|
@@ -50,6 +51,7 @@ Whitespace conventions:
|
|
50
51
|
- Super works with define_method blocks
|
51
52
|
- Added support for kwsplats.
|
52
53
|
- Added support for squiggly heredoc.
|
54
|
+
- Implement `Method#parameters` and `Proc#parameters`.
|
53
55
|
|
54
56
|
|
55
57
|
### Changed
|
@@ -57,8 +59,9 @@ Whitespace conventions:
|
|
57
59
|
- Remove deprecation of `Opal::Environment` after popular request
|
58
60
|
- Setting `Opal::Config.dynamic_require_severity` will no longer affect `Opal.dynamic_require_severity` which now needs to be explicitly set if it differs from the default value of `"warning"` (See also the `Opal.dynamic_require_severity` rename below).
|
59
61
|
- The new default for `Opal::Config.dynamic_require_severity` is now `:warning`
|
60
|
-
- `Opal.dynamic_require_severity` and `OPAL_CONFIG` are now merged into `Opal.config.missing_require_severity` (defaults to `error`, the expected ruby behavior) and `Opal.config.unsupported_features_severity` (defaults to `warning`, e.g. a one-time heads up that freezing isn't supported)
|
62
|
+
- `Opal.dynamic_require_severity` and `OPAL_CONFIG` are now merged into `Opal.config.missing_require_severity` (defaults to `error`, the expected ruby behavior) and `Opal.config.unsupported_features_severity` (defaults to `warning`, e.g. a one-time heads up that freezing isn't supported). Added variable `__OPAL_COMPILER_CONFIG__` that contains compiler options that may be used in runtime.
|
61
63
|
- `Hash` instances should now list the string map (`$$smap`) as the first key, making debugging easier (most hashes will just have keys there).
|
64
|
+
- Handle Pathname object in Pathname constructor
|
62
65
|
|
63
66
|
|
64
67
|
### Deprecated
|
@@ -75,6 +78,10 @@ Whitespace conventions:
|
|
75
78
|
|
76
79
|
### Fixed
|
77
80
|
|
81
|
+
- `Pathname#absolute?` and `Pathname#relative?` now work properly
|
82
|
+
- `File::dirname` and `File::basename` are now Rubyspec compliant
|
83
|
+
- `SourceMap::VLQ` patch (#1075)
|
84
|
+
- `Regexp::new` no longer throws error when the expression ends in \\\\
|
78
85
|
- `super` works properly with overwritten alias methods (#1384)
|
79
86
|
- `NoMethodError` does not need a name to be instantiated
|
80
87
|
- `method_added` fix for singleton class cases
|
@@ -106,6 +113,7 @@ Whitespace conventions:
|
|
106
113
|
- Fixed an issue with `"-"` inside the second arg of `String#tr`
|
107
114
|
- Fixed Base64 and enabled specs
|
108
115
|
- Fixed method definition in method body.
|
116
|
+
- Partially implemented `Marshal.load`/`Marshal.dump`. In order to use it require `opal/full`.
|
109
117
|
|
110
118
|
|
111
119
|
### Removed
|
data/lib/opal/compiler.rb
CHANGED
@@ -106,7 +106,7 @@ module Opal
|
|
106
106
|
# @!method dynamic_require_severity
|
107
107
|
#
|
108
108
|
# how to handle dynamic requires (:error, :warning, :ignore)
|
109
|
-
compiler_option :dynamic_require_severity, :
|
109
|
+
compiler_option :dynamic_require_severity, :warning, :valid_values => [:error, :warning, :ignore]
|
110
110
|
|
111
111
|
# @!method requirable?
|
112
112
|
#
|
@@ -148,13 +148,19 @@ module Opal
|
|
148
148
|
def compile
|
149
149
|
@parser = Parser.new
|
150
150
|
|
151
|
-
|
151
|
+
parsed = begin
|
152
|
+
@parser.parse(@source, self.file)
|
153
|
+
rescue => error
|
154
|
+
raise SyntaxError, error.message, error.backtrace
|
155
|
+
end
|
156
|
+
|
157
|
+
@sexp = s(:top, parsed || s(:nil))
|
152
158
|
@eof_content = @parser.lexer.eof_content
|
153
159
|
|
154
160
|
@fragments = process(@sexp).flatten
|
155
161
|
|
156
162
|
@result = @fragments.map(&:code).join('')
|
157
|
-
rescue => error
|
163
|
+
rescue Exception => error
|
158
164
|
message = "An error occurred while compiling: #{self.file}\n#{error.message}"
|
159
165
|
raise error.class, message, error.backtrace
|
160
166
|
end
|
@@ -215,8 +221,8 @@ module Opal
|
|
215
221
|
Sexp.new(parts)
|
216
222
|
end
|
217
223
|
|
218
|
-
def fragment(str, sexp = nil)
|
219
|
-
Fragment.new(str, sexp)
|
224
|
+
def fragment(str, scope, sexp = nil)
|
225
|
+
Fragment.new(str, scope, sexp)
|
220
226
|
end
|
221
227
|
|
222
228
|
# Used to generate a unique id name per file. These are used
|
@@ -320,7 +326,7 @@ module Opal
|
|
320
326
|
# Process the given sexp by creating a node instance, based on its type,
|
321
327
|
# and compiling it to fragments.
|
322
328
|
def process(sexp, level = :expr)
|
323
|
-
return fragment('') if sexp == nil
|
329
|
+
return fragment('', scope) if sexp == nil
|
324
330
|
|
325
331
|
if handler = handlers[sexp.type]
|
326
332
|
return handler.new(sexp, level, self).compile_to_fragments
|
@@ -428,11 +434,11 @@ module Opal
|
|
428
434
|
def handle_block_given_call(sexp)
|
429
435
|
@scope.uses_block!
|
430
436
|
if @scope.block_name
|
431
|
-
fragment("(#{@scope.block_name} !== nil)", sexp)
|
437
|
+
fragment("(#{@scope.block_name} !== nil)", scope, sexp)
|
432
438
|
elsif scope = @scope.find_parent_def and scope.block_name
|
433
|
-
fragment("(#{scope.block_name} !== nil)", sexp)
|
439
|
+
fragment("(#{scope.block_name} !== nil)", scope, sexp)
|
434
440
|
else
|
435
|
-
fragment("false", sexp)
|
441
|
+
fragment("false", scope, sexp)
|
436
442
|
end
|
437
443
|
end
|
438
444
|
end
|
data/lib/opal/fragment.rb
CHANGED
@@ -15,9 +15,10 @@ module Opal
|
|
15
15
|
#
|
16
16
|
# @param code [String] javascript code
|
17
17
|
# @param sexp [Opal::Sexp] sexp used for creating fragment
|
18
|
-
def initialize(code, sexp = nil)
|
18
|
+
def initialize(code, scope, sexp = nil)
|
19
19
|
@code = code.to_s
|
20
20
|
@sexp = sexp
|
21
|
+
@scope = scope
|
21
22
|
end
|
22
23
|
|
23
24
|
# Inspect the contents of this fragment, f("fooo")
|
@@ -25,6 +26,12 @@ module Opal
|
|
25
26
|
"f(#{@code.inspect})"
|
26
27
|
end
|
27
28
|
|
29
|
+
def source_map_name
|
30
|
+
return nil unless @scope
|
31
|
+
def_node = @scope.def? ? @scope : @scope.find_parent_def
|
32
|
+
def_node && def_node.mid
|
33
|
+
end
|
34
|
+
|
28
35
|
# Original line this fragment was created from
|
29
36
|
# @return [Integer, nil]
|
30
37
|
def line
|
@@ -25,7 +25,12 @@ module Opal
|
|
25
25
|
# inline restarg case
|
26
26
|
offset = @sexp.meta[:offset]
|
27
27
|
# restarg value should be taken directly from parameters
|
28
|
-
line "
|
28
|
+
line "var $args_len = arguments.length, $rest_len = $args_len - #{offset};"
|
29
|
+
line "if ($rest_len < 0) { $rest_len = 0; }"
|
30
|
+
line "#{var_name} = new Array($rest_len);"
|
31
|
+
line "for (var $arg_idx = #{offset}; $arg_idx < $args_len; $arg_idx++) {"
|
32
|
+
line " #{var_name}[$arg_idx - #{offset}] = arguments[$arg_idx];"
|
33
|
+
line "}"
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
data/lib/opal/nodes/base.rb
CHANGED
data/lib/opal/nodes/call.rb
CHANGED
@@ -291,6 +291,10 @@ module Opal
|
|
291
291
|
push fragment 'debugger'
|
292
292
|
end
|
293
293
|
|
294
|
+
add_special :__OPAL_COMPILER_CONFIG__ do
|
295
|
+
push fragment "Opal.hash({ arity_check: #{compiler.arity_check?} })"
|
296
|
+
end
|
297
|
+
|
294
298
|
class DependencyResolver
|
295
299
|
def initialize(compiler, sexp)
|
296
300
|
@compiler = compiler
|
data/lib/opal/nodes/def.rb
CHANGED
@@ -12,21 +12,10 @@ module Opal
|
|
12
12
|
|
13
13
|
def extract_block_arg
|
14
14
|
if args.last.is_a?(Sexp) && args.last.type == :blockarg
|
15
|
-
@block_arg = args.pop
|
15
|
+
@block_arg = args.pop[1]
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def argc
|
20
|
-
return @argc if @argc
|
21
|
-
|
22
|
-
@argc = args.length - 1
|
23
|
-
@argc -= 1 if block_arg
|
24
|
-
@argc -= 1 if rest_arg
|
25
|
-
@argc -= keyword_args.size
|
26
|
-
|
27
|
-
@argc
|
28
|
-
end
|
29
|
-
|
30
19
|
def compile
|
31
20
|
extract_block_arg
|
32
21
|
split_args
|
@@ -36,11 +25,7 @@ module Opal
|
|
36
25
|
|
37
26
|
# block name (&block)
|
38
27
|
if block_arg
|
39
|
-
block_name = variable(block_arg
|
40
|
-
end
|
41
|
-
|
42
|
-
if compiler.arity_check?
|
43
|
-
arity_code = arity_check(args, opt_args, rest_arg, keyword_args, block_name, mid)
|
28
|
+
block_name = variable(block_arg).to_sym
|
44
29
|
end
|
45
30
|
|
46
31
|
in_scope do
|
@@ -62,6 +47,12 @@ module Opal
|
|
62
47
|
compile_inline_args
|
63
48
|
compile_post_args
|
64
49
|
|
50
|
+
scope.identify!
|
51
|
+
|
52
|
+
if compiler.arity_check?
|
53
|
+
arity_code = arity_check(mid)
|
54
|
+
end
|
55
|
+
|
65
56
|
scope_name = scope.identity
|
66
57
|
|
67
58
|
compile_block_arg
|
@@ -100,6 +91,12 @@ module Opal
|
|
100
91
|
unshift "#{scope_name} = " if scope_name
|
101
92
|
line "}"
|
102
93
|
|
94
|
+
push ", #{scope_name}.$$arity = #{arity}"
|
95
|
+
|
96
|
+
if compiler.arity_check?
|
97
|
+
push ", #{scope_name}.$$parameters = #{parameters_code}"
|
98
|
+
end
|
99
|
+
|
103
100
|
if recvr
|
104
101
|
unshift 'Opal.defs(', recv(recvr), ", '$#{mid}', "
|
105
102
|
push ')'
|
@@ -130,18 +127,17 @@ module Opal
|
|
130
127
|
end
|
131
128
|
|
132
129
|
# Returns code used in debug mode to check arity of method call
|
133
|
-
def arity_check(
|
130
|
+
def arity_check(mid)
|
134
131
|
meth = mid.to_s.inspect
|
135
132
|
|
136
133
|
arity = args.size - 1
|
137
|
-
arity -= (
|
134
|
+
arity -= (opt_args.size)
|
138
135
|
|
139
|
-
arity -= 1 if
|
136
|
+
arity -= 1 if rest_arg
|
140
137
|
|
141
|
-
arity -= (
|
138
|
+
arity -= (keyword_args.size)
|
142
139
|
|
143
|
-
|
144
|
-
arity = -arity - 1 if !opt.empty? or !kwargs.empty? or splat
|
140
|
+
arity = -arity - 1 if !opt_args.empty? or !keyword_args.empty? or rest_arg
|
145
141
|
|
146
142
|
# $arity will point to our received arguments count
|
147
143
|
aritycode = "var $arity = arguments.length;"
|
@@ -149,10 +145,9 @@ module Opal
|
|
149
145
|
if arity < 0 # splat or opt args
|
150
146
|
min_arity = -(arity + 1)
|
151
147
|
max_arity = args.size - 1
|
152
|
-
# max_arity -= 1 if block_name
|
153
148
|
checks = []
|
154
149
|
checks << "$arity < #{min_arity}" if min_arity > 0
|
155
|
-
checks << "$arity > #{max_arity}" if max_arity and not(
|
150
|
+
checks << "$arity > #{max_arity}" if max_arity and not(rest_arg)
|
156
151
|
aritycode + "if (#{checks.join(' || ')}) { Opal.ac($arity, #{arity}, this, #{meth}); }" if checks.size > 0
|
157
152
|
else
|
158
153
|
aritycode + "if ($arity !== #{arity}) { Opal.ac($arity, #{arity}, this, #{meth}); }"
|
data/lib/opal/nodes/hash.rb
CHANGED
@@ -5,40 +5,101 @@ module Opal
|
|
5
5
|
class HashNode < Base
|
6
6
|
handle :hash
|
7
7
|
|
8
|
-
|
9
|
-
keys, values = [], []
|
8
|
+
attr_accessor :has_kwsplat, :keys, :values
|
10
9
|
|
11
|
-
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@has_kwsplat = false
|
13
|
+
@keys = []
|
14
|
+
@values = []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Splits keys/values/kwsplats
|
18
|
+
#
|
19
|
+
# hash like { **{ nested: 1 }, d: 2 }
|
20
|
+
# is represetned by sexp:
|
21
|
+
# (:hash,
|
22
|
+
# (:kwsplat,
|
23
|
+
# (:hash,
|
24
|
+
# (:sym, :nested),
|
25
|
+
# (:int, 1)
|
26
|
+
# )
|
27
|
+
# ),
|
28
|
+
# (:sym, :d),
|
29
|
+
# (:int, 2),
|
30
|
+
# )
|
31
|
+
# So k/v pairs and kwsplats can be mixed in any order.
|
32
|
+
def extract_kv_pairs_and_kwsplats
|
33
|
+
found_key = false
|
34
|
+
|
35
|
+
children.each do |obj|
|
12
36
|
if obj.type == :kwsplat
|
13
|
-
|
14
|
-
|
15
|
-
kwsplat_keys, kwsplat_values = extract_keys_and_values(kwsplat_pairs)
|
16
|
-
keys.concat(kwsplat_keys)
|
17
|
-
values.concat(kwsplat_values)
|
18
|
-
elsif idx.even?
|
19
|
-
keys << obj
|
20
|
-
else
|
37
|
+
self.has_kwsplat = true
|
38
|
+
elsif found_key
|
21
39
|
values << obj
|
40
|
+
found_key = false
|
41
|
+
else
|
42
|
+
keys << obj
|
43
|
+
found_key = true
|
22
44
|
end
|
23
45
|
end
|
24
46
|
|
25
47
|
[keys, values]
|
26
48
|
end
|
27
49
|
|
28
|
-
def simple_keys?
|
29
|
-
keys.all? { |key| [:sym, :str].include?
|
50
|
+
def simple_keys?
|
51
|
+
keys.all? { |key| [:sym, :str].include?(key.type) }
|
30
52
|
end
|
31
53
|
|
32
54
|
def compile
|
33
|
-
|
55
|
+
extract_kv_pairs_and_kwsplats
|
34
56
|
|
35
|
-
if
|
36
|
-
|
57
|
+
if has_kwsplat
|
58
|
+
compile_merge
|
59
|
+
elsif simple_keys?
|
60
|
+
compile_hash2
|
37
61
|
else
|
38
62
|
compile_hash
|
39
63
|
end
|
40
64
|
end
|
41
65
|
|
66
|
+
# Compiles hashes containing kwsplats inside.
|
67
|
+
# hash like { **{ nested: 1 }, a: 1, **{ nested: 2} }
|
68
|
+
# should be compiled to
|
69
|
+
# { nested: 1}.merge(a: 1).merge(nested: 2)
|
70
|
+
# Each kwsplat overrides previosly defined keys
|
71
|
+
# Hash k/v pairs override previously defined kwsplat values
|
72
|
+
def compile_merge
|
73
|
+
helper :hash
|
74
|
+
|
75
|
+
result, seq = [], []
|
76
|
+
|
77
|
+
children.each do |child|
|
78
|
+
if child.type == :kwsplat
|
79
|
+
unless seq.empty?
|
80
|
+
result << expr(s(:hash, *seq))
|
81
|
+
end
|
82
|
+
result << expr(child)
|
83
|
+
seq = []
|
84
|
+
else
|
85
|
+
seq << child
|
86
|
+
end
|
87
|
+
end
|
88
|
+
unless seq.empty?
|
89
|
+
result << expr(s(:hash, *seq))
|
90
|
+
end
|
91
|
+
|
92
|
+
result.each_with_index do |fragment, idx|
|
93
|
+
if idx == 0
|
94
|
+
push fragment
|
95
|
+
else
|
96
|
+
push ".$merge(", fragment, ")"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Compiles a hash without kwsplats
|
102
|
+
# with complex keys.
|
42
103
|
def compile_hash
|
43
104
|
helper :hash
|
44
105
|
|
@@ -50,7 +111,9 @@ module Opal
|
|
50
111
|
wrap '$hash(', ')'
|
51
112
|
end
|
52
113
|
|
53
|
-
|
114
|
+
# Compiles a hash without kwsplats
|
115
|
+
# and containing **only** string/symbols as keys.
|
116
|
+
def compile_hash2
|
54
117
|
hash_obj, hash_keys = {}, []
|
55
118
|
helper :hash2
|
56
119
|
|
@@ -69,5 +132,14 @@ module Opal
|
|
69
132
|
wrap "$hash2([#{hash_keys.join ', '}], {", "})"
|
70
133
|
end
|
71
134
|
end
|
135
|
+
|
136
|
+
class KwSplatNode < Base
|
137
|
+
handle :kwsplat
|
138
|
+
children :value
|
139
|
+
|
140
|
+
def compile
|
141
|
+
push "Opal.to_hash(", expr(value), ")"
|
142
|
+
end
|
143
|
+
end
|
72
144
|
end
|
73
145
|
end
|
data/lib/opal/nodes/iter.rb
CHANGED
@@ -15,8 +15,6 @@ module Opal
|
|
15
15
|
extract_shadow_args
|
16
16
|
split_args
|
17
17
|
|
18
|
-
# require 'pry'; binding.pry
|
19
|
-
|
20
18
|
to_vars = identity = body_code = nil
|
21
19
|
|
22
20
|
in_scope do
|
@@ -44,6 +42,28 @@ module Opal
|
|
44
42
|
unshift "(#{identity} = function(", inline_params, "){"
|
45
43
|
push "}, #{identity}.$$s = self,"
|
46
44
|
push " #{identity}.$$brk = $brk," if compiler.has_break?
|
45
|
+
push " #{identity}.$$arity = #{arity},"
|
46
|
+
|
47
|
+
if compiler.arity_check?
|
48
|
+
push " #{identity}.$$parameters = #{parameters_code},"
|
49
|
+
end
|
50
|
+
|
51
|
+
# MRI expands a passed argument if the block:
|
52
|
+
# 1. takes a single argument that is an array
|
53
|
+
# 2. has more that one argument
|
54
|
+
# With a few exceptions:
|
55
|
+
# 1. mlhs arg: if a block takes |(a, b)| argument
|
56
|
+
# 2. trailing ',' in the arg list (|a, |)
|
57
|
+
# This flag on the method indicates that a block has a top level mlhs argument
|
58
|
+
# which means that we have to expand passed array explicitly in runtime.
|
59
|
+
if has_top_level_mlhs_arg?
|
60
|
+
push " #{identity}.$$has_top_level_mlhs_arg = true,"
|
61
|
+
end
|
62
|
+
|
63
|
+
if has_trailing_comma_in_args?
|
64
|
+
push " #{identity}.$$has_trailing_comma_in_args = true,"
|
65
|
+
end
|
66
|
+
|
47
67
|
push " #{identity})"
|
48
68
|
end
|
49
69
|
|
@@ -122,6 +142,14 @@ module Opal
|
|
122
142
|
def mlhs_args
|
123
143
|
scope.mlhs_mapping.keys
|
124
144
|
end
|
145
|
+
|
146
|
+
def has_top_level_mlhs_arg?
|
147
|
+
args.children.any? { |arg| arg.type == :mlhs }
|
148
|
+
end
|
149
|
+
|
150
|
+
def has_trailing_comma_in_args?
|
151
|
+
args.meta[:has_trailing_comma]
|
152
|
+
end
|
125
153
|
end
|
126
154
|
end
|
127
155
|
end
|