gloss 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +3 -0
  3. data/.github/workflows/crystal_specs.yml +26 -0
  4. data/.github/workflows/ruby_specs.yml +33 -0
  5. data/.gitignore +2 -1
  6. data/.rspec +1 -0
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +26 -34
  9. data/LICENSE +21 -0
  10. data/README.md +59 -7
  11. data/Rakefile +4 -0
  12. data/exe/gloss +15 -1
  13. data/ext/gloss/Makefile +27 -5
  14. data/ext/gloss/extconf.rb +3 -25
  15. data/ext/gloss/{src/lib → lib}/cr_ruby.cr +0 -0
  16. data/ext/gloss/lib/rbs_types.cr +3 -0
  17. data/ext/gloss/spec/parser_spec.cr +124 -0
  18. data/ext/gloss/spec/spec_helper.cr +2 -0
  19. data/ext/gloss/src/cr_ast.cr +129 -31
  20. data/ext/gloss/src/gloss.cr +12 -18
  21. data/ext/gloss/src/lexer.cr +59 -1
  22. data/ext/gloss/src/parser.cr +548 -254
  23. data/ext/gloss/src/rb_ast.cr +153 -27
  24. data/gloss.gemspec +1 -0
  25. data/lib/gloss.rb +4 -1
  26. data/lib/gloss/builder.rb +607 -409
  27. data/lib/gloss/cli.rb +64 -24
  28. data/lib/gloss/config.rb +16 -10
  29. data/lib/gloss/errors.rb +13 -7
  30. data/lib/gloss/initializer.rb +11 -6
  31. data/lib/gloss/logger.rb +34 -0
  32. data/lib/gloss/parser.rb +35 -0
  33. data/lib/gloss/scope.rb +8 -3
  34. data/lib/gloss/source.rb +18 -15
  35. data/lib/gloss/type_checker.rb +96 -0
  36. data/lib/gloss/version.rb +6 -1
  37. data/lib/gloss/watcher.rb +63 -19
  38. data/lib/gloss/writer.rb +18 -12
  39. data/sig/gloss.rbs +3 -0
  40. data/sig/listen.rbs +1 -0
  41. data/src/lib/gloss/builder.gl +546 -0
  42. data/src/lib/gloss/cli.gl +55 -0
  43. data/src/lib/gloss/config.gl +21 -0
  44. data/src/lib/gloss/errors.gl +11 -0
  45. data/src/lib/gloss/initializer.gl +20 -0
  46. data/src/lib/gloss/logger.gl +26 -0
  47. data/src/lib/gloss/parser.gl +31 -0
  48. data/src/lib/gloss/scope.gl +9 -0
  49. data/src/lib/gloss/source.gl +32 -0
  50. data/src/lib/gloss/type_checker.gl +101 -0
  51. data/src/lib/gloss/version.gl +3 -0
  52. data/src/lib/gloss/watcher.gl +67 -0
  53. data/src/lib/gloss/writer.gl +33 -0
  54. metadata +42 -6
  55. data/lib/gloss.bundle.dwarf +0 -0
  56. data/src/lib/hrb/initializer.gl +0 -22
  57. data/src/lib/hrb/watcher.gl +0 -32
@@ -115,7 +115,7 @@ module Crystal
115
115
  case next_char
116
116
  when '='
117
117
  next_char :"<<="
118
- when '-'
118
+ when '-', '~'
119
119
  has_single_quote = false
120
120
  found_closing_single_quote = false
121
121
 
@@ -1182,5 +1182,63 @@ module Crystal
1182
1182
 
1183
1183
  @token
1184
1184
  end
