gloss 0.0.1 → 0.0.6

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