ruby_grammar_builder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/lib/textmate_grammar/generated/grammar.rb +32 -0
  4. data/lib/textmate_grammar/generated/rule.rb +144 -0
  5. data/lib/textmate_grammar/grammar.rb +670 -0
  6. data/lib/textmate_grammar/grammar_plugin.rb +189 -0
  7. data/lib/textmate_grammar/import_patterns.rb +14 -0
  8. data/lib/textmate_grammar/linters/flat_includes.rb +32 -0
  9. data/lib/textmate_grammar/linters/includes_then_tag_as.rb +48 -0
  10. data/lib/textmate_grammar/linters/standard_naming.rb +226 -0
  11. data/lib/textmate_grammar/linters/start_match_empty.rb +49 -0
  12. data/lib/textmate_grammar/linters/tests.rb +19 -0
  13. data/lib/textmate_grammar/linters/unused_unresolved.rb +9 -0
  14. data/lib/textmate_grammar/pattern_extensions/look_ahead_for.rb +32 -0
  15. data/lib/textmate_grammar/pattern_extensions/look_ahead_to_avoid.rb +31 -0
  16. data/lib/textmate_grammar/pattern_extensions/look_behind_for.rb +31 -0
  17. data/lib/textmate_grammar/pattern_extensions/look_behind_to_avoid.rb +31 -0
  18. data/lib/textmate_grammar/pattern_extensions/lookaround_pattern.rb +169 -0
  19. data/lib/textmate_grammar/pattern_extensions/match_result_of.rb +67 -0
  20. data/lib/textmate_grammar/pattern_extensions/maybe.rb +50 -0
  21. data/lib/textmate_grammar/pattern_extensions/one_of.rb +107 -0
  22. data/lib/textmate_grammar/pattern_extensions/one_or_more_of.rb +42 -0
  23. data/lib/textmate_grammar/pattern_extensions/or_pattern.rb +55 -0
  24. data/lib/textmate_grammar/pattern_extensions/placeholder.rb +102 -0
  25. data/lib/textmate_grammar/pattern_extensions/recursively_match.rb +76 -0
  26. data/lib/textmate_grammar/pattern_extensions/zero_or_more_of.rb +50 -0
  27. data/lib/textmate_grammar/pattern_variations/base_pattern.rb +870 -0
  28. data/lib/textmate_grammar/pattern_variations/legacy_pattern.rb +61 -0
  29. data/lib/textmate_grammar/pattern_variations/pattern.rb +9 -0
  30. data/lib/textmate_grammar/pattern_variations/pattern_range.rb +233 -0
  31. data/lib/textmate_grammar/pattern_variations/repeatable_pattern.rb +204 -0
  32. data/lib/textmate_grammar/regex_operator.rb +182 -0
  33. data/lib/textmate_grammar/regex_operators/alternation.rb +24 -0
  34. data/lib/textmate_grammar/regex_operators/concat.rb +23 -0
  35. data/lib/textmate_grammar/stdlib/common.rb +20 -0
  36. data/lib/textmate_grammar/tokens.rb +110 -0
  37. data/lib/textmate_grammar/transforms/add_ending.rb +25 -0
  38. data/lib/textmate_grammar/transforms/bailout.rb +92 -0
  39. data/lib/textmate_grammar/transforms/fix_repeated_tag_as.rb +75 -0
  40. data/lib/textmate_grammar/transforms/resolve_placeholders.rb +121 -0
  41. data/lib/textmate_grammar/util.rb +198 -0
  42. data/lib/textmate_grammar.rb +4 -0
  43. metadata +85 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby_grammar_builder/util'
