Skip to content

Commit 6dab213

Browse files
committed
translate unary expressions
1 parent 43f752e commit 6dab213

File tree

1 file changed

+155
-47
lines changed

1 file changed

+155
-47
lines changed

src/Translator.zig

+155-47
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,26 @@ fn warn(c: *Context, scope: *Scope, loc: TokenIndex, comptime format: []const u8
113113
try scope.appendNode(try ZigTag.warning.create(c.arena, value));
114114
}
115115

116-
fn tokenIndex(c: *Context, node: NodeIndex) ?TokenIndex {
116+
fn nodeLoc(c: *Context, node: NodeIndex) TokenIndex {
117117
const token_index = c.tree.nodes.items(.loc)[@intFromEnum(node)];
118118
return switch (token_index) {
119-
.none => null,
119+
.none => unreachable,
120120
else => @intFromEnum(token_index),
121121
};
122122
}
123123

124+
fn nodeTag(c: *Context, node: NodeIndex) Tree.Tag {
125+
return c.tree.nodes.items(.tag)[@intFromEnum(node)];
126+
}
127+
128+
fn nodeType(c: *Context, node: NodeIndex) Type {
129+
return c.tree.nodes.items(.ty)[@intFromEnum(node)];
130+
}
131+
132+
fn nodeData(c: *Context, node: NodeIndex) Tree.Node.Data {
133+
return c.tree.nodes.items(.data)[@intFromEnum(node)];
134+
}
135+
124136
pub fn translate(
125137
gpa: mem.Allocator,
126138
comp: *aro.Compilation,
@@ -244,9 +256,7 @@ fn transTopLevelDecls(c: *Context) !void {
244256
}
245257

246258
fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
247-
const node_tags = c.tree.nodes.items(.tag);
248-
const node_ty = c.tree.nodes.items(.ty);
249-
switch (node_tags[@intFromEnum(decl)]) {
259+
switch (c.nodeTag(decl)) {
250260
.typedef => {
251261
try c.transTypeDef(scope, decl);
252262
},
@@ -256,13 +266,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
256266
.struct_decl,
257267
.union_decl,
258268
=> {
259-
try c.transRecordDecl(scope, node_ty[@intFromEnum(decl)]);
269+
try c.transRecordDecl(scope, c.nodeType(decl));
260270
},
261271

262272
.enum_decl_two, .enum_decl => {
263273
const fields = c.tree.childNodes(decl);
264-
const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum";
265-
try c.transEnumDecl(scope, enum_decl, fields, c.tokenIndex(decl) orelse 0);
274+
const enum_decl = c.nodeType(decl).canonicalize(.standard).data.@"enum";
275+
try c.transEnumDecl(scope, enum_decl, fields, c.nodeLoc(decl));
266276
},
267277

268278
.enum_field_decl,
@@ -302,18 +312,18 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
302312
}
303313

304314
fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void {
305-
const ty = c.tree.nodes.items(.ty)[@intFromEnum(typedef_decl)];
306-
const data = c.tree.nodes.items(.data)[@intFromEnum(typedef_decl)];
315+
const ty = c.nodeType(typedef_decl);
316+
const decl = c.nodeData(typedef_decl).decl;
307317

308318
const toplevel = scope.id == .root;
309319
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
310320

311-
var name: []const u8 = c.tree.tokSlice(data.decl.name);
321+
var name: []const u8 = c.tree.tokSlice(decl.name);
312322
try c.typedefs.put(c.gpa, name, {});
313323

314324
if (!toplevel) name = try bs.makeMangledName(name);
315325

316-
const typedef_loc = data.decl.name;
326+
const typedef_loc = decl.name;
317327
const init_node = c.transType(scope, ty, .standard, typedef_loc) catch |err| switch (err) {
318328
error.UnsupportedType => {
319329
return c.failDecl(typedef_loc, name, "unable to resolve typedef child type", .{});
@@ -495,25 +505,25 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void {
495505
}
496506
}
497507

498-
fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
499-
const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];
508+
fn transFnDecl(c: *Context, fn_decl_node: NodeIndex, is_pub: bool) Error!void {
509+
const raw_ty = c.nodeType(fn_decl_node);
500510
const fn_ty = raw_ty.canonicalize(.standard);
501-
const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];
511+
const decl = c.nodeData(fn_decl_node).decl;
502512
if (c.decl_table.get(@intFromPtr(fn_ty.data.func))) |_|
503513
return; // Avoid processing this decl twice
504514

505-
const fn_name = c.tree.tokSlice(node_data.decl.name);
515+
const fn_name = c.tree.tokSlice(decl.name);
506516
if (c.global_scope.sym_table.contains(fn_name))
507517
return; // Avoid processing this decl twice
508518

509-
const fn_decl_loc = 0; // TODO
510-
const has_body = node_data.decl.node != .none;
519+
const fn_decl_loc = c.nodeLoc(fn_decl_node);
520+
const has_body = decl.node != .none;
511521
const is_always_inline = has_body and raw_ty.getAttribute(.always_inline) != null;
512522
const proto_ctx = FnProtoContext{
513523
.fn_name = fn_name,
514524
.is_inline = is_always_inline,
515525
.is_extern = !has_body,
516-
.is_export = switch (c.tree.nodes.items(.tag)[@intFromEnum(fn_decl)]) {
526+
.is_export = switch (c.nodeTag(fn_decl_node)) {
517527
.fn_proto, .fn_def => has_body and !is_always_inline,
518528

519529
.inline_fn_proto, .inline_fn_def, .inline_static_fn_proto, .inline_static_fn_def, .static_fn_proto, .static_fn_def => false,
@@ -536,7 +546,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
536546
const proto_payload = proto_node.castTag(.func).?;
537547

538548
// actual function definition with body
539-
const body_stmt = node_data.decl.node;
549+
const body_stmt = decl.node;
540550
var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
541551
block_scope.return_type = fn_ty.data.func.return_type;
542552
defer block_scope.deinit();
@@ -590,9 +600,9 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
590600
}
591601

592602
fn transVarDecl(c: *Context, node: NodeIndex) Error!void {
593-
const data = c.tree.nodes.items(.data)[@intFromEnum(node)];
594-
const name = c.tree.tokSlice(data.decl.name);
595-
return c.failDecl(data.decl.name, name, "unable to translate variable declaration", .{});
603+
const decl = c.nodeData(node).decl;
604+
const name = c.tree.tokSlice(decl.name);
605+
return c.failDecl(decl.name, name, "unable to translate variable declaration", .{});
596606
}
597607

598608
fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex, source_loc: ?TokenIndex) Error!void {
@@ -678,20 +688,20 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_
678688
}
679689

680690
fn transStaticAssert(c: *Context, scope: *Scope, static_assert_node: NodeIndex) Error!void {
681-
const node_data = c.tree.nodes.items(.data)[@intFromEnum(static_assert_node)];
691+
const node_data = c.nodeData(static_assert_node).bin;
682692

683-
const condition = c.transExpr(scope, node_data.bin.lhs, .used) catch |err| switch (err) {
693+
const condition = c.transExpr(scope, node_data.lhs, .used) catch |err| switch (err) {
684694
error.UnsupportedTranslation, error.UnsupportedType => {
685-
return try c.warn(&c.global_scope.base, c.tokenIndex(node_data.bin.lhs).?, "unable to translate _Static_assert condition", .{});
695+
return try c.warn(&c.global_scope.base, c.nodeLoc(node_data.lhs), "unable to translate _Static_assert condition", .{});
686696
},
687697
error.OutOfMemory => |e| return e,
688698
};
689699

690700
// generate @compileError message that matches C compiler output
691-
const diagnostic = if (node_data.bin.rhs != .none) str: {
701+
const diagnostic = if (node_data.rhs != .none) str: {
692702
// Aro guarantees this to be a string literal.
693-
const str_val = c.tree.value_map.get(node_data.bin.rhs).?;
694-
const str_ty = c.tree.nodes.items(.ty)[@intFromEnum(node_data.bin.rhs)];
703+
const str_val = c.tree.value_map.get(node_data.rhs).?;
704+
const str_ty = c.nodeType(node_data.rhs);
695705

696706
const bytes = c.comp.interner.get(str_val.ref()).bytes;
697707
var buf = std.ArrayList(u8).init(c.gpa);
@@ -1094,7 +1104,7 @@ fn isFunctionDeclRef(c: *Context, base_node: NodeIndex) bool {
10941104
node = node_data[@intFromEnum(node)].un;
10951105
},
10961106
.decl_ref_expr => {
1097-
const res_ty = c.tree.nodes.items(.ty)[@intFromEnum(node)];
1107+
const res_ty = c.nodeType(node);
10981108
return res_ty.isFunc();
10991109
},
11001110
.implicit_cast => {
@@ -1116,14 +1126,22 @@ fn isFunctionDeclRef(c: *Context, base_node: NodeIndex) bool {
11161126
else => return false,
11171127
};
11181128
}
1129+
fn typeHasWrappingOverflow(c: *Context, ty: Type) bool {
1130+
if (ty.isUnsignedInt(c.comp)) {
1131+
// unsigned integer overflow wraps around.
1132+
return true;
1133+
} else {
1134+
// float, signed integer, and pointer overflow is undefined behavior.
1135+
return false;
1136+
}
1137+
}
11191138

11201139
// =====================
11211140
// Statement translation
11221141
// =====================
11231142

11241143
fn transStmt(c: *Context, scope: *Scope, stmt: NodeIndex) TransError!ZigNode {
1125-
const node_tags = c.tree.nodes.items(.tag);
1126-
switch (node_tags[@intFromEnum(stmt)]) {
1144+
switch (c.nodeTag(stmt)) {
11271145
.compound_stmt, .compound_stmt_two => {
11281146
return c.transCompoundStmt(scope, stmt);
11291147
},
@@ -1133,7 +1151,7 @@ fn transStmt(c: *Context, scope: *Scope, stmt: NodeIndex) TransError!ZigNode {
11331151
},
11341152
.return_stmt => return c.transReturnStmt(scope, stmt),
11351153
.null_stmt => return ZigTag.empty_block.init(),
1136-
else => return c.fail(error.UnsupportedTranslation, c.tokenIndex(stmt).?, "TODO implement translation of stmt {s}", .{@tagName(node_tags[@intFromEnum(stmt)])}),
1154+
else => |tag| return c.fail(error.UnsupportedTranslation, c.nodeLoc(stmt), "TODO implement translation of stmt {s}", .{@tagName(tag)}),
11371155
}
11381156
}
11391157

@@ -1156,10 +1174,10 @@ fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError
11561174
}
11571175

11581176
fn transReturnStmt(c: *Context, scope: *Scope, return_stmt: NodeIndex) TransError!ZigNode {
1159-
const data = c.tree.nodes.items(.data)[@intFromEnum(return_stmt)];
1160-
if (data.un == .none) return ZigTag.return_void.init();
1177+
const operand = c.nodeData(return_stmt).un;
1178+
if (operand == .none) return ZigTag.return_void.init();
11611179

1162-
var rhs = try c.transExprCoercing(scope, data.un);
1180+
var rhs = try c.transExprCoercing(scope, operand);
11631181
const return_ty = scope.findBlockReturnType();
11641182
if (rhs.isBoolRes() and !return_ty.is(.bool)) {
11651183
rhs = try ZigTag.int_from_bool.create(c.arena, rhs);
@@ -1171,10 +1189,10 @@ fn transReturnStmt(c: *Context, scope: *Scope, return_stmt: NodeIndex) TransErro
11711189
// Expression translation
11721190
// ======================
11731191

1174-
fn transExpr(c: *Context, scope: *Scope, node: NodeIndex, used: ResultUsed) TransError!ZigNode {
1175-
std.debug.assert(node != .none);
1176-
const ty = c.tree.nodes.items(.ty)[@intFromEnum(node)];
1177-
if (c.tree.value_map.get(node)) |val| {
1192+
fn transExpr(c: *Context, scope: *Scope, expr: NodeIndex, used: ResultUsed) TransError!ZigNode {
1193+
std.debug.assert(expr != .none);
1194+
const ty = c.nodeType(expr);
1195+
if (c.tree.value_map.get(expr)) |val| {
11781196
// TODO handle other values
11791197
const int = try c.transCreateNodeInt(val);
11801198
const as_node = try ZigTag.as.create(c.arena, .{
@@ -1183,10 +1201,52 @@ fn transExpr(c: *Context, scope: *Scope, node: NodeIndex, used: ResultUsed) Tran
11831201
});
11841202
return c.maybeSuppressResult(used, as_node);
11851203
}
1186-
const node_tags = c.tree.nodes.items(.tag);
1187-
switch (node_tags[@intFromEnum(node)]) {
1188-
.explicit_cast, .implicit_cast => return c.transCastExpr(scope, node, used),
1189-
.decl_ref_expr => return c.transDeclRefExpr(scope, node),
1204+
switch (c.nodeTag(expr)) {
1205+
.explicit_cast, .implicit_cast => return c.transCastExpr(scope, expr, used),
1206+
.decl_ref_expr => return c.transDeclRefExpr(scope, expr),
1207+
.addr_of_expr => {
1208+
const operand = c.nodeData(expr).un;
1209+
const res = try ZigTag.address_of.create(c.arena, try c.transExpr(scope, operand, .used));
1210+
return c.maybeSuppressResult(used, res);
1211+
},
1212+
.deref_expr => {
1213+
if (c.typeWasDemotedToOpaque(ty))
1214+
return fail(c, error.UnsupportedTranslation, c.nodeLoc(expr), "cannot dereference opaque type", .{});
1215+
1216+
const operand = c.nodeData(expr).un;
1217+
// Dereferencing a function pointer is a no-op.
1218+
if (ty.isFunc()) return try c.transExpr(scope, operand, used);
1219+
1220+
const res = try ZigTag.deref.create(c.arena, try c.transExpr(scope, operand, .used));
1221+
return c.maybeSuppressResult(used, res);
1222+
},
1223+
.bool_not_expr => {
1224+
const operand = c.nodeData(expr).un;
1225+
const res = try ZigTag.not.create(c.arena, try c.transBoolExpr(scope, operand, .used));
1226+
return c.maybeSuppressResult(used, res);
1227+
},
1228+
.bit_not_expr => {
1229+
const operand = c.nodeData(expr).un;
1230+
const res = try ZigTag.bit_not.create(c.arena, try c.transExpr(scope, operand, .used));
1231+
return c.maybeSuppressResult(used, res);
1232+
},
1233+
.negate_expr => {
1234+
const operand = c.nodeData(expr).un;
1235+
const operand_ty = c.nodeType(expr);
1236+
if (!c.typeHasWrappingOverflow(operand_ty)) {
1237+
const sub_expr_node = try c.transExpr(scope, operand, .used);
1238+
const to_negate = if (sub_expr_node.isBoolRes()) blk: {
1239+
const ty_node = try ZigTag.type.create(c.arena, "c_int");
1240+
const int_node = try ZigTag.int_from_bool.create(c.arena, sub_expr_node);
1241+
break :blk try ZigTag.as.create(c.arena, .{ .lhs = ty_node, .rhs = int_node });
1242+
} else sub_expr_node;
1243+
1244+
return ZigTag.negate.create(c.arena, to_negate);
1245+
} else if (operand_ty.isUnsignedInt(c.comp)) {
1246+
// use -% x for unsigned integers
1247+
return ZigTag.negate_wrap.create(c.arena, try c.transExpr(scope, operand, .used));
1248+
} else return fail(c, error.UnsupportedTranslation, c.nodeLoc(expr), "C negation with non float non integer", .{});
1249+
},
11901250
else => unreachable, // Not an expression.
11911251
}
11921252
}
@@ -1198,19 +1258,67 @@ fn transExprCoercing(c: *Context, scope: *Scope, expr: NodeIndex) TransError!Zig
11981258
return c.transExpr(scope, expr, .used);
11991259
}
12001260

1261+
fn transBoolExpr(c: *Context, scope: *Scope, expr: NodeIndex, used: ResultUsed) TransError!ZigNode {
1262+
const expr_tag = c.nodeTag(expr);
1263+
if (expr_tag == .int_literal) {
1264+
const int_val = c.tree.value_map.get(expr).?;
1265+
return if (int_val.isZero(c.comp))
1266+
ZigTag.false_literal.init()
1267+
else
1268+
ZigTag.true_literal.init();
1269+
}
1270+
if (expr_tag == .implicit_cast) {
1271+
const cast = c.nodeData(expr).cast;
1272+
if (cast.kind == .bool_to_int) {
1273+
const bool_res = try c.transExpr(scope, cast.operand, .used);
1274+
return c.maybeSuppressResult(used, bool_res);
1275+
}
1276+
}
1277+
1278+
const maybe_bool_res = try c.transExpr(scope, expr, .used);
1279+
if (maybe_bool_res.isBoolRes()) {
1280+
return c.maybeSuppressResult(used, maybe_bool_res);
1281+
}
1282+
1283+
const ty = c.nodeType(expr);
1284+
const res = try c.finishBoolExpr(ty, maybe_bool_res);
1285+
return c.maybeSuppressResult(used, res);
1286+
}
1287+
1288+
fn finishBoolExpr(c: *Context, ty: Type, node: ZigNode) TransError!ZigNode {
1289+
if (ty.is(.nullptr_t)) {
1290+
// node == null, always true
1291+
return ZigTag.equal.create(c.arena, .{ .lhs = node, .rhs = ZigTag.null_literal.init() });
1292+
}
1293+
if (ty.isPtr()) {
1294+
if (node.tag() == .string_literal) {
1295+
// @intFromPtr(node) != 0, always true
1296+
const int_from_ptr = try ZigTag.int_from_ptr.create(c.arena, node);
1297+
return ZigTag.not_equal.create(c.arena, .{ .lhs = int_from_ptr, .rhs = ZigTag.zero_literal.init() });
1298+
}
1299+
// node != null
1300+
return ZigTag.not_equal.create(c.arena, .{ .lhs = node, .rhs = ZigTag.null_literal.init() });
1301+
}
1302+
if (ty.isScalar()) {
1303+
// node != 0
1304+
return ZigTag.not_equal.create(c.arena, .{ .lhs = node, .rhs = ZigTag.zero_literal.init() });
1305+
}
1306+
unreachable; // Unexpected bool expression type
1307+
}
1308+
12011309
fn transCastExpr(c: *Context, scope: *Scope, cast_node: NodeIndex, used: ResultUsed) TransError!ZigNode {
1202-
const cast = c.tree.nodes.items(.data)[@intFromEnum(cast_node)].cast;
1310+
const cast = c.nodeData(cast_node).cast;
12031311
switch (cast.kind) {
12041312
.lval_to_rval, .no_op, .function_to_pointer => {
12051313
const sub_expr_node = try c.transExpr(scope, cast.operand, .used);
12061314
return c.maybeSuppressResult(used, sub_expr_node);
12071315
},
1208-
else => return c.fail(error.UnsupportedTranslation, c.tokenIndex(cast_node).?, "TODO translate {s} cast", .{@tagName(cast.kind)}),
1316+
else => return c.fail(error.UnsupportedTranslation, c.nodeLoc(cast_node), "TODO translate {s} cast", .{@tagName(cast.kind)}),
12091317
}
12101318
}
12111319

12121320
fn transDeclRefExpr(c: *Context, scope: *Scope, decl_ref_node: NodeIndex) TransError!ZigNode {
1213-
const decl_ref = c.tree.nodes.items(.data)[@intFromEnum(decl_ref_node)].decl_ref;
1321+
const decl_ref = c.nodeData(decl_ref_node).decl_ref;
12141322

12151323
const name = c.tree.tokSlice(decl_ref);
12161324
const mangled_name = scope.getAlias(name);

0 commit comments

Comments
 (0)