parsanol 1.3.13-arm-linux

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.txt +98 -0
  3. data/LICENSE +23 -0
  4. data/README.adoc +905 -0
  5. data/Rakefile +141 -0
  6. data/lib/parsanol/3.2/parsanol_native.so +0 -0
  7. data/lib/parsanol/3.3/parsanol_native.so +0 -0
  8. data/lib/parsanol/3.4/parsanol_native.so +0 -0
  9. data/lib/parsanol/4.0/parsanol_native.so +0 -0
  10. data/lib/parsanol/ast_visitor.rb +122 -0
  11. data/lib/parsanol/atoms/alternative.rb +123 -0
  12. data/lib/parsanol/atoms/base.rb +208 -0
  13. data/lib/parsanol/atoms/can_flatten.rb +194 -0
  14. data/lib/parsanol/atoms/capture.rb +38 -0
  15. data/lib/parsanol/atoms/context.rb +357 -0
  16. data/lib/parsanol/atoms/context_optimized.rb +38 -0
  17. data/lib/parsanol/atoms/custom.rb +110 -0
  18. data/lib/parsanol/atoms/cut.rb +66 -0
  19. data/lib/parsanol/atoms/dsl.rb +96 -0
  20. data/lib/parsanol/atoms/dynamic.rb +39 -0
  21. data/lib/parsanol/atoms/entity.rb +75 -0
  22. data/lib/parsanol/atoms/ignored.rb +37 -0
  23. data/lib/parsanol/atoms/infix.rb +167 -0
  24. data/lib/parsanol/atoms/lookahead.rb +85 -0
  25. data/lib/parsanol/atoms/named.rb +74 -0
  26. data/lib/parsanol/atoms/re.rb +83 -0
  27. data/lib/parsanol/atoms/repetition.rb +277 -0
  28. data/lib/parsanol/atoms/scope.rb +35 -0
  29. data/lib/parsanol/atoms/sequence.rb +195 -0
  30. data/lib/parsanol/atoms/str.rb +109 -0
  31. data/lib/parsanol/atoms/visitor.rb +91 -0
  32. data/lib/parsanol/atoms.rb +46 -0
  33. data/lib/parsanol/buffer.rb +133 -0
  34. data/lib/parsanol/builder_callbacks.rb +353 -0
  35. data/lib/parsanol/cause.rb +122 -0
  36. data/lib/parsanol/context.rb +39 -0
  37. data/lib/parsanol/convenience.rb +36 -0
  38. data/lib/parsanol/edit_tracker.rb +111 -0
  39. data/lib/parsanol/error_reporter/contextual.rb +99 -0
  40. data/lib/parsanol/error_reporter/deepest.rb +120 -0
  41. data/lib/parsanol/error_reporter/tree.rb +63 -0
  42. data/lib/parsanol/error_reporter.rb +100 -0
  43. data/lib/parsanol/expression/treetop.rb +154 -0
  44. data/lib/parsanol/expression.rb +106 -0
  45. data/lib/parsanol/fast_mode.rb +187 -0
  46. data/lib/parsanol/first_set.rb +79 -0
  47. data/lib/parsanol/grammar_builder.rb +179 -0
  48. data/lib/parsanol/incremental_parser.rb +182 -0
  49. data/lib/parsanol/interval_tree.rb +226 -0
  50. data/lib/parsanol/lazy_result.rb +179 -0
  51. data/lib/parsanol/mermaid.rb +142 -0
  52. data/lib/parsanol/native/batch_decoder.rb +255 -0
  53. data/lib/parsanol/native/dynamic.rb +238 -0
  54. data/lib/parsanol/native/parser.rb +102 -0
  55. data/lib/parsanol/native/serializer.rb +252 -0
  56. data/lib/parsanol/native/transformer.rb +604 -0
  57. data/lib/parsanol/native/types.rb +29 -0
  58. data/lib/parsanol/native.rb +223 -0
  59. data/lib/parsanol/optimizer.rb +85 -0
  60. data/lib/parsanol/optimizers/choice_optimizer.rb +78 -0
  61. data/lib/parsanol/optimizers/cut_inserter.rb +182 -0
  62. data/lib/parsanol/optimizers/lookahead_optimizer.rb +56 -0
  63. data/lib/parsanol/optimizers/quantifier_optimizer.rb +60 -0
  64. data/lib/parsanol/optimizers/sequence_optimizer.rb +97 -0
  65. data/lib/parsanol/options/zero_copy.rb +127 -0
  66. data/lib/parsanol/options.rb +21 -0
  67. data/lib/parsanol/parallel.rb +128 -0
  68. data/lib/parsanol/parser.rb +242 -0
  69. data/lib/parsanol/parslet.rb +151 -0
  70. data/lib/parsanol/pattern/binding.rb +91 -0
  71. data/lib/parsanol/pattern.rb +162 -0
  72. data/lib/parsanol/pool.rb +219 -0
  73. data/lib/parsanol/pools/array_pool.rb +75 -0
  74. data/lib/parsanol/pools/buffer_pool.rb +182 -0
  75. data/lib/parsanol/pools/position_pool.rb +92 -0
  76. data/lib/parsanol/pools/slice_pool.rb +64 -0
  77. data/lib/parsanol/position.rb +94 -0
  78. data/lib/parsanol/resettable.rb +29 -0
  79. data/lib/parsanol/result.rb +46 -0
  80. data/lib/parsanol/result_builder.rb +208 -0
  81. data/lib/parsanol/result_stream.rb +266 -0
  82. data/lib/parsanol/rig/rspec.rb +71 -0
  83. data/lib/parsanol/rope.rb +81 -0
  84. data/lib/parsanol/scope.rb +104 -0
  85. data/lib/parsanol/slice.rb +160 -0
  86. data/lib/parsanol/source/line_cache.rb +102 -0
  87. data/lib/parsanol/source.rb +185 -0
  88. data/lib/parsanol/source_location.rb +167 -0
  89. data/lib/parsanol/streaming_parser.rb +124 -0
  90. data/lib/parsanol/string_view.rb +198 -0
  91. data/lib/parsanol/transform.rb +226 -0
  92. data/lib/parsanol/version.rb +5 -0
  93. data/lib/parsanol/wasm/README.md +80 -0
  94. data/lib/parsanol/wasm/package.json +51 -0
  95. data/lib/parsanol/wasm/parsanol.js +252 -0
  96. data/lib/parsanol/wasm/parslet.d.ts +129 -0
  97. data/lib/parsanol/wasm_parser.rb +240 -0
  98. data/lib/parsanol.rb +278 -0
  99. data/parsanol.gemspec +67 -0
  100. metadata +279 -0
