1use crate::ast::{
21 Arg, Block, Expr, ExprId, ExprKind, Item, ItemKind, MatchArm, Param, Pattern, PatternKind,
22 SourceUnit, Stmt, StmtKind, StrPart,
23};
24
25pub 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
45struct Numberer {
47 next: u32,
49}
50
51impl Numberer {
52 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 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 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 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 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 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) = ¶m.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 fn snippet(sources: &SourceMap, span: Span) -> &str {
443 &sources.get(span.file).text[span.start as usize..span.end as usize]
444 }
445
446 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 #[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 assert_eq!(ids_of(&unit, &sources, "1 + 1").len(), 1);
537 assert_eq!(ids_of(&unit, &sources, "limit").len(), 2);
540 assert_eq!(ids_of(&unit, &sources, "helper(i)").len(), 1);
542 assert_eq!(ids_of(&unit, &sources, "0").len(), 2);
543 assert_eq!(ids_of(&unit, &sources, "{\n }").len(), 1);
545 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}