syntax_tree 5.3.0 → 6.0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -1
- data/CHANGELOG.md +64 -1
- data/Gemfile.lock +2 -2
- data/README.md +28 -9
- data/Rakefile +12 -8
- data/bin/console +1 -0
- data/bin/whitequark +79 -0
- data/doc/changing_structure.md +16 -0
- data/lib/syntax_tree/basic_visitor.rb +44 -5
- data/lib/syntax_tree/cli.rb +2 -2
- data/lib/syntax_tree/dsl.rb +23 -11
- data/lib/syntax_tree/{visitor/field_visitor.rb → field_visitor.rb} +54 -55
- data/lib/syntax_tree/formatter.rb +1 -1
- data/lib/syntax_tree/index.rb +56 -54
- data/lib/syntax_tree/json_visitor.rb +55 -0
- data/lib/syntax_tree/language_server.rb +157 -2
- data/lib/syntax_tree/match_visitor.rb +120 -0
- data/lib/syntax_tree/mermaid.rb +177 -0
- data/lib/syntax_tree/mermaid_visitor.rb +69 -0
- data/lib/syntax_tree/{visitor/mutation_visitor.rb → mutation_visitor.rb} +27 -27
- data/lib/syntax_tree/node.rb +198 -107
- data/lib/syntax_tree/parser.rb +322 -118
- data/lib/syntax_tree/pretty_print_visitor.rb +83 -0
- data/lib/syntax_tree/reflection.rb +241 -0
- data/lib/syntax_tree/translation/parser.rb +3019 -0
- data/lib/syntax_tree/translation/rubocop_ast.rb +21 -0
- data/lib/syntax_tree/translation.rb +28 -0
- data/lib/syntax_tree/version.rb +1 -1
- data/lib/syntax_tree/with_scope.rb +244 -0
- data/lib/syntax_tree/yarv/basic_block.rb +53 -0
- data/lib/syntax_tree/yarv/calldata.rb +91 -0
- data/lib/syntax_tree/yarv/compiler.rb +110 -100
- data/lib/syntax_tree/yarv/control_flow_graph.rb +257 -0
- data/lib/syntax_tree/yarv/data_flow_graph.rb +338 -0
- data/lib/syntax_tree/yarv/decompiler.rb +1 -1
- data/lib/syntax_tree/yarv/disassembler.rb +104 -80
- data/lib/syntax_tree/yarv/instruction_sequence.rb +43 -18
- data/lib/syntax_tree/yarv/instructions.rb +203 -649
- data/lib/syntax_tree/yarv/legacy.rb +12 -24
- data/lib/syntax_tree/yarv/sea_of_nodes.rb +534 -0
- data/lib/syntax_tree/yarv.rb +18 -0
- data/lib/syntax_tree.rb +88 -56
- data/tasks/sorbet.rake +277 -0
- data/tasks/whitequark.rake +87 -0
- metadata +23 -11
- data/.gitmodules +0 -9
- data/lib/syntax_tree/language_server/inlay_hints.rb +0 -159
- data/lib/syntax_tree/visitor/environment.rb +0 -84
- data/lib/syntax_tree/visitor/json_visitor.rb +0 -55
- data/lib/syntax_tree/visitor/match_visitor.rb +0 -122
- data/lib/syntax_tree/visitor/pretty_print_visitor.rb +0 -85
- data/lib/syntax_tree/visitor/with_environment.rb +0 -140
data/lib/syntax_tree.rb
CHANGED
@@ -1,50 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "etc"
|
4
|
-
require "fiddle"
|
5
|
-
require "json"
|
6
|
-
require "pp"
|
7
3
|
require "prettier_print"
|
8
4
|
require "ripper"
|
9
|
-
require "stringio"
|
10
5
|
|
11
|
-
require_relative "syntax_tree/formatter"
|
12
6
|
require_relative "syntax_tree/node"
|
13
|
-
require_relative "syntax_tree/dsl"
|
14
|
-
require_relative "syntax_tree/version"
|
15
|
-
|
16
7
|
require_relative "syntax_tree/basic_visitor"
|
17
8
|
require_relative "syntax_tree/visitor"
|
18
|
-
require_relative "syntax_tree/visitor/field_visitor"
|
19
|
-
require_relative "syntax_tree/visitor/json_visitor"
|
20
|
-
require_relative "syntax_tree/visitor/match_visitor"
|
21
|
-
require_relative "syntax_tree/visitor/mutation_visitor"
|
22
|
-
require_relative "syntax_tree/visitor/pretty_print_visitor"
|
23
|
-
require_relative "syntax_tree/visitor/environment"
|
24
|
-
require_relative "syntax_tree/visitor/with_environment"
|
25
9
|
|
10
|
+
require_relative "syntax_tree/formatter"
|
26
11
|
require_relative "syntax_tree/parser"
|
27
|
-
require_relative "syntax_tree/
|
28
|
-
require_relative "syntax_tree/search"
|
29
|
-
require_relative "syntax_tree/index"
|
30
|
-
|
31
|
-
require_relative "syntax_tree/yarv"
|
32
|
-
require_relative "syntax_tree/yarv/bf"
|
33
|
-
require_relative "syntax_tree/yarv/compiler"
|
34
|
-
require_relative "syntax_tree/yarv/decompiler"
|
35
|
-
require_relative "syntax_tree/yarv/disassembler"
|
36
|
-
require_relative "syntax_tree/yarv/instruction_sequence"
|
37
|
-
require_relative "syntax_tree/yarv/instructions"
|
38
|
-
require_relative "syntax_tree/yarv/legacy"
|
39
|
-
require_relative "syntax_tree/yarv/local_table"
|
40
|
-
require_relative "syntax_tree/yarv/assembler"
|
41
|
-
require_relative "syntax_tree/yarv/vm"
|
12
|
+
require_relative "syntax_tree/version"
|
42
13
|
|
43
14
|
# Syntax Tree is a suite of tools built on top of the internal CRuby parser. It
|
44
15
|
# provides the ability to generate a syntax tree from source, as well as the
|
45
16
|
# tools necessary to inspect and manipulate that syntax tree. It can be used to
|
46
17
|
# build formatters, linters, language servers, and more.
|
47
18
|
module SyntaxTree
|
19
|
+
# Syntax Tree the library has many features that aren't always used by the
|
20
|
+
# CLI. Requiring those features takes time, so we autoload as many constants
|
21
|
+
# as possible in order to keep the CLI as fast as possible.
|
22
|
+
|
23
|
+
autoload :DSL, "syntax_tree/dsl"
|
24
|
+
autoload :FieldVisitor, "syntax_tree/field_visitor"
|
25
|
+
autoload :Index, "syntax_tree/index"
|
26
|
+
autoload :JSONVisitor, "syntax_tree/json_visitor"
|
27
|
+
autoload :LanguageServer, "syntax_tree/language_server"
|
28
|
+
autoload :MatchVisitor, "syntax_tree/match_visitor"
|
29
|
+
autoload :Mermaid, "syntax_tree/mermaid"
|
30
|
+
autoload :MermaidVisitor, "syntax_tree/mermaid_visitor"
|
31
|
+
autoload :MutationVisitor, "syntax_tree/mutation_visitor"
|
32
|
+
autoload :Pattern, "syntax_tree/pattern"
|
33
|
+
autoload :PrettyPrintVisitor, "syntax_tree/pretty_print_visitor"
|
34
|
+
autoload :Search, "syntax_tree/search"
|
35
|
+
autoload :Translation, "syntax_tree/translation"
|
36
|
+
autoload :WithScope, "syntax_tree/with_scope"
|
37
|
+
autoload :YARV, "syntax_tree/yarv"
|
38
|
+
|
48
39
|
# This holds references to objects that respond to both #parse and #format
|
49
40
|
# so that we can use them in the CLI.
|
50
41
|
HANDLERS = {}
|
@@ -63,40 +54,80 @@ module SyntaxTree
|
|
63
54
|
# that Syntax Tree can format arbitrary parts of a document.
|
64
55
|
DEFAULT_INDENTATION = 0
|
65
56
|
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
57
|
+
# Parses the given source and returns the formatted source.
|
58
|
+
def self.format(
|
59
|
+
source,
|
60
|
+
maxwidth = DEFAULT_PRINT_WIDTH,
|
61
|
+
base_indentation = DEFAULT_INDENTATION,
|
62
|
+
options: Formatter::Options.new
|
63
|
+
)
|
64
|
+
format_node(
|
65
|
+
source,
|
66
|
+
parse(source),
|
67
|
+
maxwidth,
|
68
|
+
base_indentation,
|
69
|
+
options: options
|
70
|
+
)
|
70
71
|
end
|
71
72
|
|
72
|
-
# Parses the given
|
73
|
-
def self.
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
# Parses the given file and returns the formatted source.
|
74
|
+
def self.format_file(
|
75
|
+
filepath,
|
76
|
+
maxwidth = DEFAULT_PRINT_WIDTH,
|
77
|
+
base_indentation = DEFAULT_INDENTATION,
|
78
|
+
options: Formatter::Options.new
|
79
|
+
)
|
80
|
+
format(read(filepath), maxwidth, base_indentation, options: options)
|
77
81
|
end
|
78
82
|
|
79
|
-
#
|
80
|
-
def self.
|
83
|
+
# Accepts a node in the tree and returns the formatted source.
|
84
|
+
def self.format_node(
|
81
85
|
source,
|
86
|
+
node,
|
82
87
|
maxwidth = DEFAULT_PRINT_WIDTH,
|
83
88
|
base_indentation = DEFAULT_INDENTATION,
|
84
89
|
options: Formatter::Options.new
|
85
90
|
)
|
86
91
|
formatter = Formatter.new(source, [], maxwidth, options: options)
|
87
|
-
|
92
|
+
node.format(formatter)
|
88
93
|
|
89
94
|
formatter.flush(base_indentation)
|
90
95
|
formatter.output.join
|
91
96
|
end
|
92
97
|
|
98
|
+
# Indexes the given source code to return a list of all class, module, and
|
99
|
+
# method definitions. Used to quickly provide indexing capability for IDEs or
|
100
|
+
# documentation generation.
|
101
|
+
def self.index(source)
|
102
|
+
Index.index(source)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Indexes the given file to return a list of all class, module, and method
|
106
|
+
# definitions. Used to quickly provide indexing capability for IDEs or
|
107
|
+
# documentation generation.
|
108
|
+
def self.index_file(filepath)
|
109
|
+
Index.index_file(filepath)
|
110
|
+
end
|
111
|
+
|
93
112
|
# A convenience method for creating a new mutation visitor.
|
94
113
|
def self.mutation
|
95
|
-
visitor =
|
114
|
+
visitor = MutationVisitor.new
|
96
115
|
yield visitor
|
97
116
|
visitor
|
98
117
|
end
|
99
118
|
|
119
|
+
# Parses the given source and returns the syntax tree.
|
120
|
+
def self.parse(source)
|
121
|
+
parser = Parser.new(source)
|
122
|
+
response = parser.parse
|
123
|
+
response unless parser.error?
|
124
|
+
end
|
125
|
+
|
126
|
+
# Parses the given file and returns the syntax tree.
|
127
|
+
def self.parse_file(filepath)
|
128
|
+
parse(read(filepath))
|
129
|
+
end
|
130
|
+
|
100
131
|
# Returns the source from the given filepath taking into account any potential
|
101
132
|
# magic encoding comments.
|
102
133
|
def self.read(filepath)
|
@@ -112,23 +143,24 @@ module SyntaxTree
|
|
112
143
|
File.read(filepath, encoding: encoding)
|
113
144
|
end
|
114
145
|
|
146
|
+
# This is a hook provided so that plugins can register themselves as the
|
147
|
+
# handler for a particular file type.
|
148
|
+
def self.register_handler(extension, handler)
|
149
|
+
HANDLERS[extension] = handler
|
150
|
+
end
|
151
|
+
|
115
152
|
# Searches through the given source using the given pattern and yields each
|
116
153
|
# node in the tree that matches the pattern to the given block.
|
117
154
|
def self.search(source, query, &block)
|
118
|
-
|
119
|
-
|
155
|
+
pattern = Pattern.new(query).compile
|
156
|
+
program = parse(source)
|
120
157
|
|
121
|
-
|
122
|
-
# method definitions. Used to quickly provide indexing capability for IDEs or
|
123
|
-
# documentation generation.
|
124
|
-
def self.index(source)
|
125
|
-
Index.index(source)
|
158
|
+
Search.new(pattern).scan(program, &block)
|
126
159
|
end
|
127
160
|
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
131
|
-
|
132
|
-
Index.index_file(filepath)
|
161
|
+
# Searches through the given file using the given pattern and yields each
|
162
|
+
# node in the tree that matches the pattern to the given block.
|
163
|
+
def self.search_file(filepath, query, &block)
|
164
|
+
search(read(filepath), query, &block)
|
133
165
|
end
|
134
166
|
end
|
data/tasks/sorbet.rake
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SyntaxTree
|
4
|
+
class RBI
|
5
|
+
include DSL
|
6
|
+
|
7
|
+
attr_reader :body, :line
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@body = []
|
11
|
+
@line = 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
require "syntax_tree/reflection"
|
16
|
+
|
17
|
+
body << Comment("# typed: strict", false, location)
|
18
|
+
@line += 2
|
19
|
+
|
20
|
+
generate_parent
|
21
|
+
Reflection.nodes.sort.each { |(_, node)| generate_node(node) }
|
22
|
+
|
23
|
+
Formatter.format(nil, Program(Statements(body)))
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def generate_comments(comment)
|
29
|
+
comment
|
30
|
+
.lines(chomp: true)
|
31
|
+
.map { |line| Comment("# #{line}", false, location).tap { @line += 1 } }
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate_parent
|
35
|
+
attribute = Reflection.nodes[:Program].attributes[:location]
|
36
|
+
class_location = location
|
37
|
+
|
38
|
+
node_body = generate_comments(attribute.comment)
|
39
|
+
node_body << sig_block { sig_returns { sig_type_for(attribute.type) } }
|
40
|
+
@line += 1
|
41
|
+
|
42
|
+
node_body << Command(
|
43
|
+
Ident("attr_reader"),
|
44
|
+
Args([SymbolLiteral(Ident("location"))]),
|
45
|
+
nil,
|
46
|
+
location
|
47
|
+
)
|
48
|
+
@line += 1
|
49
|
+
|
50
|
+
body << ClassDeclaration(
|
51
|
+
ConstPathRef(VarRef(Const("SyntaxTree")), Const("Node")),
|
52
|
+
nil,
|
53
|
+
BodyStmt(Statements(node_body), nil, nil, nil, nil),
|
54
|
+
class_location
|
55
|
+
)
|
56
|
+
@line += 2
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_node(node)
|
60
|
+
body.concat(generate_comments(node.comment))
|
61
|
+
class_location = location
|
62
|
+
@line += 2
|
63
|
+
|
64
|
+
body << ClassDeclaration(
|
65
|
+
ConstPathRef(VarRef(Const("SyntaxTree")), Const(node.name.to_s)),
|
66
|
+
ConstPathRef(VarRef(Const("SyntaxTree")), Const("Node")),
|
67
|
+
BodyStmt(Statements(generate_node_body(node)), nil, nil, nil, nil),
|
68
|
+
class_location
|
69
|
+
)
|
70
|
+
|
71
|
+
@line += 2
|
72
|
+
end
|
73
|
+
|
74
|
+
def generate_node_body(node)
|
75
|
+
node_body = []
|
76
|
+
node.attributes.sort.each do |(name, attribute)|
|
77
|
+
next if name == :location
|
78
|
+
|
79
|
+
node_body.concat(generate_comments(attribute.comment))
|
80
|
+
node_body << sig_block { sig_returns { sig_type_for(attribute.type) } }
|
81
|
+
@line += 1
|
82
|
+
|
83
|
+
node_body << Command(
|
84
|
+
Ident("attr_reader"),
|
85
|
+
Args([SymbolLiteral(Ident(attribute.name.to_s))]),
|
86
|
+
nil,
|
87
|
+
location
|
88
|
+
)
|
89
|
+
@line += 2
|
90
|
+
end
|
91
|
+
|
92
|
+
node_body.concat(generate_initialize(node))
|
93
|
+
|
94
|
+
node_body << sig_block do
|
95
|
+
CallNode(
|
96
|
+
sig_params do
|
97
|
+
BareAssocHash(
|
98
|
+
[Assoc(Label("visitor:"), sig_type_for(BasicVisitor))]
|
99
|
+
)
|
100
|
+
end,
|
101
|
+
Period("."),
|
102
|
+
Ident("returns"),
|
103
|
+
ArgParen(
|
104
|
+
Args(
|
105
|
+
[CallNode(VarRef(Const("T")), Period("."), Ident("untyped"), nil)]
|
106
|
+
)
|
107
|
+
)
|
108
|
+
)
|
109
|
+
end
|
110
|
+
@line += 1
|
111
|
+
|
112
|
+
node_body << generate_def_node(
|
113
|
+
"accept",
|
114
|
+
Paren(
|
115
|
+
LParen("("),
|
116
|
+
Params.new(requireds: [Ident("visitor")], location: location)
|
117
|
+
)
|
118
|
+
)
|
119
|
+
@line += 2
|
120
|
+
|
121
|
+
node_body << generate_child_nodes
|
122
|
+
@line += 1
|
123
|
+
|
124
|
+
node_body << generate_def_node("child_nodes", nil)
|
125
|
+
@line += 1
|
126
|
+
|
127
|
+
node_body
|
128
|
+
end
|
129
|
+
|
130
|
+
def generate_initialize(node)
|
131
|
+
parameters =
|
132
|
+
SyntaxTree.const_get(node.name).instance_method(:initialize).parameters
|
133
|
+
|
134
|
+
assocs =
|
135
|
+
parameters.map do |(_, name)|
|
136
|
+
Assoc(Label("#{name}:"), sig_type_for(node.attributes[name].type))
|
137
|
+
end
|
138
|
+
|
139
|
+
node_body = []
|
140
|
+
node_body << sig_block do
|
141
|
+
CallNode(
|
142
|
+
sig_params { BareAssocHash(assocs) },
|
143
|
+
Period("."),
|
144
|
+
Ident("void"),
|
145
|
+
nil
|
146
|
+
)
|
147
|
+
end
|
148
|
+
@line += 1
|
149
|
+
|
150
|
+
params = Params.new(location: location)
|
151
|
+
parameters.each do |(type, name)|
|
152
|
+
case type
|
153
|
+
when :req
|
154
|
+
params.requireds << Ident(name.to_s)
|
155
|
+
when :keyreq
|
156
|
+
params.keywords << [Label("#{name}:"), nil]
|
157
|
+
when :key
|
158
|
+
params.keywords << [
|
159
|
+
Label("#{name}:"),
|
160
|
+
CallNode(
|
161
|
+
VarRef(Const("T")),
|
162
|
+
Period("."),
|
163
|
+
Ident("unsafe"),
|
164
|
+
ArgParen(Args([VarRef(Kw("nil"))]))
|
165
|
+
)
|
166
|
+
]
|
167
|
+
else
|
168
|
+
raise
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
node_body << generate_def_node("initialize", Paren(LParen("("), params))
|
173
|
+
@line += 2
|
174
|
+
|
175
|
+
node_body
|
176
|
+
end
|
177
|
+
|
178
|
+
def generate_child_nodes
|
179
|
+
type =
|
180
|
+
Reflection::Type::ArrayType.new(
|
181
|
+
Reflection::Type::UnionType.new([NilClass, Node])
|
182
|
+
)
|
183
|
+
|
184
|
+
sig_block { sig_returns { sig_type_for(type) } }
|
185
|
+
end
|
186
|
+
|
187
|
+
def generate_def_node(name, params)
|
188
|
+
DefNode(
|
189
|
+
nil,
|
190
|
+
nil,
|
191
|
+
Ident(name),
|
192
|
+
params,
|
193
|
+
BodyStmt(Statements([VoidStmt()]), nil, nil, nil, nil),
|
194
|
+
location
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
def sig_block
|
199
|
+
MethodAddBlock(
|
200
|
+
CallNode(nil, nil, Ident("sig"), nil),
|
201
|
+
BlockNode(
|
202
|
+
LBrace("{"),
|
203
|
+
nil,
|
204
|
+
BodyStmt(Statements([yield]), nil, nil, nil, nil)
|
205
|
+
),
|
206
|
+
location
|
207
|
+
)
|
208
|
+
end
|
209
|
+
|
210
|
+
def sig_params
|
211
|
+
CallNode(nil, nil, Ident("params"), ArgParen(Args([yield])))
|
212
|
+
end
|
213
|
+
|
214
|
+
def sig_returns
|
215
|
+
CallNode(nil, nil, Ident("returns"), ArgParen(Args([yield])))
|
216
|
+
end
|
217
|
+
|
218
|
+
def sig_type_for(type)
|
219
|
+
case type
|
220
|
+
when Reflection::Type::ArrayType
|
221
|
+
ARef(
|
222
|
+
ConstPathRef(VarRef(Const("T")), Const("Array")),
|
223
|
+
sig_type_for(type.type)
|
224
|
+
)
|
225
|
+
when Reflection::Type::TupleType
|
226
|
+
ArrayLiteral(LBracket("["), Args(type.types.map { sig_type_for(_1) }))
|
227
|
+
when Reflection::Type::UnionType
|
228
|
+
if type.types.include?(NilClass)
|
229
|
+
selected = type.types.reject { _1 == NilClass }
|
230
|
+
subtype =
|
231
|
+
if selected.size == 1
|
232
|
+
selected.first
|
233
|
+
else
|
234
|
+
Reflection::Type::UnionType.new(selected)
|
235
|
+
end
|
236
|
+
|
237
|
+
CallNode(
|
238
|
+
VarRef(Const("T")),
|
239
|
+
Period("."),
|
240
|
+
Ident("nilable"),
|
241
|
+
ArgParen(Args([sig_type_for(subtype)]))
|
242
|
+
)
|
243
|
+
else
|
244
|
+
CallNode(
|
245
|
+
VarRef(Const("T")),
|
246
|
+
Period("."),
|
247
|
+
Ident("any"),
|
248
|
+
ArgParen(Args(type.types.map { sig_type_for(_1) }))
|
249
|
+
)
|
250
|
+
end
|
251
|
+
when Symbol
|
252
|
+
ConstRef(Const("Symbol"))
|
253
|
+
else
|
254
|
+
*parents, constant = type.name.split("::").map { Const(_1) }
|
255
|
+
|
256
|
+
if parents.empty?
|
257
|
+
ConstRef(constant)
|
258
|
+
else
|
259
|
+
[*parents[1..], constant].inject(
|
260
|
+
VarRef(parents.first)
|
261
|
+
) { |accum, const| ConstPathRef(accum, const) }
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def location
|
267
|
+
Location.fixed(line: line, char: 0, column: 0)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
namespace :sorbet do
|
273
|
+
desc "Generate RBI files for Sorbet"
|
274
|
+
task :rbi do
|
275
|
+
puts SyntaxTree::RBI.new.generate
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file's purpose is to extract the examples from the whitequark/parser
|
4
|
+
# gem and generate a test file that we can use to ensure that our parser
|
5
|
+
# generates equivalent syntax trees when translating. To do this, it runs the
|
6
|
+
# parser's test suite but overrides the `assert_parses` method to collect the
|
7
|
+
# examples into a hash. Then, it writes out the hash to a file that we can use
|
8
|
+
# to generate our own tests.
|
9
|
+
#
|
10
|
+
# To run the test suite, it's important to note that we have to mirror both any
|
11
|
+
# APIs provided to the test suite (for example the ParseHelper module below).
|
12
|
+
# This is obviously relatively brittle, but it's effective for now.
|
13
|
+
|
14
|
+
require "ast"
|
15
|
+
|
16
|
+
module ParseHelper
|
17
|
+
# This object is going to collect all of the examples from the parser gem into
|
18
|
+
# a hash that we can use to generate our own tests.
|
19
|
+
COLLECTED = Hash.new { |hash, key| hash[key] = [] }
|
20
|
+
|
21
|
+
include AST::Sexp
|
22
|
+
ALL_VERSIONS = %w[3.1 3.2]
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def assert_context(*)
|
27
|
+
end
|
28
|
+
|
29
|
+
def assert_diagnoses(*)
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_diagnoses_many(*)
|
33
|
+
end
|
34
|
+
|
35
|
+
def refute_diagnoses(*)
|
36
|
+
end
|
37
|
+
|
38
|
+
def with_versions(*)
|
39
|
+
end
|
40
|
+
|
41
|
+
def assert_parses(_ast, code, _source_maps = "", versions = ALL_VERSIONS)
|
42
|
+
# We're going to skip any examples that are for older Ruby versions
|
43
|
+
# that we do not support.
|
44
|
+
return if (versions & %w[3.1 3.2]).empty?
|
45
|
+
|
46
|
+
entry = caller.find { _1.include?("test_parser.rb") }
|
47
|
+
_, lineno, name = *entry.match(/(\d+):in `(.+)'/)
|
48
|
+
|
49
|
+
COLLECTED["#{name}:#{lineno}"] << code
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
namespace :extract do
|
54
|
+
desc "Extract the whitequark/parser tests"
|
55
|
+
task :whitequark do
|
56
|
+
directory = File.expand_path("../tmp/parser", __dir__)
|
57
|
+
unless File.directory?(directory)
|
58
|
+
sh "git clone --depth 1 https://github.com/whitequark/parser #{directory}"
|
59
|
+
end
|
60
|
+
|
61
|
+
mkdir_p "#{directory}/extract"
|
62
|
+
touch "#{directory}/extract/helper.rb"
|
63
|
+
touch "#{directory}/extract/parse_helper.rb"
|
64
|
+
touch "#{directory}/extract/extracted.txt"
|
65
|
+
$:.unshift "#{directory}/extract"
|
66
|
+
|
67
|
+
require "parser/current"
|
68
|
+
require "minitest/autorun"
|
69
|
+
require_relative "#{directory}/test/test_parser"
|
70
|
+
|
71
|
+
Minitest.after_run do
|
72
|
+
filepath = File.expand_path("../test/translation/parser.txt", __dir__)
|
73
|
+
|
74
|
+
File.open(filepath, "w") do |file|
|
75
|
+
ParseHelper::COLLECTED.sort.each do |(key, codes)|
|
76
|
+
if codes.length == 1
|
77
|
+
file.puts("!!! #{key}\n#{codes.first}")
|
78
|
+
else
|
79
|
+
codes.each_with_index do |code, index|
|
80
|
+
file.puts("!!! #{key}:#{index}\n#{code}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
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:
|
4
|
+
version: 6.0.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: 2023-
|
11
|
+
date: 2023-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prettier_print
|
@@ -109,7 +109,6 @@ files:
|
|
109
109
|
- ".github/workflows/gh-pages.yml"
|
110
110
|
- ".github/workflows/main.yml"
|
111
111
|
- ".gitignore"
|
112
|
-
- ".gitmodules"
|
113
112
|
- ".rubocop.yml"
|
114
113
|
- CHANGELOG.md
|
115
114
|
- CODE_OF_CONDUCT.md
|
@@ -121,7 +120,9 @@ files:
|
|
121
120
|
- bin/bench
|
122
121
|
- bin/console
|
123
122
|
- bin/profile
|
123
|
+
- bin/whitequark
|
124
124
|
- config/rubocop.yml
|
125
|
+
- doc/changing_structure.md
|
125
126
|
- doc/logo.svg
|
126
127
|
- exe/stree
|
127
128
|
- exe/yarv
|
@@ -129,42 +130,53 @@ files:
|
|
129
130
|
- lib/syntax_tree/basic_visitor.rb
|
130
131
|
- lib/syntax_tree/cli.rb
|
131
132
|
- lib/syntax_tree/dsl.rb
|
133
|
+
- lib/syntax_tree/field_visitor.rb
|
132
134
|
- lib/syntax_tree/formatter.rb
|
133
135
|
- lib/syntax_tree/index.rb
|
136
|
+
- lib/syntax_tree/json_visitor.rb
|
134
137
|
- lib/syntax_tree/language_server.rb
|
135
|
-
- lib/syntax_tree/
|
138
|
+
- lib/syntax_tree/match_visitor.rb
|
139
|
+
- lib/syntax_tree/mermaid.rb
|
140
|
+
- lib/syntax_tree/mermaid_visitor.rb
|
141
|
+
- lib/syntax_tree/mutation_visitor.rb
|
136
142
|
- lib/syntax_tree/node.rb
|
137
143
|
- lib/syntax_tree/parser.rb
|
138
144
|
- lib/syntax_tree/pattern.rb
|
139
145
|
- lib/syntax_tree/plugin/disable_ternary.rb
|
140
146
|
- lib/syntax_tree/plugin/single_quotes.rb
|
141
147
|
- lib/syntax_tree/plugin/trailing_comma.rb
|
148
|
+
- lib/syntax_tree/pretty_print_visitor.rb
|
142
149
|
- lib/syntax_tree/rake/check_task.rb
|
143
150
|
- lib/syntax_tree/rake/task.rb
|
144
151
|
- lib/syntax_tree/rake/write_task.rb
|
145
152
|
- lib/syntax_tree/rake_tasks.rb
|
153
|
+
- lib/syntax_tree/reflection.rb
|
146
154
|
- lib/syntax_tree/search.rb
|
155
|
+
- lib/syntax_tree/translation.rb
|
156
|
+
- lib/syntax_tree/translation/parser.rb
|
157
|
+
- lib/syntax_tree/translation/rubocop_ast.rb
|
147
158
|
- lib/syntax_tree/version.rb
|
148
159
|
- lib/syntax_tree/visitor.rb
|
149
|
-
- lib/syntax_tree/
|
150
|
-
- lib/syntax_tree/visitor/field_visitor.rb
|
151
|
-
- lib/syntax_tree/visitor/json_visitor.rb
|
152
|
-
- lib/syntax_tree/visitor/match_visitor.rb
|
153
|
-
- lib/syntax_tree/visitor/mutation_visitor.rb
|
154
|
-
- lib/syntax_tree/visitor/pretty_print_visitor.rb
|
155
|
-
- lib/syntax_tree/visitor/with_environment.rb
|
160
|
+
- lib/syntax_tree/with_scope.rb
|
156
161
|
- lib/syntax_tree/yarv.rb
|
157
162
|
- lib/syntax_tree/yarv/assembler.rb
|
163
|
+
- lib/syntax_tree/yarv/basic_block.rb
|
158
164
|
- lib/syntax_tree/yarv/bf.rb
|
165
|
+
- lib/syntax_tree/yarv/calldata.rb
|
159
166
|
- lib/syntax_tree/yarv/compiler.rb
|
167
|
+
- lib/syntax_tree/yarv/control_flow_graph.rb
|
168
|
+
- lib/syntax_tree/yarv/data_flow_graph.rb
|
160
169
|
- lib/syntax_tree/yarv/decompiler.rb
|
161
170
|
- lib/syntax_tree/yarv/disassembler.rb
|
162
171
|
- lib/syntax_tree/yarv/instruction_sequence.rb
|
163
172
|
- lib/syntax_tree/yarv/instructions.rb
|
164
173
|
- lib/syntax_tree/yarv/legacy.rb
|
165
174
|
- lib/syntax_tree/yarv/local_table.rb
|
175
|
+
- lib/syntax_tree/yarv/sea_of_nodes.rb
|
166
176
|
- lib/syntax_tree/yarv/vm.rb
|
167
177
|
- syntax_tree.gemspec
|
178
|
+
- tasks/sorbet.rake
|
179
|
+
- tasks/whitequark.rake
|
168
180
|
homepage: https://github.com/kddnewton/syntax_tree
|
169
181
|
licenses:
|
170
182
|
- MIT
|
data/.gitmodules
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
[submodule "mspec"]
|
2
|
-
path = spec/mspec
|
3
|
-
url = git@github.com:ruby/mspec.git
|
4
|
-
[submodule "spec"]
|
5
|
-
path = spec/ruby
|
6
|
-
url = git@github.com:ruby/spec.git
|
7
|
-
[submodule "test/ruby-syntax-fixtures"]
|
8
|
-
path = test/ruby-syntax-fixtures
|
9
|
-
url = https://github.com/ruby-syntax-tree/ruby-syntax-fixtures
|