1185
+
1186
+ def check_heredoc_start
1187
+ return nil unless current_char == '<' && next_char == '<' && {'-', '~'}.includes?(next_char)
1188
+
1189
+ has_single_quote = false
1190
+ found_closing_single_quote = false
1191
+
1192
+ char = next_char
1193
+ start_here = current_pos
1194
+
1195
+ if char == '\''
1196
+ has_single_quote = true
1197
+ char = next_char
1198
+ start_here = current_pos
1199
+ end
1200
+
1201
+ return nil unless ident_part?(char)
1202
+
1203
+ end_here = 0
1204
+
1205
+ while true
1206
+ char = next_char
1207
+ case
1208
+ when char == '\r'
1209
+ if peek_next_char == '\n'
1210
+ end_here = current_pos
1211
+ next_char
1212
+ break
1213
+ else
1214
+ return nil
1215
+ end
1216
+ when char == '\n'
1217
+ end_here = current_pos
1218
+ break
1219
+ when ident_part?(char)
1220
+ # ok
1221
+ when char == '\0'
1222
+ return nil
1223
+ else
1224
+ if char == '\'' && has_single_quote
1225
+ found_closing_single_quote = true
1226
+ end_here = current_pos
1227
+ next_char
1228
+ break
1229
+ elsif has_single_quote
1230
+ # wait until another quote
1231
+ else
1232
+ end_here = current_pos
1233
+ break
1234
+ end
1235
+ end
1236
+ end
1237
+
1238
+ return nil if has_single_quote && !found_closing_single_quote
1239
+
1240
+ here = string_range(start_here, end_here)
1241
+ Token::DelimiterState.new(:heredoc, here, here, allow_escapes: !has_single_quote)
1242
+ end
1185
1243
  end
1186
1244
  end
@@ -1,7 +1,13 @@
1
1
  require "compiler/crystal/syntax/*"
2
2
  require "./lexer"
3
+ require "./cr_ast"
3
4
 
4
5
  module Gloss
6
+ def self.parse_string(string : String)
7
+ tree = Gloss::Parser.parse string
8
+ tree.to_rb.to_json
9
+ end
10
+
5
11
  class Parser < Crystal::Parser
6
12
  parse_operator :or_keyword, :and_keyword, "Or.new left, right", ":or"
7
13
  parse_operator :and_keyword, :prefix, "And.new left, right", ":and"
@@ -11,10 +17,10 @@ module Gloss
11
17
  line = @line_number
12
18
  column = @token.column_number
13
19
 
14
- # next_token_skip_space
15
- # next_token_skip_space_or_newline
16
- # of = nil
17
- Crystal::ArrayLiteral.new([] of Crystal::ASTNode) # .at_end(of)
20
+ next_token_skip_space
21
+ next_token_skip_space_or_newline
22
+ of = nil
23
+ Crystal::ArrayLiteral.new([] of Crystal::ASTNode).at_end(of)
18
24
  end
19
25
 
20
26
  def new_hash_literal(entries, line, column, end_location, allow_of = true)
@@ -86,255 +92,543 @@ module Gloss
86
92
  types
87
93
  end
88
94
 
