swift-ast-dump-parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc8754e58b54b5563e95e3f2abaa81782823aa1f
4
+ data.tar.gz: fb0ea24daf5b73f6b32be241bd33ea62e391d5be
5
+ SHA512:
6
+ metadata.gz: 3def18d0b3d524c6879bf0d29c6d3e58ce4811b3069abe1c0054b0ac3b5691d951e0e314c6afe70106458c6ceb4f98b862f8dad863536d31ed4796737f722cd8
7
+ data.tar.gz: 91b56fbe416abaf10ad8029b57c45ed7530975766cb6bc96c7b1e662843019cea4ddb3faa144fa450d5d127ab4e5070e477982db5c632ec0eadc7b32172c96cf
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require 'swift_ast_dump_parser'
5
+
6
+ ast_path = ARGV[0]
7
+ @tree = SwiftAST::Parser.new().parse_build_log_output(File.read(ast_path))
8
+ @tree.dump
@@ -0,0 +1,225 @@
1
+ module SwiftAST
2
+ autoload :StringScanner, 'strscan'
3
+ class Parser
4
+ def parse(string)
5
+ @scanner = StringScanner.new(string)
6
+ node = scan_children.first
7
+ node
8
+ end
9
+
10
+
11
+ def parse_build_log_output(string)
12
+ @scanner = StringScanner.new(string)
13
+ return unless @scanner.scan_until(/^\(source_file/)
14
+ unscan("(source_file")
15
+ children = scan_children
16
+
17
+ return if children.empty?
18
+ Node.new("ast", [], children)
19
+ end
20
+
21
+
22
+ def scan_parameters
23
+ parameters = []
24
+
25
+ while true
26
+ @scanner.skip(/\s*/)
27
+ parameter = scan_parameter?
28
+ break unless parameter
29
+ parameters << parameter
30
+ end
31
+
32
+ parameters
33
+ end
34
+
35
+ def scan_parameters_from_types
36
+ first_param = @scanner.scan(/\d+:/)
37
+ return [] unless first_param
38
+ return [first_param] + scan_parameters
39
+ end
40
+
41
+ def scan_children(level = 0)
42
+ children = []
43
+ while true
44
+ return children unless whitespaces = whitespaces_at(level)
45
+ node_name = scan_name?
46
+ return children if node_name == "source_file" && level != 0 && unscan(node_name + whitespaces)
47
+ node_parameters = scan_parameters
48
+
49
+ node_children = scan_children(level + 1)
50
+
51
+ while next_params = scan_parameters_from_types # these are stupid params alike
52
+ break if next_params.empty?
53
+ node_parameters += next_params
54
+ node_children += scan_children(level + 1)
55
+ end
56
+ node = Node.new(node_name, node_parameters, node_children)
57
+
58
+ children << node
59
+ @scanner.scan(/(\s|\\|\n|\r|\t)*\)[\w\s]*/)
60
+ end
61
+ children
62
+ end
63
+
64
+ def whitespaces_at(level = 0)
65
+ whitespaces = @scanner.scan(/(\s|\\|\n|\r|\t)*\(/)
66
+ if level == 0 && whitespaces.nil?
67
+ whitespaces = @scanner.scan(/.*?\(source_file/m)
68
+ return nil unless whitespaces
69
+ unscan("source_file")
70
+ end
71
+ whitespaces
72
+ end
73
+
74
+ def unscan(string)
75
+ @scanner.pos = @scanner.pos - string.length
76
+ end
77
+
78
+ def scan_name?
79
+ el_name = @scanner.scan(/#?[\w:]+/)
80
+ el_name
81
+ end
82
+
83
+ def scan_parameter?(is_parsing_rvalue = false)
84
+ #white spaces are skipped
85
+
86
+ # scan everything until space or opening sequence like ( < ' ".
87
+ # Since we can end up with closing bracket - we alos check for )
88
+
89
+ prefix = @scanner.scan(/[^\s()'"\[\\]+/) if is_parsing_rvalue
90
+ prefix = @scanner.scan(/[^\s()<'"\[\\=]+/) unless is_parsing_rvalue
91
+
92
+ next_char = @scanner.peek(1)
93
+ return nil unless next_char
94
+ should_unwrap_strings = !is_parsing_rvalue && !prefix
95
+
96
+ case next_char
97
+ when " " # next parameter
98
+ result = prefix
99
+ when "\\" # next parameter
100
+ @scanner.scan(/./)
101
+ result = prefix
102
+
103
+ when "\n" # next parameter
104
+ result = prefix
105
+ when ")" # closing bracket == end of element
106
+ result = prefix
107
+ when "\"" # doube quoted string
108
+ result = @scanner.scan(/./) + @scanner.scan_until(/"/)
109
+ result = result[1..-2] if should_unwrap_strings
110
+ result = (prefix || "") + result
111
+ when "'" # single quoted string
112
+ result = @scanner.scan(/./) + @scanner.scan_until(/'/)
113
+ result = result[1..-2] if should_unwrap_strings
114
+ result = (prefix || "") + result + (scan_parameter?(is_parsing_rvalue) || "")
115
+ when "<" # kinda generic
116
+ result = (prefix || "") + @scanner.scan(/./)
117
+ #in some cases this can be last char, just because we can end up with a=sdsd.function.<
118
+ result += @scanner.scan_until(/>/) + (scan_parameter?(is_parsing_rvalue) || "")
119
+ when "("
120
+ #rare case for enums in type (EnumType).enumValue
121
+ if !prefix && @scanner.check(/\([\w\s\(\)<>,:\]\[\.?]+\)\.\w+/)
122
+ return @scanner.scan(/\([\w\s\(\)<>,:\]\[\.?]+\)\.\w+/)
123
+ end
124
+
125
+ return nil if !prefix && !is_parsing_rvalue
126
+ result = (prefix || "") + @scanner.scan_until(/\)/) + (scan_parameter?(is_parsing_rvalue) || "")
127
+ when "["
128
+ result = (prefix || "") + scan_range + (scan_parameter?(is_parsing_rvalue) || "")
129
+ #rare case for tuple_shuffle_expr [with ([ProductDict], UserDict)]0: ([ProductDict], UserDict)
130
+ if result.start_with?("[with") && result.end_with?("]0:")
131
+ result = result + @scanner.scan_until(/\n/).chomp("\n")
132
+
133
+ end
134
+ when "="
135
+ result = prefix + @scanner.scan(/./) + (scan_parameter?(true) || "")
136
+
137
+ end
138
+
139
+ result
140
+
141
+ end
142
+
143
+ def scan_range
144
+ return unless @scanner.peek(1) == "["
145
+ result = @scanner.scan(/./)
146
+
147
+ while true
148
+ inside = @scanner.scan(/[^\]\[]+/) #everything but [ or ]
149
+ result += inside || ""
150
+ next_char = @scanner.peek(1)
151
+
152
+ return result + @scanner.scan(/./) if next_char == "]" # we found the end
153
+ result += scan_range if next_char == "["
154
+ raise "Unexpected character #{next_char} - [ or ] expected" if next_char != "[" && next_char != "]"
155
+ end
156
+
157
+ end
158
+
159
+ def scan_line_and_column
160
+ @scanner.scan(/:\d+:\d+/)
161
+ end
162
+
163
+ def isalpha(str)
164
+ !str.match(/[^A-Za-z@_]/)
165
+ end
166
+ def isAlphaDigit(str)
167
+ !str.match(/[^A-Za-z@_0-9]/)
168
+ end
169
+ def isalphaOrDot(str)
170
+ !str.match(/[^A-Za-z@_.,]/)
171
+ end
172
+
173
+
174
+ end
175
+
176
+ class Node
177
+
178
+ def initialize(name, parameters = [], children = [])
179
+ @name = name
180
+ @parameters = parameters
181
+ @children = children
182
+ end
183
+
184
+ def name
185
+ @name
186
+ end
187
+
188
+ def parameters
189
+ @parameters
190
+ end
191
+
192
+ def children
193
+ @children
194
+ end
195
+
196
+ def dump(level = 0)
197
+ @@line = 0 if level == 0
198
+ puts "\n" if level == 0
199
+ puts " " * level + "[#{@@line}][#{@name} #{@parameters}"
200
+ @@line = @@line + 1
201
+ @children.each { |child| child.dump(level + 1) }
202
+ end
203
+
204
+ def find_nodes(type)
205
+ found_nodes = []
206
+ @children.each { |child|
207
+ if child.name == type
208
+ found_nodes << child
209
+ else
210
+ found_nodes += child.find_nodes(type)
211
+ end
212
+ }
213
+ found_nodes
214
+ end
215
+
216
+ def on_node(type, &block)
217
+ @children.each { |child|
218
+ yield child if child.name == type
219
+ child.on_node(type, &block)
220
+ }
221
+ end
222
+
223
+ end
224
+
225
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: swift-ast-dump-parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paul Taykalo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |2
14
+ Tool that allows to build AST tree representation from the swift's AST dump
15
+ swift-ast-dump-parser <ast-file>
16
+ email: tt.kilew@gmail.com
17
+ executables:
18
+ - swift-ast-dump-parser
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - bin/swift-ast-dump-parser
23
+ - lib/swift_ast_dump_parser.rb
24
+ homepage: https://github.com/PaulTaykalo/swift-ast-dump-parser.git
25
+ licenses:
26
+ - MIT
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 2.6.10
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Swift AST dump parser
48
+ test_files: []