authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-25 23:23:22+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-10-01 23:51:54+03:00
log31ecf75311f83efb0bc0f108c3a3fb6b4c64e153
treea985e33f8d09a67e9e3e33787a7355d681262970
parentfef94da958c92e59ad277b6934a337b6fb45396c

aro-translate-c: translate enums


4 files changed, 755 insertions(+), 15 deletions(-)

src/Compilation.zig+1
...@@ -3976,6 +3976,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {...@@ -3976,6 +3976,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
3976 if (builtin.zig_backend == .stage2_c) @panic("the CBE cannot compile Aro yet!");3976 if (builtin.zig_backend == .stage2_c) @panic("the CBE cannot compile Aro yet!");
3977 const translate_c = @import("aro_translate_c.zig");3977 const translate_c = @import("aro_translate_c.zig");
3978 _ = translate_c;3978 _ = translate_c;
3979 if (true) @panic("TODO");
3979 break :tree undefined;3980 break :tree undefined;
3980 },3981 },
3981 .clang => tree: {3982 .clang => tree: {
src/aro_translate_c.zig created+728
...@@ -0,0 +1,728 @@
1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const translate_c = @import("translate_c.zig");
5const aro = @import("aro");
6const Tree = aro.Tree;
7const NodeIndex = Tree.NodeIndex;
8const TokenIndex = Tree.TokenIndex;
9const Type = aro.Type;
10const ast = @import("translate_c/ast.zig");
11const ZigNode = ast.Node;
12const ZigTag = ZigNode.Tag;
13
14const Error = mem.Allocator.Error;
15const TransError = translate_c.TransError;
16const TypeError = translate_c.TypeError;
17const ResultUsed = translate_c.ResultUsed;
18const AliasList = translate_c.AliasList;
19const SymbolTable = translate_c.SymbolTable;
20pub const Compilation = aro.Compilation;
21
22const 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
307const Context = struct {
308 gpa: mem.Allocator,
309 arena: mem.Allocator,
310 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},
311 alias_list: translate_c.AliasList,
312 global_scope: *Scope.Root,
313 mangle_count: u32 = 0,
314 /// Table of record decls that have been demoted to opaques.
315 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
316 /// Table of unnamed enums and records that are child types of typedefs.
317 unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},
318 /// Needed to decide if we are parsing a typename
319 typedefs: std.StringArrayHashMapUnmanaged(void) = .{},
320
321 /// This one is different than the root scope's name table. This contains
322 /// a list of names that we found by visiting all the top level decls without
323 /// translating them. The other maps are updated as we translate; this one is updated
324 /// up front in a pre-processing step.
325 global_names: std.StringArrayHashMapUnmanaged(void) = .{},
326
327 /// This is similar to `global_names`, but contains names which we would
328 /// *like* to use, but do not strictly *have* to if they are unavailable.
329 /// These are relevant to types, which ideally we would name like
330 /// 'struct_foo' with an alias 'foo', but if either of those names is taken,
331 /// may be mangled.
332 /// This is distinct from `global_names` so we can detect at a type
333 /// declaration whether or not the name is available.
334 weak_global_names: std.StringArrayHashMapUnmanaged(void) = .{},
335
336 pattern_list: translate_c.PatternList,
337 tree: Tree,
338 comp: *Compilation,
339 mapper: aro.TypeMapper,
340
341 fn getMangle(c: *Context) u32 {
342 c.mangle_count += 1;
343 return c.mangle_count;
344 }
345
346 /// Convert a clang source location to a file:line:column string
347 fn locStr(c: *Context, loc: TokenIndex) ![]const u8 {
348 _ = c;
349 _ = loc;
350 // const spelling_loc = c.source_manager.getSpellingLoc(loc);
351 // const filename_c = c.source_manager.getFilename(spelling_loc);
352 // const filename = if (filename_c) |s| try c.str(s) else @as([]const u8, "(no file)");
353
354 // const line = c.source_manager.getSpellingLineNumber(spelling_loc);
355 // const column = c.source_manager.getSpellingColumnNumber(spelling_loc);
356 // return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });
357 return "somewhere";
358 }
359};
360
361fn maybeSuppressResult(c: *Context, used: ResultUsed, result: ZigNode) TransError!ZigNode {
362 if (used == .used) return result;
363 return ZigTag.discard.create(c.arena, .{ .should_skip = false, .value = result });
364}
365
366fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void {
367 const gop = try c.global_scope.sym_table.getOrPut(name);
368 if (!gop.found_existing) {
369 gop.value_ptr.* = decl_node;
370 try c.global_scope.nodes.append(decl_node);
371 }
372}
373
374fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void {
375 // location
376 // pub const name = @compileError(msg);
377 const fail_msg = try std.fmt.allocPrint(c.arena, format, args);
378 try addTopLevelDecl(c, name, try ZigTag.fail_decl.create(c.arena, .{ .actual = name, .mangled = fail_msg }));
379 const str = try c.locStr(loc);
380 const location_comment = try std.fmt.allocPrint(c.arena, "// {s}", .{str});
381 try c.global_scope.nodes.append(try ZigTag.warning.create(c.arena, location_comment));
382}
383
384pub fn translate(
385 gpa: mem.Allocator,
386 comp: *Compilation,
387 args: []const []const u8,
388) !std.zig.Ast {
389 try comp.addDefaultPragmaHandlers();
390 comp.langopts.setEmulatedCompiler(aro.target_util.systemCompiler(comp.target));
391
392 var driver: aro.Driver = .{ .comp = comp };
393 defer driver.deinit();
394
395 var macro_buf = std.ArrayList(u8).init(gpa);
396 defer macro_buf.deinit();
397
398 assert(!try driver.parseArgs(std.io.null_writer, macro_buf.writer(), args));
399 assert(driver.inputs.items.len == 1);
400 const source = driver.inputs.items[0];
401
402 const builtin = try comp.generateBuiltinMacros();
403 const user_macros = try comp.addSourceFromBuffer("<command line>", macro_buf.items);
404
405 var pp = aro.Preprocessor.init(comp);
406 defer pp.deinit();
407
408 try pp.addBuiltinMacros();
409
410 _ = try pp.preprocess(builtin);
411 _ = try pp.preprocess(user_macros);
412 const eof = try pp.preprocess(source);
413 try pp.tokens.append(pp.comp.gpa, eof);
414
415 var tree = try aro.Parser.parse(&pp);
416 defer tree.deinit();
417
418 if (driver.comp.diag.errors != 0) {
419 return error.SemanticAnalyzeFail;
420 }
421
422 const mapper = tree.comp.string_interner.getFastTypeMapper(tree.comp.gpa) catch tree.comp.string_interner.getSlowTypeMapper();
423 defer mapper.deinit(tree.comp.gpa);
424
425 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
426 errdefer arena_allocator.deinit();
427 const arena = arena_allocator.allocator();
428
429 var context = Context{
430 .gpa = gpa,
431 .arena = arena,
432 .alias_list = translate_c.AliasList.init(gpa),
433 .global_scope = try arena.create(Scope.Root),
434 .pattern_list = try translate_c.PatternList.init(gpa),
435 .comp = comp,
436 .mapper = mapper,
437 .tree = tree,
438 };
439 context.global_scope.* = Scope.Root.init(&context);
440 defer {
441 context.decl_table.deinit(gpa);
442 context.alias_list.deinit();
443 context.global_names.deinit(gpa);
444 context.opaque_demotes.deinit(gpa);
445 context.unnamed_typedefs.deinit(gpa);
446 context.typedefs.deinit(gpa);
447 context.global_scope.deinit();
448 context.pattern_list.deinit(gpa);
449 }
450
451 inline for (@typeInfo(std.zig.c_builtins).Struct.decls) |decl| {
452 const builtin_fn = try ZigTag.pub_var_simple.create(arena, .{
453 .name = decl.name,
454 .init = try ZigTag.import_c_builtin.create(arena, decl.name),
455 });
456 try addTopLevelDecl(&context, decl.name, builtin_fn);
457 }
458
459 try prepopulateGlobalNameTable(&context);
460 try transTopLevelDecls(&context);
461
462 for (context.alias_list.items) |alias| {
463 if (!context.global_scope.sym_table.contains(alias.alias)) {
464 const node = try ZigTag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name });
465 try addTopLevelDecl(&context, alias.alias, node);
466 }
467 }
468
469 return ast.render(gpa, context.global_scope.nodes.items);
470}
471
472fn prepopulateGlobalNameTable(c: *Context) !void {
473 const node_tags = c.tree.nodes.items(.tag);
474 const node_types = c.tree.nodes.items(.ty);
475 const node_data = c.tree.nodes.items(.data);
476 for (c.tree.root_decls) |node| {
477 const data = node_data[@enumToInt(node)];
478 const decl_name = switch (node_tags[@enumToInt(node)]) {
479 .typedef => @panic("TODO"),
480
481 .static_assert,
482 .struct_decl_two,
483 .union_decl_two,
484 .struct_decl,
485 .union_decl,
486 => blk: {
487 const ty = node_types[@enumToInt(node)];
488 const name_id = ty.data.record.name;
489 break :blk c.mapper.lookup(name_id);
490 },
491
492 .enum_decl_two,
493 .enum_decl,
494 => blk: {
495 const ty = node_types[@enumToInt(node)];
496 const name_id = ty.data.@"enum".name;
497 break :blk c.mapper.lookup(name_id);
498 },
499
500 .fn_proto,
501 .static_fn_proto,
502 .inline_fn_proto,
503 .inline_static_fn_proto,
504 .fn_def,
505 .static_fn_def,
506 .inline_fn_def,
507 .inline_static_fn_def,
508 .@"var",
509 .static_var,
510 .threadlocal_var,
511 .threadlocal_static_var,
512 .extern_var,
513 .threadlocal_extern_var,
514 => c.tree.tokSlice(data.decl.name),
515 else => unreachable,
516 };
517 try c.global_names.put(c.gpa, decl_name, {});
518 }
519}
520
521fn transTopLevelDecls(c: *Context) !void {
522 const node_tags = c.tree.nodes.items(.tag);
523 const node_data = c.tree.nodes.items(.data);
524 for (c.tree.root_decls) |node| {
525 const data = node_data[@enumToInt(node)];
526 switch (node_tags[@enumToInt(node)]) {
527 .typedef => {
528 try transTypeDef(c, &c.global_scope.base, node);
529 },
530
531 .static_assert,
532 .struct_decl_two,
533 .union_decl_two,
534 .struct_decl,
535 .union_decl,
536 => {
537 try transRecordDecl(c, &c.global_scope.base, node);
538 },
539
540 .enum_decl_two,
541 => {
542 var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };
543 var field_count: u8 = 0;
544 if (fields[0] != .none) field_count += 1;
545 if (fields[1] != .none) field_count += 1;
546 try transEnumDecl(c, &c.global_scope.base, node, fields[0..field_count]);
547 },
548 .enum_decl,
549 => {
550 const fields = c.tree.data[data.range.start..data.range.end];
551 try transEnumDecl(c, &c.global_scope.base, node, fields);
552 },
553
554 .fn_proto,
555 .static_fn_proto,
556 .inline_fn_proto,
557 .inline_static_fn_proto,
558 .fn_def,
559 .static_fn_def,
560 .inline_fn_def,
561 .inline_static_fn_def,
562 => {
563 try transFnDecl(c, node);
564 },
565
566 .@"var",
567 .static_var,
568 .threadlocal_var,
569 .threadlocal_static_var,
570 .extern_var,
571 .threadlocal_extern_var,
572 => {
573 try transVarDecl(c, node, null);
574 },
575 else => unreachable,
576 }
577 }
578}
579
580fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {
581 @panic("TODO");
582}
583fn transRecordDecl(_: *Context, _: *Scope, _: NodeIndex) Error!void {
584 @panic("TODO");
585}
586fn transFnDecl(_: *Context, _: NodeIndex) Error!void {
587 @panic("TODO");
588}
589fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void {
590 @panic("TODO");
591}
592fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void {
593 const node_types = c.tree.nodes.items(.ty);
594 const ty = node_types[@enumToInt(enum_decl)];
595 const node_data = c.tree.nodes.items(.data);
596 if (c.decl_table.get(@ptrToInt(ty.data.@"enum"))) |_|
597 return; // Avoid processing this decl twice
598 const toplevel = scope.id == .root;
599 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
600
601 var is_unnamed = false;
602 var bare_name: []const u8 = c.mapper.lookup(ty.data.@"enum".name);
603 var name = bare_name;
604 if (c.unnamed_typedefs.get(@ptrToInt(ty.data.@"enum"))) |typedef_name| {
605 bare_name = typedef_name;
606 name = typedef_name;
607 } else {
608 if (bare_name.len == 0) {
609 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
610 is_unnamed = true;
611 }
612 name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
613 }
614 if (!toplevel) name = try bs.makeMangledName(c, name);
615 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(ty.data.@"enum"), name);
616
617 const enum_type_node = if (!ty.data.@"enum".isIncomplete()) blk: {
618 for (ty.data.@"enum".fields, field_nodes) |field, field_node| {
619 var enum_val_name: []const u8 = c.mapper.lookup(field.name);
620 if (!toplevel) {
621 enum_val_name = try bs.makeMangledName(c, enum_val_name);
622 }
623
624 const enum_const_type_node: ?ZigNode = transType(c, scope, field.ty, field.name_tok) catch |err| switch (err) {
625 error.UnsupportedType => null,
626 else => |e| return e,
627 };
628
629 const enum_const_def = try ZigTag.enum_constant.create(c.arena, .{
630 .name = enum_val_name,
631 .is_public = toplevel,
632 .type = enum_const_type_node,
633 .value = transExpr(c, node_data[@enumToInt(field_node)].decl.node, .used) catch @panic("TODO"),
634 });
635 if (toplevel)
636 try addTopLevelDecl(c, enum_val_name, enum_const_def)
637 else {
638 try scope.appendNode(enum_const_def);
639 try bs.discardVariable(c, enum_val_name);
640 }
641 }
642
643 break :blk transType(c, scope, ty.data.@"enum".tag_ty, 0) catch |err| switch (err) {
644 error.UnsupportedType => {
645 return failDecl(c, 0, name, "unable to translate enum integer type", .{});
646 },
647 else => |e| return e,
648 };
649 } else blk: {
650 try c.opaque_demotes.put(c.gpa, @ptrToInt(ty.data.@"enum"), {});
651 break :blk ZigTag.opaque_literal.init();
652 };
653
654 const is_pub = toplevel and !is_unnamed;
655 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
656 payload.* = .{
657 .base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
658 .data = .{
659 .init = enum_type_node,
660 .name = name,
661 },
662 };
663 const node = ZigNode.initPayload(&payload.base);
664 if (toplevel) {
665 try addTopLevelDecl(c, name, node);
666 if (!is_unnamed)
667 try c.alias_list.append(.{ .alias = bare_name, .name = name });
668 } else {
669 try scope.appendNode(node);
670 if (node.tag() != .pub_var_simple) {
671 try bs.discardVariable(c, name);
672 }
673 }
674}
675
676fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) TypeError!ZigNode {
677 _ = source_loc;
678 _ = scope;
679 const ty = raw_ty.canonicalize(.standard);
680 switch (ty.specifier) {
681 .void => return ZigTag.type.create(c.arena, "anyopaque"),
682 .bool => return ZigTag.type.create(c.arena, "bool"),
683 .char => return ZigTag.type.create(c.arena, "c_char"),
684 .schar => return ZigTag.type.create(c.arena, "i8"),
685 .uchar => return ZigTag.type.create(c.arena, "u8"),
686 .short => return ZigTag.type.create(c.arena, "c_short"),
687 .ushort => return ZigTag.type.create(c.arena, "c_ushort"),
688 .int => return ZigTag.type.create(c.arena, "c_int"),
689 .uint => return ZigTag.type.create(c.arena, "c_uint"),
690 .long => return ZigTag.type.create(c.arena, "c_long"),
691 .ulong => return ZigTag.type.create(c.arena, "c_ulong"),
692 .long_long => return ZigTag.type.create(c.arena, "c_longlong"),
693 .ulong_long => return ZigTag.type.create(c.arena, "c_ulonglong"),
694 .int128 => return ZigTag.type.create(c.arena, "i128"),
695 .uint128 => return ZigTag.type.create(c.arena, "u128"),
696 .fp16, .float16 => return ZigTag.type.create(c.arena, "f16"),
697 .float => return ZigTag.type.create(c.arena, "f32"),
698 .double => return ZigTag.type.create(c.arena, "f64"),
699 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
700 .float80 => return ZigTag.type.create(c.arena, "f80"),
701 .float128 => return ZigTag.type.create(c.arena, "f128"),
702 else => @panic("TODO"),
703 }
704}
705
706fn transStmt(c: *Context, node: NodeIndex) TransError!void {
707 _ = try c.transExpr(node, .unused);
708}
709
710fn transExpr(c: *Context, node: NodeIndex, result_used: ResultUsed) TransError!ZigNode {
711 std.debug.assert(node != .none);
712 const ty = c.tree.nodes.items(.ty)[@enumToInt(node)];
713 if (c.tree.value_map.get(node)) |val| {
714 // TODO handle other values
715 const str = try std.fmt.allocPrint(c.arena, "{d}", .{val.data.int});
716 const int = try ZigTag.integer_literal.create(c.arena, str);
717 const as_node = try ZigTag.as.create(c.arena, .{
718 .lhs = try transType(c, undefined, ty, undefined),
719 .rhs = int,
720 });
721 return maybeSuppressResult(c, result_used, as_node);
722 }
723 const node_tags = c.tree.nodes.items(.tag);
724 switch (node_tags[@enumToInt(node)]) {
725 else => unreachable, // Not an expression.
726 }
727 return .none;
728}
src/main.zig+15-4
...@@ -4229,7 +4229,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati...@@ -4229,7 +4229,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
42294229
4230 const ext = Compilation.classifyFileExt(c_source_file.src_path);4230 const ext = Compilation.classifyFileExt(c_source_file.src_path);
4231 const out_dep_path: ?[]const u8 = blk: {4231 const out_dep_path: ?[]const u8 = blk: {
4232 if (comp.disable_c_depfile or !ext.clangSupportsDepFile())4232 if (comp.c_frontend == .aro or comp.disable_c_depfile or !ext.clangSupportsDepFile())
4233 break :blk null;4233 break :blk null;
42344234
4235 const c_src_basename = fs.path.basename(c_source_file.src_path);4235 const c_src_basename = fs.path.basename(c_source_file.src_path);
...@@ -4238,7 +4238,8 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati...@@ -4238,7 +4238,8 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
4238 break :blk out_dep_path;4238 break :blk out_dep_path;
4239 };4239 };
42404240
4241 try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path);4241 // TODO
4242 if (comp.c_frontend != .aro) try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path);
4242 try argv.append(c_source_file.src_path);4243 try argv.append(c_source_file.src_path);
42434244
4244 if (comp.verbose_cc) {4245 if (comp.verbose_cc) {
...@@ -4249,8 +4250,18 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati...@@ -4249,8 +4250,18 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
4249 .aro => tree: {4250 .aro => tree: {
4250 if (builtin.zig_backend == .stage2_c) @panic("the CBE cannot compile Aro yet!");4251 if (builtin.zig_backend == .stage2_c) @panic("the CBE cannot compile Aro yet!");
4251 const translate_c = @import("aro_translate_c.zig");4252 const translate_c = @import("aro_translate_c.zig");
4252 _ = translate_c;4253 var aro_comp = translate_c.Compilation.init(comp.gpa);
4253 break :tree undefined;4254 defer aro_comp.deinit();
4255
4256 break :tree translate_c.translate(comp.gpa, &aro_comp, argv.items) catch |err| switch (err) {
4257 error.SemanticAnalyzeFail, error.FatalError => {
4258 // TODO convert these to zig errors
4259 aro_comp.renderErrors();
4260 process.exit(1);
4261 },
4262 error.OutOfMemory => return error.OutOfMemory,
4263 error.StreamTooLong => fatal("StreamTooLong?", .{}),
4264 };
4254 },4265 },
4255 .clang => tree: {4266 .clang => tree: {
4256 if (!build_options.have_llvm) unreachable;4267 if (!build_options.have_llvm) unreachable;
src/translate_c.zig+11-11
...@@ -14,12 +14,12 @@ const Tag = Node.Tag;...@@ -14,12 +14,12 @@ const Tag = Node.Tag;
14const CallingConvention = std.builtin.CallingConvention;14const CallingConvention = std.builtin.CallingConvention;
1515
16pub const Error = std.mem.Allocator.Error;16pub const Error = std.mem.Allocator.Error;
17const MacroProcessingError = Error || error{UnexpectedMacroToken};17pub const MacroProcessingError = Error || error{UnexpectedMacroToken};
18const TypeError = Error || error{UnsupportedType};18pub const TypeError = Error || error{UnsupportedType};
19const TransError = TypeError || error{UnsupportedTranslation};19pub const TransError = TypeError || error{UnsupportedTranslation};
2020
21const SymbolTable = std.StringArrayHashMap(Node);21pub const SymbolTable = std.StringArrayHashMap(Node);
22const AliasList = std.ArrayList(struct {22pub const AliasList = std.ArrayList(struct {
23 alias: []const u8,23 alias: []const u8,
24 name: []const u8,24 name: []const u8,
25});25});
...@@ -1423,7 +1423,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E...@@ -1423,7 +1423,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
1423 }1423 }
1424}1424}
14251425
1426const ResultUsed = enum {1426pub const ResultUsed = enum {
1427 used,1427 used,
1428 unused,1428 unused,
1429};1429};
...@@ -5322,7 +5322,7 @@ pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, compti...@@ -5322,7 +5322,7 @@ pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, compti
5322 try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment));5322 try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment));
5323}5323}
53245324
5325const PatternList = struct {5325pub const PatternList = struct {
5326 patterns: []Pattern,5326 patterns: []Pattern,
53275327
5328 /// Templates must be function-like macros5328 /// Templates must be function-like macros
...@@ -5455,7 +5455,7 @@ const PatternList = struct {...@@ -5455,7 +5455,7 @@ const PatternList = struct {
5455 /// macro. Please review this logic carefully if changing that assumption. Two5455 /// macro. Please review this logic carefully if changing that assumption. Two
5456 /// function-like macros are considered equivalent if and only if they contain the same5456 /// function-like macros are considered equivalent if and only if they contain the same
5457 /// list of tokens, modulo parameter names.5457 /// list of tokens, modulo parameter names.
5458 fn isEquivalent(self: Pattern, ms: MacroSlicer, args_hash: ArgsPositionMap) bool {5458 pub fn isEquivalent(self: Pattern, ms: MacroSlicer, args_hash: ArgsPositionMap) bool {
5459 if (self.tokens.len != ms.tokens.len) return false;5459 if (self.tokens.len != ms.tokens.len) return false;
5460 if (args_hash.count() != self.args_hash.count()) return false;5460 if (args_hash.count() != self.args_hash.count()) return false;
54615461
...@@ -5496,7 +5496,7 @@ const PatternList = struct {...@@ -5496,7 +5496,7 @@ const PatternList = struct {
5496 }5496 }
5497 };5497 };
54985498
5499 fn init(allocator: mem.Allocator) Error!PatternList {5499 pub fn init(allocator: mem.Allocator) Error!PatternList {
5500 const patterns = try allocator.alloc(Pattern, templates.len);5500 const patterns = try allocator.alloc(Pattern, templates.len);
5501 for (templates, 0..) |template, i| {5501 for (templates, 0..) |template, i| {
5502 try patterns[i].init(allocator, template);5502 try patterns[i].init(allocator, template);
...@@ -5504,12 +5504,12 @@ const PatternList = struct {...@@ -5504,12 +5504,12 @@ const PatternList = struct {
5504 return PatternList{ .patterns = patterns };5504 return PatternList{ .patterns = patterns };
5505 }5505 }
55065506
5507 fn deinit(self: *PatternList, allocator: mem.Allocator) void {5507 pub fn deinit(self: *PatternList, allocator: mem.Allocator) void {
5508 for (self.patterns) |*pattern| pattern.deinit(allocator);5508 for (self.patterns) |*pattern| pattern.deinit(allocator);
5509 allocator.free(self.patterns);5509 allocator.free(self.patterns);
5510 }5510 }
55115511
5512 fn match(self: PatternList, allocator: mem.Allocator, ms: MacroSlicer) Error!?Pattern {5512 pub fn match(self: PatternList, allocator: mem.Allocator, ms: MacroSlicer) Error!?Pattern {
5513 var args_hash: ArgsPositionMap = .{};5513 var args_hash: ArgsPositionMap = .{};
5514 defer args_hash.deinit(allocator);5514 defer args_hash.deinit(allocator);
55155515