syntax_tree 5.0.1 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,215 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SyntaxTree
4
+ module YARV
5
+ # This module contains the instructions that used to be a part of YARV but
6
+ # have been replaced or removed in more recent versions.
7
+ module Legacy
8
+ # ### Summary
9
+ #
10
+ # `getclassvariable` looks for a class variable in the current class and
11
+ # pushes its value onto the stack.
12
+ #
13
+ # This version of the `getclassvariable` instruction is no longer used
14
+ # since in Ruby 3.0 it gained an inline cache.`
15
+ #
16
+ # ### Usage
17
+ #
18
+ # ~~~ruby
19
+ # @@class_variable
20
+ # ~~~
21
+ #
22
+ class GetClassVariable
23
+ attr_reader :name
24
+
25
+ def initialize(name)
26
+ @name = name
27
+ end
28
+
29
+ def disasm(fmt)
30
+ fmt.instruction("getclassvariable", [fmt.object(name)])
31
+ end
32
+
33
+ def to_a(_iseq)
34
+ [:getclassvariable, name]
35
+ end
36
+
37
+ def length
38
+ 2
39
+ end
40
+
41
+ def pops
42
+ 0
43
+ end
44
+
45
+ def pushes
46
+ 1
47
+ end
48
+
49
+ def canonical
50
+ YARV::GetClassVariable.new(name, nil)
51
+ end
52
+
53
+ def call(vm)
54
+ canonical.call(vm)
55
+ end
56
+ end
57
+
58
+ # ### Summary
59
+ #
60
+ # `opt_getinlinecache` is a wrapper around a series of `putobject` and
61
+ # `getconstant` instructions that allows skipping past them if the inline
62
+ # cache is currently set. It pushes the value of the cache onto the stack
63
+ # if it is set, otherwise it pushes `nil`.
64
+ #
65
+ # This instruction is no longer used since in Ruby 3.2 it was replaced by
66
+ # the consolidated `opt_getconstant_path` instruction.
67
+ #
68
+ # ### Usage
69
+ #
70
+ # ~~~ruby
71
+ # Constant
72
+ # ~~~
73
+ #
74
+ class OptGetInlineCache
75
+ attr_reader :label, :cache
76
+
77
+ def initialize(label, cache)
78
+ @label = label
79
+ @cache = cache
80
+ end
81
+
82
+ def disasm(fmt)
83
+ fmt.instruction(
84
+ "opt_getinlinecache",
85
+ [fmt.label(label), fmt.inline_storage(cache)]
86
+ )
87
+ end
88
+
89
+ def to_a(_iseq)
90
+ [:opt_getinlinecache, label.name, cache]
91
+ end
92
+
93
+ def length
94
+ 3
95
+ end
96
+
97
+ def pops
98
+ 0
99
+ end
100
+
101
+ def pushes
102
+ 1
103
+ end
104
+
105
+ def canonical
106
+ self
107
+ end
108
+
109
+ def call(vm)
110
+ vm.push(nil)
111
+ end
112
+ end
113
+
114
+ # ### Summary
115
+ #
116
+ # `opt_setinlinecache` sets an inline cache for a constant lookup. It pops
117
+ # the value it should set off the top of the stack. It uses this value to
118
+ # set the cache. It then pushes that value back onto the top of the stack.
119
+ #
120
+ # This instruction is no longer used since in Ruby 3.2 it was replaced by
121
+ # the consolidated `opt_getconstant_path` instruction.
122
+ #
123
+ # ### Usage
124
+ #
125
+ # ~~~ruby
126
+ # Constant
127
+ # ~~~
128
+ #
129
+ class OptSetInlineCache
130
+ attr_reader :cache
131
+
132
+ def initialize(cache)
133
+ @cache = cache
134
+ end
135
+
136
+ def disasm(fmt)
137
+ fmt.instruction("opt_setinlinecache", [fmt.inline_storage(cache)])
138
+ end
139
+
140
+ def to_a(_iseq)
141
+ [:opt_setinlinecache, cache]
142
+ end
143
+
144
+ def length
145
+ 2
146
+ end
147
+
148
+ def pops
149
+ 1
150
+ end
151
+
152
+ def pushes
153
+ 1
154
+ end
155
+
156
+ def canonical
157
+ self
158
+ end
159
+
160
+ def call(vm)
161
+ end
162
+ end
163
+
164
+ # ### Summary
165
+ #
166
+ # `setclassvariable` looks for a class variable in the current class and
167
+ # sets its value to the value it pops off the top of the stack.
168
+ #
169
+ # This version of the `setclassvariable` instruction is no longer used
170
+ # since in Ruby 3.0 it gained an inline cache.
171
+ #
172
+ # ### Usage
173
+ #
174
+ # ~~~ruby
175
+ # @@class_variable = 1
176
+ # ~~~
177
+ #
178
+ class SetClassVariable
179
+ attr_reader :name
180
+
181
+ def initialize(name)
182
+ @name = name
183
+ end
184
+
185
+ def disasm(fmt)
186
+ fmt.instruction("setclassvariable", [fmt.object(name)])
187
+ end
188
+
189
+ def to_a(_iseq)
190
+ [:setclassvariable, name]
191
+ end
192
+
193
+ def length
194
+ 2
195
+ end
196
+
197
+ def pops
198
+ 1
199
+ end
200
+
201
+ def pushes
202
+ 0
203
+ end
204
+
205
+ def canonical
206
+ YARV::SetClassVariable.new(name, nil)
207
+ end
208
+
209
+ def call(vm)
210
+ canonical.call(vm)
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SyntaxTree
4
+ module YARV
5
+ # This represents every local variable associated with an instruction
6
+ # sequence. There are two kinds of locals: plain locals that are what you
7
+ # expect, and block proxy locals, which represent local variables
8
+ # associated with blocks that were passed into the current instruction
9
+ # sequence.
10
+ class LocalTable
11
+ # A local representing a block passed into the current instruction
12
+ # sequence.
13
+ class BlockLocal
14
+ attr_reader :name
15
+
16
+ def initialize(name)
17
+ @name = name
18
+ end
19
+ end
20
+
21
+ # A regular local variable.
22
+ class PlainLocal
23
+ attr_reader :name
24
+
25
+ def initialize(name)
26
+ @name = name
27
+ end
28
+ end
29
+
30
+ # The result of looking up a local variable in the current local table.
31
+ class Lookup
32
+ attr_reader :local, :index, :level
33
+
34
+ def initialize(local, index, level)
35
+ @local = local
36
+ @index = index
37
+ @level = level
38
+ end
39
+ end
40
+
41
+ attr_reader :locals
42
+
43
+ def initialize
44
+ @locals = []
45
+ end
46
+
47
+ def empty?
48
+ locals.empty?
49
+ end
50
+
51
+ def find(name, level = 0)
52
+ index = locals.index { |local| local.name == name }
53
+ Lookup.new(locals[index], index, level) if index
54
+ end
55
+
56
+ def has?(name)
57
+ locals.any? { |local| local.name == name }
58
+ end
59
+
60
+ def names
61
+ locals.map(&:name)
62
+ end
63
+
64
+ def name_at(index)
65
+ locals[index].name
66
+ end
67
+
68
+ def size
69
+ locals.length
70
+ end
71
+
72
+ # Add a BlockLocal to the local table.
73
+ def block(name)
74
+ locals << BlockLocal.new(name) unless has?(name)
75
+ end
76
+
77
+ # Add a PlainLocal to the local table.
78
+ def plain(name)
79
+ locals << PlainLocal.new(name) unless has?(name)
80
+ end
81
+
82
+ # This is the offset from the top of the stack where this local variable
83
+ # lives.
84
+ def offset(index)
85
+ size - (index - 3) - 1
86
+ end
87
+ end
88
+ end
89
+ end