89
- # def parse_arg(args, extra_assigns, parentheses, found_default_value, found_splat, found_double_splat, allow_restrictions)
90
- # if @token.type == :"&"
91
- # next_token_skip_space_or_newline
92
- # block_arg = parse_block_arg(extra_assigns)
93
- # skip_space_or_newline
94
- # # When block_arg.name is empty, this is an anonymous argument.
95
- # # An anonymous argument should not conflict other arguments names.
96
- # # (In fact `args` may contain anonymous splat argument. See #9108).
97
- # # So check is skipped.
98
- # unless block_arg.name.empty?
99
- # conflict_arg = args.any?(&.name.==(block_arg.name))
100
- # conflict_double_splat = found_double_splat && found_double_splat.name == block_arg.name
101
- # if conflict_arg || conflict_double_splat
102
- # raise "duplicated argument name: #{block_arg.name}", block_arg.location.not_nil!
103
- # end
104
- # end
105
- # return ArgExtras.new(block_arg, false, false, false)
106
- # end
107
-
108
- # if found_double_splat
109
- # raise "only block argument is allowed after double splat"
110
- # end
111
-
112
- # splat = false
113
- # double_splat = false
114
- # arg_location = @token.location
115
- # allow_external_name = true
116
-
117
- # case @token.type
118
- # when :"*"
119
- # if found_splat
120
- # unexpected_token
121
- # end
122
-
123
- # splat = true
124
- # allow_external_name = false
125
- # next_token_skip_space
126
- # when :"**"
127
- # double_splat = true
128
- # allow_external_name = false
129
- # next_token_skip_space
130
- # else
131
- # # not a splat
132
- # end
133
-
134
- # found_space = false
135
-
136
- # if splat && (@token.type == :"," || @token.type == :")")
137
- # arg_name = ""
138
- # uses_arg = false
139
- # allow_restrictions = false
140
- # else
141
- # arg_location = @token.location
142
- # arg_name, external_name, found_space, uses_arg = parse_arg_name(arg_location, extra_assigns, allow_external_name: allow_external_name)
143
-
144
- # args.each do |arg|
145
- # if arg.name == arg_name
146
- # raise "duplicated argument name: #{arg_name}", arg_location
147
- # end
148
-
149
- # if arg.external_name == external_name
150
- # raise "duplicated argument external name: #{external_name}", arg_location
151
- # end
152
- # end
153
-
154
- # if @token.type == :SYMBOL
155
- # raise "space required after colon in type restriction", @token
156
- # end
157
- # end
158
-
159
- # default_value = nil
160
- # restriction = nil
161
- # keyword_argument = @token.type == :":" && !found_space
162
-
163
- # found_colon = false
164
-
165
- # next_token_skip_space
166
-
167
- # if allow_restrictions && @token.type == :":"
168
-
169
- # next_token_skip_space_or_newline
170
-
171
- # location = @token.location
172
- # splat_restriction = false
173
- # if (splat && @token.type == :"*") || (double_splat && @token.type == :"**")
174
- # splat_restriction = true
175
- # next_token
176
- # end
177
-
178
- # restriction = parse_bare_proc_type
179
-
180
- # if splat_restriction
181
- # restriction = splat ? Crystal::Splat.new(restriction) : Crystal::DoubleSplat.new(restriction)
182
- # restriction.at(location)
183
- # end
184
- # found_colon = true
185
- # end
186
-
187
- # if @token.type == :"="
188
- # raise "splat argument can't have default value", @token if splat
189
- # raise "double splat argument can't have default value", @token if double_splat
190
-
191
- # slash_is_regex!
192
- # next_token_skip_space_or_newline
193
-
194
- # case @token.type
195
- # when :__LINE__, :__END_LINE__, :__FILE__, :__DIR__
196
- # default_value = Crystal::MagicConstant.new(@token.type).at(@token.location)
197
- # next_token
198
- # else
199
- # @no_type_declaration += 1
200
- # default_value = parse_op_assign
201
- # @no_type_declaration -= 1
202
- # end
203
-
204
- # skip_space
205
- # else
206
- # if found_default_value && !found_splat && !splat && !double_splat
207
- # raise "argument must have a default value", arg_location
208
- # end
209
- # end
210
-
211
- # unless found_colon
212
- # if @token.type == :SYMBOL
213
- # raise "the syntax for an argument with a default value V and type T is `arg : T = V`", @token
214
- # end
215
-
216
- # if allow_restrictions && @token.type == :":"
217
- # raise "the syntax for an argument with a default value V and type T is `arg : T = V`", @token
218
- # end
219
- # end
220
-
221
- # raise "BUG: arg_name is nil" unless arg_name
222
-
223
- # arg = Crystal::Arg.new(arg_name, default_value, restriction, external_name: external_name).at(arg_location)
224
- # arg.keyword_arg = keyword_argument
225
- # args << arg
226
- # push_var arg
227
-
228
- # Crystal::Parser::ArgExtras.new(nil, !!default_value, splat, !!double_splat)
229
- # end
230
-
231
- #def parse_arg_name(location, extra_assigns, allow_external_name)
232
- # do_next_token = true
233
- # found_string_literal = false
234
- # invalid_internal_name = nil
235
-
236
- # if allow_external_name && (@token.type == :IDENT || string_literal_start?)
237
- # if @token.type == :IDENT
238
- # if @token.keyword? && invalid_internal_name?(@token.value)
239
- # invalid_internal_name = @token.dup
240
- # end
241
- # external_name = @token.type == :IDENT ? @token.value.to_s : ""
242
- # next_token
243
- # else
244
- # external_name = parse_string_without_interpolation("external name")
245
- # found_string_literal = true
246
- # end
247
- # found_space = @token.type == :SPACE || @token.type == :NEWLINE
248
- # skip_space
249
- # do_next_token = false
250
- # end
251
-
252
- # case @token.type
253
- # when :IDENT
254
- # if @token.keyword? && invalid_internal_name?(@token.value)
255
- # raise "cannot use '#{@token}' as an argument name", @token
256
- # end
257
-
258
- # arg_name = @token.value.to_s
259
- # if arg_name == external_name
260
- # raise "when specified, external name must be different than internal name", @token
261
- # end
262
-
263
- # uses_arg = false
264
- # do_next_token = true
265
- # when :INSTANCE_VAR
266
- # arg_name = @token.value.to_s[1..-1]
267
- # if arg_name == external_name
268
- # raise "when specified, external name must be different than internal name", @token
269
- # end
270
-
271
- # # If it's something like @select, we can't transform it to:
272
- # #
273
- # # @select = select
274
- # #
275
- # # because if someone uses `to_s` later it will produce invalid code.
276
- # # So we do something like:
277
- # #
278
- # # def method(select __arg0)
279
- # # @select = __arg0
280
- # # end
281
- # if !external_name && invalid_internal_name?(arg_name)
282
- # arg_name, external_name = temp_arg_name, arg_name
283
- # end
284
-
285
- # ivar = Crystal::InstanceVar.new(@token.value.to_s).at(location)
286
- # var = Crystal::Var.new(arg_name).at(location)
287
- # assign = Crystal::Assign.new(ivar, var).at(location)
288
- # if extra_assigns
289
- # extra_assigns.push assign
290
- # else
291
- # raise "can't use @instance_variable here"
292
- # end
293
- # uses_arg = true
294
- # do_next_token = true
295
- # when :CLASS_VAR
296
- # arg_name = @token.value.to_s[2..-1]
297
- # if arg_name == external_name
298
- # raise "when specified, external name must be different than internal name", @token
299
- # end
300
-
301
- # # Same case as :INSTANCE_VAR for things like @select
302
- # if !external_name && invalid_internal_name?(arg_name)
303
- # arg_name, external_name = temp_arg_name, arg_name
304
- # end
305
-
306
- # cvar = Crystal::ClassVar.new(@token.value.to_s).at(location)
307
- # var = Crystal::Var.new(arg_name).at(location)
308
- # assign = Crystal::Assign.new(cvar, var).at(location)
309
- # if extra_assigns
310
- # extra_assigns.push assign
311
- # else
312
- # raise "can't use @@class_var here"
313
- # end
314
- # uses_arg = true
315
- # do_next_token = true
316
- # else
317
- # if external_name
318
- # if found_string_literal
319
- # raise "unexpected token: #{@token}, expected argument internal name"
320
- # end
321
- # if invalid_internal_name
322
- # raise "cannot use '#{invalid_internal_name}' as an argument name", invalid_internal_name
323
- # end
324
- # arg_name = external_name
325
- # else
326
- # raise "unexpected token: #{@token}"
327
- # end
328
- # end
329
-
330
- # if do_next_token
331
- # next_token
332
- # found_space = @token.type == :SPACE || @token.type == :NEWLINE
333
- # end
334
-
335
- # skip_space
336
-
337
- # {arg_name, external_name, found_space, uses_arg}
338
- #end
95
+
96
+ def parse_arg(args, extra_assigns, parentheses, found_default_value, found_splat, found_double_splat, allow_restrictions)
97
+ if @token.type == :"&"
98
+ next_token_skip_space_or_newline
99
+ block_arg = parse_block_arg(extra_assigns)
100
+ skip_space_or_newline
101
+ # When block_arg.name is empty, this is an anonymous argument.
102
+ # An anonymous argument should not conflict other arguments names.
103
+ # (In fact `args` may contain anonymous splat argument. See #9108).
104
+ # So check is skipped.
105
+ unless block_arg.name.empty?
106
+ conflict_arg = args.any?(&.name.==(block_arg.name))
107
+ conflict_double_splat = found_double_splat && found_double_splat.name == block_arg.name
108
+ if conflict_arg || conflict_double_splat
109
+ raise "duplicated argument name: #{block_arg.name}", block_arg.location.not_nil!
110
+ end
111
+ end
112
+ return Crystal::Parser::ArgExtras.new(block_arg, false, false, false)
113
+ end
114
+
115
+ if found_double_splat
116
+ raise "only block argument is allowed after double splat"
117
+ end
118
+
119
+ splat = false
120
+ double_splat = false
121
+ arg_location = @token.location
122
+ allow_external_name = true
123
+
124
+ case @token.type
125
+ when :"*"
126
+ if found_splat
127
+ unexpected_token
128
+ end
129
+
130
+ splat = true
131
+ allow_external_name = false
132
+ next_token_skip_space
133
+ when :"**"
134
+ double_splat = true
135
+ allow_external_name = false
136
+ next_token_skip_space
137
+ else
138
+ # not a splat
139
+ end
140
+
141
+ found_space = false
142
+
143
+ if splat && (@token.type == :"," || @token.type == :")")
144
+ arg_name = ""
145
+ uses_arg = false
146
+ allow_restrictions = false
147
+ else
148
+ arg_location = @token.location
149
+ arg_name, external_name, found_space, uses_arg = parse_arg_name(arg_location, extra_assigns, allow_external_name: allow_external_name)
150
+
151
+ args.each do |arg|
152
+ if arg.name == arg_name
153
+ raise "duplicated argument name: #{arg_name}", arg_location
154
+ end
155
+
156
+ if arg.external_name == external_name
157
+ raise "duplicated argument external name: #{external_name}", arg_location
158
+ end
159
+ end
160
+
161
+ if @token.type == :SYMBOL
162
+ raise "space required after colon in type restriction", @token
163
+ end
164
+ end
165
+
166
+ default_value = nil
167
+ restriction = nil
168
+ keyword_arg = false
169
+ found_colon = false
170
+
171
+ # KEYWORD ARGUMENTS
172
+ # eg. def abc(a: : String? = "")
173
+ if @token.type == :":" && !found_space
174
+ keyword_arg = true
175
+ next_token_skip_space
176
+ found_space = true
177
+ end
178
+
179
+ if allow_restrictions && @token.type == :":"
180
+ if !default_value && !found_space
181
+ raise "space required before colon in type restriction", @token
182
+ end
183
+
184
+ next_token_skip_space_or_newline
185
+
186
+ location = @token.location
187
+ splat_restriction = false
188
+ if (splat && @token.type == :"*") || (double_splat && @token.type == :"**")
189
+ splat_restriction = true
190
+ next_token
191
+ end
192
+
193
+ restriction = parse_bare_proc_type
194
+
195
+ if splat_restriction
196
+ restriction = splat ? Crystal::Splat.new(restriction) : Crystal::DoubleSplat.new(restriction)
197
+ restriction.at(location)
198
+ end
199
+ found_colon = true
200
+ end
201
+
202
+ if @token.type == :"="
203
+ raise "splat argument can't have default value", @token if splat
204
+ raise "double splat argument can't have default value", @token if double_splat
205
+
206
+ slash_is_regex!
207
+ next_token_skip_space_or_newline
208
+
209
+ case @token.type
210
+ when :__LINE__, :__END_LINE__, :__FILE__, :__DIR__
211
+ default_value = Crystal::MagicConstant.new(@token.type).at(@token.location)
212
+ next_token
213
+ else
214
+ @no_type_declaration += 1
215
+ default_value = parse_op_assign
216
+ @no_type_declaration -= 1
217
+ end
218
+
219
+ skip_space
220
+ else
221
+ if found_default_value && !found_splat && !splat && !double_splat
222
+ raise "argument must have a default value", arg_location
223
+ end
224
+ end
225
+
226
+ unless found_colon
227
+ if @token.type == :SYMBOL
228
+ raise "the syntax for an argument with a default value V and type T is `arg : T = V`", @token
229
+ end
230
+
231
+ if allow_restrictions && @token.type == :":"
232
+ raise "the syntax for an argument with a default value V and type T is `arg : T = V`", @token
233
+ end
234
+ end
235
+
236
+ raise "BUG: arg_name is nil" unless arg_name
237
+
238
+ arg = Crystal::Arg.new(arg_name, default_value, restriction, external_name: external_name).at(arg_location)
239
+ arg.keyword_arg = keyword_arg
240
+ args << arg
241
+ push_var arg
242
+
243
+ Crystal::Parser::ArgExtras.new(nil, !!default_value, splat, !!double_splat)
244
+ end
245
+
246
+ def parse_arg_name(location, extra_assigns, allow_external_name)
247
+ do_next_token = true
248
+ found_string_literal = false
249
+ invalid_internal_name = nil
250
+
251
+ if allow_external_name && (@token.type == :IDENT || string_literal_start?)
252
+ if @token.type == :IDENT
253
+ if @token.keyword? && invalid_internal_name?(@token.value)
254
+ invalid_internal_name = @token.dup
255
+ end
256
+ external_name = @token.type == :IDENT ? @token.value.to_s : ""
257
+ next_token
258
+ else
259
+ external_name = parse_string_without_interpolation("external name")
260
+ found_string_literal = true
261
+ end
262
+ found_space = @token.type == :SPACE || @token.type == :NEWLINE
263
+ skip_space
264
+ do_next_token = false
265
+ end
266
+
267
+ case @token.type
268
+ when :IDENT
269
+ if @token.keyword? && invalid_internal_name?(@token.value)
270
+ raise "cannot use '#{@token}' as an argument name", @token
271
+ end
272
+
273
+ arg_name = @token.value.to_s
274
+ if arg_name == external_name
275
+ raise "when specified, external name must be different than internal name", @token
276
+ end
277
+
278
+ uses_arg = false
279
+ do_next_token = true
280
+ when :INSTANCE_VAR
281
+ arg_name = @token.value.to_s[1..-1]
282
+ if arg_name == external_name
283
+ raise "when specified, external name must be different than internal name", @token
284
+ end
285
+
286
+ # If it's something like @select, we can't transform it to:
287
+ #
288
+ # @select = select
289
+ #
290
+ # because if someone uses `to_s` later it will produce invalid code.
291
+ # So we do something like:
292
+ #
293
+ # def method(select __arg0)
294
+ # @select = __arg0
295
+ # end
296
+ if !external_name && invalid_internal_name?(arg_name)
297
+ arg_name, external_name = temp_arg_name, arg_name
298
+ end
299
+
300
+ ivar = Crystal::InstanceVar.new(@token.value.to_s).at(location)
301
+ var = Crystal::Var.new(arg_name).at(location)
302
+ assign = Crystal::Assign.new(ivar, var).at(location)
303
+ if extra_assigns
304
+ extra_assigns.push assign
305
+ else
306
+ raise "can't use @instance_variable here"
307
+ end
308
+ uses_arg = true
309
+ do_next_token = true
310
+ when :CLASS_VAR
311
+ arg_name = @token.value.to_s[2..-1]
312
+ if arg_name == external_name
313
+ raise "when specified, external name must be different than internal name", @token
314
+ end
315
+
316
+ # Same case as :INSTANCE_VAR for things like @select
317
+ if !external_name && invalid_internal_name?(arg_name)
318
+ arg_name, external_name = temp_arg_name, arg_name
319
+ end
320
+
321
+ cvar = Crystal::ClassVar.new(@token.value.to_s).at(location)
322
+ var = Crystal::Var.new(arg_name).at(location)
323
+ assign = Crystal::Assign.new(cvar, var).at(location)
324
+ if extra_assigns
325
+ extra_assigns.push assign
326
+ else
327
+ raise "can't use @@class_var here"
328
+ end
329
+ uses_arg = true
330
+ do_next_token = true
331
+ else
332
+ if external_name
333
+ if found_string_literal
334
+ raise "unexpected token: #{@token}, expected argument internal name"
335
+ end
336
+ if invalid_internal_name
337
+ raise "cannot use '#{invalid_internal_name}' as an argument name", invalid_internal_name
338
+ end
339
+ arg_name = external_name
340
+ else
341
+ raise "unexpected token: #{@token}"
342
+ end
343
+ end
344
+
345
+ if do_next_token
346
+ next_token
347
+ found_space = @token.type == :SPACE || @token.type == :NEWLINE
348
+ end
349
+
350
+ skip_space
351
+
352
+ {arg_name, external_name, found_space, uses_arg}
353
+ end
354
+
355
+ ### USE [] INSTEAD OF CRYSTAL'S ()
356
+ def parse_type_args(name)
357
+ return name unless @token.type == :"["
358
+
359
+ next_token_skip_space_or_newline
360
+ args = [] of Crystal::ASTNode
361
+ if named_tuple_start? || string_literal_start?
362
+ named_args = parse_named_type_args(:"]")
363
+ else
364
+ args << parse_type_splat { parse_type_arg }
365
+ while @token.type == :","
366
+ next_token_skip_space_or_newline
367
+ break if @token.type == :"]" # allow trailing comma
368
+ args << parse_type_splat { parse_type_arg }
369
+ end
370
+
371
+ has_int = args.any? do |arg|
372
+ arg.is_a?(Crystal::NumberLiteral) ||
373
+ arg.is_a?(Crystal::SizeOf) ||
374
+ arg.is_a?(Crystal::InstanceSizeOf) ||
375
+ arg.is_a?(Crystal::OffsetOf)
376
+ end
377
+ if @token.type == :"->" && !has_int
378
+ args = [parse_proc_type_output(args, args.first.location)] of Crystal::ASTNode
379
+ end
380
+ end
381
+
382
+ skip_space_or_newline
383
+ check :"]"
384
+ end_location = token_end_location
385
+ next_token
386
+
387
+ Crystal::Generic.new(name, args, named_args).at(name).at_end(end_location)
388
+ end
389
+
390
+ def parse_atomic_without_location
391
+ case @token.type
392
+ when :"("
393
+ parse_parenthesized_expression
394
+ when :"[]"
395
+ parse_empty_array_literal
396
+ when :"["
397
+ parse_array_literal
398
+ when :"{"
399
+ parse_hash_or_tuple_literal
400
+ when :"{{"
401
+ parse_percent_macro_expression
402
+ when :"{%"
403
+ parse_percent_macro_control
404
+ when :"::"
405
+ parse_generic_or_global_call
406
+ when :"->"
407
+ parse_fun_literal
408
+ when :"@["
409
+ parse_annotation
410
+ when :NUMBER
411
+ @wants_regex = false
412
+ node_and_next_token Crystal::NumberLiteral.new(@token.value.to_s, @token.number_kind)
413
+ when :CHAR
414
+ node_and_next_token Crystal::CharLiteral.new(@token.value.as(Char))
415
+ when :STRING, :DELIMITER_START
416
+ parse_delimiter
417
+ when :STRING_ARRAY_START
418
+ parse_string_array
419
+ when :SYMBOL_ARRAY_START
420
+ parse_symbol_array
421
+ when :SYMBOL
422
+ node_and_next_token Crystal::SymbolLiteral.new(@token.value.to_s)
423
+ when :GLOBAL
424
+ new_node_check_type_declaration Crystal::Global
425
+ when :"$~", :"$?"
426
+ location = @token.location
427
+ var = Crystal::Var.new(@token.to_s).at(location)
428
+
429
+ old_pos, old_line, old_column = current_pos, @line_number, @column_number
430
+ @temp_token.copy_from(@token)
431
+
432
+ next_token_skip_space
433
+
434
+ if @token.type == :"="
435
+ @token.copy_from(@temp_token)
436
+ self.current_pos, @line_number, @column_number = old_pos, old_line, old_column
437
+
438
+ push_var var
439
+ node_and_next_token var
440
+ else
441
+ @token.copy_from(@temp_token)
442
+ self.current_pos, @line_number, @column_number = old_pos, old_line, old_column
443
+
444
+ node_and_next_token Crystal::Global.new(var.name).at(location)
445
+ end
446
+ when :GLOBAL_MATCH_DATA_INDEX
447
+ value = @token.value.to_s
448
+ if value_prefix = value.rchop? '?'
449
+ method = "[]?"
450
+ value = value_prefix
451
+ else
452
+ method = "[]"
453
+ end
454
+ location = @token.location
455
+ node_and_next_token Crystal::Call.new(Crystal::Global.new("$~").at(location), method, Crystal::NumberLiteral.new(value.to_i))
456
+ when :__LINE__
457
+ node_and_next_token Crystal::MagicConstant.expand_line_node(@token.location)
458
+ when :__END_LINE__
459
+ raise "__END_LINE__ can only be used in default argument value", @token
460
+ when :__FILE__
461
+ node_and_next_token Crystal::MagicConstant.expand_file_node(@token.location)
462
+ when :__DIR__
463
+ node_and_next_token Crystal::MagicConstant.expand_dir_node(@token.location)
464
+ when :IDENT
465
+ # NOTE: Update `Parser#invalid_internal_name?` keyword list
466
+ # when adding or removing keyword to handle here.
467
+ case @token.value
468
+ when :begin
469
+ check_type_declaration { parse_begin }
470
+ when :nil
471
+ check_type_declaration { node_and_next_token Crystal::NilLiteral.new }
472
+ when :true
473
+ check_type_declaration { node_and_next_token Crystal::BoolLiteral.new(true) }
474
+ when :false
475
+ check_type_declaration { node_and_next_token Crystal::BoolLiteral.new(false) }
476
+ when :yield
477
+ check_type_declaration { parse_yield }
478
+ when :with
479
+ check_type_declaration { parse_yield_with_scope }
480
+ when :abstract
481
+ check_type_declaration do
482
+ check_not_inside_def("can't use abstract") do
483
+ doc = @token.doc
484
+
485
+ next_token_skip_space_or_newline
486
+ case @token.type
487
+ when :IDENT
488
+ case @token.value
489
+ when :def
490
+ parse_def is_abstract: true, doc: doc
491
+ when :class
492
+ parse_class_def is_abstract: true, doc: doc
493
+ when :struct
494
+ parse_class_def is_abstract: true, is_struct: true, doc: doc
495
+ else
496
+ unexpected_token
497
+ end
498
+ else
499
+ unexpected_token
500
+ end
501
+ end
502
+ end
503
+ when :def
504
+ check_type_declaration do
505
+ check_not_inside_def("can't define def") do
506
+ parse_def
507
+ end
508
+ end
509
+ when :macro
510
+ check_type_declaration do
511
+ check_not_inside_def("can't define macro") do
512
+ parse_macro
513
+ end
514
+ end
515
+ when :require
516
+ check_type_declaration do
517
+ check_not_inside_def("can't require") do
518
+ parse_require
519
+ end
520
+ end
521
+ when :case
522
+ check_type_declaration { parse_case }
523
+ when :select
524
+ check_type_declaration { parse_select }
525
+ when :if
526
+ check_type_declaration { parse_if }
527
+ when :unless
528
+ check_type_declaration { parse_unless }
529
+ when :include
530
+ check_type_declaration do
531
+ check_not_inside_def("can't include") do
532
+ parse_include
533
+ end
534
+ end
535
+ when :extend
536
+ check_type_declaration do
537
+ check_not_inside_def("can't extend") do
538
+ parse_extend
539
+ end
540
+ end
541
+ when :class
542
+ check_type_declaration do
543
+ check_not_inside_def("can't define class") do
544
+ parse_class_def
545
+ end
546
+ end
547
+ when :struct
548
+ check_type_declaration do
549
+ check_not_inside_def("can't define struct") do
550
+ parse_class_def is_struct: true
551
+ end
552
+ end
553
+ when :module
554
+ check_type_declaration do
555
+ check_not_inside_def("can't define module") do
556
+ parse_module_def
557
+ end
558
+ end
559
+ when :enum
560
+ check_type_declaration do
561
+ check_not_inside_def("can't define enum") do
562
+ parse_enum_def
563
+ end
564
+ end
565
+ when :while
566
+ check_type_declaration { parse_while }
567
+ when :until
568
+ check_type_declaration { parse_until }
569
+ when :return
570
+ check_type_declaration { parse_return }
571
+ when :next
572
+ check_type_declaration { parse_next }
573
+ when :break
574
+ check_type_declaration { parse_break }
575
+ when :lib
576
+ check_type_declaration do
577
+ check_not_inside_def("can't define lib") do
578
+ parse_lib
579
+ end
580
+ end
581
+ when :fun
582
+ check_type_declaration do
583
+ check_not_inside_def("can't define fun") do
584
+ parse_fun_def top_level: true, require_body: true
585
+ end
586
+ end
587
+ when :alias
588
+ check_type_declaration do
589
+ check_not_inside_def("can't define alias") do
590
+ parse_alias
591
+ end
592
+ end
593
+ when :pointerof
594
+ check_type_declaration { parse_pointerof }
595
+ when :sizeof
596
+ check_type_declaration { parse_sizeof }
597
+ when :instance_sizeof
598
+ check_type_declaration { parse_instance_sizeof }
599
+ when :offsetof
600
+ check_type_declaration { parse_offsetof }
601
+ when :typeof
602
+ check_type_declaration { parse_typeof }
603
+ when :private
604
+ check_type_declaration { parse_visibility_modifier Crystal::Visibility::Private }
605
+ when :protected
606
+ check_type_declaration { parse_visibility_modifier Crystal::Visibility::Protected }
607
+ when :asm
608
+ check_type_declaration { parse_asm }
609
+ when :annotation
610
+ check_type_declaration do
611
+ check_not_inside_def("can't define annotation") do
612
+ parse_annotation_def
613
+ end
614
+ end
615
+ else
616
+ set_visibility parse_var_or_call
617
+ end
618
+ when :CONST
619
+ parse_generic_or_custom_literal
620
+ when :INSTANCE_VAR
621
+ if @in_macro_expression && @token.value == "@type"
622
+ @is_macro_def = true
623
+ end
624
+ new_node_check_type_declaration Crystal::InstanceVar
625
+ when :CLASS_VAR
626
+ new_node_check_type_declaration Crystal::ClassVar
627
+ when :UNDERSCORE
628
+ node_and_next_token Crystal::Underscore.new
629
+ else
630
+ unexpected_token_in_atomic
631
+ end
632
+ end
339
633
  end
340
634
  end