v / vlib / v2 / ast / flatbackup
1286 lines · 1223 sloc · 27.73 KB · 113fab684d3c76dd7b32c4c9db24fc3fb8b55de8
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module ast
5
6pub type FlatNodeId = int
7
8pub const invalid_flat_node_id = FlatNodeId(-1)
9
10// FlatNodeKind is a dense tag for every stored AST node variant.
11pub enum FlatNodeKind {
12 file
13 stmt_asm
14 stmt_assert
15 stmt_assign
16 stmt_block
17 stmt_comptime
18 stmt_const_decl
19 stmt_defer
20 stmt_directive
21 stmt_empty
22 stmt_enum_decl
23 stmt_expr
24 stmt_flow_control
25 stmt_fn_decl
26 stmt_for_in
27 stmt_for
28 stmt_global_decl
29 stmt_import
30 stmt_interface_decl
31 stmt_label
32 stmt_module
33 stmt_return
34 stmt_struct_decl
35 stmt_type_decl
36 stmt_attributes
37 expr_array_init
38 expr_as_cast
39 expr_assoc
40 expr_basic_literal
41 expr_call
42 expr_call_or_cast
43 expr_cast
44 expr_comptime
45 expr_empty
46 expr_fn_literal
47 expr_generic_arg_or_index
48 expr_generic_args
49 expr_ident
50 expr_if
51 expr_if_guard
52 expr_index
53 expr_infix
54 expr_init
55 expr_keyword
56 expr_keyword_operator
57 expr_lambda
58 expr_lock
59 expr_map_init
60 expr_match
61 expr_modifier
62 expr_or
63 expr_paren
64 expr_postfix
65 expr_prefix
66 expr_range
67 expr_select
68 expr_selector
69 expr_sql
70 expr_string_inter
71 expr_string
72 expr_tuple
73 expr_unsafe
74 typ_anon_struct
75 typ_array_fixed
76 typ_array
77 typ_channel
78 typ_fn
79 typ_generic
80 typ_map
81 typ_nil
82 typ_none
83 typ_option
84 typ_result
85 typ_thread
86 typ_tuple
87 aux_attribute
88 aux_field_init
89 aux_field_decl
90 aux_parameter
91 aux_match_branch
92 aux_string_inter
93}
94
95// FlatEdge represents a parent->child relationship.
96pub struct FlatEdge {
97pub:
98 child_id FlatNodeId
99}
100
101// FlatNode stores a compact, index-based AST node.
102pub struct FlatNode {
103pub:
104 kind FlatNodeKind
105 data_idx int = -1
106 first_edge int
107 edge_count int
108}
109
110// FlatFile maps a source file to its flat root node.
111pub struct FlatFile {
112pub:
113 file_id FlatNodeId
114 name_idx int
115 mod_idx int
116}
117
118// FlatAst is a contiguous AST graph representation.
119pub struct FlatAst {
120pub mut:
121 files []FlatFile
122 nodes []FlatNode
123 edges []FlatEdge
124 strings []string
125}
126
127// FlatAstStats captures high-level memory and shape metrics.
128pub struct FlatAstStats {
129pub:
130 file_roots int
131 nodes int
132 edges int
133 strings int
134 string_bytes u64
135 bytes_estimate u64
136}
137
138// LegacyAstStats captures estimated dynamic memory and node shape for the existing AST.
139pub struct LegacyAstStats {
140pub mut:
141 files int
142 expr_nodes int
143 stmt_nodes int
144 type_nodes int
145 aux_nodes int
146 node_bytes u64
147 array_bytes u64
148 string_entries int
149 string_bytes u64
150 bytes_estimate u64
151}
152
153// flatten_files converts recursive v2 AST files into a flat, index-based graph.
154pub fn flatten_files(files []File) FlatAst {
155 mut b := new_flat_builder()
156 for file in files {
157 file_id := b.add_file(file)
158 b.flat.files << FlatFile{
159 file_id: file_id
160 name_idx: b.intern(file.name)
161 mod_idx: b.intern(file.mod)
162 }
163 }
164 return b.flat
165}
166
167// legacy_ast_stats estimates dynamic memory and node counts for the recursive AST.
168pub fn legacy_ast_stats(files []File) LegacyAstStats {
169 mut w := LegacyAstWalker{}
170 w.walk_files(files)
171 return w.stats
172}
173
174// count_legacy_nodes returns the total legacy node count used by the walker.
175pub fn count_legacy_nodes(files []File) int {
176 stats := legacy_ast_stats(files)
177 return stats.files + stats.expr_nodes + stats.stmt_nodes + stats.type_nodes + stats.aux_nodes
178}
179
180// stats returns aggregate shape and estimated memory usage for FlatAst.
181pub fn (flat &FlatAst) stats() FlatAstStats {
182 mut string_bytes := u64(0)
183 for s in flat.strings {
184 string_bytes += u64(s.len)
185 }
186 mut bytes := u64(flat.files.len) * u64(sizeof(FlatFile))
187 bytes += u64(flat.nodes.len) * u64(sizeof(FlatNode))
188 bytes += u64(flat.edges.len) * u64(sizeof(FlatEdge))
189 bytes += u64(flat.strings.len) * u64(sizeof(string))
190 bytes += string_bytes
191 return FlatAstStats{
192 file_roots: flat.files.len
193 nodes: flat.nodes.len
194 edges: flat.edges.len
195 strings: flat.strings.len
196 string_bytes: string_bytes
197 bytes_estimate: bytes
198 }
199}
200
201// count_reachable_nodes traverses from file roots and counts unique reachable nodes.
202pub fn (flat &FlatAst) count_reachable_nodes() int {
203 if flat.nodes.len == 0 || flat.files.len == 0 {
204 return 0
205 }
206 mut seen := []bool{len: flat.nodes.len}
207 mut stack := []int{cap: flat.files.len}
208 for file in flat.files {
209 stack << file.file_id
210 }
211 mut count := 0
212 for stack.len > 0 {
213 node_id := stack.pop()
214 if node_id < 0 || node_id >= flat.nodes.len {
215 continue
216 }
217 if seen[node_id] {
218 continue
219 }
220 seen[node_id] = true
221 count++
222 node := flat.nodes[node_id]
223 for i in 0 .. node.edge_count {
224 edge := flat.edges[node.first_edge + i]
225 stack << edge.child_id
226 }
227 }
228 return count
229}
230
231// node_type_name returns the short type-name tag associated with a flat node.
232pub fn (flat &FlatAst) node_type_name(node_id FlatNodeId) string {
233 if node_id < 0 || node_id >= flat.nodes.len {
234 return ''
235 }
236 return flat.nodes[node_id].kind.str()
237}
238
239struct FlatBuilder {
240mut:
241 flat FlatAst
242 string_ids map[string]int
243}
244
245fn new_flat_builder() FlatBuilder {
246 return FlatBuilder{
247 flat: FlatAst{
248 files: []FlatFile{}
249 nodes: []FlatNode{cap: 1024}
250 edges: []FlatEdge{cap: 2048}
251 strings: []string{cap: 512}
252 }
253 string_ids: map[string]int{}
254 }
255}
256
257fn (mut b FlatBuilder) intern(s string) int {
258 if idx := b.string_ids[s] {
259 return idx
260 }
261 idx := b.flat.strings.len
262 b.flat.strings << s
263 b.string_ids[s] = idx
264 return idx
265}
266
267fn (mut b FlatBuilder) add_node(kind FlatNodeKind, data string, edges []FlatEdge) FlatNodeId {
268 first_edge := b.flat.edges.len
269 if edges.len > 0 {
270 b.flat.edges << edges
271 }
272 node_id := FlatNodeId(b.flat.nodes.len)
273 b.flat.nodes << FlatNode{
274 kind: kind
275 data_idx: if data.len > 0 { b.intern(data) } else { -1 }
276 first_edge: first_edge
277 edge_count: edges.len
278 }
279 return node_id
280}
281
282fn (mut b FlatBuilder) push_edge(mut edges []FlatEdge, child FlatNodeId) {
283 if child == invalid_flat_node_id {
284 return
285 }
286 edges << FlatEdge{
287 child_id: child
288 }
289}
290
291fn (mut b FlatBuilder) push_expr(mut edges []FlatEdge, expr Expr) {
292 b.push_edge(mut edges, b.add_expr(expr))
293}
294
295fn (mut b FlatBuilder) push_stmt(mut edges []FlatEdge, stmt Stmt) {
296 b.push_edge(mut edges, b.add_stmt(stmt))
297}
298
299fn (mut b FlatBuilder) push_type(mut edges []FlatEdge, typ Type) {
300 b.push_edge(mut edges, b.add_type(typ))
301}
302
303fn (mut b FlatBuilder) push_attribute(mut edges []FlatEdge, attr Attribute) {
304 b.push_edge(mut edges, b.add_attribute(attr))
305}
306
307fn (mut b FlatBuilder) push_field_init(mut edges []FlatEdge, field FieldInit) {
308 b.push_edge(mut edges, b.add_field_init(field))
309}
310
311fn (mut b FlatBuilder) push_field_decl(mut edges []FlatEdge, field FieldDecl) {
312 b.push_edge(mut edges, b.add_field_decl(field))
313}
314
315fn (mut b FlatBuilder) push_parameter(mut edges []FlatEdge, param Parameter) {
316 b.push_edge(mut edges, b.add_parameter(param))
317}
318
319fn (mut b FlatBuilder) push_match_branch(mut edges []FlatEdge, branch MatchBranch) {
320 b.push_edge(mut edges, b.add_match_branch(branch))
321}
322
323fn (mut b FlatBuilder) push_string_inter(mut edges []FlatEdge, inter StringInter) {
324 b.push_edge(mut edges, b.add_string_inter(inter))
325}
326
327fn (mut b FlatBuilder) collect_children[T](node T, mut edges []FlatEdge) {
328 $for field in T.fields {
329 $if field.typ is Expr {
330 b.push_expr(mut edges, node.$(field.name))
331 } $else $if field.typ is []Expr {
332 for child in node.$(field.name) {
333 b.push_expr(mut edges, child)
334 }
335 } $else $if field.typ is Stmt {
336 b.push_stmt(mut edges, node.$(field.name))
337 } $else $if field.typ is []Stmt {
338 for child in node.$(field.name) {
339 b.push_stmt(mut edges, child)
340 }
341 } $else $if field.typ is Type {
342 b.push_type(mut edges, node.$(field.name))
343 } $else $if field.typ is []Type {
344 for child in node.$(field.name) {
345 b.push_type(mut edges, child)
346 }
347 } $else $if field.typ is Attribute {
348 b.push_attribute(mut edges, node.$(field.name))
349 } $else $if field.typ is []Attribute {
350 for child in node.$(field.name) {
351 b.push_attribute(mut edges, child)
352 }
353 } $else $if field.typ is FieldInit {
354 b.push_field_init(mut edges, node.$(field.name))
355 } $else $if field.typ is []FieldInit {
356 for child in node.$(field.name) {
357 b.push_field_init(mut edges, child)
358 }
359 } $else $if field.typ is FieldDecl {
360 b.push_field_decl(mut edges, node.$(field.name))
361 } $else $if field.typ is []FieldDecl {
362 for child in node.$(field.name) {
363 b.push_field_decl(mut edges, child)
364 }
365 } $else $if field.typ is Parameter {
366 b.push_parameter(mut edges, node.$(field.name))
367 } $else $if field.typ is []Parameter {
368 for child in node.$(field.name) {
369 b.push_parameter(mut edges, child)
370 }
371 } $else $if field.typ is MatchBranch {
372 b.push_match_branch(mut edges, node.$(field.name))
373 } $else $if field.typ is []MatchBranch {
374 for child in node.$(field.name) {
375 b.push_match_branch(mut edges, child)
376 }
377 } $else $if field.typ is StringInter {
378 b.push_string_inter(mut edges, node.$(field.name))
379 } $else $if field.typ is []StringInter {
380 for child in node.$(field.name) {
381 b.push_string_inter(mut edges, child)
382 }
383 } $else $if field.typ is Ident {
384 b.push_expr(mut edges, Expr(node.$(field.name)))
385 } $else $if field.typ is []Ident {
386 for child in node.$(field.name) {
387 b.push_expr(mut edges, Expr(child))
388 }
389 } $else $if field.typ is ImportStmt {
390 b.push_stmt(mut edges, Stmt(node.$(field.name)))
391 } $else $if field.typ is []ImportStmt {
392 for child in node.$(field.name) {
393 b.push_stmt(mut edges, Stmt(child))
394 }
395 } $else $if field.typ is AnonStructType {
396 b.push_type(mut edges, Type(node.$(field.name)))
397 } $else $if field.typ is ArrayFixedType {
398 b.push_type(mut edges, Type(node.$(field.name)))
399 } $else $if field.typ is ArrayType {
400 b.push_type(mut edges, Type(node.$(field.name)))
401 } $else $if field.typ is ChannelType {
402 b.push_type(mut edges, Type(node.$(field.name)))
403 } $else $if field.typ is FnType {
404 b.push_type(mut edges, Type(node.$(field.name)))
405 } $else $if field.typ is GenericType {
406 b.push_type(mut edges, Type(node.$(field.name)))
407 } $else $if field.typ is MapType {
408 b.push_type(mut edges, Type(node.$(field.name)))
409 } $else $if field.typ is NilType {
410 b.push_type(mut edges, Type(node.$(field.name)))
411 } $else $if field.typ is NoneType {
412 b.push_type(mut edges, Type(node.$(field.name)))
413 } $else $if field.typ is OptionType {
414 b.push_type(mut edges, Type(node.$(field.name)))
415 } $else $if field.typ is ResultType {
416 b.push_type(mut edges, Type(node.$(field.name)))
417 } $else $if field.typ is ThreadType {
418 b.push_type(mut edges, Type(node.$(field.name)))
419 } $else $if field.typ is TupleType {
420 b.push_type(mut edges, Type(node.$(field.name)))
421 }
422 }
423}
424
425fn (mut b FlatBuilder) add_file(file File) FlatNodeId {
426 mut edges := []FlatEdge{}
427 for attr in file.attributes {
428 b.push_attribute(mut edges, attr)
429 }
430 for imp in file.imports {
431 b.push_stmt(mut edges, Stmt(imp))
432 }
433 for stmt in file.stmts {
434 b.push_stmt(mut edges, stmt)
435 }
436 return b.add_node(.file, file.name, edges)
437}
438
439fn (mut b FlatBuilder) add_stmt(stmt Stmt) FlatNodeId {
440 if stmt is []Attribute {
441 mut edges := []FlatEdge{}
442 for attr in stmt {
443 b.push_attribute(mut edges, attr)
444 }
445 return b.add_node(.stmt_attributes, '', edges)
446 }
447
448 mut edges := []FlatEdge{}
449 mut data := ''
450 mut kind := FlatNodeKind.stmt_empty
451
452 match stmt {
453 AsmStmt {
454 kind = .stmt_asm
455 data = stmt.arch
456 }
457 AssertStmt {
458 kind = .stmt_assert
459 b.collect_children(stmt, mut edges)
460 }
461 AssignStmt {
462 kind = .stmt_assign
463 data = stmt.op.str()
464 b.collect_children(stmt, mut edges)
465 }
466 BlockStmt {
467 kind = .stmt_block
468 b.collect_children(stmt, mut edges)
469 }
470 ComptimeStmt {
471 kind = .stmt_comptime
472 b.collect_children(stmt, mut edges)
473 }
474 ConstDecl {
475 kind = .stmt_const_decl
476 if stmt.is_public {
477 data = 'pub'
478 }
479 b.collect_children(stmt, mut edges)
480 }
481 DeferStmt {
482 kind = .stmt_defer
483 data = stmt.mode.str()
484 b.collect_children(stmt, mut edges)
485 }
486 Directive {
487 kind = .stmt_directive
488 data = '${stmt.name}:${stmt.value}'
489 }
490 EmptyStmt {
491 kind = .stmt_empty
492 }
493 EnumDecl {
494 kind = .stmt_enum_decl
495 data = stmt.name
496 if stmt.is_public {
497 data = 'pub ${stmt.name}'
498 }
499 b.collect_children(stmt, mut edges)
500 }
501 ExprStmt {
502 kind = .stmt_expr
503 b.collect_children(stmt, mut edges)
504 }
505 FlowControlStmt {
506 kind = .stmt_flow_control
507 data = '${stmt.op.str()}:${stmt.label}'
508 }
509 FnDecl {
510 kind = .stmt_fn_decl
511 data = stmt.name
512 if stmt.is_public {
513 data = 'pub ${data}'
514 }
515 if stmt.is_method {
516 data = 'method ${data}'
517 }
518 if stmt.is_static {
519 data = 'static ${data}'
520 }
521 b.collect_children(stmt, mut edges)
522 }
523 ForInStmt {
524 kind = .stmt_for_in
525 b.collect_children(stmt, mut edges)
526 }
527 ForStmt {
528 kind = .stmt_for
529 b.collect_children(stmt, mut edges)
530 }
531 GlobalDecl {
532 kind = .stmt_global_decl
533 b.collect_children(stmt, mut edges)
534 }
535 ImportStmt {
536 kind = .stmt_import
537 data = if stmt.alias.len > 0 { '${stmt.name}:${stmt.alias}' } else { stmt.name }
538 b.collect_children(stmt, mut edges)
539 }
540 InterfaceDecl {
541 kind = .stmt_interface_decl
542 data = stmt.name
543 if stmt.is_public {
544 data = 'pub ${stmt.name}'
545 }
546 b.collect_children(stmt, mut edges)
547 }
548 LabelStmt {
549 kind = .stmt_label
550 data = stmt.name
551 b.collect_children(stmt, mut edges)
552 }
553 ModuleStmt {
554 kind = .stmt_module
555 data = stmt.name
556 }
557 ReturnStmt {
558 kind = .stmt_return
559 b.collect_children(stmt, mut edges)
560 }
561 StructDecl {
562 kind = .stmt_struct_decl
563 data = stmt.name
564 if stmt.is_public {
565 data = 'pub ${data}'
566 }
567 if stmt.is_union {
568 data = 'union ${data}'
569 }
570 b.collect_children(stmt, mut edges)
571 }
572 TypeDecl {
573 kind = .stmt_type_decl
574 data = stmt.name
575 if stmt.is_public {
576 data = 'pub ${data}'
577 }
578 b.collect_children(stmt, mut edges)
579 }
580 []Attribute {}
581 }
582
583 return b.add_node(kind, data, edges)
584}
585
586fn (mut b FlatBuilder) add_expr(expr Expr) FlatNodeId {
587 match expr {
588 Type {
589 return b.add_type(expr)
590 }
591 FieldInit {
592 return b.add_field_init(expr)
593 }
594 else {}
595 }
596
597 mut edges := []FlatEdge{}
598 mut data := ''
599 mut kind := FlatNodeKind.expr_empty
600
601 match expr {
602 ArrayInitExpr {
603 kind = .expr_array_init
604 b.collect_children(expr, mut edges)
605 }
606 AsCastExpr {
607 kind = .expr_as_cast
608 b.collect_children(expr, mut edges)
609 }
610 AssocExpr {
611 kind = .expr_assoc
612 b.collect_children(expr, mut edges)
613 }
614 BasicLiteral {
615 kind = .expr_basic_literal
616 data = '${expr.kind.str()}:${expr.value}'
617 }
618 CallExpr {
619 kind = .expr_call
620 b.collect_children(expr, mut edges)
621 }
622 CallOrCastExpr {
623 kind = .expr_call_or_cast
624 b.collect_children(expr, mut edges)
625 }
626 CastExpr {
627 kind = .expr_cast
628 b.collect_children(expr, mut edges)
629 }
630 ComptimeExpr {
631 kind = .expr_comptime
632 b.collect_children(expr, mut edges)
633 }
634 EmptyExpr {
635 kind = .expr_empty
636 }
637 FnLiteral {
638 kind = .expr_fn_literal
639 b.collect_children(expr, mut edges)
640 }
641 GenericArgOrIndexExpr {
642 kind = .expr_generic_arg_or_index
643 b.collect_children(expr, mut edges)
644 }
645 GenericArgs {
646 kind = .expr_generic_args
647 b.collect_children(expr, mut edges)
648 }
649 Ident {
650 kind = .expr_ident
651 data = expr.name
652 }
653 IfExpr {
654 kind = .expr_if
655 b.collect_children(expr, mut edges)
656 }
657 IfGuardExpr {
658 kind = .expr_if_guard
659 b.collect_children(expr, mut edges)
660 }
661 IndexExpr {
662 kind = .expr_index
663 if expr.is_gated {
664 data = 'gated'
665 }
666 b.collect_children(expr, mut edges)
667 }
668 InfixExpr {
669 kind = .expr_infix
670 data = expr.op.str()
671 b.collect_children(expr, mut edges)
672 }
673 InitExpr {
674 kind = .expr_init
675 b.collect_children(expr, mut edges)
676 }
677 Keyword {
678 kind = .expr_keyword
679 data = expr.tok.str()
680 }
681 KeywordOperator {
682 kind = .expr_keyword_operator
683 data = expr.op.str()
684 b.collect_children(expr, mut edges)
685 }
686 LambdaExpr {
687 kind = .expr_lambda
688 b.collect_children(expr, mut edges)
689 }
690 LockExpr {
691 kind = .expr_lock
692 b.collect_children(expr, mut edges)
693 }
694 MapInitExpr {
695 kind = .expr_map_init
696 b.collect_children(expr, mut edges)
697 }
698 MatchExpr {
699 kind = .expr_match
700 b.collect_children(expr, mut edges)
701 }
702 ModifierExpr {
703 kind = .expr_modifier
704 data = expr.kind.str()
705 b.collect_children(expr, mut edges)
706 }
707 OrExpr {
708 kind = .expr_or
709 b.collect_children(expr, mut edges)
710 }
711 ParenExpr {
712 kind = .expr_paren
713 b.collect_children(expr, mut edges)
714 }
715 PostfixExpr {
716 kind = .expr_postfix
717 data = expr.op.str()
718 b.collect_children(expr, mut edges)
719 }
720 PrefixExpr {
721 kind = .expr_prefix
722 data = expr.op.str()
723 b.collect_children(expr, mut edges)
724 }
725 RangeExpr {
726 kind = .expr_range
727 data = expr.op.str()
728 b.collect_children(expr, mut edges)
729 }
730 SelectExpr {
731 kind = .expr_select
732 b.collect_children(expr, mut edges)
733 }
734 SelectorExpr {
735 kind = .expr_selector
736 b.collect_children(expr, mut edges)
737 }
738 SqlExpr {
739 kind = .expr_sql
740 b.collect_children(expr, mut edges)
741 }
742 StringInterLiteral {
743 kind = .expr_string_inter
744 if expr.values.len > 0 {
745 data = '${expr.values[0]}:${expr.values.len}'
746 }
747 b.collect_children(expr, mut edges)
748 }
749 StringLiteral {
750 kind = .expr_string
751 data = '${expr.kind.str()}:${expr.value}'
752 }
753 Tuple {
754 kind = .expr_tuple
755 b.collect_children(expr, mut edges)
756 }
757 Type {}
758 UnsafeExpr {
759 kind = .expr_unsafe
760 b.collect_children(expr, mut edges)
761 }
762 FieldInit {}
763 }
764
765 return b.add_node(kind, data, edges)
766}
767
768fn (mut b FlatBuilder) add_type(typ Type) FlatNodeId {
769 mut edges := []FlatEdge{}
770 mut data := ''
771 mut kind := FlatNodeKind.typ_nil
772
773 match typ {
774 AnonStructType {
775 kind = .typ_anon_struct
776 b.collect_children(typ, mut edges)
777 }
778 ArrayFixedType {
779 kind = .typ_array_fixed
780 b.collect_children(typ, mut edges)
781 }
782 ArrayType {
783 kind = .typ_array
784 b.collect_children(typ, mut edges)
785 }
786 ChannelType {
787 kind = .typ_channel
788 b.collect_children(typ, mut edges)
789 }
790 FnType {
791 kind = .typ_fn
792 b.collect_children(typ, mut edges)
793 }
794 GenericType {
795 kind = .typ_generic
796 data = typ.name.name()
797 b.collect_children(typ, mut edges)
798 }
799 MapType {
800 kind = .typ_map
801 b.collect_children(typ, mut edges)
802 }
803 NilType {
804 kind = .typ_nil
805 }
806 NoneType {
807 kind = .typ_none
808 }
809 OptionType {
810 kind = .typ_option
811 b.collect_children(typ, mut edges)
812 }
813 ResultType {
814 kind = .typ_result
815 b.collect_children(typ, mut edges)
816 }
817 ThreadType {
818 kind = .typ_thread
819 b.collect_children(typ, mut edges)
820 }
821 TupleType {
822 kind = .typ_tuple
823 b.collect_children(typ, mut edges)
824 }
825 }
826
827 return b.add_node(kind, data, edges)
828}
829
830fn (mut b FlatBuilder) add_attribute(attr Attribute) FlatNodeId {
831 mut edges := []FlatEdge{}
832 b.collect_children(attr, mut edges)
833 return b.add_node(.aux_attribute, attr.name, edges)
834}
835
836fn (mut b FlatBuilder) add_field_init(field FieldInit) FlatNodeId {
837 mut edges := []FlatEdge{}
838 b.collect_children(field, mut edges)
839 return b.add_node(.aux_field_init, field.name, edges)
840}
841
842fn (mut b FlatBuilder) add_field_decl(field FieldDecl) FlatNodeId {
843 mut edges := []FlatEdge{}
844 b.collect_children(field, mut edges)
845 return b.add_node(.aux_field_decl, field.name, edges)
846}
847
848fn (mut b FlatBuilder) add_parameter(param Parameter) FlatNodeId {
849 mut edges := []FlatEdge{}
850 b.collect_children(param, mut edges)
851 name := if param.is_mut { 'mut ${param.name}' } else { param.name }
852 return b.add_node(.aux_parameter, name, edges)
853}
854
855fn (mut b FlatBuilder) add_match_branch(branch MatchBranch) FlatNodeId {
856 mut edges := []FlatEdge{}
857 b.collect_children(branch, mut edges)
858 return b.add_node(.aux_match_branch, '', edges)
859}
860
861fn (mut b FlatBuilder) add_string_inter(inter StringInter) FlatNodeId {
862 mut edges := []FlatEdge{}
863 b.collect_children(inter, mut edges)
864 data := '${inter.format.str()}:${inter.width}:${inter.precision}'
865 return b.add_node(.aux_string_inter, data, edges)
866}
867
868struct LegacyAstWalker {
869mut:
870 stats LegacyAstStats
871}
872
873fn (mut w LegacyAstWalker) walk_files(files []File) {
874 w.stats.files = files.len
875 w.stats.node_bytes += u64(files.len) * u64(sizeof(File))
876 w.add_array_storage(sizeof(File), files.len)
877 for file in files {
878 w.walk_file(file)
879 }
880 w.stats.bytes_estimate = w.stats.node_bytes + w.stats.array_bytes + w.stats.string_bytes
881}
882
883fn (mut w LegacyAstWalker) add_array_storage(elem_size u32, len int) {
884 if len <= 0 || elem_size == 0 {
885 return
886 }
887 w.stats.array_bytes += u64(elem_size) * u64(len)
888}
889
890fn (mut w LegacyAstWalker) add_string(s string) {
891 w.stats.string_entries++
892 w.stats.string_bytes += u64(s.len)
893}
894
895fn (mut w LegacyAstWalker) walk_file(file File) {
896 w.scan_dynamic(file)
897}
898
899fn (mut w LegacyAstWalker) walk_stmt(stmt Stmt) {
900 if stmt is []Attribute {
901 w.add_array_storage(sizeof(Attribute), stmt.len)
902 for attr in stmt {
903 w.walk_attribute(attr)
904 }
905 return
906 }
907 w.stats.stmt_nodes++
908 w.stats.node_bytes += u64(sizeof(Stmt))
909 match stmt {
910 AssignStmt {
911 w.scan_dynamic(stmt)
912 }
913 AssertStmt {
914 w.scan_dynamic(stmt)
915 }
916 AsmStmt {
917 w.scan_dynamic(stmt)
918 }
919 BlockStmt {
920 w.scan_dynamic(stmt)
921 }
922 ComptimeStmt {
923 w.scan_dynamic(stmt)
924 }
925 ConstDecl {
926 w.scan_dynamic(stmt)
927 }
928 DeferStmt {
929 w.scan_dynamic(stmt)
930 }
931 Directive {
932 w.scan_dynamic(stmt)
933 }
934 EmptyStmt {}
935 EnumDecl {
936 w.scan_dynamic(stmt)
937 }
938 ExprStmt {
939 w.scan_dynamic(stmt)
940 }
941 FlowControlStmt {
942 w.scan_dynamic(stmt)
943 }
944 FnDecl {
945 w.scan_dynamic(stmt)
946 }
947 ForInStmt {
948 w.scan_dynamic(stmt)
949 }
950 ForStmt {
951 w.scan_dynamic(stmt)
952 }
953 GlobalDecl {
954 w.scan_dynamic(stmt)
955 }
956 ImportStmt {
957 w.scan_dynamic(stmt)
958 }
959 InterfaceDecl {
960 w.scan_dynamic(stmt)
961 }
962 LabelStmt {
963 w.scan_dynamic(stmt)
964 }
965 ModuleStmt {
966 w.scan_dynamic(stmt)
967 }
968 ReturnStmt {
969 w.scan_dynamic(stmt)
970 }
971 StructDecl {
972 w.scan_dynamic(stmt)
973 }
974 TypeDecl {
975 w.scan_dynamic(stmt)
976 }
977 []Attribute {}
978 }
979}
980
981fn (mut w LegacyAstWalker) walk_expr(expr Expr) {
982 match expr {
983 Type {
984 w.walk_type(expr)
985 return
986 }
987 FieldInit {
988 w.walk_field_init(expr)
989 return
990 }
991 else {}
992 }
993 w.stats.expr_nodes++
994 w.stats.node_bytes += u64(sizeof(Expr))
995 match expr {
996 ArrayInitExpr {
997 w.scan_dynamic(expr)
998 }
999 AsCastExpr {
1000 w.scan_dynamic(expr)
1001 }
1002 AssocExpr {
1003 w.scan_dynamic(expr)
1004 }
1005 BasicLiteral {
1006 w.scan_dynamic(expr)
1007 }
1008 CallExpr {
1009 w.scan_dynamic(expr)
1010 }
1011 CallOrCastExpr {
1012 w.scan_dynamic(expr)
1013 }
1014 CastExpr {
1015 w.scan_dynamic(expr)
1016 }
1017 ComptimeExpr {
1018 w.scan_dynamic(expr)
1019 }
1020 EmptyExpr {}
1021 FnLiteral {
1022 w.scan_dynamic(expr)
1023 }
1024 GenericArgOrIndexExpr {
1025 w.scan_dynamic(expr)
1026 }
1027 GenericArgs {
1028 w.scan_dynamic(expr)
1029 }
1030 Ident {
1031 w.scan_dynamic(expr)
1032 }
1033 IfExpr {
1034 w.scan_dynamic(expr)
1035 }
1036 IfGuardExpr {
1037 w.scan_dynamic(expr)
1038 }
1039 IndexExpr {
1040 w.scan_dynamic(expr)
1041 }
1042 InfixExpr {
1043 w.scan_dynamic(expr)
1044 }
1045 InitExpr {
1046 w.scan_dynamic(expr)
1047 }
1048 Keyword {}
1049 KeywordOperator {
1050 w.scan_dynamic(expr)
1051 }
1052 LambdaExpr {
1053 w.scan_dynamic(expr)
1054 }
1055 LockExpr {
1056 w.scan_dynamic(expr)
1057 }
1058 MapInitExpr {
1059 w.scan_dynamic(expr)
1060 }
1061 MatchExpr {
1062 w.scan_dynamic(expr)
1063 }
1064 ModifierExpr {
1065 w.scan_dynamic(expr)
1066 }
1067 OrExpr {
1068 w.scan_dynamic(expr)
1069 }
1070 ParenExpr {
1071 w.scan_dynamic(expr)
1072 }
1073 PostfixExpr {
1074 w.scan_dynamic(expr)
1075 }
1076 PrefixExpr {
1077 w.scan_dynamic(expr)
1078 }
1079 RangeExpr {
1080 w.scan_dynamic(expr)
1081 }
1082 SelectExpr {
1083 w.scan_dynamic(expr)
1084 }
1085 SelectorExpr {
1086 w.scan_dynamic(expr)
1087 }
1088 SqlExpr {
1089 w.scan_dynamic(expr)
1090 }
1091 StringInterLiteral {
1092 w.scan_dynamic(expr)
1093 }
1094 StringLiteral {
1095 w.scan_dynamic(expr)
1096 }
1097 Tuple {
1098 w.scan_dynamic(expr)
1099 }
1100 Type {}
1101 UnsafeExpr {
1102 w.scan_dynamic(expr)
1103 }
1104 FieldInit {}
1105 }
1106}
1107
1108fn (mut w LegacyAstWalker) walk_type(typ Type) {
1109 w.stats.type_nodes++
1110 w.stats.node_bytes += u64(sizeof(Type))
1111 match typ {
1112 AnonStructType {
1113 w.scan_dynamic(typ)
1114 }
1115 ArrayFixedType {
1116 w.scan_dynamic(typ)
1117 }
1118 ArrayType {
1119 w.scan_dynamic(typ)
1120 }
1121 ChannelType {
1122 w.scan_dynamic(typ)
1123 }
1124 FnType {
1125 w.scan_dynamic(typ)
1126 }
1127 GenericType {
1128 w.scan_dynamic(typ)
1129 }
1130 MapType {
1131 w.scan_dynamic(typ)
1132 }
1133 NilType {}
1134 NoneType {}
1135 OptionType {
1136 w.scan_dynamic(typ)
1137 }
1138 ResultType {
1139 w.scan_dynamic(typ)
1140 }
1141 ThreadType {
1142 w.scan_dynamic(typ)
1143 }
1144 TupleType {
1145 w.scan_dynamic(typ)
1146 }
1147 }
1148}
1149
1150fn (mut w LegacyAstWalker) walk_attribute(attr Attribute) {
1151 w.stats.aux_nodes++
1152 w.stats.node_bytes += u64(sizeof(Attribute))
1153 w.scan_dynamic(attr)
1154}
1155
1156fn (mut w LegacyAstWalker) walk_field_init(field FieldInit) {
1157 w.stats.aux_nodes++
1158 w.stats.node_bytes += u64(sizeof(FieldInit))
1159 w.scan_dynamic(field)
1160}
1161
1162fn (mut w LegacyAstWalker) walk_field_decl(field FieldDecl) {
1163 w.stats.aux_nodes++
1164 w.stats.node_bytes += u64(sizeof(FieldDecl))
1165 w.scan_dynamic(field)
1166}
1167
1168fn (mut w LegacyAstWalker) walk_parameter(param Parameter) {
1169 w.stats.aux_nodes++
1170 w.stats.node_bytes += u64(sizeof(Parameter))
1171 w.scan_dynamic(param)
1172}
1173
1174fn (mut w LegacyAstWalker) walk_match_branch(branch MatchBranch) {
1175 w.stats.aux_nodes++
1176 w.stats.node_bytes += u64(sizeof(MatchBranch))
1177 w.scan_dynamic(branch)
1178}
1179
1180fn (mut w LegacyAstWalker) walk_string_inter(inter StringInter) {
1181 w.stats.aux_nodes++
1182 w.stats.node_bytes += u64(sizeof(StringInter))
1183 w.scan_dynamic(inter)
1184}
1185
1186fn (mut w LegacyAstWalker) scan_dynamic[T](node T) {
1187 $for field in T.fields {
1188 $if field.typ is string {
1189 w.add_string(node.$(field.name))
1190 } $else $if field.typ is []string {
1191 arr := node.$(field.name)
1192 w.add_array_storage(sizeof(string), arr.len)
1193 for v in arr {
1194 w.add_string(v)
1195 }
1196 } $else $if field.typ is Expr {
1197 w.walk_expr(node.$(field.name))
1198 } $else $if field.typ is []Expr {
1199 arr := node.$(field.name)
1200 w.add_array_storage(sizeof(Expr), arr.len)
1201 for v in arr {
1202 w.walk_expr(v)
1203 }
1204 } $else $if field.typ is Stmt {
1205 w.walk_stmt(node.$(field.name))
1206 } $else $if field.typ is []Stmt {
1207 arr := node.$(field.name)
1208 w.add_array_storage(sizeof(Stmt), arr.len)
1209 for v in arr {
1210 w.walk_stmt(v)
1211 }
1212 } $else $if field.typ is Type {
1213 w.walk_type(node.$(field.name))
1214 } $else $if field.typ is []Type {
1215 arr := node.$(field.name)
1216 w.add_array_storage(sizeof(Type), arr.len)
1217 for v in arr {
1218 w.walk_type(v)
1219 }
1220 } $else $if field.typ is Attribute {
1221 w.walk_attribute(node.$(field.name))
1222 } $else $if field.typ is []Attribute {
1223 arr := node.$(field.name)
1224 w.add_array_storage(sizeof(Attribute), arr.len)
1225 for v in arr {
1226 w.walk_attribute(v)
1227 }
1228 } $else $if field.typ is FieldInit {
1229 w.walk_field_init(node.$(field.name))
1230 } $else $if field.typ is []FieldInit {
1231 arr := node.$(field.name)
1232 w.add_array_storage(sizeof(FieldInit), arr.len)
1233 for v in arr {
1234 w.walk_field_init(v)
1235 }
1236 } $else $if field.typ is FieldDecl {
1237 w.walk_field_decl(node.$(field.name))
1238 } $else $if field.typ is []FieldDecl {
1239 arr := node.$(field.name)
1240 w.add_array_storage(sizeof(FieldDecl), arr.len)
1241 for v in arr {
1242 w.walk_field_decl(v)
1243 }
1244 } $else $if field.typ is Parameter {
1245 w.walk_parameter(node.$(field.name))
1246 } $else $if field.typ is []Parameter {
1247 arr := node.$(field.name)
1248 w.add_array_storage(sizeof(Parameter), arr.len)
1249 for v in arr {
1250 w.walk_parameter(v)
1251 }
1252 } $else $if field.typ is MatchBranch {
1253 w.walk_match_branch(node.$(field.name))
1254 } $else $if field.typ is []MatchBranch {
1255 arr := node.$(field.name)
1256 w.add_array_storage(sizeof(MatchBranch), arr.len)
1257 for v in arr {
1258 w.walk_match_branch(v)
1259 }
1260 } $else $if field.typ is StringInter {
1261 w.walk_string_inter(node.$(field.name))
1262 } $else $if field.typ is []StringInter {
1263 arr := node.$(field.name)
1264 w.add_array_storage(sizeof(StringInter), arr.len)
1265 for v in arr {
1266 w.walk_string_inter(v)
1267 }
1268 } $else $if field.typ is Ident {
1269 w.walk_expr(Expr(node.$(field.name)))
1270 } $else $if field.typ is []Ident {
1271 arr := node.$(field.name)
1272 w.add_array_storage(sizeof(Ident), arr.len)
1273 for v in arr {
1274 w.walk_expr(Expr(v))
1275 }
1276 } $else $if field.typ is ImportStmt {
1277 w.walk_stmt(Stmt(node.$(field.name)))
1278 } $else $if field.typ is []ImportStmt {
1279 arr := node.$(field.name)
1280 w.add_array_storage(sizeof(ImportStmt), arr.len)
1281 for v in arr {
1282 w.walk_stmt(Stmt(v))
1283 }
1284 }
1285 }
1286}
1287