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

Commit 4631b5c

Browse files
committed
Convert options into an object
1 parent be9465d commit 4631b5c

File tree

4 files changed

+87
-87
lines changed

4 files changed

+87
-87
lines changed

lib/syntax_tree/yarv.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ module SyntaxTree
44
# This module provides an object representation of the YARV bytecode.
55
module YARV
66
# Compile the given source into a YARV instruction sequence.
7-
def self.compile(source, **options)
8-
SyntaxTree.parse(source).accept(Compiler.new(**options))
7+
def self.compile(source, options = Compiler::Options.new)
8+
SyntaxTree.parse(source).accept(Compiler.new(options))
99
end
1010
end
1111
end

lib/syntax_tree/yarv/compiler.rb

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,53 @@ module YARV
4545
# RubyVM::InstructionSequence.compile("1 + 2").to_a
4646
#
4747
class Compiler < BasicVisitor
48+
# This represents a set of options that can be passed to the compiler to
49+
# control how it compiles the code. It mirrors the options that can be
50+
# passed to RubyVM::InstructionSequence.compile, except it only includes
51+
# options that actually change the behavior.
52+
class Options
53+
def initialize(
54+
frozen_string_literal: false,
55+
inline_const_cache: true,
56+
operands_unification: true,
57+
specialized_instruction: true
58+
)
59+
@frozen_string_literal = frozen_string_literal
60+
@inline_const_cache = inline_const_cache
61+
@operands_unification = operands_unification
62+
@specialized_instruction = specialized_instruction
63+
end
64+
65+
def to_hash
66+
{
67+
frozen_string_literal: @frozen_string_literal,
68+
inline_const_cache: @inline_const_cache,
69+
operands_unification: @operands_unification,
70+
specialized_instruction: @specialized_instruction
71+
}
72+
end
73+
74+
def frozen_string_literal!
75+
@frozen_string_literal = true
76+
end
77+
78+
def frozen_string_literal?
79+
@frozen_string_literal
80+
end
81+
82+
def inline_const_cache?
83+
@inline_const_cache
84+
end
85+
86+
def operands_unification?
87+
@operands_unification
88+
end
89+
90+
def specialized_instruction?
91+
@specialized_instruction
92+
end
93+
end
94+
4895
# This visitor is responsible for converting Syntax Tree nodes into their
4996
# corresponding Ruby structures. This is used to convert the operands of
5097
# some instructions like putobject that push a Ruby object directly onto
@@ -203,10 +250,7 @@ def visit_unsupported(_node)
203250

204251
# These options mirror the compilation options that we currently support
205252
# that can be also passed to RubyVM::InstructionSequence.compile.
206-
attr_reader :frozen_string_literal,
207-
:inline_const_cache,
208-
:operands_unification,
209-
:specialized_instruction
253+
attr_reader :options
210254

211255
# The current instruction sequence that is being compiled.
212256
attr_reader :iseq
@@ -216,17 +260,8 @@ def visit_unsupported(_node)
216260
# if we need to return the value of the last statement.
217261
attr_reader :last_statement
218262

219-
def initialize(
220-
frozen_string_literal: false,
221-
inline_const_cache: true,
222-
operands_unification: true,
223-
specialized_instruction: true
224-
)
225-
@frozen_string_literal = frozen_string_literal
226-
@inline_const_cache = inline_const_cache
227-
@operands_unification = operands_unification
228-
@specialized_instruction = specialized_instruction
229-
263+
def initialize(options)
264+
@options = options
230265
@iseq = nil
231266
@last_statement = false
232267
end
@@ -236,7 +271,7 @@ def visit_BEGIN(node)
236271
end
237272

238273
def visit_CHAR(node)
239-
if frozen_string_literal
274+
if options.frozen_string_literal?
240275
iseq.putobject(node.value[1..])
241276
else
242277
iseq.putstring(node.value[1..])
@@ -282,7 +317,7 @@ def visit_aref(node)
282317
calldata = YARV.calldata(:[], 1)
283318
visit(node.collection)
284319

285-
if !frozen_string_literal && specialized_instruction &&
320+
if !options.frozen_string_literal? && options.specialized_instruction? &&
286321
(node.index.parts.length == 1)
287322
arg = node.index.parts.first
288323

@@ -453,7 +488,7 @@ def visit_assign(node)
453488
when ARefField
454489
calldata = YARV.calldata(:[]=, 2)
455490

456-
if !frozen_string_literal && specialized_instruction &&
491+
if !options.frozen_string_literal? && options.specialized_instruction? &&
457492
(node.target.index.parts.length == 1)
458493
arg = node.target.index.parts.first
459494

