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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/packcr/context.rb +14 -5
- data/lib/packcr/generated/context.rb +184 -85
- data/lib/packcr/generated/node/action_node.rb +16 -1
- data/lib/packcr/generated/node/alternate_node.rb +47 -7
- data/lib/packcr/generated/node/capture_node.rb +16 -1
- data/lib/packcr/generated/node/charclass_node.rb +73 -6
- data/lib/packcr/generated/node/eof_node.rb +8 -1
- data/lib/packcr/generated/node/error_node.rb +8 -1
- data/lib/packcr/generated/node/expand_node.rb +8 -1
- data/lib/packcr/generated/node/predicate_node.rb +37 -2
- data/lib/packcr/generated/node/quantity_node.rb +56 -2
- data/lib/packcr/generated/node/reference_node.rb +11 -2
- data/lib/packcr/generated/node/rule_node.rb +32 -1
- data/lib/packcr/generated/node/sequence_node.rb +19 -1
- data/lib/packcr/generated/node/string_node.rb +50 -2
- data/lib/packcr/generator.rb +4 -3
- data/lib/packcr/node/action_node.rb +2 -2
- data/lib/packcr/node/alternate_node.rb +2 -2
- data/lib/packcr/node/capture_node.rb +2 -2
- data/lib/packcr/node/charclass_node.rb +15 -15
- data/lib/packcr/node/eof_node.rb +2 -2
- data/lib/packcr/node/error_node.rb +2 -2
- data/lib/packcr/node/expand_node.rb +2 -2
- data/lib/packcr/node/predicate_node.rb +3 -3
- data/lib/packcr/node/quantity_node.rb +4 -4
- data/lib/packcr/node/reference_node.rb +5 -4
- data/lib/packcr/node/rule_node.rb +4 -3
- data/lib/packcr/node/sequence_node.rb +2 -2
- data/lib/packcr/node/string_node.rb +17 -3
- data/lib/packcr/parser.rb +403 -254
- data/lib/packcr/stream.rb +1 -1
- data/lib/packcr/templates/context/source.c.erb +30 -26
- data/lib/packcr/templates/context/source.rb.erb +160 -159
- data/lib/packcr/templates/context/source.rs.erb +627 -0
- data/lib/packcr/templates/node/action.rs.erb +6 -0
- data/lib/packcr/templates/node/alternate.rs.erb +38 -0
- data/lib/packcr/templates/node/capture.rs.erb +13 -0
- data/lib/packcr/templates/node/charclass_utf8.rs.erb +41 -0
- data/lib/packcr/templates/node/predicate_neg.rs.erb +24 -0
- data/lib/packcr/templates/node/quantity_many.rs.erb +77 -0
- data/lib/packcr/templates/node/reference.rs.erb +3 -0
- data/lib/packcr/templates/node/rule.rs.erb +43 -0
- data/lib/packcr/templates/node/sequence.rs.erb +12 -0
- data/lib/packcr/templates/node/string_many.rs.erb +10 -0
- data/lib/packcr/templates/node/string_many_reverse.rs.erb +7 -0
- data/lib/packcr/templates/node/string_one.rs.erb +9 -0
- data/lib/packcr/templates/node/string_one_reverse.rs.erb +6 -0
- data/lib/packcr/util.rb +9 -0
- data/lib/packcr/version.rb +1 -1
- 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 -%>
|