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

Commit 76428d0

Browse files
committed
Compile blocks
1 parent 61924f8 commit 76428d0

File tree

2 files changed

+89
-19
lines changed

2 files changed

+89
-19
lines changed

lib/syntax_tree/visitor/compiler.rb

Lines changed: 82 additions & 18 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)
@@ -1024,7 +1032,7 @@ def visit_args(node)
10241032
end
10251033

10261034
def visit_array(node)
1027-
if compiled = RubyVisitor.compile(node)
1035+
if (compiled = RubyVisitor.compile(node))
10281036
builder.duparray(compiled)
10291037
else
10301038
length = 0
@@ -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

@@ -1134,7 +1144,7 @@ def visit_backref(node)
11341144
end
11351145

11361146
def visit_bare_assoc_hash(node)
1137-
if compiled = RubyVisitor.compile(node)
1147+
if (compiled = RubyVisitor.compile(node))
11381148
builder.duphash(compiled)
11391149
else
11401150
visit_all(node.assocs)
@@ -1168,6 +1178,35 @@ 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? &&
1198+
!params.rest && params.posts.empty? && params.keywords.empty? &&
1199+
!params.keyword_rest && !params.block
1200+
current_iseq.argument_options[:ambiguous_param0] = true
1201+
end
1202+
1203+
visit(node.params)
1204+
1205+
node.locals.each do |local|
1206+
current_iseq.local_table.plain(local.value.to_sym)
1207+
end
1208+
end
1209+
11711210
def visit_blockarg(node)
11721211
current_iseq.argument_options[:block_start] = current_iseq.argument_size
11731212
current_iseq.local_table.block_proxy(node.name.value.to_sym)
@@ -1184,12 +1223,14 @@ def visit_call(node)
11841223
# First we're going to check if we're calling a method on an array
11851224
# literal without any arguments. In that case there are some
11861225
# specializations we might be able to perform.
1187-
if arg_parts.length == 0 && (node.message.is_a?(Ident) || node.message.is_a?(Op))
1226+
if arg_parts.empty? &&
1227+
(node.message.is_a?(Ident) || node.message.is_a?(Op))
11881228
case node.receiver
11891229
when ArrayLiteral
11901230
parts = node.receiver.contents&.parts || []
11911231

1192-
if parts.none? { |part| part.is_a?(ArgStar) } && RubyVisitor.compile(node.receiver).nil?
1232+
if parts.none? { |part| part.is_a?(ArgStar) } &&
1233+
RubyVisitor.compile(node.receiver).nil?
11931234
case node.message.value
11941235
when "max"
11951236
visit(node.receiver.contents)
@@ -1215,13 +1256,10 @@ def visit_call(node)
12151256
end
12161257
end
12171258

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

12241261
visit(node.arguments)
1262+
block_iseq = visit(node.block) if node.respond_to?(:block) && node.block
12251263

12261264
if arg_parts.last.is_a?(ArgBlock)
12271265
flag = node.receiver.nil? ? VM_CALL_FCALL : 0
@@ -1235,7 +1273,12 @@ def visit_call(node)
12351273
flag |= VM_CALL_KW_SPLAT
12361274
end
12371275

1238-
builder.send(node.message.value.to_sym, arg_parts.length - 1, flag)
1276+
builder.send(
1277+
node.message.value.to_sym,
1278+
arg_parts.length - 1,
1279+
flag,
1280+
block_iseq
1281+
)
12391282
else
12401283
flag = 0
12411284
arg_parts.each do |arg_part|
@@ -1247,9 +1290,14 @@ def visit_call(node)
12471290
end
12481291
end
12491292

1250-
flag |= VM_CALL_ARGS_SIMPLE if flag == 0
1293+
flag |= VM_CALL_ARGS_SIMPLE if block_iseq.nil? && flag == 0
12511294
flag |= VM_CALL_FCALL if node.receiver.nil?
1252-
builder.send(node.message.value.to_sym, arg_parts.length, flag)
1295+
builder.send(
1296+
node.message.value.to_sym,
1297+
arg_parts.length,
1298+
flag,
1299+
block_iseq
1300+
)
12531301
end
12541302
end
12551303

@@ -1291,23 +1339,25 @@ def visit_class(node)
12911339

12921340
def visit_command(node)
12931341
visit_call(
1294-
CallNode.new(
1342+
CommandCall.new(
12951343
receiver: nil,
12961344
operator: nil,
12971345
message: node.message,
12981346
arguments: node.arguments,
1347+
block: node.block,
12991348
location: node.location
13001349
)
13011350
)
13021351
end
13031352

13041353
def visit_command_call(node)
13051354
visit_call(
1306-
CallNode.new(
1355+
CommandCall.new(
13071356
receiver: node.receiver,
13081357
operator: node.operator,
13091358
message: node.message,
13101359
arguments: node.arguments,
1360+
block: node.block,
13111361
location: node.location
13121362
)
13131363
)
@@ -1537,6 +1587,19 @@ def visit_label(node)
15371587
builder.putobject(node.accept(RubyVisitor.new))
15381588
end
15391589

1590+
def visit_method_add_block(node)
1591+
visit_call(
1592+
CommandCall.new(
1593+
receiver: node.call.receiver,
1594+
operator: node.call.operator,
1595+
message: node.call.message,
1596+
arguments: node.call.arguments,
1597+
block: node.block,
1598+
location: node.location
1599+
)
1600+
)
1601+
end
1602+
15401603
def visit_module(node)
15411604
name = node.constant.constant.value.to_sym
15421605
module_iseq =
@@ -1898,11 +1961,12 @@ def visit_unary(node)
18981961
end
18991962

19001963
visit_call(
1901-
CallNode.new(
1964+
CommandCall.new(
19021965
receiver: node.statement,
19031966
operator: nil,
19041967
message: Ident.new(value: method_id, location: Location.default),
19051968
arguments: nil,
1969+
block: nil,
19061970
location: Location.default
19071971
)
19081972
)

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)