@@ -1352,7 +1387,7 @@ def visit_program(node)
13521387
break unless statement.is_a?(Comment)
13531388

13541389
if statement.value == "# frozen_string_literal: true"
1355-
@frozen_string_literal = true
1390+
options.frozen_string_literal!
13561391
end
13571392
end
13581393

@@ -1370,18 +1405,7 @@ def visit_program(node)
13701405
end
13711406
end
13721407

1373-
top_iseq =
1374-
InstructionSequence.new(
1375-
:top,
1376-
"<compiled>",
1377-
nil,
1378-
node.location,
1379-
frozen_string_literal: frozen_string_literal,
1380-
inline_const_cache: inline_const_cache,
1381-
operands_unification: operands_unification,
1382-
specialized_instruction: specialized_instruction
1383-
)
1384-
1408+
top_iseq = InstructionSequence.new(:top, "<compiled>", nil, node.location, options)
13851409
with_child_iseq(top_iseq) do
13861410
visit_all(preexes)
13871411

@@ -1402,7 +1426,7 @@ def visit_qsymbols(node)
14021426
end
14031427

14041428
def visit_qwords(node)
1405-
if frozen_string_literal
1429+
if options.frozen_string_literal?
14061430
iseq.duparray(node.accept(RubyVisitor.new))
14071431
else
14081432
visit_all(node.elements)
@@ -1632,7 +1656,7 @@ def visit_top_const_ref(node)
16321656
end
16331657

16341658
def visit_tstring_content(node)
1635-
if frozen_string_literal
1659+
if options.frozen_string_literal?
16361660
iseq.putobject(node.accept(RubyVisitor.new))
16371661
else
16381662
iseq.putstring(node.accept(RubyVisitor.new))
@@ -1808,7 +1832,7 @@ def visit_word(node)
18081832
end
18091833

18101834
def visit_words(node)
1811-
if frozen_string_literal && (compiled = RubyVisitor.compile(node))
1835+
if options.frozen_string_literal? && (compiled = RubyVisitor.compile(node))
18121836
iseq.duparray(compiled)
18131837
else
18141838
visit_all(node.elements)

lib/syntax_tree/yarv/instruction_sequence.rb

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,9 @@ def change_by(value)
7676
attr_reader :stack
7777

