Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f094cae

Browse files
committed
Compile blocks
1 parent 61924f8 commit f094cae

File tree

2 files changed

+85
-17
lines changed

2 files changed

+85
-17
lines changed

lib/syntax_tree/visitor/compiler.rb

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,13 @@ def opt_setinlinecache(inline_storage)
702702
def opt_str_freeze(value)
703703
if specialized_instruction
704704
stack.change_by(+1)
705-
iseq.push([:opt_str_freeze, value, call_data(:freeze, 0, VM_CALL_ARGS_SIMPLE)])
705+
iseq.push(
706+
[
707+
:opt_str_freeze,
708+
value,
709+
call_data(:freeze, 0, VM_CALL_ARGS_SIMPLE)
710+
]
711+
)
706712
else
707713
putstring(value)
708714
send(:freeze, 0, VM_CALL_ARGS_SIMPLE)
@@ -712,7 +718,9 @@ def opt_str_freeze(value)
712718
def opt_str_uminus(value)
713719
if specialized_instruction
714720
stack.change_by(+1)
715-
iseq.push([:opt_str_uminus, value, call_data(:-@, 0, VM_CALL_ARGS_SIMPLE)])
721+
iseq.push(
722+
[:opt_str_uminus, value, call_data(:-@, 0, VM_CALL_ARGS_SIMPLE)]
723+
)
716724
else
717725
putstring(value)
718726
send(:-@, 0, VM_CALL_ARGS_SIMPLE)
@@ -1045,7 +1053,9 @@ def visit_array(node)
10451053
end
10461054

10471055
builder.newarray(length) if length > 0
1048-
builder.concatarray if length > 0 && length != node.contents.parts.length
1056+
if length > 0 && length != node.contents.parts.length
1057+
builder.concatarray
1058+
end
10491059
end
10501060
end
10511061

@@ -1168,6 +1178,33 @@ def visit_binary(node)
11681178
end
11691179
end
11701180

1181+
def visit_block(node)
1182+
with_instruction_sequence(
1183+
:block,
1184+
"block in #{current_iseq.name}",
1185+
current_iseq,
1186+
node
1187+
) do
1188+
visit(node.block_var)
1189+
visit(node.bodystmt)
1190+
builder.leave
1191+
end
1192+
end
1193+
1194+
def visit_block_var(node)
1195+
params = node.params
1196+
1197+
if params.requireds.length == 1 && params.optionals.empty? && !params.rest && params.posts.empty? && params.keywords.empty? && !params.keyword_rest && !params.block
1198+
current_iseq.argument_options[:ambiguous_param0] = true
1199+
end
1200+
1201+
visit(node.params)
1202+
1203+
node.locals.each do |local|
1204+
current_iseq.local_table.plain(local.value.to_sym)
1205+
end
1206+
end
1207+
11711208
def visit_blockarg(node)
11721209
current_iseq.argument_options[:block_start] = current_iseq.argument_size
11731210
current_iseq.local_table.block_proxy(node.name.value.to_sym)
@@ -1184,12 +1221,14 @@ def visit_call(node)
11841221
# First we're going to check if we're calling a method on an array
11851222
# literal without any arguments. In that case there are some
11861223
# specializations we might be able to perform.
1187-
if arg_parts.length == 0 && (node.message.is_a?(Ident) || node.message.is_a?(Op))
1224+
if arg_parts.length == 0 &&
1225+
(node.message.is_a?(Ident) || node.message.is_a?(Op))
11881226
case node.receiver
11891227
when ArrayLiteral
11901228
parts = node.receiver.contents&.parts || []
11911229

1192-
if parts.none? { |part| part.is_a?(ArgStar) } && RubyVisitor.compile(node.receiver).nil?
1230+
if parts.none? { |part| part.is_a?(ArgStar) } &&
1231+
RubyVisitor.compile(node.receiver).nil?
11931232
case node.message.value
11941233
when "max"
11951234
visit(node.receiver.contents)
@@ -1215,13 +1254,10 @@ def visit_call(node)
12151254
end
12161255
end
12171256

