packcr 0.0.8 → 0.1.1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/packcr/context.rb +14 -5
  4. data/lib/packcr/generated/context.rb +184 -85
  5. data/lib/packcr/generated/node/action_node.rb +16 -1
  6. data/lib/packcr/generated/node/alternate_node.rb +47 -7
  7. data/lib/packcr/generated/node/capture_node.rb +16 -1
  8. data/lib/packcr/generated/node/charclass_node.rb +73 -6
  9. data/lib/packcr/generated/node/eof_node.rb +8 -1
  10. data/lib/packcr/generated/node/error_node.rb +8 -1
  11. data/lib/packcr/generated/node/expand_node.rb +8 -1
  12. data/lib/packcr/generated/node/predicate_node.rb +37 -2
  13. data/lib/packcr/generated/node/quantity_node.rb +56 -2
  14. data/lib/packcr/generated/node/reference_node.rb +11 -2
  15. data/lib/packcr/generated/node/rule_node.rb +32 -1
  16. data/lib/packcr/generated/node/sequence_node.rb +19 -1
  17. data/lib/packcr/generated/node/string_node.rb +50 -2
  18. data/lib/packcr/generator.rb +4 -3
  19. data/lib/packcr/node/action_node.rb +2 -2
  20. data/lib/packcr/node/alternate_node.rb +2 -2
  21. data/lib/packcr/node/capture_node.rb +2 -2
  22. data/lib/packcr/node/charclass_node.rb +15 -15
  23. data/lib/packcr/node/eof_node.rb +2 -2
  24. data/lib/packcr/node/error_node.rb +2 -2
  25. data/lib/packcr/node/expand_node.rb +2 -2
  26. data/lib/packcr/node/predicate_node.rb +3 -3
  27. data/lib/packcr/node/quantity_node.rb +4 -4
  28. data/lib/packcr/node/reference_node.rb +5 -4
  29. data/lib/packcr/node/rule_node.rb +4 -3
  30. data/lib/packcr/node/sequence_node.rb +2 -2
  31. data/lib/packcr/node/string_node.rb +17 -3
  32. data/lib/packcr/parser.rb +403 -254
  33. data/lib/packcr/stream.rb +1 -1
  34. data/lib/packcr/templates/context/source.c.erb +30 -26
  35. data/lib/packcr/templates/context/source.rb.erb +160 -159
  36. data/lib/packcr/templates/context/source.rs.erb +627 -0
  37. data/lib/packcr/templates/node/action.rs.erb +6 -0
  38. data/lib/packcr/templates/node/alternate.rs.erb +38 -0
  39. data/lib/packcr/templates/node/capture.rs.erb +13 -0
  40. data/lib/packcr/templates/node/charclass_utf8.rs.erb +41 -0
  41. data/lib/packcr/templates/node/predicate_neg.rs.erb +24 -0
  42. data/lib/packcr/templates/node/quantity_many.rs.erb +77 -0
  43. data/lib/packcr/templates/node/reference.rs.erb +3 -0
  44. data/lib/packcr/templates/node/rule.rs.erb +43 -0
  45. data/lib/packcr/templates/node/sequence.rs.erb +12 -0
  46. data/lib/packcr/templates/node/string_many.rs.erb +10 -0
  47. data/lib/packcr/templates/node/string_many_reverse.rs.erb +7 -0
  48. data/lib/packcr/templates/node/string_one.rs.erb +9 -0
  49. data/lib/packcr/templates/node/string_one_reverse.rs.erb +6 -0
  50. data/lib/packcr/util.rb +9 -0
  51. data/lib/packcr/version.rb +1 -1
  52. metadata +20 -67
