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