syntax_tree 5.1.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,277 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "forwardable"
4
-
5
3
  module SyntaxTree
6
4
  # This module provides an object representation of the YARV bytecode.
7
5
  module YARV
8
- class VM
9
- class Jump
10
- attr_reader :name
11
-
12
- def initialize(name)
13
- @name = name
14
- end
15
- end
16
-
17
- class Leave
18
- attr_reader :value
19
-
20
- def initialize(value)
21
- @value = value
22
- end
23
- end
24
-
25
- class Frame
26
- attr_reader :iseq, :parent, :stack_index, :_self, :nesting, :svars
27
-
28
- def initialize(iseq, parent, stack_index, _self, nesting)
29
- @iseq = iseq
30
- @parent = parent
31
- @stack_index = stack_index
32
- @_self = _self
33
- @nesting = nesting
34
- @svars = {}
35
- end
36
- end
37
-
38
- class TopFrame < Frame
39
- def initialize(iseq)
40
- super(iseq, nil, 0, TOPLEVEL_BINDING.eval("self"), [Object])
41
- end
42
- end
43
-
44
- class BlockFrame < Frame
45
- def initialize(iseq, parent, stack_index)
46
- super(iseq, parent, stack_index, parent._self, parent.nesting)
47
- end
48
- end
49
-
50
- class MethodFrame < Frame
51
- attr_reader :name, :block
52
-
53
- def initialize(iseq, parent, stack_index, _self, name, block)
54
- super(iseq, parent, stack_index, _self, parent.nesting)
55
- @name = name
56
- @block = block
57
- end
58
- end
59
-
60
- class ClassFrame < Frame
61
- def initialize(iseq, parent, stack_index, _self)
62
- super(iseq, parent, stack_index, _self, parent.nesting + [_self])
63
- end
64
- end
65
-
66
- class FrozenCore
67
- define_method("core#hash_merge_kwd") { |left, right| left.merge(right) }
68
-
69
- define_method("core#hash_merge_ptr") do |hash, *values|
70
- hash.merge(values.each_slice(2).to_h)
71
- end
72
-
73
- define_method("core#set_method_alias") do |clazz, new_name, old_name|
74
- clazz.alias_method(new_name, old_name)
75
- end
76
-
77
- define_method("core#set_variable_alias") do |new_name, old_name|
78
- # Using eval here since there isn't a reflection API to be able to
79
- # alias global variables.
80
- eval("alias #{new_name} #{old_name}", binding, __FILE__, __LINE__)
81
- end
82
-
83
- define_method("core#set_postexe") { |&block| END { block.call } }
84
-
85
- define_method("core#undef_method") do |clazz, name|
86
- clazz.undef_method(name)
87
- end
88
- end
89
-
90
- FROZEN_CORE = FrozenCore.new.freeze
91
-
92
- extend Forwardable
93
-
94
- attr_reader :stack
95
- def_delegators :stack, :push, :pop
96
-
97
- attr_reader :frame
98
- def_delegators :frame, :_self
99
-
100
- def initialize
101
- @stack = []
102
- @frame = nil
103
- end
104
-
105
- ##########################################################################
106
- # Helper methods for frames
107
- ##########################################################################
108
-
109
- def run_frame(frame)
110
- # First, set the current frame to the given value.
111
- @frame = frame
112
-
113
- # Next, set up the local table for the frame. This is actually incorrect
114
- # as it could use the values already on the stack, but for now we're
115
- # just doing this for simplicity.
116
- frame.iseq.local_table.size.times { push(nil) }
117
-
118
- # Yield so that some frame-specific setup can be done.
119
- yield if block_given?
120
-
121
- # This hash is going to hold a mapping of label names to their
122
- # respective indices in our instruction list.
123
- labels = {}
124
-
125
- # This array is going to hold our instructions.
126
- insns = []
127
-
128
- # Here we're going to preprocess the instruction list from the
129
- # instruction sequence to set up the labels hash and the insns array.
130
- frame.iseq.insns.each do |insn|
131
- case insn
132
- when Integer, Symbol
133
- # skip
134
- when InstructionSequence::Label
135
- labels[insn.name] = insns.length
136
- else
137
- insns << insn
138
- end
139
- end
140
-
141
- # Finally we can execute the instructions one at a time. If they return
142
- # jumps or leaves we will handle those appropriately.
143
- pc = 0
144
- while pc < insns.length
145
- insn = insns[pc]
146
- pc += 1
147
-
148
- case (result = insn.call(self))
149
- when Jump
150
- pc = labels[result.name]
151
- when Leave
152
- return result.value
153
- end
154
- end
155
- ensure
156
- @stack = stack[0...frame.stack_index]
157
- @frame = frame.parent
158
- end
159
-
160
- def run_top_frame(iseq)
161
- run_frame(TopFrame.new(iseq))
162
- end
163
-
164
- def run_block_frame(iseq, *args, &block)
165
- run_frame(BlockFrame.new(iseq, frame, stack.length)) do
166
- locals = [*args, block]
167
- iseq.local_table.size.times do |index|
168
- local_set(index, 0, locals.shift)
169
- end
170
- end
171
- end
172
-
173
- def run_class_frame(iseq, clazz)
174
- run_frame(ClassFrame.new(iseq, frame, stack.length, clazz))
175
- end
176
-
177
- def run_method_frame(name, iseq, _self, *args, **kwargs, &block)
178
- run_frame(
179
- MethodFrame.new(iseq, frame, stack.length, _self, name, block)
180
- ) do
181
- locals = [*args, block]
182
-
183
- if iseq.argument_options[:keyword]
184
- # First, set up the keyword bits array.
185
- keyword_bits =
186
- iseq.argument_options[:keyword].map do |config|
187
- kwargs.key?(config.is_a?(Array) ? config[0] : config)
188
- end
189
-
190
- iseq.local_table.locals.each_with_index do |local, index|
191
- # If this is the keyword bits local, then set it appropriately.
192
- if local.name == 2
193
- locals.insert(index, keyword_bits)
194
- next
195
- end
196
-
197
- # First, find the configuration for this local in the keywords
198
- # list if it exists.
199
- name = local.name
200
- config =
201
- iseq.argument_options[:keyword].find do |keyword|
202
- keyword.is_a?(Array) ? keyword[0] == name : keyword == name
203
- end
204
-
205
- # If the configuration doesn't exist, then the local is not a
206
- # keyword local.
207
- next unless config
208
-
209
- if !config.is_a?(Array)
210
- # required keyword
211
- locals.insert(index, kwargs.fetch(name))
212
- elsif !config[1].nil?
213
- # optional keyword with embedded default value
214
- locals.insert(index, kwargs.fetch(name, config[1]))
215
- else
216
- # optional keyword with expression default value
217
- locals.insert(index, nil)
218
- end
219
- end
220
- end
221
-
222
- iseq.local_table.size.times do |index|
223
- local_set(index, 0, locals.shift)
224
- end
225
- end
226
- end
227
-
228
- ##########################################################################
229
- # Helper methods for instructions
230
- ##########################################################################
231
-
232
- def const_base
233
- frame.nesting.last
234
- end
235
-
236
- def frame_at(level)
237
- current = frame
238
- level.times { current = current.parent }
239
- current
240
- end
241
-
242
- def frame_svar
243
- current = frame
244
- current = current.parent while current.is_a?(BlockFrame)
245
- current
246
- end
247
-
248
- def frame_yield
249
- current = frame
250
- current = current.parent until current.is_a?(MethodFrame)
251
- current
252
- end
253
-
254
- def frozen_core
255
- FROZEN_CORE
256
- end
257
-
258
- def jump(label)
259
- Jump.new(label.name)
260
- end
261
-
262
- def leave
263
- Leave.new(pop)
264
- end
265
-
266
- def local_get(index, level)
267
- stack[frame_at(level).stack_index + index]
268
- end
269
-
270
- def local_set(index, level, value)
271
- stack[frame_at(level).stack_index + index] = value
272
- end
273
- end
274
-
275
6
  # Compile the given source into a YARV instruction sequence.
