@@ -336,8 +336,6 @@ def local_variable(name, level = 0)
336
336
lookup
337
337
elsif parent_iseq
338
338
parent_iseq . local_variable ( name , level + 1 )
339
- else
340
- raise "Unknown local variable: #{ name } "
341
339
end
342
340
end
343
341
@@ -388,7 +386,7 @@ def to_a
388
386
name ,
389
387
"<compiled>" ,
390
388
"<compiled>" ,
391
- 1 ,
389
+ location . start_line ,
392
390
type ,
393
391
local_table . names ,
394
392
argument_options ,
@@ -424,6 +422,8 @@ def serialize(insn)
424
422
# For any instructions that push instruction sequences onto the
425
423
# stack, we need to call #to_a on them as well.
426
424
[ insn [ 0 ] , insn [ 1 ] , ( insn [ 2 ] . to_a if insn [ 2 ] ) ]
425
+ when :once
426
+ [ insn [ 0 ] , insn [ 1 ] . to_a , insn [ 2 ] ]
427
427
else
428
428
insn
429
429
end
@@ -655,6 +655,11 @@ def objtostring(method_id, argc, flag)
655
655
iseq . push ( [ :objtostring , call_data ( method_id , argc , flag ) ] )
656
656
end
657
657
658
+ def once ( postexe_iseq , inline_storage )
659
+ stack . change_by ( +1 )
660
+ iseq . push ( [ :once , postexe_iseq , inline_storage ] )
661
+ end
662
+
658
663
def opt_getconstant_path ( names )
659
664
if RUBY_VERSION >= "3.2"
660
665
stack . change_by ( +1 )
@@ -1002,6 +1007,10 @@ def initialize(
1002
1007
@last_statement = false
1003
1008
end
1004
1009
1010
+ def visit_BEGIN ( node )
1011
+ visit ( node . statements )
1012
+ end
1013
+
1005
1014
def visit_CHAR ( node )
1006
1015
if frozen_string_literal
1007
1016
builder . putobject ( node . value [ 1 ..] )
@@ -1010,6 +1019,27 @@ def visit_CHAR(node)
1010
1019
end
1011
1020
end
1012
1021
1022
+ def visit_END ( node )
1023
+ name = "block in #{ current_iseq . name } "
1024
+ once_iseq =
1025
+ with_instruction_sequence ( :block , name , current_iseq , node ) do
1026
+ postexe_iseq =
1027
+ with_instruction_sequence ( :block , name , current_iseq , node ) do
1028
+ *statements , last_statement = node . statements . body
1029
+ visit_all ( statements )
1030
+ with_last_statement { visit ( last_statement ) }
1031
+ builder . leave
1032
+ end
1033
+
1034
+ builder . putspecialobject ( VM_SPECIAL_OBJECT_VMCORE )
1035
+ builder . send ( :"core#set_postexe" , 0 , VM_CALL_FCALL , postexe_iseq )
1036
+ builder . leave
1037
+ end
1038
+
1039
+ builder . once ( once_iseq , current_iseq . inline_storage )
1040
+ builder . pop
1041
+ end
1042
+
1013
1043
def visit_alias ( node )
1014
1044
builder . putspecialobject ( VM_SPECIAL_OBJECT_VMCORE )
1015
1045
builder . putspecialobject ( VM_SPECIAL_OBJECT_CBASE )
@@ -1898,17 +1928,23 @@ def visit_program(node)
1898
1928
end
1899
1929
end
1900
1930
1901
- statements =
1902
- node . statements . body . select do |statement |
1903
- case statement
1904
- when Comment , EmbDoc , EndContent , VoidStmt
1905
- false
1906
- else
1907
- true
1908
- end
1931
+ preexes = [ ]
1932
+ statements = [ ]
1933
+
1934
+ node . statements . body . each do |statement |
1935
+ case statement
1936
+ when Comment , EmbDoc , EndContent , VoidStmt
1937
+ # ignore
1938
+ when BEGINBlock
1939
+ preexes << statement
1940
+ else
1941
+ statements << statement
1909
1942
end
1943
+ end
1910
1944
1911
1945
with_instruction_sequence ( :top , "<compiled>" , nil , node ) do
1946
+ visit_all ( preexes )
1947
+
1912
1948
if statements . empty?
1913
1949
builder . putnil
1914
1950
else
@@ -2144,8 +2180,13 @@ def visit_var_field(node)
2144
2180
current_iseq . inline_storage_for ( name )
2145
2181
when Ident
2146
2182
name = node . value . value . to_sym
2147
- current_iseq . local_table . plain ( name )
2148
- current_iseq . local_variable ( name )
2183
+
2184
+ if ( local_variable = current_iseq . local_variable ( name ) )
2185
+ local_variable
2186
+ else
2187
+ current_iseq . local_table . plain ( name )
2188
+ current_iseq . local_variable ( name )
2189
+ end
2149
2190
end
2150
2191
end
2151
2192
@@ -2460,12 +2501,13 @@ def with_instruction_sequence(type, name, parent_iseq, node)
2460
2501
# last statement of a scope and allow visit methods to query that
2461
2502
# information.
2462
2503
def with_last_statement
2504
+ previous = @last_statement
2463
2505
@last_statement = true
2464
2506
2465
2507
begin
2466
2508
yield
2467
2509
ensure
2468
- @last_statement = false
2510
+ @last_statement = previous
2469
2511
end
2470
2512
end
2471
2513
0 commit comments