feature. See also
. The project being documented here (as the example) is the Zig library itself.
Translator.transExpr
fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed) TransError!ZigNode
File
Code
fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed) TransError!ZigNode {
const qt = expr.qt(t.tree);
return t.maybeSuppressResult(used, switch (expr.get(t.tree)) {
.paren_expr => |paren_expr| {
return t.transExpr(scope, paren_expr.operand, used);
},
.cast => |cast| return t.transCastExpr(scope, cast, cast.qt, used, .with_as),
.decl_ref_expr => |decl_ref| try t.transDeclRefExpr(scope, decl_ref),
.enumeration_ref => |enum_ref| try t.transDeclRefExpr(scope, enum_ref),
.addr_of_expr => |addr_of_expr| try ZigTag.address_of.create(t.arena, try t.transExpr(scope, addr_of_expr.operand, .used)),
.deref_expr => |deref_expr| res: {
if (t.typeWasDemotedToOpaque(qt))
return t.fail(error.UnsupportedTranslation, deref_expr.op_tok, "cannot dereference opaque type", .{});
if (qt.is(t.comp, .func)) return t.transExpr(scope, deref_expr.operand, used);
break :res try ZigTag.deref.create(t.arena, try t.transExpr(scope, deref_expr.operand, .used));
},
.bool_not_expr => |bool_not_expr| try ZigTag.not.create(t.arena, try t.transBoolExpr(scope, bool_not_expr.operand)),
.bit_not_expr => |bit_not_expr| try ZigTag.bit_not.create(t.arena, op: {
const operand = try t.transExpr(scope, bit_not_expr.operand, .used);
if (!operand.isBoolRes()) break :op operand;
const casted = try ZigTag.int_from_bool.create(t.arena, operand);
const ty = try t.transType(scope, bit_not_expr.qt, bit_not_expr.op_tok);
break :op try ZigTag.as.create(t.arena, .{ .lhs = ty, .rhs = casted });
}),
.plus_expr => |plus_expr| return t.transExpr(scope, plus_expr.operand, used),
.negate_expr => |negate_expr| res: {
const operand_qt = negate_expr.operand.qt(t.tree);
if (!t.typeHasWrappingOverflow(operand_qt)) {
const sub_expr_node = try t.transExpr(scope, negate_expr.operand, .used);
const to_negate = if (sub_expr_node.isBoolRes()) blk: {
const ty_node = try ZigTag.type.create(t.arena, "c_int");
const int_node = try ZigTag.int_from_bool.create(t.arena, sub_expr_node);
break :blk try ZigTag.as.create(t.arena, .{ .lhs = ty_node, .rhs = int_node });
} else sub_expr_node;
break :res try ZigTag.negate.create(t.arena, to_negate);
} else if (t.signedness(operand_qt) == .unsigned) {
break :res try ZigTag.negate_wrap.create(t.arena, try t.transExpr(scope, negate_expr.operand, .used));
} else return t.fail(error.UnsupportedTranslation, negate_expr.op_tok, "C negation with non float non integer", .{});
},
.div_expr => |div_expr| res: {
if (qt.isInt(t.comp) and t.signedness(qt) == .signed) {
const lhs = try t.transExpr(scope, div_expr.lhs, .used);
const rhs = try t.transExpr(scope, div_expr.rhs, .used);
break :res try ZigTag.div_trunc.create(t.arena, .{ .lhs = lhs, .rhs = rhs });
}
break :res try t.transBinExpr(scope, div_expr, .div);
},
.mod_expr => |mod_expr| res: {
if (qt.isInt(t.comp) and t.signedness(qt) == .signed) {
const lhs = try t.transExpr(scope, mod_expr.lhs, .used);
const rhs = try t.transExpr(scope, mod_expr.rhs, .used);
break :res try t.createHelperCallNode(.signedRemainder, &.{ lhs, rhs });
}
break :res try t.transBinExpr(scope, mod_expr, .mod);
},
.add_expr => |add_expr| res: {
const lhs_qt = add_expr.lhs.qt(t.tree);
const rhs_qt = add_expr.rhs.qt(t.tree);
if (qt.isPointer(t.comp) and (t.signedness(lhs_qt) == .signed or
t.signedness(rhs_qt) == .signed))
{
break :res try t.transPointerArithmeticSignedOp(scope, add_expr, .add);
}
if (t.signedness(qt) == .unsigned) {
break :res try t.transBinExpr(scope, add_expr, .add_wrap);
} else {
break :res try t.transBinExpr(scope, add_expr, .add);
}
},
.sub_expr => |sub_expr| res: {
const lhs_qt = sub_expr.lhs.qt(t.tree);
const rhs_qt = sub_expr.rhs.qt(t.tree);
if (qt.isPointer(t.comp) and (t.signedness(lhs_qt) == .signed or
t.signedness(rhs_qt) == .signed))
{
break :res try t.transPointerArithmeticSignedOp(scope, sub_expr, .sub);
}
if (sub_expr.lhs.qt(t.tree).isPointer(t.comp) and sub_expr.rhs.qt(t.tree).isPointer(t.comp)) {
break :res try t.transPtrDiffExpr(scope, sub_expr);
} else if (t.signedness(qt) == .unsigned) {
break :res try t.transBinExpr(scope, sub_expr, .sub_wrap);
} else {
break :res try t.transBinExpr(scope, sub_expr, .sub);
}
},
.mul_expr => |mul_expr| if (t.signedness(qt) == .unsigned)
try t.transBinExpr(scope, mul_expr, .mul_wrap)
else
try t.transBinExpr(scope, mul_expr, .mul),
.less_than_expr => |lt| try t.transBinExpr(scope, lt, .less_than),
.greater_than_expr => |gt| try t.transBinExpr(scope, gt, .greater_than),
.less_than_equal_expr => |lte| try t.transBinExpr(scope, lte, .less_than_equal),
.greater_than_equal_expr => |gte| try t.transBinExpr(scope, gte, .greater_than_equal),
.equal_expr => |equal_expr| try t.transBinExpr(scope, equal_expr, .equal),
.not_equal_expr => |not_equal_expr| try t.transBinExpr(scope, not_equal_expr, .not_equal),
.bool_and_expr => |bool_and_expr| try t.transBoolBinExpr(scope, bool_and_expr, .@"and"),
.bool_or_expr => |bool_or_expr| try t.transBoolBinExpr(scope, bool_or_expr, .@"or"),
.bit_and_expr => |bit_and_expr| try t.transBinExpr(scope, bit_and_expr, .bit_and),
.bit_or_expr => |bit_or_expr| try t.transBinExpr(scope, bit_or_expr, .bit_or),
.bit_xor_expr => |bit_xor_expr| try t.transBinExpr(scope, bit_xor_expr, .bit_xor),
.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| try t.transMemberAccess(scope, .normal, member_access, null, .accessor),
.member_access_ptr_expr => |member_access| try t.transMemberAccess(scope, .ptr, member_access, null, .accessor),
.array_access_expr => |array_access| try t.transArrayAccess(scope, array_access, null),
.builtin_ref => unreachable,
.builtin_call_expr => |call| return t.transBuiltinCall(scope, call, used),
.call_expr => |call| return t.transCall(scope, call, used),
.builtin_types_compatible_p => |compatible| blk: {
const lhs = try t.transType(scope, compatible.lhs, compatible.builtin_tok);
const rhs = try t.transType(scope, compatible.rhs, compatible.builtin_tok);
break :blk try ZigTag.equal.create(t.arena, .{
.lhs = lhs,
.rhs = rhs,
});
},
.builtin_choose_expr => |choose| return t.transCondExpr(scope, choose, used),
.cond_expr => |cond_expr| return t.transCondExpr(scope, cond_expr, used),
.binary_cond_expr => |conditional| return t.transBinaryCondExpr(scope, conditional, used),
.cond_dummy_expr => unreachable,
.assign_expr => |assign| return t.transAssignExpr(scope, assign, used),
.add_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.sub_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.mul_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.div_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.mod_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.shl_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.shr_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.bit_and_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.bit_xor_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.bit_or_assign_expr => |assign| return t.transCompoundAssign(scope, assign, used),
.compound_assign_dummy_expr => {
assert(used == .used);
return t.compound_assign_dummy.?;
},
.comma_expr => |comma_expr| return t.transCommaExpr(scope, comma_expr, used),
.pre_inc_expr => |un| return t.transIncDecExpr(scope, un, .pre, .inc, used),
.pre_dec_expr => |un| return t.transIncDecExpr(scope, un, .pre, .dec, used),
.post_inc_expr => |un| return t.transIncDecExpr(scope, un, .post, .inc, used),
.post_dec_expr => |un| return t.transIncDecExpr(scope, un, .post, .dec, used),
.int_literal => return t.transIntLiteral(scope, expr, used, .with_as),
.char_literal => return t.transCharLiteral(scope, expr, used, .with_as),
.float_literal => return t.transFloatLiteral(scope, expr, used, .with_as),
.string_literal_expr => |literal| try t.transStringLiteral(scope, expr, literal),
.bool_literal => res: {
const val = t.tree.value_map.get(expr).?;
break :res if (val.toBool(t.comp))
ZigTag.true_literal.init()
else
ZigTag.false_literal.init();
},
.nullptr_literal => ZigTag.null_literal.init(),
.imaginary_literal => |literal| {
return t.fail(error.UnsupportedTranslation, literal.op_tok, "TODO complex numbers", .{});
},
.compound_literal_expr => |literal| return t.transCompoundLiteral(scope, literal, used),
.default_init_expr => |default_init| return t.transDefaultInit(scope, default_init, used, .with_as),
.array_init_expr => |array_init| return t.transArrayInit(scope, array_init, used),
.union_init_expr => |union_init| return t.transUnionInit(scope, union_init, used),
.struct_init_expr => |struct_init| return t.transStructInit(scope, struct_init, used),
.array_filler_expr => unreachable,
.sizeof_expr => |sizeof| try t.transTypeInfo(scope, .sizeof, sizeof),
.alignof_expr => |alignof| try t.transTypeInfo(scope, .alignof, alignof),
.imag_expr, .real_expr => |un| {
return t.fail(error.UnsupportedTranslation, un.op_tok, "TODO complex numbers", .{});
},
.addr_of_label => |addr_of_label| {
return t.fail(error.UnsupportedTranslation, addr_of_label.label_tok, "TODO computed goto", .{});
},
.generic_expr => |generic| return t.transExpr(scope, generic.chosen, used),
.generic_association_expr => |generic| return t.transExpr(scope, generic.expr, used),
.generic_default_expr => |generic| return t.transExpr(scope, generic.expr, used),
.stmt_expr => |stmt_expr| return t.transStmtExpr(scope, stmt_expr, used),
.builtin_convertvector => |convertvector| try t.transConvertvectorExpr(scope, convertvector),
.builtin_shufflevector => |shufflevector| try t.transShufflevectorExpr(scope, shufflevector),
.builtin_va_arg_pack, .builtin_va_arg_pack_len => |va_arg_pack| {
return t.fail(error.UnsupportedTranslation, va_arg_pack.builtin_tok, "TODO va arg pack", .{});
},
.compound_stmt,
.static_assert,
.return_stmt,
.null_stmt,
.if_stmt,
.while_stmt,
.do_while_stmt,
.for_stmt,
.continue_stmt,
.break_stmt,
.labeled_stmt,
.switch_stmt,
.case_stmt,
.default_stmt,
.goto_stmt,
.computed_goto_stmt,
.asm_stmt,
.global_asm,
.typedef,
.struct_decl,
.union_decl,
.enum_decl,
.function,
.param,
.variable,
.enum_field,
.record_field,
.struct_forward_decl,
.union_forward_decl,
.enum_forward_decl,
.empty_decl,
=> unreachable,
});
}