Skip to main content

lang_forge/
fields.rs

1//! Fields: what each node kind's labels can hold (LSF2 §11.3).
2//!
3//! A label applies to every element its labelled part adds directly to the
4//! current node; a label on a group or a hidden rule applies to every element
5//! added at that level that carries no label from inside (inner labels win).
6//! From that rule the forge derives, per node kind, each field's name, the
7//! kinds it can hold, and its cardinality — one, optional, or many — computed
8//! structurally from where the label occurs: under a repetition it is many,
9//! under an optional or in only some alternatives it is optional, and twice in
10//! one sequence it is many.
11//!
12//! The computation is a bottom-up pass over each rule's expressions (children
13//! before parents, so no recursion), with hidden rules summarized and the
14//! summaries iterated to a fixpoint, since hidden rules can call each other.
15//!
16//! Each summary lists kinds, so a hostile sketch (a hidden rule over thousands
17//! of keywords, referenced from thousands of places) could make the summaries
18//! grow as expressions times kinds. Every kind list computed counts against
19//! [`BUDGET`]; past it the sketch is refused (`LSF9008`) instead of followed.
20
21use 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
28/// The most kind entries the summaries may compute in total, over every
29/// round: far above any real grammar (Mox's sketch computes about 30,000), and about
30/// 64 MiB of `u16`s at most.
31const BUDGET: u64 = 1 << 25;
32
33/// How many elements a field or level holds: at least `min`, at most `max`
34/// (2 standing for "two or more").
35#[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    /// Adds `kinds`: one linear merge, not an insertion each.
52    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            // Operator-node lists come in level order.
58            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    /// One after the other.
81    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    /// One or the other.
88    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/// What a part of a rule adds at its own level.
96#[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        // A label missing from one side is absent there: min 0.
112        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    /// The entries the summary holds, counted against [`BUDGET`].
147    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
153/// The summaries passed [`BUDGET`].
154pub(crate) struct TooLarge;
155
156/// Derives every node kind's fields. `labels` is the number of labels.
157///
158/// # Errors
159///
160/// [`TooLarge`] if the work passes [`BUDGET`].
161pub(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    // Hidden rules' summaries, iterated to a fixpoint (bounded: counts
180    // saturate at 2 and kind sets only grow).
181    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    // Fields of each node kind.
207    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                // Labels inside the operand stay on the operand's elements.
242                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
313/// The FIRST set of a `WORD` expression (every keyword and `IDENT`), or an
314/// empty set if the grammar has none.
315fn 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/// The summary of rule `r`'s body, computing every expression's summary on
327/// the way (children before parents). Each summary computed counts against
328/// `spent`.
329#[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            // The rule's node holds the operand's elements or one operator
416            // node.
417            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/// How many children a field holds (LSF2 §11.3).
436#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
437#[non_exhaustive]
438pub enum Cardinality {
439    /// Exactly one child.
440    One,
441    /// None or one.
442    Optional,
443    /// Any number (a list field, such as `args:arg (',' args:arg)*`).
444    Many,
445}
446
447/// A field of a node kind: a label its children carry, the kinds it can
448/// hold, and how many (see [`Language::fields`](crate::Language::fields)).
449///
450/// # Examples
451///
452/// ```
453/// use lang_forge::{Cardinality, Language};
454///
455/// let lang = Language::from_lsf(
456///     "[sketch]\nformat = 2\n[language]\nname = \"x\"\nversion = \"1.0.0\"\n\
457///      [rules]\npair = \"key:IDENT '=' value:(NUMBER | IDENT)\"\n",
458/// )?;
459/// let pair = lang.kind("pair").expect("a rule");
460/// let value = lang.fields(pair).find(|f| f.name() == "value").expect("labelled");
461/// assert_eq!(value.cardinality(), Cardinality::One);
462/// let kinds: Vec<&str> = value.kinds().map(|k| lang.kind_name(k)).collect();
463/// assert_eq!(kinds, ["IDENT", "NUMBER"]);
464/// assert_eq!(lang.label_name(value.label()), Some("value"));
465/// # Ok::<(), lang_forge::Error>(())
466/// ```
467#[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    /// The label's id (see [`Language::label_id`](crate::Language::label_id)).
479    #[must_use]
480    pub fn label(&self) -> u16 {
481        self.def.label
482    }
483
484    /// The label's name.
485    #[must_use]
486    pub fn name(&self) -> &'a str {
487        self.language.label_name(self.def.label).unwrap_or("")
488    }
489
490    /// How many children the field holds.
491    #[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    /// The kinds the field's children can have, in index order.
501    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}