@@ -0,0 +1,252 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parsanol
4
+ # Grammar serializer for native parser
5
+ # Serializes Parslet atoms to JSON format expected by Rust parser
6
+ #
7
+ class GrammarSerializer
8
+ # Serialize a Parslet grammar (root atom) to JSON string
9
+ #
10
+ # @param root [Parsanol::Atoms::Base] The root atom of the grammar
11
+ # @return [String] JSON representation of the grammar
12
+ def self.serialize(root)
13
+ # Create fresh instance for each serialization
14
+ # (state is specific to each grammar)
15
+ new.serialize(root)
16
+ end
17
+
18
+ def initialize
19
+ @atoms = []
20
+ @atom_cache = {} # object_id => atom_id for deduplication
21
+ end
22
+
23
+ # Main serialization method
24
+ def serialize(root)
25
+ root_id = serialize_atom(root)
26
+
27
+ # Build JSON output directly to avoid intermediate Hash
28
+ # This is faster than creating a Hash and calling to_json
29
+ %({"atoms":#{@atoms.to_json},"root":#{root_id}})
30
+ end
31
+
32
+ private
33
+
34
+ # Serialize a single atom and return its atom_id
35
+ def serialize_atom(atom)
36
+ # Check cache for deduplication
37
+ cache_key = atom.object_id
38
+ return @atom_cache[cache_key] if @atom_cache.key?(cache_key)
39
+
40
+ # Entity atoms are special - they're just lazy references to other atoms
41
+ # Don't create a new atom, just resolve and return the referenced atom_id
42
+ return serialize_entity(atom) if atom.is_a?(Parsanol::Atoms::Entity)
43
+
44
+ # Serialize based on atom type first (recursively)
45
+ serialized = case atom
46
+ when Parsanol::Atoms::Str
47
+ serialize_str(atom)
48
+ when Parsanol::Atoms::Re
49
+ serialize_re(atom)
50
+ when Parsanol::Atoms::Sequence
51
+ serialize_sequence(atom)
52
+ when Parsanol::Atoms::Alternative
53
+ serialize_alternative(atom)
54
+ when Parsanol::Atoms::Repetition
55
+ serialize_repetition(atom)
56
+ when Parsanol::Atoms::Named
57
+ serialize_named(atom)
58
+ when Parsanol::Atoms::Lookahead
59
+ serialize_lookahead(atom)
60
+ when Parsanol::Atoms::Capture
61
+ serialize_capture(atom)
62
+ when Parsanol::Atoms::Scope
63
+ serialize_scope(atom)
64
+ when Parsanol::Atoms::Dynamic
65
+ serialize_dynamic(atom)
66
+ else
67
+ # Fallback for unknown atom types
68
+ serialize_unknown(atom)
69
+ end
70
+
71
+ # Now reserve an atom_id and cache
72
+ atom_id = @atoms.size
73
+ @atom_cache[cache_key] = atom_id
74
+ @atoms << serialized
75
+
76
+ atom_id
77
+ end
78
+
79
+ def serialize_str(atom)
80
+ {
81
+ "Str" => {
82
+ "pattern" => atom.str,
83
+ },
84
+ }
85
+ end
86
+
87
+ def serialize_re(atom)
88
+ # Ruby's Regexp#to_s produces "(?-mix:pattern)" format
89
+ # We need to extract just the pattern for the Rust parser
90
+ pattern = atom.match
91
+ pattern = ::Regexp.last_match(1) if pattern =~ /^\(\?[-mix]*:(.+)\)$/
92
+ {
93
+ "Re" => {
94
+ "pattern" => pattern,
95
+ },
96
+ }
97
+ end
98
+
99
+ def serialize_sequence(atom)
100
+ atom_ids = atom.parslets.map { |p| serialize_atom(p) }
101
+ {
102
+ "Sequence" => {
103
+ "atoms" => atom_ids,
104
+ },
105
+ }
106
+ end
107
+
108
+ def serialize_alternative(atom)
109
+ atom_ids = atom.alternatives.map { |p| serialize_atom(p) }
110
+ {
111
+ "Alternative" => {
112
+ "atoms" => atom_ids,
113
+ },
114
+ }
115
+ end
116
+
117
+ def serialize_repetition(atom)
118
+ {
119
+ "Repetition" => {
120
+ "atom" => serialize_atom(atom.parslet),
121
+ "min" => atom.min,
122
+ "max" => atom.max,
123
+ "tag" => atom.result_tag == :maybe ? "Maybe" : "Repetition",
124
+ },
125
+ }
126
+ end
127
+
128
+ def serialize_named(atom)
129
+ {
130
+ "Named" => {
131
+ "name" => atom.name.to_s,
132
+ "atom" => serialize_atom(atom.parslet),
133
+ },
134
+ }
135
+ end
136
+
137
+ def serialize_entity(atom)
138
+ # Entity is a lazy reference - resolve it to the actual parslet
139
+ # Cache FIRST before resolving to handle circular references
140
+ cache_key = atom.object_id
141
+
142
+ # Reserve an atom_id and cache it before resolving
143
+ # This prevents infinite recursion when a rule references itself
144
+ atom_id = @atoms.size
145
+ @atom_cache[cache_key] = atom_id
146
+
147
+ # Add a placeholder that will be replaced
148
+ @atoms << nil
149
+
150
+ parslet = begin
151
+ atom.parslet
152
+ rescue StandardError
153
+ nil
154
+ end
155
+
156
+ if parslet
157
+ # Serialize the resolved parslet inline (don't call serialize_atom to avoid double-caching)
158
+ serialized = case parslet
159
+ when Parsanol::Atoms::Str
160
+ serialize_str(parslet)
161
+ when Parsanol::Atoms::Re
162
+ serialize_re(parslet)
163
+ when Parsanol::Atoms::Sequence
164
+ serialize_sequence(parslet)
165
+ when Parsanol::Atoms::Alternative
166
+ serialize_alternative(parslet)
167
+ when Parsanol::Atoms::Repetition
168
+ serialize_repetition(parslet)
169
+ when Parsanol::Atoms::Named
170
+ serialize_named(parslet)
171
+ when Parsanol::Atoms::Entity
172
+ # Nested entity - just reference it via serialize_atom
173
+ { "Entity" => { "atom" => serialize_atom(parslet) } }
174
+ when Parsanol::Atoms::Lookahead
175
+ serialize_lookahead(parslet)
176
+ else
177
+ serialize_unknown(parslet)
178
+ end
179
+
180
+ # Replace the placeholder with the serialized atom
181
+ @atoms[atom_id] = serialized
182
+ else
183
+ # If the entity's block returns nil, create a placeholder that will fail
184
+ @atoms[atom_id] = {
185
+ "Str" => {
186
+ "pattern" => "\x00__UNIMPLEMENTED_ENTITY_#{atom.name}__",
187
+ },
188
+ }
189
+ end
190
+ atom_id
191
+ end
192
+
193
+ def serialize_lookahead(atom)
194
+ {
195
+ "Lookahead" => {
196
+ "atom" => serialize_atom(atom.bound_parslet),
197
+ "positive" => atom.positive,
198
+ },
199
+ }
200
+ end
201
+
202
+ def serialize_capture(atom)
203
+ # Capture stores matched text for later reference by Dynamic atoms.
204
+ # Now properly serialized for native parser support (parsanol-rs 0.3.0+).
205
+ {
206
+ "Capture" => {
207
+ "name" => atom.capture_key.to_s,
208
+ "atom" => serialize_atom(atom.inner_atom),
209
+ },
210
+ }
211
+ end
212
+
213
+ def serialize_scope(atom)
214
+ # Scope creates an isolated capture context.
215
+ # Captures made within scope are discarded when scope exits.
216
+ inner = begin
217
+ atom.block.call
218
+ rescue StandardError
219
+ nil
220
+ end
221
+ return serialize_unknown(atom) unless inner
222
+
223
+ {
224
+ "Scope" => {
225
+ "atom" => serialize_atom(inner),
226
+ },
227
+ }
228
+ end
229
+
230
+ def serialize_dynamic(atom)
231
+ # Dynamic evaluates a Ruby block at parse time.
232
+ # Register the block and get a callback ID for FFI.
233
+ callback_id = Parsanol::Native::Dynamic.register(atom.block)
234
+
235
+ {
236
+ "Dynamic" => {
237
+ "callback_id" => callback_id,
238
+ },
239
+ }
240
+ end
241
+
242
+ def serialize_unknown(_atom)
243
+ # For unsupported atom types, create a placeholder
244
+ # This will cause a parse error at runtime
245
+ {
246
+ "Str" => {
247
+ "pattern" => "", # Empty pattern that will never match
248
+ },
249
+ }
250
+ end
251
+ end
252
+ end