textmate_grammar 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|