ruby2js 3.5.3 → 4.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -665
- data/lib/ruby2js.rb +60 -15
- data/lib/ruby2js/converter.rb +39 -3
- data/lib/ruby2js/converter/args.rb +6 -1
- data/lib/ruby2js/converter/assign.rb +159 -0
- data/lib/ruby2js/converter/begin.rb +7 -2
- data/lib/ruby2js/converter/case.rb +7 -2
- data/lib/ruby2js/converter/class.rb +80 -21
- data/lib/ruby2js/converter/class2.rb +107 -33
- data/lib/ruby2js/converter/def.rb +7 -3
- data/lib/ruby2js/converter/dstr.rb +8 -3
- data/lib/ruby2js/converter/for.rb +1 -1
- data/lib/ruby2js/converter/hash.rb +28 -6
- data/lib/ruby2js/converter/hide.rb +13 -0
- data/lib/ruby2js/converter/if.rb +10 -2
- data/lib/ruby2js/converter/import.rb +19 -4
- data/lib/ruby2js/converter/kwbegin.rb +9 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/logical.rb +1 -1
- data/lib/ruby2js/converter/module.rb +41 -4
- data/lib/ruby2js/converter/next.rb +10 -2
- data/lib/ruby2js/converter/opasgn.rb +8 -0
- data/lib/ruby2js/converter/redo.rb +14 -0
- data/lib/ruby2js/converter/return.rb +2 -1
- data/lib/ruby2js/converter/send.rb +73 -8
- data/lib/ruby2js/converter/vasgn.rb +5 -0
- data/lib/ruby2js/converter/while.rb +1 -1
- data/lib/ruby2js/converter/whilepost.rb +1 -1
- data/lib/ruby2js/converter/xstr.rb +2 -3
- data/lib/ruby2js/demo.rb +53 -0
- data/lib/ruby2js/es2022.rb +5 -0
- data/lib/ruby2js/es2022/strict.rb +3 -0
- data/lib/ruby2js/filter.rb +9 -1
- data/lib/ruby2js/filter/active_functions.rb +44 -0
- data/lib/ruby2js/filter/camelCase.rb +6 -3
- data/lib/ruby2js/filter/cjs.rb +2 -0
- data/lib/ruby2js/filter/esm.rb +118 -26
- data/lib/ruby2js/filter/functions.rb +137 -109
- data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
- data/lib/ruby2js/filter/node.rb +58 -14
- data/lib/ruby2js/filter/nokogiri.rb +12 -12
- data/lib/ruby2js/filter/react.rb +182 -57
- data/lib/ruby2js/filter/require.rb +102 -11
- data/lib/ruby2js/filter/return.rb +13 -1
- data/lib/ruby2js/filter/stimulus.rb +187 -0
- data/lib/ruby2js/jsx.rb +309 -0
- data/lib/ruby2js/namespace.rb +75 -0
- data/lib/ruby2js/serializer.rb +19 -12
- data/lib/ruby2js/sprockets.rb +40 -0
- data/lib/ruby2js/version.rb +3 -3
- data/ruby2js.gemspec +2 -2
- metadata +23 -13
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
- data/lib/ruby2js/rails.rb +0 -63
data/lib/ruby2js.rb
CHANGED
@@ -10,9 +10,15 @@ end
|
|
10
10
|
|
11
11
|
require 'ruby2js/converter'
|
12
12
|
require 'ruby2js/filter'
|
13
|
+
require 'ruby2js/namespace'
|
13
14
|
|
14
15
|
module Ruby2JS
|
15
16
|
class SyntaxError < RuntimeError
|
17
|
+
attr_reader :diagnostic
|
18
|
+
def initialize(message, diagnostic=nil)
|
19
|
+
super(message)
|
20
|
+
@diagnostic = diagnostic
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
@@eslevel_default = 2009 # ecmascript 5
|
@@ -61,26 +67,42 @@ module Ruby2JS
|
|
61
67
|
include Ruby2JS::Filter
|
62
68
|
BINARY_OPERATORS = Converter::OPERATORS[2..-1].flatten
|
63
69
|
|
64
|
-
attr_accessor :prepend_list
|
70
|
+
attr_accessor :prepend_list, :disable_autoimports, :namespace
|
65
71
|
|
66
72
|
def initialize(comments)
|
67
73
|
@comments = comments
|
74
|
+
|
75
|
+
# check if magic comment is present:
|
76
|
+
first_comment = @comments.values.first&.map(&:text)&.first
|
77
|
+
@disable_autoimports = first_comment&.include?(" autoimports: false")
|
78
|
+
@disable_autoexports = first_comment&.include?(" autoexports: false")
|
79
|
+
|
68
80
|
@ast = nil
|
69
81
|
@exclude_methods = []
|
70
|
-
@esm = false
|
71
82
|
@prepend_list = Set.new
|
72
83
|
end
|
73
84
|
|
74
85
|
def options=(options)
|
75
86
|
@options = options
|
76
87
|
|
77
|
-
@included =
|
78
|
-
@excluded =
|
88
|
+
@included = Filter.included_methods
|
89
|
+
@excluded = Filter.excluded_methods
|
79
90
|
|
80
91
|
include_all if options[:include_all]
|
81
92
|
include_only(options[:include_only]) if options[:include_only]
|
82
93
|
include(options[:include]) if options[:include]
|
83
94
|
exclude(options[:exclude]) if options[:exclude]
|
95
|
+
|
96
|
+
filters = options[:filters] || DEFAULTS
|
97
|
+
@modules_enabled =
|
98
|
+
(defined? Ruby2JS::Filter::ESM and
|
99
|
+
filters.include? Ruby2JS::Filter::ESM) or
|
100
|
+
(defined? Ruby2JS::Filter::CJS and
|
101
|
+
filters.include? Ruby2JS::Filter::CJS)
|
102
|
+
end
|
103
|
+
|
104
|
+
def modules_enabled?
|
105
|
+
@modules_enabled
|
84
106
|
end
|
85
107
|
|
86
108
|
def es2015
|
@@ -111,6 +133,10 @@ module Ruby2JS
|
|
111
133
|
@options[:eslevel] >= 2021
|
112
134
|
end
|
113
135
|
|
136
|
+
def es2022
|
137
|
+
@options[:eslevel] >= 2022
|
138
|
+
end
|
139
|
+
|
114
140
|
def process(node)
|
115
141
|
ast, @ast = @ast, node
|
116
142
|
replacement = super
|
@@ -125,6 +151,7 @@ module Ruby2JS
|
|
125
151
|
end
|
126
152
|
|
127
153
|
# handle all of the 'invented/synthetic' ast types
|
154
|
+
def on_assign(node); end
|
128
155
|
def on_async(node); on_def(node); end
|
129
156
|
def on_asyncs(node); on_defs(node); end
|
130
157
|
def on_attr(node); on_send(node); end
|
@@ -132,17 +159,23 @@ module Ruby2JS
|
|
132
159
|
def on_await(node); on_send(node); end
|
133
160
|
def on_call(node); on_send(node); end
|
134
161
|
def on_class_extend(node); on_send(node); end
|
162
|
+
def on_class_hash(node); on_class(node); end
|
135
163
|
def on_class_module(node); on_send(node); end
|
136
164
|
def on_constructor(node); on_def(node); end
|
165
|
+
def on_deff(node); on_def(node); end
|
137
166
|
def on_defm(node); on_defs(node); end
|
138
167
|
def on_defp(node); on_defs(node); end
|
139
168
|
def on_for_of(node); on_for(node); end
|
140
169
|
def on_in?(node); on_send(node); end
|
141
170
|
def on_method(node); on_send(node); end
|
171
|
+
def on_module_hash(node); on_module(node); end
|
142
172
|
def on_prop(node); on_array(node); end
|
143
173
|
def on_prototype(node); on_begin(node); end
|
174
|
+
def on_send!(node); on_send(node); end
|
144
175
|
def on_sendw(node); on_send(node); end
|
145
176
|
def on_undefined?(node); on_defined?(node); end
|
177
|
+
def on_defineProps(node); end
|
178
|
+
def on_hide(node); on_begin(node); end
|
146
179
|
def on_nil(node); end
|
147
180
|
def on_xnode(node); end
|
148
181
|
def on_export(node); end
|
@@ -160,10 +193,12 @@ module Ruby2JS
|
|
160
193
|
return on_block s(:block, s(:send, *node.children[0..-2]),
|
161
194
|
s(:args, s(:arg, :a), s(:arg, :b)), s(:return,
|
162
195
|
process(s(:send, s(:lvar, :a), method, s(:lvar, :b)))))
|
163
|
-
|
196
|
+
elsif node.children.last.children.first.type == :sym
|
164
197
|
return on_block s(:block, s(:send, *node.children[0..-2]),
|
165
198
|
s(:args, s(:arg, :item)), s(:return,
|
166
199
|
process(s(:attr, s(:lvar, :item), method))))
|
200
|
+
else
|
201
|
+
super
|
167
202
|
end
|
168
203
|
end
|
169
204
|
super
|
@@ -172,6 +207,7 @@ module Ruby2JS
|
|
172
207
|
end
|
173
208
|
|
174
209
|
def self.convert(source, options={})
|
210
|
+
options = options.dup
|
175
211
|
options[:eslevel] ||= @@eslevel_default
|
176
212
|
options[:strict] = @@strict_default if options[:strict] == nil
|
177
213
|
options[:module] ||= @@module_default || :esm
|
@@ -188,9 +224,11 @@ module Ruby2JS
|
|
188
224
|
source = ast.loc.expression.source_buffer.source
|
189
225
|
else
|
190
226
|
ast, comments = parse( source, options[:file] )
|
191
|
-
comments = Parser::Source::Comment.associate(ast, comments)
|
227
|
+
comments = ast ? Parser::Source::Comment.associate(ast, comments) : {}
|
192
228
|
end
|
193
229
|
|
230
|
+
namespace = Namespace.new
|
231
|
+
|
194
232
|
filters = (options[:filters] || Filter::DEFAULTS)
|
195
233
|
|
196
234
|
unless filters.empty?
|
@@ -205,11 +243,13 @@ module Ruby2JS
|
|
205
243
|
filter = filter.new(comments)
|
206
244
|
|
207
245
|
filter.options = options
|
246
|
+
filter.namespace = namespace
|
208
247
|
ast = filter.process(ast)
|
209
248
|
|
210
|
-
|
249
|
+
unless filter.prepend_list.empty?
|
211
250
|
prepend = filter.prepend_list.sort_by {|ast| ast.type == :import ? 0 : 1}
|
212
|
-
ast
|
251
|
+
prepend.reject! {|ast| ast.type == :import} if filter.disable_autoimports
|
252
|
+
ast = Parser::AST::Node.new(:begin, [*prepend, ast])
|
213
253
|
end
|
214
254
|
end
|
215
255
|
|
@@ -222,7 +262,10 @@ module Ruby2JS
|
|
222
262
|
ruby2js.comparison = options[:comparison] || :equality
|
223
263
|
ruby2js.or = options[:or] || :logical
|
224
264
|
ruby2js.module_type = options[:module] || :esm
|
225
|
-
ruby2js.underscored_private = (options[:eslevel] <
|
265
|
+
ruby2js.underscored_private = (options[:eslevel] < 2022) || options[:underscored_private]
|
266
|
+
|
267
|
+
ruby2js.namespace = namespace
|
268
|
+
|
226
269
|
if ruby2js.binding and not ruby2js.ivars
|
227
270
|
ruby2js.ivars = ruby2js.binding.eval \
|
228
271
|
'Hash[instance_variables.map {|var| [var, instance_variable_get(var)]}]'
|
@@ -240,23 +283,25 @@ module Ruby2JS
|
|
240
283
|
|
241
284
|
ruby2js.timestamp options[:file]
|
242
285
|
|
286
|
+
ruby2js.file_name = options[:file] || ast&.loc&.expression&.source_buffer&.name || ''
|
287
|
+
|
243
288
|
ruby2js
|
244
289
|
end
|
245
290
|
|
246
291
|
def self.parse(source, file=nil, line=1)
|
247
292
|
buffer = Parser::Source::Buffer.new(file, line)
|
248
|
-
buffer.source = source.encode('
|
293
|
+
buffer.source = source.encode('UTF-8')
|
249
294
|
parser = Parser::CurrentRuby.new
|
250
|
-
parser.
|
251
|
-
|
252
|
-
|
253
|
-
|
295
|
+
parser.diagnostics.all_errors_are_fatal = true
|
296
|
+
parser.diagnostics.consumer = lambda {|diagnostic| nil}
|
297
|
+
parser.builder.emit_file_line_as_literals = false
|
298
|
+
parser.parse_with_comments(buffer)
|
254
299
|
rescue Parser::SyntaxError => e
|
255
300
|
split = source[0..e.diagnostic.location.begin_pos].split("\n")
|
256
301
|
line, col = split.length, split.last.length
|
257
302
|
message = "line #{line}, column #{col}: #{e.diagnostic.message}"
|
258
303
|
message += "\n in file #{file}" if file
|
259
|
-
raise Ruby2JS::SyntaxError.new(message)
|
304
|
+
raise Ruby2JS::SyntaxError.new(message, e.diagnostic)
|
260
305
|
end
|
261
306
|
|
262
307
|
def self.find_block(ast, line)
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -14,7 +14,7 @@ module Ruby2JS
|
|
14
14
|
|
15
15
|
class Converter < Serializer
|
16
16
|
attr_accessor :ast
|
17
|
-
|
17
|
+
|
18
18
|
LOGICAL = :and, :not, :or
|
19
19
|
OPERATORS = [:[], :[]=], [:not, :!], [:**], [:*, :/, :%], [:+, :-],
|
20
20
|
[:>>, :<<], [:&], [:^, :|], [:<=, :<, :>, :>=], [:==, :!=, :===, :"!=="],
|
@@ -34,7 +34,7 @@ module Ruby2JS
|
|
34
34
|
|
35
35
|
VASGN = [:cvasgn, :ivasgn, :gvasgn, :lvasgn]
|
36
36
|
|
37
|
-
attr_accessor :binding, :ivars
|
37
|
+
attr_accessor :binding, :ivars, :namespace
|
38
38
|
|
39
39
|
def initialize( ast, comments, vars = {} )
|
40
40
|
super()
|
@@ -66,6 +66,7 @@ module Ruby2JS
|
|
66
66
|
@comparison = :equality
|
67
67
|
@or = :logical
|
68
68
|
@underscored_private = true
|
69
|
+
@redoable = false
|
69
70
|
end
|
70
71
|
|
71
72
|
def width=(width)
|
@@ -160,6 +161,10 @@ module Ruby2JS
|
|
160
161
|
@eslevel >= 2021
|
161
162
|
end
|
162
163
|
|
164
|
+
def es2022
|
165
|
+
@eslevel >= 2022
|
166
|
+
end
|
167
|
+
|
163
168
|
@@handlers = []
|
164
169
|
def self.handle(*types, &block)
|
165
170
|
types.each do |type|
|
@@ -239,6 +244,34 @@ module Ruby2JS
|
|
239
244
|
end
|
240
245
|
end
|
241
246
|
|
247
|
+
def redoable(block)
|
248
|
+
save_redoable = @redoable
|
249
|
+
|
250
|
+
has_redo = proc do |node|
|
251
|
+
node.children.any? do |child|
|
252
|
+
next false unless child.is_a? Parser::AST::Node
|
253
|
+
next true if child.type == :redo
|
254
|
+
next false if %i[for while while_post until until_post].include? child.type
|
255
|
+
has_redo[child]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
@redoable = has_redo[@ast]
|
260
|
+
|
261
|
+
if @redoable
|
262
|
+
put es2015 ? 'let ' : 'var '
|
263
|
+
put "redo$#@sep"
|
264
|
+
puts 'do {'
|
265
|
+
put "redo$ = false#@sep"
|
266
|
+
scope block
|
267
|
+
put "#@nl} while(redo$)"
|
268
|
+
else
|
269
|
+
scope block
|
270
|
+
end
|
271
|
+
ensure
|
272
|
+
@redoable = save_redoable
|
273
|
+
end
|
274
|
+
|
242
275
|
def timestamp(file)
|
243
276
|
super
|
244
277
|
|
@@ -248,7 +281,7 @@ module Ruby2JS
|
|
248
281
|
if ast.loc and ast.loc.expression
|
249
282
|
filename = ast.loc.expression.source_buffer.name
|
250
283
|
if filename and not filename.empty?
|
251
|
-
@timestamps[filename] ||= File.mtime(filename)
|
284
|
+
@timestamps[filename] ||= File.mtime(filename) rescue nil
|
252
285
|
end
|
253
286
|
end
|
254
287
|
|
@@ -295,6 +328,7 @@ end
|
|
295
328
|
require 'ruby2js/converter/arg'
|
296
329
|
require 'ruby2js/converter/args'
|
297
330
|
require 'ruby2js/converter/array'
|
331
|
+
require 'ruby2js/converter/assign'
|
298
332
|
require 'ruby2js/converter/begin'
|
299
333
|
require 'ruby2js/converter/block'
|
300
334
|
require 'ruby2js/converter/blockpass'
|
@@ -314,6 +348,7 @@ require 'ruby2js/converter/dstr'
|
|
314
348
|
require 'ruby2js/converter/fileline'
|
315
349
|
require 'ruby2js/converter/for'
|
316
350
|
require 'ruby2js/converter/hash'
|
351
|
+
require 'ruby2js/converter/hide'
|
317
352
|
require 'ruby2js/converter/if'
|
318
353
|
require 'ruby2js/converter/in'
|
319
354
|
require 'ruby2js/converter/import'
|
@@ -329,6 +364,7 @@ require 'ruby2js/converter/nil'
|
|
329
364
|
require 'ruby2js/converter/nthref'
|
330
365
|
require 'ruby2js/converter/opasgn'
|
331
366
|
require 'ruby2js/converter/prototype'
|
367
|
+
require 'ruby2js/converter/redo'
|
332
368
|
require 'ruby2js/converter/regexp'
|
333
369
|
require 'ruby2js/converter/return'
|
334
370
|
require 'ruby2js/converter/self'
|
@@ -30,13 +30,18 @@ module Ruby2JS
|
|
30
30
|
if kw.type == :kwarg
|
31
31
|
put kw.children.first
|
32
32
|
elsif kw.type == :kwoptarg
|
33
|
-
put kw.children.first
|
33
|
+
put kw.children.first
|
34
|
+
unless kw.children.last == s(:send, nil, :undefined)
|
35
|
+
put '='; parse kw.children.last
|
36
|
+
end
|
34
37
|
elsif kw.type == :kwrestarg
|
35
38
|
raise 'Rest arg requires ES2018' unless es2018
|
36
39
|
put '...'; put kw.children.first
|
37
40
|
end
|
38
41
|
end
|
39
42
|
put ' }'
|
43
|
+
|
44
|
+
put ' = {}' unless kwargs.any? {|kw| kw.type == :kwarg}
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# Kinda like Object.assign, except it handles properties
|
2
|
+
#
|
3
|
+
# Note: Object.defineProperties, Object.getOwnPropertyNames, etc. technically
|
4
|
+
# were not part of ES5, but were implemented by IE prior to ES6, and are
|
5
|
+
# the only way to implement getters and setters.
|
6
|
+
|
7
|
+
module Ruby2JS
|
8
|
+
class Converter
|
9
|
+
|
10
|
+
# (assign
|
11
|
+
# target
|
12
|
+
# (hash)
|
13
|
+
# ...
|
14
|
+
|
15
|
+
handle :assign do |target, *args|
|
16
|
+
collapsible = false
|
17
|
+
|
18
|
+
nonprop = proc do |node|
|
19
|
+
next false unless node.is_a? Parser::AST::Node
|
20
|
+
next false if node.type == :pair and node.children.first.type == :prop and es2015
|
21
|
+
next true unless node.type == :def
|
22
|
+
next false if node.children.first.to_s.end_with? '='
|
23
|
+
node.is_method?
|
24
|
+
end
|
25
|
+
|
26
|
+
collapsible = true if args.length == 1 and args.first.type == :hash and
|
27
|
+
args.first.children.length == 1
|
28
|
+
|
29
|
+
collapsible = true if args.length == 1 and args.first.type == :class_module and
|
30
|
+
args.first.children.length == 3 and nonprop[args.first.children.last]
|
31
|
+
|
32
|
+
if es2015 and not collapsible and args.all? {|arg|
|
33
|
+
case arg.type
|
34
|
+
when :pair, :hash, :class_module
|
35
|
+
arg.children.all? {|child| nonprop[child]}
|
36
|
+
when :const
|
37
|
+
false
|
38
|
+
else
|
39
|
+
true
|
40
|
+
end
|
41
|
+
}
|
42
|
+
parse s(:send, s(:const, nil, :Object), :assign, target, *args)
|
43
|
+
else
|
44
|
+
|
45
|
+
if target == s(:hash)
|
46
|
+
copy = [s(:gvasgn, :$$, target)]
|
47
|
+
target = s(:gvar, :$$)
|
48
|
+
shadow = [s(:shadowarg, :$$)]
|
49
|
+
elsif collapsible or es2015 or
|
50
|
+
(%i(send const).include? target.type and
|
51
|
+
target.children.length == 2 and target.children[0] == nil)
|
52
|
+
then
|
53
|
+
copy = []
|
54
|
+
shadow = []
|
55
|
+
else
|
56
|
+
copy = [s(:gvasgn, :$0, target)]
|
57
|
+
target = s(:gvar, :$0)
|
58
|
+
shadow = [s(:shadowarg, :$0)]
|
59
|
+
end
|
60
|
+
|
61
|
+
body = [*copy,
|
62
|
+
*args.map {|modname|
|
63
|
+
if modname.type == :hash and
|
64
|
+
modname.children.all? {|pair| pair.children.first.type == :prop}
|
65
|
+
|
66
|
+
if modname.children.length == 1
|
67
|
+
pair = modname.children.first
|
68
|
+
s(:send, s(:const, nil, :Object), :defineProperty, target,
|
69
|
+
s(:sym, pair.children.first.children.last),
|
70
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
71
|
+
s(:sym, name), value)}))
|
72
|
+
else
|
73
|
+
pair = modname.children.first
|
74
|
+
s(:send, s(:const, nil, :Object), :defineProperties, target,
|
75
|
+
s(:hash, *modname.children.map {|pair| s(:pair,
|
76
|
+
s(:sym, pair.children.first.children.last),
|
77
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
78
|
+
s(:sym, name), value)})
|
79
|
+
)}))
|
80
|
+
end
|
81
|
+
|
82
|
+
elsif modname.type == :hash and
|
83
|
+
modname.children.all? {|child| nonprop[child]}
|
84
|
+
|
85
|
+
s(:begin, *modname.children.map {|pair|
|
86
|
+
if pair.children.first.type == :prop
|
87
|
+
s(:send, s(:const, nil, :Object), :defineProperty, target,
|
88
|
+
s(:sym, pair.children.first.children.last),
|
89
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
90
|
+
s(:sym, name), value)}))
|
91
|
+
else
|
92
|
+
s(:send, target, :[]=, *pair.children)
|
93
|
+
end
|
94
|
+
})
|
95
|
+
|
96
|
+
elsif modname.type == :class_module and
|
97
|
+
modname.children[2..-1].all? {|child| nonprop[child]}
|
98
|
+
|
99
|
+
s(:begin, *modname.children[2..-1].map {|pair|
|
100
|
+
s(:send, target, :[]=, s(:sym, pair.children.first),
|
101
|
+
pair.updated(:defm, [nil, *pair.children[1..-1]]))
|
102
|
+
})
|
103
|
+
|
104
|
+
elsif modname.type == :lvar and not es2015
|
105
|
+
s(:for, s(:lvasgn, :$_), modname,
|
106
|
+
s(:send, target, :[]=,
|
107
|
+
s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
|
108
|
+
|
109
|
+
else
|
110
|
+
if es2017
|
111
|
+
s(:send, s(:const, nil, :Object), :defineProperties, target,
|
112
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyDescriptors, modname))
|
113
|
+
else
|
114
|
+
if modname.type == :lvar or (%i(send const).include? modname.type and
|
115
|
+
modname.children.length == 2 and modname.children[0] == nil)
|
116
|
+
|
117
|
+
object = modname
|
118
|
+
else
|
119
|
+
shadow += [s(:shadowarg, :$1)]
|
120
|
+
object = s(:gvar, :$1)
|
121
|
+
end
|
122
|
+
|
123
|
+
copy = s(:send,
|
124
|
+
s(:const, nil, :Object), :defineProperties, target,
|
125
|
+
s(:send,
|
126
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyNames, object),
|
127
|
+
:reduce,
|
128
|
+
s(:block,
|
129
|
+
s(:send, nil, :lambda),
|
130
|
+
s(:args, s(:arg, :$2), s(:arg, :$3)),
|
131
|
+
s(:begin,
|
132
|
+
s(:send,
|
133
|
+
s(:lvar, :$2), :[]=, s(:lvar, :$3),
|
134
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyDescriptor,
|
135
|
+
object, s(:lvar, :$3))),
|
136
|
+
s(:return, s(:lvar, :$2)))),
|
137
|
+
s(:hash)))
|
138
|
+
|
139
|
+
|
140
|
+
if object.type == :gvar
|
141
|
+
s(:begin, s(:gvasgn, object.children.last, modname), copy)
|
142
|
+
else
|
143
|
+
copy
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
}]
|
148
|
+
|
149
|
+
if @state == :statement and shadow.empty?
|
150
|
+
parse s(:begin, *body)
|
151
|
+
else
|
152
|
+
body.push s(:return, target) if @state == :expression
|
153
|
+
parse s(:send, s(:block, s(:send, nil, :lambda), s(:args, *shadow),
|
154
|
+
s(:begin, *body)), :[])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|