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

Commit a7e7825

Browse files
committed
Handle BEGIN{} and END{}
1 parent db88d33 commit a7e7825

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

lib/syntax_tree/visitor/compiler.rb

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,6 @@ def local_variable(name, level = 0)
336336
lookup
337337
elsif parent_iseq
338338
parent_iseq.local_variable(name, level + 1)
339-
else
340-
raise "Unknown local variable: #{name}"
341339
end
342340
end
343341

@@ -388,7 +386,7 @@ def to_a
388386
name,
389387
"<compiled>",
390388
"<compiled>",
391-
1,
389+
location.start_line,
392390
type,
393391
local_table.names,
394392
argument_options,
@@ -424,6 +422,8 @@ def serialize(insn)
424422
# For any instructions that push instruction sequences onto the
425423
# stack, we need to call #to_a on them as well.
426424
[insn[0], insn[1], (insn[2].to_a if insn[2])]
425+
when :once
426+
[insn[0], insn[1].to_a, insn[2]]
427427
else
428428
insn
429429
end
@@ -655,6 +655,11 @@ def objtostring(method_id, argc, flag)
655655
iseq.push([:objtostring, call_data(method_id, argc, flag)])
656656
end
657657

658+
def once(postexe_iseq, inline_storage)
659+
stack.change_by(+1)
660+
iseq.push([:once, postexe_iseq, inline_storage])
661+
end
662+
658663
def opt_getconstant_path(names)
659664
if RUBY_VERSION >= "3.2"
660665
stack.change_by(+1)
@@ -1002,6 +1007,10 @@ def initialize(
10021007
@last_statement = false
10031008
end
10041009

1010+
def visit_BEGIN(node)
1011+
visit(node.statements)
1012+
end
1013+
10051014
def visit_CHAR(node)
10061015
if frozen_string_literal
10071016
builder.putobject(node.value[1..])
@@ -1010,6 +1019,27 @@ def visit_CHAR(node)
10101019
end
10111020
end
10121021

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+
10131043
def visit_alias(node)
10141044
builder.putspecialobject(VM_SPECIAL_OBJECT_VMCORE)
10151045
builder.putspecialobject(VM_SPECIAL_OBJECT_CBASE)
@@ -1898,17 +1928,23 @@ def visit_program(node)
18981928
end
18991929
end
19001930

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
19091942
end
1943+
end
19101944

19111945
with_instruction_sequence(:top, "<compiled>", nil, node) do
1946+
visit_all(preexes)
1947+
19121948
if statements.empty?
19131949
builder.putnil
19141950
else
@@ -2144,8 +2180,13 @@ def visit_var_field(node)
21442180
current_iseq.inline_storage_for(name)
21452181
when Ident
21462182
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
21492190
end
21502191
end
21512192

@@ -2460,12 +2501,13 @@ def with_instruction_sequence(type, name, parent_iseq, node)
24602501
# last statement of a scope and allow visit methods to query that
24612502
# information.
24622503
def with_last_statement
2504+
previous = @last_statement
24632505
@last_statement = true
24642506

24652507
begin
24662508
yield
24672509
ensure
2468-
@last_statement = false
2510+
@last_statement = previous
24692511
end
24702512
end
24712513

0 commit comments

Comments
 (0)