yoda-language-server 0.4.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 (171) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +78 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +85 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/client/atom/main.js +27 -0
  13. data/client/vscode/.gitignore +4 -0
  14. data/client/vscode/.vscode/launch.json +28 -0
  15. data/client/vscode/.vscode/settings.json +9 -0
  16. data/client/vscode/.vscode/tasks.json +20 -0
  17. data/client/vscode/.vscodeignore +8 -0
  18. data/client/vscode/CHANGELOG.md +7 -0
  19. data/client/vscode/README.md +65 -0
  20. data/client/vscode/package-lock.json +2688 -0
  21. data/client/vscode/package.json +39 -0
  22. data/client/vscode/src/extension.ts +42 -0
  23. data/client/vscode/src/test/extension.test.ts +22 -0
  24. data/client/vscode/src/test/index.ts +22 -0
  25. data/client/vscode/tsconfig.json +16 -0
  26. data/client/vscode/vsc-extension-quickstart.md +33 -0
  27. data/exe/yoda +27 -0
  28. data/lib/yoda.rb +11 -0
  29. data/lib/yoda/evaluation.rb +9 -0
  30. data/lib/yoda/evaluation/code_completion.rb +65 -0
  31. data/lib/yoda/evaluation/code_completion/base_provider.rb +57 -0
  32. data/lib/yoda/evaluation/code_completion/const_provider.rb +90 -0
  33. data/lib/yoda/evaluation/code_completion/method_provider.rb +82 -0
  34. data/lib/yoda/evaluation/code_completion/variable_provider.rb +18 -0
  35. data/lib/yoda/evaluation/comment_completion.rb +70 -0
  36. data/lib/yoda/evaluation/comment_completion/base_provider.rb +64 -0
  37. data/lib/yoda/evaluation/comment_completion/param_provider.rb +18 -0
  38. data/lib/yoda/evaluation/comment_completion/tag_provider.rb +41 -0
  39. data/lib/yoda/evaluation/comment_completion/type_provider.rb +58 -0
  40. data/lib/yoda/evaluation/current_node_explain.rb +70 -0
  41. data/lib/yoda/evaluation/evaluator.rb +103 -0
  42. data/lib/yoda/evaluation/signature_discovery.rb +83 -0
  43. data/lib/yoda/model.rb +12 -0
  44. data/lib/yoda/model/completion_item.rb +56 -0
  45. data/lib/yoda/model/descriptions.rb +10 -0
  46. data/lib/yoda/model/descriptions/base.rb +26 -0
  47. data/lib/yoda/model/descriptions/function_description.rb +40 -0
  48. data/lib/yoda/model/descriptions/value_description.rb +33 -0
  49. data/lib/yoda/model/descriptions/word_description.rb +32 -0
  50. data/lib/yoda/model/function_signatures.rb +13 -0
  51. data/lib/yoda/model/function_signatures/base.rb +68 -0
  52. data/lib/yoda/model/function_signatures/constructor.rb +70 -0
  53. data/lib/yoda/model/function_signatures/formatter.rb +82 -0
  54. data/lib/yoda/model/function_signatures/method.rb +67 -0
  55. data/lib/yoda/model/function_signatures/overload.rb +79 -0
  56. data/lib/yoda/model/function_signatures/parameter_list.rb +108 -0
  57. data/lib/yoda/model/function_signatures/type_builder.rb +101 -0
  58. data/lib/yoda/model/node_signature.rb +28 -0
  59. data/lib/yoda/model/path.rb +96 -0
  60. data/lib/yoda/model/scoped_path.rb +44 -0
  61. data/lib/yoda/model/types.rb +84 -0
  62. data/lib/yoda/model/types/any_type.rb +32 -0
  63. data/lib/yoda/model/types/base.rb +37 -0
  64. data/lib/yoda/model/types/duck_type.rb +41 -0
  65. data/lib/yoda/model/types/function_type.rb +174 -0
  66. data/lib/yoda/model/types/generic_type.rb +66 -0
  67. data/lib/yoda/model/types/instance_type.rb +42 -0
  68. data/lib/yoda/model/types/module_type.rb +42 -0
  69. data/lib/yoda/model/types/sequence_type.rb +53 -0
  70. data/lib/yoda/model/types/union_type.rb +56 -0
  71. data/lib/yoda/model/types/unknown_type.rb +40 -0
  72. data/lib/yoda/model/types/value_type.rb +58 -0
  73. data/lib/yoda/model/values.rb +9 -0
  74. data/lib/yoda/model/values/base.rb +32 -0
  75. data/lib/yoda/model/values/instance_value.rb +65 -0
  76. data/lib/yoda/model/values/module_value.rb +72 -0
  77. data/lib/yoda/parsing.rb +15 -0
  78. data/lib/yoda/parsing/ast_traversable.rb +18 -0
  79. data/lib/yoda/parsing/comment_tokenizer.rb +59 -0
  80. data/lib/yoda/parsing/location.rb +101 -0
  81. data/lib/yoda/parsing/node_objects.rb +10 -0
  82. data/lib/yoda/parsing/node_objects/const_node.rb +52 -0
  83. data/lib/yoda/parsing/node_objects/method_definition.rb +46 -0
  84. data/lib/yoda/parsing/node_objects/namespace.rb +104 -0
  85. data/lib/yoda/parsing/node_objects/send_node.rb +72 -0
  86. data/lib/yoda/parsing/parser.rb +27 -0
  87. data/lib/yoda/parsing/query.rb +11 -0
  88. data/lib/yoda/parsing/query/current_comment_query.rb +80 -0
  89. data/lib/yoda/parsing/query/current_comment_token_query.rb +153 -0
  90. data/lib/yoda/parsing/query/current_commenting_node_query.rb +68 -0
  91. data/lib/yoda/parsing/query/current_location_node_query.rb +51 -0
  92. data/lib/yoda/parsing/query/current_node_comment_query.rb +40 -0
  93. data/lib/yoda/parsing/range.rb +41 -0
  94. data/lib/yoda/parsing/scopes.rb +15 -0
  95. data/lib/yoda/parsing/scopes/base.rb +78 -0
  96. data/lib/yoda/parsing/scopes/builder.rb +60 -0
  97. data/lib/yoda/parsing/scopes/class_definition.rb +47 -0
  98. data/lib/yoda/parsing/scopes/meta_class_definition.rb +44 -0
  99. data/lib/yoda/parsing/scopes/meta_method_definition.rb +70 -0
  100. data/lib/yoda/parsing/scopes/method_definition.rb +69 -0
  101. data/lib/yoda/parsing/scopes/module_definition.rb +36 -0
  102. data/lib/yoda/parsing/scopes/root.rb +25 -0
  103. data/lib/yoda/parsing/source_analyzer.rb +59 -0
  104. data/lib/yoda/parsing/source_cutter.rb +231 -0
  105. data/lib/yoda/parsing/type_parser.rb +141 -0
  106. data/lib/yoda/runner.rb +6 -0
  107. data/lib/yoda/runner/infer.rb +50 -0
  108. data/lib/yoda/runner/setup.rb +26 -0
  109. data/lib/yoda/server.rb +191 -0
  110. data/lib/yoda/server/client_info.rb +98 -0
  111. data/lib/yoda/server/completion_provider.rb +78 -0
  112. data/lib/yoda/server/definition_provider.rb +36 -0
  113. data/lib/yoda/server/deserializer.rb +27 -0
  114. data/lib/yoda/server/hover_provider.rb +38 -0
  115. data/lib/yoda/server/signature_provider.rb +46 -0
  116. data/lib/yoda/store.rb +13 -0
  117. data/lib/yoda/store/actions.rb +10 -0
  118. data/lib/yoda/store/actions/import_core_library.rb +30 -0
  119. data/lib/yoda/store/actions/import_gems.rb +91 -0
  120. data/lib/yoda/store/actions/read_file.rb +36 -0
  121. data/lib/yoda/store/actions/read_project_files.rb +29 -0
  122. data/lib/yoda/store/adapters.rb +14 -0
  123. data/lib/yoda/store/adapters/base.rb +58 -0
  124. data/lib/yoda/store/adapters/leveldb_adapter.rb +80 -0
  125. data/lib/yoda/store/adapters/lmdb_adapter.rb +113 -0
  126. data/lib/yoda/store/objects.rb +46 -0
  127. data/lib/yoda/store/objects/addressable.rb +25 -0
  128. data/lib/yoda/store/objects/base.rb +116 -0
  129. data/lib/yoda/store/objects/class_object.rb +51 -0
  130. data/lib/yoda/store/objects/merger.rb +94 -0
  131. data/lib/yoda/store/objects/meta_class_object.rb +41 -0
  132. data/lib/yoda/store/objects/method_object.rb +94 -0
  133. data/lib/yoda/store/objects/module_object.rb +11 -0
  134. data/lib/yoda/store/objects/namespace_object.rb +67 -0
  135. data/lib/yoda/store/objects/overload.rb +51 -0
  136. data/lib/yoda/store/objects/patch.rb +46 -0
  137. data/lib/yoda/store/objects/patch_set.rb +80 -0
  138. data/lib/yoda/store/objects/tag.rb +62 -0
  139. data/lib/yoda/store/objects/value_object.rb +45 -0
  140. data/lib/yoda/store/project.rb +159 -0
  141. data/lib/yoda/store/query.rb +12 -0
  142. data/lib/yoda/store/query/associators.rb +10 -0
  143. data/lib/yoda/store/query/associators/associate_ancestors.rb +103 -0
  144. data/lib/yoda/store/query/associators/associate_methods.rb +38 -0
  145. data/lib/yoda/store/query/base.rb +16 -0
  146. data/lib/yoda/store/query/find_constant.rb +150 -0
  147. data/lib/yoda/store/query/find_meta_class.rb +18 -0
  148. data/lib/yoda/store/query/find_method.rb +74 -0
  149. data/lib/yoda/store/query/find_signature.rb +43 -0
  150. data/lib/yoda/store/registry.rb +67 -0
  151. data/lib/yoda/store/yard_importer.rb +260 -0
  152. data/lib/yoda/typing.rb +10 -0
  153. data/lib/yoda/typing/context.rb +96 -0
  154. data/lib/yoda/typing/environment.rb +35 -0
  155. data/lib/yoda/typing/evaluator.rb +256 -0
  156. data/lib/yoda/typing/lexical_scope.rb +26 -0
  157. data/lib/yoda/typing/relation.rb +15 -0
  158. data/lib/yoda/typing/traces.rb +9 -0
  159. data/lib/yoda/typing/traces/base.rb +26 -0
  160. data/lib/yoda/typing/traces/normal.rb +22 -0
  161. data/lib/yoda/typing/traces/send.rb +26 -0
  162. data/lib/yoda/version.rb +3 -0
  163. data/lib/yoda/yard_extensions.rb +11 -0
  164. data/lib/yoda/yard_extensions/sig_directive.rb +40 -0
  165. data/lib/yoda/yard_extensions/type_tag.rb +10 -0
  166. data/package.json +76 -0
  167. data/scripts/benchmark.rb +6 -0
  168. data/scripts/build_core_index.sh +16 -0
  169. data/yarn.lock +13 -0
  170. data/yoda-language-server.gemspec +40 -0
  171. metadata +424 -0
