herb 0.1.0-x86_64-linux-gnu
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 +7 -0
- data/License.txt +21 -0
- data/Makefile +121 -0
- data/README.md +166 -0
- data/Rakefile +184 -0
- data/exe/herb +5 -0
- data/ext/herb/error_helpers.c +302 -0
- data/ext/herb/error_helpers.h +15 -0
- data/ext/herb/extconf.rb +75 -0
- data/ext/herb/extension.c +110 -0
- data/ext/herb/extension.h +6 -0
- data/ext/herb/extension_helpers.c +117 -0
- data/ext/herb/extension_helpers.h +24 -0
- data/ext/herb/nodes.c +936 -0
- data/ext/herb/nodes.h +12 -0
- data/herb.gemspec +49 -0
- data/lib/herb/3.0/herb.so +0 -0
- data/lib/herb/3.1/herb.so +0 -0
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/ast/node.rb +61 -0
- data/lib/herb/ast/nodes.rb +1542 -0
- data/lib/herb/ast.rb +6 -0
- data/lib/herb/cli.rb +164 -0
- data/lib/herb/errors.rb +352 -0
- data/lib/herb/lex_result.rb +20 -0
- data/lib/herb/libherb/array.rb +48 -0
- data/lib/herb/libherb/ast_node.rb +47 -0
- data/lib/herb/libherb/buffer.rb +53 -0
- data/lib/herb/libherb/extract_result.rb +17 -0
- data/lib/herb/libherb/lex_result.rb +29 -0
- data/lib/herb/libherb/libherb.rb +49 -0
- data/lib/herb/libherb/parse_result.rb +17 -0
- data/lib/herb/libherb/token.rb +43 -0
- data/lib/herb/libherb.rb +32 -0
- data/lib/herb/location.rb +42 -0
- data/lib/herb/parse_result.rb +26 -0
- data/lib/herb/position.rb +36 -0
- data/lib/herb/project.rb +361 -0
- data/lib/herb/range.rb +40 -0
- data/lib/herb/result.rb +21 -0
- data/lib/herb/token.rb +43 -0
- data/lib/herb/token_list.rb +11 -0
- data/lib/herb/version.rb +5 -0
- data/lib/herb.rb +32 -0
- data/src/analyze.c +989 -0
- data/src/analyze_helpers.c +241 -0
- data/src/analyzed_ruby.c +35 -0
- data/src/array.c +137 -0
- data/src/ast_node.c +81 -0
- data/src/ast_nodes.c +866 -0
- data/src/ast_pretty_print.c +588 -0
- data/src/buffer.c +199 -0
- data/src/errors.c +740 -0
- data/src/extract.c +110 -0
- data/src/herb.c +103 -0
- data/src/html_util.c +143 -0
- data/src/include/analyze.h +36 -0
- data/src/include/analyze_helpers.h +43 -0
- data/src/include/analyzed_ruby.h +33 -0
- data/src/include/array.h +33 -0
- data/src/include/ast_node.h +35 -0
- data/src/include/ast_nodes.h +303 -0
- data/src/include/ast_pretty_print.h +17 -0
- data/src/include/buffer.h +36 -0
- data/src/include/errors.h +125 -0
- data/src/include/extract.h +20 -0
- data/src/include/herb.h +32 -0
- data/src/include/html_util.h +13 -0
- data/src/include/io.h +9 -0
- data/src/include/json.h +28 -0
- data/src/include/lexer.h +13 -0
- data/src/include/lexer_peek_helpers.h +23 -0
- data/src/include/lexer_struct.h +32 -0
- data/src/include/location.h +25 -0
- data/src/include/macros.h +10 -0
- data/src/include/memory.h +12 -0
- data/src/include/parser.h +22 -0
- data/src/include/parser_helpers.h +33 -0
- data/src/include/position.h +22 -0
- data/src/include/pretty_print.h +53 -0
- data/src/include/prism_helpers.h +18 -0
- data/src/include/range.h +23 -0
- data/src/include/ruby_parser.h +6 -0
- data/src/include/token.h +25 -0
- data/src/include/token_matchers.h +21 -0
- data/src/include/token_struct.h +51 -0
- data/src/include/util.h +25 -0
- data/src/include/version.h +6 -0
- data/src/include/visitor.h +11 -0
- data/src/io.c +30 -0
- data/src/json.c +205 -0
- data/src/lexer.c +284 -0
- data/src/lexer_peek_helpers.c +59 -0
- data/src/location.c +41 -0
- data/src/main.c +162 -0
- data/src/memory.c +53 -0
- data/src/parser.c +704 -0
- data/src/parser_helpers.c +161 -0
- data/src/position.c +33 -0
- data/src/pretty_print.c +242 -0
- data/src/prism_helpers.c +50 -0
- data/src/range.c +38 -0
- data/src/ruby_parser.c +47 -0
- data/src/token.c +194 -0
- data/src/token_matchers.c +32 -0
- data/src/util.c +128 -0
- data/src/visitor.c +321 -0
- metadata +159 -0
data/lib/herb/ast.rb
ADDED
data/lib/herb/cli.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "lz_string"
|
5
|
+
|
6
|
+
class Herb::CLI
|
7
|
+
attr_accessor :json, :silent
|
8
|
+
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
@command = args[0]
|
12
|
+
@file = args[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
options
|
17
|
+
|
18
|
+
if silent
|
19
|
+
if result.failed?
|
20
|
+
puts "Failed"
|
21
|
+
else
|
22
|
+
puts "Success"
|
23
|
+
end
|
24
|
+
elsif json
|
25
|
+
puts result.value.to_json
|
26
|
+
else
|
27
|
+
puts result.value.inspect
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def directory
|
32
|
+
unless @file
|
33
|
+
puts "No directory provided."
|
34
|
+
puts
|
35
|
+
puts "Usage:"
|
36
|
+
puts " bundle exec herb #{@command} [directory] [options]"
|
37
|
+
puts
|
38
|
+
puts "Tip: Use `.` for the current directory"
|
39
|
+
puts " bundle exec herb #{@command} . [options]"
|
40
|
+
|
41
|
+
exit(1)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless File.exist?(@file)
|
45
|
+
puts "Not a directory: '#{@file}'."
|
46
|
+
puts
|
47
|
+
end
|
48
|
+
|
49
|
+
unless File.directory?(@file)
|
50
|
+
puts "Not a directory: '#{@file}'."
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
|
54
|
+
@file
|
55
|
+
end
|
56
|
+
|
57
|
+
def file_content
|
58
|
+
if @file && File.exist?(@file)
|
59
|
+
File.read(@file)
|
60
|
+
elsif @file
|
61
|
+
puts "File doesn't exist: #{@file}"
|
62
|
+
exit(1)
|
63
|
+
else
|
64
|
+
puts "No file provided."
|
65
|
+
puts
|
66
|
+
puts "Usage:"
|
67
|
+
puts " bundle exec herb #{@command} [file] [options]"
|
68
|
+
exit(1)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def help(exit_code = 0)
|
73
|
+
message = <<~HELP
|
74
|
+
▗▖ ▗▖▗▄▄▄▖▗▄▄▖ ▗▄▄▖
|
75
|
+
▐▌ ▐▌▐▌ ▐▌ ▐▌▐▌ ▐▌
|
76
|
+
▐▛▀▜▌▐▛▀▀▘▐▛▀▚▖▐▛▀▚▖
|
77
|
+
▐▌ ▐▌▐▙▄▄▖▐▌ ▐▌▐▙▄▞▘
|
78
|
+
|
79
|
+
Herb 🌿 Powerful and seamless HTML-aware ERB parsing.
|
80
|
+
|
81
|
+
Usage:
|
82
|
+
bundle exec herb [command] [options]
|
83
|
+
|
84
|
+
Commands:
|
85
|
+
bundle exec herb lex [file] Lex a file.
|
86
|
+
bundle exec herb parse [file] Parse a file.
|
87
|
+
bundle exec herb analyze [path] Analyze a project by passing a directory to the root of the project
|
88
|
+
bundle exec herb ruby [file] Extract Ruby from a file.
|
89
|
+
bundle exec herb html [file] Extract HTML from a file.
|
90
|
+
bundle exec herb prism [file] Extract Ruby from a file and parse the Ruby source with Prism.
|
91
|
+
bundle exec herb playground [file] Open the content of the source file in the playground
|
92
|
+
bundle exec herb version Prints the versions of the Herb gem and the libherb library.
|
93
|
+
|
94
|
+
Options:
|
95
|
+
#{option_parser.to_s.strip.gsub(/^ /, " ")}
|
96
|
+
|
97
|
+
HELP
|
98
|
+
|
99
|
+
puts message
|
100
|
+
|
101
|
+
exit(exit_code)
|
102
|
+
end
|
103
|
+
|
104
|
+
def result
|
105
|
+
@result ||= case @command
|
106
|
+
when "analyze"
|
107
|
+
Herb::Project.new(directory).parse!
|
108
|
+
exit(0)
|
109
|
+
when "parse"
|
110
|
+
Herb.parse(file_content)
|
111
|
+
when "lex"
|
112
|
+
Herb.lex(file_content)
|
113
|
+
when "ruby"
|
114
|
+
puts Herb.extract_ruby(file_content)
|
115
|
+
exit(0)
|
116
|
+
when "html"
|
117
|
+
puts Herb.extract_html(file_content)
|
118
|
+
exit(0)
|
119
|
+
when "playground"
|
120
|
+
if Dir.pwd.include?("/herb")
|
121
|
+
system(%(npx concurrently "nx dev playground" "sleep 1 && open http://localhost:5173##{LZString::UriSafe.compress(file_content)}"))
|
122
|
+
exit(0)
|
123
|
+
else
|
124
|
+
puts "This command can currently only be run within the herb repo itself"
|
125
|
+
exit(1)
|
126
|
+
end
|
127
|
+
when "help", "-h", "--help"
|
128
|
+
help
|
129
|
+
when "version", "-v", "--version"
|
130
|
+
puts Herb.version
|
131
|
+
exit(0)
|
132
|
+
when String
|
133
|
+
puts "Unknown command: '#{@command}'"
|
134
|
+
puts
|
135
|
+
|
136
|
+
help(1)
|
137
|
+
else
|
138
|
+
help(1)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def option_parser
|
143
|
+
@option_parser ||= OptionParser.new do |parser|
|
144
|
+
parser.banner = ""
|
145
|
+
|
146
|
+
parser.on_tail("-h", "--help", "Show this message") do
|
147
|
+
help
|
148
|
+
exit(0)
|
149
|
+
end
|
150
|
+
|
151
|
+
parser.on("-j", "--json", "Return result in the JSON format") do
|
152
|
+
self.json = true
|
153
|
+
end
|
154
|
+
|
155
|
+
parser.on("-s", "--silent", "Log no result to stdout") do
|
156
|
+
self.silent = true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def options
|
162
|
+
option_parser.parse!(@args)
|
163
|
+
end
|
164
|
+
end
|
data/lib/herb/errors.rb
ADDED
@@ -0,0 +1,352 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# NOTE: This file is generated by the templates/template.rb script and should not be
|
4
|
+
# modified manually. See /Users/marcoroth/Development/herb-release/templates/lib/herb/errors.rb.erb
|
5
|
+
|
6
|
+
module Herb
|
7
|
+
module Errors
|
8
|
+
class Error
|
9
|
+
attr_reader :type
|
10
|
+
attr_reader :location
|
11
|
+
attr_reader :message
|
12
|
+
|
13
|
+
def initialize(type, location, message)
|
14
|
+
@type = type
|
15
|
+
@location = location
|
16
|
+
@message = message
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
{
|
21
|
+
type: type,
|
22
|
+
location: location&.to_hash,
|
23
|
+
message: message,
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def error_name
|
28
|
+
self.class.name.split("::").last
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_json(*args)
|
32
|
+
to_hash.to_json(*args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class UnexpectedError < Error
|
37
|
+
attr_reader :description
|
38
|
+
attr_reader :expected
|
39
|
+
attr_reader :found
|
40
|
+
|
41
|
+
def initialize(type, location, message, description, expected, found)
|
42
|
+
super(type, location, message)
|
43
|
+
|
44
|
+
@description = description
|
45
|
+
@expected = expected
|
46
|
+
@found = found
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_hash
|
54
|
+
super.merge({
|
55
|
+
description: description,
|
56
|
+
expected: expected,
|
57
|
+
found: found,
|
58
|
+
})
|
59
|
+
end
|
60
|
+
|
61
|
+
def tree_inspect(indent = 0)
|
62
|
+
output = +""
|
63
|
+
|
64
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
65
|
+
output += %(├── message: #{message.inspect}\n)
|
66
|
+
output += %(├── description: #{description.inspect}\n)
|
67
|
+
output += %(├── expected: #{expected.inspect}\n)
|
68
|
+
output += %(└── found: #{found.inspect}\n)
|
69
|
+
output += %(\n)
|
70
|
+
|
71
|
+
output.gsub(/^/, " " * indent)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class UnexpectedTokenError < Error
|
76
|
+
attr_reader :expected_type
|
77
|
+
attr_reader :found
|
78
|
+
|
79
|
+
def initialize(type, location, message, expected_type, found)
|
80
|
+
super(type, location, message)
|
81
|
+
|
82
|
+
@expected_type = expected_type
|
83
|
+
@found = found
|
84
|
+
end
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_hash
|
91
|
+
super.merge({
|
92
|
+
expected_type: expected_type,
|
93
|
+
found: found,
|
94
|
+
})
|
95
|
+
end
|
96
|
+
|
97
|
+
def tree_inspect(indent = 0)
|
98
|
+
output = +""
|
99
|
+
|
100
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
101
|
+
output += %(├── message: #{message.inspect}\n)
|
102
|
+
output += %(├── expected_type: #{expected_type.inspect}\n)
|
103
|
+
output += %(└── found: #{found ? found.tree_inspect : "∅"}\n)
|
104
|
+
output += %(\n)
|
105
|
+
|
106
|
+
output.gsub(/^/, " " * indent)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class MissingOpeningTagError < Error
|
111
|
+
attr_reader :closing_tag
|
112
|
+
|
113
|
+
def initialize(type, location, message, closing_tag)
|
114
|
+
super(type, location, message)
|
115
|
+
|
116
|
+
@closing_tag = closing_tag
|
117
|
+
end
|
118
|
+
|
119
|
+
def inspect
|
120
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_hash
|
124
|
+
super.merge({
|
125
|
+
closing_tag: closing_tag,
|
126
|
+
})
|
127
|
+
end
|
128
|
+
|
129
|
+
def tree_inspect(indent = 0)
|
130
|
+
output = +""
|
131
|
+
|
132
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
133
|
+
output += %(├── message: #{message.inspect}\n)
|
134
|
+
output += %(└── closing_tag: #{closing_tag ? closing_tag.tree_inspect : "∅"}\n)
|
135
|
+
output += %(\n)
|
136
|
+
|
137
|
+
output.gsub(/^/, " " * indent)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class MissingClosingTagError < Error
|
142
|
+
attr_reader :opening_tag
|
143
|
+
|
144
|
+
def initialize(type, location, message, opening_tag)
|
145
|
+
super(type, location, message)
|
146
|
+
|
147
|
+
@opening_tag = opening_tag
|
148
|
+
end
|
149
|
+
|
150
|
+
def inspect
|
151
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
152
|
+
end
|
153
|
+
|
154
|
+
def to_hash
|
155
|
+
super.merge({
|
156
|
+
opening_tag: opening_tag,
|
157
|
+
})
|
158
|
+
end
|
159
|
+
|
160
|
+
def tree_inspect(indent = 0)
|
161
|
+
output = +""
|
162
|
+
|
163
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
164
|
+
output += %(├── message: #{message.inspect}\n)
|
165
|
+
output += %(└── opening_tag: #{opening_tag ? opening_tag.tree_inspect : "∅"}\n)
|
166
|
+
output += %(\n)
|
167
|
+
|
168
|
+
output.gsub(/^/, " " * indent)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class TagNamesMismatchError < Error
|
173
|
+
attr_reader :opening_tag
|
174
|
+
attr_reader :closing_tag
|
175
|
+
|
176
|
+
def initialize(type, location, message, opening_tag, closing_tag)
|
177
|
+
super(type, location, message)
|
178
|
+
|
179
|
+
@opening_tag = opening_tag
|
180
|
+
@closing_tag = closing_tag
|
181
|
+
end
|
182
|
+
|
183
|
+
def inspect
|
184
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
185
|
+
end
|
186
|
+
|
187
|
+
def to_hash
|
188
|
+
super.merge({
|
189
|
+
opening_tag: opening_tag,
|
190
|
+
closing_tag: closing_tag,
|
191
|
+
})
|
192
|
+
end
|
193
|
+
|
194
|
+
def tree_inspect(indent = 0)
|
195
|
+
output = +""
|
196
|
+
|
197
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
198
|
+
output += %(├── message: #{message.inspect}\n)
|
199
|
+
output += %(├── opening_tag: #{opening_tag ? opening_tag.tree_inspect : "∅"}\n)
|
200
|
+
output += %(└── closing_tag: #{closing_tag ? closing_tag.tree_inspect : "∅"}\n)
|
201
|
+
output += %(\n)
|
202
|
+
|
203
|
+
output.gsub(/^/, " " * indent)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class QuotesMismatchError < Error
|
208
|
+
attr_reader :opening_quote
|
209
|
+
attr_reader :closing_quote
|
210
|
+
|
211
|
+
def initialize(type, location, message, opening_quote, closing_quote)
|
212
|
+
super(type, location, message)
|
213
|
+
|
214
|
+
@opening_quote = opening_quote
|
215
|
+
@closing_quote = closing_quote
|
216
|
+
end
|
217
|
+
|
218
|
+
def inspect
|
219
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
220
|
+
end
|
221
|
+
|
222
|
+
def to_hash
|
223
|
+
super.merge({
|
224
|
+
opening_quote: opening_quote,
|
225
|
+
closing_quote: closing_quote,
|
226
|
+
})
|
227
|
+
end
|
228
|
+
|
229
|
+
def tree_inspect(indent = 0)
|
230
|
+
output = +""
|
231
|
+
|
232
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
233
|
+
output += %(├── message: #{message.inspect}\n)
|
234
|
+
output += %(├── opening_quote: #{opening_quote ? opening_quote.tree_inspect : "∅"}\n)
|
235
|
+
output += %(└── closing_quote: #{closing_quote ? closing_quote.tree_inspect : "∅"}\n)
|
236
|
+
output += %(\n)
|
237
|
+
|
238
|
+
output.gsub(/^/, " " * indent)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class VoidElementClosingTagError < Error
|
243
|
+
attr_reader :tag_name
|
244
|
+
attr_reader :expected
|
245
|
+
attr_reader :found
|
246
|
+
|
247
|
+
def initialize(type, location, message, tag_name, expected, found)
|
248
|
+
super(type, location, message)
|
249
|
+
|
250
|
+
@tag_name = tag_name
|
251
|
+
@expected = expected
|
252
|
+
@found = found
|
253
|
+
end
|
254
|
+
|
255
|
+
def inspect
|
256
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
257
|
+
end
|
258
|
+
|
259
|
+
def to_hash
|
260
|
+
super.merge({
|
261
|
+
tag_name: tag_name,
|
262
|
+
expected: expected,
|
263
|
+
found: found,
|
264
|
+
})
|
265
|
+
end
|
266
|
+
|
267
|
+
def tree_inspect(indent = 0)
|
268
|
+
output = +""
|
269
|
+
|
270
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
271
|
+
output += %(├── message: #{message.inspect}\n)
|
272
|
+
output += %(├── tag_name: #{tag_name ? tag_name.tree_inspect : "∅"}\n)
|
273
|
+
output += %(├── expected: #{expected.inspect}\n)
|
274
|
+
output += %(└── found: #{found.inspect}\n)
|
275
|
+
output += %(\n)
|
276
|
+
|
277
|
+
output.gsub(/^/, " " * indent)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class UnclosedElementError < Error
|
282
|
+
attr_reader :opening_tag
|
283
|
+
|
284
|
+
def initialize(type, location, message, opening_tag)
|
285
|
+
super(type, location, message)
|
286
|
+
|
287
|
+
@opening_tag = opening_tag
|
288
|
+
end
|
289
|
+
|
290
|
+
def inspect
|
291
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
292
|
+
end
|
293
|
+
|
294
|
+
def to_hash
|
295
|
+
super.merge({
|
296
|
+
opening_tag: opening_tag,
|
297
|
+
})
|
298
|
+
end
|
299
|
+
|
300
|
+
def tree_inspect(indent = 0)
|
301
|
+
output = +""
|
302
|
+
|
303
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
304
|
+
output += %(├── message: #{message.inspect}\n)
|
305
|
+
output += %(└── opening_tag: #{opening_tag ? opening_tag.tree_inspect : "∅"}\n)
|
306
|
+
output += %(\n)
|
307
|
+
|
308
|
+
output.gsub(/^/, " " * indent)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class RubyParseError < Error
|
313
|
+
attr_reader :error_message
|
314
|
+
attr_reader :diagnostic_id
|
315
|
+
attr_reader :level
|
316
|
+
|
317
|
+
def initialize(type, location, message, error_message, diagnostic_id, level)
|
318
|
+
super(type, location, message)
|
319
|
+
|
320
|
+
@error_message = error_message
|
321
|
+
@diagnostic_id = diagnostic_id
|
322
|
+
@level = level
|
323
|
+
end
|
324
|
+
|
325
|
+
def inspect
|
326
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
327
|
+
end
|
328
|
+
|
329
|
+
def to_hash
|
330
|
+
super.merge({
|
331
|
+
error_message: error_message,
|
332
|
+
diagnostic_id: diagnostic_id,
|
333
|
+
level: level,
|
334
|
+
})
|
335
|
+
end
|
336
|
+
|
337
|
+
def tree_inspect(indent = 0)
|
338
|
+
output = +""
|
339
|
+
|
340
|
+
output += %(@ #{error_name} #{location.tree_inspect}\n)
|
341
|
+
output += %(├── message: #{message.inspect}\n)
|
342
|
+
output += %(├── error_message: #{error_message.inspect}\n)
|
343
|
+
output += %(├── diagnostic_id: #{diagnostic_id.inspect}\n)
|
344
|
+
output += %(└── level: #{level.inspect}\n)
|
345
|
+
output += %(\n)
|
346
|
+
|
347
|
+
output.gsub(/^/, " " * indent)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
352
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Herb
|
4
|
+
class LexResult < Result
|
5
|
+
attr_reader :value
|
6
|
+
|
7
|
+
def initialize(value, source, warnings, errors)
|
8
|
+
@value = TokenList.new(value)
|
9
|
+
super(source, warnings, errors)
|
10
|
+
end
|
11
|
+
|
12
|
+
def success?
|
13
|
+
errors.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
def failed?
|
17
|
+
errors.any?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Herb
|
6
|
+
module LibHerb
|
7
|
+
attach_function :array_get, [:pointer, :int], :pointer
|
8
|
+
attach_function :array_capacity, [:pointer], :size_t
|
9
|
+
attach_function :array_size, [:pointer], :size_t
|
10
|
+
|
11
|
+
class Array
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
attr_reader :pointer, :item_class
|
15
|
+
|
16
|
+
def_delegators :items, :first, :last, :[]
|
17
|
+
|
18
|
+
def initialize(pointer, item_class)
|
19
|
+
@pointer = pointer
|
20
|
+
@item_class = item_class
|
21
|
+
end
|
22
|
+
|
23
|
+
def capacity
|
24
|
+
LibHerb.array_capacity(pointer)
|
25
|
+
end
|
26
|
+
|
27
|
+
def size
|
28
|
+
LibHerb.array_size(pointer)
|
29
|
+
end
|
30
|
+
|
31
|
+
def item_pointers
|
32
|
+
size.times.map { |item|
|
33
|
+
LibHerb.array_get(pointer, item)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def items
|
38
|
+
item_pointers.map { |item_pointer|
|
39
|
+
item_class.new(item_pointer)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
%(#<#{self.class} size=#{size} capacity=#{capacity} item_class=#{item_class} pointer=#{pointer}>)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Herb
|
4
|
+
module LibHerb
|
5
|
+
attach_function :ast_node_type, [:pointer], :int
|
6
|
+
attach_function :ast_node_type_to_string, [:pointer], :string
|
7
|
+
attach_function :ast_node_children, [:pointer], :pointer
|
8
|
+
attach_function :ast_node_child_count, [:pointer], :size_t
|
9
|
+
attach_function :ast_pretty_print_node, [:pointer, :size_t, :size_t, :pointer], :void
|
10
|
+
attach_function :ast_node_free, [:pointer], :void
|
11
|
+
|
12
|
+
class ASTNode
|
13
|
+
attr_reader :pointer
|
14
|
+
|
15
|
+
def initialize(pointer)
|
16
|
+
@pointer = pointer
|
17
|
+
end
|
18
|
+
|
19
|
+
def type_int
|
20
|
+
LibHerb.ast_node_type(pointer)
|
21
|
+
end
|
22
|
+
|
23
|
+
def type
|
24
|
+
LibHerb.ast_node_type_to_string(pointer)
|
25
|
+
end
|
26
|
+
|
27
|
+
def child_count
|
28
|
+
LibHerb.ast_node_child_count(pointer)
|
29
|
+
end
|
30
|
+
|
31
|
+
def children
|
32
|
+
LibHerb::Array.new(
|
33
|
+
LibHerb.ast_node_children(pointer),
|
34
|
+
ASTNode
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
LibHerb::Buffer.with do |output|
|
40
|
+
LibHerb.ast_pretty_print_node(pointer, 0, 0, output.pointer)
|
41
|
+
|
42
|
+
output.read.force_encoding("utf-8") # TODO: remove force_encoding
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Herb
|
4
|
+
module LibHerb
|
5
|
+
attach_function :buffer_init, [:pointer], :bool
|
6
|
+
attach_function :buffer_free, [:pointer], :void
|
7
|
+
attach_function :buffer_value, [:pointer], :pointer
|
8
|
+
attach_function :buffer_length, [:pointer], :size_t
|
9
|
+
attach_function :buffer_capacity, [:pointer], :size_t
|
10
|
+
attach_function :buffer_sizeof, [], :size_t
|
11
|
+
attach_function :buffer_append, [:pointer, :pointer], :void
|
12
|
+
|
13
|
+
class Buffer
|
14
|
+
SIZEOF = LibHerb.buffer_sizeof
|
15
|
+
|
16
|
+
attr_reader :pointer
|
17
|
+
|
18
|
+
def initialize(pointer)
|
19
|
+
@pointer = pointer
|
20
|
+
end
|
21
|
+
|
22
|
+
def append(string)
|
23
|
+
LibHerb.buffer_append(pointer, string)
|
24
|
+
end
|
25
|
+
|
26
|
+
def value
|
27
|
+
LibHerb.buffer_value(pointer)
|
28
|
+
end
|
29
|
+
|
30
|
+
def length
|
31
|
+
LibHerb.buffer_length(pointer)
|
32
|
+
end
|
33
|
+
|
34
|
+
def capacity
|
35
|
+
LibHerb.buffer_capacity(pointer)
|
36
|
+
end
|
37
|
+
|
38
|
+
def read
|
39
|
+
value.read_string(length)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.with
|
43
|
+
FFI::MemoryPointer.new(SIZEOF) do |pointer|
|
44
|
+
raise "couldn't allocate Buffer" unless LibHerb.buffer_init(pointer)
|
45
|
+
|
46
|
+
return yield new(pointer)
|
47
|
+
ensure
|
48
|
+
LibHerb.buffer_free(pointer)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Herb
|
6
|
+
class ExtractResult
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@buffer, :read
|
10
|
+
|
11
|
+
attr_accessor :buffer
|
12
|
+
|
13
|
+
def initialize(pointer)
|
14
|
+
@buffer = LibHerb::Buffer.new(pointer)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|