@@ -10,305 +10,23 @@ const Type = aro.Type;
10
10
const ast = @import ("translate_c/ast.zig" );
11
11
const ZigNode = ast .Node ;
12
12
const ZigTag = ZigNode .Tag ;
13
+ const common = @import ("translate_c/common.zig" );
14
+ const Error = common .Error ;
15
+ const MacroProcessingError = common .MacroProcessingError ;
16
+ const TypeError = common .TypeError ;
17
+ const TransError = common .TransError ;
18
+ const SymbolTable = common .SymbolTable ;
19
+ const AliasList = common .AliasList ;
20
+ const ResultUsed = common .ResultUsed ;
21
+ const Scope = common .ScopeExtra (Context , Type );
13
22
14
- const Error = mem .Allocator .Error ;
15
- const TransError = translate_c .TransError ;
16
- const TypeError = translate_c .TypeError ;
17
- const ResultUsed = translate_c .ResultUsed ;
18
- const AliasList = translate_c .AliasList ;
19
- const SymbolTable = translate_c .SymbolTable ;
20
23
pub const Compilation = aro .Compilation ;
21
24
22
- const Scope = struct {
23
- id : Id ,
24
- parent : ? * Scope ,
25
-
26
- const Id = enum {
27
- block ,
28
- root ,
29
- condition ,
30
- loop ,
31
- do_loop ,
32
- };
33
-
34
- /// Used for the scope of condition expressions, for example `if (cond)`.
35
- /// The block is lazily initialised because it is only needed for rare
36
- /// cases of comma operators being used.
37
- const Condition = struct {
38
- base : Scope ,
39
- block : ? Block = null ,
40
-
41
- fn getBlockScope (self : * Condition , c : * Context ) ! * Block {
42
- if (self .block ) | * b | return b ;
43
- self .block = try Block .init (c , & self .base , true );
44
- return & self .block .? ;
45
- }
46
-
47
- fn deinit (self : * Condition ) void {
48
- if (self .block ) | * b | b .deinit ();
49
- }
50
- };
51
-
52
- /// Represents an in-progress ZigNode.Block. This struct is stack-allocated.
53
- /// When it is deinitialized, it produces an ZigNode.Block which is allocated
54
- /// into the main arena.
55
- const Block = struct {
56
- base : Scope ,
57
- statements : std .ArrayList (ZigNode ),
58
- variables : AliasList ,
59
- mangle_count : u32 = 0 ,
60
- label : ? []const u8 = null ,
61
-
62
- /// By default all variables are discarded, since we do not know in advance if they
63
- /// will be used. This maps the variable's name to the Discard payload, so that if
64
- /// the variable is subsequently referenced we can indicate that the discard should
65
- /// be skipped during the intermediate AST -> Zig AST render step.
66
- variable_discards : std .StringArrayHashMap (* ast .Payload .Discard ),
67
-
68
- /// When the block corresponds to a function, keep track of the return type
69
- /// so that the return expression can be cast, if necessary
70
- return_type : ? Type = null ,
71
-
72
- /// C static local variables are wrapped in a block-local struct. The struct
73
- /// is named after the (mangled) variable name, the Zig variable within the
74
- /// struct itself is given this name.
75
- const StaticInnerName = "static" ;
76
-
77
- fn init (c : * Context , parent : * Scope , labeled : bool ) ! Block {
78
- var blk = Block {
79
- .base = .{
80
- .id = .block ,
81
- .parent = parent ,
82
- },
83
- .statements = std .ArrayList (ZigNode ).init (c .gpa ),
84
- .variables = AliasList .init (c .gpa ),
85
- .variable_discards = std .StringArrayHashMap (* ast .Payload .Discard ).init (c .gpa ),
86
- };
87
- if (labeled ) {
88
- blk .label = try blk .makeMangledName (c , "blk" );
89
- }
90
- return blk ;
91
- }
92
-
93
- fn deinit (self : * Block ) void {
94
- self .statements .deinit ();
95
- self .variables .deinit ();
96
- self .variable_discards .deinit ();
97
- self .* = undefined ;
98
- }
99
-
100
- fn complete (self : * Block , c : * Context ) ! ZigNode {
101
- if (self .base .parent .? .id == .do_loop ) {
102
- // We reserve 1 extra statement if the parent is a do_loop. This is in case of
103
- // do while, we want to put `if (cond) break;` at the end.
104
- const alloc_len = self .statements .items .len + @boolToInt (self .base .parent .? .id == .do_loop );
105
- var stmts = try c .arena .alloc (ZigNode , alloc_len );
106
- stmts .len = self .statements .items .len ;
107
- @memcpy (stmts [0.. self .statements .items .len ], self .statements .items );
108
- return ZigTag .block .create (c .arena , .{
109
- .label = self .label ,
110
- .stmts = stmts ,
111
- });
112
- }
113
- if (self .statements .items .len == 0 ) return ZigTag .empty_block .init ();
114
- return ZigTag .block .create (c .arena , .{
115
- .label = self .label ,
116
- .stmts = try c .arena .dupe (ZigNode , self .statements .items ),
117
- });
118
- }
119
-
120
- /// Given the desired name, return a name that does not shadow anything from outer scopes.
121
- /// Inserts the returned name into the scope.
122
- /// The name will not be visible to callers of getAlias.
123
- fn reserveMangledName (scope : * Block , c : * Context , name : []const u8 ) ! []const u8 {
124
- return scope .createMangledName (c , name , true );
125
- }
126
-
127
- /// Same as reserveMangledName, but enables the alias immediately.
128
- fn makeMangledName (scope : * Block , c : * Context , name : []const u8 ) ! []const u8 {
129
- return scope .createMangledName (c , name , false );
130
- }
131
-
132
- fn createMangledName (scope : * Block , c : * Context , name : []const u8 , reservation : bool ) ! []const u8 {
133
- const name_copy = try c .arena .dupe (u8 , name );
134
- var proposed_name = name_copy ;
135
- while (scope .contains (proposed_name )) {
136
- scope .mangle_count += 1 ;
137
- proposed_name = try std .fmt .allocPrint (c .arena , "{s}_{d}" , .{ name , scope .mangle_count });
138
- }
139
- const new_mangle = try scope .variables .addOne ();
140
- if (reservation ) {
141
- new_mangle .* = .{ .name = name_copy , .alias = name_copy };
142
- } else {
143
- new_mangle .* = .{ .name = name_copy , .alias = proposed_name };
144
- }
145
- return proposed_name ;
146
- }
147
-
148
- fn getAlias (scope : * Block , name : []const u8 ) []const u8 {
149
- for (scope .variables .items ) | p | {
150
- if (mem .eql (u8 , p .name , name ))
151
- return p .alias ;
152
- }
153
- return scope .base .parent .? .getAlias (name );
154
- }
155
-
156
- fn localContains (scope : * Block , name : []const u8 ) bool {
157
- for (scope .variables .items ) | p | {
158
- if (mem .eql (u8 , p .alias , name ))
159
- return true ;
160
- }
161
- return false ;
162
- }
163
-
164
- fn contains (scope : * Block , name : []const u8 ) bool {
165
- if (scope .localContains (name ))
166
- return true ;
167
- return scope .base .parent .? .contains (name );
168
- }
169
-
170
- fn discardVariable (scope : * Block , c : * Context , name : []const u8 ) Error ! void {
171
- const name_node = try ZigTag .identifier .create (c .arena , name );
172
- const discard = try ZigTag .discard .create (c .arena , .{ .should_skip = false , .value = name_node });
173
- try scope .statements .append (discard );
174
- try scope .variable_discards .putNoClobber (name , discard .castTag (.discard ).? );
175
- }
176
- };
177
-
178
- const Root = struct {
179
- base : Scope ,
180
- sym_table : SymbolTable ,
181
- macro_table : SymbolTable ,
182
- context : * Context ,
183
- nodes : std .ArrayList (ZigNode ),
184
-
185
- fn init (c : * Context ) Root {
186
- return .{
187
- .base = .{
188
- .id = .root ,
189
- .parent = null ,
190
- },
191
- .sym_table = SymbolTable .init (c .gpa ),
192
- .macro_table = SymbolTable .init (c .gpa ),
193
- .context = c ,
194
- .nodes = std .ArrayList (ZigNode ).init (c .gpa ),
195
- };
196
- }
197
-
198
- fn deinit (scope : * Root ) void {
199
- scope .sym_table .deinit ();
200
- scope .macro_table .deinit ();
201
- scope .nodes .deinit ();
202
- }
203
-
204
- /// Check if the global scope contains this name, without looking into the "future", e.g.
205
- /// ignore the preprocessed decl and macro names.
206
- fn containsNow (scope : * Root , name : []const u8 ) bool {
207
- return scope .sym_table .contains (name ) or scope .macro_table .contains (name );
208
- }
209
-
210
- /// Check if the global scope contains the name, includes all decls that haven't been translated yet.
211
- fn contains (scope : * Root , name : []const u8 ) bool {
212
- return scope .containsNow (name ) or scope .context .global_names .contains (name );
213
- }
214
- };
215
-
216
- fn findBlockScope (inner : * Scope , c : * Context ) ! * Scope.Block {
217
- var scope = inner ;
218
- while (true ) {
219
- switch (scope .id ) {
220
- .root = > unreachable ,
221
- .block = > return @fieldParentPtr (Block , "base" , scope ),
222
- .condition = > return @fieldParentPtr (Condition , "base" , scope ).getBlockScope (c ),
223
- else = > scope = scope .parent .? ,
224
- }
225
- }
226
- }
227
-
228
- fn findBlockReturnType (inner : * Scope ) Type {
229
- var scope = inner ;
230
- while (true ) {
231
- switch (scope .id ) {
232
- .root = > unreachable ,
233
- .block = > {
234
- const block = @fieldParentPtr (Block , "base" , scope );
235
- if (block .return_type ) | qt | return qt ;
236
- scope = scope .parent .? ;
237
- },
238
- else = > scope = scope .parent .? ,
239
- }
240
- }
241
- }
242
-
243
- fn getAlias (scope : * Scope , name : []const u8 ) []const u8 {
244
- return switch (scope .id ) {
245
- .root = > return name ,
246
- .block = > @fieldParentPtr (Block , "base" , scope ).getAlias (name ),
247
- .loop , .do_loop , .condition = > scope .parent .? .getAlias (name ),
248
- };
249
- }
250
-
251
- fn contains (scope : * Scope , name : []const u8 ) bool {
252
- return switch (scope .id ) {
253
- .root = > @fieldParentPtr (Root , "base" , scope ).contains (name ),
254
- .block = > @fieldParentPtr (Block , "base" , scope ).contains (name ),
255
- .loop , .do_loop , .condition = > scope .parent .? .contains (name ),
256
- };
257
- }
258
-
259
- fn getBreakableScope (inner : * Scope ) * Scope {
260
- var scope = inner ;
261
- while (true ) {
262
- switch (scope .id ) {
263
- .root = > unreachable ,
264
- .loop , .do_loop = > return scope ,
265
- else = > scope = scope .parent .? ,
266
- }
267
- }
268
- }
269
-
270
- /// Appends a node to the first block scope if inside a function, or to the root tree if not.
271
- fn appendNode (inner : * Scope , node : ZigNode ) ! void {
272
- var scope = inner ;
273
- while (true ) {
274
- switch (scope .id ) {
275
- .root = > {
276
- const root = @fieldParentPtr (Root , "base" , scope );
277
- return root .nodes .append (node );
278
- },
279
- .block = > {
280
- const block = @fieldParentPtr (Block , "base" , scope );
281
- return block .statements .append (node );
282
- },
283
- else = > scope = scope .parent .? ,
284
- }
285
- }
286
- }
287
-
288
- fn skipVariableDiscard (inner : * Scope , name : []const u8 ) void {
289
- var scope = inner ;
290
- while (true ) {
291
- switch (scope .id ) {
292
- .root = > return ,
293
- .block = > {
294
- const block = @fieldParentPtr (Block , "base" , scope );
295
- if (block .variable_discards .get (name )) | discard | {
296
- discard .data .should_skip = true ;
297
- return ;
298
- }
299
- },
300
- else = > {},
301
- }
302
- scope = scope .parent .? ;
303
- }
304
- }
305
- };
306
-
307
25
const Context = struct {
308
26
gpa : mem.Allocator ,
309
27
arena : mem.Allocator ,
310
28
decl_table : std .AutoArrayHashMapUnmanaged (usize , []const u8 ) = .{},
311
- alias_list : translate_c. AliasList ,
29
+ alias_list : AliasList ,
312
30
global_scope : * Scope.Root ,
313
31
mangle_count : u32 = 0 ,
314
32
/// Table of record decls that have been demoted to opaques.
@@ -429,7 +147,7 @@ pub fn translate(
429
147
var context = Context {
430
148
.gpa = gpa ,
431
149
.arena = arena ,
432
- .alias_list = translate_c . AliasList .init (gpa ),
150
+ .alias_list = AliasList .init (gpa ),
433
151
.global_scope = try arena .create (Scope .Root ),
434
152
.pattern_list = try translate_c .PatternList .init (gpa ),
435
153
.comp = comp ,
0 commit comments