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