translate-c: convert casts and string/array init

This commit is contained in:
Veikka Tuominen 2021-02-10 22:04:19 +02:00
parent 5dac3683c9
commit d8b9fca0b1
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 174 additions and 342 deletions

View File

@ -1084,7 +1084,6 @@ fn transStmt(
const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;
const expr = try transExpr(c, scope, source_expr, .used, lrvalue);
return maybeSuppressResult(c, scope, result_used, expr);
const node = try c.arena.create(Node.GroupedExpression);
},
else => {
return revertAndWarn(
@ -1389,62 +1388,56 @@ fn transDeclRefExpr(
}
fn transImplicitCastExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
expr: *const clang.ImplicitCastExpr,
result_used: ResultUsed,
) TransError!*ast.Node {
const c = rp.c;
) TransError!Node {
const sub_expr = expr.getSubExpr();
const dest_type = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
const src_type = getExprQualType(c, sub_expr);
switch (expr.getCastKind()) {
.BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {
const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
return try transCCast(rp, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);
const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value);
const casted = try transCCast(c, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);
return maybeSuppressResult(c, scope, result_used, casted);
},
.LValueToRValue, .NoOp, .FunctionToPointerDecay => {
const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value);
return maybeSuppressResult(c, scope, result_used, sub_expr_node);
},
.ArrayToPointerDecay => {
if (exprIsNarrowStringLiteral(sub_expr)) {
const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value);
return maybeSuppressResult(c, scope, result_used, sub_expr_node);
}
const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);
return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
const addr = try Node.address_of.create(c.arena, try transExpr(c, scope, sub_expr, .used, .r_value));
return maybeSuppressResult(c, scope, result_used, addr);
},
.NullToPointer => {
return try transCreateNodeNullLiteral(rp.c);
return Node.null_literal.init();
},
.PointerToBoolean => {
// @ptrToInt(val) != 0
const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1);
ptr_to_int.params()[0] = try transExpr(rp, scope, sub_expr, .used, .r_value);
ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");
const ptr_to_int = try Node.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used, .r_value));
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false);
const ne = try Node.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Node.zero_literal.init() });
return maybeSuppressResult(c, scope, result_used, ne);
},
.IntegralToBoolean => {
const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value);
// The expression is already a boolean one, return it as-is
if (isBoolRes(sub_expr_node))
return sub_expr_node;
return maybeSuppressResult(c, scope, result_used, sub_expr_node);
// val != 0
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, sub_expr_node, .BangEqual, op_token, rhs_node, result_used, false);
const ne = try Node.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Node.zero_literal.init() });
return maybeSuppressResult(c, scope, result_used, ne);
},
.BuiltinFnToFnPtr => {
return transExpr(rp, scope, sub_expr, .used, .r_value);
return transExpr(rp, scope, sub_expr, result_used, .r_value);
},
else => |kind| return revertAndWarn(
rp,
@ -1468,12 +1461,12 @@ fn transBoolExpr(
if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) {
return revertAndWarn(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
}
return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[is_zero] };
return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)] };
}
var res = try transExpr(c, scope, expr, used, lrvalue);
if (isBoolRes(res)) {
return res;
return maybeSuppressResult(c, scope, used, res);
}
const ty = getExprQualType(c, expr).getTypePtr();
@ -1563,18 +1556,18 @@ fn finishBoolExpr(
.Float16,
=> {
// node != 0
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init()});
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init() });
},
.NullPtr => {
// node == null
return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init()});
return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init() });
},
else => {},
}
},
.Pointer => {
// node == null
return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init()});
return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init() });
},
.Typedef => {
const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
@ -1584,7 +1577,7 @@ fn finishBoolExpr(
},
.Enum => {
// node != 0
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init()});
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init() });
const op_token = try appendToken(c, .BangEqual, "!=");
},
.Elaborated => {
@ -1653,11 +1646,11 @@ fn transReturnStmt(
}
fn transStringLiteral(
rp: RestorePoint,
c: *Context,
scope: *Scope,
stmt: *const clang.StringLiteral,
result_used: ResultUsed,
) TransError!*ast.Node {
) TransError!Node {
const kind = stmt.getKind();
switch (kind) {
.Ascii, .UTF8 => {
@ -1665,55 +1658,28 @@ fn transStringLiteral(
const bytes_ptr = stmt.getString_bytes_begin_size(&len);
const str = bytes_ptr[0..len];
const token = try appendTokenFmt(rp.c, .StringLiteral, "\"{}\"", .{std.zig.fmtEscapes(str)});
const node = try rp.c.arena.create(ast.Node.OneToken);
node.* = .{
.base = .{ .tag = .StringLiteral },
.token = token,
};
return maybeSuppressResult(rp, scope, result_used, &node.base);
const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(str)});
const node = try Node.string_literal.create(c.arena, str);
return maybeSuppressResult(c, scope, result_used, node);
},
.UTF16, .UTF32, .Wide => {
const node = try transWideStringLiteral(rp, scope, stmt);
return maybeSuppressResult(rp, scope, result_used, node);
const str_type = @tagName(stmt.getKind());
const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() });
const lit_array = try transStringLiteralAsArray(c, scope, stmt, stmt.getLength() + 1);
const decl = try Node.var_simple.create(c.arena, .{ .name = name, .init = lit_array });
try scope.appendNode(name, decl);
const node = try Node.identifier.create(c.arena, name);
return maybeSuppressResult(c, scope, result_used, node);
},
}
}
/// Translates a wide string literal as a global "anonymous" array of the relevant-sized
/// integer type + null terminator, and returns an identifier node for it
fn transWideStringLiteral(rp: RestorePoint, scope: *Scope, stmt: *const clang.StringLiteral) TransError!*ast.Node {
const str_type = @tagName(stmt.getKind());
const mangle = rp.c.getMangle();
const name = try std.fmt.allocPrint(rp.c.arena, "zig.{s}_string_{d}", .{ str_type, mangle });
const const_tok = try appendToken(rp.c, .Keyword_const, "const");
const name_tok = try appendIdentifier(rp.c, name);
const eq_tok = try appendToken(rp.c, .Equal, "=");
var semi_tok: ast.TokenIndex = undefined;
const lit_array = try transStringLiteralAsArray(rp, scope, stmt, stmt.getLength() + 1);
semi_tok = try appendToken(rp.c, .Semicolon, ";");
const var_decl_node = try ast.Node.VarDecl.create(rp.c.arena, .{
.name_token = name_tok,
.mut_token = const_tok,
.semicolon_token = semi_tok,
}, .{
.visib_token = null,
.eq_token = eq_tok,
.init_node = lit_array,
});
try addTopLevelDecl(rp.c, name, &var_decl_node.base);
return transCreateNodeIdentifier(rp.c, name);
}
/// Parse the size of an array back out from an ast Node.
fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {
if (node.castTag(.ArrayType)) |array| {
if (array.len_expr.castTag(.IntegerLiteral)) |int_lit| {
const tok = tokenSlice(c, int_lit.token);
return std.fmt.parseUnsigned(usize, tok, 10) catch error.UnsupportedTranslation;
fn zigArraySize(c: *Context, node: Node) TransError!usize {
if (node.castTag(.array_type)) |array| {
if (array.data.len.castTag(.int_literal)) |int_lit| {
return std.fmt.parseUnsigned(usize, int_lit.data, 10) catch error.UnsupportedTranslation;
}
}
return error.UnsupportedTranslation;
@ -1725,11 +1691,11 @@ fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {
/// than the array, truncate the string. If the array is larger than the
/// string literal, pad the array with 0's
fn transStringLiteralAsArray(
rp: RestorePoint,
c: *Context,
scope: *Scope,
stmt: *const clang.StringLiteral,
array_size: usize,
) TransError!*ast.Node {
) TransError!Node {
if (array_size == 0) return error.UnsupportedType;
const str_length = stmt.getLength();
@ -1738,40 +1704,21 @@ fn transStringLiteralAsArray(
const ty = expr_base.getType().getTypePtr();
const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
const ty_node = try rp.c.arena.create(ast.Node.ArrayType);
const op_token = try appendToken(rp.c, .LBracket, "[");
const len_expr = try transCreateNodeInt(rp.c, array_size);
_ = try appendToken(rp.c, .RBracket, "]");
ty_node.* = .{
.op_token = op_token,
.rhs = try transQualType(rp, const_arr_ty.getElementType(), expr_base.getBeginLoc()),
.len_expr = len_expr,
};
_ = try appendToken(rp.c, .LBrace, "{");
var init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, array_size);
init_node.* = .{
.lhs = &ty_node.base,
.rtoken = undefined,
.list_len = array_size,
};
const init_list = init_node.list();
const arr_type = try transQualType(c, const_arr_ty.getElementType(), expr_base.getBeginLoc());
const init_list = try c.arena.alloc(Node, array_size);
var i: c_uint = 0;
const kind = stmt.getKind();
const narrow = kind == .Ascii or kind == .UTF8;
while (i < str_length and i < array_size) : (i += 1) {
const code_unit = stmt.getCodeUnit(i);
init_list[i] = try transCreateCharLitNode(rp.c, narrow, code_unit);
_ = try appendToken(rp.c, .Comma, ",");
init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);
}
while (i < array_size) : (i += 1) {
init_list[i] = try transCreateNodeInt(rp.c, 0);
_ = try appendToken(rp.c, .Comma, ",");
init_list[i] = try transCreateNodeInt(c, 0);
}
init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
return &init_node.base;
return Node.array_init.create(c.arena, init_list);
}
fn cIsEnum(qt: clang.QualType) bool {
@ -1790,152 +1737,87 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
}
fn transCCast(
rp: RestorePoint,
c: *Context,
scope: *Scope,
loc: clang.SourceLocation,
dst_type: clang.QualType,
src_type: clang.QualType,
expr: *ast.Node,
) !*ast.Node {
expr: Node,
) !Node {
if (qualTypeCanon(dst_type).isVoidType()) return expr;
if (dst_type.eq(src_type)) return expr;
if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
return transCPtrCast(rp, loc, dst_type, src_type, expr);
return transCPtrCast(c, loc, dst_type, src_type, expr);
const dst_node = try transQualType(c, dst_type, loc);
if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
// 1. If src_type is an enum, determine the underlying signed int type
// 2. Extend or truncate without changing signed-ness.
// 3. Bit-cast to correct signed-ness
const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type);
const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type);
var src_int_expr = if (cIsInteger(src_type)) expr else try transEnumToInt(rp.c, expr);
// @bitCast(dest_type, intermediate_value)
const cast_node = try rp.c.createBuiltinCall("@bitCast", 2);
cast_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
var src_int_expr = if (cIsInteger(src_type)) expr else Node.enum_to_int.create(c.arena, expr);
if (isBoolRes(src_int_expr)) {
const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);
bool_to_int_node.params()[0] = src_int_expr;
bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")");
src_int_expr = &bool_to_int_node.base;
src_int_expr = try Node.bool_to_int.create(c.arena, src_int_expr);
}
switch (cIntTypeCmp(dst_type, src_int_type)) {
.lt => {
// @truncate(SameSignSmallerInt, src_int_expr)
const trunc_node = try rp.c.createBuiltinCall("@truncate", 2);
const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, src_type_is_signed);
trunc_node.params()[0] = ty_node;
_ = try appendToken(rp.c, .Comma, ",");
trunc_node.params()[1] = src_int_expr;
trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
cast_node.params()[1] = &trunc_node.base;
const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
src_int_expr = try Node.truncate.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr });
},
.gt => {
// @as(SameSignBiggerInt, src_int_expr)
const as_node = try rp.c.createBuiltinCall("@as", 2);
const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, src_type_is_signed);
as_node.params()[0] = ty_node;
_ = try appendToken(rp.c, .Comma, ",");
as_node.params()[1] = src_int_expr;
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
cast_node.params()[1] = &as_node.base;
const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
src_int_expr = try Node.as.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr });
},
.eq => {
cast_node.params()[1] = src_int_expr;
// src_int_expr = src_int_expr
},
}
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &cast_node.base;
// @bitCast(dest_type, intermediate_value)
return Node.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });
}
if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
// @intCast(dest_type, @ptrToInt(val))
const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
cast_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
const builtin_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
builtin_node.params()[0] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
cast_node.params()[1] = &builtin_node.base;
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &cast_node.base;
const ptr_to_int = try Node.ptr_to_int.create(c.arena, expr);
return Node.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
}
if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
// @intToPtr(dest_type, val)
const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2);
builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
builtin_node.params()[1] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &builtin_node.base;
return Node.int_to_ptr.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (cIsFloating(src_type) and cIsFloating(dst_type)) {
const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2);
builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
builtin_node.params()[1] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &builtin_node.base;
// @floatCast(dest_type, val)
return Node.float_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (cIsFloating(src_type) and !cIsFloating(dst_type)) {
const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2);
builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
builtin_node.params()[1] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &builtin_node.base;
// @floatToInt(dest_type, val)
return Node.float_to_int.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (!cIsFloating(src_type) and cIsFloating(dst_type)) {
const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2);
builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
builtin_node.params()[1] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &builtin_node.base;
// @intToFloat(dest_type, val)
return Node.int_to_float.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {
// @boolToInt returns either a comptime_int or a u1
// TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast
// instead of @as
const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
builtin_node.params()[0] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
const as_node = try rp.c.createBuiltinCall("@as", 2);
as_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
as_node.params()[1] = &builtin_node.base;
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &as_node.base;
const bool_to_int = Node.bool_to_int.create(c.arena, expr);
return Node.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
}
if (cIsEnum(dst_type)) {
const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);
builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
builtin_node.params()[1] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &builtin_node.base;
// @intToEnum(dest_type, val)
return Node.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (cIsEnum(src_type) and !cIsEnum(dst_type)) {
return transEnumToInt(rp.c, expr);
// @enumToInt(val)
return Node.enum_to_int.create(c.arena, expr);
}
const cast_node = try rp.c.createBuiltinCall("@as", 2);
cast_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
cast_node.params()[1] = expr;
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &cast_node.base;
}
fn transEnumToInt(c: *Context, enum_expr: *ast.Node) TypeError!*ast.Node {
const builtin_node = try c.createBuiltinCall("@enumToInt", 1);
builtin_node.params()[0] = enum_expr;
builtin_node.rparen_token = try appendToken(c, .RParen, ")");
return &builtin_node.base;
// @as(dest_type, val)
return Node.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
fn transExpr(
@ -1976,13 +1858,12 @@ fn transExprCoercing(
}
fn transInitListExprRecord(
rp: RestorePoint,
c: *Context,
scope: *Scope,
loc: clang.SourceLocation,
expr: *const clang.InitListExpr,
ty: *const clang.Type,
used: ResultUsed,
) TransError!*ast.Node {
) TransError!Node {
var is_union_type = false;
// Unions and Structs are both represented as RecordDecl
const record_ty = ty.getAsRecordType() orelse
@ -1994,13 +1875,11 @@ fn transInitListExprRecord(
const record_def = record_decl.getDefinition() orelse
unreachable;
const ty_node = try transType(rp, ty, loc);
const ty_node = try transType(c, ty, loc);
const init_count = expr.getNumInits();
var field_inits = std.ArrayList(*ast.Node).init(rp.c.gpa);
var field_inits = std.ArrayList(ast.Payload.ContainerInit.Initializer).init(c.gpa);
defer field_inits.deinit();
_ = try appendToken(rp.c, .LBrace, "{");
var init_i: c_uint = 0;
var it = record_def.field_begin();
const end_it = record_def.field_end();
@ -2018,76 +1897,28 @@ fn transInitListExprRecord(
// Generate the field assignment expression:
// .field_name = expr
const period_tok = try appendToken(rp.c, .Period, ".");
var raw_name = try rp.c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
var raw_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
if (field_decl.isAnonymousStructOrUnion()) {
const name = rp.c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
raw_name = try mem.dupe(rp.c.arena, u8, name);
const name = c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
raw_name = try mem.dupe(c.arena, u8, name);
}
const field_name_tok = try appendIdentifier(rp.c, raw_name);
_ = try appendToken(rp.c, .Equal, "=");
const field_init_node = try rp.c.arena.create(ast.Node.FieldInitializer);
field_init_node.* = .{
.period_token = period_tok,
.name_token = field_name_tok,
.expr = try transExpr(rp, scope, elem_expr, .used, .r_value),
};
try field_inits.append(&field_init_node.base);
_ = try appendToken(rp.c, .Comma, ",");
try field_inits.append(.{
.name = raw_name,
.value = try transExpr(c, scope, elem_expr, .used, .r_value),
});
}
const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len);
node.* = .{
.lhs = ty_node,
.rtoken = try appendToken(rp.c, .RBrace, "}"),
.list_len = field_inits.items.len,
};
mem.copy(*ast.Node, node.list(), field_inits.items);
return &node.base;
}
fn transCreateNodeArrayType(
rp: RestorePoint,
source_loc: clang.SourceLocation,
ty: *const clang.Type,
len: anytype,
) !*ast.Node {
const node = try rp.c.arena.create(ast.Node.ArrayType);
const op_token = try appendToken(rp.c, .LBracket, "[");
const len_expr = try transCreateNodeInt(rp.c, len);
_ = try appendToken(rp.c, .RBracket, "]");
node.* = .{
.op_token = op_token,
.rhs = try transType(rp, ty, source_loc),
.len_expr = len_expr,
};
return &node.base;
}
fn transCreateEmptyArray(rp: RestorePoint, loc: clang.SourceLocation, ty: *const clang.Type) TransError!*ast.Node {
const ty_node = try transCreateNodeArrayType(rp, loc, ty, 0);
_ = try appendToken(rp.c, .LBrace, "{");
const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 0);
filler_init_node.* = .{
.lhs = ty_node,
.rtoken = try appendToken(rp.c, .RBrace, "}"),
.list_len = 0,
};
return &filler_init_node.base;
return Node.container_init.create(c.arena, try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items));
}
fn transInitListExprArray(
rp: RestorePoint,
c: *Context,
scope: *Scope,
loc: clang.SourceLocation,
expr: *const clang.InitListExpr,
ty: *const clang.Type,
used: ResultUsed,
) TransError!*ast.Node {
) TransError!Node {
const arr_type = ty.getAsArrayTypeUnsafe();
const child_qt = arr_type.getElementType();
const init_count = expr.getNumInits();
@ -2098,111 +1929,67 @@ fn transInitListExprArray(
const leftover_count = all_count - init_count;
if (all_count == 0) {
return transCreateEmptyArray(rp, loc, child_qt.getTypePtr());
return Node.empty_array.create(c.arena, try transQualType(c, child_qt, source_loc));
}
const ty_node = try transType(ty);
const init_node = if (init_count != 0) blk: {
const init_list = try c.arena.alloc(Node, init_count);
var init_node: *ast.Node.ArrayInitializer = undefined;
var cat_tok: ast.TokenIndex = undefined;
if (init_count != 0) {
const ty_node = try transCreateNodeArrayType(
rp,
loc,
child_qt.getTypePtr(),
init_count,
);
_ = try appendToken(rp.c, .LBrace, "{");
init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, init_count);
init_node.* = .{
.lhs = ty_node,
.rtoken = undefined,
.list_len = init_count,
};
const init_list = init_node.list();
var i: c_uint = 0;
while (i < init_count) : (i += 1) {
for (init_list) |*init, i| {
const elem_expr = expr.getInit(i);
init_list[i] = try transExpr(rp, scope, elem_expr, .used, .r_value);
_ = try appendToken(rp.c, .Comma, ",");
init.* = try transExpr(c, scope, elem_expr, .used, .r_value);
}
init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
const init_node = try Node.array_init.create(c.arena, init_list);
if (leftover_count == 0) {
return &init_node.base;
return init_node;
}
cat_tok = try appendToken(rp.c, .PlusPlus, "++");
}
break :blk init_node;
} else null;
const ty_node = try transCreateNodeArrayType(rp, loc, child_qt.getTypePtr(), 1);
_ = try appendToken(rp.c, .LBrace, "{");
const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 1);
filler_init_node.* = .{
.lhs = ty_node,
.rtoken = undefined,
.list_len = 1,
};
const filler_val_expr = expr.getArrayFiller();
filler_init_node.list()[0] = try transExpr(rp, scope, filler_val_expr, .used, .r_value);
filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
const filler_node = try Node.array_filler.create(c.arena, .{
.type = ty_node,
.filler = try transExpr(c, scope, filler_val_expr, .used, .r_value),
.count = leftover_count,
});
const rhs_node = if (leftover_count == 1)
&filler_init_node.base
else blk: {
const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");
const mul_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
mul_node.* = .{
.base = .{ .tag = .ArrayMult },
.op_token = mul_tok,
.lhs = &filler_init_node.base,
.rhs = try transCreateNodeInt(rp.c, leftover_count),
};
break :blk &mul_node.base;
};
if (init_count == 0) {
return rhs_node;
if (init_node) |some| {
return Node.array_cat.create(c.arena, some, filler_node);
} else {
return filler_node;
}
const cat_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
cat_node.* = .{
.base = .{ .tag = .ArrayCat },
.op_token = cat_tok,
.lhs = &init_node.base,
.rhs = rhs_node,
};
return &cat_node.base;
}
fn transInitListExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
expr: *const clang.InitListExpr,
used: ResultUsed,
) TransError!*ast.Node {
const qt = getExprQualType(rp.c, @ptrCast(*const clang.Expr, expr));
) TransError!Node {
const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
var qual_type = qt.getTypePtr();
const source_loc = @ptrCast(*const clang.Expr, expr).getBeginLoc();
if (qual_type.isRecordType()) {
return transInitListExprRecord(
return maybeSuppressResult(c, scope, used, try transInitListExprRecord(
rp,
scope,
source_loc,
expr,
qual_type,
used,
);
));
} else if (qual_type.isArrayType()) {
return transInitListExprArray(
return maybeSuppressResult(c, scope, used, try transInitListExprArray(
rp,
scope,
source_loc,
expr,
qual_type,
used,
);
));
} else {
const type_name = rp.c.str(qual_type.getTypeClassName());
return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
const type_name = c.str(qual_type.getTypeClassName());
return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
}
}
@ -2259,15 +2046,15 @@ fn transZeroInitExpr(
}
fn transImplicitValueInitExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
expr: *const clang.Expr,
used: ResultUsed,
) TransError!*ast.Node {
) TransError!Node {
const source_loc = expr.getBeginLoc();
const qt = getExprQualType(rp.c, expr);
const qt = getExprQualType(c, expr);
const ty = qt.getTypePtr();
return transZeroInitExpr(rp, scope, source_loc, ty);
return transZeroInitExpr(c, scope, source_loc, ty);
}
fn transIfStmt(

View File

@ -104,6 +104,7 @@ pub const Node = extern union {
bit_and,
bit_or,
bit_xor,
array_cat,
log2_int_type,
/// @import("std").math.Log2Int(operand)
@ -118,6 +119,24 @@ pub const Node = extern union {
bool_to_int,
/// @as(lhs, rhs)
as,
/// @truncate(lhs, rhs)
truncate,
/// @bitCast(lhs, rhs)
bit_cast,
/// @floatCast(lhs, rhs)
float_cast,
/// @floatToInt(lhs, rhs)
float_to_int,
/// @intToFloat(lhs, rhs)
int_to_float,
/// @intToEnum(lhs, rhs)
int_to_enum,
/// @enumToInt(operand)
enum_to_int,
/// @intToPtr(lhs, rhs)
int_to_ptr,
/// @ptrToInt(operand)
ptr_to_int,
negate,
negate_wrap,
@ -154,6 +173,11 @@ pub const Node = extern union {
/// pub const enum_field_name = @enumToInt(enum_name.field_name);
enum_redecl,
/// [0]type{}
empty_array,
/// [1]type{val} ** count
array_filler,
pub const last_no_payload_tag = Tag.usingnamespace_builtins;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@ -184,6 +208,9 @@ pub const Node = extern union {
.optional_type,
.address_of,
.unwrap_deref,
.ptr_to_int,
.enum_to_int,
.empty_array,
=> Payload.UnOp,
.add,
@ -239,6 +266,14 @@ pub const Node = extern union {
.int_cast,
.bool_to_int,
.as,
.truncate,
.bit_cast,
.float_cast,
.float_to_int,
.int_to_float,
.int_to_enum,
.int_to_ptr,
.array_cat,
=> Payload.BinOp,
.int,
@ -274,6 +309,7 @@ pub const Node = extern union {
.log2_int_type => Payload.Log2IntType,
.typedef, .pub_typedef, .pub_var_simple => Payload.SimpleVarDecl,
.enum_redecl => Payload.EnumRedecl,
.array_filler => Payload.ArrayFiller,
};
}
@ -533,6 +569,15 @@ pub const Payload = struct {
enum_name: []const u8,
},
};
pub const ArrayFiller = struct {
base: Node,
data: struct {
type: Node,
filler: Node,
count: usize,
},
};
};
/// Converts the nodes into a Zig ast.