Skip to main content

meta_language/grammar/feature_runtime/
load.rs

1//! Loading a grammar for the native executor, as
2//! `js/src/grammar-runtime/load.js`: imports are resolved through the
3//! injected resolver (no file system or network access), macros are
4//! expanded, parameterized rules are instantiated, and `compile.rs` checks
5//! every operation against its context and compiles the terminals.
6
7use std::collections::{HashMap, HashSet, VecDeque};
8use std::fmt;
9use std::sync::Arc;
10
11use super::compile::Compiler;
12use super::forking::GrammarFacts;
13use super::program::{
14    Compiled, Expr, Program, Rule, Scanner, Settling, SettlingStep, Target, Trivia,
15};
16use super::token_ranks::token_ranks;
17use crate::grammar::interchange::render_native_expression;
18use crate::grammar::{
19    FeatureExpr, FeatureForm, FieldValue, Grammar, GrammarExpr, GrammarFormat, GrammarMacro,
20    GrammarScanner, Operation, PrecedenceEntry, RuleAttributes, RuleKind, default_settling,
21    settling_problem,
22};
23
24/// A grammar that cannot be loaded or a parse that cannot run; `reason`
25/// names the step: `import`, `macro`, `parameter`, `reference`,
26/// `declaration`, `operation`, `pattern` or `embed`.
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct GrammarRuntimeError {
29    /// The step that refused the grammar.
30    pub reason: &'static str,
31    /// What is wrong.
32    pub message: String,
33}
34
35impl fmt::Display for GrammarRuntimeError {
36    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(formatter, "{} ({})", self.message, self.reason)
38    }
39}
40
41impl std::error::Error for GrammarRuntimeError {}
42
43pub(super) type LoadResult<T> = Result<T, GrammarRuntimeError>;
44
45/// Fails a load with `reason` and `message`.
46pub(super) fn refuse<T>(reason: &'static str, message: impl Into<String>) -> LoadResult<T> {
47    Err(GrammarRuntimeError {
48        reason,
49        message: message.into(),
50    })
51}
52
53/// Resolves the grammar an import or an embedded language names.
54pub(super) type Resolver<'a> = Option<&'a dyn Fn(&str) -> Option<Grammar>>;
55
56const INSTANCE_LIMIT: usize = 1000;
57
58/// A map that keeps the order of first insertion and replaces in place.
59struct Ordered<T> {
60    items: Vec<(String, T)>,
61    index: HashMap<String, usize>,
62}
63
64impl<T> Ordered<T> {
65    fn new() -> Self {
66        Self {
67            items: Vec::new(),
68            index: HashMap::new(),
69        }
70    }
71
72    fn set(&mut self, name: String, value: T) {
73        if let Some(&position) = self.index.get(&name) {
74            self.items[position].1 = value;
75        } else {
76            self.index.insert(name.clone(), self.items.len());
77            self.items.push((name, value));
78        }
79    }
80
81    fn get(&self, name: &str) -> Option<&T> {
82        self.index
83            .get(name)
84            .map(|&position| &self.items[position].1)
85    }
86
87    fn contains(&self, name: &str) -> bool {
88        self.index.contains_key(name)
89    }
90
91    const fn len(&self) -> usize {
92        self.items.len()
93    }
94}
95
96/// The form `head` when `expr` is one.
97pub(super) fn form_of<'a>(expr: &'a GrammarExpr, head: &str) -> Option<&'a FeatureForm> {
98    match expr {
99        GrammarExpr::Feature(feature) => match &**feature {
100            FeatureExpr::Form(form) if form.head == head => Some(form),
101            _ => None,
102        },
103        _ => None,
104    }
105}
106
107/// Rewrites the direct sub-expressions of `expr`.
108fn map_children_mut(expr: &mut GrammarExpr, map: &mut impl FnMut(&mut GrammarExpr)) {
109    match expr {
110        GrammarExpr::Optional(inner)
111        | GrammarExpr::ZeroOrMore(inner)
112        | GrammarExpr::OneOrMore(inner)
113        | GrammarExpr::And(inner)
114        | GrammarExpr::Not(inner)
115        | GrammarExpr::Repeat { expr: inner, .. }
116        | GrammarExpr::Capture { expr: inner, .. } => map(inner),
117        GrammarExpr::Choice { alternatives, .. } => alternatives.iter_mut().for_each(map),
118        GrammarExpr::Sequence(items) => items.iter_mut().for_each(map),
119        GrammarExpr::Feature(feature) => feature.map_expressions(map),
120        GrammarExpr::Empty
121        | GrammarExpr::Terminal(_)
122        | GrammarExpr::TerminalInsensitive(_)
123        | GrammarExpr::CharRange(..)
124        | GrammarExpr::CharClass { .. }
125        | GrammarExpr::AnyChar
126        | GrammarExpr::NonTerminal(_) => {}
127    }
128}
129
130/// A copy of `expr` with each direct sub-expression replaced by `map`'s result.
131fn try_map_children(
132    expr: &GrammarExpr,
133    mut map: impl FnMut(&GrammarExpr) -> LoadResult<GrammarExpr>,
134) -> LoadResult<GrammarExpr> {
135    let mut copy = expr.clone();
136    let mut failure = None;
137    map_children_mut(&mut copy, &mut |child: &mut GrammarExpr| {
138        if failure.is_none() {
139            match map(child) {
140                Ok(mapped) => *child = mapped,
141                Err(error) => failure = Some(error),
142            }
143        }
144    });
145    failure.map_or(Ok(copy), Err)
146}
147
148/// A copy of `operations` with every expression they hold replaced by `map`'s result.
149fn try_map_operations(
150    operations: &[Operation],
151    mut map: impl FnMut(&GrammarExpr) -> LoadResult<GrammarExpr>,
152) -> LoadResult<Vec<Operation>> {
153    let mut copy = operations.to_vec();
154    let mut failure = None;
155    for operation in &mut copy {
156        operation.map_expressions(&mut |child: &mut GrammarExpr| {
157            if failure.is_none() {
158                match map(child) {
159                    Ok(mapped) => *child = mapped,
160                    Err(error) => failure = Some(error),
161                }
162            }
163        });
164    }
165    failure.map_or(Ok(copy), Err)
166}
167
168/// The shared state of one load: the resolver and every language loaded so far.
169struct Context<'a> {
170    resolver: Resolver<'a>,
171    programs: Vec<Program>,
172    languages: HashMap<String, usize>,
173}
174
175impl Context<'_> {
176    fn resolve(&self, name: &str, purpose: &'static str) -> LoadResult<Grammar> {
177        let resolved = self.resolver.and_then(|resolve| resolve(name));
178        resolved.map_or_else(
179            || {
180                let what = if purpose == "import" {
181                    "imported grammar"
182                } else {
183                    "embedded language"
184                };
185                refuse(purpose, format!("{what} {name} cannot be resolved"))
186            },
187            Ok,
188        )
189    }
190}
191
192/// A grammar with its imports merged in.
193struct Resolved {
194    start: Option<String>,
195    peg_source: bool,
196    matching: Option<String>,
197    settling: Option<Vec<String>>,
198    rules: Ordered<(RuleKind, GrammarExpr, RuleAttributes)>,
199    modes: Vec<String>,
200    extras: Vec<GrammarExpr>,
201    conflicts: Vec<Vec<String>>,
202    precedences: Vec<Vec<PrecedenceEntry>>,
203    macros: Ordered<GrammarMacro>,
204    scanners: Vec<GrammarScanner>,
205}
206
207// Imports: every imported grammar's rules first (recursively, in import
208// order), then the local rules, which override imported rules of the same
209// name in place; declarations accumulate, and a local macro overrides an
210// imported one of the same name.
211fn resolve_imports(
212    grammar: &Grammar,
213    context: &Context<'_>,
214    chain: &[String],
215) -> LoadResult<Resolved> {
216    let declarations = grammar.declarations();
217    let mut resolved = Resolved {
218        start: grammar
219            .start()
220            .map(str::to_owned)
221            .or_else(|| grammar.rules().first().map(|rule| rule.name.clone())),
222        peg_source: grammar.source_format() == Some(GrammarFormat::Peg),
223        matching: declarations.matching.clone(),
224        settling: declarations.settling.clone(),
225        rules: Ordered::new(),
226        modes: Vec::new(),
227        extras: Vec::new(),
228        conflicts: Vec::new(),
229        precedences: Vec::new(),
230        macros: Ordered::new(),
231        scanners: Vec::new(),
232    };
233    for name in &declarations.imports {
234        let mut next = chain.to_vec();
235        next.push(name.clone());
236        if chain.contains(name) {
237            return refuse("import", format!("import cycle {}", next.join(" -> ")));
238        }
239        let imported = context.resolve(name, "import")?;
240        let inner = resolve_imports(&imported, context, &next)?;
241        for (rule_name, rule) in inner.rules.items {
242            resolved.rules.set(rule_name, rule);
243        }
244        resolved.modes.extend(inner.modes);
245        resolved.extras.extend(inner.extras);
246        resolved.conflicts.extend(inner.conflicts);
247        resolved.precedences.extend(inner.precedences);
248        for (macro_name, item) in inner.macros.items {
249            resolved.macros.set(macro_name, item);
250        }
251        resolved.scanners.extend(inner.scanners);
252    }
253    for rule in grammar.rules() {
254        resolved.rules.set(
255            rule.name.clone(),
256            (rule.kind, rule.expr.clone(), rule.attributes.clone()),
257        );
258    }
259    resolved.modes.extend(declarations.modes.iter().cloned());
260    resolved.extras.extend(declarations.extras.iter().cloned());
261    resolved
262        .conflicts
263        .extend(declarations.conflicts.iter().cloned());
264    resolved
265        .precedences
266        .extend(declarations.precedences.iter().cloned());
267    for item in &declarations.macros {
268        resolved.macros.set(item.name.clone(), item.clone());
269    }
270    resolved
271        .scanners
272        .extend(declarations.scanners.iter().cloned());
273    Ok(resolved)
274}
275
276fn substitute(expr: &GrammarExpr, bindings: &HashMap<String, GrammarExpr>) -> GrammarExpr {
277    if let Some(bound) = form_of(expr, "parameter")
278        .and_then(|form| form.text("name"))
279        .and_then(|name| bindings.get(name))
280    {
281        return bound.clone();
282    }
283    let mut copy = expr.clone();
284    map_children_mut(&mut copy, &mut |child: &mut GrammarExpr| {
285        *child = substitute(child, bindings);
286    });
287    copy
288}
289
290// Macros expand inline at load: `expand(NAME, ARG...)` becomes the macro body
291// with each `parameter(P)` replaced by its argument.
292fn expand_macros(
293    expr: &GrammarExpr,
294    macros: &Ordered<GrammarMacro>,
295    active: &mut Vec<String>,
296) -> LoadResult<GrammarExpr> {
297    let Some(form) = form_of(expr, "expand") else {
298        return try_map_children(expr, |child| expand_macros(child, macros, active));
299    };
300    let name = form.text("name").unwrap_or_default();
301    let arguments = form.expressions("arguments");
302    let Some(definition) = macros.get(name) else {
303        return refuse("macro", format!("undefined macro {name}"));
304    };
305    if active.iter().any(|item| item == name) {
306        return refuse(
307            "macro",
308            format!("recursive macro {} -> {name}", active.join(" -> ")),
309        );
310    }
311    if definition.parameters.len() != arguments.len() {
312        return refuse(
313            "macro",
314            format!(
315                "macro {name} takes {} arguments, not {}",
316                definition.parameters.len(),
317                arguments.len()
318            ),
319        );
320    }
321    let mut bindings = HashMap::new();
322    for (parameter, argument) in definition.parameters.iter().zip(arguments) {
323        bindings.insert(parameter.clone(), expand_macros(argument, macros, active)?);
324    }
325    active.push(name.to_owned());
326    let expanded = expand_macros(
327        &substitute(&definition.expression, &bindings),
328        macros,
329        active,
330    );
331    active.pop();
332    expanded
333}
334
335/// A rule after macro expansion.
336struct Source {
337    kind: RuleKind,
338    expression: GrammarExpr,
339    action: Option<Vec<Operation>>,
340    attributes: RuleAttributes,
341}
342
343/// A rule after instantiation.
344struct Instance {
345    node_kind: String,
346    source: String,
347    expression: GrammarExpr,
348    action: Option<Vec<Operation>>,
349}
350
351struct Pending {
352    name: String,
353    target: String,
354    bindings: HashMap<String, GrammarExpr>,
355}
356
357// Parameterized rules are instantiated per distinct argument list; an
358// instance is a rule named `NAME(ARGUMENT, ...)` whose nodes keep the kind NAME.
359struct Instantiator<'a> {
360    sources: &'a Ordered<Source>,
361    external: &'a HashMap<String, usize>,
362    rules: Ordered<Instance>,
363    pending: VecDeque<Pending>,
364    queued: HashSet<String>,
365}
366
367impl Instantiator<'_> {
368    fn instantiate(
369        &mut self,
370        expr: &GrammarExpr,
371        bindings: Option<&HashMap<String, GrammarExpr>>,
372        owner: &str,
373    ) -> LoadResult<GrammarExpr> {
374        if let Some(form) = form_of(expr, "parameter") {
375            let name = form.text("name").unwrap_or_default();
376            return bindings.and_then(|bound| bound.get(name)).map_or_else(
377                || {
378                    refuse(
379                        "parameter",
380                        format!("parameter {name} is not a parameter of {owner}"),
381                    )
382                },
383                |bound| Ok(bound.clone()),
384            );
385        }
386        let (name, arguments): (&str, &[GrammarExpr]) = match expr {
387            GrammarExpr::NonTerminal(name) => (name, &[]),
388            GrammarExpr::Feature(feature) => match &**feature {
389                FeatureExpr::Call { name, arguments } => (name, arguments),
390                _ => {
391                    return try_map_children(expr, |child| {
392                        self.instantiate(child, bindings, owner)
393                    });
394                }
395            },
396            _ => return try_map_children(expr, |child| self.instantiate(child, bindings, owner)),
397        };
398        if self.external.contains_key(name) {
399            if !arguments.is_empty() {
400                return refuse(
401                    "parameter",
402                    format!("external token {name} takes no arguments"),
403                );
404            }
405            return Ok(GrammarExpr::NonTerminal(name.to_owned()));
406        }
407        let Some(target) = self.sources.get(name) else {
408            return refuse("reference", format!("undefined rule {name} in {owner}"));
409        };
410        let parameters = &target.attributes.parameters;
411        if arguments.len() != parameters.len() {
412            return refuse(
413                "parameter",
414                format!(
415                    "rule {name} takes {} arguments, not {}",
416                    parameters.len(),
417                    arguments.len()
418                ),
419            );
420        }
421        if parameters.is_empty() {
422            return Ok(GrammarExpr::NonTerminal(name.to_owned()));
423        }
424        let concrete = arguments
425            .iter()
426            .map(|argument| self.instantiate(argument, bindings, owner))
427            .collect::<LoadResult<Vec<_>>>()?;
428        let rendered = concrete
429            .iter()
430            .map(render_native_expression)
431            .collect::<Vec<_>>();
432        let instance = format!("{name}({})", rendered.join(", "));
433        if !self.rules.contains(&instance) && !self.queued.contains(&instance) {
434            if self.rules.len() + self.pending.len() >= INSTANCE_LIMIT + self.sources.len() {
435                return refuse(
436                    "parameter",
437                    format!("parameterized rule {name} needs more than {INSTANCE_LIMIT} instances"),
438                );
439            }
440            self.queued.insert(instance.clone());
441            self.pending.push_back(Pending {
442                name: instance.clone(),
443                target: name.to_owned(),
444                bindings: parameters.iter().cloned().zip(concrete).collect(),
445            });
446        }
447        Ok(GrammarExpr::NonTerminal(instance))
448    }
449
450    fn instantiate_operations(
451        &mut self,
452        operations: &[Operation],
453        bindings: Option<&HashMap<String, GrammarExpr>>,
454        owner: &str,
455    ) -> LoadResult<Vec<Operation>> {
456        try_map_operations(operations, |expr| self.instantiate(expr, bindings, owner))
457    }
458
459    fn drain(&mut self) -> LoadResult<()> {
460        while let Some(Pending {
461            name,
462            target,
463            bindings,
464        }) = self.pending.pop_front()
465        {
466            let source = self
467                .sources
468                .get(&target)
469                .expect("a pending instance names a rule");
470            let owner = format!("rule {target}");
471            let expression = self.instantiate(&source.expression, Some(&bindings), &owner)?;
472            let action = match &source.action {
473                Some(action) => {
474                    Some(self.instantiate_operations(action, Some(&bindings), &owner)?)
475                }
476                None => None,
477            };
478            self.rules.set(
479                name,
480                Instance {
481                    node_kind: target.clone(),
482                    source: target,
483                    expression,
484                    action,
485                },
486            );
487        }
488        Ok(())
489    }
490}
491
492/// Loads `grammar` and every language it embeds.
493pub(super) fn load(grammar: &Grammar, resolver: Resolver<'_>) -> LoadResult<Compiled> {
494    let mut context = Context {
495        resolver,
496        programs: Vec::new(),
497        languages: HashMap::new(),
498    };
499    let main = load_in_context(grammar, &mut context)?;
500    Ok(Compiled {
501        programs: context.programs,
502        languages: context.languages,
503        main,
504    })
505}
506
507/// The extras of a rule that builds a node and reaches no token of an
508/// external scanner, the extras another extra nests in (see `skip_trivia` in
509/// lexing.rs). tree-sitter lexes the extras in every parse state, inside the
510/// rule of an extra too, but runs the external scanner first wherever one of
511/// its tokens is valid: so an extra starts inside an extra whose rule only the
512/// lexer lexes (Rocq's nested `(* a (* b *) c *)`), and none inside one that
513/// lexes scanner tokens (Rust's comments, whose scanner reads their content).
514fn nesting_extras(
515    trivia: &[Trivia],
516    rules: &[Rule],
517    rule_index: &HashMap<String, usize>,
518) -> HashSet<Arc<str>> {
519    fn targets<'e>(expr: &'e Expr, found: &mut Vec<&'e Target>) {
520        match expr {
521            Expr::Ref(target) => found.push(target),
522            Expr::Seq(items) | Expr::Choice { items, .. } | Expr::Longest(items) => {
523                for item in items {
524                    targets(item, found);
525                }
526            }
527            Expr::Repeat { item, .. }
528            | Expr::Capture { item, .. }
529            | Expr::Alias { item, .. }
530            | Expr::Precedence { item, .. }
531            | Expr::DynamicPrecedence { item, .. }
532            | Expr::LexicalPrecedence { item, .. }
533            | Expr::Predicate { item, .. }
534            | Expr::Missing { item, .. }
535            | Expr::Embed { item, .. } => targets(item, found),
536            Expr::And(item) | Expr::Not(item) | Expr::Token(item) | Expr::ImmediateToken(item) => {
537                targets(item, found);
538            }
539            Expr::Recover { item, synchronize } => {
540                targets(item, found);
541                targets(synchronize, found);
542            }
543            Expr::Empty | Expr::Terminal { .. } => {}
544        }
545    }
546    let mut nesting = HashSet::new();
547    for kind in trivia.iter().filter_map(|item| item.kind.as_ref()) {
548        let Some(&index) = rule_index.get(&**kind) else {
549            continue;
550        };
551        if !matches!(rules[index].kind, RuleKind::Normal) {
552            continue;
553        }
554        let mut seen = HashSet::from([index]);
555        let mut pending = vec![index];
556        let mut scanned = false;
557        while let Some(at) = pending.pop() {
558            let mut found = Vec::new();
559            targets(&rules[at].expression, &mut found);
560            for target in found {
561                match target {
562                    Target::External(_) => scanned = true,
563                    Target::Rule(next) => {
564                        if seen.insert(*next) {
565                            pending.push(*next);
566                        }
567                    }
568                }
569            }
570            if scanned {
571                break;
572            }
573        }
574        if !scanned {
575            nesting.insert(kind.clone());
576        }
577    }
578    nesting
579}
580
581fn load_in_context(grammar: &Grammar, context: &mut Context<'_>) -> LoadResult<usize> {
582    let resolved = resolve_imports(grammar, context, &[])?;
583    let macros = &resolved.macros;
584    let expand = |expr: &GrammarExpr| expand_macros(expr, macros, &mut Vec::new());
585
586    let mut external = HashMap::new();
587    for (index, scanner) in resolved.scanners.iter().enumerate() {
588        for token in &scanner.tokens {
589            if external.contains_key(token) {
590                return refuse(
591                    "declaration",
592                    format!("external token {token} is declared twice"),
593                );
594            }
595            if resolved.rules.contains(token) {
596                return refuse(
597                    "declaration",
598                    format!("external token {token} is also a rule"),
599                );
600            }
601            external.insert(token.clone(), index);
602        }
603    }
604    let mut modes: HashSet<String> = HashSet::from(["default".to_owned()]);
605    modes.extend(resolved.modes.iter().cloned());
606
607    let mut sources = Ordered::new();
608    for (name, (kind, expression, attributes)) in &resolved.rules.items {
609        let action = match &attributes.action {
610            Some(action) => Some(try_map_operations(action, expand)?),
611            None => None,
612        };
613        sources.set(
614            name.clone(),
615            Source {
616                kind: *kind,
617                expression: expand(expression)?,
618                action,
619                attributes: attributes.clone(),
620            },
621        );
622    }
623
624    let mut instantiator = Instantiator {
625        sources: &sources,
626        external: &external,
627        rules: Ordered::new(),
628        pending: VecDeque::new(),
629        queued: HashSet::new(),
630    };
631    for (name, source) in &sources.items {
632        if !source.attributes.parameters.is_empty() {
633            continue;
634        }
635        let owner = format!("rule {name}");
636        let expression = instantiator.instantiate(&source.expression, None, &owner)?;
637        let action = match &source.action {
638            Some(action) => Some(instantiator.instantiate_operations(action, None, &owner)?),
639            None => None,
640        };
641        instantiator.rules.set(
642            name.clone(),
643            Instance {
644                node_kind: name.clone(),
645                source: name.clone(),
646                expression,
647                action,
648            },
649        );
650    }
651    instantiator.drain()?;
652
653    let start = resolved.start.clone();
654    let Some(start_source) = start.as_deref().and_then(|name| sources.get(name)) else {
655        return refuse(
656            "reference",
657            format!(
658                "undefined start rule {}",
659                start.as_deref().unwrap_or("null")
660            ),
661        );
662    };
663    if !start_source.attributes.parameters.is_empty() {
664        return refuse(
665            "parameter",
666            format!(
667                "start rule {} is parameterized",
668                start.as_deref().unwrap_or_default()
669            ),
670        );
671    }
672
673    let mut extras = Vec::new();
674    for extra in &resolved.extras {
675        extras.push(instantiator.instantiate(&expand(extra)?, None, "an extra")?);
676    }
677    let mut scanner_operations = Vec::new();
678    for scanner in &resolved.scanners {
679        let expanded = try_map_operations(&scanner.operations, expand)?;
680        let owner = format!("scanner {}", scanner.name);
681        scanner_operations.push(instantiator.instantiate_operations(&expanded, None, &owner)?);
682    }
683    instantiator.drain()?;
684
685    let mut conflicts = HashSet::new();
686    for group in &resolved.conflicts {
687        for name in group {
688            if !sources.contains(name) {
689                return refuse(
690                    "declaration",
691                    format!("conflict names undefined rule {name}"),
692                );
693            }
694            conflicts.insert(name.clone());
695        }
696    }
697    // The orders of named precedences (see `compare_precedence`).
698    for order in &resolved.precedences {
699        for entry in order {
700            if let PrecedenceEntry::Rule(name) = entry
701                && !sources.contains(name)
702            {
703                return refuse(
704                    "declaration",
705                    format!("precedences names undefined rule {name}"),
706                );
707            }
708        }
709    }
710
711    let peg = resolved
712        .matching
713        .as_deref()
714        .map_or(resolved.peg_source, |matching| matching == "peg");
715    let matching = resolved
716        .matching
717        .as_deref()
718        .unwrap_or(if peg { "peg" } else { "generalized" });
719    // How two parses of one text that end alike are settled: the steps the
720    // grammar declares, or its matching's default (see `SETTLING_STEPS`).
721    let settling = match &resolved.settling {
722        Some(steps) => {
723            if let Some(problem) = settling_problem(steps) {
724                return refuse("declaration", problem);
725            }
726            Settling::new(steps)
727        }
728        None => Settling::new(default_settling(matching)),
729    };
730    let instances = instantiator.rules;
731    let rule_index: HashMap<String, usize> = instances
732        .items
733        .iter()
734        .enumerate()
735        .map(|(index, (name, _))| (name.clone(), index))
736        .collect();
737    let node_kinds = instances
738        .items
739        .iter()
740        .map(|(name, instance)| (name.clone(), Arc::from(instance.node_kind.as_str())))
741        .collect();
742    let mut compiler = Compiler::new(&rule_index, &external, &modes, node_kinds);
743    // The items a scanner's `expected` asks about, each with an id, which
744    // the parse requests where its rules try them (see `Expectations` in
745    // executor.rs); a scanner that asks answers per context offset.
746    let mut consults = Vec::new();
747    for (scanner, operations) in resolved.scanners.iter().zip(&scanner_operations) {
748        let mut items = Vec::new();
749        if !scanner.tokens.is_empty() {
750            expected_items(operations, &mut items);
751        }
752        consults.push(!items.is_empty());
753        for item in items {
754            if let Some(key) = compiler.expectation(item) {
755                let id = compiler.expectations.len();
756                compiler.expectations.entry(key).or_insert(id);
757            }
758        }
759    }
760    let expected_references = compiler
761        .expectations
762        .iter()
763        .filter_map(|(key, &id)| Some((key.strip_prefix("ref ")?.to_owned(), id)))
764        .collect();
765
766    // Trivia: the `extra` expressions first, in declaration order, then every
767    // rule on a channel other than `default`, each limited to its modes.
768    let mut trivia = Vec::new();
769    for extra in &extras {
770        let expression = compiler.expression(extra, "an extra")?;
771        let kind = match extra {
772            GrammarExpr::NonTerminal(name) => Some(Arc::from(name.as_str())),
773            _ => None,
774        };
775        trivia.push(Trivia {
776            expression,
777            kind,
778            modes: None,
779        });
780    }
781    let mut rules = Vec::new();
782    for (index, (name, instance)) in instances.items.iter().enumerate() {
783        let source = sources
784            .get(&instance.source)
785            .expect("an instance has a source");
786        let owner = format!("rule {}", instance.node_kind);
787        compiler.requesting = true;
788        let expression = compiler.expression(&instance.expression, &owner);
789        compiler.requesting = false;
790        let expression = expression?;
791        let action = match &instance.action {
792            Some(action) => {
793                if source.kind == RuleKind::Silent && action.iter().any(builds_node) {
794                    return refuse(
795                        "operation",
796                        format!("silent {owner} has no node for its action"),
797                    );
798                }
799                Some(compiler.statements(action, "action", &owner, None)?)
800            }
801            None => None,
802        };
803        let rule_modes = match &source.attributes.modes {
804            Some(rule_modes) => {
805                for mode in rule_modes {
806                    compiler.check_mode(mode, &owner)?;
807                }
808                Some(
809                    rule_modes
810                        .iter()
811                        .map(|mode| Arc::from(mode.as_str()))
812                        .collect(),
813                )
814            }
815            None => None,
816        };
817        let lexical_priority = form_of(&instance.expression, "lexicalPrecedence")
818            .and_then(|form| form.integer("level"))
819            .unwrap_or(0);
820        let node_kind: Arc<str> = Arc::from(instance.node_kind.as_str());
821        if source
822            .attributes
823            .channel
824            .as_deref()
825            .is_some_and(|channel| channel != "default")
826        {
827            trivia.push(Trivia {
828                expression: super::program::Expr::Ref(Target::Rule(index)),
829                kind: Some(node_kind.clone()),
830                modes: rule_modes.clone(),
831            });
832        }
833        rules.push(Rule {
834            name: Arc::from(name.as_str()),
835            node_kind,
836            kind: source.kind,
837            expression,
838            action,
839            modes: rule_modes,
840            lexical_priority,
841        });
842    }
843    let mut scanners = Vec::new();
844    for ((scanner, operations), consults) in resolved
845        .scanners
846        .iter()
847        .zip(&scanner_operations)
848        .zip(consults)
849    {
850        let owner = format!("scanner {}", scanner.name);
851        let operations = if scanner.tokens.is_empty() {
852            Vec::new()
853        } else {
854            compiler.statements(
855                operations,
856                "scanner",
857                &owner,
858                Some(scanner.tokens.as_slice()),
859            )?
860        };
861        scanners.push(Scanner {
862            operations,
863            consults,
864        });
865    }
866    let embedded = compiler.into_embedded();
867
868    let index = context.programs.len();
869    let token_ranks = (settling.has(SettlingStep::Tokens)
870        || settling.has(SettlingStep::Precedence))
871    .then(|| token_ranks(&rules));
872    let ranked_silent = resolved
873        .precedences
874        .iter()
875        .flatten()
876        .filter_map(|entry| match entry {
877            PrecedenceEntry::Rule(name)
878                if rule_index
879                    .get(name)
880                    .is_some_and(|&at| matches!(rules[at].kind, RuleKind::Silent)) =>
881            {
882                Some(name.clone())
883            }
884            _ => None,
885        })
886        .collect();
887    let grammar = GrammarFacts::new(
888        &rules,
889        &resolved.conflicts,
890        settling.has(SettlingStep::Precedence),
891    );
892    let nesting_extras = nesting_extras(&trivia, &rules, &rule_index);
893    context.programs.push(Program {
894        peg,
895        settling,
896        token_ranks,
897        start,
898        rules,
899        rule_index,
900        external,
901        scanners,
902        conflicts,
903        precedence_orders: resolved.precedences.clone(),
904        ranked_silent,
905        trivia,
906        nesting_extras,
907        expected_references,
908        grammar,
909    });
910    for language in embedded {
911        if context.languages.contains_key(&language) {
912            continue;
913        }
914        context.languages.insert(language.clone(), usize::MAX);
915        let grammar = context.resolve(&language, "embed")?;
916        let loaded = load_in_context(&grammar, context)?;
917        context.languages.insert(language, loaded);
918    }
919    Ok(index)
920}
921
922/// The items of the `expected` conditions in a scanner's operations.
923fn expected_items<'a>(operations: &'a [Operation], items: &mut Vec<&'a GrammarExpr>) {
924    for operation in operations {
925        if operation.head == "expected"
926            && let Some(item) = operation.expression("item")
927        {
928            items.push(item);
929        }
930        for value in &operation.fields {
931            match value {
932                FieldValue::Operation(operation) => {
933                    expected_items(std::slice::from_ref(operation), items);
934                }
935                FieldValue::Operations(block) | FieldValue::Block(Some(block)) => {
936                    expected_items(block, items);
937                }
938                _ => {}
939            }
940        }
941    }
942}
943
944fn builds_node(operation: &Operation) -> bool {
945    if operation.head == "setAttribute" || operation.head == "buildNode" {
946        return true;
947    }
948    ["consequent", "alternative", "body"].iter().any(|key| {
949        operation
950            .operations(key)
951            .is_some_and(|block| block.iter().any(builds_node))
952    })
953}