@@ -0,0 +1,36 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Scopes
4
+ # Wrapper class for class node.
5
+ # @see https://github.com/whitequark/parser/blob/2.2/doc/AST_FORMAT.md#module
6
+ # ```
7
+ # (module (const nil :Foo) (nil))
8
+ # "module Foo; end"
9
+ # ~~~~~~ keyword
10
+ # ~~~ end
11
+ # ```
12
+ class ModuleDefinition < Base
13
+ def const_node
14
+ @const_node ||= NodeObjects::ConstNode.new(node.children[0])
15
+ end
16
+
17
+ def body_nodes
18
+ [body_node]
19
+ end
20
+
21
+ def body_node
22
+ node.children.last
23
+ end
24
+
25
+ def kind
26
+ :module
27
+ end
28
+
29
+ # @return [String]
30
+ def scope_name
31
+ const_node.to_s(parent.scope_name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ module Yoda
2
+ module Parsing
3
+ module Scopes
4
+ # Represents root namespace.
5
+ class Root < Base
6
+ def body_nodes
7
+ [node.children.last]
8
+ end
9
+
10
+ def body_node
11
+ body_nodes.first
12
+ end
13
+
14
+ def kind
15
+ :root
16
+ end
17
+
18
+ # @return [String]
19
+ def scope_name
20
+ 'Object'
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ module Yoda
2
+ module Parsing
3
+ # @deprecated
4
+ class SourceAnalyzer
5
+ include AstTraversable
6
+
7
+ # @param source [String]
8
+ # @param location [Location]
9
+ # @return [SourceAnalyzer]
10
+ def self.from_source(source, location)
11
+ new(Parser.new.parse(source), location)
12
+ end
13
+
14
+ attr_reader :ast, :location
15
+
16
+ # @param ast [::Parser::AST::Node]
17
+ # @param location [Location]
18
+ def initialize(ast, location)
19
+ @ast = ast
20
+ @location = location
21
+ end
22
+
23
+ # @return [Array<::Parser::AST::Node>]
24
+ def nodes_to_current_location_from_root
25
+ @nodes_to_current_location ||= calc_nodes_to_current_location(ast, location)
26
+ end
27
+
28
+ # @return [true, false]
29
+ def on_method?
30
+ !!current_method_node
31
+ end
32
+
33
+ # @return [::Parser::AST::Node]
34
+ def current_method_node
35
+ nodes_to_current_location_from_root.reverse.find { |node| [:def, :defs].include?(node.type) }
36
+ end
37
+
38
+ # @return [Array<::Parser::AST::Node>]
39
+ def current_namespace_nodes
40
+ nodes_to_current_location_from_root.find_all { |node| [:class, :module, :sclass].include?(node.type) }
41
+ end
42
+
43
+ # @return [Namespace]
44
+ def namespace
45
+ @namespace ||= NodeObjects::Namespace.new(self.ast)
46
+ end
47
+
48
+ # @return [NodeObjects::Namespace, nil]
49
+ def current_namespace
50
+ @current_namespace ||= namespace.calc_current_location_namespace(location)
51
+ end
52
+
53
+ # @return [NodeObjects::MethodDefition, nil]
54
+ def current_method
55
+ @current_method ||= namespace.calc_current_location_method(location)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,231 @@
1
+ module Yoda
2
+ module Parsing
3
+ class SourceCutter
4
+ class CannotRecoverError < StandardError; end
5
+
6
+ attr_reader :source, :current_location
7
+ def initialize(source, current_location)
8
+ @source = source
9
+ @current_location = current_location
10
+ end
11
+
12
+ # The last point of cut source.
13
+ # @return [Integer]
14
+ def cut_position
15
+ @cut_position ||= current_location_token_range.end_pos - 1
16
+ end
17
+
18
+ # @return [::Parser::Source::Range]
19
+ def current_location_token_range
20
+ @current_location_token_range ||= current_location_token.last.last
21
+ end
22
+
23
+ # @return [Integer]
24
+ def current_location_token_index
25
+ @current_location_token_index ||= begin
26
+ reverse_index = tokens_of_source.reverse_each.find_index { |type, (name, range)| current_location.later_than?(range) }
27
+ tokens_of_source.length - 1 - reverse_index
28
+ end
29
+ end
30
+
31
+ # @return [(Symbol, (String, ::Parser::Source::Range))]
32
+ def current_location_token
33
+ tokens_of_source[current_location_token_index]
34
+ end
35
+
36
+ # @return [Array<(Symbol, (String, ::Parser::Source::Range))>]
37
+ def tokens_of_source
38
+ @tokens_of_source ||= begin
39
+ _, _, tokens = ::Parser::CurrentRuby.new.tokenize(::Parser::Source::Buffer.new("(string)").tap { |b| b.source = source }, true)
40
+ tokens
41
+ end
42
+ end
43
+
44
+ # @return [String]
45
+ def cut_source
46
+ @cut_source ||= source.slice(0..cut_position)
47
+ end
48
+
49
+ # Returns a source that is made parsable from cut_source.
50
+ # @return [String]
51
+ def error_recovered_source
52
+ @error_recovered_source ||= recover_source
53
+ end
54
+
55
+ private
56
+
57
+ # @return [String]
58
+ def recover_source
59
+ remained_tokens = tokens_of_source.slice(0..current_location_token_index)
60
+ tokens_to_append = [:tSEMI]
61
+
62
+ while
63
+ fixing_source = FixingSource.new(cut_source, tokens_to_append)
64
+ case fixing_source.diagnostic
65
+ when :fix_line
66
+ remained_tokens, tokens_to_append = LineFixer.new.process(remained_tokens, tokens_to_append)
67
+ when :fix_block
68
+ tokens_to_append = BlockFixer.new.process(remained_tokens, tokens_to_append)
69
+ remained_tokens = []
70
+ else
71
+ return fixing_source.to_s
72
+ end
73
+ end
74
+ end
75
+
76
+ class FixingSource
77
+ attr_reader :source, :tokens_to_append
78
+ # @param source [String]
79
+ # @param tokens_to_append [Array<Symbol>]
80
+ def initialize(source, tokens_to_append)
81
+ @source = source
82
+ @tokens_to_append = tokens_to_append
83
+ end
84
+
85
+ def to_s
86
+ @to_s ||= source + "\n" + tokens_to_append.map(&token_mapper).join("\n")
87
+ end
88
+
89
+ def token_mapper
90
+ {
91
+ tSEMI: ';',
92
+ tLBRACE: '{',
93
+ tRBRACE: '}',
94
+ tLPAREN: '(',
95
+ tRPAREN: ')',
96
+ kEND: 'end',
97
+ kNIL: 'nil',
98
+ dummy_constant: 'DUMMY_CONSTANT',
99
+ dummy_method: 'dummy_method',
100
+ }
101
+ end
102
+
103
+ # @return [Symbol, nil]
104
+ def diagnostic
105
+ begin
106
+ ::Parser::CurrentRuby.parse(to_s)
107
+ nil
108
+ rescue ::Parser::SyntaxError => ex
109
+ fail CannotRecoverError, "Cannot recover: #{ex.diagnostic.render}" unless ex.diagnostic.reason == :unexpected_token
110
+ fail CannotRecoverError, "Cannot recover: #{ex.diagnostic.render}" unless ex.diagnostic.location.end_pos == to_s.length
111
+ case ex.diagnostic.arguments[:token]
112
+ when 'tSEMI'
113
+ :fix_line
114
+ when '$end'
115
+ :fix_block
116
+ else
117
+ fail CannotRecoverError, "Cannot recover: #{ex.diagnostic.render}"
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ class LineFixer
124
+ # @param remained_tokens [Array<(Symbol, (String, ::Parser::Source::Range))>]
125
+ # @param tokens_to_add [Array<Symbol>]
126
+ def process(remained_tokens, tokens_to_add)
127
+ if tokens_to_add.first == :tSEMI
128
+ token = fix_operator(remained_tokens)
129
+ return [remained_tokens, [token] + tokens_to_add] if token
130
+ end
131
+
132
+ fix_inline_block(remained_tokens, tokens_to_add)
133
+ end
134
+
135
+ # @return [Symbol, nil]
136
+ def fix_operator(remained_tokens)
137
+ case remained_tokens.last.first
138
+ when :tEQL, :tAMPER2, :tPIPE, :tBANG, :tCARET, :tPLUS, :tMINUS, :tSTAR2, :tDIVIDE, :tPERCENT, :tTILDE, :tCOMMA, :tDOT2, :tDOT3, :tCOLON,
139
+ :tANDOP, :tOROP, :tUMINUS, :tUPLUS, :tTILDE, :tPOW, :tMATCH, :tNMATCH, :tEQ, :tNEQ, :tGT, :tRSHFT, :tGEQ, :tLT, :tLSHFT, :tLEQ, :tASSOC, :tEQQ, :tCMP, :tBANG, :tANDDOT
140
+ :kNIL
141
+ when :tCOLON2, :tCOLON3
142
+ :dummy_constant
143
+ when :tDOT
144
+ :dummy_method
145
+ else
146
+ nil
147
+ end
148
+ end
149
+
150
+ def fix_inline_block(remained_tokens, tokens_to_add)
151
+ stack = []
152
+
153
+ remained_tokens.each_with_index.reverse_each do |(token, _), i|
154
+ token_to_add =
155
+ case token
156
+ when :tSTRING_BEG
157
+ reduce(stack, :tSTRING_END)
158
+ when :tSTRING_END
159
+ reduce(stack, :tSTRING_END)
160
+ when :tLBRACE
161
+ reduce(stack, :tRBRACE)
162
+ when :tRBRACE
163
+ next stack.push(:tRBRACE)
164
+ when :tLPAREN, :tLPAREN2
165
+ reduce(stack, :tRPAREN)
166
+ when :tRPAREN, :tRPAREN2
167
+ next stack.push(:tRPAREN)
168
+ else
169
+ nil
170
+ end
171
+ return [remained_tokens.slice(0...i), tokens_to_add.slice(0..-2) + [token_to_add, tokens_to_add.last]] if token_to_add
172
+ end
173
+
174
+ fail CannotRecoverError, "Cannot fix inline error"
175
+ end
176
+
177
+ def reduce(stack, expected)
178
+ if stack.empty?
179
+ expected
180
+ else
181
+ if stack.last == expected
182
+ stack.pop
183
+ else
184
+ fail CannotRecoverError, "Block mismatch in existing source"
185
+ end
186
+ nil
187
+ end
188
+ end
189
+ end
190
+
191
+ class BlockFixer
192
+ def process(remained_tokens, tokens_to_add)
193
+ fail CannotRecoverError, "Cannot resolve block error" if remained_tokens.empty?
194
+ stack = []
195
+ tokens_to_add = tokens_to_add.dup
196
+
197
+ remained_tokens.each_with_index.reverse_each do |(token, _), i|
198
+ case token
199
+ when :kIF, :kUNLESS, :kWHILE, :kUNTIL, :kCLASS, :kFOR, :kBEGIN, :kCASE, :kCLASS, :kMODULE, :kDEF
200
+ reduce(stack, tokens_to_add, :kEND)
201
+ when :kDO
202
+ next if i > 0 && [:kWHILE, :kUNTIL, :kFOR].include?(remained_tokens[i].first)
203
+ reduce(stack, tokens_to_add, :kEND)
204
+ when :kEND
205
+ stack.push(:kEND)
206
+ when :tLBRACE, :tLCURLY
207
+ reduce(stack, tokens_to_add, :tRBRACE)
208
+ when :tRBRACE, :tRCURLY
209
+ stack.push(:tRBRACE)
210
+ end
211
+ end
212
+
213
+ fail CannotRecoverError, "Block mismatch in existing source" unless stack.empty?
214
+ tokens_to_add
215
+ end
216
+
217
+ def reduce(stack, tokens_to_add, expected)
218
+ if stack.empty?
219
+ tokens_to_add.push(expected)
220
+ else
221
+ if stack.last == expected
222
+ stack.pop
223
+ else
224
+ fail CannotRecoverError, "Block mismatch in existing source"
225
+ end
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,141 @@
1
+ require 'parslet'
2
+
3
+ module Yoda
4
+ module Parsing
5
+ class TypeParser
6
+ # @return [Model::Types::Base]
7
+ def parse(str)
8
+ Generator.new.apply(Parser.new.parse(str))
9
+ end
10
+
11
+ # @return [Model::Types::Base, nil]
12
+ def safe_parse(str)
13
+ parse(str)
14
+ rescue Parslet::ParseFailed => failure
15
+ nil
16
+ end
17
+
18
+ class Parser < Parslet::Parser
19
+ rule(:space) { match('\s').repeat(1) }
20
+ rule(:space?) { space.maybe }
21
+
22
+ rule(:special_value) { str('void') | str('nil') | str('true') | str('false') }
23
+ rule(:any_type) { str('any').as(:any_type) }
24
+ rule(:keyword) { match['a-z'] >> match['a-zA-Z0-9_'].repeat(1) }
25
+ rule(:generic_name) { constant_name }
26
+ rule(:constant_name) { match['A-Z'] >> match['a-zA-Z0-9_'].repeat }
27
+ rule(:constant_full_name) { str('::').maybe >> (constant_name >> str('::')).repeat >> constant_name }
28
+
29
+ rule(:required_param) { type.as(:required) }
30
+ rule(:optional_param) { str('?') >> space? >> type.as(:optional) }
31
+ rule(:rest_param) { str('*') >> space? >> type.as(:rest) }
32
+ rule(:required_keyword_param) { keyword.as(:required_keyword) >> str(':') >> space? >> type.as(:type_for_keyword) }
33
+ rule(:optional_keyword_param) { keyword.as(:optinal_keyword) >> str('?:') >> space? >> type.as(:type_for_keyword) }
34
+ rule(:keyword_rest_param) { str('**') >> space? >> type.as(:keyword_rest) }
35
+ rule(:block_param) { str('&') >> space? >> type.as(:block) }
36
+
37
+ rule(:context) { str('(') >> space? >> type >> space? >> str(')') }
38
+ rule(:param) { keyword_rest_param | block_param | optional_param | rest_param | required_keyword_param | optional_keyword_param | required_param }
39
+ rule(:params_inner) { param >> (space? >> str(',') >> space? >> param).repeat }
40
+ rule(:params) { str('(') >> space? >> params_inner >> space? >> str(')') }
41
+ rule(:generic_abs) { str('<') >> space? >> generic_name >> (space? >> str(',') >> space? >> generic_name).repeat >> space? >> str('>') }
42
+ rule(:function_type_inner) { params.as(:params) >> space? >> str('->') >> space? >> type.as(:return_type) }
43
+ rule(:function_type_inner_with_context) { context.maybe.as(:context) >> space? >> function_type_inner }
44
+ rule(:function_type) { generic_abs.maybe.as(:generic_abs) >> space? >> (function_type_inner | function_type_inner_with_context).as(:generic_abs_body) }
45
+
46
+ rule(:self_instance_type) { str('self') >> space? >> str('.') >> space? >> str('instance') }
47
+ rule(:self_class_type) { str('self') >> space? >> str('.') >> space? >> str('class') }
48
+ rule(:self_type) { str('self') }
49
+
50
+ rule(:instance_type) { constant_full_name.as(:instance_type) }
51
+ rule(:module_type) { constant_full_name.as(:module_type) >> space? >> str('.') >> space? >> (str('class') | str('module')) }
52
+ rule(:value_type) { special_value.as(:value_type) }
53
+ rule(:sequence_type) { (str('[') >> space? >> type >> (space? >> str(',') >> space? >> type).repeat >> space? >> str(']')).as(:sequence_type) }
54
+
55
+ rule(:type_with_paren) { str('(') >> type >> str(')') }
56
+ rule(:simple_type) { function_type | type_with_paren | sequence_type | value_type | any_type | module_type | instance_type }
57
+
58
+ rule(:generic_type_params) { str('<') >> space? >> type >> (space? >> str(',') >> space? >> type).repeat >> space? >> str('>') }
59
+ rule(:generic_type) { simple_type.as(:base_type) >> (space? >> generic_type_params.as(:generic_type_params)).maybe }
60
+ rule(:type_without_union) { generic_type }
61
+ rule(:union_type) { (type_without_union >> (space? >> str('|') >> space? >> type).repeat(1)).as(:union_type) }
62
+
63
+ rule(:type) { union_type | generic_type }
64
+
65
+ rule(:base) { type }
66
+ root :base
67
+ end
68
+
69
+ class Generator < Parslet::Transform
70
+ rule(required: simple(:type)) { Param.new(:required, type) }
71
+ rule(optional: simple(:type)) { Param.new(:optional, type) }
72
+ rule(rest: simple(:type)) { Param.new(:rest, type) }
73
+ rule(required_keyword: simple(:keyword), type_for_keyword: simple(:type)) { Param.new(:keyword_required, type, keyword.to_s) }
74
+ rule(optional_keyword: simple(:keyword), type_for_keyword: simple(:type)) { Param.new(:keyword_optional, type, keyword.to_s) }
75
+ rule(keyword_rest: simple(:type)) { Param.new(:keyword_rest, type) }
76
+ rule(block: simple(:type)) { Param.new(:block, type) }
77
+
78
+ rule(context: simple(:context), params: sequence(:param_types), return_type: simple(:return_type)) { create_function_type(context, param_types, return_type) }
79
+ rule(context: simple(:context), params: simple(:param_type), return_type: simple(:return_type)) { create_function_type(context, [param_type], return_type) }
80
+ rule(params: sequence(:param_types), return_type: simple(:return_type)) { Generator.create_function_type(nil, param_types, return_type) }
81
+ rule(params: simple(:param_type), return_type: simple(:return_type)) { Generator.create_function_type(nil, [param_type], return_type) }
82
+
83
+ rule(instance_type: simple(:class_name)) { Model::Types::InstanceType.new(class_name.to_s) }
84
+ rule(module_type: simple(:module_name)) { Model::Types::ModuleType.new(module_name.to_s) }
85
+ rule(value_type: simple(:value_name)) { Model::Types::ValueType.new(value_name.to_s) }
86
+ rule(any_type: simple(:any)) { Model::Types::AnyType.new }
87
+
88
+ rule(sequence_type: simple(:type)) { Model::Types::SequenceType.new(Model::Types::InstanceType.new('::Array'), [type]) }
89
+ rule(sequence_type: sequence(:types)) { Model::Types::SequenceType.new(Model::Types::InstanceType.new('::Array'), types) }
90
+
91
+ rule(generic_abs: simple(:generic_abs), generic_abs_body: simple(:type)) { type }
92
+
93
+ rule(base_type: simple(:base_type)) { base_type }
94
+ rule(base_type: simple(:base_type), generic_type_params: simple(:type_param)) { Model::Types::GenericType.new(base_type, [type_param]) }
95
+ rule(base_type: simple(:base_type), generic_type_params: sequence(:type_params)) { Model::Types::GenericType.new(base_type, type_params) }
96
+ rule(union_type: sequence(:types)) { Model::Types::UnionType.new(types) }
97
+
98
+ def self.create_function_type(context, param_types, return_type)
99
+ func_options = param_types.each_with_object({ context: context, return_type: return_type }).with_index do |(param, func_options), index|
100
+ case param.kind
101
+ when :required
102
+ if func_options[:rest_parameter]
103
+ func_options[:post_parameters] ||= []
104
+ func_options[:post_parameters].push(param.type)
105
+ else
106
+ func_options[:required_parameters] ||= []
107
+ func_options[:required_parameters].push(param.type)
108
+ end
109
+ when :optional
110
+ func_options[:optional_parameters] ||= []
111
+ func_options[:optional_parameters].push(param.type)
112
+ when :rest
113
+ func_options[:rest_parameter] = param.type
114
+ when :required_keyword
115
+ func_options[:required_keyword_parameters] ||= []
116
+ func_options[:required_keyword_parameters].push(param.keyword, param.type)
117
+ when :optional_keyword
118
+ func_options[:optional_keyword_parameters] ||= []
119
+ func_options[:optional_keyword_parameters].push(param.keyword, param.type)
120
+ when :keyword_rest
121
+ func_options[:keyword_rest_parameter] = param.type
122
+ when :block
123
+ func_options[:block_parameter] = param.type
124
+ end
125
+ end
126
+
127
+ Model::Types::FunctionType.new(func_options)
128
+ end
129
+
130
+ class Param
131
+ attr_reader :kind, :type, :keyword
132
+ def initialize(kind, type, keyword = nil)
133
+ @kind = kind
134
+ @keyword = keyword
135
+ @type = type
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end