herb 0.8.8-arm-linux-gnu → 0.8.10-arm-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 +4 -4
- data/Makefile +22 -8
- data/config.yml +7 -0
- data/ext/herb/error_helpers.c +25 -0
- data/ext/herb/nodes.c +1 -1
- 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/4.0/herb.so +0 -0
- data/lib/herb/engine/compiler.rb +5 -3
- data/lib/herb/engine/debug_visitor.rb +38 -3
- data/lib/herb/engine.rb +16 -4
- data/lib/herb/errors.rb +20 -0
- data/lib/herb/version.rb +1 -1
- data/sig/herb/engine/debug_visitor.rbs +6 -0
- data/sig/herb/engine.rbs +2 -0
- data/sig/herb/errors.rbs +10 -0
- data/sig/serialized_ast_errors.rbs +3 -0
- data/src/analyze.c +28 -12
- data/src/analyze_helpers.c +32 -9
- data/src/errors.c +37 -0
- data/src/extract.c +6 -3
- data/src/include/analyze_helpers.h +18 -15
- data/src/include/errors.h +8 -0
- data/src/include/util/string.h +11 -0
- data/src/include/version.h +1 -1
- data/src/main.c +32 -44
- data/src/parser.c +6 -5
- data/vendor/prism/config.yml +4 -4
- data/vendor/prism/include/prism/ast.h +4 -4
- data/vendor/prism/include/prism/version.h +2 -2
- data/vendor/prism/src/prism.c +1 -1
- data/vendor/prism/templates/java/org/prism/Loader.java.erb +1 -1
- data/vendor/prism/templates/javascript/src/deserialize.js.erb +1 -1
- data/vendor/prism/templates/lib/prism/node.rb.erb +23 -15
- data/vendor/prism/templates/lib/prism/serialize.rb.erb +1 -1
- data/vendor/prism/templates/rbi/prism/node.rbi.erb +3 -0
- data/vendor/prism/templates/sig/prism/node.rbs.erb +3 -0
- data/vendor/prism/templates/sig/prism.rbs.erb +9 -10
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cce970c625f82f590b7b864222c558590b780b8beb41832ee1fcabbcc4921dc8
|
|
4
|
+
data.tar.gz: 87551da6a74a277c15dadf68d4b365a9f42461a05c1f9c6f22738da825e9b853
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c0d464f05bf5126d41ed6b0d82354733b09f67f5392c82aae800b90c61e8e30bc8aed4f213022b447548636e1707142e2e4c30c1c0d3fb7f6123d4a4029228b6
|
|
7
|
+
data.tar.gz: 2b11b9480eecddcede77573534358a3bb42b9539bc0a40f5ab3d3a0c06c51dc711a1d15e8205d77f61654d9013fa611c7fc76d91ee28ab704cdc9601bcca93f8
|
data/Makefile
CHANGED
|
@@ -67,15 +67,19 @@ ifeq ($(os),Linux)
|
|
|
67
67
|
endif
|
|
68
68
|
|
|
69
69
|
ifeq ($(os),Darwin)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
cc
|
|
75
|
-
clang_format
|
|
76
|
-
clang_tidy
|
|
70
|
+
llvm_version := 21
|
|
71
|
+
llvm_prefix ?= $(shell brew --prefix llvm@$(llvm_version))
|
|
72
|
+
check_prefix ?= $(shell brew --prefix check)
|
|
73
|
+
|
|
74
|
+
cc ?= $(llvm_prefix)/bin/clang
|
|
75
|
+
clang_format ?= $(llvm_prefix)/bin/clang-format
|
|
76
|
+
clang_tidy ?= $(llvm_prefix)/bin/clang-tidy
|
|
77
|
+
|
|
78
|
+
test_cflags = $(test_flags) -I$(check_prefix)/include
|
|
79
|
+
test_ldflags = -L$(check_prefix)/lib -lcheck -lm $(prism_ldflags)
|
|
77
80
|
endif
|
|
78
81
|
|
|
82
|
+
.PHONY: all
|
|
79
83
|
all: templates prism $(exec) $(lib_name) $(static_lib_name) test wasm clangd_config
|
|
80
84
|
|
|
81
85
|
$(exec): $(objects)
|
|
@@ -91,39 +95,49 @@ $(static_lib_name): $(objects)
|
|
|
91
95
|
src/%.o: src/%.c templates
|
|
92
96
|
$(cc) -c $(flags) -fPIC $< -o $@
|
|
93
97
|
|
|
94
|
-
test/%.o: test/%.c templates
|
|
98
|
+
test/%.o: test/%.c templates prism
|
|
95
99
|
$(cc) -c $(test_cflags) $(test_flags) $(prism_flags) $< -o $@
|
|
96
100
|
|
|
101
|
+
.PHONY: test
|
|
97
102
|
test: $(test_objects) $(non_main_objects)
|
|
98
103
|
$(cc) $(test_objects) $(non_main_objects) $(test_cflags) $(test_ldflags) -o $(test_exec)
|
|
99
104
|
|
|
105
|
+
.PHONY: clean
|
|
100
106
|
clean:
|
|
101
107
|
rm -f $(exec) $(test_exec) $(lib_name) $(shared_lib_name) $(ruby_extension)
|
|
102
108
|
rm -rf $(objects) $(test_objects) $(extension_objects) lib/herb/*.bundle tmp
|
|
103
109
|
rm -rf $(prism_path)
|
|
104
110
|
rake prism:clean
|
|
105
111
|
|
|
112
|
+
.PHONY: bundle_install
|
|
106
113
|
bundle_install:
|
|
107
114
|
bundle install
|
|
108
115
|
|
|
116
|
+
.PHONY: templates
|
|
109
117
|
templates: bundle_install
|
|
110
118
|
bundle exec rake templates
|
|
111
119
|
|
|
120
|
+
.PHONY: prism
|
|
112
121
|
prism: bundle_install
|
|
113
122
|
cd $(prism_path) && ruby templates/template.rb && make static && cd -
|
|
114
123
|
rake prism:vendor
|
|
115
124
|
|
|
125
|
+
.PHONY: format
|
|
116
126
|
format:
|
|
117
127
|
$(clang_format) -i $(project_and_extension_files)
|
|
118
128
|
|
|
129
|
+
.PHONY: lint
|
|
119
130
|
lint:
|
|
120
131
|
$(clang_format) --dry-run --Werror $(project_and_extension_files)
|
|
121
132
|
|
|
133
|
+
.PHONY: tidy
|
|
122
134
|
tidy:
|
|
123
135
|
$(clang_tidy) $(project_files) -- $(flags)
|
|
124
136
|
|
|
137
|
+
.PHONY: clangd_config
|
|
125
138
|
clangd_config:
|
|
126
139
|
@echo "$(flags) $(test_cflags)" | tr ' ' '\n' | sort -u > compile_flags.txt
|
|
127
140
|
|
|
141
|
+
.PHONY: wasm
|
|
128
142
|
wasm:
|
|
129
143
|
cd wasm && make
|
data/config.yml
CHANGED
|
@@ -178,6 +178,13 @@ errors:
|
|
|
178
178
|
|
|
179
179
|
fields: []
|
|
180
180
|
|
|
181
|
+
- name: ERBCaseWithConditionsError
|
|
182
|
+
message:
|
|
183
|
+
template: "A `case` statement with `when`/`in` in a single ERB tag cannot be formatted. Use separate tags for `case` and its conditions."
|
|
184
|
+
arguments: []
|
|
185
|
+
|
|
186
|
+
fields: []
|
|
187
|
+
|
|
181
188
|
warnings:
|
|
182
189
|
fields: []
|
|
183
190
|
types: []
|
data/ext/herb/error_helpers.c
CHANGED
|
@@ -341,6 +341,30 @@ static VALUE rb_erb_multiple_blocks_in_tag_error_from_c_struct(ERB_MULTIPLE_BLOC
|
|
|
341
341
|
return rb_class_new_instance(3, args, ERBMultipleBlocksInTagError);
|
|
342
342
|
};
|
|
343
343
|
|
|
344
|
+
static VALUE rb_erb_case_with_conditions_error_from_c_struct(ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error) {
|
|
345
|
+
if (erb_case_with_conditions_error == NULL) { return Qnil; }
|
|
346
|
+
|
|
347
|
+
ERROR_T* error = &erb_case_with_conditions_error->base;
|
|
348
|
+
|
|
349
|
+
VALUE Herb = rb_define_module("Herb");
|
|
350
|
+
VALUE Errors = rb_define_module_under(Herb, "Errors");
|
|
351
|
+
VALUE Error = rb_define_class_under(Errors, "Error", rb_cObject);
|
|
352
|
+
VALUE ERBCaseWithConditionsError = rb_define_class_under(Errors, "ERBCaseWithConditionsError", Error);
|
|
353
|
+
|
|
354
|
+
VALUE type = rb_utf8_str_new_cstr(error_type_to_string(error));
|
|
355
|
+
VALUE location = rb_location_from_c_struct(error->location);
|
|
356
|
+
VALUE message = rb_utf8_str_new_cstr(error->message);
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
VALUE args[3] = {
|
|
360
|
+
type,
|
|
361
|
+
location,
|
|
362
|
+
message
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
return rb_class_new_instance(3, args, ERBCaseWithConditionsError);
|
|
366
|
+
};
|
|
367
|
+
|
|
344
368
|
|
|
345
369
|
VALUE rb_error_from_c_struct(ERROR_T* error) {
|
|
346
370
|
if (!error) { return Qnil; }
|
|
@@ -358,6 +382,7 @@ VALUE rb_error_from_c_struct(ERROR_T* error) {
|
|
|
358
382
|
case ERB_CONTROL_FLOW_SCOPE_ERROR: return rb_erb_control_flow_scope_error_from_c_struct((ERB_CONTROL_FLOW_SCOPE_ERROR_T*) error); break;
|
|
359
383
|
case MISSINGERB_END_TAG_ERROR: return rb_missingerb_end_tag_error_from_c_struct((MISSINGERB_END_TAG_ERROR_T*) error); break;
|
|
360
384
|
case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: return rb_erb_multiple_blocks_in_tag_error_from_c_struct((ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T*) error); break;
|
|
385
|
+
case ERB_CASE_WITH_CONDITIONS_ERROR: return rb_erb_case_with_conditions_error_from_c_struct((ERB_CASE_WITH_CONDITIONS_ERROR_T*) error); break;
|
|
361
386
|
}
|
|
362
387
|
|
|
363
388
|
return Qnil;
|
data/ext/herb/nodes.c
CHANGED
|
@@ -464,7 +464,7 @@ static VALUE rb_erb_content_node_from_c_struct(AST_ERB_CONTENT_NODE_T* erb_conte
|
|
|
464
464
|
VALUE erb_content_node_tag_opening = rb_token_from_c_struct(erb_content_node->tag_opening);
|
|
465
465
|
VALUE erb_content_node_content = rb_token_from_c_struct(erb_content_node->content);
|
|
466
466
|
VALUE erb_content_node_tag_closing = rb_token_from_c_struct(erb_content_node->tag_closing);
|
|
467
|
-
/* #<Herb::Template::AnalyzedRubyField:
|
|
467
|
+
/* #<Herb::Template::AnalyzedRubyField:0x00007fb54f94c300 @name="analyzed_ruby", @options={kind: nil}> */
|
|
468
468
|
VALUE erb_content_node_analyzed_ruby = Qnil;
|
|
469
469
|
VALUE erb_content_node_parsed = (erb_content_node->parsed) ? Qtrue : Qfalse;
|
|
470
470
|
VALUE erb_content_node_valid = (erb_content_node->valid) ? Qtrue : Qfalse;
|
data/lib/herb/3.0/herb.so
CHANGED
|
Binary file
|
data/lib/herb/3.1/herb.so
CHANGED
|
Binary file
|
data/lib/herb/3.2/herb.so
CHANGED
|
Binary file
|
data/lib/herb/3.3/herb.so
CHANGED
|
Binary file
|
data/lib/herb/3.4/herb.so
CHANGED
|
Binary file
|
data/lib/herb/4.0/herb.so
CHANGED
|
Binary file
|
data/lib/herb/engine/compiler.rb
CHANGED
|
@@ -297,18 +297,20 @@ module Herb
|
|
|
297
297
|
end
|
|
298
298
|
|
|
299
299
|
def add_context_aware_expression(code, context)
|
|
300
|
+
closing = code.include?("#") ? "\n))" : "))"
|
|
301
|
+
|
|
300
302
|
case context
|
|
301
303
|
when :attribute_value
|
|
302
304
|
@engine.send(:with_buffer) {
|
|
303
|
-
@engine.src << " << #{@attrfunc}((" << code <<
|
|
305
|
+
@engine.src << " << #{@attrfunc}((" << code << closing
|
|
304
306
|
}
|
|
305
307
|
when :script_content
|
|
306
308
|
@engine.send(:with_buffer) {
|
|
307
|
-
@engine.src << " << #{@jsfunc}((" << code <<
|
|
309
|
+
@engine.src << " << #{@jsfunc}((" << code << closing
|
|
308
310
|
}
|
|
309
311
|
when :style_content
|
|
310
312
|
@engine.send(:with_buffer) {
|
|
311
|
-
@engine.src << " << #{@cssfunc}((" << code <<
|
|
313
|
+
@engine.src << " << #{@cssfunc}((" << code << closing
|
|
312
314
|
}
|
|
313
315
|
else
|
|
314
316
|
@engine.send(:add_expression_result_escaped, code)
|
|
@@ -178,7 +178,7 @@ module Herb
|
|
|
178
178
|
|
|
179
179
|
debug_attributes = [
|
|
180
180
|
create_debug_attribute("data-herb-debug-outline-type", view_type),
|
|
181
|
-
create_debug_attribute("data-herb-debug-file-name",
|
|
181
|
+
create_debug_attribute("data-herb-debug-file-name", component_display_name),
|
|
182
182
|
create_debug_attribute("data-herb-debug-file-relative-path", @relative_file_path || "unknown"),
|
|
183
183
|
create_debug_attribute("data-herb-debug-file-full-path", @filename&.to_s || "unknown")
|
|
184
184
|
]
|
|
@@ -231,7 +231,7 @@ module Herb
|
|
|
231
231
|
debug_attributes = [
|
|
232
232
|
create_debug_attribute("data-herb-debug-outline-type", outline_type),
|
|
233
233
|
create_debug_attribute("data-herb-debug-erb", escaped_erb),
|
|
234
|
-
create_debug_attribute("data-herb-debug-file-name",
|
|
234
|
+
create_debug_attribute("data-herb-debug-file-name", component_display_name),
|
|
235
235
|
create_debug_attribute("data-herb-debug-file-relative-path", @relative_file_path || "unknown"),
|
|
236
236
|
create_debug_attribute("data-herb-debug-file-full-path", @filename&.to_s || "unknown"),
|
|
237
237
|
create_debug_attribute("data-herb-debug-inserted", "true")
|
|
@@ -288,8 +288,43 @@ module Herb
|
|
|
288
288
|
def component?
|
|
289
289
|
return false unless @filename
|
|
290
290
|
|
|
291
|
+
@filename.to_s.match?(%r{(^|/)app/components/})
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def sidecar_component?
|
|
295
|
+
return false unless component?
|
|
296
|
+
return false unless @filename
|
|
297
|
+
|
|
298
|
+
@filename.basename.to_s.match?(/\Acomponent\.(html\.erb|html\.herb|erb|herb)\z/)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def component_display_name
|
|
302
|
+
return @filename&.basename&.to_s || "unknown" unless @filename
|
|
303
|
+
|
|
304
|
+
basename = @filename.basename.to_s
|
|
291
305
|
path = @filename.to_s
|
|
292
|
-
|
|
306
|
+
|
|
307
|
+
if sidecar_component? && (match = path.match(%r{/components/(.+)/component\.[^/]+\z}))
|
|
308
|
+
return match[1].split("/").map { |s| classify(s) }.join("::")
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
if component?
|
|
312
|
+
path_without_ext = path.sub(/\.(?:html\.erb|html\.herb|erb|herb)\z/, "")
|
|
313
|
+
|
|
314
|
+
if (match = path_without_ext.match(%r{/components/(.+)\z}))
|
|
315
|
+
return match[1].split("/").map { |s| classify(s) }.join("::")
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
basename
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def classify(name)
|
|
323
|
+
if name.respond_to?(:camelize)
|
|
324
|
+
name.camelize
|
|
325
|
+
else
|
|
326
|
+
name.split(/[_-]/).map(&:capitalize).join
|
|
327
|
+
end
|
|
293
328
|
end
|
|
294
329
|
|
|
295
330
|
def in_head_context?
|
data/lib/herb/engine.rb
CHANGED
|
@@ -212,11 +212,15 @@ module Herb
|
|
|
212
212
|
end
|
|
213
213
|
|
|
214
214
|
def add_expression_result(code)
|
|
215
|
-
with_buffer {
|
|
215
|
+
with_buffer {
|
|
216
|
+
@src << " << (" << code << comment_aware_newline(code) << ").to_s"
|
|
217
|
+
}
|
|
216
218
|
end
|
|
217
219
|
|
|
218
220
|
def add_expression_result_escaped(code)
|
|
219
|
-
with_buffer {
|
|
221
|
+
with_buffer {
|
|
222
|
+
@src << " << " << @escapefunc << "((" << code << comment_aware_newline(code) << "))"
|
|
223
|
+
}
|
|
220
224
|
end
|
|
221
225
|
|
|
222
226
|
def add_expression_block(indicator, code)
|
|
@@ -228,11 +232,19 @@ module Herb
|
|
|
228
232
|
end
|
|
229
233
|
|
|
230
234
|
def add_expression_block_result(code)
|
|
231
|
-
with_buffer {
|
|
235
|
+
with_buffer {
|
|
236
|
+
@src << " << " << code << comment_aware_newline(code)
|
|
237
|
+
}
|
|
232
238
|
end
|
|
233
239
|
|
|
234
240
|
def add_expression_block_result_escaped(code)
|
|
235
|
-
with_buffer {
|
|
241
|
+
with_buffer {
|
|
242
|
+
@src << " << " << @escapefunc << "(" << code << comment_aware_newline(code) << ")"
|
|
243
|
+
}
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def comment_aware_newline(code)
|
|
247
|
+
code.include?("#") ? "\n" : ""
|
|
236
248
|
end
|
|
237
249
|
|
|
238
250
|
def add_postamble(postamble)
|
data/lib/herb/errors.rb
CHANGED
|
@@ -518,5 +518,25 @@ module Herb
|
|
|
518
518
|
end
|
|
519
519
|
end
|
|
520
520
|
|
|
521
|
+
class ERBCaseWithConditionsError < Error
|
|
522
|
+
include Colors
|
|
523
|
+
|
|
524
|
+
#: () -> String
|
|
525
|
+
def inspect
|
|
526
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
#: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
530
|
+
def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
|
|
531
|
+
output = +""
|
|
532
|
+
|
|
533
|
+
output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
|
|
534
|
+
output += white("└── message: #{green(message.inspect)}\n")
|
|
535
|
+
output += %(\n)
|
|
536
|
+
|
|
537
|
+
output.gsub(/^/, " " * indent)
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
521
541
|
end
|
|
522
542
|
end
|
data/lib/herb/version.rb
CHANGED
|
@@ -57,6 +57,12 @@ module Herb
|
|
|
57
57
|
|
|
58
58
|
def component?: () -> untyped
|
|
59
59
|
|
|
60
|
+
def sidecar_component?: () -> untyped
|
|
61
|
+
|
|
62
|
+
def component_display_name: () -> untyped
|
|
63
|
+
|
|
64
|
+
def classify: (untyped name) -> untyped
|
|
65
|
+
|
|
60
66
|
def in_head_context?: () -> untyped
|
|
61
67
|
|
|
62
68
|
def in_script_or_style_context?: () -> untyped
|
data/sig/herb/engine.rbs
CHANGED
data/sig/herb/errors.rbs
CHANGED
|
@@ -253,5 +253,15 @@ module Herb
|
|
|
253
253
|
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
254
254
|
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
255
255
|
end
|
|
256
|
+
|
|
257
|
+
class ERBCaseWithConditionsError < Error
|
|
258
|
+
include Colors
|
|
259
|
+
|
|
260
|
+
# : () -> String
|
|
261
|
+
def inspect: () -> String
|
|
262
|
+
|
|
263
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
264
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
265
|
+
end
|
|
256
266
|
end
|
|
257
267
|
end
|
data/src/analyze.c
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#include "include/util.h"
|
|
15
15
|
#include "include/util/hb_array.h"
|
|
16
16
|
#include "include/util/hb_string.h"
|
|
17
|
+
#include "include/util/string.h"
|
|
17
18
|
#include "include/visitor.h"
|
|
18
19
|
|
|
19
20
|
#include <prism.h>
|
|
@@ -34,17 +35,20 @@ static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source) {
|
|
|
34
35
|
pm_visit_node(analyzed->root, search_until_nodes, analyzed);
|
|
35
36
|
pm_visit_node(analyzed->root, search_begin_nodes, analyzed);
|
|
36
37
|
pm_visit_node(analyzed->root, search_unless_nodes, analyzed);
|
|
38
|
+
pm_visit_node(analyzed->root, search_when_nodes, analyzed);
|
|
39
|
+
pm_visit_node(analyzed->root, search_in_nodes, analyzed);
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
search_unexpected_elsif_nodes(analyzed);
|
|
42
|
+
search_unexpected_else_nodes(analyzed);
|
|
43
|
+
search_unexpected_end_nodes(analyzed);
|
|
44
|
+
search_unexpected_when_nodes(analyzed);
|
|
45
|
+
search_unexpected_in_nodes(analyzed);
|
|
46
|
+
|
|
47
|
+
search_unexpected_rescue_nodes(analyzed);
|
|
48
|
+
search_unexpected_ensure_nodes(analyzed);
|
|
45
49
|
search_yield_nodes(analyzed->root, analyzed);
|
|
46
50
|
search_then_keywords(analyzed->root, analyzed);
|
|
47
|
-
|
|
51
|
+
search_unexpected_block_closing_nodes(analyzed);
|
|
48
52
|
|
|
49
53
|
if (!analyzed->valid) { pm_visit_node(analyzed->root, search_unclosed_control_flows, analyzed); }
|
|
50
54
|
|
|
@@ -57,8 +61,8 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
|
|
|
57
61
|
|
|
58
62
|
const char* opening = erb_content_node->tag_opening->value;
|
|
59
63
|
|
|
60
|
-
if (
|
|
61
|
-
&&
|
|
64
|
+
if (!string_equals(opening, "<%%") && !string_equals(opening, "<%%=") && !string_equals(opening, "<%#")
|
|
65
|
+
&& !string_equals(opening, "<%graphql")) {
|
|
62
66
|
analyzed_ruby_T* analyzed = herb_analyze_ruby(hb_string(erb_content_node->content->value));
|
|
63
67
|
|
|
64
68
|
erb_content_node->parsed = true;
|
|
@@ -72,6 +76,16 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
|
|
|
72
76
|
erb_content_node->base.errors
|
|
73
77
|
);
|
|
74
78
|
}
|
|
79
|
+
|
|
80
|
+
if (!analyzed->valid
|
|
81
|
+
&& ((analyzed->case_node_count > 0 && analyzed->when_node_count > 0)
|
|
82
|
+
|| (analyzed->case_match_node_count > 0 && analyzed->in_node_count > 0))) {
|
|
83
|
+
append_erb_case_with_conditions_error(
|
|
84
|
+
erb_content_node->base.location.start,
|
|
85
|
+
erb_content_node->base.location.end,
|
|
86
|
+
erb_content_node->base.errors
|
|
87
|
+
);
|
|
88
|
+
}
|
|
75
89
|
} else {
|
|
76
90
|
erb_content_node->parsed = false;
|
|
77
91
|
erb_content_node->valid = true;
|
|
@@ -274,12 +288,14 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
|
|
|
274
288
|
if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
|
|
275
289
|
if (has_else_node(ruby)) { return CONTROL_TYPE_ELSE; }
|
|
276
290
|
if (has_end(ruby)) { return CONTROL_TYPE_END; }
|
|
277
|
-
if (has_when_node(ruby)) { return CONTROL_TYPE_WHEN; }
|
|
278
|
-
if (has_in_node(ruby)) { return CONTROL_TYPE_IN; }
|
|
291
|
+
if (has_when_node(ruby) && !has_case_node(ruby)) { return CONTROL_TYPE_WHEN; }
|
|
292
|
+
if (has_in_node(ruby) && !has_case_match_node(ruby)) { return CONTROL_TYPE_IN; }
|
|
279
293
|
if (has_rescue_node(ruby)) { return CONTROL_TYPE_RESCUE; }
|
|
280
294
|
if (has_ensure_node(ruby)) { return CONTROL_TYPE_ENSURE; }
|
|
281
295
|
if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
|
|
282
296
|
|
|
297
|
+
if (ruby->unclosed_control_flow_count == 0 && !has_yield_node(ruby)) { return CONTROL_TYPE_UNKNOWN; }
|
|
298
|
+
|
|
283
299
|
return find_earliest_control_keyword(root, ruby->parser.start);
|
|
284
300
|
}
|
|
285
301
|
|
data/src/analyze_helpers.c
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <string.h>
|
|
4
4
|
|
|
5
5
|
#include "include/analyzed_ruby.h"
|
|
6
|
+
#include "include/util/string.h"
|
|
6
7
|
|
|
7
8
|
bool has_if_node(analyzed_ruby_T* analyzed) {
|
|
8
9
|
return analyzed->if_node_count > 0;
|
|
@@ -83,7 +84,7 @@ bool has_then_keyword(analyzed_ruby_T* analyzed) {
|
|
|
83
84
|
bool has_error_message(analyzed_ruby_T* anlayzed, const char* message) {
|
|
84
85
|
for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) anlayzed->parser.error_list.head; error != NULL;
|
|
85
86
|
error = (const pm_diagnostic_t*) error->node.next) {
|
|
86
|
-
if (
|
|
87
|
+
if (string_equals(error->message, message)) { return true; }
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
return false;
|
|
@@ -242,7 +243,28 @@ bool search_unless_nodes(const pm_node_t* node, void* data) {
|
|
|
242
243
|
return false;
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
bool
|
|
246
|
+
bool search_when_nodes(const pm_node_t* node, void* data) {
|
|
247
|
+
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
248
|
+
|
|
249
|
+
if (node->type == PM_WHEN_NODE) { analyzed->when_node_count++; }
|
|
250
|
+
|
|
251
|
+
pm_visit_child_nodes(node, search_when_nodes, analyzed);
|
|
252
|
+
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
bool search_in_nodes(const pm_node_t* node, void* data) {
|
|
257
|
+
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
258
|
+
|
|
259
|
+
if (node->type == PM_IN_NODE) { analyzed->in_node_count++; }
|
|
260
|
+
if (node->type == PM_MATCH_PREDICATE_NODE) { analyzed->in_node_count++; }
|
|
261
|
+
|
|
262
|
+
pm_visit_child_nodes(node, search_in_nodes, analyzed);
|
|
263
|
+
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed) {
|
|
246
268
|
if (has_error_message(analyzed, "unexpected 'elsif', ignoring it")) {
|
|
247
269
|
analyzed->elsif_node_count++;
|
|
248
270
|
return true;
|
|
@@ -251,7 +273,7 @@ bool search_elsif_nodes(analyzed_ruby_T* analyzed) {
|
|
|
251
273
|
return false;
|
|
252
274
|
}
|
|
253
275
|
|
|
254
|
-
bool
|
|
276
|
+
bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed) {
|
|
255
277
|
if (has_error_message(analyzed, "unexpected 'else', ignoring it")) {
|
|
256
278
|
analyzed->else_node_count++;
|
|
257
279
|
return true;
|
|
@@ -260,7 +282,7 @@ bool search_else_nodes(analyzed_ruby_T* analyzed) {
|
|
|
260
282
|
return false;
|
|
261
283
|
}
|
|
262
284
|
|
|
263
|
-
bool
|
|
285
|
+
bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed) {
|
|
264
286
|
if (has_error_message(analyzed, "unexpected 'end', ignoring it")) {
|
|
265
287
|
if (has_error_message(analyzed, "unexpected '=', ignoring it")) {
|
|
266
288
|
// `=end`
|
|
@@ -274,7 +296,7 @@ bool search_end_nodes(analyzed_ruby_T* analyzed) {
|
|
|
274
296
|
return false;
|
|
275
297
|
}
|
|
276
298
|
|
|
277
|
-
bool
|
|
299
|
+
bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed) {
|
|
278
300
|
if (has_error_message(analyzed, "unexpected '}', ignoring it")) {
|
|
279
301
|
analyzed->block_closing_count++;
|
|
280
302
|
return true;
|
|
@@ -283,7 +305,7 @@ bool search_block_closing_nodes(analyzed_ruby_T* analyzed) {
|
|
|
283
305
|
return false;
|
|
284
306
|
}
|
|
285
307
|
|
|
286
|
-
bool
|
|
308
|
+
bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed) {
|
|
287
309
|
if (has_error_message(analyzed, "unexpected 'when', ignoring it")) {
|
|
288
310
|
analyzed->when_node_count++;
|
|
289
311
|
return true;
|
|
@@ -292,7 +314,7 @@ bool search_when_nodes(analyzed_ruby_T* analyzed) {
|
|
|
292
314
|
return false;
|
|
293
315
|
}
|
|
294
316
|
|
|
295
|
-
bool
|
|
317
|
+
bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed) {
|
|
296
318
|
if (has_error_message(analyzed, "unexpected 'in', ignoring it")) {
|
|
297
319
|
analyzed->in_node_count++;
|
|
298
320
|
return true;
|
|
@@ -301,7 +323,7 @@ bool search_in_nodes(analyzed_ruby_T* analyzed) {
|
|
|
301
323
|
return false;
|
|
302
324
|
}
|
|
303
325
|
|
|
304
|
-
bool
|
|
326
|
+
bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed) {
|
|
305
327
|
if (has_error_message(analyzed, "unexpected 'rescue', ignoring it")) {
|
|
306
328
|
analyzed->rescue_node_count++;
|
|
307
329
|
return true;
|
|
@@ -310,7 +332,7 @@ bool search_rescue_nodes(analyzed_ruby_T* analyzed) {
|
|
|
310
332
|
return false;
|
|
311
333
|
}
|
|
312
334
|
|
|
313
|
-
bool
|
|
335
|
+
bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed) {
|
|
314
336
|
if (has_error_message(analyzed, "unexpected 'ensure', ignoring it")) {
|
|
315
337
|
analyzed->ensure_node_count++;
|
|
316
338
|
return true;
|
|
@@ -468,6 +490,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
468
490
|
if (has_opening && !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc)) {
|
|
469
491
|
analyzed->unclosed_control_flow_count++;
|
|
470
492
|
}
|
|
493
|
+
|
|
471
494
|
break;
|
|
472
495
|
}
|
|
473
496
|
|
data/src/errors.c
CHANGED
|
@@ -511,6 +511,20 @@ void append_erb_multiple_blocks_in_tag_error(position_T start, position_T end, h
|
|
|
511
511
|
hb_array_append(errors, erb_multiple_blocks_in_tag_error_init(start, end));
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
+
ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error_init(position_T start, position_T end) {
|
|
515
|
+
ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error = malloc(sizeof(ERB_CASE_WITH_CONDITIONS_ERROR_T));
|
|
516
|
+
|
|
517
|
+
error_init(&erb_case_with_conditions_error->base, ERB_CASE_WITH_CONDITIONS_ERROR, start, end);
|
|
518
|
+
|
|
519
|
+
erb_case_with_conditions_error->base.message = herb_strdup("A `case` statement with `when`/`in` in a single ERB tag cannot be formatted. Use separate tags for `case` and its conditions.");
|
|
520
|
+
|
|
521
|
+
return erb_case_with_conditions_error;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
void append_erb_case_with_conditions_error(position_T start, position_T end, hb_array_T* errors) {
|
|
525
|
+
hb_array_append(errors, erb_case_with_conditions_error_init(start, end));
|
|
526
|
+
}
|
|
527
|
+
|
|
514
528
|
const char* error_type_to_string(ERROR_T* error) {
|
|
515
529
|
switch (error->type) {
|
|
516
530
|
case UNEXPECTED_ERROR: return "UNEXPECTED_ERROR";
|
|
@@ -525,6 +539,7 @@ const char* error_type_to_string(ERROR_T* error) {
|
|
|
525
539
|
case ERB_CONTROL_FLOW_SCOPE_ERROR: return "ERB_CONTROL_FLOW_SCOPE_ERROR";
|
|
526
540
|
case MISSINGERB_END_TAG_ERROR: return "MISSINGERB_END_TAG_ERROR";
|
|
527
541
|
case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: return "ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR";
|
|
542
|
+
case ERB_CASE_WITH_CONDITIONS_ERROR: return "ERB_CASE_WITH_CONDITIONS_ERROR";
|
|
528
543
|
}
|
|
529
544
|
|
|
530
545
|
return "Unknown error_type_T";
|
|
@@ -544,6 +559,7 @@ const char* error_human_type(ERROR_T* error) {
|
|
|
544
559
|
case ERB_CONTROL_FLOW_SCOPE_ERROR: return "ERBControlFlowScopeError";
|
|
545
560
|
case MISSINGERB_END_TAG_ERROR: return "MissingERBEndTagError";
|
|
546
561
|
case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: return "ERBMultipleBlocksInTagError";
|
|
562
|
+
case ERB_CASE_WITH_CONDITIONS_ERROR: return "ERBCaseWithConditionsError";
|
|
547
563
|
}
|
|
548
564
|
|
|
549
565
|
return "Unknown error_type_T";
|
|
@@ -638,6 +654,12 @@ static void error_free_erb_multiple_blocks_in_tag_error(ERB_MULTIPLE_BLOCKS_IN_T
|
|
|
638
654
|
error_free_base_error(&erb_multiple_blocks_in_tag_error->base);
|
|
639
655
|
}
|
|
640
656
|
|
|
657
|
+
static void error_free_erb_case_with_conditions_error(ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error) {
|
|
658
|
+
/* no ERB_CASE_WITH_CONDITIONS_ERROR_T specific fields to free up */
|
|
659
|
+
|
|
660
|
+
error_free_base_error(&erb_case_with_conditions_error->base);
|
|
661
|
+
}
|
|
662
|
+
|
|
641
663
|
void error_free(ERROR_T* error) {
|
|
642
664
|
if (!error) { return; }
|
|
643
665
|
|
|
@@ -654,6 +676,7 @@ void error_free(ERROR_T* error) {
|
|
|
654
676
|
case ERB_CONTROL_FLOW_SCOPE_ERROR: error_free_erb_control_flow_scope_error((ERB_CONTROL_FLOW_SCOPE_ERROR_T*) error); break;
|
|
655
677
|
case MISSINGERB_END_TAG_ERROR: error_free_missingerb_end_tag_error((MISSINGERB_END_TAG_ERROR_T*) error); break;
|
|
656
678
|
case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: error_free_erb_multiple_blocks_in_tag_error((ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T*) error); break;
|
|
679
|
+
case ERB_CASE_WITH_CONDITIONS_ERROR: error_free_erb_case_with_conditions_error((ERB_CASE_WITH_CONDITIONS_ERROR_T*) error); break;
|
|
657
680
|
}
|
|
658
681
|
}
|
|
659
682
|
|
|
@@ -877,6 +900,19 @@ static void error_pretty_print_erb_multiple_blocks_in_tag_error(ERB_MULTIPLE_BLO
|
|
|
877
900
|
pretty_print_quoted_property(hb_string("message"), hb_string(error->base.message), indent, relative_indent, true, buffer);
|
|
878
901
|
}
|
|
879
902
|
|
|
903
|
+
static void error_pretty_print_erb_case_with_conditions_error(ERB_CASE_WITH_CONDITIONS_ERROR_T* error, const size_t indent, const size_t relative_indent, hb_buffer_T* buffer) {
|
|
904
|
+
if (!error) { return; }
|
|
905
|
+
|
|
906
|
+
hb_buffer_append(buffer, "@ ");
|
|
907
|
+
hb_buffer_append(buffer, error_human_type((ERROR_T*) error));
|
|
908
|
+
hb_buffer_append(buffer, " ");
|
|
909
|
+
|
|
910
|
+
pretty_print_location(error->base.location, buffer);
|
|
911
|
+
hb_buffer_append(buffer, "\n");
|
|
912
|
+
|
|
913
|
+
pretty_print_quoted_property(hb_string("message"), hb_string(error->base.message), indent, relative_indent, true, buffer);
|
|
914
|
+
}
|
|
915
|
+
|
|
880
916
|
void error_pretty_print(ERROR_T* error, const size_t indent, const size_t relative_indent, hb_buffer_T* buffer) {
|
|
881
917
|
if (!error) { return; }
|
|
882
918
|
|
|
@@ -893,5 +929,6 @@ void error_pretty_print(ERROR_T* error, const size_t indent, const size_t relati
|
|
|
893
929
|
case ERB_CONTROL_FLOW_SCOPE_ERROR: error_pretty_print_erb_control_flow_scope_error((ERB_CONTROL_FLOW_SCOPE_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
894
930
|
case MISSINGERB_END_TAG_ERROR: error_pretty_print_missingerb_end_tag_error((MISSINGERB_END_TAG_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
895
931
|
case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: error_pretty_print_erb_multiple_blocks_in_tag_error((ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
932
|
+
case ERB_CASE_WITH_CONDITIONS_ERROR: error_pretty_print_erb_case_with_conditions_error((ERB_CASE_WITH_CONDITIONS_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
896
933
|
}
|
|
897
934
|
}
|