1use alloc::{boxed::Box, collections::BTreeMap, vec, vec::Vec};
22
23use crate::{
24 grammar::{Analysis, Expr, FieldDef, Pratt, Rule, RuleBody, Shape},
25 schematic::Fixity,
26};
27
28const BUDGET: u64 = 1 << 25;
32
33#[derive(Clone, Debug, Default, PartialEq, Eq)]
36struct Card {
37 min: u8,
38 max: u8,
39 kinds: Vec<u16>,
40}
41
42impl Card {
43 fn one(kind: u16) -> Self {
44 Self {
45 min: 1,
46 max: 1,
47 kinds: vec![kind],
48 }
49 }
50
51 fn add_kinds(&mut self, kinds: &[u16]) {
53 if kinds.is_empty() {
54 return;
55 }
56 if !kinds.windows(2).all(|w| w[0] < w[1]) {
57 let mut sorted = kinds.to_vec();
59 sorted.sort_unstable();
60 sorted.dedup();
61 return self.add_kinds(&sorted);
62 }
63 if self.kinds.is_empty() {
64 self.kinds.extend_from_slice(kinds);
65 return;
66 }
67 let mut merged = Vec::with_capacity(self.kinds.len() + kinds.len());
68 let (mut i, mut j) = (0, 0);
69 while i < self.kinds.len() && j < kinds.len() {
70 let (a, b) = (self.kinds[i], kinds[j]);
71 merged.push(a.min(b));
72 i += usize::from(a <= b);
73 j += usize::from(b <= a);
74 }
75 merged.extend_from_slice(&self.kinds[i..]);
76 merged.extend_from_slice(&kinds[j..]);
77 self.kinds = merged;
78 }
79
80 fn then(&mut self, other: &Card) {
82 self.min = (self.min + other.min).min(2);
83 self.max = (self.max + other.max).min(2);
84 self.add_kinds(&other.kinds);
85 }
86
87 fn or(&mut self, other: &Card) {
89 self.min = self.min.min(other.min);
90 self.max = self.max.max(other.max);
91 self.add_kinds(&other.kinds);
92 }
93}
94
95#[derive(Clone, Debug, Default, PartialEq, Eq)]
97struct Summary {
98 labelled: BTreeMap<u16, Card>,
99 unlabelled: Card,
100}
101
102impl Summary {
103 fn then(&mut self, other: &Summary) {
104 for (l, c) in &other.labelled {
105 self.labelled.entry(*l).or_default().then(c);
106 }
107 self.unlabelled.then(&other.unlabelled);
108 }
109
110 fn or(&mut self, other: &Summary) {
111 for (l, c) in self.labelled.iter_mut() {
113 match other.labelled.get(l) {
114 Some(o) => c.or(o),
115 None => c.min = 0,
116 }
117 }
118 for (l, c) in &other.labelled {
119 if !self.labelled.contains_key(l) {
120 let mut c = c.clone();
121 c.min = 0;
122 let _ = self.labelled.insert(*l, c);
123 }
124 }
125 self.unlabelled.or(&other.unlabelled);
126 }
127
128 fn repeat(&mut self, min_one: bool) {
129 let scale = |c: &mut Card| {
130 if !min_one {
131 c.min = 0;
132 }
133 if c.max > 0 {
134 c.max = 2;
135 }
136 };
137 self.labelled.values_mut().for_each(scale);
138 scale(&mut self.unlabelled);
139 }
140
141 fn optional(&mut self) {
142 self.labelled.values_mut().for_each(|c| c.min = 0);
143 self.unlabelled.min = 0;
144 }
145
146 fn size(&self) -> u64 {
148 let labelled: usize = self.labelled.values().map(|c| c.kinds.len() + 1).sum();
149 (labelled + self.unlabelled.kinds.len()) as u64
150 }
151}
152
153pub(crate) struct TooLarge;
155
156pub(crate) fn derive(
162 a: &Analysis<'_>,
163 rules: &[Rule],
164 pratts: &[Pratt],
165 shape: &Shape,
166 labels: usize,
167) -> Result<crate::grammar::FieldTable, TooLarge> {
168 if labels == 0 {
169 return Ok(Box::new([]));
170 }
171 let mut spent: u64 = 0;
172 let op_labels = shape.v2.as_ref().map_or([0; 4], |v| v.op_labels);
173 let word_set = first_of_word(a);
174 let word_kinds: Vec<u16> = if word_set == crate::set::NO_SET {
175 Vec::new()
176 } else {
177 a.sets.members(word_set).map(|k| k as u16).collect()
178 };
179 let mut hidden: Vec<Summary> = vec![Summary::default(); rules.len()];
182 let mut summaries: Vec<Summary> = vec![Summary::default(); a.exprs.len()];
183 for _round in 0..16 {
184 let mut changed = false;
185 for (r, rule) in rules.iter().enumerate() {
186 let s = rule_summary(
187 a,
188 rules,
189 pratts,
190 r,
191 &hidden,
192 &mut summaries,
193 &word_kinds,
194 &mut spent,
195 )?;
196 if rule.node.is_none() && s != hidden[r] {
197 hidden[r] = s;
198 changed = true;
199 }
200 }
201 if !changed {
202 break;
203 }
204 }
205
206 let mut fields: BTreeMap<u16, BTreeMap<u16, Card>> = BTreeMap::new();
208 let mut add = |node: u16, s: &Summary| {
209 let entry = fields.entry(node).or_default();
210 for (l, c) in &s.labelled {
211 match entry.get_mut(l) {
212 Some(existing) => existing.or(c),
213 None => {
214 let _ = entry.insert(*l, c.clone());
215 }
216 }
217 }
218 };
219 for (r, rule) in rules.iter().enumerate() {
220 let Some(node) = rule.node else { continue };
221 let s = rule_summary(
222 a,
223 rules,
224 pratts,
225 r,
226 &hidden,
227 &mut summaries,
228 &word_kinds,
229 &mut spent,
230 )?;
231 add(node.index(), &s);
232 if let RuleBody::Pratt(p) = rule.body {
233 let pratt = &pratts[p as usize];
234 let operand = expr_summary_cached(&summaries, pratt.operand);
235 let op_nodes: Vec<u16> = pratt.levels.iter().map(|l| l.node.index()).collect();
236 let mut side = operand.unlabelled.clone();
237 side.add_kinds(&op_nodes);
238 side.min = 1;
239 for level in pratt.levels.iter() {
240 let mut s = Summary::default();
241 for (l, c) in &operand.labelled {
243 let mut c = c.clone();
244 c.min = 0;
245 let _ = s.labelled.insert(*l, c);
246 }
247 let mut ops: Vec<u16> = (0..pratt.prefix.len())
248 .filter(|&k| {
249 let at = if level.fixity == Fixity::Prefix {
250 pratt.prefix[k]
251 } else {
252 pratt.after[k]
253 };
254 at != 0 && pratt.levels[usize::from(at) - 1].node == level.node
255 })
256 .map(|k| k as u16)
257 .collect();
258 ops.extend(pratt.contextual.iter().map(|c| c.0));
259 ops.sort_unstable();
260 ops.dedup();
261 let op = Card {
262 min: 1,
263 max: 1,
264 kinds: ops,
265 };
266 let [lhs, op_label, rhs, operand_label] = op_labels;
267 match level.fixity {
268 Fixity::Prefix => {
269 let _ = s.labelled.insert(op_label, op);
270 let _ = s.labelled.insert(operand_label, side.clone());
271 }
272 Fixity::Postfix => {
273 let _ = s.labelled.insert(operand_label, side.clone());
274 let _ = s.labelled.insert(op_label, op);
275 }
276 _ => {
277 let _ = s.labelled.insert(lhs, side.clone());
278 let _ = s.labelled.insert(op_label, op);
279 let _ = s.labelled.insert(rhs, side.clone());
280 }
281 }
282 if let Some(then) = level.then {
283 let t = expr_summary_cached(&summaries, then);
284 s.then(&Summary {
285 labelled: t.labelled.clone(),
286 unlabelled: Card::default(),
287 });
288 }
289 add(level.node.index(), &s);
290 }
291 }
292 }
293 Ok(fields
294 .into_iter()
295 .map(|(node, labels)| {
296 let defs: Box<[FieldDef]> = labels
297 .into_iter()
298 .map(|(label, c)| FieldDef {
299 label,
300 cardinality: match (c.min, c.max) {
301 (_, 2) => 2,
302 (0, _) => 1,
303 _ => 0,
304 },
305 kinds: c.kinds.into(),
306 })
307 .collect();
308 (node, defs)
309 })
310 .collect())
311}
312
313fn first_of_word(a: &Analysis<'_>) -> crate::set::SetId {
316 a.exprs
317 .iter()
318 .position(|e| matches!(e, Expr::Word))
319 .map_or(crate::set::NO_SET, |e| a.first[e])
320}
321
322fn expr_summary_cached(summaries: &[Summary], e: u32) -> Summary {
323 summaries.get(e as usize).cloned().unwrap_or_default()
324}
325
326#[allow(clippy::too_many_arguments)]
330fn rule_summary(
331 a: &Analysis<'_>,
332 rules: &[Rule],
333 pratts: &[Pratt],
334 r: usize,
335 hidden: &[Summary],
336 summaries: &mut [Summary],
337 word: &[u16],
338 spent: &mut u64,
339) -> Result<Summary, TooLarge> {
340 for &e in &a.owned[r] {
341 let e = e as usize;
342 let s = match a.exprs[e] {
343 Expr::Token(k) | Expr::Keyword(k) => Summary {
344 labelled: BTreeMap::new(),
345 unlabelled: Card::one(k),
346 },
347 Expr::Word => Summary {
348 labelled: BTreeMap::new(),
349 unlabelled: Card {
350 min: 1,
351 max: 1,
352 kinds: word.to_vec(),
353 },
354 },
355 Expr::Rule(callee) => match rules[callee as usize].node {
356 Some(node) => Summary {
357 labelled: BTreeMap::new(),
358 unlabelled: Card::one(node.index()),
359 },
360 None => hidden[callee as usize].clone(),
361 },
362 Expr::Seq { start, len } => {
363 let mut s = Summary::default();
364 for &item in a.children(start, len) {
365 s.then(&summaries[item as usize]);
366 }
367 s
368 }
369 Expr::Choice { start, len } => {
370 let mut items = a.children(start, len).iter();
371 match items.next() {
372 None => Summary::default(),
373 Some(&first) => {
374 let mut s = summaries[first as usize].clone();
375 for &item in items {
376 s.or(&summaries[item as usize]);
377 }
378 s
379 }
380 }
381 }
382 Expr::Repeat { body, min_one, .. } => {
383 let mut s = summaries[body as usize].clone();
384 s.repeat(min_one);
385 s
386 }
387 Expr::Optional(body) => {
388 let mut s = summaries[body as usize].clone();
389 s.optional();
390 s
391 }
392 Expr::Label { label, body } => {
393 let inner = &summaries[body as usize];
394 let mut s = Summary {
395 labelled: inner.labelled.clone(),
396 unlabelled: Card::default(),
397 };
398 s.labelled.entry(label).or_default().then(&inner.unlabelled);
399 s
400 }
401 Expr::BackRef { body, .. } => summaries[body as usize].clone(),
402 Expr::And(_) | Expr::Not(_) | Expr::Eof | Expr::LineStart | Expr::NlBefore => {
403 Summary::default()
404 }
405 };
406 *spent += s.size();
407 if *spent > BUDGET {
408 return Err(TooLarge);
409 }
410 summaries[e] = s;
411 }
412 Ok(match rules[r].body {
413 RuleBody::Expr(e) => summaries[e as usize].clone(),
414 RuleBody::Pratt(p) => {
415 let pratt = &pratts[p as usize];
418 let mut s = summaries[pratt.operand as usize].clone();
419 let mut ops = Summary::default();
420 ops.unlabelled.min = 1;
421 ops.unlabelled.max = 1;
422 ops.unlabelled.add_kinds(
423 &pratt
424 .levels
425 .iter()
426 .map(|l| l.node.index())
427 .collect::<Vec<_>>(),
428 );
429 s.or(&ops);
430 s
431 }
432 })
433}
434
435#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
437#[non_exhaustive]
438pub enum Cardinality {
439 One,
441 Optional,
443 Many,
445}
446
447#[derive(Clone, Copy, Debug)]
468pub struct Field<'a> {
469 language: &'a crate::Language,
470 def: &'a FieldDef,
471}
472
473impl<'a> Field<'a> {
474 pub(crate) fn new(language: &'a crate::Language, def: &'a FieldDef) -> Self {
475 Self { language, def }
476 }
477
478 #[must_use]
480 pub fn label(&self) -> u16 {
481 self.def.label
482 }
483
484 #[must_use]
486 pub fn name(&self) -> &'a str {
487 self.language.label_name(self.def.label).unwrap_or("")
488 }
489
490 #[must_use]
492 pub fn cardinality(&self) -> Cardinality {
493 match self.def.cardinality {
494 0 => Cardinality::One,
495 1 => Cardinality::Optional,
496 _ => Cardinality::Many,
497 }
498 }
499
500 pub fn kinds(&self) -> impl Iterator<Item = crate::Kind> + 'a {
502 let language = self.language;
503 self.def
504 .kinds
505 .iter()
506 .filter_map(move |&k| language.kind_at(k))
507 }
508}