syntax_tree 5.3.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|