1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! The AST parsed by the chirp grammar.
//!
//! # Architecture
//!
//! So this isn't a casual AST. It is designed as a single contiguous buffer.
//!
//! Basically, each node is a variable size slice of this contiguous buffer.
//!
//! The type of the buffer is [`Block`](header::Block) where `Block` is just a `u32`. Each node
//! has:
//!
//! 1. A fixed size "header", that takes a fixed number of blocks and has a fixed layout.
//! 2. Optionally a variable size list of sub-items. Such as arguments to methods
//! or methods and children to statements.
//!
//! The "header" contains information proper to the node (such as the `name` of
//! a statement, and the size of the sub-item lists of AST nodes within this node.)
//!
//! A "sub-item" list is a variable length homogenous list (think of a `Vec<T>`) of a given node.
//!
//! For example, `Template` may have arguments, methods, or children statements.
//! `ChirpFile` has multiple imports, fn declarations, and a single root statement.
//!
//! We have two kind of sub-item lists:
//!
//! - Fixed size item lists, when the item has a fixed size (such as `Argument` or `Import`)
//! - Dynamic size item lists, when the item has a dynamic size (such as `Methods` or `Statements`)
//!
//! The size of the sub-item list is expressed as the item count when the item
//! has a fixed size. While it is expressed as the number of blocks occupied by
//! the list when the item has a dynamic size.
//!
//! The distinction is carefully kept in this module:
//!
//! - Methods returning a block length are suffixed with **`_len`**.
//! - Methods returning item counts are suffixed with **`_count`**.
//!
//! This is important to express it as the number of blocks for dynamic size lists
//! because then we can crate a slice with the complete list within it and safely
//! iterate through dynamic-size stuff, which is usually completely impossible in rust.
//!
//! ## Node layout
//!
//! Currently the layout (header order and sub-item list order) is defined in
//! `design_docs/ast.md`.
//!
//! - In [`header`], we define helpers to define headers
//! - In [`node`], we define all the AST nodes, using [`header`] helpers inside macros
//! - In [`build`], we define a way to build AST nodes on top of a buffer.
//!
//! ## Creating the AST
//!
//! This setup has a major flaw: It doesn't play nice with the `winnow` API.
//! Most "many" combinators in `winnow` work by creating an accumulator, pushing
//! items to it and returning that iterator.
//!
//! The single buffer architecture requires keeping a single buffer and accumulate
//! new blocks into it. The accumulator cannot be created from nothing.
//!
//! Thankfully, `winnow` is very flexible, and allows imperative style.
//! [`AstBuilder`] is the single buffer for the AST. Through the [`WriteHeader`]
//! trait, it knows about the layout and size of each AST node headers (as
//! `WriteHeader` is implemented for each AST nodes in the [`node`] macro).
//!
//! In [`crate::parser::grammar::chirp_file`] each time we encounter a new node, we:
//!
//! - "reserve" an unitialized header with [`AstBuilder::reserve_header`].
//! - Add the sub-item nodes of this node, counting them
//! - Create a `node::XYZHeader` struct, a representation of the header content
//! with the counted nodes.
//! - Write to the reserved header with [`AstBuilder::write`].
pub use ;
pub use *;
pub use List;
pub use FnIndex;
pub use ;
pub use ;
pub use ;
pub type Methods<'a> = ;
pub type Statements<'a> = ;
pub type Arguments<'a> = ;
pub type IdentOffsets<'a> = ;
;
;
const