translate-c: more binaryoperator chagnes, blocks and unary type expressions

This commit is contained in:
Veikka Tuominen 2021-02-07 22:02:42 +02:00
parent 4c0c9b0755
commit f5041caa2e
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 156 additions and 197 deletions

View File

@ -68,16 +68,15 @@ const Scope = struct {
}
};
/// Represents an in-progress ast.Node.Block. This struct is stack-allocated.
/// When it is deinitialized, it produces an ast.Node.Block which is allocated
/// Represents an in-progress Node.Block. This struct is stack-allocated.
/// When it is deinitialized, it produces an Node.Block which is allocated
/// into the main arena.
const Block = struct {
base: Scope,
statements: std.ArrayList(*ast.Node),
statements: std.ArrayList(Node),
variables: AliasList,
label: ?ast.TokenIndex,
mangle_count: u32 = 0,
lbrace: ast.TokenIndex,
label: ?[]const u8 = null,
/// When the block corresponds to a function, keep track of the return type
/// so that the return expression can be cast, if necessary
@ -89,14 +88,11 @@ const Scope = struct {
.id = .Block,
.parent = parent,
},
.statements = std.ArrayList(*ast.Node).init(c.gpa),
.statements = std.ArrayList(Node).init(c.gpa),
.variables = AliasList.init(c.gpa),
.label = null,
.lbrace = try appendToken(c, .LBrace, "{"),
};
if (labeled) {
blk.label = try appendIdentifier(c, try blk.makeMangledName(c, "blk"));
_ = try appendToken(c, .Colon, ":");
blk.label = try blk.makeMangledName(c, "blk");
}
return blk;
}
@ -107,31 +103,16 @@ const Scope = struct {
self.* = undefined;
}
fn complete(self: *Block, c: *Context) !*ast.Node {
fn complete(self: *Block, c: *Context) !Node {
// We reserve 1 extra statement if the parent is a Loop. This is in case of
// do while, we want to put `if (cond) break;` at the end.
const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
const rbrace = try appendToken(c, .RBrace, "}");
if (self.label) |label| {
const node = try ast.Node.LabeledBlock.alloc(c.arena, alloc_len);
node.* = .{
.statements_len = self.statements.items.len,
.lbrace = self.lbrace,
.rbrace = rbrace,
.label = label,
};
mem.copy(*ast.Node, node.statements(), self.statements.items);
return &node.base;
} else {
const node = try ast.Node.Block.alloc(c.arena, alloc_len);
node.* = .{
.statements_len = self.statements.items.len,
.lbrace = self.lbrace,
.rbrace = rbrace,
};
mem.copy(*ast.Node, node.statements(), self.statements.items);
return &node.base;
}
const stmts = try c.arena.alloc(Node, alloc_len);
mem.copy(Node, stmts, self.statements.items);
return Node.block.create(c.arena, .{
.lable = self.label,
.stmts = stmts,
});
}
/// Given the desired name, return a name that does not shadow anything from outer scopes.
@ -1390,7 +1371,7 @@ fn transBinaryOperator(
// signed integer division uses @divTrunc
const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs});
const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
return maybeSuppressResult(c, scope, result_used, div_trunc);
}
},
@ -1399,7 +1380,7 @@ fn transBinaryOperator(
// signed integer division uses @rem
const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs});
const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
return maybeSuppressResult(c, scope, result_used, rem);
}
},
@ -1411,6 +1392,12 @@ fn transBinaryOperator(
const node = try transCreateNodeShiftOp(c, scope, stmt, .shr);
return maybeSuppressResult(c, scope, result_used, node);
},
.LAnd => {
return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_and, result_used, true);
},
.LOr => {
return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_or, result_used, true);
},
else => {},
}
var op_id: Node.Tag = undefined;
@ -1471,17 +1458,19 @@ fn transBinaryOperator(
.Or => {
op_id = .bit_or;
},
.LAnd => {
op_id = .@"and";
},
.LOr => {
op_id = .@"or";
},
else => unreachable,
}
const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
const lhs_uncasted = try transExpr(c, scope, stmt.getLHS(), .used, .l_value);
const rhs_uncasted = try transExpr(c, scope, stmt.getRHS(), .used, .r_value);
const lhs = if (isBoolRes(lhs_uncasted))
try Node.bool_to_int.create(c.arena, lhs_uncasted)
else lhs_uncasted;
const rhs = if (isBoolRes(rhs_uncasted))
try Node.bool_to_int.create(c.arena, rhs_uncasted)
else rhs_uncasted;
const payload = try c.arena.create(ast.Payload.BinOp);
payload.* = .{
@ -1495,7 +1484,7 @@ fn transBinaryOperator(
}
fn transCompoundStmtInline(
rp: RestorePoint,
c: *Context,
parent_scope: *Scope,
stmt: *const clang.CompoundStmt,
block: *Scope.Block,
@ -1503,16 +1492,16 @@ fn transCompoundStmtInline(
var it = stmt.body_begin();
const end_it = stmt.body_end();
while (it != end_it) : (it += 1) {
const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);
const result = try transStmt(c, parent_scope, it[0], .unused, .r_value);
try block.statements.append(result);
}
}
fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!*ast.Node {
var block_scope = try Scope.Block.init(rp.c, scope, false);
fn transCompoundStmt(c: *Context, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!Node {
var block_scope = try Scope.Block.init(c, scope, false);
defer block_scope.deinit();
try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
return try block_scope.complete(rp.c);
try transCompoundStmtInline(c, &block_scope.base, stmt, &block_scope);
return try block_scope.complete(c);
}
fn transCStyleCastExprClass(
@ -3233,22 +3222,18 @@ fn qualTypeGetFnProto(qt: clang.QualType, is_ptr: *bool) ?ClangFunctionType {
}
fn transUnaryExprOrTypeTraitExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
stmt: *const clang.UnaryExprOrTypeTraitExpr,
result_used: ResultUsed,
) TransError!*ast.Node {
) TransError!Node {
const loc = stmt.getBeginLoc();
const type_node = try transQualType(
rp,
stmt.getTypeOfArgument(),
loc,
);
const type_node = try transQualType(rp, stmt.getTypeOfArgument(), loc);
const kind = stmt.getKind();
const kind_str = switch (kind) {
.SizeOf => "@sizeOf",
.AlignOf => "@alignOf",
switch (kind) {
.SizeOf => return Node.sizeof.create(c.arena, type_node),
.AlignOf => return Node.alignof.create(c.arena, type_node),
.PreferredAlignOf,
.VecStep,
.OpenMPRequiredSimdAlign,
@ -3259,12 +3244,7 @@ fn transUnaryExprOrTypeTraitExpr(
"Unsupported type trait kind {}",
.{kind},
),
};
const builtin_node = try rp.c.createBuiltinCall(kind_str, 1);
builtin_node.params()[0] = type_node;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
}
}
fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
@ -3967,8 +3947,8 @@ fn transQualTypeInitialized(
return transQualType(rp, qt, source_loc);
}
fn transQualType(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!*ast.Node {
return transType(rp, qt.getTypePtr(), source_loc);
fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {
return transType(c, qt.getTypePtr(), source_loc);
}
/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
@ -4318,19 +4298,27 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c
return &field_access_node.base;
}
fn transCreateNodeSimplePrefixOp(
fn transCreateNodeBoolInfixOp(
c: *Context,
comptime tag: ast.Node.Tag,
op_tok_id: std.zig.Token.Id,
bytes: []const u8,
) !*ast.Node.SimplePrefixOp {
const node = try c.arena.create(ast.Node.SimplePrefixOp);
node.* = .{
.base = .{ .tag = tag },
.op_token = try appendToken(c, op_tok_id, bytes),
.rhs = undefined, // translate and set afterward
scope: *Scope,
stmt: *const clang.BinaryOperator,
op: ast.Node.Tag,
used: ResultUsed,
) !Node {
std.debug.assert(op == .bool_and or op == .bool_or);
const lhs = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value, true);
const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value, true);
const payload = try c.arena.create(ast.Payload.BinOp);
payload.* = .{
.base = .{ .tag = op },
.data = .{
.lhs = lhs,
.rhs = rhs,
},
};
return node;
return maybeSuppressResult(c, scope, used, &payload.base);
}
fn transCreateNodePtrType(
@ -4784,30 +4772,30 @@ fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAcces
return node;
}
fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Type {
fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {
switch (ty.getTypeClass()) {
.Builtin => {
const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
return Type.initTag(switch (builtin_ty.getKind()) {
.Void => .c_void,
.Bool => .bool,
.Char_U, .UChar, .Char_S, .Char8 => .u8,
.SChar => .i8,
.UShort => .c_ushort,
.UInt => .c_uint,
.ULong => .c_ulong,
.ULongLong => .c_ulonglong,
.Short => .c_short,
.Int => .c_int,
.Long => .c_long,
.LongLong => .c_longlong,
.UInt128 => .u128,
.Int128 => .i128,
.Float => .f32,
.Double => .f64,
.Float128 => .f128,
.Float16 => .f16,
.LongDouble => .c_longdouble,
return Node.type.create(c.arena, switch (builtin_ty.getKind()) {
.Void => "c_void",
.Bool => "bool",
.Char_U, .UChar, .Char_S, .Char8 => "u8",
.SChar => "i8",
.UShort => "c_ushort",
.UInt => "c_uint",
.ULong => "c_ulong",
.ULongLong => "c_ulonglong",
.Short => "c_short",
.Int => "c_int",
.Long => "c_long",
.LongLong => "c_longlong",
.UInt128 => "u128",
.Int128 => "i128",
.Float => "f32",
.Double => "f64",
.Float128 => "f128",
.Float16 => "f16",
.LongDouble => "c_longdouble",
else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
});
},
@ -4826,61 +4814,25 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
.Pointer => {
const child_qt = ty.getPointeeType();
if (qualTypeChildIsFnProto(child_qt)) {
return Type.optional_single_mut_pointer.create(c.arena, try transQualType(c, child_qt, source_loc));
return Node.optional_type.create(c.arena, try transQualType(c, child_qt, source_loc));
}
const is_const = child_qt.isConstQualified();
const is_volatile = child_qt.isVolatileQualified();
const elem_type = try transQualType(c, child_qt, source_loc);
if (elem_type.zigTypeTag() == .Opaque) {
if (!is_volatile) {
if (is_const) {
return Type.optional_single_const_pointer.create(c.arena, elem_type);
} else {
return Type.optional_single_mut_pointer.create(c.arena, elem_type);
}
}
return Type.pointer.create(c.arena, .{
.pointee_type = elem_type,
.sentinel = null,
.@"align" = 0,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = !is_const,
.@"volatile" = true,
.size = .Single,
});
if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) {
return Node.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
}
if (!is_volatile) {
if (is_const) {
return Type.c_const_pointer.create(c.arena, elem_type);
} else {
return Type.c_mut_pointer.create(c.arena, elem_type);
}
}
return Type.pointer.create(c.arena, .{
.pointee_type = elem_type,
.sentinel = null,
.@"align" = 0,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = !is_const,
.@"volatile" = true,
.size = .C,
});
return Node.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
},
.ConstantArray => {
const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
const size_ap_int = const_arr_ty.getSize();
const size = size_ap_int.getLimitedValue(math.maxInt(usize));
const elem_type = try transType1(c, const_arr_ty.getElementType().getTypePtr(), source_loc);
return Type.array.create(c.arena, .{ .len = size, .elem_type = elem_type });
const elem_type = try transType(c, const_arr_ty.getElementType().getTypePtr(), source_loc);
return Node.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type });
},
.IncompleteArray => {
const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
@ -4890,25 +4842,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
const is_volatile = child_qt.isVolatileQualified();
const elem_type = try transQualType(c, child_qt, source_loc);
if (!is_volatile) {
if (is_const) {
return Type.c_const_pointer.create(c.arena, elem_type);
} else {
return Type.c_mut_pointer.create(c.arena, elem_type);
}
}
return Type.pointer.create(c.arena, .{
.pointee_type = elem_type,
.sentinel = null,
.@"align" = 0,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = !is_const,
.@"volatile" = true,
.size = .C,
});
return Node.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
},
.Typedef => {
const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
@ -5233,25 +5167,14 @@ fn finishTransFnProto(
return fn_proto;
}
fn revertAndWarn(
rp: RestorePoint,
err: anytype,
source_loc: clang.SourceLocation,
comptime format: []const u8,
args: anytype,
) (@TypeOf(err) || error{OutOfMemory}) {
rp.activate();
try emitWarning(rp.c, source_loc, format, args);
return err;
}
fn emitWarning(c: *Context, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void {
fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void {
const args_prefix = .{c.locStr(loc)};
_ = try appendTokenFmt(c, .LineComment, "// {s}: warning: " ++ format, args_prefix ++ args);
const value = std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, args_prefix ++ args);
try scope.appendNode(c.gpa, try Node.warning.create(c.arena, value));
}
fn fail(
rp: RestorePoint,
c: *Context,
err: anytype,
source_loc: clang.SourceLocation,
comptime format: []const u8,

View File

@ -107,6 +107,25 @@ pub const Node = extern union {
rem,
/// @divTrunc(lhs, rhs)
div_trunc,
/// @boolToInt(lhs, rhs)
bool_to_int,
negate,
negate_wrap,
bit_not,
not,
block,
@"break",
sizeof,
alignof,
type,
optional_type,
c_pointer,
single_pointer,
array_type,
pub const last_no_payload_tag = Tag.false_literal;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@ -127,6 +146,14 @@ pub const Node = extern union {
.@"return",
.discard,
.std_math_Log2Int,
.negate,
.negate_wrap,
.bit_not,
.not,
.optional_type,
.c_pointer,
.single_pointer,
.array_type,
=> Payload.UnOp,
.add,
@ -180,6 +207,7 @@ pub const Node = extern union {
.div_trunc,
.rem,
.int_cast,
.bool_to_int,
=> Payload.BinOp,
.int,
@ -191,6 +219,9 @@ pub const Node = extern union {
.field_access_arrow,
.warning,
.failed_decl,
.sizeof,
.alignof,
.type,
=> Payload.Value,
.@"if" => Payload.If,
.@"while" => Payload.While,
@ -234,8 +265,8 @@ pub const Payload = struct {
pub const Infix = struct {
base: Node,
data: struct {
lhs: *Node,
rhs: *Node,
lhs: Node,
rhs: Node,
},
};
@ -246,44 +277,44 @@ pub const Payload = struct {
pub const UnOp = struct {
base: Node,
data: *Node,
data: Node,
};
pub const BinOp = struct {
base: Node,
data: struct {
lhs: *Node,
rhs: *Node,
lhs: Node,
rhs: Node,
},
};
pub const If = struct {
base: Node = .{ .tag = .@"if" },
data: struct {
cond: *Node,
then: *Node,
@"else": ?*Node,
cond: Node,
then: Node,
@"else": ?Node,
},
};
pub const While = struct {
base: Node = .{ .tag = .@"while" },
data: struct {
cond: *Node,
body: *Node,
cond: Node,
body: Node,
},
};
pub const Switch = struct {
base: Node = .{ .tag = .@"switch" },
data: struct {
cond: *Node,
cond: Node,
cases: []Prong,
default: ?[]const u8,
pub const Prong = struct {
lhs: *Node,
rhs: ?*Node,
lhs: Node,
rhs: ?Node,
label: []const u8,
};
},
@ -293,15 +324,15 @@ pub const Payload = struct {
base: Node = .{ .tag = .@"break" },
data: struct {
label: ?[]const u8,
rhs: ?*Node,
rhs: ?Node,
},
};
pub const Call = struct {
base: Node = .{.call},
data: struct {
lhs: *Node,
args: []*Node,
lhs: Node,
args: []Node,
},
};
@ -314,7 +345,7 @@ pub const Payload = struct {
@"export": bool,
name: []const u8,
type: Type,
init: *Node,
init: Node,
},
};
@ -328,7 +359,7 @@ pub const Payload = struct {
cc: std.builtin.CallingConvention,
params: []Param,
return_type: Type,
body: ?*Node,
body: ?Node,
pub const Param = struct {
@"noalias": bool,
@ -368,7 +399,7 @@ pub const Payload = struct {
pub const ArrayInit = struct {
base: Node = .{ .tag = .array_init },
data: []*Node,
data: []Node,
};
pub const ContainerInit = struct {
@ -377,17 +408,22 @@ pub const Payload = struct {
pub const Initializer = struct {
name: []const u8,
value: *Node,
value: Node,
};
};
pub const Block = struct {
base: Node = .{ .tag = .block },
base: Node,
data: struct {
label: ?[]const u8,
stmts: []*Node,
stmts: []Node
},
};
pub const Break = struct {
base: Node = .{ .tag = .@"break" },
data: *Block
};
};
/// Converts the nodes into a Zig ast and then renders it.