1
1
//! Abstract Syntax Tree for Zig source code.
2
+ //! For Zig syntax, the root node is at nodes[0] and contains the list of
3
+ //! sub-nodes.
4
+ //! For Zon syntax, the root node is at nodes[0] and contains lhs as the node
5
+ //! index of the main expression.
2
6
3
7
/// Reference to externally-owned data.
4
8
source : [:0 ]const u8 ,
@@ -11,13 +15,6 @@ extra_data: []Node.Index,
11
15
12
16
errors : []const Error ,
13
17
14
- const std = @import ("../std.zig" );
15
- const assert = std .debug .assert ;
16
- const testing = std .testing ;
17
- const mem = std .mem ;
18
- const Token = std .zig .Token ;
19
- const Ast = @This ();
20
-
21
18
pub const TokenIndex = u32 ;
22
19
pub const ByteOffset = u32 ;
23
20
@@ -34,7 +31,7 @@ pub const Location = struct {
34
31
line_end : usize ,
35
32
};
36
33
37
- pub fn deinit (tree : * Ast , gpa : mem. Allocator ) void {
34
+ pub fn deinit (tree : * Ast , gpa : Allocator ) void {
38
35
tree .tokens .deinit (gpa );
39
36
tree .nodes .deinit (gpa );
40
37
gpa .free (tree .extra_data );
@@ -48,11 +45,69 @@ pub const RenderError = error{
48
45
OutOfMemory ,
49
46
};
50
47
48
+ pub const Mode = enum { zig , zon };
49
+
50
+ /// Result should be freed with tree.deinit() when there are
51
+ /// no more references to any of the tokens or nodes.
52
+ pub fn parse (gpa : Allocator , source : [:0 ]const u8 , mode : Mode ) Allocator.Error ! Ast {
53
+ var tokens = Ast.TokenList {};
54
+ defer tokens .deinit (gpa );
55
+
56
+ // Empirically, the zig std lib has an 8:1 ratio of source bytes to token count.
57
+ const estimated_token_count = source .len / 8 ;
58
+ try tokens .ensureTotalCapacity (gpa , estimated_token_count );
59
+
60
+ var tokenizer = std .zig .Tokenizer .init (source );
61
+ while (true ) {
62
+ const token = tokenizer .next ();
63
+ try tokens .append (gpa , .{
64
+ .tag = token .tag ,
65
+ .start = @intCast (u32 , token .loc .start ),
66
+ });
67
+ if (token .tag == .eof ) break ;
68
+ }
69
+
70
+ var parser : Parse = .{
71
+ .source = source ,
72
+ .gpa = gpa ,
73
+ .token_tags = tokens .items (.tag ),
74
+ .token_starts = tokens .items (.start ),
75
+ .errors = .{},
76
+ .nodes = .{},
77
+ .extra_data = .{},
78
+ .scratch = .{},
79
+ .tok_i = 0 ,
80
+ };
81
+ defer parser .errors .deinit (gpa );
82
+ defer parser .nodes .deinit (gpa );
83
+ defer parser .extra_data .deinit (gpa );
84
+ defer parser .scratch .deinit (gpa );
85
+
86
+ // Empirically, Zig source code has a 2:1 ratio of tokens to AST nodes.
87
+ // Make sure at least 1 so we can use appendAssumeCapacity on the root node below.
88
+ const estimated_node_count = (tokens .len + 2 ) / 2 ;
89
+ try parser .nodes .ensureTotalCapacity (gpa , estimated_node_count );
90
+
91
+ switch (mode ) {
92
+ .zig = > try parser .parseRoot (),
93
+ .zon = > try parser .parseZon (),
94
+ }
95
+
96
+ // TODO experiment with compacting the MultiArrayList slices here
97
+ return Ast {
98
+ .source = source ,
99
+ .tokens = tokens .toOwnedSlice (),
100
+ .nodes = parser .nodes .toOwnedSlice (),
101
+ .extra_data = try parser .extra_data .toOwnedSlice (gpa ),
102
+ .errors = try parser .errors .toOwnedSlice (gpa ),
103
+ };
104
+ }
105
+
51
106
/// `gpa` is used for allocating the resulting formatted source code, as well as
52
107
/// for allocating extra stack memory if needed, because this function utilizes recursion.
53
108
/// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006.
54
109
/// Caller owns the returned slice of bytes, allocated with `gpa`.
55
- pub fn render (tree : Ast , gpa : mem. Allocator ) RenderError ! []u8 {
110
+ pub fn render (tree : Ast , gpa : Allocator ) RenderError ! []u8 {
56
111
var buffer = std .ArrayList (u8 ).init (gpa );
57
112
defer buffer .deinit ();
58
113
@@ -3347,3 +3402,12 @@ pub const Node = struct {
3347
3402
rparen : TokenIndex ,
3348
3403
};
3349
3404
};
3405
+
3406
+ const std = @import ("../std.zig" );
3407
+ const assert = std .debug .assert ;
3408
+ const testing = std .testing ;
3409
+ const mem = std .mem ;
3410
+ const Token = std .zig .Token ;
3411
+ const Ast = @This ();
3412
+ const Allocator = std .mem .Allocator ;
3413
+ const Parse = @import ("Parse.zig" );
0 commit comments