1218-
if node.receiver
1219-
visit(node.receiver)
1220-
else
1221-
builder.putself
1222-
end
1257+
node.receiver ? visit(node.receiver) : builder.putself
12231258

12241259
visit(node.arguments)
1260+
block_iseq = visit(node.block) if node.respond_to?(:block) && node.block
12251261

12261262
if arg_parts.last.is_a?(ArgBlock)
12271263
flag = node.receiver.nil? ? VM_CALL_FCALL : 0
@@ -1235,7 +1271,12 @@ def visit_call(node)
12351271
flag |= VM_CALL_KW_SPLAT
12361272
end
12371273

1238-
builder.send(node.message.value.to_sym, arg_parts.length - 1, flag)
1274+
builder.send(
1275+
node.message.value.to_sym,
1276+
arg_parts.length - 1,
1277+
flag,
1278+
block_iseq
1279+
)
12391280
else
12401281
flag = 0
12411282
arg_parts.each do |arg_part|
@@ -1247,9 +1288,14 @@ def visit_call(node)
12471288
end
12481289
end
12491290

1250-
flag |= VM_CALL_ARGS_SIMPLE if flag == 0
1291+
flag |= VM_CALL_ARGS_SIMPLE if block_iseq.nil? && flag == 0
12511292
flag |= VM_CALL_FCALL if node.receiver.nil?
1252-
builder.send(node.message.value.to_sym, arg_parts.length, flag)
1293+
builder.send(
1294+
node.message.value.to_sym,
1295+
arg_parts.length,
1296+
flag,
1297+
block_iseq
1298+
)
12531299
end
12541300
end
12551301

@@ -1291,23 +1337,25 @@ def visit_class(node)
12911337

12921338
def visit_command(node)
12931339
visit_call(
1294-
CallNode.new(
1340+
CommandCall.new(
12951341
receiver: nil,
12961342
operator: nil,
12971343
message: node.message,
12981344
arguments: node.arguments,
1345+
block: node.block,
12991346
location: node.location
13001347
)
13011348
)
13021349
end
13031350

13041351
def visit_command_call(node)
13051352
visit_call(
1306-
CallNode.new(
1353+
CommandCall.new(
13071354
receiver: node.receiver,
13081355
operator: node.operator,
13091356
message: node.message,
13101357
arguments: node.arguments,
1358+
block: node.block,
13111359
location: node.location
13121360
)
13131361
)
@@ -1537,6 +1585,19 @@ def visit_label(node)
15371585
builder.putobject(node.accept(RubyVisitor.new))
15381586
end
15391587

1588+
def visit_method_add_block(node)
1589+
visit_call(
1590+
CommandCall.new(
1591+
receiver: node.call.receiver,
1592+
operator: node.call.operator,
1593+
message: node.call.message,
1594+
arguments: node.call.arguments,
1595+
block: node.block,
1596+
location: node.location
1597+
)
1598+
)
1599+
end
1600+
15401601
def visit_module(node)
15411602
name = node.constant.constant.value.to_sym
15421603
module_iseq =
@@ -1898,11 +1959,12 @@ def visit_unary(node)
18981959
end
18991960

19001961
visit_call(
1901-
CallNode.new(
1962+
CommandCall.new(
19021963
receiver: node.statement,
19031964
operator: nil,
19041965
message: Ident.new(value: method_id, location: Location.default),
19051966
arguments: nil,
1967+
block: nil,
19061968
location: Location.default
19071969
)
19081970
)

test/compiler_test.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,13 @@ class CompilerTest < Minitest::Test
370370
"class Foo::Bar < Baz; end",
371371
"class ::Foo::Bar < Baz; end",
372372
"class Foo; class Bar < Baz; end; end",
373-
"class Foo < baz; end"
373+
"class Foo < baz; end",
374+
# Block
375+
"foo do end",
376+
"foo {}",
377+
"foo do |bar| end",
378+
"foo { |bar| }",
379+
"foo { |bar; baz| }"
374380
]
375381

376382
# These are the combinations of instructions that we're going to test.

0 commit comments

Comments
 (0)