tinygql 0.1.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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +46 -0
- data/.gitignore +4 -0
- data/CODE_OF_CONDUCT.md +77 -0
- data/Gemfile +3 -0
- data/LICENSE +201 -0
- data/README.md +71 -0
- data/Rakefile +132 -0
- data/bin/bench.rb +11 -0
- data/lib/tinygql/lexer.rb +256 -0
- data/lib/tinygql/nodes.rb +870 -0
- data/lib/tinygql/nodes.rb.erb +45 -0
- data/lib/tinygql/nodes.yml +205 -0
- data/lib/tinygql/parser.rb +598 -0
- data/lib/tinygql/version.rb +3 -0
- data/lib/tinygql/visitors.rb +442 -0
- data/lib/tinygql/visitors.rb.erb +46 -0
- data/lib/tinygql.rb +10 -0
- data/test/helper.rb +14 -0
- data/test/kitchen-sink.graphql +59 -0
- data/test/lexer_test.rb +93 -0
- data/test/parser_test.rb +144 -0
- data/test/schema-kitchen-sink.graphql +78 -0
- data/tinygql.gemspec +20 -0
- metadata +98 -0
@@ -0,0 +1,598 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tinygql/lexer"
|
4
|
+
require "tinygql/nodes"
|
5
|
+
|
6
|
+
module TinyGQL
|
7
|
+
class Parser
|
8
|
+
class UnexpectedToken < StandardError; end
|
9
|
+
|
10
|
+
attr_reader :token_name
|
11
|
+
|
12
|
+
def initialize doc
|
13
|
+
@lexer = Lexer.new doc
|
14
|
+
@lexer.advance
|
15
|
+
@token_name = @lexer.token_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse
|
19
|
+
document
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def document
|
25
|
+
Nodes::Document.new definition_list
|
26
|
+
end
|
27
|
+
|
28
|
+
def definition_list
|
29
|
+
list = []
|
30
|
+
while !@lexer.done?
|
31
|
+
list << definition
|
32
|
+
end
|
33
|
+
list
|
34
|
+
end
|
35
|
+
|
36
|
+
def definition
|
37
|
+
case token_name
|
38
|
+
when :FRAGMENT, :QUERY, :MUTATION, :SUBSCRIPTION, :LCURLY
|
39
|
+
executable_definition
|
40
|
+
when :EXTEND
|
41
|
+
type_system_extension
|
42
|
+
else
|
43
|
+
type_system_definition
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def type_system_extension
|
48
|
+
expect_token :EXTEND
|
49
|
+
case token_name
|
50
|
+
when :TYPE then object_type_extension
|
51
|
+
else
|
52
|
+
expect_token :FAIL
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def object_type_extension
|
57
|
+
expect_token :TYPE
|
58
|
+
name = self.name
|
59
|
+
implements_interfaces = if at?(:IMPLEMENTS); self.implements_interfaces; end
|
60
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
61
|
+
fields_definition = if at?(:LCURLY); self.fields_definition; end
|
62
|
+
Nodes::ObjectTypeExtension.new(name, implements_interfaces, directives, fields_definition)
|
63
|
+
end
|
64
|
+
|
65
|
+
def type_system_definition
|
66
|
+
case token_name
|
67
|
+
when :SCHEMA then schema_definition
|
68
|
+
when :DIRECTIVE then directive_defintion(nil)
|
69
|
+
else
|
70
|
+
type_definition(nil)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def directive_defintion desc
|
75
|
+
expect_token :DIRECTIVE
|
76
|
+
expect_token :DIR_SIGN
|
77
|
+
name = self.name
|
78
|
+
arguments_definition = if at?(:LPAREN); self.arguments_definition; end
|
79
|
+
expect_token :ON
|
80
|
+
directive_locations = self.directive_locations
|
81
|
+
Nodes::DirectiveDefinition.new(desc, name, arguments_definition, directive_locations)
|
82
|
+
end
|
83
|
+
|
84
|
+
def directive_locations
|
85
|
+
list = [directive_location]
|
86
|
+
while at?(:PIPE)
|
87
|
+
accept_token
|
88
|
+
list << directive_location
|
89
|
+
end
|
90
|
+
list
|
91
|
+
end
|
92
|
+
|
93
|
+
def directive_location
|
94
|
+
case token_name
|
95
|
+
when "QUERY", "MUTATION", "SUBSCRIPTION", "FIELD", "FRAGMENT_DEFINITION", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"
|
96
|
+
Nodes::ExecutableDirectiveLocation.new(accept_token_value)
|
97
|
+
when "SCHEMA",
|
98
|
+
"SCALAR",
|
99
|
+
"OBJECT",
|
100
|
+
"FIELD_DEFINITION",
|
101
|
+
"ARGUMENT_DEFINITION",
|
102
|
+
"INTERFACE",
|
103
|
+
"UNION",
|
104
|
+
"ENUM",
|
105
|
+
"ENUM_VALUE",
|
106
|
+
"INPUT_OBJECT",
|
107
|
+
"INPUT_FIELD_DEFINITION"
|
108
|
+
Nodes::TypeSystemDirectiveLocation.new(accept_token_value)
|
109
|
+
else
|
110
|
+
expect_token(:IDENTIFIER); nil # error
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def type_definition desc
|
115
|
+
case token_name
|
116
|
+
when :TYPE then object_type_definition(desc)
|
117
|
+
when :INTERFACE then interface_type_definition(desc)
|
118
|
+
when :UNION then union_type_definition(desc)
|
119
|
+
when :SCALAR then scalar_type_definition(desc)
|
120
|
+
when :ENUM then enum_type_definition(desc)
|
121
|
+
when :INPUT then input_object_type_definition(desc)
|
122
|
+
else
|
123
|
+
expect_token :FAIL
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def input_object_type_definition desc
|
128
|
+
expect_token :INPUT
|
129
|
+
name = self.name
|
130
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
131
|
+
input_fields_definition = if at?(:LCURLY); self.input_fields_definition; end
|
132
|
+
Nodes::InputObjectTypeDefinition.new(desc, name, directives, input_fields_definition)
|
133
|
+
end
|
134
|
+
|
135
|
+
def input_fields_definition
|
136
|
+
expect_token :LCURLY
|
137
|
+
list = []
|
138
|
+
while !at?(:RCURLY)
|
139
|
+
list << input_value_definition
|
140
|
+
end
|
141
|
+
expect_token :RCURLY
|
142
|
+
list
|
143
|
+
end
|
144
|
+
|
145
|
+
def enum_type_definition desc
|
146
|
+
expect_token :ENUM
|
147
|
+
name = self.name
|
148
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
149
|
+
enum_values_definition = if at?(:LCURLY); self.enum_values_definition; end
|
150
|
+
Nodes::EnumTypeDefinition.new(desc, name, directives, enum_values_definition)
|
151
|
+
end
|
152
|
+
|
153
|
+
def enum_values_definition
|
154
|
+
expect_token :LCURLY
|
155
|
+
list = []
|
156
|
+
while !at?(:RCURLY)
|
157
|
+
list << enum_value_definition
|
158
|
+
end
|
159
|
+
expect_token :RCURLY
|
160
|
+
list
|
161
|
+
end
|
162
|
+
|
163
|
+
def enum_value_definition
|
164
|
+
description = if at?(:STRING); accept_token_value; end
|
165
|
+
enum_value = self.enum_value
|
166
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
167
|
+
Nodes::EnumValueDefinition.new(description, enum_value, directives)
|
168
|
+
end
|
169
|
+
|
170
|
+
def scalar_type_definition desc
|
171
|
+
expect_token :SCALAR
|
172
|
+
name = self.name
|
173
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
174
|
+
Nodes::ScalarTypeDefinition.new(desc, name, directives)
|
175
|
+
end
|
176
|
+
|
177
|
+
def union_type_definition desc
|
178
|
+
expect_token :UNION
|
179
|
+
name = self.name
|
180
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
181
|
+
union_member_types = if at?(:EQUALS); self.union_member_types; end
|
182
|
+
Nodes::UnionTypeDefinition.new(desc, name, directives, union_member_types)
|
183
|
+
end
|
184
|
+
|
185
|
+
def union_member_types
|
186
|
+
expect_token :EQUALS
|
187
|
+
list = [named_type]
|
188
|
+
while at?(:PIPE)
|
189
|
+
accept_token
|
190
|
+
list << named_type
|
191
|
+
end
|
192
|
+
list
|
193
|
+
end
|
194
|
+
|
195
|
+
def interface_type_definition desc
|
196
|
+
expect_token :INTERFACE
|
197
|
+
name = self.name
|
198
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
199
|
+
fields_definition = if at?(:LCURLY); self.fields_definition; end
|
200
|
+
Nodes::InterfaceTypeDefinition.new(desc, name, directives, fields_definition)
|
201
|
+
end
|
202
|
+
|
203
|
+
def object_type_definition desc
|
204
|
+
expect_token :TYPE
|
205
|
+
name = self.name
|
206
|
+
implements_interfaces = if at?(:IMPLEMENTS); self.implements_interfaces; end
|
207
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
208
|
+
fields_definition = if at?(:LCURLY); self.fields_definition; end
|
209
|
+
|
210
|
+
Nodes::ObjectTypeDefinition.new(desc, name, implements_interfaces, directives, fields_definition)
|
211
|
+
end
|
212
|
+
|
213
|
+
def fields_definition
|
214
|
+
expect_token :LCURLY
|
215
|
+
list = []
|
216
|
+
while !at?(:RCURLY)
|
217
|
+
list << field_definition
|
218
|
+
end
|
219
|
+
expect_token :RCURLY
|
220
|
+
list
|
221
|
+
end
|
222
|
+
|
223
|
+
def field_definition
|
224
|
+
description = if at?(:STRING); accept_token_value; end
|
225
|
+
name = self.name
|
226
|
+
arguments_definition = if at?(:LPAREN); self.arguments_definition; end
|
227
|
+
expect_token :COLON
|
228
|
+
type = self.type
|
229
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
230
|
+
|
231
|
+
Nodes::FieldDefinition.new(description, name, arguments_definition, type, directives)
|
232
|
+
end
|
233
|
+
|
234
|
+
def arguments_definition
|
235
|
+
expect_token :LPAREN
|
236
|
+
list = []
|
237
|
+
while !at?(:RPAREN)
|
238
|
+
list << input_value_definition
|
239
|
+
end
|
240
|
+
expect_token :RPAREN
|
241
|
+
list
|
242
|
+
end
|
243
|
+
|
244
|
+
def input_value_definition
|
245
|
+
description = if at?(:STRING); accept_token_value; end
|
246
|
+
name = self.name
|
247
|
+
expect_token :COLON
|
248
|
+
type = self.type
|
249
|
+
default_value = if at?(:EQUALS); self.default_value; end
|
250
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
251
|
+
Nodes::InputValueDefinition.new(description, name, type, default_value, directives)
|
252
|
+
end
|
253
|
+
|
254
|
+
def implements_interfaces
|
255
|
+
expect_token :IMPLEMENTS
|
256
|
+
list = [self.named_type]
|
257
|
+
while at?(:AMP)
|
258
|
+
accept_token
|
259
|
+
list << self.named_type
|
260
|
+
end
|
261
|
+
list
|
262
|
+
end
|
263
|
+
|
264
|
+
def schema_definition
|
265
|
+
expect_token :SCHEMA
|
266
|
+
|
267
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
268
|
+
expect_token :LCURLY
|
269
|
+
defs = root_operation_type_definition
|
270
|
+
expect_token :RCURLY
|
271
|
+
Nodes::SchemaDefinition.new(directives, defs)
|
272
|
+
end
|
273
|
+
|
274
|
+
def root_operation_type_definition
|
275
|
+
list = []
|
276
|
+
while !at?(:RCURLY)
|
277
|
+
operation_type = self.operation_type
|
278
|
+
expect_token :COLON
|
279
|
+
list << Nodes::RootOperationTypeDefinition.new(operation_type, named_type)
|
280
|
+
end
|
281
|
+
list
|
282
|
+
end
|
283
|
+
|
284
|
+
def executable_definition
|
285
|
+
if at?(:FRAGMENT)
|
286
|
+
fragment_definition
|
287
|
+
else
|
288
|
+
operation_definition
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def fragment_definition
|
293
|
+
expect_token :FRAGMENT
|
294
|
+
expect_token(:FAIL) if at?(:ON)
|
295
|
+
name = self.name
|
296
|
+
tc = self.type_condition
|
297
|
+
directives = if at?(:DIR_SIGN)
|
298
|
+
self.directives
|
299
|
+
end
|
300
|
+
|
301
|
+
Nodes::FragmentDefinition.new(name, tc, directives, selection_set)
|
302
|
+
end
|
303
|
+
|
304
|
+
def operation_definition
|
305
|
+
case token_name
|
306
|
+
when :QUERY, :MUTATION, :SUBSCRIPTION
|
307
|
+
type = self.operation_type
|
308
|
+
ident = if at?(:IDENTIFIER); name; end
|
309
|
+
variable_definitions = if at?(:LPAREN); self.variable_definitions; end
|
310
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
311
|
+
end
|
312
|
+
|
313
|
+
Nodes::OperationDefinition.new(
|
314
|
+
type,
|
315
|
+
ident,
|
316
|
+
variable_definitions,
|
317
|
+
directives,
|
318
|
+
selection_set
|
319
|
+
)
|
320
|
+
end
|
321
|
+
|
322
|
+
def selection_set
|
323
|
+
expect_token(:LCURLY)
|
324
|
+
list = []
|
325
|
+
while !at?(:RCURLY)
|
326
|
+
list << selection
|
327
|
+
end
|
328
|
+
expect_token(:RCURLY)
|
329
|
+
list
|
330
|
+
end
|
331
|
+
|
332
|
+
def selection
|
333
|
+
if at?(:ELLIPSIS)
|
334
|
+
selection_fragment
|
335
|
+
else
|
336
|
+
field
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def selection_fragment
|
341
|
+
expect_token :ELLIPSIS
|
342
|
+
|
343
|
+
case token_name
|
344
|
+
when :ON, :DIR_SIGN, :LCURLY then inline_fragment
|
345
|
+
when :IDENTIFIER then fragment_spread
|
346
|
+
else
|
347
|
+
expect_token :FAIL
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def fragment_spread
|
352
|
+
name = self.name
|
353
|
+
directives = if at?(:DIR_SIGN)
|
354
|
+
self.directives
|
355
|
+
end
|
356
|
+
|
357
|
+
Nodes::FragmentSpread.new(name, directives)
|
358
|
+
end
|
359
|
+
|
360
|
+
def inline_fragment
|
361
|
+
type_condition = if at?(:ON)
|
362
|
+
self.type_condition
|
363
|
+
end
|
364
|
+
|
365
|
+
directives = if at?(:DIR_SIGN)
|
366
|
+
self.directives
|
367
|
+
end
|
368
|
+
|
369
|
+
Nodes::InlineFragment.new(type_condition, directives, selection_set)
|
370
|
+
end
|
371
|
+
|
372
|
+
def type_condition
|
373
|
+
expect_token :ON
|
374
|
+
Nodes::TypeCondition.new(named_type)
|
375
|
+
end
|
376
|
+
|
377
|
+
def field
|
378
|
+
name = self.name
|
379
|
+
|
380
|
+
aliaz = nil
|
381
|
+
|
382
|
+
if at?(:COLON)
|
383
|
+
expect_token(:COLON)
|
384
|
+
aliaz = name
|
385
|
+
name = self.name
|
386
|
+
end
|
387
|
+
|
388
|
+
arguments = if at?(:LPAREN); self.arguments; end
|
389
|
+
directives = if at?(:DIR_SIGN); self.directives; end
|
390
|
+
selection_set = if at?(:LCURLY); self.selection_set; end
|
391
|
+
|
392
|
+
Nodes::Field.new(aliaz, name, arguments, directives, selection_set)
|
393
|
+
end
|
394
|
+
|
395
|
+
def operation_type
|
396
|
+
expect_tokens([:QUERY, :MUTATION, :SUBSCRIPTION])
|
397
|
+
end
|
398
|
+
|
399
|
+
def directives
|
400
|
+
list = []
|
401
|
+
while at?(:DIR_SIGN)
|
402
|
+
list << directive
|
403
|
+
end
|
404
|
+
list
|
405
|
+
end
|
406
|
+
|
407
|
+
def directive
|
408
|
+
expect_token(:DIR_SIGN)
|
409
|
+
name = self.name
|
410
|
+
arguments = if at?(:LPAREN)
|
411
|
+
self.arguments
|
412
|
+
end
|
413
|
+
|
414
|
+
Nodes::Directive.new(name, arguments)
|
415
|
+
end
|
416
|
+
|
417
|
+
def arguments
|
418
|
+
expect_token(:LPAREN)
|
419
|
+
args = []
|
420
|
+
while !at?(:RPAREN)
|
421
|
+
args << argument
|
422
|
+
end
|
423
|
+
expect_token(:RPAREN)
|
424
|
+
args
|
425
|
+
end
|
426
|
+
|
427
|
+
def argument
|
428
|
+
name = self.name
|
429
|
+
expect_token(:COLON)
|
430
|
+
Nodes::Argument.new(name, value)
|
431
|
+
end
|
432
|
+
|
433
|
+
def variable_definitions
|
434
|
+
expect_token(:LPAREN)
|
435
|
+
defs = []
|
436
|
+
while !at?(:RPAREN)
|
437
|
+
defs << variable_definition
|
438
|
+
end
|
439
|
+
expect_token(:RPAREN)
|
440
|
+
defs
|
441
|
+
end
|
442
|
+
|
443
|
+
def variable_definition
|
444
|
+
var = variable
|
445
|
+
expect_token(:COLON)
|
446
|
+
type = self.type
|
447
|
+
default_value = if at?(:EQUALS)
|
448
|
+
self.default_value
|
449
|
+
end
|
450
|
+
|
451
|
+
Nodes::VariableDefinition.new(var, type, default_value)
|
452
|
+
end
|
453
|
+
|
454
|
+
def default_value
|
455
|
+
expect_token(:EQUALS)
|
456
|
+
value
|
457
|
+
end
|
458
|
+
|
459
|
+
def value
|
460
|
+
case token_name
|
461
|
+
when :INT then int_value
|
462
|
+
when :FLOAT then float_value
|
463
|
+
when :STRING then string_value
|
464
|
+
when :TRUE, :FALSE then boolean_value
|
465
|
+
when :NULL then null_value
|
466
|
+
when :IDENTIFIER then enum_value
|
467
|
+
when :LBRACKET then list_value
|
468
|
+
when :LCURLY then object_value
|
469
|
+
when :VAR_SIGN then variable
|
470
|
+
else
|
471
|
+
expect_token :FAIL
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def object_value
|
476
|
+
expect_token(:LCURLY)
|
477
|
+
list = []
|
478
|
+
while !at?(:RCURLY)
|
479
|
+
n = name
|
480
|
+
expect_token(:COLON)
|
481
|
+
list << Nodes::ObjectField.new(n, value)
|
482
|
+
end
|
483
|
+
expect_token(:RCURLY)
|
484
|
+
Nodes::ObjectValue.new(list)
|
485
|
+
end
|
486
|
+
|
487
|
+
def list_value
|
488
|
+
expect_token(:LBRACKET)
|
489
|
+
list = []
|
490
|
+
while !at?(:RBRACKET)
|
491
|
+
list << value
|
492
|
+
end
|
493
|
+
expect_token(:RBRACKET)
|
494
|
+
Nodes::ListValue.new(list)
|
495
|
+
end
|
496
|
+
|
497
|
+
def enum_value
|
498
|
+
Nodes::EnumValue.new(expect_token_value(:IDENTIFIER))
|
499
|
+
end
|
500
|
+
|
501
|
+
def float_value
|
502
|
+
Nodes::FloatValue.new(expect_token_value(:FLOAT))
|
503
|
+
end
|
504
|
+
|
505
|
+
def int_value
|
506
|
+
Nodes::IntValue.new(expect_token_value(:INT))
|
507
|
+
end
|
508
|
+
|
509
|
+
def string_value
|
510
|
+
Nodes::StringValue.new(expect_token_value(:STRING))
|
511
|
+
end
|
512
|
+
|
513
|
+
def boolean_value
|
514
|
+
Nodes::BooleanValue.new(expect_tokens([:TRUE, :FALSE]))
|
515
|
+
end
|
516
|
+
|
517
|
+
def null_value
|
518
|
+
Nodes::NullValue.new(expect_token_value(:NULL))
|
519
|
+
end
|
520
|
+
|
521
|
+
def type
|
522
|
+
type = case token_name
|
523
|
+
when :IDENTIFIER then named_type
|
524
|
+
when :LBRACKET then list_type
|
525
|
+
end
|
526
|
+
|
527
|
+
if at?(:BANG)
|
528
|
+
Nodes::NotNullType.new type
|
529
|
+
expect_token(:BANG)
|
530
|
+
end
|
531
|
+
type
|
532
|
+
end
|
533
|
+
|
534
|
+
def list_type
|
535
|
+
expect_token(:LBRACKET)
|
536
|
+
type = Nodes::ListType.new(self.type)
|
537
|
+
expect_token(:RBRACKET)
|
538
|
+
type
|
539
|
+
end
|
540
|
+
|
541
|
+
def named_type
|
542
|
+
Nodes::NamedType.new(name)
|
543
|
+
end
|
544
|
+
|
545
|
+
def variable
|
546
|
+
return unless at?(:VAR_SIGN)
|
547
|
+
accept_token
|
548
|
+
Nodes::Variable.new name
|
549
|
+
end
|
550
|
+
|
551
|
+
def name
|
552
|
+
case token_name
|
553
|
+
when :IDENTIFIER, :INPUT, :QUERY, :TYPE then accept_token_value
|
554
|
+
else
|
555
|
+
expect_token_value(:IDENTIFIER)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
def accept_token
|
560
|
+
@lexer.advance
|
561
|
+
@token_name = @lexer.token_name
|
562
|
+
end
|
563
|
+
|
564
|
+
# Only use when we care about the accepted token's value
|
565
|
+
def accept_token_value
|
566
|
+
token_value = @lexer.token_value
|
567
|
+
accept_token
|
568
|
+
token_value
|
569
|
+
end
|
570
|
+
|
571
|
+
def expect_token tok
|
572
|
+
unless at?(tok)
|
573
|
+
raise UnexpectedToken, "Expected token #{tok}, actual: #{token_name} line: #{@lexer.line}"
|
574
|
+
end
|
575
|
+
accept_token
|
576
|
+
end
|
577
|
+
|
578
|
+
# Only use when we care about the expected token's value
|
579
|
+
def expect_token_value tok
|
580
|
+
token_value = @lexer.token_value
|
581
|
+
expect_token tok
|
582
|
+
token_value
|
583
|
+
end
|
584
|
+
|
585
|
+
def expect_tokens toks
|
586
|
+
token_value = @lexer.token_value
|
587
|
+
unless toks.any? { |tok| at?(tok) }
|
588
|
+
raise UnexpectedToken, "Expected token #{tok}, actual: #{token_name}"
|
589
|
+
end
|
590
|
+
accept_token
|
591
|
+
token_value
|
592
|
+
end
|
593
|
+
|
594
|
+
def at? tok
|
595
|
+
token_name == tok
|
596
|
+
end
|
597
|
+
end
|
598
|
+
end
|