@@ -0,0 +1,627 @@
1
+ /* A packrat parser generated by PackCR <%= Packcr::VERSION %> */
2
+
3
+ use std::cell::RefCell;
4
+ use std::collections::{HashMap, HashSet};
5
+ use std::io::Read;
6
+ use std::rc::Rc;
7
+ <%- if !code(:esource).empty? -%>
8
+
9
+ <%- code(:esource).each do |code| -%>
10
+ <%= stream.get_code_block(code, 0, @iname) -%>
11
+ <%- end -%>
12
+ <%- end -%>
13
+ <%- use_value = @root.rules.map {|r| r.vars.size }.max > 0 -%>
14
+
15
+ struct LrMemoTable {
16
+ memos: HashMap<usize, LrMemoMap>,
17
+ }
18
+ impl LrMemoTable {
19
+ fn new() -> Self {
20
+ Self {
21
+ memos: HashMap::new(),
22
+ }
23
+ }
24
+
25
+ fn clear(&mut self) {
26
+ self.memos.clear();
27
+ }
28
+
29
+ fn set(&mut self, index: usize, rule: Rule, memo: LrMemo) {
30
+ let memo_map = self.memos.entry(index).or_default();
31
+ memo_map.insert(rule, memo);
32
+ }
33
+
34
+ fn get(&mut self, index: usize, rule: Rule) -> &mut LrMemo {
35
+ self.memos.get_mut(&index).unwrap().get_mut(&rule).unwrap()
36
+ }
37
+ fn has(&self, index: usize, rule: Rule) -> bool {
38
+ self.memos
39
+ .get(&index)
40
+ .is_some_and(|memo_map| memo_map.contains_key(&rule))
41
+ }
42
+ }
43
+
44
+ struct LrMemo {
45
+ offset: usize,
46
+ answer: Option<Rc<RefCell<ThunkChunk>>>,
47
+ grow: bool,
48
+ }
49
+
50
+ impl LrMemo {
51
+ fn new(offset: usize) -> Self {
52
+ Self {
53
+ offset,
54
+ answer: None,
55
+ grow: false,
56
+ }
57
+ }
58
+
59
+ fn start_grow(&mut self) -> bool {
60
+ if !self.grow && self.answer.is_none() {
61
+ self.grow = true;
62
+ true
63
+ } else {
64
+ false
65
+ }
66
+ }
67
+
68
+ fn update(&mut self, answer: Option<ThunkChunk>, offset: usize) {
69
+ self.answer = answer.map(|c| Rc::new(RefCell::new(c)));
70
+ self.offset = offset;
71
+ }
72
+
73
+ fn clone_answer(&mut self) -> Option<Rc<RefCell<ThunkChunk>>> {
74
+ self.answer.as_ref().map(Rc::clone)
75
+ }
76
+ }
77
+
78
+ struct ThunkChunk {
79
+ thunks: Rc<RefCell<Vec<Thunk>>>,
80
+ capts: CaptureTable,
81
+ pos: usize,
82
+ values: ValueTable,
83
+ }
84
+
85
+ impl ThunkChunk {
86
+ fn new(pos: usize) -> Self {
87
+ Self {
88
+ values: ValueTable::new(),
89
+ capts: CaptureTable::new(),
90
+ thunks: Rc::new(RefCell::new(Vec::new())),
91
+ pos,
92
+ }
93
+ }
94
+
95
+ fn push_leaf(
96
+ &self,
97
+ action: Action,
98
+ end: usize,
99
+ value_indices: &[usize],
100
+ capt_indices: &[usize],
101
+ ) {
102
+ {
103
+ let start = self.pos;
104
+ let mut value_refs = HashMap::new();
105
+ for &index in value_indices {
106
+ value_refs.insert(index, ValueRef::new(index, self.values.clone()));
107
+ }
108
+ let mut capts = HashMap::new();
109
+ for &index in capt_indices {
110
+ capts.insert(index, self.capts[index].clone());
111
+ }
112
+ let leaf = Thunk::Leaf(ThunkLeaf::new(action, start, end, value_refs, capts));
113
+ self.thunks.borrow_mut().push(leaf);
114
+ }
115
+ }
116
+
117
+ fn value_ref(&self, index: usize) -> ValueRef {
118
+ ValueRef::new(index, self.values.clone())
119
+ }
120
+ }
121
+
122
+ enum Thunk {
123
+ Leaf(ThunkLeaf),
124
+ Node(ThunkNode),
125
+ }
126
+ impl Thunk {
127
+ fn do_action(&self, processor: &ThunkProcessor, value: ValueRef) -> Value {
128
+ match self {
129
+ Thunk::Leaf(leaf) => leaf.do_action(processor, value),
130
+ Thunk::Node(node) => node.do_action(processor),
131
+ }
132
+ }
133
+ }
134
+
135
+ #[allow(dead_code)]
136
+ struct ThunkLeaf {
137
+ value_refs: HashMap<usize, ValueRef>,
138
+ capts: HashMap<usize, Capture>,
139
+ capt0: Capture,
140
+ action: Action,
141
+ }
142
+ impl ThunkLeaf {
143
+ fn new(
144
+ action: Action,
145
+ start: usize,
146
+ end: usize,
147
+ value_refs: HashMap<usize, ValueRef>,
148
+ capts: HashMap<usize, Capture>,
149
+ ) -> Self {
150
+ Self {
151
+ value_refs,
152
+ capts,
153
+ capt0: Capture { start, end },
154
+ action,
155
+ }
156
+ }
157
+
158
+ fn do_action(&self, processor: &ThunkProcessor, mut value: ValueRef) -> Value {
159
+ value.with_mut(|v| {
160
+ processor.call_action(self.action, self, v);
161
+ });
162
+ value.get()
163
+ }
164
+ <%- if use_value -%>
165
+
166
+ fn values(&self) -> HashMap<usize, Value> {
167
+ self.value_refs.iter().map(|(k, v)| (*k, v.get())).collect()
168
+ }
169
+ <%- end -%>
170
+ }
171
+
172
+ struct ThunkNode {
173
+ thunks: Rc<RefCell<Vec<Thunk>>>,
174
+ value: ValueRef,
175
+ }
176
+ impl ThunkNode {
177
+ fn do_action(&self, processor: &ThunkProcessor) -> Value {
178
+ let mut v = 0;
179
+ for thunk in self.thunks.borrow_mut().iter_mut() {
180
+ v = thunk.do_action(processor, self.value.clone());
181
+ }
182
+ v
183
+ }
184
+ }
185
+
186
+ #[derive(Clone)]
187
+ struct Capture {
188
+ start: usize,
189
+ end: usize,
190
+ }
191
+
192
+ type Value = i32;
193
+
194
+ struct ValueTable {
195
+ table: Rc<RefCell<HashMap<usize, Value>>>,
196
+ }
197
+ impl ValueTable {
198
+ fn new() -> Self {
199
+ Self {
200
+ table: Rc::new(RefCell::new(HashMap::new())),
201
+ }
202
+ }
203
+ <%- if use_value -%>
204
+
205
+ fn clear(&mut self) {
206
+ self.table.borrow_mut().clear();
207
+ }
208
+ <%- end -%>
209
+
210
+ fn with_mut<F>(&mut self, index: usize, f: F)
211
+ where
212
+ F: FnOnce(&mut Value),
213
+ {
214
+ let mut table = self.table.borrow_mut();
215
+ let value = table.entry(index).or_insert(0);
216
+ f(value);
217
+ }
218
+ }
219
+ impl Clone for ValueTable {
220
+ fn clone(&self) -> Self {
221
+ Self {
222
+ table: self.table.clone(),
223
+ }
224
+ }
225
+ }
226
+
227
+ struct ValueRef {
228
+ values: ValueTable,
229
+ index: usize,
230
+ }
231
+ impl ValueRef {
232
+ fn new(index: usize, values: ValueTable) -> Self {
233
+ Self { index, values }
234
+ }
235
+
236
+ fn with_mut<F>(&mut self, f: F)
237
+ where
238
+ F: FnOnce(&mut i32),
239
+ {
240
+ self.values.with_mut(self.index, f);
241
+ }
242
+
243
+ fn get(&self) -> i32 {
244
+ *self.values.table.borrow().get(&self.index).unwrap_or(&0)
245
+ }
246
+ }
247
+ impl Clone for ValueRef {
248
+ fn clone(&self) -> Self {
249
+ Self {
250
+ index: self.index,
251
+ values: self.values.clone(),
252
+ }
253
+ }
254
+ }
255
+
256
+ struct CaptureTable {
257
+ table: HashMap<usize, Capture>,
258
+ len: usize,
259
+ }
260
+
261
+ type RuleSet = HashSet<Rule>;
262
+ type RuleLimit = Option<RuleSet>;
263
+
264
+ type LrMemoMap = HashMap<Rule, LrMemo>;
265
+
266
+ impl CaptureTable {
267
+ fn new() -> Self {
268
+ Self {
269
+ table: HashMap::new(),
270
+ len: 0,
271
+ }
272
+ }
273
+
274
+ fn resize(&mut self, len: usize) {
275
+ let current_len = self.len;
276
+ if len > current_len {
277
+ for i in current_len..len {
278
+ self.table.insert(i, Capture { start: 0, end: 0 });
279
+ }
280
+ } else if len < current_len {
281
+ for i in len..current_len {
282
+ self.table.remove(&i);
283
+ }
284
+ }
285
+ self.len = len;
286
+ }
287
+ }
288
+ impl std::ops::Index<usize> for CaptureTable {
289
+ type Output = Capture;
290
+
291
+ fn index(&self, index: usize) -> &Self::Output {
292
+ &self.table[&index]
293
+ }
294
+ }
295
+ impl std::ops::IndexMut<usize> for CaptureTable {
296
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
297
+ if self.len <= index {
298
+ self.resize(index + 1);
299
+ }
300
+ self.table.get_mut(&index).unwrap()
301
+ }
302
+ }
303
+
304
+ struct Input {
305
+ input: Box<dyn std::io::Read>,
306
+ start_position: usize,
307
+ position_offset: usize,
308
+ buffer: String,
309
+ closed: bool,
310
+ }
311
+
312
+ impl Input {
313
+ fn new(input: impl std::io::Read + 'static) -> Self {
314
+ Self {
315
+ input: Box::new(input),
316
+ start_position: 0,
317
+ position_offset: 0,
318
+ buffer: String::new(),
319
+ closed: false,
320
+ }
321
+ }
322
+
323
+ fn refill_buffer(&mut self, num: usize) -> usize {
324
+ let mut len = self.buffer.len();
325
+ if len >= self.position_offset + num {
326
+ return len - self.position_offset;
327
+ }
328
+
329
+ let mut input_buffer = [0u8; 1024];
330
+
331
+ while len < self.position_offset + num {
332
+ match self.input.read(&mut input_buffer) {
333
+ Ok(0) => break,
334
+ Ok(bytes_read) => {
335
+ let s = std::string::String::from_utf8_lossy(&input_buffer[..bytes_read]);
336
+ self.buffer.push_str(&s);
337
+ }
338
+ Err(_) => break,
339
+ }
340
+ len = self.buffer.len();
341
+ }
342
+
343
+ len - self.position_offset
344
+ }
345
+
346
+ fn commit_buffer(&mut self) {
347
+ let position_offset = self.position_offset;
348
+
349
+ self.buffer.drain(..position_offset);
350
+
351
+ self.start_position += position_offset;
352
+ self.position_offset = 0;
353
+ }
354
+
355
+ #[allow(dead_code)]
356
+ fn get_char_as_utf32(&mut self) -> (i32, usize) {
357
+ if self.refill_buffer(1) < 1 {
358
+ return (0, 0);
359
+ }
360
+
361
+ let current_position = self.position_offset;
362
+ let remaining_chars: &str = &self.buffer[current_position..];
363
+
364
+ if let Some(ch) = remaining_chars.chars().next() {
365
+ let bytes_used = ch.len_utf8();
366
+
367
+ if self.refill_buffer(bytes_used) < bytes_used {
368
+ return (0, 0);
369
+ }
370
+
371
+ let utf32_value = ch as u32 as i32;
372
+
373
+ return (utf32_value, bytes_used);
374
+ }
375
+
376
+ (0, 0)
377
+ }
378
+
379
+ fn back_to(&mut self, memo: &mut LrMemo) -> Option<Rc<RefCell<ThunkChunk>>> {
380
+ self.position_offset = memo.offset;
381
+ memo.clone_answer()
382
+ }
383
+ }
384
+
385
+ const NOP: Result<usize, usize> = Ok(0);
386
+ const fn throw(label: usize) -> Result<usize, usize> {
387
+ Err(label)
388
+ }
389
+
390
+ fn catch(label: usize, f: impl FnOnce() -> Result<usize, usize>) -> Result<usize, usize> {
391
+ match f() {
392
+ Ok(_) => NOP,
393
+ Err(e) if e == label => NOP,
394
+ Err(e) => throw(e),
395
+ }
396
+ }
397
+
398
+ struct <%= class_name %> {
399
+ level: usize,
400
+ memos: LrMemoTable,
401
+ input: Input,
402
+ }
403
+
404
+ impl <%= class_name %> {
405
+ fn new(input: impl std::io::Read + 'static) -> Self {
406
+ Self {
407
+ level: 0,
408
+ memos: LrMemoTable::new(),
409
+ input: Input::new(input),
410
+ }
411
+ }
412
+
413
+ fn parse(&mut self) -> Option<Value> {
414
+ if self.input.closed {
415
+ return None;
416
+ }
417
+
418
+ let mut answer = ThunkChunk::new(0);
419
+ let pos = self.input.start_position;
420
+ <%- if !@root.rules.empty? -%>
421
+
422
+ let value = {
423
+ let node = self.rule_thunk_node(
424
+ Rule::<%= Packcr.camelize(@root.rules[0].name) %>,
425
+ &mut answer,
426
+ 0,
427
+ self.input.position_offset,
428
+ &None,
429
+ );
430
+ self.memos.clear();
431
+ node.map(|node| node.do_action(&ThunkProcessor::new(&self.input.buffer)))
432
+ };
433
+ self.input.commit_buffer();
434
+ if pos == self.input.start_position || self.input.refill_buffer(1) < 1 {
435
+ self.input.closed = true;
436
+ }
437
+ value
438
+ <%- end -%>
439
+ }
440
+
441
+ fn grow_lr(&mut self, rule: Rule, offset: usize) {
442
+ loop {
443
+ let old_offset = self.input.position_offset;
444
+ self.input.position_offset = offset;
445
+
446
+ let answer = self.call_rule(rule, offset, Some(RuleSet::new()));
447
+ match answer {
448
+ Some(answer) if self.input.position_offset > old_offset => {
449
+ let memo = self.memos.get(offset, rule);
450
+ memo.update(Some(answer), self.input.position_offset);
451
+ }
452
+ _ => {
453
+ return;
454
+ }
455
+ }
456
+ }
457
+ }
458
+
459
+ fn rule_answer_without_limits(&mut self, rule: Rule) -> Option<Rc<RefCell<ThunkChunk>>> {
460
+ let offset = self.input.position_offset;
461
+ if !self.memos.has(offset, rule) {
462
+ let memo = LrMemo::new(offset);
463
+ self.memos.set(offset, rule, memo);
464
+ let answer = self.call_rule(rule, offset, None);
465
+
466
+ let memo = self.memos.get(offset, rule);
467
+ memo.update(answer, self.input.position_offset);
468
+ if !memo.grow {
469
+ return self.input.back_to(memo);
470
+ }
471
+ self.grow_lr(rule, offset);
472
+
473
+ let memo = self.memos.get(offset, rule);
474
+ memo.grow = false;
475
+ return self.input.back_to(memo);
476
+ }
477
+
478
+ let memo = self.memos.get(offset, rule);
479
+ if memo.start_grow() {
480
+ return None;
481
+ }
482
+ self.input.back_to(memo)
483
+ }
484
+
485
+ fn rule_answer_with_limits(
486
+ &mut self,
487
+ rule: Rule,
488
+ limits: RuleSet,
489
+ ) -> Option<Rc<RefCell<ThunkChunk>>> {
490
+ let offset = self.input.position_offset;
491
+ let answer = self.call_rule(rule, offset, Some(limits));
492
+ if !self.memos.has(offset, rule) {
493
+ return answer.map(|answer| Rc::new(RefCell::new(answer)));
494
+ }
495
+
496
+ let memo = self.memos.get(offset, rule);
497
+ if self.input.position_offset > memo.offset {
498
+ memo.update(answer, self.input.position_offset);
499
+ }
500
+ self.input.back_to(memo)
501
+ }
502
+
503
+ fn apply_rule(
504
+ &mut self,
505
+ rule: Rule,
506
+ parent: &mut ThunkChunk,
507
+ value_index: usize,
508
+ offset: usize,
509
+ limits: &RuleLimit,
510
+ ) -> bool {
511
+ let node = self.rule_thunk_node(rule, parent, value_index, offset, limits);
512
+ node.is_some_and(|node| {
513
+ parent.thunks.borrow_mut().push(Thunk::Node(node));
514
+ true
515
+ })
516
+ }
517
+
518
+ fn rule_thunk_node(
519
+ &mut self,
520
+ rule: Rule,
521
+ parent: &ThunkChunk,
522
+ value_index: usize,
523
+ offset: usize,
524
+ limits: &RuleLimit,
525
+ ) -> Option<ThunkNode> {
526
+ match limits {
527
+ Some(limit_set)
528
+ if self.input.position_offset == offset && !limit_set.contains(&rule) =>
529
+ {
530
+ self.rule_answer_with_limits(rule, limits.clone().unwrap())
531
+ }
532
+ _ => self.rule_answer_without_limits(rule),
533
+ }
534
+ .map(|answer| ThunkNode {
535
+ thunks: answer.borrow().thunks.clone(),
536
+ value: parent.value_ref(value_index),
537
+ })
538
+ }
539
+
540
+ fn call_rule(
541
+ &mut self,
542
+ rule: Rule,
543
+ offset: usize,
544
+ mut limits: RuleLimit,
545
+ ) -> Option<ThunkChunk> {
546
+ if let Some(ref mut limits) = limits {
547
+ limits.insert(rule);
548
+ }
549
+ match rule {
550
+ <%- @root.rules.each do |rule| -%>
551
+ Rule::<%= Packcr.camelize(rule.name) %> => self.evaluate_rule_<%= rule.name %>(offset, limits),
552
+ <%- end -%>
553
+ }
554
+ }
555
+ <%- @root.rules.each do |rule| -%>
556
+
557
+ <%- gen = ::Packcr::Generator.new(rule, @ascii, @location, :rs) -%>
558
+ <%- %><%= gen.generate_code(rule, 0, 4, false) -%>
559
+ <%- end -%>
560
+ }
561
+
562
+ struct ThunkProcessor<'a> {
563
+ buffer: &'a str,
564
+ }
565
+
566
+ impl<'a> ThunkProcessor<'a> {
567
+ fn new(buffer: &'a str) -> Self {
568
+ Self { buffer }
569
+ }
570
+
571
+ fn call_action(&self, action: Action, thunk: &ThunkLeaf, value: &mut i32) {
572
+ match action {
573
+ <%- @root.rules.each do |rule| -%>
574
+ <%- rule.codes.each do |code| -%>
575
+ Action::<%= Packcr.camelize(rule.name) %><%= code.index %> => self.action_<%= rule.name %>_<%= code.index %>(thunk, value),
576
+ <%- end -%>
577
+ <%- end -%>
578
+ }
579
+ }
580
+ <%- @root.rules.each do |rule| -%>
581
+ <%- rule.codes.each do |code| -%>
582
+
583
+ #[allow(unused_variables, non_snake_case)]
584
+ fn action_<%= rule.name %>_<%= code.index %>(&self, leaf: &ThunkLeaf, out: &mut i32) {
585
+ <%- code.vars.each_with_index do |ref, i| -%>
586
+ <%- if i == 0 -%>
587
+ let values = leaf.values();
588
+ <%- end -%>
589
+ let <%= ref.var %> = values[&<%= ref.index %>];
590
+ <%- end -%>
591
+ let _0 = {
592
+ let capt = &leaf.capt0;
593
+ &self.buffer[(capt.start)..(capt.end)]
594
+ };
595
+ <%- code.capts.size.times do |i| -%>
596
+ let _<%= i + 1 %> = {
597
+ let capt = &leaf.capts[&<%= i %>];
598
+ &self.buffer[(capt.start)..(capt.end)]
599
+ };
600
+ <%- end -%>
601
+ <%= stream.get_code_block(code.code, 4, @iname) -%>
602
+ }
603
+ <%- end -%>
604
+ <%- end -%>
605
+ }
606
+
607
+ #[derive(Copy, Clone)]
608
+ enum Action {
609
+ <%- @root.rules.each do |rule| -%>
610
+ <%- rule.codes.each do |code| -%>
611
+ <%= Packcr.camelize(rule.name) %><%= code.index %>,
612
+ <%- end -%>
613
+ <%- end -%>
614
+ }
615
+
616
+ #[derive(Copy, Clone, PartialEq, Eq, Hash)]
617
+ enum Rule {
618
+ <%- @root.rules.each do |rule| -%>
619
+ <%= Packcr.camelize(rule.name) %>,
620
+ <%- end -%>
621
+ }
622
+ <%- if !code(:lsource).empty? -%>
623
+
624
+ <%- code(:lsource).each do |code| -%>
625
+ <%= stream.get_code_block(code, 0, @iname) -%>
626
+ <%- end -%>
627
+ <%- end -%>
@@ -0,0 +1,6 @@
1
+ answer.push_leaf(<% -%>
2
+ <%- %>Action::<%= Packcr.camelize(gen.rule.name) %><%= index %>, <% -%>
3
+ <%- %>self.input.position_offset, <% -%>
4
+ <%- %>&[<% vars.each_with_index do |var, i| %><%= ", " if i > 0 %><%= var.index %><% end %>], <% -%>
5
+ <%- %>&[<% capts.each_with_index do |capt, i| %><%= ", " if i > 0 %><%= capt.index %><% end %>]<% -%>
6
+ );
@@ -0,0 +1,38 @@
1
+ <%- m = gen.next_label -%>
2
+ catch(<%= m %>, || {
3
+ let p = self.input.position_offset;
4
+ <%- if gen.location -%>
5
+ TODO
6
+ <%- end -%>
7
+ <%- nodes.each_with_index do |expr, i| -%>
8
+ <%- c = i + 1 < nodes.length -%>
9
+ <%- if expr.reversible?(gen) -%>
10
+ <%- %><%= gen.generate_code(expr, m, 4, false, reverse: true, oncut: onfail) -%>
11
+ <%- else -%>
12
+ <%- l = gen.next_label -%>
13
+ <%- r = expr.reachability -%>
14
+ <%- if r == Packcr::CODE_REACH__ALWAYS_SUCCEED -%>
15
+ catch(<%= l %>, || {
16
+ <%- %><%= gen.generate_code(expr, l, 8, false, oncut: onfail) -%>
17
+ <%- if c -%>
18
+ // unreachable codes omitted
19
+ <%- end -%>
20
+ NOP
21
+ })?
22
+ <%- break -%>
23
+ <%- else -%>
24
+ catch(<%= l %>, || {
25
+ <%- %><%= gen.generate_code(expr, l, 8, false, oncut: onfail) -%>
26
+ throw(<%= m %>)
27
+ })?;
28
+ <%- end -%>
29
+ <%- end -%>
30
+ self.input.position_offset = p;
31
+ <%- if gen.location -%>
32
+ TODO
33
+ <%- end -%>
34
+ <%- if !c -%>
35
+ throw(<%= onfail %>)
36
+ <%- end -%>
37
+ <%- end -%>
38
+ })?;
@@ -0,0 +1,13 @@
1
+ let p_inner = self.input.position_offset;
2
+ <%- if gen.location -%>
3
+ TODO
4
+ <%- end -%>
5
+ {
6
+ <%- %><%= gen.generate_code(expr, onfail, 4, false) -%>
7
+ }
8
+ let q = self.input.position_offset;
9
+ answer.capts[<%= index %>].start = p_inner;
10
+ answer.capts[<%= index %>].end = q;
11
+ <%- if gen.location -%>
12
+ TODO
13
+ <%- end -%>