Skip to content

Commit 1e7a0fc

Browse files
authored
Merge pull request #378 from ruby-syntax-tree/newarray-send
Support opt_newarray_send
2 parents 40bee7a + b345765 commit 1e7a0fc

File tree

5 files changed

+157
-71
lines changed

5 files changed

+157
-71
lines changed

Diff for: lib/syntax_tree/node.rb

+7-4
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ def format(q)
12991299
end
13001300
end
13011301

1302-
# [nil | VarRef] the optional constant wrapper
1302+
# [nil | VarRef | ConstPathRef] the optional constant wrapper
13031303
attr_reader :constant
13041304

13051305
# [Array[ Node ]] the regular positional arguments that this array
@@ -2849,7 +2849,10 @@ def format_chain(q, children)
28492849
# to print the operator trailing in order to keep it working.
28502850
last_child = children.last
28512851
if last_child.is_a?(CallNode) && last_child.message != :call &&
2852-
last_child.message.comments.any? && last_child.operator
2852+
(
2853+
(last_child.message.comments.any? && last_child.operator) ||
2854+
(last_child.operator && last_child.operator.comments.any?)
2855+
)
28532856
q.format(CallOperatorFormatter.new(last_child.operator))
28542857
skip_operator = true
28552858
else
@@ -5413,7 +5416,7 @@ def ===(other)
54135416
# end
54145417
#
54155418
class FndPtn < Node
5416-
# [nil | Node] the optional constant wrapper
5419+
# [nil | VarRef | ConstPathRef] the optional constant wrapper
54175420
attr_reader :constant
54185421

54195422
# [VarField] the splat on the left-hand side
@@ -6035,7 +6038,7 @@ def format(q)
60356038
end
60366039
end
60376040

6038-
# [nil | Node] the optional constant wrapper
6041+
# [nil | VarRef | ConstPathRef] the optional constant wrapper
60396042
attr_reader :constant
60406043

60416044
# [Array[ [DynaSymbol | Label, nil | Node] ]] the set of tuples

Diff for: lib/syntax_tree/yarv/instruction_sequence.rb

+22-3
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,27 @@ def specialize_instructions!
353353
next unless calldata.argc == 0
354354

