Skip to content

Commit c7c372c

Browse files
committed
aro-translate-c: move shared types to a common namespace
1 parent e52b825 commit c7c372c

File tree

3 files changed

+335
-599
lines changed

3 files changed

+335
-599
lines changed

src/aro_translate_c.zig

+11-293
Original file line numberDiff line numberDiff line change
@@ -10,305 +10,23 @@ const Type = aro.Type;
1010
const ast = @import("translate_c/ast.zig");
1111
const ZigNode = ast.Node;
1212
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);
1322

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;
2023
pub const Compilation = aro.Compilation;
2124

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-
30725
const Context = struct {
30826
gpa: mem.Allocator,
30927
arena: mem.Allocator,
31028
decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},
311-
alias_list: translate_c.AliasList,
29+
alias_list: AliasList,
31230
global_scope: *Scope.Root,
31331
mangle_count: u32 = 0,
31432
/// Table of record decls that have been demoted to opaques.
@@ -429,7 +147,7 @@ pub fn translate(
429147
var context = Context{
430148
.gpa = gpa,
431149
.arena = arena,
432-
.alias_list = translate_c.AliasList.init(gpa),
150+
.alias_list = AliasList.init(gpa),
433151
.global_scope = try arena.create(Scope.Root),
434152
.pattern_list = try translate_c.PatternList.init(gpa),
435153
.comp = comp,

0 commit comments

Comments
 (0)