textmate_grammar 0.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 +7 -0
- data/LICENSE +21 -0
- data/lib/textmate_grammar/generated/grammar.rb +32 -0
- data/lib/textmate_grammar/generated/rule.rb +144 -0
- data/lib/textmate_grammar/grammar.rb +670 -0
- data/lib/textmate_grammar/grammar_plugin.rb +189 -0
- data/lib/textmate_grammar/import_patterns.rb +14 -0
- data/lib/textmate_grammar/linters/flat_includes.rb +32 -0
- data/lib/textmate_grammar/linters/includes_then_tag_as.rb +48 -0
- data/lib/textmate_grammar/linters/standard_naming.rb +226 -0
- data/lib/textmate_grammar/linters/start_match_empty.rb +49 -0
- data/lib/textmate_grammar/linters/tests.rb +19 -0
- data/lib/textmate_grammar/linters/unused_unresolved.rb +9 -0
- data/lib/textmate_grammar/pattern_extensions/look_ahead_for.rb +32 -0
- data/lib/textmate_grammar/pattern_extensions/look_ahead_to_avoid.rb +31 -0
- data/lib/textmate_grammar/pattern_extensions/look_behind_for.rb +31 -0
- data/lib/textmate_grammar/pattern_extensions/look_behind_to_avoid.rb +31 -0
- data/lib/textmate_grammar/pattern_extensions/lookaround_pattern.rb +169 -0
- data/lib/textmate_grammar/pattern_extensions/match_result_of.rb +67 -0
- data/lib/textmate_grammar/pattern_extensions/maybe.rb +50 -0
- data/lib/textmate_grammar/pattern_extensions/one_of.rb +107 -0
- data/lib/textmate_grammar/pattern_extensions/one_or_more_of.rb +42 -0
- data/lib/textmate_grammar/pattern_extensions/or_pattern.rb +55 -0
- data/lib/textmate_grammar/pattern_extensions/placeholder.rb +102 -0
- data/lib/textmate_grammar/pattern_extensions/recursively_match.rb +76 -0
- data/lib/textmate_grammar/pattern_extensions/zero_or_more_of.rb +50 -0
- data/lib/textmate_grammar/pattern_variations/base_pattern.rb +870 -0
- data/lib/textmate_grammar/pattern_variations/legacy_pattern.rb +61 -0
- data/lib/textmate_grammar/pattern_variations/pattern.rb +9 -0
- data/lib/textmate_grammar/pattern_variations/pattern_range.rb +233 -0
- data/lib/textmate_grammar/pattern_variations/repeatable_pattern.rb +204 -0
- data/lib/textmate_grammar/regex_operator.rb +182 -0
- data/lib/textmate_grammar/regex_operators/alternation.rb +24 -0
- data/lib/textmate_grammar/regex_operators/concat.rb +23 -0
- data/lib/textmate_grammar/stdlib/common.rb +20 -0
- data/lib/textmate_grammar/tokens.rb +110 -0
- data/lib/textmate_grammar/transforms/add_ending.rb +25 -0
- data/lib/textmate_grammar/transforms/bailout.rb +92 -0
- data/lib/textmate_grammar/transforms/fix_repeated_tag_as.rb +75 -0
- data/lib/textmate_grammar/transforms/resolve_placeholders.rb +121 -0
- data/lib/textmate_grammar/util.rb +198 -0
- data/lib/textmate_grammar.rb +4 -0
- metadata +85 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# An optional pattern
|
4
|
+
# for some pattern `p` this is equivalent to (?:p?)
|
5
|
+
class MaybePattern < RepeatablePattern
|
6
|
+
#
|
7
|
+
# Construct a new MaybePattern
|
8
|
+
#
|
9
|
+
# @param [any] args arguments to pass to {PatternBase#initialize}
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
# @see maybe
|
13
|
+
# @see PatternBase#maybe
|
14
|
+
def initialize(*args)
|
15
|
+
# run the normal pattern
|
16
|
+
super(*args)
|
17
|
+
# add quantifying options
|
18
|
+
@at_least = 0
|
19
|
+
@at_most = 1
|
20
|
+
end
|
21
|
+
|
22
|
+
# (see Pattern#quantifying_allowed?)
|
23
|
+
# @return [false]
|
24
|
+
def quantifying_allowed?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# (see PatternBase#do_get_to_s_name)
|
29
|
+
def do_get_to_s_name(top_level)
|
30
|
+
top_level ? "maybe(" : ".maybe("
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class PatternBase
|
35
|
+
#
|
36
|
+
# Optionally match pattern
|
37
|
+
#
|
38
|
+
# @param [PatternBase,Regexp,String,Hash] pattern a pattern to optionally match
|
39
|
+
#
|
40
|
+
# @return [PatternBase] a pattern to append to
|
41
|
+
#
|
42
|
+
def maybe(pattern)
|
43
|
+
insert(MaybePattern.new(pattern))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# (see PatternBase#maybe)
|
48
|
+
def maybe(pattern)
|
49
|
+
MaybePattern.new(pattern)
|
50
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Provides alternation
|
4
|
+
# when one of the passed in patterns is accepted, this pattern is accepted
|
5
|
+
class OneOfPattern < PatternBase
|
6
|
+
# create a new OneOfPattern
|
7
|
+
# this is expects an array of patterns
|
8
|
+
|
9
|
+
#
|
10
|
+
# Create a new OneOfPattern
|
11
|
+
#
|
12
|
+
# @param [Array<PatternBase,Regexp,String>] patterns a list of patterns to match
|
13
|
+
#
|
14
|
+
def initialize(patterns, deep_clone = nil, original_arguments = nil)
|
15
|
+
if deep_clone == :deep_clone
|
16
|
+
super(patterns, deep_clone, original_arguments)
|
17
|
+
return
|
18
|
+
end
|
19
|
+
unless patterns.is_a? Array
|
20
|
+
raise <<-HEREDOC.remove_indent
|
21
|
+
oneOf() expects an array of patterns, the provided argument is not an array.
|
22
|
+
The arguments to oneOf is below
|
23
|
+
#{patterns}
|
24
|
+
HEREDOC
|
25
|
+
end
|
26
|
+
super(
|
27
|
+
match: "one of",
|
28
|
+
patterns: patterns.map do |pattern|
|
29
|
+
next pattern if pattern.is_a? PatternBase
|
30
|
+
|
31
|
+
PatternBase.new(pattern)
|
32
|
+
end
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
# (see PatternBase#do_evaluate_self)
|
37
|
+
def do_evaluate_self(groups)
|
38
|
+
patterns_strings = @arguments[:patterns].map do |pattern|
|
39
|
+
regex = pattern.evaluate(groups)
|
40
|
+
next regex if pattern.single_entity?
|
41
|
+
|
42
|
+
"(?:#{regex})"
|
43
|
+
end
|
44
|
+
|
45
|
+
return "(#{patterns_strings.join '|'})" if needs_to_capture?
|
46
|
+
|
47
|
+
"(?:#{patterns_strings.join '|'})"
|
48
|
+
end
|
49
|
+
|
50
|
+
# (see PatternBase#do_collect_self_groups)
|
51
|
+
def do_collect_self_groups(next_group)
|
52
|
+
groups = []
|
53
|
+
@arguments[:patterns].each do |pattern|
|
54
|
+
pat_groups = pattern.collect_group_attributes(next_group)
|
55
|
+
groups.concat(pat_groups)
|
56
|
+
next_group += pat_groups.length
|
57
|
+
end
|
58
|
+
groups
|
59
|
+
end
|
60
|
+
|
61
|
+
# (see PatternBase#single_entity?)
|
62
|
+
# @return [true]
|
63
|
+
def single_entity?
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
# (see PatternBase#map!)
|
68
|
+
def map!(map_includes = false, &block)
|
69
|
+
@arguments[:patterns].map! { |p| p.map!(map_includes, &block) }
|
70
|
+
@next_pattern.map!(map_includes, &block) if @next_pattern.is_a? PatternBase
|
71
|
+
map_includes!(&block) if map_includes
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# (see PatternBase#to_s)
|
76
|
+
def to_s(depth = 0, top_level = true)
|
77
|
+
indent = " " * depth
|
78
|
+
output = top_level ? "oneOf([" : ".oneOf(["
|
79
|
+
output += "\n#{indent} "
|
80
|
+
output += (@arguments[:patterns].map do |pattern|
|
81
|
+
pattern.to_s(depth + 1, true).lstrip
|
82
|
+
end).join ",\n#{indent} "
|
83
|
+
output += "\n#{indent}])"
|
84
|
+
output += @next_pattern.to_s(depth, false).lstrip if @next_pattern
|
85
|
+
output
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class PatternBase
|
90
|
+
#
|
91
|
+
# Match one of the supplied patterns
|
92
|
+
#
|
93
|
+
# @param [Array<PatternBase,Regexp,String>] patterns a list of patterns to match
|
94
|
+
#
|
95
|
+
# @return [PatternBase] a pattern to append to
|
96
|
+
#
|
97
|
+
def oneOf(patterns)
|
98
|
+
insert(OneOfPattern.new(patterns))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# (see PatternBase#oneOf)
|
104
|
+
#
|
105
|
+
def oneOf(patterns)
|
106
|
+
OneOfPattern.new(patterns)
|
107
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# An optional repeated pattern
|
4
|
+
# for some pattern `p` this is equivalent to (?:p+)
|
5
|
+
class OneOrMoreOfPattern < RepeatablePattern
|
6
|
+
def initialize(*args)
|
7
|
+
# run the normal pattern
|
8
|
+
super(*args)
|
9
|
+
# add quantifying options
|
10
|
+
@at_least = 1
|
11
|
+
@at_most = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# (see Pattern#quantifying_allowed?)
|
15
|
+
# @return [false]
|
16
|
+
def quantifying_allowed?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
# (see PatternBase#do_get_to_s_name)
|
21
|
+
def do_get_to_s_name(top_level)
|
22
|
+
top_level ? "oneOrMoreOf(" : ".oneOrMoreOf("
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class PatternBase
|
27
|
+
#
|
28
|
+
# Match pattern one or more times
|
29
|
+
#
|
30
|
+
# @param [PatternBase,Regexp,String,Hash] pattern a pattern to match
|
31
|
+
#
|
32
|
+
# @return [PatternBase] a pattern to append to
|
33
|
+
#
|
34
|
+
def oneOrMoreOf(pattern)
|
35
|
+
insert(OneOrMoreOfPattern.new(pattern))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# (see PatternBase#oneOrMoreOf)
|
40
|
+
def oneOrMoreOf(pattern)
|
41
|
+
OneOrMoreOfPattern.new(pattern)
|
42
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../regex_operators/alternation'
|
4
|
+
|
5
|
+
# Provides alternation
|
6
|
+
# Either the previous pattern or provided pattern is accepted
|
7
|
+
# @note OneOfPattern is likely just as powerful and less confusing
|
8
|
+
class OrPattern < PatternBase
|
9
|
+
#
|
10
|
+
# (see PatternBase#evaluate_operator)
|
11
|
+
#
|
12
|
+
# @return [AlternationOperator] the alternation operator
|
13
|
+
#
|
14
|
+
def evaluate_operator
|
15
|
+
AlternationOperator.new
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Raises an error to prevent use as initial type
|
20
|
+
#
|
21
|
+
# @param _ignored ignored
|
22
|
+
#
|
23
|
+
# @return [void]
|
24
|
+
#
|
25
|
+
def evaluate(*_ignored)
|
26
|
+
raise "evaluate is not implemented for OrPattern"
|
27
|
+
end
|
28
|
+
|
29
|
+
# (see PatternBase#do_get_to_s_name)
|
30
|
+
def do_get_to_s_name(top_level)
|
31
|
+
top_level ? "or(" : ".or("
|
32
|
+
end
|
33
|
+
|
34
|
+
# (see PatternBase#single_entity?)
|
35
|
+
# @return [true]
|
36
|
+
def single_entity?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class PatternBase
|
42
|
+
#
|
43
|
+
# Match either the preceding pattern chain or pattern
|
44
|
+
#
|
45
|
+
# @param [PatternBase,Regexp,String,Hash] pattern a pattern to match
|
46
|
+
# instead of the previous chain
|
47
|
+
#
|
48
|
+
# @return [PatternBase] a pattern to append to
|
49
|
+
#
|
50
|
+
def or(pattern)
|
51
|
+
insert(OrPattern.new(pattern))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# or does not have a top level option
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Implements using a pattern that has not been defined
|
5
|
+
#
|
6
|
+
class PlaceholderPattern < PatternBase
|
7
|
+
#
|
8
|
+
# Constructs a new placeholder pattern
|
9
|
+
# @overload initialize(placeholder)
|
10
|
+
# @param [Symbol] placeholder the name to replace with
|
11
|
+
#
|
12
|
+
# @overload initialize(opts, deep_clone, original)
|
13
|
+
# @param (see PatternBase#initialize)
|
14
|
+
#
|
15
|
+
def initialize(placeholder, deep_clone = nil, original_arguments = nil)
|
16
|
+
if deep_clone == :deep_clone
|
17
|
+
super(placeholder, deep_clone, original_arguments)
|
18
|
+
else
|
19
|
+
super(
|
20
|
+
match: Regexp.new("placeholder(?##{placeholder})"),
|
21
|
+
placeholder: placeholder
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# (see PatternBase#to_s)
|
27
|
+
def to_s(depth = 0, top_level = true)
|
28
|
+
return super unless @match == "placeholder"
|
29
|
+
|
30
|
+
output = top_level ? "placeholder(" : ".placeholder("
|
31
|
+
output += ":#{@arguments[:placeholder]})"
|
32
|
+
output += @next_pattern.to_s(depth, false).lstrip if @next_pattern
|
33
|
+
output
|
34
|
+
end
|
35
|
+
|
36
|
+
# (see PatternBase#to_tag)
|
37
|
+
# @note this raises a runtime error if the pattern has not been resolved
|
38
|
+
def to_tag
|
39
|
+
if @match.is_a?(String) && @match.start_with?("placeholder")
|
40
|
+
placeholder = @arguments[:placeholder]
|
41
|
+
raise "Attempting to create a tag from an unresolved placeholder `:#{placeholder}'"
|
42
|
+
end
|
43
|
+
|
44
|
+
super()
|
45
|
+
end
|
46
|
+
|
47
|
+
# (see PatternBase#evaluate)
|
48
|
+
# @note this raises a runtime error if the pattern has not been resolved
|
49
|
+
def evaluate(groups = nil)
|
50
|
+
if @match.is_a?(String) && @match.start_with?("placeholder")
|
51
|
+
raise "Attempting to evaluate an unresolved placeholder `:#{@arguments[:placeholder]}'"
|
52
|
+
end
|
53
|
+
|
54
|
+
super(groups)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Resolves the placeholder
|
59
|
+
#
|
60
|
+
# @param [Hash] repository the repository to use to resolve the placeholder
|
61
|
+
#
|
62
|
+
# @return [self]
|
63
|
+
#
|
64
|
+
def resolve!(repository)
|
65
|
+
unless repository[@arguments[:placeholder]].is_a? PatternBase
|
66
|
+
raise ":#{@arguments[:placeholder]} is not a pattern and cannot be substituted"
|
67
|
+
end
|
68
|
+
|
69
|
+
@match = repository[@arguments[:placeholder]].__deep_clone__
|
70
|
+
self
|
71
|
+
# repository[@arguments[:placeholder]].resolve(repository)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class PatternBase
|
76
|
+
#
|
77
|
+
# Match a pattern that does not exist yet
|
78
|
+
#
|
79
|
+
# @param [Symbol] placeholder the name of the pattern to match
|
80
|
+
#
|
81
|
+
# @return [PatternBase] a pattern to append to
|
82
|
+
#
|
83
|
+
def placeholder(placeholder)
|
84
|
+
insert(PlaceholderPattern.new(placeholder))
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Resolves any placeholder patterns
|
89
|
+
#
|
90
|
+
# @param [Hash] repository the repository to resolve patterns with
|
91
|
+
#
|
92
|
+
# @return [PatternBase] a copy of self with placeholders resolved
|
93
|
+
#
|
94
|
+
def resolve(repository)
|
95
|
+
__deep_clone__.map!(true) { |s| s.resolve!(repository) if s.respond_to? :resolve! }.freeze
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# (see PatternBase#placeholder)
|
100
|
+
def placeholder(placeholder)
|
101
|
+
PlaceholderPattern.new(placeholder)
|
102
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Implements subexp calls
|
5
|
+
# for some group N whose reference is "foo"
|
6
|
+
# recursivelyMatch("foo") results in the pattern /\gN/
|
7
|
+
#
|
8
|
+
class RecursivelyMatchPattern < PatternBase
|
9
|
+
def initialize(reference, deep_clone = nil, original_arguments = nil)
|
10
|
+
if reference.is_a? String
|
11
|
+
super(
|
12
|
+
match: Regexp.new("(?#[:subroutine:#{reference}:])"),
|
13
|
+
subroutine_key: reference
|
14
|
+
)
|
15
|
+
else
|
16
|
+
# most likely __deep_clone__ was called, just call the super initializer
|
17
|
+
super(reference, deep_clone, original_arguments)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# (see PatternBase#to_s)
|
22
|
+
def to_s(depth = 0, top_level = true)
|
23
|
+
output = top_level ? "recursivelyMatch(" : ".recursivelyMatch("
|
24
|
+
output += "\"#{@arguments[:subroutine_key]}\")"
|
25
|
+
output += @next_pattern.to_s(depth, false).lstrip if @next_pattern
|
26
|
+
output
|
27
|
+
end
|
28
|
+
|
29
|
+
# (see PatternBase#single_entity?)
|
30
|
+
# @return [true]
|
31
|
+
def single_entity?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
# (see PatternBase#self_scramble_references)
|
36
|
+
def self_scramble_references
|
37
|
+
scramble = lambda do |name|
|
38
|
+
return name if name.start_with?("__scrambled__")
|
39
|
+
|
40
|
+
"__scrambled__" + name
|
41
|
+
end
|
42
|
+
|
43
|
+
key = @arguments[:subroutine_key]
|
44
|
+
scrambled = scramble.call(key)
|
45
|
+
|
46
|
+
@match = @match.sub(key, scrambled)
|
47
|
+
@arguments[:subroutine_key] = scrambled
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# RecursivelyMatchPattern can cause its capture groups to be rematched
|
52
|
+
#
|
53
|
+
# @return [true] rematching is possible
|
54
|
+
#
|
55
|
+
def self_capture_group_rematch
|
56
|
+
true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class PatternBase
|
61
|
+
#
|
62
|
+
# Recursively match some outer pattern
|
63
|
+
#
|
64
|
+
# @param [String] reference a reference to an outer pattern
|
65
|
+
#
|
66
|
+
# @return [PatternBase] a PatternBase to append to
|
67
|
+
#
|
68
|
+
def recursivelyMatch(reference)
|
69
|
+
insert(RecursivelyMatchPattern.new(reference))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# (see PatternBase#recursivelyMatch)
|
74
|
+
def recursivelyMatch(reference)
|
75
|
+
RecursivelyMatchPattern.new(reference)
|
76
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# An repeated pattern
|
4
|
+
# for some pattern `p` this is equivalent to (?:p*)
|
5
|
+
class ZeroOrMoreOfPattern < RepeatablePattern
|
6
|
+
#
|
7
|
+
# Construct a new ZeroOrMoreOfPattern
|
8
|
+
#
|
9
|
+
# @param [any] args arguments to pass to {PatternBase#initialize}
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
# @see zeroOrMoreOf
|
13
|
+
# @see PatternBase#zeroOrMoreOf
|
14
|
+
def initialize(*args)
|
15
|
+
# run the normal pattern
|
16
|
+
super(*args)
|
17
|
+
# add quantifying options
|
18
|
+
@at_least = 0
|
19
|
+
@at_most = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# (see Pattern#quantifying_allowed?)
|
23
|
+
# @return [false]
|
24
|
+
def quantifying_allowed?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# (see PatternBase#do_get_to_s_name)
|
29
|
+
def do_get_to_s_name(top_level)
|
30
|
+
top_level ? "zeroOrMoreOf(" : ".zeroOrMoreOf("
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class PatternBase
|
35
|
+
#
|
36
|
+
# Match pattern zero or more times
|
37
|
+
#
|
38
|
+
# @param [PatternBase,Regexp,String,Hash] pattern a pattern to match
|
39
|
+
#
|
40
|
+
# @return [PatternBase] a pattern to append to
|
41
|
+
#
|
42
|
+
def zeroOrMoreOf(pattern)
|
43
|
+
insert(ZeroOrMoreOfPattern.new(pattern))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# (see PatternBase#zeroOrMoreOf)
|
48
|
+
def zeroOrMoreOf(pattern)
|
49
|
+
ZeroOrMoreOfPattern.new(pattern)
|
50
|
+
end
|