kumi-parser 0.0.33 → 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.
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ostruct'
4
-
5
- module Kumi
6
- module Parser
7
- module TextParser
8
- # Public API for TextParser
9
- class Api
10
- class << self
11
- def parse(text, source_file: '<input>')
12
- parser = Parser.new
13
- parser.parse(text, source_file: source_file)
14
- end
15
-
16
- def validate(text, source_file: '<input>')
17
- parse(text, source_file: source_file)
18
- []
19
- rescue StandardError => e
20
- [create_diagnostic(e, source_file)]
21
- end
22
-
23
- def valid?(text, source_file: '<input>')
24
- validate(text, source_file: source_file).empty?
25
- end
26
-
27
- def diagnostics_for_monaco(text, source_file: '<input>')
28
- validate(text, source_file: source_file)
29
- end
30
-
31
- def diagnostics_for_codemirror(text, source_file: '<input>')
32
- validate(text, source_file: source_file)
33
- end
34
-
35
- def diagnostics_as_json(text, source_file: '<input>')
36
- validate(text, source_file: source_file).map(&:to_h)
37
- end
38
-
39
- def analyze(text, source_file: '<input>')
40
- ast = parse(text, source_file: source_file)
41
- { success: true, ast: ast, diagnostics: [] }
42
- rescue StandardError => e
43
- { success: false, ast: nil, diagnostics: [create_diagnostic(e, source_file)] }
44
- end
45
-
46
- private
47
-
48
- def create_diagnostic(error, source_file)
49
- OpenStruct.new(
50
- line: 1,
51
- column: 1,
52
- message: error.message,
53
- source_file: source_file
54
- )
55
- end
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,468 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kumi
4
- module Parser
5
- # Token types
6
- module TokenType
7
- # Literals
8
- INTEGER = :integer
9
- FLOAT = :float
10
- STRING = :string
11
- BOOLEAN = :boolean
12
-
13
- # Identifiers and symbols
14
- IDENTIFIER = :identifier
15
- SYMBOL = :symbol # :name
16
- CONSTANT = :constant # Float::INFINITY
17
-
18
- # Keywords
19
- SCHEMA = :schema
20
- INPUT = :input
21
- VALUE = :value
22
- TRAIT = :trait
23
- IMPORT = :import
24
- CODEGEN = :codegen
25
- FROM = :from
26
- DO = :do
27
- END_KW = :end
28
- ON = :on
29
- BASE = :base
30
-
31
- # Type keywords
32
- INTEGER_TYPE = :integer_type # integer
33
- FLOAT_TYPE = :float_type # float
34
- DECIMAL_TYPE = :decimal_type # decimal
35
- STRING_TYPE = :string_type # string
36
- BOOLEAN_TYPE = :boolean_type # boolean
37
- ANY_TYPE = :any_type # any
38
- ARRAY_TYPE = :array_type # array
39
- ELEMENT_TYPE = :element_type # element
40
- INDEX_TYPE = :index_type # index
41
-
42
- # Function keywords
43
- FN = :fn
44
-
45
- # Operators (by precedence)
46
- EXPONENT = :exponent # **
47
- MULTIPLY = :multiply # *
48
- DIVIDE = :divide # /
49
- MODULO = :modulo # %
50
- ADD = :add # +
51
- SUBTRACT = :subtract # -
52
- GTE = :gte # >=
53
- LTE = :lte # <=
54
- GT = :gt # >
55
- LT = :lt # <
56
- EQ = :eq # ==
57
- NE = :ne # !=
58
- AND = :and # &
59
- OR = :or # |
60
-
61
- # Punctuation
62
- DOT = :dot # .
63
- DOT_DOT = :dot_dot # ..
64
- DOT_DOT_DOT = :dot_dot_dot # ...
65
- COMMA = :comma # ,
66
- COLON = :colon # :
67
- LPAREN = :lparen # (
68
- RPAREN = :rparen # )
69
- LBRACKET = :lbracket # [
70
- RBRACKET = :rbracket # ]
71
-
72
- # Special
73
- NEWLINE = :newline
74
- EOF = :eof
75
- COMMENT = :comment # # comment
76
- end
77
-
78
- # Rich metadata for each token type
79
- TOKEN_METADATA = {
80
- # Keywords with parsing hints
81
- schema: {
82
- category: :keyword,
83
- expects_block: true,
84
- block_terminator: :end
85
- },
86
- input: {
87
- category: :keyword,
88
- expects_block: true,
89
- block_terminator: :end,
90
- context: :input_declarations
91
- },
92
- value: {
93
- category: :keyword,
94
- expects_expression: true,
95
- declaration_type: :value
96
- },
97
- let: {
98
- category: :keyword,
99
- expects_expression: true
100
- },
101
- trait: {
102
- category: :keyword,
103
- expects_expression: true,
104
- declaration_type: :trait
105
- },
106
- import: {
107
- category: :keyword,
108
- import_declaration: true
109
- },
110
- codegen: {
111
- category: :keyword,
112
- schema_directive: true
113
- },
114
- from: {
115
- category: :keyword,
116
- import_source: true
117
- },
118
- do: {
119
- category: :keyword,
120
- block_opener: true
121
- },
122
- end: {
123
- category: :keyword,
124
- block_closer: true,
125
- terminates_expression: true
126
- },
127
- on: {
128
- category: :keyword,
129
- cascade_keyword: true,
130
- expects_condition: true
131
- },
132
- base: {
133
- category: :keyword,
134
- cascade_keyword: true,
135
- is_base_case: true
136
- },
137
-
138
- # Type keywords
139
- integer_type: {
140
- category: :type_keyword,
141
- starts_declaration: true,
142
- type_name: :integer
143
- },
144
- float_type: {
145
- category: :type_keyword,
146
- starts_declaration: true,
147
- type_name: :float
148
- },
149
- decimal_type: {
150
- category: :type_keyword,
151
- starts_declaration: true,
152
- type_name: :decimal
153
- },
154
- string_type: {
155
- category: :type_keyword,
156
- starts_declaration: true,
157
- type_name: :string
158
- },
159
- boolean_type: {
160
- category: :type_keyword,
161
- starts_declaration: true,
162
- type_name: :boolean
163
- },
164
- any_type: {
165
- category: :type_keyword,
166
- starts_declaration: true,
167
- type_name: :any
168
- },
169
- array_type: {
170
- category: :type_keyword,
171
- starts_declaration: true,
172
- type_name: :array
173
- },
174
- hash_type: {
175
- category: :type_keyword,
176
- starts_declaration: true,
177
- type_name: :hash
178
- },
179
- element_type: {
180
- category: :type_keyword,
181
- starts_declaration: true,
182
- type_name: :element
183
- },
184
- index_type: {
185
- category: :type_keyword,
186
- starts_declaration: true,
187
- type_name: :index
188
- },
189
-
190
- # Function keyword
191
- fn: {
192
- category: :keyword,
193
- function_keyword: true,
194
- starts_expression: true
195
- },
196
-
197
- function_sugar: {
198
- function_keyword: true,
199
- starts_expression: true
200
- },
201
-
202
- # Operators with precedence and associativity
203
- exponent: {
204
- category: :operator,
205
- precedence: 7,
206
- associativity: :right,
207
- arity: :binary
208
- },
209
- multiply: {
210
- category: :operator,
211
- precedence: 6,
212
- associativity: :left,
213
- arity: :binary
214
- },
215
- divide: {
216
- category: :operator,
217
- precedence: 6,
218
- associativity: :left,
219
- arity: :binary
220
- },
221
- modulo: {
222
- category: :operator,
223
- precedence: 6,
224
- associativity: :left,
225
- arity: :binary
226
- },
227
- add: {
228
- category: :operator,
229
- precedence: 5,
230
- associativity: :left,
231
- arity: :binary
232
- },
233
- subtract: {
234
- category: :operator,
235
- precedence: 5,
236
- associativity: :left,
237
- arity: :binary
238
- },
239
- gte: {
240
- category: :operator,
241
- precedence: 4,
242
- associativity: :left,
243
- arity: :binary,
244
- returns_boolean: true
245
- },
246
- lte: {
247
- category: :operator,
248
- precedence: 4,
249
- associativity: :left,
250
- arity: :binary,
251
- returns_boolean: true
252
- },
253
- gt: {
254
- category: :operator,
255
- precedence: 4,
256
- associativity: :left,
257
- arity: :binary,
258
- returns_boolean: true
259
- },
260
- lt: {
261
- category: :operator,
262
- precedence: 4,
263
- associativity: :left,
264
- arity: :binary,
265
- returns_boolean: true
266
- },
267
- eq: {
268
- category: :operator,
269
- precedence: 4,
270
- associativity: :left,
271
- arity: :binary,
272
- returns_boolean: true
273
- },
274
- ne: {
275
- category: :operator,
276
- precedence: 4,
277
- associativity: :left,
278
- arity: :binary,
279
- returns_boolean: true
280
- },
281
- and: {
282
- category: :operator,
283
- precedence: 3,
284
- associativity: :left,
285
- arity: :binary,
286
- requires_boolean: true
287
- },
288
- or: {
289
- category: :operator,
290
- precedence: 2,
291
- associativity: :left,
292
- arity: :binary,
293
- requires_boolean: true
294
- },
295
- # Literals with type information
296
- integer: {
297
- category: :literal,
298
- starts_expression: true,
299
- ast_class: 'Kumi::Syntax::Literal'
300
- },
301
- float: {
302
- category: :literal,
303
- starts_expression: true,
304
- ast_class: 'Kumi::Syntax::Literal'
305
- },
306
- string: {
307
- category: :literal,
308
- starts_expression: true,
309
- ast_class: 'Kumi::Syntax::Literal'
310
- },
311
- boolean: {
312
- category: :literal,
313
- starts_expression: true,
314
- ast_class: 'Kumi::Syntax::Literal'
315
- },
316
- # Identifiers and references
317
- identifier: {
318
- category: :identifier,
319
- starts_expression: true,
320
- can_be_reference: true
321
- },
322
- symbol: {
323
- category: :identifier,
324
- starts_expression: true,
325
- is_declaration_name: true
326
- },
327
- constant: {
328
- category: :literal,
329
- starts_expression: true,
330
- ast_class: 'Kumi::Syntax::Literal'
331
- },
332
-
333
- # Punctuation with parser hints
334
- dot: {
335
- category: :punctuation,
336
- indicates_member_access: true
337
- },
338
- dot_dot: {
339
- category: :range
340
- },
341
- dot_dot_dot: {
342
- category: :range
343
- },
344
- comma: {
345
- category: :punctuation,
346
- separates_items: true
347
- },
348
- colon: {
349
- category: :punctuation,
350
- indicates_symbol: true
351
- },
352
- lparen: {
353
- category: :punctuation,
354
- opens_group: true,
355
- group_closer: :rparen,
356
- starts_expression: true
357
- },
358
- rparen: {
359
- category: :punctuation,
360
- closes_group: true,
361
- terminates_expression: true
362
- },
363
- lbracket: {
364
- category: :punctuation,
365
- opens_group: true,
366
- group_closer: :rbracket,
367
- starts_expression: true,
368
- indicates_array: true
369
- },
370
- rbracket: {
371
- category: :punctuation,
372
- closes_group: true,
373
- terminates_expression: true
374
- },
375
-
376
- left_brace: {
377
- category: :punctuation,
378
- opens_scope: :hash
379
- },
380
- right_brace: {
381
- category: :punctuation,
382
- closes_scope: :hash
383
- },
384
-
385
- # Special tokens
386
- newline: {
387
- category: :whitespace,
388
- separates_statements: true
389
- },
390
- eof: {
391
- category: :special,
392
- terminates_input: true
393
- },
394
- comment: {
395
- category: :whitespace,
396
- ignored_by_parser: true
397
- }
398
- }.freeze
399
-
400
- # Character to token mappings
401
- CHAR_TO_TOKEN = {
402
- '(' => :lparen,
403
- ')' => :rparen,
404
- '[' => :lbracket,
405
- ']' => :rbracket,
406
- '{' => :left_brace,
407
- '}' => :right_brace,
408
- ',' => :comma,
409
- '.' => :dot,
410
- ':' => :colon,
411
- '+' => :add,
412
- '-' => :subtract,
413
- '*' => :multiply,
414
- '/' => :divide,
415
- '%' => :modulo,
416
- '&' => :and,
417
- '|' => :or,
418
- '=>' => :arrow
419
- }.freeze
420
-
421
- FUNCTION_SUGAR = {
422
- 'select' => '__select__',
423
- 'shift' => 'shift',
424
- 'roll' => 'roll',
425
- 'cross' => 'cross',
426
- 'outer' => 'outer',
427
- 'index' => 'index',
428
- 'to_decimal' => 'to_decimal',
429
- 'to_integer' => 'to_integer',
430
- 'to_float' => 'to_float',
431
- 'to_string' => 'to_string'
432
- }.freeze
433
-
434
- # Keywords mapping
435
- KEYWORDS = {
436
- 'schema' => :schema,
437
- 'input' => :input,
438
- 'value' => :value,
439
- 'let' => :let,
440
- 'trait' => :trait,
441
- 'import' => :import,
442
- 'codegen' => :codegen,
443
- 'from' => :from,
444
- 'do' => :do,
445
- 'end' => :end,
446
- 'on' => :on,
447
- 'base' => :base,
448
- 'fn' => :fn,
449
- 'true' => :boolean,
450
- 'false' => :boolean,
451
- 'integer' => :integer_type,
452
- 'float' => :float_type,
453
- 'decimal' => :decimal_type,
454
- 'string' => :string_type,
455
- 'boolean' => :boolean_type,
456
- 'any' => :any_type,
457
- 'array' => :array_type,
458
- 'hash' => :hash_type,
459
- 'element' => :element_type
460
- }.freeze
461
-
462
- # Opener to closer mappings for error recovery
463
- OPENER_FOR_CLOSER = {
464
- rparen: :lparen,
465
- rbracket: :lbracket
466
- }.freeze
467
- end
468
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'parser/text_parser'
4
-
5
- module Kumi
6
- # Top-level text parser module with same interface as Ruby DSL
7
- module TextParser
8
- extend self
9
-
10
- # Parse text schema and return AST (same interface as RubyParser::Dsl.build_syntax_tree)
11
- def parse(text, source_file: '<input>')
12
- Parser::TextParser.parse(text, source_file: source_file)
13
- end
14
-
15
- # Validate text schema
16
- def valid?(text, source_file: '<input>')
17
- Parser::TextParser.valid?(text, source_file: source_file)
18
- end
19
-
20
- # Get validation diagnostics
21
- def validate(text, source_file: '<input>')
22
- Parser::TextParser.validate(text, source_file: source_file)
23
- end
24
-
25
- # Get Monaco Editor format diagnostics
26
- def diagnostics_for_monaco(text, source_file: '<input>')
27
- Parser::TextParser.diagnostics_for_monaco(text, source_file: source_file)
28
- end
29
-
30
- # Get CodeMirror format diagnostics
31
- def diagnostics_for_codemirror(text, source_file: '<input>')
32
- Parser::TextParser.diagnostics_for_codemirror(text, source_file: source_file)
33
- end
34
-
35
- # Get JSON format diagnostics
36
- def diagnostics_as_json(text, source_file: '<input>')
37
- Parser::TextParser.diagnostics_as_json(text, source_file: source_file)
38
- end
39
- end
40
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'kumi'
4
- require_relative 'text_parser'
5
-
6
- module Kumi
7
- # Text-based schema that extends Kumi::Schema with text parsing capabilities
8
- class TextSchema
9
- extend Kumi::Schema
10
-
11
- # Create a schema from text using the same pipeline as Ruby DSL
12
- def self.from_text(text, source_file: '<input>')
13
- # Parse text to AST (same as RubyParser::Dsl.build_syntax_tree)
14
- @__kumi_syntax_tree__ = Kumi::TextParser.parse(text, source_file: source_file).freeze
15
- @__analyzer_result__ = Analyzer.analyze!(@__kumi_syntax_tree__).freeze
16
- @__compiled_schema__ = Compiler.compile(@__kumi_syntax_tree__, analyzer: @__analyzer_result__).freeze
17
-
18
- Inspector.new(@__kumi_syntax_tree__, @__analyzer_result__, @__compiled_schema__)
19
- end
20
-
21
- # Validate text schema
22
- def self.valid?(text, source_file: '<input>')
23
- Kumi::TextParser.valid?(text, source_file: source_file)
24
- end
25
-
26
- # Get validation diagnostics
27
- def self.validate(text, source_file: '<input>')
28
- Kumi::TextParser.validate(text, source_file: source_file)
29
- end
30
- end
31
- end