276
7
  def self.compile(source, options = Compiler::Options.new)
277
8
  SyntaxTree.parse(source).accept(Compiler.new(options))
data/lib/syntax_tree.rb CHANGED
@@ -26,6 +26,7 @@ require_relative "syntax_tree/visitor/with_environment"
26
26
  require_relative "syntax_tree/parser"
27
27
  require_relative "syntax_tree/pattern"
28
28
  require_relative "syntax_tree/search"
29
+ require_relative "syntax_tree/index"
29
30
 
30
31
  require_relative "syntax_tree/yarv"
31
32
  require_relative "syntax_tree/yarv/bf"
@@ -37,6 +38,7 @@ require_relative "syntax_tree/yarv/instructions"
37
38
  require_relative "syntax_tree/yarv/legacy"
38
39
  require_relative "syntax_tree/yarv/local_table"
39
40
  require_relative "syntax_tree/yarv/assembler"
41
+ require_relative "syntax_tree/yarv/vm"
40
42
 
41
43
  # Syntax Tree is a suite of tools built on top of the internal CRuby parser. It
42
44
  # provides the ability to generate a syntax tree from source, as well as the
@@ -115,4 +117,18 @@ module SyntaxTree
115
117
  def self.search(source, query, &block)
116
118
  Search.new(Pattern.new(query).compile).scan(parse(source), &block)
