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,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