7878
# These are various compilation options provided.
79-
attr_reader :frozen_string_literal,
80-
:inline_const_cache,
81-
:operands_unification,
82-
:specialized_instruction
83-
84-
def initialize(
85-
type,
86-
name,
87-
parent_iseq,
88-
location,
89-
frozen_string_literal: false,
90-
inline_const_cache: true,
91-
operands_unification: true,
92-
specialized_instruction: true
93-
)
79+
attr_reader :options
80+
81+
def initialize(type, name, parent_iseq, location, options = Compiler::Options.new)
9482
@type = type
9583
@name = name
9684
@parent_iseq = parent_iseq
@@ -105,10 +93,7 @@ def initialize(
10593
@storage_index = 0
10694
@stack = Stack.new
10795

108-
@frozen_string_literal = frozen_string_literal
109-
@inline_const_cache = inline_const_cache
110-
@operands_unification = operands_unification
111-
@specialized_instruction = specialized_instruction
96+
@options = options
11297
end
11398

11499
##########################################################################
@@ -189,16 +174,7 @@ def to_a
189174
##########################################################################
190175

191176
def child_iseq(type, name, location)
192-
InstructionSequence.new(
193-
type,
194-
name,
195-
self,
196-
location,
197-
frozen_string_literal: frozen_string_literal,
198-
inline_const_cache: inline_const_cache,
199-
operands_unification: operands_unification,
200-
specialized_instruction: specialized_instruction
201-
)
177+
InstructionSequence.new(type, name, self, location, options)
202178
end
203179

204180
def block_child_iseq(location)
@@ -359,7 +335,7 @@ def getinstancevariable(name)
359335
end
360336

361337
def getlocal(index, level)
362-
if operands_unification
338+
if options.operands_unification?
363339
# Specialize the getlocal instruction based on the level of the
364340
# local variable. If it's 0 or 1, then there's a specialized
365341
# instruction that will look at the current scope or the parent
@@ -438,11 +414,11 @@ def opt_aset_with(object, calldata)
438414
end
439415

440416
def opt_getconstant_path(names)
441-
if RUBY_VERSION < "3.2" || !inline_const_cache
417+
if RUBY_VERSION < "3.2" || !options.inline_const_cache?
442418
cache = nil
443419
getinlinecache = nil
444420

445-
if inline_const_cache
421+
if options.inline_const_cache?
446422
cache = inline_storage
447423
getinlinecache = opt_getinlinecache(-1, cache)
448424

@@ -463,7 +439,7 @@ def opt_getconstant_path(names)
463439
getconstant(name)
464440
end
465441

466-
if inline_const_cache
442+
if options.inline_const_cache?
467443
opt_setinlinecache(cache)
468444
getinlinecache.patch!(self)
469445
end
@@ -477,7 +453,7 @@ def opt_getinlinecache(label, cache)
477453
end
478454

479455
def opt_newarray_max(length)
480-
if specialized_instruction
456+
if options.specialized_instruction?
481457
push(OptNewArrayMax.new(length))
482458
else
483459
newarray(length)
@@ -486,7 +462,7 @@ def opt_newarray_max(length)
486462
end
487463

488464
def opt_newarray_min(length)
489-
if specialized_instruction
465+
if options.specialized_instruction?
490466
push(OptNewArrayMin.new(length))
491467
else
492468
newarray(length)
@@ -499,7 +475,7 @@ def opt_setinlinecache(cache)
499475
end
500476

501477
def opt_str_freeze(object)
502-
if specialized_instruction
478+
if options.specialized_instruction?
503479
push(OptStrFreeze.new(object, YARV.calldata(:freeze)))
504480
else
505481
putstring(object)
@@ -508,7 +484,7 @@ def opt_str_freeze(object)
508484
end
509485

510486
def opt_str_uminus(object)
511-
if specialized_instruction
487+
if options.specialized_instruction?
512488
push(OptStrUMinus.new(object, YARV.calldata(:-@)))
513489
else
514490
putstring(object)
@@ -525,7 +501,7 @@ def putnil
525501
end
526502

527503
def putobject(object)
528-
if operands_unification
504+
if options.operands_unification?
529505
# Specialize the putobject instruction based on the value of the
530506
# object. If it's 0 or 1, then there's a specialized instruction
531507
# that will push the object onto the stack and requires fewer
@@ -555,7 +531,7 @@ def putstring(object)
555531
end
556532

557533
def send(calldata, block_iseq = nil)
558-
if specialized_instruction && !block_iseq &&
534+
if options.specialized_instruction? && !block_iseq &&
559535
!calldata.flag?(CallData::CALL_ARGS_BLOCKARG)
560536
# Specialize the send instruction. If it doesn't have a block
561537
# attached, then we will replace it with an opt_send_without_block
@@ -645,7 +621,7 @@ def setinstancevariable(name)
645621
end
646622

647623
def setlocal(index, level)
648-
if operands_unification
624+
if options.operands_unification?
649625
# Specialize the setlocal instruction based on the level of the
650626
# local variable. If it's 0 or 1, then there's a specialized
651627
# instruction that will write to the current scope or the parent

test/compiler_test.rb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -428,20 +428,20 @@ class CompilerTest < Minitest::Test
428428

429429
# These are the combinations of instructions that we're going to test.
430430
OPTIONS = [
431-
{},
432-
{ frozen_string_literal: true },
433-
{ operands_unification: false },
434-
{ specialized_instruction: false },
435-
{ inline_const_cache: false },
436-
{ operands_unification: false, specialized_instruction: false }
431+
YARV::Compiler::Options.new,
432+
YARV::Compiler::Options.new(frozen_string_literal: true),
433+
YARV::Compiler::Options.new(operands_unification: false),
434+
YARV::Compiler::Options.new(specialized_instruction: false),
435+
YARV::Compiler::Options.new(inline_const_cache: false),
436+
YARV::Compiler::Options.new(operands_unification: false, specialized_instruction: false)
437437
]
438438

439439
OPTIONS.each do |options|
440440
suffix = options.inspect
441441

442442
CASES.each do |source|
443443
define_method(:"test_#{source}_#{suffix}") do
444-
assert_compiles(source, **options)
444+
assert_compiles(source, options)
445445
end
446446
end
447447
end
@@ -481,17 +481,17 @@ def serialize_iseq(iseq)
481481
serialized
482482
end
483483

484-
def assert_compiles(source, **options)
484+
def assert_compiles(source, options)
485485
program = SyntaxTree.parse(source)
486486

487487
assert_equal(
488488
serialize_iseq(RubyVM::InstructionSequence.compile(source, **options)),
489-
serialize_iseq(program.accept(YARV::Compiler.new(**options)))
489+
serialize_iseq(program.accept(YARV::Compiler.new(options)))
490490
)
491491
end
492492

493-
def assert_evaluates(expected, source, **options)
494-
assert_equal expected, YARV.compile(source, **options).eval
493+
def assert_evaluates(expected, source)
494+
assert_equal expected, YARV.compile(source).eval
495495
end
496496
end
497497
end

0 commit comments

Comments
 (0)