Skip to main content

cove_syntax/
number.rs

1//! Numbering every expression in a file.
2//!
3//! The parser leaves every [`Expr`] holding [`ExprId::UNSET`], and this pass
4//! replaces those with `0`, `1`, … in one walk of the finished tree. Keeping
5//! it separate from the parser is what makes the ids a property of the file:
6//! they follow source order, not the order the parser happened to build
7//! things in, so re-parsing the same text gives the same numbers and a
8//! parser change that reorders its own work does not renumber anything.
9//!
10//! The walk is deliberately exhaustive and deliberately written without a
11//! catch-all arm. Every variant of [`ExprKind`] is named here, so a variant
12//! added to the tree later stops compiling in this file rather than quietly
13//! leaving its children unnumbered — which is the one failure this pass can
14//! have, and the one that would be hardest to notice downstream.
15//!
16//! Recursion here is bounded by the parser's `MAX_NESTING_DEPTH`: a tree only
17//! exists because the parser built it, and a walker spends less stack per
18//! level than the parser did.
19
20use crate::ast::{
21    Arg, Block, Expr, ExprId, ExprKind, Item, ItemKind, MatchArm, Param, Pattern, PatternKind,
22    SourceUnit, Stmt, StmtKind, StrPart,
23};
24
25/// Assigns every expression in `unit` an id unique within it.
26///
27/// Ids are handed out in pre-order and in source order, starting at
28/// [`ExprId`]`(0)`: an expression is numbered before its children, and a
29/// child before anything to its right. So the ids of one unit are exactly
30/// `0..n` for `n` expressions, with no gaps and no repeats, which is what
31/// lets a later pass index a `Vec` of `n` entries by them.
32///
33/// The numbering starts from zero for each unit, so ids from two files are
34/// not comparable. See [`ExprId`].
35///
36/// Running this twice over the same unit assigns the same ids again, so it is
37/// idempotent rather than merely repeatable.
38pub fn number_unit(unit: &mut SourceUnit) {
39    let mut numberer = Numberer { next: 0 };
40    for item in &mut unit.items {
41        numberer.item(item);
42    }
43}
44
45/// The one counter the walk hands out ids from.
46struct Numberer {
47    /// The id the next expression visited will be given.
48    next: u32,
49}
50
51impl Numberer {
52    /// Numbers everything an item can hold.
53    ///
54    /// A struct, an enum, and a type alias hold types and nothing else, and a
55    /// type holds no expression: the parser gives a function type's
56    /// parameters no default, which is the only place inside a type an
57    /// expression could otherwise appear.
58    fn item(&mut self, item: &mut Item) {
59        match &mut item.kind {
60            ItemKind::Fn(decl) => {
61                self.params(&mut decl.params);
62                self.block(&mut decl.body);
63            }
64            ItemKind::Struct(_) | ItemKind::Enum(_) | ItemKind::TypeAlias(_) => {}
65            ItemKind::Trait(decl) => {
66                for method in &mut decl.methods {
67                    self.params(&mut method.params);
68                    if let Some(body) = &mut method.default {
69                        self.block(body);
70                    }
71                }
72            }
73            ItemKind::Impl(block) => {
74                for item in &mut block.items {
75                    self.item(item);
76                }
77            }
78        }
79    }
80
81    /// Numbers the default values of a parameter list.
82    ///
83    /// A default is an ordinary expression evaluated at the call site, so it
84    /// is numbered like one, and it comes before the body because that is
85    /// where it is written.
86    fn params(&mut self, params: &mut [Param]) {
87        for param in params {
88            if let Some(default) = &mut param.default {
89                self.expr(default);
90            }
91        }
92    }
93
94    fn block(&mut self, block: &mut Block) {
95        for stmt in &mut block.statements {
96            self.stmt(stmt);
97        }
98        if let Some(tail) = &mut block.tail {
99            self.expr(tail);
100        }
101    }
102
103    fn stmt(&mut self, stmt: &mut Stmt) {
104        match &mut stmt.kind {
105            StmtKind::Let { value, .. } => self.expr(value),
106            StmtKind::Expr(value) => self.expr(value),
107            StmtKind::Item(item) => self.item(item),
108        }
109    }
110
111    /// Gives `expr` the next id, then numbers its children left to right.
112    fn expr(&mut self, expr: &mut Expr) {
113        expr.id = ExprId(self.next);
114        self.next += 1;
115        match &mut expr.kind {
116            ExprKind::Int(_)
117            | ExprKind::Float(_)
118            | ExprKind::Bool(_)
119            | ExprKind::Duration(_)
120            | ExprKind::Unit
121            | ExprKind::Ident(_)
122            | ExprKind::Continue => {}
123            ExprKind::Str(parts) => {
124                for part in parts {
125                    match part {
126                        StrPart::Text(_) => {}
127                        StrPart::Interpolation(inner) => self.expr(inner),
128                    }
129                }
130            }
131            ExprKind::ArrayLit(elements) => {
132                for element in elements {
133                    self.expr(element);
134                }
135            }
136            ExprKind::Field { base, name: _ } => self.expr(base),
137            ExprKind::Call {
138                callee,
139                generics: _,
140                args,
141                trailing,
142            } => {
143                self.expr(callee);
144                self.args(args);
145                if let Some(trailing) = trailing {
146                    self.expr(trailing);
147                }
148            }
149            ExprKind::Unary { op: _, operand } => self.expr(operand),
150            ExprKind::Binary { op: _, lhs, rhs } => {
151                self.expr(lhs);
152                self.expr(rhs);
153            }
154            ExprKind::Assign {
155                op: _,
156                target,
157                value,
158            } => {
159                self.expr(target);
160                self.expr(value);
161            }
162            ExprKind::Try(inner) => self.expr(inner),
163            ExprKind::Await(inner) => self.expr(inner),
164            ExprKind::Block(block) => self.block(block),
165            ExprKind::If {
166                condition,
167                then_branch,
168                else_branch,
169            } => {
170                self.expr(condition);
171                self.block(then_branch);
172                if let Some(else_branch) = else_branch {
173                    self.expr(else_branch);
174                }
175            }
176            ExprKind::Match { scrutinee, arms } => {
177                self.expr(scrutinee);
178                for arm in arms {
179                    self.arm(arm);
180                }
181            }
182            ExprKind::For {
183                binding: _,
184                iterable,
185                body,
186            } => {
187                self.expr(iterable);
188                self.block(body);
189            }
190            ExprKind::While { condition, body } => {
191                self.expr(condition);
192                self.block(body);
193            }
194            ExprKind::Return(value) => self.optional(value),
195            ExprKind::Break(value) => self.optional(value),
196            ExprKind::Lambda {
197                is_async: _,
198                params,
199                body,
200            } => {
201                self.params(params);
202                self.block(body);
203            }
204            ExprKind::Scope { name: _, body } => self.block(body),
205            ExprKind::Range {
206                start,
207                end,
208                inclusive_end: _,
209            } => {
210                self.expr(start);
211                self.expr(end);
212            }
213        }
214    }
215
216    fn optional(&mut self, value: &mut Option<Box<Expr>>) {
217        if let Some(value) = value {
218            self.expr(value);
219        }
220    }
221
222    fn args(&mut self, args: &mut [Arg]) {
223        for arg in args {
224            self.expr(&mut arg.value);
225        }
226    }
227
228    /// Numbers a match arm: its pattern first, then its body.
229    ///
230    /// A literal pattern holds a real expression, and it is numbered for the
231    /// same reason every other expression is — a pass keyed by id must be
232    /// total over the tree, and an unnumbered corner of it would read as
233    /// another expression's entry.
234    fn arm(&mut self, arm: &mut MatchArm) {
235        self.pattern(&mut arm.pattern);
236        self.expr(&mut arm.body);
237    }
238
239    fn pattern(&mut self, pattern: &mut Pattern) {
240        match &mut pattern.kind {
241            PatternKind::Wildcard | PatternKind::Binding(_) => {}
242            PatternKind::Literal(value) => self.expr(value),
243            PatternKind::Variant { path: _, payload } => {
244                for pattern in payload {
245                    self.pattern(pattern);
246                }
247            }
248        }
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255    use cove_diag::{SourceMap, Span};
256    use std::collections::HashSet;
257
258    /// A file that puts an expression in each of the corners this pass is
259    /// most likely to miss: a parameter default, a string interpolation, a
260    /// nested local `fn`, a match arm and its literal pattern, a trailing
261    /// closure, and a range.
262    const AWKWARD: &str = r#"/// Doc.
263export fn main(limit: Int = 1 + 1) -> Result<Unit, Error> {
264  let name = "a{limit}b"
265  fn helper(x: Int) -> Int {
266    x + 1
267  }
268  for i in 0..<limit {
269    match i {
270      0 => helper(i)
271      other => other
272    }
273  }
274  console.println("{name}") {
275  }
276  Ok(())
277}
278"#;
279
280    fn parse(source: &str) -> SourceUnit {
281        parse_with(source).0
282    }
283
284    /// Collects every expression in a unit, by a walk written independently
285    /// of the one under test so that a shared omission cannot hide.
286    fn collect(unit: &SourceUnit) -> Vec<Expr> {
287        let mut found = Vec::new();
288        for item in &unit.items {
289            collect_item(item, &mut found);
290        }
291        found
292    }
293
294    fn collect_item(item: &Item, found: &mut Vec<Expr>) {
295        match &item.kind {
296            ItemKind::Fn(decl) => {
297                collect_params(&decl.params, found);
298                collect_block(&decl.body, found);
299            }
300            ItemKind::Struct(_) | ItemKind::Enum(_) | ItemKind::TypeAlias(_) => {}
301            ItemKind::Trait(decl) => {
302                for method in &decl.methods {
303                    collect_params(&method.params, found);
304                    if let Some(body) = &method.default {
305                        collect_block(body, found);
306                    }
307                }
308            }
309            ItemKind::Impl(block) => {
310                for item in &block.items {
311                    collect_item(item, found);
312                }
313            }
314        }
315    }
316
317    fn collect_params(params: &[Param], found: &mut Vec<Expr>) {
318        for param in params {
319            if let Some(default) = &param.default {
320                collect_expr(default, found);
321            }
322        }
323    }
324
325    fn collect_block(block: &Block, found: &mut Vec<Expr>) {
326        for stmt in &block.statements {
327            match &stmt.kind {
328                StmtKind::Let { value, .. } => collect_expr(value, found),
329                StmtKind::Expr(value) => collect_expr(value, found),
330                StmtKind::Item(item) => collect_item(item, found),
331            }
332        }
333        if let Some(tail) = &block.tail {
334            collect_expr(tail, found);
335        }
336    }
337
338    fn collect_pattern(pattern: &Pattern, found: &mut Vec<Expr>) {
339        match &pattern.kind {
340            PatternKind::Wildcard | PatternKind::Binding(_) => {}
341            PatternKind::Literal(value) => collect_expr(value, found),
342            PatternKind::Variant { path: _, payload } => {
343                for pattern in payload {
344                    collect_pattern(pattern, found);
345                }
346            }
347        }
348    }
349
350    fn collect_expr(expr: &Expr, found: &mut Vec<Expr>) {
351        found.push(expr.clone());
352        match &expr.kind {
353            ExprKind::Int(_)
354            | ExprKind::Float(_)
355            | ExprKind::Bool(_)
356            | ExprKind::Duration(_)
357            | ExprKind::Unit
358            | ExprKind::Ident(_)
359            | ExprKind::Continue => {}
360            ExprKind::Str(parts) => {
361                for part in parts {
362                    if let StrPart::Interpolation(inner) = part {
363                        collect_expr(inner, found);
364                    }
365                }
366            }
367            ExprKind::ArrayLit(elements) => {
368                for element in elements {
369                    collect_expr(element, found);
370                }
371            }
372            ExprKind::Field { base, .. } => collect_expr(base, found),
373            ExprKind::Call {
374                callee,
375                args,
376                trailing,
377                ..
378            } => {
379                collect_expr(callee, found);
380                for arg in args {
381                    collect_expr(&arg.value, found);
382                }
383                if let Some(trailing) = trailing {
384                    collect_expr(trailing, found);
385                }
386            }
387            ExprKind::Unary { operand, .. } => collect_expr(operand, found),
388            ExprKind::Binary { lhs, rhs, .. } => {
389                collect_expr(lhs, found);
390                collect_expr(rhs, found);
391            }
392            ExprKind::Assign { target, value, .. } => {
393                collect_expr(target, found);
394                collect_expr(value, found);
395            }
396            ExprKind::Try(inner) | ExprKind::Await(inner) => collect_expr(inner, found),
397            ExprKind::Block(block) => collect_block(block, found),
398            ExprKind::If {
399                condition,
400                then_branch,
401                else_branch,
402            } => {
403                collect_expr(condition, found);
404                collect_block(then_branch, found);
405                if let Some(else_branch) = else_branch {
406                    collect_expr(else_branch, found);
407                }
408            }
409            ExprKind::Match { scrutinee, arms } => {
410                collect_expr(scrutinee, found);
411                for arm in arms {
412                    collect_pattern(&arm.pattern, found);
413                    collect_expr(&arm.body, found);
414                }
415            }
416            ExprKind::For { iterable, body, .. } => {
417                collect_expr(iterable, found);
418                collect_block(body, found);
419            }
420            ExprKind::While { condition, body } => {
421                collect_expr(condition, found);
422                collect_block(body, found);
423            }
424            ExprKind::Return(value) | ExprKind::Break(value) => {
425                if let Some(value) = value {
426                    collect_expr(value, found);
427                }
428            }
429            ExprKind::Lambda { params, body, .. } => {
430                collect_params(params, found);
431                collect_block(body, found);
432            }
433            ExprKind::Scope { body, .. } => collect_block(body, found),
434            ExprKind::Range { start, end, .. } => {
435                collect_expr(start, found);
436                collect_expr(end, found);
437            }
438        }
439    }
440
441    /// The source text a span covers.
442    fn snippet(sources: &SourceMap, span: Span) -> &str {
443        &sources.get(span.file).text[span.start as usize..span.end as usize]
444    }
445
446    /// The ids of every expression whose source text is exactly `text`.
447    fn ids_of(unit: &SourceUnit, sources: &SourceMap, text: &str) -> Vec<ExprId> {
448        collect(unit)
449            .iter()
450            .filter(|expr| snippet(sources, expr.span) == text)
451            .map(|expr| expr.id)
452            .collect()
453    }
454
455    fn parse_with(source: &str) -> (SourceUnit, SourceMap) {
456        let mut sources = SourceMap::new();
457        let file = sources.add("test.cove", source.to_string());
458        let unit = crate::parse_file(&sources, file).expect("source parses");
459        (unit, sources)
460    }
461
462    #[test]
463    fn every_expression_is_numbered() {
464        let unit = parse(AWKWARD);
465        let found = collect(&unit);
466        assert!(!found.is_empty(), "the source has expressions");
467        for expr in &found {
468            assert_ne!(
469                expr.id,
470                ExprId::UNSET,
471                "expression {:?} was left unnumbered",
472                expr.kind
473            );
474        }
475    }
476
477    /// Checks completeness without trusting either hand-written walk.
478    ///
479    /// The derived `Debug` reaches every field of every node there is, so an
480    /// id left unset shows up in its text wherever it is hiding, and the
481    /// number of ids in that text is the number of expressions the tree
482    /// actually holds — which is what says the walk above visits all of them.
483    #[test]
484    fn no_unset_id_survives_anywhere_in_the_tree() {
485        let unit = parse(AWKWARD);
486        let debug = format!("{unit:?}");
487        let unset = format!("{:?}", ExprId::UNSET);
488        assert!(
489            !debug.contains(&unset),
490            "an expression somewhere still holds {unset}"
491        );
492        assert_eq!(
493            debug.matches("ExprId(").count(),
494            collect(&unit).len(),
495            "the walk in this test visits every expression the tree holds"
496        );
497    }
498
499    #[test]
500    fn the_ids_are_exactly_zero_to_n_without_gaps_or_duplicates() {
501        let unit = parse(AWKWARD);
502        let mut ids: Vec<u32> = collect(&unit).iter().map(|expr| expr.id.0).collect();
503        let count = ids.len();
504        ids.sort_unstable();
505        assert_eq!(ids, (0..count as u32).collect::<Vec<_>>());
506        assert_eq!(
507            ids.iter().collect::<HashSet<_>>().len(),
508            count,
509            "no id is used twice"
510        );
511    }
512
513    #[test]
514    fn numbering_is_deterministic() {
515        let first = collect(&parse(AWKWARD));
516        let second = collect(&parse(AWKWARD));
517        let first: Vec<_> = first.iter().map(|expr| (expr.id, expr.span)).collect();
518        let second: Vec<_> = second.iter().map(|expr| (expr.id, expr.span)).collect();
519        assert_eq!(first, second);
520    }
521
522    #[test]
523    fn numbering_twice_changes_nothing() {
524        let mut unit = parse(AWKWARD);
525        let before: Vec<_> = collect(&unit).iter().map(|expr| expr.id).collect();
526        number_unit(&mut unit);
527        let after: Vec<_> = collect(&unit).iter().map(|expr| expr.id).collect();
528        assert_eq!(before, after);
529    }
530
531    #[test]
532    fn the_easy_to_miss_corners_are_numbered() {
533        let (unit, sources) = parse_with(AWKWARD);
534
535        // A parameter default.
536        assert_eq!(ids_of(&unit, &sources, "1 + 1").len(), 1);
537        // A string interpolation: the expression inside the braces, not the
538        // literal that holds it.
539        assert_eq!(ids_of(&unit, &sources, "limit").len(), 2);
540        // A match arm body, and the literal pattern beside it.
541        assert_eq!(ids_of(&unit, &sources, "helper(i)").len(), 1);
542        assert_eq!(ids_of(&unit, &sources, "0").len(), 2);
543        // A trailing closure.
544        assert_eq!(ids_of(&unit, &sources, "{\n  }").len(), 1);
545        // The body of a nested local `fn`.
546        assert_eq!(ids_of(&unit, &sources, "x + 1").len(), 1);
547
548        for text in ["1 + 1", "limit", "helper(i)", "0", "{\n  }", "x + 1"] {
549            for id in ids_of(&unit, &sources, text) {
550                assert_ne!(id, ExprId::UNSET, "`{text}` was left unnumbered");
551            }
552        }
553    }
554
555    #[test]
556    fn a_lambda_parameter_default_is_numbered() {
557        let (unit, sources) =
558            parse_with("export fn main() {\n  let f = fn(x = 7) {\n    x\n  }\n}\n");
559        assert_eq!(ids_of(&unit, &sources, "7").len(), 1);
560        for expr in collect(&unit) {
561            assert_ne!(expr.id, ExprId::UNSET);
562        }
563    }
564
565    #[test]
566    fn ids_do_not_leak_across_files() {
567        let mut sources = SourceMap::new();
568        let first = sources.add("first.cove", "export fn a() {\n  1\n}\n".to_string());
569        let second = sources.add("second.cove", "export fn b() {\n  2\n}\n".to_string());
570        let first = crate::parse_file(&sources, first).expect("first parses");
571        let second = crate::parse_file(&sources, second).expect("second parses");
572
573        let first: Vec<_> = collect(&first).iter().map(|expr| expr.id).collect();
574        let second: Vec<_> = collect(&second).iter().map(|expr| expr.id).collect();
575        assert_eq!(first, vec![ExprId(0)]);
576        assert_eq!(second, vec![ExprId(0)]);
577    }
578
579    #[test]
580    fn parents_are_numbered_before_their_children() {
581        let (unit, sources) = parse_with("export fn main() {\n  1 + 2\n}\n");
582        let ids = |text| ids_of(&unit, &sources, text);
583        assert_eq!(ids("1 + 2"), vec![ExprId(0)]);
584        assert_eq!(ids("1"), vec![ExprId(1)]);
585        assert_eq!(ids("2"), vec![ExprId(2)]);
586    }
587}