355355
case calldata.method
356+
when :min
357+
node.value =
358+
if RUBY_VERSION < "3.3"
359+
Legacy::OptNewArrayMin.new(value.number)
360+
else
361+
OptNewArraySend.new(value.number, :min)
362+
end
363+
364+
node.next_node = next_node.next_node
356365
when :max
357-
node.value = OptNewArrayMax.new(value.number)
366+
node.value =
367+
if RUBY_VERSION < "3.3"
368+
Legacy::OptNewArrayMax.new(value.number)
369+
else
370+
OptNewArraySend.new(value.number, :max)
371+
end
372+
358373
node.next_node = next_node.next_node
359-
when :min
360-
node.value = OptNewArrayMin.new(value.number)
374+
when :hash
375+
next if RUBY_VERSION < "3.3"
376+
node.value = OptNewArraySend.new(value.number, :hash)
361377
node.next_node = next_node.next_node
362378
end
363379
when PutObject, PutString
@@ -1174,6 +1190,9 @@ def self.from(source, options = Compiler::Options.new, parent_iseq = nil)
11741190
when :opt_newarray_min
11751191
iseq.newarray(opnds[0])
11761192
iseq.send(YARV.calldata(:min))
1193+
when :opt_newarray_send
1194+
iseq.newarray(opnds[0])
1195+
iseq.send(CallData.new(opnds[1]))
11771196
when :opt_neq
11781197
iseq.push(
11791198
OptNEq.new(CallData.from(opnds[0]), CallData.from(opnds[1]))

Diff for: lib/syntax_tree/yarv/instructions.rb

+18-64
Original file line numberDiff line numberDiff line change
@@ -3818,93 +3818,47 @@ def call(vm)
38183818

38193819
# ### Summary
38203820
#
3821-
# `opt_newarray_max` is a specialization that occurs when the `max` method
3822-
# is called on an array literal. It pops the values of the array off the
3823-
# stack and pushes on the result.
3821+
# `opt_newarray_send` is a specialization that occurs when a dynamic array
3822+
# literal is created and immediately sent the `min`, `max`, or `hash`
3823+
# methods. It pops the values of the array off the stack and pushes on the
3824+
# result of the method call.
38243825
#
38253826
# ### Usage
38263827
#
38273828
# ~~~ruby
38283829
# [a, b, c].max
38293830
# ~~~
38303831
#
3831-
class OptNewArrayMax < Instruction
3832-
attr_reader :number
3833-
3834-
def initialize(number)
3835-
@number = number
3836-
end
3837-
3838-
def disasm(fmt)
3839-
fmt.instruction("opt_newarray_max", [fmt.object(number)])
3840-
end
3841-
3842-
def to_a(_iseq)
3843-
[:opt_newarray_max, number]
3844-
end
3845-
3846-
def deconstruct_keys(_keys)
3847-
{ number: number }
3848-
end
3849-
3850-
def ==(other)
3851-
other.is_a?(OptNewArrayMax) && other.number == number
3852-
end
3853-
3854-
def length
3855-
2
3856-
end
3857-
3858-
def pops
3859-
number
3860-
end
3832+
class OptNewArraySend < Instruction
3833+
attr_reader :number, :method
38613834

3862-
def pushes
3863-
1
3864-
end
3865-
3866-
def call(vm)
3867-
vm.push(vm.pop(number).max)
3868-
end
3869-
end
3870-
3871-
# ### Summary
3872-
#
3873-
# `opt_newarray_min` is a specialization that occurs when the `min` method
3874-
# is called on an array literal. It pops the values of the array off the
3875-
# stack and pushes on the result.
3876-
#
3877-
# ### Usage
3878-
#
3879-
# ~~~ruby
3880-
# [a, b, c].min
3881-
# ~~~
3882-
#
3883-
class OptNewArrayMin < Instruction
3884-
attr_reader :number
3885-
3886-
def initialize(number)
3835+
def initialize(number, method)
38873836
@number = number
3837+
@method = method
38883838
end
38893839

38903840
def disasm(fmt)
3891-
fmt.instruction("opt_newarray_min", [fmt.object(number)])
3841+
fmt.instruction(
3842+
"opt_newarray_send",
3843+
[fmt.object(number), fmt.object(method)]
3844+
)
38923845
end
38933846

38943847
def to_a(_iseq)
3895-
[:opt_newarray_min, number]
3848+
[:opt_newarray_send, number, method]
38963849
end
38973850

38983851
def deconstruct_keys(_keys)
3899-
{ number: number }
3852+
{ number: number, method: method }
39003853
end
39013854

39023855
def ==(other)
3903-
other.is_a?(OptNewArrayMin) && other.number == number
3856+
other.is_a?(OptNewArraySend) && other.number == number &&
3857+
other.method == method
39043858
end
39053859

39063860
def length
3907-
2
3861+
3
39083862
end
39093863

39103864
def pops
@@ -3916,7 +3870,7 @@ def pushes
39163870
end
39173871

39183872
def call(vm)
3919-
vm.push(vm.pop(number).min)
3873+
vm.push(vm.pop(number).__send__(method))
39203874
end
39213875
end
39223876

Diff for: lib/syntax_tree/yarv/legacy.rb

+104
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,110 @@ def falls_through?
124124
end
125125
end
126126

127+
# ### Summary
128+
#
129+
# `opt_newarray_max` is a specialization that occurs when the `max` method
130+
# is called on an array literal. It pops the values of the array off the
131+
# stack and pushes on the result.
132+
#
133+
# ### Usage
134+
#
135+
# ~~~ruby
136+
# [a, b, c].max
137+
# ~~~
138+
#
139+
class OptNewArrayMax < Instruction
140+
attr_reader :number
141+
142+
def initialize(number)
143+
@number = number
144+
end
145+
146+
def disasm(fmt)
147+
fmt.instruction("opt_newarray_max", [fmt.object(number)])
148+
end
149+
150+
def to_a(_iseq)
151+
[:opt_newarray_max, number]
152+
end
153+
154+
def deconstruct_keys(_keys)
155+
{ number: number }
156+
end
157+
158+
def ==(other)
159+
other.is_a?(OptNewArrayMax) && other.number == number
160+
end
161+
162+
def length
163+
2
164+
end
165+
166+
def pops
167+
number
168+
end
169+
170+
def pushes
171+
1
172+
end
173+
174+
def call(vm)
175+
vm.push(vm.pop(number).max)
176+
end
177+
end
178+
179+
# ### Summary
180+
#
181+
# `opt_newarray_min` is a specialization that occurs when the `min` method
182+
# is called on an array literal. It pops the values of the array off the
183+
# stack and pushes on the result.
184+
#
185+
# ### Usage
186+
#
187+
# ~~~ruby
188+
# [a, b, c].min
189+
# ~~~
190+
#
191+
class OptNewArrayMin < Instruction
192+
attr_reader :number
193+
194+
def initialize(number)
195+
@number = number
196+
end
197+
198+
def disasm(fmt)
199+
fmt.instruction("opt_newarray_min", [fmt.object(number)])
200+
end
201+
202+
def to_a(_iseq)
203+
[:opt_newarray_min, number]
204+
end
205+
206+
def deconstruct_keys(_keys)
207+
{ number: number }
208+
end
209+
210+
def ==(other)
211+
other.is_a?(OptNewArrayMin) && other.number == number
212+
end
213+
214+
def length
215+
2
216+
end
217+
218+
def pops
219+
number
220+
end
221+
222+
def pushes
223+
1
224+
end
225+
226+
def call(vm)
227+
vm.push(vm.pop(number).min)
228+
end
229+
end
230+
127231
# ### Summary
128232
#
129233
# `opt_setinlinecache` sets an inline cache for a constant lookup. It pops

Diff for: test/compiler_test.rb

+6
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@ class CompilerTest < Minitest::Test
311311
"[1, 2, 3].min",
312312
"[foo, bar, baz].min",
313313
"[foo, bar, baz].min(1)",
314+
"[1, 2, 3].hash",
315+
"[foo, bar, baz].hash",
316+
"[foo, bar, baz].hash(1)",
317+
"[1, 2, 3].foo",
318+
"[foo, bar, baz].foo",
319+
"[foo, bar, baz].foo(1)",
314320
"[**{ x: true }][0][:x]",
315321
# Core method calls
316322
"alias foo bar",

0 commit comments

Comments
 (0)