Skip to content

Commit

Permalink
Merge pull request #11 from sno2/exprs-and-stmts
Browse files Browse the repository at this point in the history
translate static local variables and field access
  • Loading branch information
Vexu authored Feb 14, 2025
2 parents 8eedcf4 + 5858c9a commit 4febc09
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 28 deletions.
48 changes: 47 additions & 1 deletion src/Translator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ type_decls: std.AutoArrayHashMapUnmanaged(Node.Index, []const u8) = .empty,
opaque_demotes: std.AutoHashMapUnmanaged(QualType, void) = .empty,
/// Table of unnamed enums and records that are child types of typedefs.
unnamed_typedefs: std.AutoHashMapUnmanaged(QualType, []const u8) = .empty,
/// Table of anonymous record to generated field names.
anonymous_record_field_names: std.AutoHashMapUnmanaged(struct {
parent: QualType,
field: QualType,
}, []const u8) = .empty,

/// This one is different than the root scope's name table. This contains
/// a list of names that we found by visiting all the top level decls without
Expand Down Expand Up @@ -156,6 +161,7 @@ pub fn translate(
translator.weak_global_names.deinit(gpa);
translator.opaque_demotes.deinit(gpa);
translator.unnamed_typedefs.deinit(gpa);
translator.anonymous_record_field_names.deinit(gpa);
translator.typedefs.deinit(gpa);
translator.global_scope.deinit();
translator.pattern_list.deinit(gpa);
Expand Down Expand Up @@ -476,6 +482,10 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
if (field.name_tok == 0) {
field_name = try std.fmt.allocPrint(t.arena, "unnamed_{d}", .{unnamed_field_count});
unnamed_field_count += 1;
try t.anonymous_record_field_names.put(t.gpa, .{
.parent = base.qt,
.field = field.qt,
}, field_name);
}
const field_type = t.transType(scope, field.qt, field_loc) catch |err| switch (err) {
error.UnsupportedType => {
Expand Down Expand Up @@ -647,6 +657,7 @@ fn transFnDecl(t: *Translator, fn_decl_node: Node.Index, is_pub: bool) Error!voi
fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!void {
var name = t.tree.tokSlice(variable.name_tok);
const toplevel = scope.id == .root;
const is_static_local = !toplevel and variable.storage_class == .static;
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(t) else undefined;
if (!toplevel) {
if (variable.storage_class == .@"extern") {
Expand Down Expand Up @@ -707,7 +718,7 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
.is_threadlocal = variable.thread_local,
.linksection_string = null,
.alignment = alignment,
.name = name,
.name = if (is_static_local) Scope.Block.static_inner_name else name,
.type = type_node,
.init = init_node,
},
Expand All @@ -719,6 +730,9 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
if (variable.storage_class == .@"extern") {
node = try ZigTag.extern_local_var.create(t.arena, .{ .name = name, .init = node });
}
if (variable.storage_class == .static) {
node = try ZigTag.static_local_var.create(t.arena, .{ .name = name, .init = node });
}
try scope.appendNode(node);
try bs.discardVariable(name);
}
Expand Down Expand Up @@ -1625,6 +1639,9 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
.shl_expr => |shl_expr| try t.transShiftExpr(scope, shl_expr, .shl),
.shr_expr => |shr_expr| try t.transShiftExpr(scope, shr_expr, .shr),

.member_access_expr => |member_access| return t.transMemberAccess(scope, .normal, member_access, used),
.member_access_ptr_expr => |member_access| return t.transMemberAccess(scope, .ptr, member_access, used),

.builtin_call_expr => |call| return t.transBuiltinCall(scope, call, used),

.cond_expr => |cond_expr| return t.transCondExpr(scope, cond_expr, used),
Expand Down Expand Up @@ -2152,6 +2169,35 @@ fn transPointerArithmeticSignedOp(t: *Translator, scope: *Scope, bin: Node.Binar
return t.createBinOpNode(op_id, lhs_node, bitcast_node);
}

fn transMemberAccess(
t: *Translator,
scope: *Scope,
kind: enum { normal, ptr },
member_access: Node.MemberAccess,
used: ResultUsed,
) TransError!ZigNode {
const base_info = switch (kind) {
.normal => member_access.base.qt(t.tree),
.ptr => member_access.base.qt(t.tree).childType(t.comp),
};
const record = base_info.getRecord(t.comp).?;
const field = record.fields[member_access.member_index];
const field_name = if (field.name_tok == 0) t.anonymous_record_field_names.get(.{
.parent = base_info.base(t.comp).qt,
.field = field.qt,
}).? else field.name.lookup(t.comp);
const base_node = try t.transExpr(scope, member_access.base, .used);
const lhs = switch (kind) {
.normal => base_node,
.ptr => try ZigTag.deref.create(t.arena, base_node),
};
const field_access = try ZigTag.field_access.create(t.arena, .{
.lhs = lhs,
.field_name = field_name,
});
return t.maybeSuppressResult(used, field_access);
}

fn transBuiltinCall(
t: *Translator,
scope: *Scope,
Expand Down
7 changes: 3 additions & 4 deletions test/cases/translate/anonymous_struct_&_unions.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,19 @@ typedef struct {
void foo(outer *x) { x->y = x->x; }

// translate
// expect=fail
//
// const struct_unnamed_2 = extern struct {
// y: c_int = @import("std").mem.zeroes(c_int),
// y: c_int = 0,
// };
// const union_unnamed_1 = extern union {
// x: u8,
// unnamed_0: struct_unnamed_2,
// };
// pub const outer = extern struct {
// const outer = extern struct {
// unnamed_0: union_unnamed_1 = @import("std").mem.zeroes(union_unnamed_1),
// };
// pub export fn foo(arg_x: [*c]outer) void {
// var x = arg_x;
// _ = &x;
// x.*.unnamed_0.unnamed_0.y = @as(c_int, @bitCast(@as(c_uint, x.*.unnamed_0.x)));
// x.*.unnamed_0.unnamed_0.y = x.*.unnamed_0.x;
// }
16 changes: 3 additions & 13 deletions test/cases/translate/field_access_expression.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#define ARROW a->b
#define DOT a.b
extern struct Foo {
int b;
}a;
Expand All @@ -11,24 +9,16 @@ void foo(void) {
}

// translate
// expect=fail
//
// pub const struct_Foo = extern struct {
// b: c_int = @import("std").mem.zeroes(c_int),
// b: c_int = 0,
// };
// pub extern var a: struct_Foo;
// pub export var b: f32 = 2.0;
// pub export var b: f32 = 2;
// pub export fn foo() void {
// var c: [*c]struct_Foo = undefined;
// _ = &c;
// _ = a.b;
// _ = c.*.b;
// }
//
// pub inline fn ARROW() @TypeOf(a.*.b) {
// return a.*.b;
// }
//
// pub inline fn DOT() @TypeOf(a.b) {
// return a.b;
// }
// pub const Foo = struct_Foo;
13 changes: 13 additions & 0 deletions test/cases/translate/field_access_macros.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#define ARROW a->b
#define DOT a.b

// translate
// expect=fail
//
// pub inline fn ARROW() @TypeOf(a.*.b) {
// return a.*.b;
// }
//
// pub inline fn DOT() @TypeOf(a.b) {
// return a.b;
// }
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ void foo(void) {
}

// translate
// expect=fail
//
// pub export fn foo() void {
// var i: c_int = undefined;
Expand Down
8 changes: 5 additions & 3 deletions test/cases/translate/static empty struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ struct empty_struct {};

static inline void foo() {
static struct empty_struct bar = {};
(void)bar;
}

// translate
// target=x86_64-linux
// expect=fail
//
// pub const struct_empty_struct = extern struct {};
// pub fn foo() callconv(.c) void {
// pub fn foo(...) callconv(.c) void {
// const bar = struct {
// var static: struct_empty_struct = @import("std").mem.zeroes(struct_empty_struct);
// var static: struct_empty_struct = struct_empty_struct{};
// };
// _ = &bar;
// _ = bar.static;
// }
// pub const empty_struct = struct_empty_struct;
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ int bar(void) {
}

// translate
// expect=fail
//
// pub const struct_FOO = extern struct {
// x: c_int = @import("std").mem.zeroes(c_int),
// y: c_int = @import("std").mem.zeroes(c_int),
// x: c_int = 0,
// y: c_int = 0,
// };
// pub export fn bar() c_int {
// const foo = struct {
Expand All @@ -18,3 +17,4 @@ int bar(void) {
// _ = &foo;
// return foo.static.x;
// }
// pub const FOO = struct_FOO;
7 changes: 4 additions & 3 deletions test/cases/translate/static_variable_in_block_scope.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
float bar;
int foo() {
_Thread_local static int bar = 2;
(void)bar;
}

// translate
// expect=fail
//
// pub export var bar: f32 = @import("std").mem.zeroes(f32);
// pub export var bar: f32 = 0;
// pub export fn foo() c_int {
// const bar_1 = struct {
// threadlocal var static: c_int = 2;
// };
// _ = &bar_1;
// return 0;
// _ = bar_1.static;
// return undefined;
// }

0 comments on commit 4febc09

Please sign in to comment.