4
+
5
+ #
6
+ # Warns when a PatternRange has a start_pattern that matches the empty string
7
+ #
8
+ class StartMatchEmpty < GrammarLinter
9
+ #
10
+ # (see GrammarLinter#pre_lint)
11
+ #
12
+ def pre_lint(pattern, options)
13
+ return true unless pattern.is_a? PatternRange
14
+
15
+ regexp = with_no_warnings do
16
+ Regexp.new(pattern.start_pattern.evaluate.gsub("\\G", '\uFFFF'))
17
+ end
18
+ if "" =~ regexp and !options[:zeroLengthStart?]
19
+ puts "Warning: #{pattern.start_pattern.evaluate}"
20
+ puts "matches the zero length string (\"\").\n\n"
21
+ puts "This means that the patternRange always matches"
22
+ puts "You can disable this warning by setting :zeroLengthStart? to true."
23
+ puts "The pattern is:\n#{pattern}"
24
+ end
25
+ true # return true for warnings
26
+ end
27
+
28
+ #
29
+ # Contributes the option :zeroLengthStart?
30
+ #
31
+ # :zeroLengthStart? disables this linter
32
+ #
33
+ # @return (see GrammarPlugin.options)
34
+ #
35
+ def self.options
36
+ [:zeroLengthStart?]
37
+ end
38
+
39
+ #
40
+ # Displays the state of the options
41
+ #
42
+ # @return (see GrammarPlugin.display_options)
43
+ #
44
+ def self.display_options(indent, options)
45
+ ",\n#{indent}zeroLengthStart?: #{options[:zeroLengthStart?]}"
46
+ end
47
+ end
48
+
49
+ Grammar.register_linter(StartMatchEmpty.new)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Runs the unit tests on each pattern
5
+ #
6
+ class RunPatternTests < GrammarLinter
7
+ #
8
+ # Runs the unit tests on each pattern
9
+ #
10
+ # @return [Boolean] the result of the unit tests
11
+ #
12
+ def pre_lint(pattern, _options)
13
+ return true unless pattern.is_a? PatternBase
14
+
15
+ pattern.run_tests
16
+ end
17
+ end
18
+
19
+ Grammar.register_linter(RunPatternTests.new)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UnusedUnresolvedLinter < GrammarLinter
4
+ def post_lint(grammar_hash)
5
+ true
6
+ end
7
+ end
8
+
9
+ Grammar.register_linter(UnusedUnresolvedLinter.new)
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./lookaround_pattern.rb"
4
+
5
+
6
+ class PatternBase
7
+ #
8
+ # Equivalent to lookAround with type set to :lookAheadFor
9
+ #
10
+ # @param (see lookAround)
11
+ #
12
+ # @return (see lookAround)
13
+ #
14
+ def lookAheadFor(pattern)
15
+ if pattern.is_a? Hash
16
+ pattern[:type] = :lookAheadFor
17
+ else
18
+ pattern = {match: pattern, type: :lookAheadFor}
19
+ end
20
+ lookAround(pattern)
21
+ end
22
+ end
23
+
24
+ # (see PatternBase#lookAheadFor)
25
+ def lookAheadFor(pattern)
26
+ if pattern.is_a? Hash
27
+ pattern[:type] = :lookAheadFor
28
+ else
29
+ pattern = {match: pattern, type: :lookAheadFor}
30
+ end
31
+ lookAround(pattern)
32
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./lookaround_pattern.rb"
4
+
5
+ class PatternBase
6
+ #
7
+ # Equivalent to lookAround with type set to :lookAheadToAvoid
8
+ #
9
+ # @param (see lookAround)
10
+ #
11
+ # @return (see lookAround)
12
+ #
13
+ def lookAheadToAvoid(pattern)
14
+ if pattern.is_a? Hash
15
+ pattern[:type] = :lookAheadToAvoid
16
+ else
17
+ pattern = {match: pattern, type: :lookAheadToAvoid}
18
+ end
19
+ lookAround(pattern)
20
+ end
21
+ end
22
+
23
+ # (see PatternBase#lookAheadToAvoid)
24
+ def lookAheadToAvoid(pattern)
25
+ if pattern.is_a? Hash
26
+ pattern[:type] = :lookAheadToAvoid
27
+ else
28
+ pattern = {match: pattern, type: :lookAheadToAvoid}
29
+ end
30
+ lookAround(pattern)
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./lookaround_pattern.rb"
4
+
5
+ class PatternBase
6
+ #
7
+ # Equivalent to lookAround with type set to :lookBehindFor
8
+ #
9
+ # @param (see lookAround)
10
+ #
11
+ # @return (see lookAround)
12
+ #
13
+ def lookBehindFor(pattern)
14
+ if pattern.is_a? Hash
15
+ pattern[:type] = :lookBehindFor
16
+ else
17
+ pattern = {match: pattern, type: :lookBehindFor}
18
+ end
19
+ lookAround(pattern)
20
+ end
21
+ end
22
+
23
+ # (see PatternBase#lookBehindFor)
24
+ def lookBehindFor(pattern)
25
+ if pattern.is_a? Hash
26
+ pattern[:type] = :lookBehindFor
27
+ else
28
+ pattern = {match: pattern, type: :lookBehindFor}
29
+ end
30
+ lookAround(pattern)
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./lookaround_pattern.rb"
4
+
5
+ class PatternBase
6
+ #
7
+ # Equivalent to lookAround with type set to :lookBehindToAvoid
8
+ #
9
+ # @param (see lookAround)
10
+ #
11
+ # @return (see lookAround)
12
+ #
13
+ def lookBehindToAvoid(pattern)
14
+ if pattern.is_a? Hash
15
+ pattern[:type] = :lookBehindToAvoid
16
+ else
17
+ pattern = {match: pattern, type: :lookBehindToAvoid}
18
+ end
19
+ lookAround(pattern)
20
+ end
21
+ end
22
+
23
+ # (see PatternBase#lookBehindToAvoid)
24
+ def lookBehindToAvoid(pattern)
25
+ if pattern.is_a? Hash
26
+ pattern[:type] = :lookBehindToAvoid
27
+ else
28
+ pattern = {match: pattern, type: :lookBehindToAvoid}
29
+ end
30
+ lookAround(pattern)
31
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Implements lookarounds
5
+ # for some pattern p this is equivalent to one of /(?=p)/, /(?!p)/, /(?<p)/, /(?<!p)/
6
+ # depending on the type
7
+ #
8
+ class LookAroundPattern < PatternBase
9
+ # (see PatternBase#do_evaluate_self)
10
+ def do_evaluate_self(groups)
11
+ self_regex = @match
12
+ self_regex = @match.evaluate(groups) if @match.is_a? PatternBase
13
+
14
+ case @arguments[:type]
15
+ when :lookAheadFor then self_regex = "(?=#{self_regex})"
16
+ when :lookAheadToAvoid then self_regex = "(?!#{self_regex})"
17
+ when :lookBehindFor then self_regex = "(?<=#{self_regex})"
18
+ when :lookBehindToAvoid then self_regex = "(?<!#{self_regex})"
19
+ end
20
+
21
+ if needs_to_capture?
22
+ raise "You cannot capture a lookAround\nconsider capturing the pattern inside"
23
+ end
24
+
25
+ self_regex
26
+ end
27
+
28
+ # (see PatternBase#do_get_to_s_name)
29
+ def do_get_to_s_name(top_level)
30
+ top_level ? "lookAround(" : ".lookAround("
31
+ end
32
+
33
+ # (see PatternBase#do_add_attributes)
34
+ def do_add_attributes(indent)
35
+ ",\n#{indent} type: :#{@arguments[:type]}"
36
+ end
37
+
38
+ # (see PatternBase#single_entity?)
39
+ # @return [true]
40
+ def single_entity?
41
+ true
42
+ end
43
+ end
44
+
45
+ class PatternBase
46
+ #
47
+ # Looks around for the pattern
48
+ #
49
+ # @param [Hash] pattern pattern constructor
50
+ # option [Symbol] :type the look-around type
51
+ # can be one of :lookAheadFor, :lookAheadToAvoid, :lookBehindFor, :lookBehindToAvoid
52
+ #
53
+ # @return [PatternBase] a pattern to append to
54
+ #
55
+ def lookAround(pattern)
56
+ insert(LookAroundPattern.new(pattern))
57
+ end
58
+
59
+ #
60
+ # Equivalent to lookAround with type set to :lookBehindToAvoid
61
+ #
62
+ # @param (see lookAround)
63
+ #
64
+ # @return (see lookAround)
65
+ #
66
+ def lookBehindToAvoid(pattern)
67
+ if pattern.is_a? Hash
68
+ pattern[:type] = :lookBehindToAvoid
69
+ else
70
+ pattern = {match: pattern, type: :lookBehindToAvoid}
71
+ end
72
+ lookAround(pattern)
73
+ end
74
+
75
+ #
76
+ # Equivalent to lookAround with type set to :lookBehindFor
77
+ #
78
+ # @param (see lookAround)
79
+ #
80
+ # @return (see lookAround)
81
+ #
82
+ def lookBehindFor(pattern)
83
+ if pattern.is_a? Hash
84
+ pattern[:type] = :lookBehindFor
85
+ else
86
+ pattern = {match: pattern, type: :lookBehindFor}
87
+ end
88
+ lookAround(pattern)
89
+ end
90
+
91
+ #
92
+ # Equivalent to lookAround with type set to :lookAheadToAvoid
93
+ #
94
+ # @param (see lookAround)
95
+ #
96
+ # @return (see lookAround)
97
+ #
98
+ def lookAheadToAvoid(pattern)
99
+ if pattern.is_a? Hash
100
+ pattern[:type] = :lookAheadToAvoid
101
+ else
102
+ pattern = {match: pattern, type: :lookAheadToAvoid}
103
+ end
104
+ lookAround(pattern)
105
+ end
106
+
107
+ #
108
+ # Equivalent to lookAround with type set to :lookAheadFor
109
+ #
110
+ # @param (see lookAround)
111
+ #
112
+ # @return (see lookAround)
113
+ #
114
+ def lookAheadFor(pattern)
115
+ if pattern.is_a? Hash
116
+ pattern[:type] = :lookAheadFor
117
+ else
118
+ pattern = {match: pattern, type: :lookAheadFor}
119
+ end
120
+ lookAround(pattern)
121
+ end
122
+ end
123
+
124
+ # (see PatternBase#lookAround)
125
+ def lookAround(pattern)
126
+ LookAroundPattern.new(pattern)
127
+ end
128
+
129
+ # TODO: eliminate this code duplication
130
+
131
+ # (see PatternBase#lookBehindToAvoid)
132
+ def lookBehindToAvoid(pattern)
133
+ if pattern.is_a? Hash
134
+ pattern[:type] = :lookBehindToAvoid
135
+ else
136
+ pattern = {match: pattern, type: :lookBehindToAvoid}
137
+ end
138
+ lookAround(pattern)
139
+ end
140
+
141
+ # (see PatternBase#lookBehindFor)
142
+ def lookBehindFor(pattern)
143
+ if pattern.is_a? Hash
144
+ pattern[:type] = :lookBehindFor
145
+ else
146
+ pattern = {match: pattern, type: :lookBehindFor}
147
+ end
148
+ lookAround(pattern)
149
+ end
150
+
151
+ # (see PatternBase#lookAheadToAvoid)
152
+ def lookAheadToAvoid(pattern)
153
+ if pattern.is_a? Hash
154
+ pattern[:type] = :lookAheadToAvoid
155
+ else
156
+ pattern = {match: pattern, type: :lookAheadToAvoid}
157
+ end
158
+ lookAround(pattern)
159
+ end
160
+
161
+ # (see PatternBase#lookAheadFor)
162
+ def lookAheadFor(pattern)
163
+ if pattern.is_a? Hash
164
+ pattern[:type] = :lookAheadFor
165
+ else
166
+ pattern = {match: pattern, type: :lookAheadFor}
167
+ end
168
+ lookAround(pattern)
169
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Implements back references
5
+ # for some group N whose reference is "foo"
6
+ # matchResultOf("foo") results in the pattern /\N/
7
+ #
8
+ class MatchResultOfPattern < PatternBase
9
+ def initialize(reference, deep_clone = nil, original_arguments = nil)
10
+ if reference.is_a? String
11
+ super(
12
+ match: Regexp.new("(?#[:backreference:#{reference}:])"),
13
+ backreference_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 ? "matchResultOf(" : ".matchResultOf("
24
+ output += "\"#{@arguments[:backreference_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
+ end
50
+
51
+ class PatternBase
52
+ #
53
+ # Match the result of some other pattern
54
+ #
55
+ # @param [String] reference a reference to match the result of
56
+ #
57
+ # @return [PatternBase] a pattern to append to
58
+ #
59
+ def matchResultOf(reference)
60
+ insert(MatchResultOfPattern.new(reference))
61
+ end
62
+ end
63
+
64
+ # (see PatternBase#matchResultOf)
65
+ def matchResultOf(reference)
66
+ MatchResultOfPattern.new(reference)
67
+ end