meta_language/grammar/inference/
sequitur.rs1use std::collections::{BTreeMap, VecDeque};
11
12use crate::grammar::{Grammar, GrammarExpr, GrammarFormat, GrammarRule};
13
14pub type Symbol = String;
16
17type NodeId = usize;
18type RuleId = usize;
19
20const START_RULE: RuleId = 0;
21
22#[must_use]
31pub fn run_sequitur(sequence: &[Symbol]) -> Grammar {
32 let mut builder = Sequitur::new();
33 for symbol in sequence {
34 builder.append(symbol.clone());
35 }
36 builder.finish()
37}
38
39#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
40enum SymRef {
41 Terminal(Symbol),
42 Rule(RuleId),
43}
44
45#[derive(Clone, Debug)]
46struct SymbolNode {
47 value: SymRef,
48 prev: Option<NodeId>,
49 next: Option<NodeId>,
50 rule: RuleId,
51 alive: bool,
52}
53
54#[derive(Clone, Debug)]
55struct RuleState {
56 head: Option<NodeId>,
57 tail: Option<NodeId>,
58 active: bool,
59 ref_count: usize,
60}
61
62impl RuleState {
63 const fn active() -> Self {
64 Self {
65 head: None,
66 tail: None,
67 active: true,
68 ref_count: 0,
69 }
70 }
71}
72
73#[derive(Debug)]
74struct Sequitur {
75 nodes: Vec<SymbolNode>,
76 rules: Vec<RuleState>,
77 digrams: BTreeMap<(SymRef, SymRef), NodeId>,
78 digram_queue: VecDeque<NodeId>,
79 utility_queue: VecDeque<RuleId>,
80}
81
82impl Sequitur {
83 fn new() -> Self {
84 Self {
85 nodes: Vec::new(),
86 rules: vec![RuleState::active()],
87 digrams: BTreeMap::new(),
88 digram_queue: VecDeque::new(),
89 utility_queue: VecDeque::new(),
90 }
91 }
92
93 fn append(&mut self, terminal: Symbol) {
94 let node = self.append_node(START_RULE, SymRef::Terminal(terminal));
95 if let Some(prev) = self.nodes[node].prev {
96 self.queue_digram(prev);
97 }
98 self.settle();
99 }
100
101 fn finish(mut self) -> Grammar {
102 self.settle();
103
104 let names = self.final_rule_names();
105 let mut grammar = Grammar::new().with_source_format(GrammarFormat::Inferred);
106 grammar.add_rule(GrammarRule::new(
107 "start",
108 GrammarExpr::Sequence(self.rule_exprs(START_RULE, &names)),
109 ));
110
111 for rule_id in 1..self.rules.len() {
112 if self.rules[rule_id].active {
113 let name = names
114 .get(&rule_id)
115 .expect("active generated rules must be named")
116 .clone();
117 grammar.add_rule(GrammarRule::new(
118 name,
119 GrammarExpr::Sequence(self.rule_exprs(rule_id, &names)),
120 ));
121 }
122 }
123
124 grammar.set_start("start");
125 grammar
126 }
127
128 fn settle(&mut self) {
129 while !self.digram_queue.is_empty() || !self.utility_queue.is_empty() {
130 if let Some(start) = self.digram_queue.pop_front() {
131 self.enforce_digram_at(start);
132 } else if let Some(rule_id) = self.utility_queue.pop_front() {
133 self.enforce_rule_utility(rule_id);
134 }
135 }
136 }
137
138 fn append_node(&mut self, rule: RuleId, value: SymRef) -> NodeId {
139 self.increment_ref_in_value(&value);
140
141 let node = self.nodes.len();
142 let prev = self.rules[rule].tail;
143 self.nodes.push(SymbolNode {
144 value,
145 prev,
146 next: None,
147 rule,
148 alive: true,
149 });
150
151 if let Some(prev) = prev {
152 self.nodes[prev].next = Some(node);
153 } else {
154 self.rules[rule].head = Some(node);
155 }
156 self.rules[rule].tail = Some(node);
157
158 node
159 }
160
161 fn insert_node_after(&mut self, previous: NodeId, value: SymRef) -> NodeId {
162 self.increment_ref_in_value(&value);
163
164 let node = self.nodes.len();
165 let rule = self.nodes[previous].rule;
166 let next = self.nodes[previous].next;
167 self.nodes.push(SymbolNode {
168 value,
169 prev: Some(previous),
170 next,
171 rule,
172 alive: true,
173 });
174
175 self.nodes[previous].next = Some(node);
176 if let Some(next) = next {
177 self.nodes[next].prev = Some(node);
178 } else {
179 self.rules[rule].tail = Some(node);
180 }
181
182 node
183 }
184
185 fn enforce_digram_at(&mut self, start: NodeId) {
186 let Some(key) = self.digram_key(start) else {
187 return;
188 };
189
190 let Some(existing) = self.digrams.get(&key).copied() else {
191 self.digrams.insert(key, start);
192 return;
193 };
194
195 if existing == start {
196 return;
197 }
198
199 if self.digram_key(existing).as_ref() != Some(&key) {
200 self.digrams.remove(&key);
201 self.queue_digram(start);
202 return;
203 }
204
205 if self.occurrences_overlap(existing, start) {
206 return;
207 }
208
209 if let Some(rule_id) = self.rule_matching_body(existing) {
210 self.replace_digram_with_rule(start, rule_id);
211 } else {
212 self.create_rule_for_duplicate(key, existing, start);
213 }
214 }
215
216 fn create_rule_for_duplicate(
217 &mut self,
218 key: (SymRef, SymRef),
219 existing: NodeId,
220 current: NodeId,
221 ) {
222 if self.digram_key(existing).as_ref() != Some(&key)
223 || self.digram_key(current).as_ref() != Some(&key)
224 {
225 self.queue_digram(current);
226 return;
227 }
228
229 let rule_id = self.rules.len();
230 self.rules.push(RuleState::active());
231 let first = self.append_node(rule_id, key.0.clone());
232 self.append_node(rule_id, key.1.clone());
233
234 self.replace_digram_with_rule(existing, rule_id);
235 if self.digram_key(current).as_ref() == Some(&key) {
236 self.replace_digram_with_rule(current, rule_id);
237 }
238
239 if self.rules[rule_id].active {
240 self.digrams.insert(key, first);
241 if self.rules[rule_id].ref_count <= 1 {
242 self.queue_utility(rule_id);
243 }
244 }
245 }
246
247 fn replace_digram_with_rule(&mut self, start: NodeId, rule_id: RuleId) {
248 let Some(second) = self.nodes.get(start).and_then(|node| node.next) else {
249 return;
250 };
251 if !self.nodes[start].alive
252 || !self.nodes[second].alive
253 || self.nodes[start].rule != self.nodes[second].rule
254 {
255 return;
256 }
257
258 let containing_rule = self.nodes[start].rule;
259 let prev = self.nodes[start].prev;
260 let next = self.nodes[second].next;
261
262 if let Some(prev) = prev {
263 self.unregister_digram_at(prev);
264 }
265 self.unregister_digram_at(start);
266 self.unregister_digram_at(second);
267
268 let first_value = self.nodes[start].value.clone();
269 let second_value = self.nodes[second].value.clone();
270 self.decrement_ref_in_value(&first_value);
271 self.decrement_ref_in_value(&second_value);
272
273 self.nodes[start].value = SymRef::Rule(rule_id);
274 self.increment_ref(rule_id);
275 self.nodes[start].next = next;
276
277 if let Some(next) = next {
278 self.nodes[next].prev = Some(start);
279 } else {
280 self.rules[containing_rule].tail = Some(start);
281 }
282
283 self.nodes[second].alive = false;
284 self.nodes[second].prev = None;
285 self.nodes[second].next = None;
286
287 if self.rules[containing_rule].head == Some(second) {
288 self.rules[containing_rule].head = Some(start);
289 }
290 if self.rules[containing_rule].tail == Some(second) {
291 self.rules[containing_rule].tail = Some(start);
292 }
293
294 if let Some(prev) = prev {
295 self.queue_digram(prev);
296 }
297 self.queue_digram(start);
298 }
299
300 fn enforce_rule_utility(&mut self, rule_id: RuleId) {
301 if rule_id == START_RULE
302 || !self
303 .rules
304 .get(rule_id)
305 .is_some_and(|rule| rule.active && rule.ref_count <= 1)
306 {
307 return;
308 }
309
310 if self.rules[rule_id].ref_count == 0 {
311 self.delete_rule(rule_id);
312 return;
313 }
314
315 if let Some(reference) = self.find_reference(rule_id) {
316 self.inline_rule_at(reference, rule_id);
317 } else {
318 self.rules[rule_id].ref_count = 0;
319 self.delete_rule(rule_id);
320 }
321 }
322
323 fn inline_rule_at(&mut self, reference: NodeId, rule_id: RuleId) {
324 let body = self.rule_values(rule_id);
325 if body.is_empty() {
326 self.remove_node(reference);
327 self.delete_rule(rule_id);
328 return;
329 }
330
331 let prev = self.nodes[reference].prev;
332 let old_next = self.nodes[reference].next;
333
334 if let Some(prev) = prev {
335 self.unregister_digram_at(prev);
336 }
337 self.unregister_digram_at(reference);
338
339 let old_value = self.nodes[reference].value.clone();
340 self.decrement_ref_in_value(&old_value);
341
342 self.nodes[reference].value = body[0].clone();
343 self.increment_ref_in_value(&body[0]);
344
345 let mut last = reference;
346 for value in body.into_iter().skip(1) {
347 last = self.insert_node_after(last, value);
348 }
349
350 if let Some(prev) = prev {
351 self.queue_digram(prev);
352 }
353 self.queue_inserted_digrams(reference, old_next);
354 self.delete_rule(rule_id);
355 }
356
357 fn remove_node(&mut self, node: NodeId) {
358 if !self.nodes[node].alive {
359 return;
360 }
361
362 let rule = self.nodes[node].rule;
363 let prev = self.nodes[node].prev;
364 let next = self.nodes[node].next;
365
366 if let Some(prev) = prev {
367 self.unregister_digram_at(prev);
368 }
369 self.unregister_digram_at(node);
370
371 let value = self.nodes[node].value.clone();
372 self.decrement_ref_in_value(&value);
373
374 if let Some(prev) = prev {
375 self.nodes[prev].next = next;
376 } else {
377 self.rules[rule].head = next;
378 }
379 if let Some(next) = next {
380 self.nodes[next].prev = prev;
381 } else {
382 self.rules[rule].tail = prev;
383 }
384
385 self.nodes[node].alive = false;
386 self.nodes[node].prev = None;
387 self.nodes[node].next = None;
388
389 if let Some(prev) = prev {
390 self.queue_digram(prev);
391 }
392 }
393
394 fn delete_rule(&mut self, rule_id: RuleId) {
395 if rule_id == START_RULE || !self.rules[rule_id].active {
396 return;
397 }
398
399 let mut cursor = self.rules[rule_id].head;
400 while let Some(node) = cursor {
401 cursor = self.nodes[node].next;
402 self.unregister_digram_at(node);
403 }
404
405 cursor = self.rules[rule_id].head;
406 while let Some(node) = cursor {
407 cursor = self.nodes[node].next;
408 let value = self.nodes[node].value.clone();
409 self.decrement_ref_in_value(&value);
410 self.nodes[node].alive = false;
411 self.nodes[node].prev = None;
412 self.nodes[node].next = None;
413 }
414
415 self.rules[rule_id].head = None;
416 self.rules[rule_id].tail = None;
417 self.rules[rule_id].active = false;
418 self.rules[rule_id].ref_count = 0;
419 }
420
421 fn find_reference(&self, rule_id: RuleId) -> Option<NodeId> {
422 self.nodes.iter().enumerate().find_map(|(node_id, node)| {
423 (node.alive && node.value == SymRef::Rule(rule_id)).then_some(node_id)
424 })
425 }
426
427 fn queue_inserted_digrams(&mut self, first: NodeId, old_next: Option<NodeId>) {
428 let mut cursor = Some(first);
429 while let Some(node) = cursor {
430 self.queue_digram(node);
431 if self.nodes[node].next == old_next {
432 break;
433 }
434 cursor = self.nodes[node].next;
435 }
436 }
437
438 fn queue_digram(&mut self, start: NodeId) {
439 if self.nodes.get(start).is_some_and(|node| node.alive) {
440 self.digram_queue.push_back(start);
441 }
442 }
443
444 fn queue_utility(&mut self, rule_id: RuleId) {
445 if rule_id != START_RULE {
446 self.utility_queue.push_back(rule_id);
447 }
448 }
449
450 fn unregister_digram_at(&mut self, start: NodeId) {
451 let Some(key) = self.digram_key(start) else {
452 return;
453 };
454 if self.digrams.get(&key).copied() == Some(start) {
455 self.digrams.remove(&key);
456 }
457 }
458
459 fn digram_key(&self, start: NodeId) -> Option<(SymRef, SymRef)> {
460 let node = self.nodes.get(start)?;
461 if !node.alive {
462 return None;
463 }
464 let next = node.next?;
465 let next_node = self.nodes.get(next)?;
466 if !next_node.alive || next_node.rule != node.rule {
467 return None;
468 }
469
470 Some((node.value.clone(), next_node.value.clone()))
471 }
472
473 fn occurrences_overlap(&self, left: NodeId, right: NodeId) -> bool {
474 left == right
475 || self.nodes[left].next == Some(right)
476 || self.nodes[right].next == Some(left)
477 }
478
479 fn rule_matching_body(&self, start: NodeId) -> Option<RuleId> {
480 let node = self.nodes.get(start)?;
481 let rule_id = node.rule;
482 if rule_id == START_RULE {
483 return None;
484 }
485
486 let next = node.next?;
487 let rule = self.rules.get(rule_id)?;
488 (rule.active && rule.head == Some(start) && rule.tail == Some(next)).then_some(rule_id)
489 }
490
491 fn increment_ref_in_value(&mut self, value: &SymRef) {
492 if let SymRef::Rule(rule_id) = value {
493 self.increment_ref(*rule_id);
494 }
495 }
496
497 fn increment_ref(&mut self, rule_id: RuleId) {
498 if let Some(rule) = self.rules.get_mut(rule_id) {
499 rule.ref_count = rule.ref_count.saturating_add(1);
500 }
501 }
502
503 fn decrement_ref_in_value(&mut self, value: &SymRef) {
504 if let SymRef::Rule(rule_id) = value {
505 self.decrement_ref(*rule_id);
506 }
507 }
508
509 fn decrement_ref(&mut self, rule_id: RuleId) {
510 if rule_id == START_RULE {
511 return;
512 }
513
514 let should_queue = if let Some(rule) = self.rules.get_mut(rule_id) {
515 rule.ref_count = rule.ref_count.saturating_sub(1);
516 rule.active && rule.ref_count <= 1
517 } else {
518 false
519 };
520
521 if should_queue {
522 self.queue_utility(rule_id);
523 }
524 }
525
526 fn final_rule_names(&self) -> BTreeMap<RuleId, String> {
527 let mut names = BTreeMap::from([(START_RULE, "start".to_string())]);
528 let mut next = 1usize;
529
530 for rule_id in 1..self.rules.len() {
531 if self.rules[rule_id].active {
532 names.insert(rule_id, format!("R{next}"));
533 next += 1;
534 }
535 }
536
537 names
538 }
539
540 fn rule_exprs(&self, rule_id: RuleId, names: &BTreeMap<RuleId, String>) -> Vec<GrammarExpr> {
541 self.rule_values(rule_id)
542 .into_iter()
543 .map(|value| Self::symref_to_expr(value, names))
544 .collect()
545 }
546
547 fn rule_values(&self, rule_id: RuleId) -> Vec<SymRef> {
548 let mut values = Vec::new();
549 let mut cursor = self.rules[rule_id].head;
550
551 while let Some(node) = cursor {
552 if self.nodes[node].alive {
553 values.push(self.nodes[node].value.clone());
554 }
555 cursor = self.nodes[node].next;
556 }
557
558 values
559 }
560
561 fn symref_to_expr(value: SymRef, names: &BTreeMap<RuleId, String>) -> GrammarExpr {
562 match value {
563 SymRef::Terminal(value) => GrammarExpr::Terminal(value),
564 SymRef::Rule(rule_id) => GrammarExpr::NonTerminal(
565 names
566 .get(&rule_id)
567 .expect("referenced generated rules must be named")
568 .clone(),
569 ),
570 }
571 }
572}