fear 0.9.0 → 1.2.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.
Files changed (155) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rubocop.yml +39 -0
  3. data/.github/workflows/spec.yml +42 -0
  4. data/.gitignore +0 -1
  5. data/.rubocop.yml +4 -12
  6. data/.simplecov +17 -0
  7. data/CHANGELOG.md +40 -0
  8. data/Gemfile +5 -2
  9. data/Gemfile.lock +130 -0
  10. data/LICENSE.txt +1 -1
  11. data/README.md +1293 -97
  12. data/Rakefile +369 -1
  13. data/benchmarks/README.md +1 -0
  14. data/benchmarks/dry_do_vs_fear_for.txt +11 -0
  15. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
  16. data/benchmarks/factorial.txt +16 -0
  17. data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
  18. data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
  19. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
  20. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
  21. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
  22. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
  23. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
  24. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
  25. data/examples/pattern_extracting.rb +17 -0
  26. data/examples/pattern_extracting_ruby2.7.rb +15 -0
  27. data/examples/pattern_matching_binary_tree_set.rb +101 -0
  28. data/examples/pattern_matching_number_in_words.rb +60 -0
  29. data/fear.gemspec +34 -23
  30. data/lib/dry/types/fear.rb +8 -0
  31. data/lib/dry/types/fear/option.rb +125 -0
  32. data/lib/fear.rb +65 -15
  33. data/lib/fear/await.rb +33 -0
  34. data/lib/fear/awaitable.rb +28 -0
  35. data/lib/fear/either.rb +131 -71
  36. data/lib/fear/either_api.rb +23 -0
  37. data/lib/fear/either_pattern_match.rb +53 -0
  38. data/lib/fear/empty_partial_function.rb +38 -0
  39. data/lib/fear/extractor.rb +112 -0
  40. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +10 -0
  41. data/lib/fear/extractor/any_matcher.rb +17 -0
  42. data/lib/fear/extractor/array_head_matcher.rb +36 -0
  43. data/lib/fear/extractor/array_matcher.rb +40 -0
  44. data/lib/fear/extractor/array_splat_matcher.rb +16 -0
  45. data/lib/fear/extractor/empty_list_matcher.rb +20 -0
  46. data/lib/fear/extractor/extractor_matcher.rb +44 -0
  47. data/lib/fear/extractor/grammar.rb +203 -0
  48. data/lib/fear/extractor/grammar.treetop +129 -0
  49. data/lib/fear/extractor/identifier_matcher.rb +18 -0
  50. data/lib/fear/extractor/matcher.rb +53 -0
  51. data/lib/fear/extractor/matcher/and.rb +38 -0
  52. data/lib/fear/extractor/named_array_splat_matcher.rb +17 -0
  53. data/lib/fear/extractor/pattern.rb +58 -0
  54. data/lib/fear/extractor/typed_identifier_matcher.rb +26 -0
  55. data/lib/fear/extractor/value_matcher.rb +19 -0
  56. data/lib/fear/extractor_api.rb +35 -0
  57. data/lib/fear/failure.rb +46 -14
  58. data/lib/fear/failure_pattern_match.rb +10 -0
  59. data/lib/fear/for.rb +37 -95
  60. data/lib/fear/for_api.rb +68 -0
  61. data/lib/fear/future.rb +497 -0
  62. data/lib/fear/future_api.rb +21 -0
  63. data/lib/fear/left.rb +19 -2
  64. data/lib/fear/left_pattern_match.rb +11 -0
  65. data/lib/fear/none.rb +67 -3
  66. data/lib/fear/none_pattern_match.rb +14 -0
  67. data/lib/fear/option.rb +120 -56
  68. data/lib/fear/option_api.rb +40 -0
  69. data/lib/fear/option_pattern_match.rb +48 -0
  70. data/lib/fear/partial_function.rb +176 -0
  71. data/lib/fear/partial_function/and_then.rb +50 -0
  72. data/lib/fear/partial_function/any.rb +28 -0
  73. data/lib/fear/partial_function/combined.rb +53 -0
  74. data/lib/fear/partial_function/empty.rb +10 -0
  75. data/lib/fear/partial_function/guard.rb +80 -0
  76. data/lib/fear/partial_function/guard/and.rb +38 -0
  77. data/lib/fear/partial_function/guard/and3.rb +41 -0
  78. data/lib/fear/partial_function/guard/or.rb +38 -0
  79. data/lib/fear/partial_function/lifted.rb +23 -0
  80. data/lib/fear/partial_function/or_else.rb +64 -0
  81. data/lib/fear/partial_function_class.rb +38 -0
  82. data/lib/fear/pattern_match.rb +114 -0
  83. data/lib/fear/pattern_matching_api.rb +137 -0
  84. data/lib/fear/promise.rb +95 -0
  85. data/lib/fear/right.rb +20 -2
  86. data/lib/fear/right_biased.rb +6 -14
  87. data/lib/fear/right_pattern_match.rb +11 -0
  88. data/lib/fear/some.rb +55 -3
  89. data/lib/fear/some_pattern_match.rb +13 -0
  90. data/lib/fear/struct.rb +248 -0
  91. data/lib/fear/success.rb +35 -5
  92. data/lib/fear/success_pattern_match.rb +12 -0
  93. data/lib/fear/try.rb +136 -79
  94. data/lib/fear/try_api.rb +33 -0
  95. data/lib/fear/try_pattern_match.rb +33 -0
  96. data/lib/fear/unit.rb +32 -0
  97. data/lib/fear/utils.rb +39 -14
  98. data/lib/fear/version.rb +4 -1
  99. data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
  100. data/spec/dry/types/fear/option/core_spec.rb +77 -0
  101. data/spec/dry/types/fear/option/default_spec.rb +21 -0
  102. data/spec/dry/types/fear/option/hash_spec.rb +58 -0
  103. data/spec/dry/types/fear/option/option_spec.rb +97 -0
  104. data/spec/fear/awaitable_spec.rb +17 -0
  105. data/spec/fear/done_spec.rb +8 -6
  106. data/spec/fear/either/mixin_spec.rb +17 -0
  107. data/spec/fear/either_pattern_match_spec.rb +37 -0
  108. data/spec/fear/either_pattern_matching_spec.rb +28 -0
  109. data/spec/fear/extractor/array_matcher_spec.rb +230 -0
  110. data/spec/fear/extractor/extractor_matcher_spec.rb +153 -0
  111. data/spec/fear/extractor/grammar_array_spec.rb +25 -0
  112. data/spec/fear/extractor/identified_matcher_spec.rb +49 -0
  113. data/spec/fear/extractor/identifier_matcher_spec.rb +68 -0
  114. data/spec/fear/extractor/pattern_spec.rb +34 -0
  115. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +64 -0
  116. data/spec/fear/extractor/value_matcher_number_spec.rb +79 -0
  117. data/spec/fear/extractor/value_matcher_string_spec.rb +88 -0
  118. data/spec/fear/extractor/value_matcher_symbol_spec.rb +71 -0
  119. data/spec/fear/extractor_api_spec.rb +115 -0
  120. data/spec/fear/extractor_spec.rb +61 -0
  121. data/spec/fear/failure_spec.rb +145 -45
  122. data/spec/fear/for_spec.rb +57 -67
  123. data/spec/fear/future_spec.rb +691 -0
  124. data/spec/fear/guard_spec.rb +103 -0
  125. data/spec/fear/left_spec.rb +112 -46
  126. data/spec/fear/none_spec.rb +114 -16
  127. data/spec/fear/option/mixin_spec.rb +39 -0
  128. data/spec/fear/option_pattern_match_spec.rb +35 -0
  129. data/spec/fear/option_pattern_matching_spec.rb +34 -0
  130. data/spec/fear/option_spec.rb +121 -8
  131. data/spec/fear/partial_function/empty_spec.rb +38 -0
  132. data/spec/fear/partial_function_and_then_spec.rb +147 -0
  133. data/spec/fear/partial_function_composition_spec.rb +82 -0
  134. data/spec/fear/partial_function_or_else_spec.rb +276 -0
  135. data/spec/fear/partial_function_spec.rb +239 -0
  136. data/spec/fear/pattern_match_spec.rb +93 -0
  137. data/spec/fear/pattern_matching_api_spec.rb +31 -0
  138. data/spec/fear/promise_spec.rb +96 -0
  139. data/spec/fear/right_biased/left.rb +29 -32
  140. data/spec/fear/right_biased/right.rb +51 -54
  141. data/spec/fear/right_spec.rb +109 -41
  142. data/spec/fear/some_spec.rb +80 -15
  143. data/spec/fear/success_spec.rb +99 -32
  144. data/spec/fear/try/mixin_spec.rb +19 -0
  145. data/spec/fear/try_pattern_match_spec.rb +37 -0
  146. data/spec/fear/try_pattern_matching_spec.rb +34 -0
  147. data/spec/fear/utils_spec.rb +16 -14
  148. data/spec/spec_helper.rb +13 -7
  149. data/spec/struct_pattern_matching_spec.rb +36 -0
  150. data/spec/struct_spec.rb +226 -0
  151. data/spec/support/dry_types.rb +6 -0
  152. metadata +320 -29
  153. data/.travis.yml +0 -9
  154. data/lib/fear/done.rb +0 -22
  155. data/lib/fear/for/evaluation_context.rb +0 -91
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module EitherApi
5
+ # @param value [any]
6
+ # @return [Fear::Left]
7
+ # @example
8
+ # Fear.left(42) #=> #<Fear::Left value=42>
9
+ #
10
+ def left(value)
11
+ Fear::Left.new(value)
12
+ end
13
+
14
+ # @param value [any]
15
+ # @return [Fear::Right]
16
+ # @example
17
+ # Fear.right(42) #=> #<Fear::Right value=42>
18
+ #
19
+ def right(value)
20
+ Fear::Right.new(value)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ # Either pattern matcher
5
+ #
6
+ # @example
7
+ # pattern_match =
8
+ # EitherPatternMatch.new
9
+ # .right(Integer, ->(x) { x > 2 }) { |x| x * 2 }
10
+ # .right(String) { |x| x.to_i * 2 }
11
+ # .left(String) { :err }
12
+ # .else { 'error '}
13
+ #
14
+ # pattern_match.call(42) => 'NaN'
15
+ #
16
+ # @example the same matcher may be defined using block syntax
17
+ # EitherPatternMatch.new do |m|
18
+ # m.right(Integer, ->(x) { x > 2 }) { |x| x * 2 }
19
+ # m.right(String) { |x| x.to_i * 2 }
20
+ # m.left(String) { :err }
21
+ # m.else { 'error '}
22
+ # end
23
+ #
24
+ # @note it has two optimized subclasses +Fear::LeftPatternMatch+ and +Fear::RightPatternMatch+
25
+ # @api private
26
+ class EitherPatternMatch < Fear::PatternMatch
27
+ LEFT_EXTRACTOR = :left_value.to_proc
28
+ public_constant :LEFT_EXTRACTOR
29
+
30
+ RIGHT_EXTRACTOR = :right_value.to_proc
31
+ public_constant :RIGHT_EXTRACTOR
32
+
33
+ # Match against +Fear::Right+
34
+ #
35
+ # @param conditions [<#==>]
36
+ # @return [Fear::EitherPatternMatch]
37
+ def right(*conditions, &effect)
38
+ branch = Fear.case(Fear::Right, &RIGHT_EXTRACTOR).and_then(Fear.case(*conditions, &effect))
39
+ or_else(branch)
40
+ end
41
+ alias success right
42
+
43
+ # Match against +Fear::Left+
44
+ #
45
+ # @param conditions [<#==>]
46
+ # @return [Fear::EitherPatternMatch]
47
+ def left(*conditions, &effect)
48
+ branch = Fear.case(Fear::Left, &LEFT_EXTRACTOR).and_then(Fear.case(*conditions, &effect))
49
+ or_else(branch)
50
+ end
51
+ alias failure left
52
+ end
53
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ # Use singleton version of EmptyPartialFunction -- PartialFunction::EMPTY
5
+ # @api private
6
+ class EmptyPartialFunction
7
+ include PartialFunction
8
+
9
+ def defined_at?(_)
10
+ false
11
+ end
12
+
13
+ def call(arg)
14
+ raise MatchError, "partial function not defined at: #{arg}"
15
+ end
16
+
17
+ alias === call
18
+ alias [] call
19
+
20
+ def call_or_else(arg)
21
+ yield arg
22
+ end
23
+
24
+ def or_else(other)
25
+ other
26
+ end
27
+
28
+ def and_then(*)
29
+ self
30
+ end
31
+
32
+ def to_s
33
+ "Empty partial function"
34
+ end
35
+ end
36
+
37
+ private_constant :EmptyPartialFunction
38
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "treetop"
4
+ require "fear/extractor/grammar"
5
+ Treetop.load File.expand_path("extractor/grammar.treetop", __dir__)
6
+
7
+ module Fear
8
+ # @api private
9
+ module Extractor
10
+ autoload :Pattern, "fear/extractor/pattern"
11
+ autoload :Matcher, "fear/extractor/matcher"
12
+
13
+ autoload :AnonymousArraySplatMatcher, "fear/extractor/anonymous_array_splat_matcher"
14
+ autoload :AnyMatcher, "fear/extractor/any_matcher"
15
+ autoload :ArrayHeadMatcher, "fear/extractor/array_head_matcher"
16
+ autoload :ArrayMatcher, "fear/extractor/array_matcher"
17
+ autoload :ArraySplatMatcher, "fear/extractor/array_splat_matcher"
18
+ autoload :EmptyListMatcher, "fear/extractor/empty_list_matcher"
19
+ autoload :ExtractorMatcher, "fear/extractor/extractor_matcher"
20
+ autoload :IdentifierMatcher, "fear/extractor/identifier_matcher"
21
+ autoload :NamedArraySplatMatcher, "fear/extractor/named_array_splat_matcher"
22
+ autoload :TypedIdentifierMatcher, "fear/extractor/typed_identifier_matcher"
23
+ autoload :ValueMatcher, "fear/extractor/value_matcher"
24
+
25
+ ExtractorNotFound = Class.new(Error)
26
+ public_constant :ExtractorNotFound
27
+
28
+ @mutex = Mutex.new
29
+ @registry = PartialFunction::EMPTY
30
+
31
+ EXTRACTOR_NOT_FOUND = proc do |klass|
32
+ raise ExtractorNotFound, "could not find extractor for " + klass.inspect
33
+ end
34
+ private_constant :EXTRACTOR_NOT_FOUND
35
+
36
+ class << self
37
+ # @param klass [Class, String]
38
+ # @api private
39
+ def find_extractor(klass)
40
+ @registry.call_or_else(klass, &EXTRACTOR_NOT_FOUND)
41
+ end
42
+
43
+ # Register extractor for given class
44
+ # @!method register_extractor(*names, extractor)
45
+ # @param names [<Class, String>, Class, String] name of a class. You can also pass alias for the name
46
+ # @param extractor [Proc<any => Fear::Option>] proc taking any argument and returned Option
47
+ # of extracted value('s)
48
+ #
49
+ # @example
50
+ # register_extractor(Fear::Some, Fear.case(Fear::Some) { |some| some.get }.lift)
51
+ #
52
+ # register_extractor(User, Fear.case(User) { |user|} [user.id, user.email] , )
53
+ #
54
+ # @example registering an alias. Alias should be CamelCased string
55
+ # register_extractor(Fear::Some, 'Some', Fear.case(Fear::Some) { |some| some.get }.lift)
56
+ #
57
+ # # no you can extract Fear::Some's using Some alias
58
+ # m.case(Fear['Some(value : Integer)']) { |value:| value * 2 }
59
+ #
60
+ def register_extractor(*args)
61
+ *keys, extractor = *args
62
+
63
+ @mutex.synchronize do
64
+ keys.uniq.each do |key|
65
+ @registry = BUILD_EXTRACTOR.(key, extractor).or_else(@registry)
66
+ end
67
+ end
68
+ self
69
+ end
70
+
71
+ BUILD_EXTRACTOR = proc do |key, extractor|
72
+ Fear.matcher do |m|
73
+ case key
74
+ when String
75
+ m.case(Module, ->(lookup) { lookup.to_s == key }) { extractor }
76
+ m.case(String, key) { extractor }
77
+ when Module
78
+ m.case(Module, ->(lookup) { lookup <= key }) { extractor }
79
+ m.case(String, key.to_s) { extractor }
80
+ else
81
+ m.case(key) { extractor } # may it be useful to register other types of keys? lambda?
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ # Multiple arguments extractor example
88
+ register_extractor("Date", proc do |other|
89
+ if other.class.name == "Date"
90
+ Fear.some([other.year, other.month, other.day])
91
+ else
92
+ Fear.none
93
+ end
94
+ end)
95
+ register_extractor(::Struct, Fear.case(::Struct, &:to_a).lift)
96
+ # No argument boolean extractor example
97
+ register_extractor("IsEven", proc do |int|
98
+ if int.is_a?(Integer) && int.even?
99
+ Fear.some([])
100
+ else
101
+ Fear.none
102
+ end
103
+ end)
104
+ # Single argument extractor example
105
+ register_extractor("Fear::Some", "Some", Some::EXTRACTOR)
106
+ register_extractor("Fear::None", "None", NoneClass::EXTRACTOR)
107
+ register_extractor("Fear::Right", "Right", Right::EXTRACTOR)
108
+ register_extractor("Fear::Left", "Left", Left::EXTRACTOR)
109
+ register_extractor("Fear::Success", "Success", Success::EXTRACTOR)
110
+ register_extractor("Fear::Failure", "Failure", Failure::EXTRACTOR)
111
+ end
112
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # Match against array splat, E.g. `[1, 2, *]` or `[1, 2, *_]`
6
+ #
7
+ class AnonymousArraySplatMatcher < ArraySplatMatcher
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # Always match, E.g. `_ : Integer` without capturing variable
6
+ #
7
+ class AnyMatcher < Matcher
8
+ def defined_at?(_other)
9
+ true
10
+ end
11
+
12
+ def bindings(_)
13
+ Utils::EMPTY_HASH
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # Part of recursive array matcher. Match against its head.
6
+ # @see ArrayMatcher
7
+ class ArrayHeadMatcher < Matcher
8
+ # @!attribute matcher
9
+ # @return [Matcher]
10
+ # @!attribute index
11
+ # @return [Types::Strict::Integer]
12
+
13
+ # @param other [<>]
14
+ def defined_at?(other)
15
+ if other.empty?
16
+ false
17
+ else
18
+ matcher.defined_at?(other.first)
19
+ end
20
+ end
21
+
22
+ # @param other [<>]
23
+ def bindings(other)
24
+ if other.empty?
25
+ super
26
+ else
27
+ matcher.bindings(other.first)
28
+ end
29
+ end
30
+
31
+ def failure_reason(other)
32
+ matcher.failure_reason(other.first)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # Recursive array matcher. Match against its head and tail
6
+ #
7
+ class ArrayMatcher < Matcher
8
+ # @!attribute head
9
+ # @return [ArrayHeadMatcher]
10
+ # @!attribute tail
11
+ # @return [ArrayMatcher | EmptyListMatcher]
12
+
13
+ def defined_at?(other)
14
+ if other.is_a?(Array)
15
+ head.defined_at?(other) && tail.defined_at?(other.slice(1..-1))
16
+ end
17
+ end
18
+
19
+ def bindings(other)
20
+ if head.is_a?(ArraySplatMatcher)
21
+ head.bindings(other)
22
+ else
23
+ head.bindings(other).merge(tail.bindings(other.slice(1..-1)))
24
+ end
25
+ end
26
+
27
+ def failure_reason(other)
28
+ if other.is_a?(Array)
29
+ if head.defined_at?(other)
30
+ tail.failure_reason(other.slice(1..-1))
31
+ else
32
+ head.failure_reason(other)
33
+ end
34
+ else
35
+ super
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # @abstract
6
+ class ArraySplatMatcher < Matcher
7
+ def defined_at?(_other)
8
+ true
9
+ end
10
+
11
+ def bindings(_)
12
+ Utils::EMPTY_HASH
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # Match only if array is empty
6
+ #
7
+ class EmptyListMatcher < Matcher
8
+ # @!attribute index
9
+ # @return [Types::Strict::Integer]
10
+ #
11
+ def defined_at?(other)
12
+ other.empty?
13
+ end
14
+
15
+ def bindings(_)
16
+ Utils::EMPTY_HASH
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # Match and extract pattern using registered extractor objects
6
+ # E.g. +Some(a : Integer)+
7
+ # @see Extractor.register_extractor
8
+ class ExtractorMatcher < Matcher
9
+ # @!attribute name
10
+ # @return [Types::Strict::String]
11
+ # @!attribute arguments_matcher
12
+ # @return [ArrayMatcher | EmptyListMatcher]
13
+ #
14
+
15
+ def initialize(*)
16
+ super
17
+ @extractor = Extractor.find_extractor(name)
18
+ end
19
+ attr_reader :extractor
20
+ private :extractor
21
+
22
+ def defined_at?(other)
23
+ extractor
24
+ .(other)
25
+ .map { |v| arguments_matcher.defined_at?(v) }
26
+ .get_or_else(false)
27
+ end
28
+
29
+ def call_or_else(arg)
30
+ extractor.(arg)
31
+ .map { |v| arguments_matcher.call_or_else(v) { yield arg } }
32
+ .get_or_else { yield arg }
33
+ end
34
+
35
+ def failure_reason(other)
36
+ extractor.(other).match do |m|
37
+ m.some(->(v) { arguments_matcher.defined_at?(v) }) { Fear.none }
38
+ m.some { |v| arguments_matcher.failure_reason(v) }
39
+ m.none { super }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Extractor
5
+ # This module contains AST nodes for GrammarParser
6
+ # generated by +treetop+. The sole purpose of them all is to
7
+ # generate matchers
8
+ module Grammar
9
+ class Node < Treetop::Runtime::SyntaxNode
10
+ end
11
+
12
+ class EmptyArray < Node
13
+ def to_matcher
14
+ EmptyListMatcher.new(node: self)
15
+ end
16
+ end
17
+
18
+ class ArrayLiteral < Node
19
+ def to_matcher
20
+ elements[1].to_matcher
21
+ end
22
+ end
23
+
24
+ class NonEmptyArray < Node
25
+ def to_matcher
26
+ head, tail = elements
27
+ ArrayMatcher.new(head: head.to_matcher, tail: tail.to_matcher, node: self)
28
+ end
29
+ end
30
+
31
+ class ArrayTail < Node
32
+ def to_matcher
33
+ elements[1].to_matcher
34
+ end
35
+ end
36
+
37
+ class ArrayHead < Node
38
+ def to_matcher
39
+ ArrayHeadMatcher.new(matcher: elements[1].to_matcher, node: elements[1])
40
+ end
41
+ end
42
+
43
+ class ArraySplat < Node
44
+ def to_matcher
45
+ elements[1].to_matcher
46
+ end
47
+ end
48
+
49
+ class AnonymousArraySplat < Node
50
+ def to_matcher
51
+ AnonymousArraySplatMatcher.new(node: self)
52
+ end
53
+ end
54
+
55
+ class FloatLiteral < Node
56
+ def to_matcher
57
+ ValueMatcher.new(value: value, node: self)
58
+ end
59
+
60
+ def value
61
+ Float(text_value)
62
+ end
63
+ end
64
+
65
+ class IntegerLiteral < Node
66
+ def to_matcher
67
+ ValueMatcher.new(value: value, node: self)
68
+ end
69
+
70
+ def value
71
+ Integer(text_value, 10)
72
+ end
73
+ end
74
+
75
+ class StringLiteral < Node
76
+ def to_matcher
77
+ ValueMatcher.new(value: value, node: self)
78
+ end
79
+
80
+ def value
81
+ elements[1].text_value
82
+ end
83
+ end
84
+
85
+ require "yaml"
86
+
87
+ class DoubleQuotedStringLiteral < StringLiteral
88
+ def to_matcher
89
+ ValueMatcher.new(value: value, node: self)
90
+ end
91
+
92
+ def value
93
+ YAML.safe_load(%(---\n"#{super}"\n))
94
+ end
95
+ end
96
+
97
+ class SymbolLiteral < Node
98
+ def to_matcher
99
+ ValueMatcher.new(value: value, node: self)
100
+ end
101
+
102
+ def value
103
+ elements[1].value.to_sym
104
+ end
105
+ end
106
+
107
+ class TrueLiteral < Node
108
+ def to_matcher
109
+ ValueMatcher.new(value: true, node: self)
110
+ end
111
+ end
112
+
113
+ class FalseLiteral < Node
114
+ def to_matcher
115
+ ValueMatcher.new(value: false, node: self)
116
+ end
117
+ end
118
+
119
+ class NilLiteral < Node
120
+ def to_matcher
121
+ ValueMatcher.new(value: nil, node: self)
122
+ end
123
+ end
124
+
125
+ class AnyIdentifier < Node
126
+ def to_matcher
127
+ AnyMatcher.new(node: self)
128
+ end
129
+ end
130
+
131
+ class Identifier < Node
132
+ def to_matcher
133
+ IdentifierMatcher.new(name: value, node: self)
134
+ end
135
+
136
+ def value
137
+ text_value.to_sym
138
+ end
139
+ end
140
+
141
+ class NamedArraySplat < Node
142
+ def to_matcher
143
+ NamedArraySplatMatcher.new(name: name, node: self)
144
+ end
145
+
146
+ def name
147
+ text_value[1..-1].to_sym
148
+ end
149
+ end
150
+
151
+ class TypeLiteral < Node
152
+ def to_matcher
153
+ ValueMatcher.new(value: value, node: self)
154
+ end
155
+
156
+ def value
157
+ Object.const_get(text_value)
158
+ end
159
+ end
160
+
161
+ class TypedIdentifier < Node
162
+ def to_matcher
163
+ identifier, type = elements.values_at(0, 2)
164
+ type.to_matcher.and(identifier.to_matcher)
165
+ end
166
+ end
167
+
168
+ class IdentifiedMatcher < Node
169
+ def to_matcher
170
+ identifier, matcher = elements.values_at(0, -1)
171
+ identifier.to_matcher.and(matcher.to_matcher)
172
+ end
173
+ end
174
+
175
+ class ExtractorLiteral < Node
176
+ def to_matcher
177
+ ExtractorMatcher.new(
178
+ name: extractor_name,
179
+ arguments_matcher: extractor_arguments,
180
+ node: self,
181
+ )
182
+ end
183
+
184
+ private def extractor_name
185
+ name = elements[0].text_value
186
+ if Object.const_defined?(name)
187
+ Object.const_get(name)
188
+ else
189
+ name
190
+ end
191
+ end
192
+
193
+ private def extractor_arguments
194
+ if elements[2].empty?
195
+ EmptyListMatcher.new(node: self)
196
+ else
197
+ elements[2].to_matcher
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end