117
119
  end
120
+
121
+ # Indexes the given source code to return a list of all class, module, and
122
+ # method definitions. Used to quickly provide indexing capability for IDEs or
123
+ # documentation generation.
124
+ def self.index(source)
125
+ Index.index(source)
126
+ end
127
+
128
+ # Indexes the given file to return a list of all class, module, and method
129
+ # definitions. Used to quickly provide indexing capability for IDEs or
130
+ # documentation generation.
131
+ def self.index_file(filepath)
132
+ Index.index_file(filepath)
133
+ end
118
134
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syntax_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Newton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-29 00:00:00.000000000 Z
11
+ date: 2023-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prettier_print
@@ -99,6 +99,7 @@ email:
99
99
  - kddnewton@gmail.com
100
100
  executables:
101
101
  - stree
102
+ - yarv
102
103
  extensions: []
103
104
  extra_rdoc_files: []
104
105
  files:
@@ -108,6 +109,7 @@ files:
108
109
  - ".github/workflows/gh-pages.yml"
109
110
  - ".github/workflows/main.yml"
110
111
  - ".gitignore"
112
+ - ".gitmodules"
111
113
  - ".rubocop.yml"
112
114
  - CHANGELOG.md
113
115
  - CODE_OF_CONDUCT.md
@@ -122,16 +124,19 @@ files:
122
124
  - config/rubocop.yml
123
125
  - doc/logo.svg
124
126
  - exe/stree
127
+ - exe/yarv
125
128
  - lib/syntax_tree.rb
126
129
  - lib/syntax_tree/basic_visitor.rb
127
130
  - lib/syntax_tree/cli.rb
128
131
  - lib/syntax_tree/dsl.rb
129
132
  - lib/syntax_tree/formatter.rb
133
+ - lib/syntax_tree/index.rb
130
134
  - lib/syntax_tree/language_server.rb
131
135
  - lib/syntax_tree/language_server/inlay_hints.rb
132
136
  - lib/syntax_tree/node.rb
133
137
  - lib/syntax_tree/parser.rb
134
138
  - lib/syntax_tree/pattern.rb
139
+ - lib/syntax_tree/plugin/disable_ternary.rb
135
140
  - lib/syntax_tree/plugin/single_quotes.rb
136
141
  - lib/syntax_tree/plugin/trailing_comma.rb
137
142
  - lib/syntax_tree/rake/check_task.rb
@@ -158,6 +163,7 @@ files:
158
163
  - lib/syntax_tree/yarv/instructions.rb
159
164
  - lib/syntax_tree/yarv/legacy.rb
160
165
  - lib/syntax_tree/yarv/local_table.rb
166
+ - lib/syntax_tree/yarv/vm.rb
161
167
  - syntax_tree.gemspec
162
168
  homepage: https://github.com/kddnewton/syntax_tree
163
169
  licenses:
@@ -179,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
185
  - !ruby/object:Gem::Version
180
186
  version: '0'
181
187
  requirements: []
182
- rubygems_version: 3.3.21
188
+ rubygems_version: 3.4.1
183
189
  signing_key:
184
190
  specification_version: 4
185
191
  summary: A parser based on ripper