translate-c: convert vardecl and typedef

This commit is contained in:
Veikka Tuominen 2021-02-08 11:07:44 +02:00
parent f36849fed2
commit bb867b071a
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 231 additions and 306 deletions

View File

@ -2664,8 +2664,11 @@ fn identifier(
return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
}
if (getSimplePrimitiveValue(ident_name)) |typed_value| {
const result = try addZIRInstConst(mod, scope, src, typed_value);
if (simple_types.get(ident_name)) |val_tag| {
const result = try addZIRInstConst(mod, scope, src, TypedValue{
.ty = Type.initTag(.type),
.val = Value.initTag(val_tag),
});
return rvalue(mod, scope, rl, result);
}
@ -3325,42 +3328,33 @@ fn callExpr(
return rvalue(mod, scope, rl, result);
}
fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
const simple_types = std.ComptimeStringMap(Value.Tag, .{
.{ "u8", .u8_type },
.{ "i8", .i8_type },
.{ "isize", .isize_type },
.{ "usize", .usize_type },
.{ "c_short", .c_short_type },
.{ "c_ushort", .c_ushort_type },
.{ "c_int", .c_int_type },
.{ "c_uint", .c_uint_type },
.{ "c_long", .c_long_type },
.{ "c_ulong", .c_ulong_type },
.{ "c_longlong", .c_longlong_type },
.{ "c_ulonglong", .c_ulonglong_type },
.{ "c_longdouble", .c_longdouble_type },
.{ "f16", .f16_type },
.{ "f32", .f32_type },
.{ "f64", .f64_type },
.{ "f128", .f128_type },
.{ "c_void", .c_void_type },
.{ "bool", .bool_type },
.{ "void", .void_type },
.{ "type", .type_type },
.{ "anyerror", .anyerror_type },
.{ "comptime_int", .comptime_int_type },
.{ "comptime_float", .comptime_float_type },
.{ "noreturn", .noreturn_type },
});
if (simple_types.get(name)) |tag| {
return TypedValue{
.ty = Type.initTag(.type),
.val = Value.initTag(tag),
};
}
return null;
}
pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
.{ "u8", .u8_type },
.{ "i8", .i8_type },
.{ "isize", .isize_type },
.{ "usize", .usize_type },
.{ "c_short", .c_short_type },
.{ "c_ushort", .c_ushort_type },
.{ "c_int", .c_int_type },
.{ "c_uint", .c_uint_type },
.{ "c_long", .c_long_type },
.{ "c_ulong", .c_ulong_type },
.{ "c_longlong", .c_longlong_type },
.{ "c_ulonglong", .c_ulonglong_type },
.{ "c_longdouble", .c_longdouble_type },
.{ "f16", .f16_type },
.{ "f32", .f32_type },
.{ "f64", .f64_type },
.{ "f128", .f128_type },
.{ "c_void", .c_void_type },
.{ "bool", .bool_type },
.{ "void", .void_type },
.{ "type", .type_type },
.{ "anyerror", .anyerror_type },
.{ "comptime_int", .comptime_int_type },
.{ "comptime_float", .comptime_float_type },
.{ "noreturn", .noreturn_type },
});
fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
var node = start_node;

View File

@ -614,25 +614,21 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
return addTopLevelDecl(c, fn_name, &proto_node.base);
}
fn transQualTypeMaybeInitialized(rp: RestorePoint, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!*ast.Node {
fn transQualTypeMaybeInitialized(c: *Context, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!Node {
return if (decl_init) |init_expr|
transQualTypeInitialized(rp, qt, init_expr, loc)
transQualTypeInitialized(c, qt, init_expr, loc)
else
transQualType(rp, qt, loc);
transQualType(c, qt, loc);
}
/// if mangled_name is not null, this var decl was declared in a block scope.
fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void {
const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());
if (c.global_scope.sym_table.contains(var_name))
return; // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub");
const thread_local_token = if (var_decl.getTLSKind() == .None)
null
else
try appendToken(c, .Keyword_threadlocal, "threadlocal");
const is_pub = mangled_name == null;
const is_thread_local = var_decl.getTLSKind() != .None;
const scope = &c.global_scope.base;
// TODO https://github.com/ziglang/zig/issues/3756
@ -651,42 +647,27 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
// does the same as:
// extern int foo;
// int foo = 2;
const extern_tok = if (storage_class == .Extern and !has_init)
try appendToken(c, .Keyword_extern, "extern")
else if (storage_class != .Static)
try appendToken(c, .Keyword_export, "export")
else
null;
const is_extern = storage_class == .Extern and !has_init;
const is_export = !is_extern and storage_class != .Static;
const mut_tok = if (is_const)
try appendToken(c, .Keyword_const, "const")
else
try appendToken(c, .Keyword_var, "var");
const name_tok = try appendIdentifier(c, checked_name);
_ = try appendToken(c, .Colon, ":");
const type_node = transQualTypeMaybeInitialized(rp, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
const type_node = transQualTypeMaybeInitialized(c, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
error.UnsupportedTranslation, error.UnsupportedType => {
return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{});
},
error.OutOfMemory => |e| return e,
};
var eq_tok: ast.TokenIndex = undefined;
var init_node: ?*ast.Node = null;
var init_node: ?Node = null;
// If the initialization expression is not present, initialize with undefined.
// If it is an integer literal, we can skip the @as since it will be redundant
// with the variable type.
if (has_init) {
eq_tok = try appendToken(c, .Equal, "=");
if (decl_init) |expr| {
const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)
transStringLiteralAsArray(rp, &c.global_scope.base, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(rp.c, type_node) catch 0)
transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(c, type_node) catch 0)
else
transExprCoercing(rp, scope, expr, .used, .r_value);
transExprCoercing(c, scope, expr, .used, .r_value);
init_node = node_or_error catch |err| switch (err) {
error.UnsupportedTranslation,
error.UnsupportedType,
@ -695,118 +676,83 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
},
error.OutOfMemory => |e| return e,
};
if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
init_node = try Node.bool_to_int.create(c.arena, init_node);
}
} else {
init_node = try transCreateNodeUndefinedLiteral(c);
init_node = Node.undefined_literal.init();
}
} else if (storage_class != .Extern) {
eq_tok = try appendToken(c, .Equal, "=");
// The C language specification states that variables with static or threadlocal
// storage without an initializer are initialized to a zero value.
// @import("std").mem.zeroes(T)
const import_fn_call = try c.createBuiltinCall("@import", 1);
const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
import_fn_call.params()[0] = std_node;
import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem");
const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes");
const zero_init_call = try c.createCall(outer_field_access, 1);
zero_init_call.params()[0] = type_node;
zero_init_call.rtoken = try appendToken(c, .RParen, ")");
init_node = &zero_init_call.base;
init_node = try Node.std_mem_zeroes.create(c.arena, type_node);
}
const linksection_expr = blk: {
const linksection_string = blk: {
var str_len: usize = undefined;
if (var_decl.getSectionAttribute(&str_len)) |str_ptr| {
_ = try appendToken(rp.c, .Keyword_linksection, "linksection");
_ = try appendToken(rp.c, .LParen, "(");
const expr = try transCreateNodeStringLiteral(
rp.c,
try std.fmt.allocPrint(rp.c.arena, "\"{s}\"", .{str_ptr[0..str_len]}),
);
_ = try appendToken(rp.c, .RParen, ")");
break :blk expr;
break :blk str_ptr[0..str_len];
}
break :blk null;
};
const align_expr = blk: {
const alignment = var_decl.getAlignedAttribute(rp.c.clang_context);
const alignment = blk: {
const alignment = var_decl.getAlignedAttribute(c.clang_context);
if (alignment != 0) {
_ = try appendToken(rp.c, .Keyword_align, "align");
_ = try appendToken(rp.c, .LParen, "(");
// Clang reports the alignment in bits
const expr = try transCreateNodeInt(rp.c, alignment / 8);
_ = try appendToken(rp.c, .RParen, ")");
break :blk expr;
break :blk alignment / 8;
}
break :blk null;
};
const node = try ast.Node.VarDecl.create(c.arena, .{
.name_token = name_tok,
.mut_token = mut_tok,
.semicolon_token = try appendToken(c, .Semicolon, ";"),
}, .{
.visib_token = visib_tok,
.thread_local_token = thread_local_token,
.eq_token = eq_tok,
.extern_export_token = extern_tok,
.type_node = type_node,
.align_node = align_expr,
.section_node = linksection_expr,
.init_node = init_node,
const node = try Node.var_decl.create(c.arena, .{
.is_pub = is_pub,
.is_const = is_const,
.is_extern = is_extern,
.is_export = is_export,
.linksection_string = linksection_string,
.alignment = alignment,
.name = checked_name,
.type = type_node,
.init = init_node,
});
return addTopLevelDecl(c, checked_name, &node.base);
}
fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !*ast.Node {
fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !Node {
_ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name);
return transCreateNodeIdentifier(c, builtin_name);
return Node.identifier.create(c.arena, builtin_name);
}
fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {
const table = [_][2][]const u8{
.{ "uint8_t", "u8" },
.{ "int8_t", "i8" },
.{ "uint16_t", "u16" },
.{ "int16_t", "i16" },
.{ "uint32_t", "u32" },
.{ "int32_t", "i32" },
.{ "uint64_t", "u64" },
.{ "int64_t", "i64" },
.{ "intptr_t", "isize" },
.{ "uintptr_t", "usize" },
.{ "ssize_t", "isize" },
.{ "size_t", "usize" },
};
const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{
.{ "uint8_t", "u8" },
.{ "int8_t", "i8" },
.{ "uint16_t", "u16" },
.{ "int16_t", "i16" },
.{ "uint32_t", "u32" },
.{ "int32_t", "i32" },
.{ "uint64_t", "u64" },
.{ "int64_t", "i64" },
.{ "intptr_t", "isize" },
.{ "uintptr_t", "usize" },
.{ "ssize_t", "isize" },
.{ "size_t", "usize" },
});
for (table) |entry| {
if (mem.eql(u8, checked_name, entry[0])) {
return entry[1];
}
}
return null;
}
fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?*ast.Node {
fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?Node {
if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name|
return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const typedef_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ typedef_name, c.getMangle() }) else typedef_name;
if (checkForBuiltinTypedef(checked_name)) |builtin| {
return transTypeDefAsBuiltin(c, typedef_decl, builtin);
if (builtin_typedef_map.get(checked_name)) |builtin| {
_ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
return Node.identifier.create(c.arena, builtin);
}
if (!top_level_visit) {
@ -814,42 +760,36 @@ fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_lev
}
_ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), checked_name);
const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
const node = (try transCreateNodeTypedef(c, typedef_decl, true, checked_name)) orelse return null;
try addTopLevelDecl(c, checked_name, node);
return transCreateNodeIdentifier(c, checked_name);
}
fn transCreateNodeTypedef(
rp: RestorePoint,
c: *Context,
typedef_decl: *const clang.TypedefNameDecl,
toplevel: bool,
checked_name: []const u8,
) Error!?*ast.Node {
const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null;
const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
const name_tok = try appendIdentifier(rp.c, checked_name);
const eq_token = try appendToken(rp.c, .Equal, "=");
) Error!?Node {
const child_qt = typedef_decl.getUnderlyingType();
const typedef_loc = typedef_decl.getLocation();
const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
const init_node = transQualType(c, child_qt, typedef_loc) catch |err| switch (err) {
error.UnsupportedType => {
try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
try failDecl(c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
return null;
},
error.OutOfMemory => |e| return e,
};
const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
const node = try ast.Node.VarDecl.create(rp.c.arena, .{
.name_token = name_tok,
.mut_token = mut_tok,
.semicolon_token = semicolon_token,
}, .{
.visib_token = visib_tok,
.eq_token = eq_token,
.init_node = init_node,
});
return &node.base;
const payload = try c.arena.create(ast.Payload.Typedef);
payload.* = .{
.base = .{ .tag = ([2]ast.Node.Tag{ .typedef, .pub_typedef })[toplevel] },
.data = .{
.name = checked_name,
.init = init_node,
},
};
return Node.initPayload(&payload.base);
}
fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*ast.Node {
@ -1399,13 +1339,15 @@ fn transBinaryOperator(
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))
const lhs = if (isBoolRes(lhs_uncasted))
try Node.bool_to_int.create(c.arena, lhs_uncasted)
else lhs_uncasted;
else
lhs_uncasted;
const rhs = if (isBoolRes(rhs_uncasted))
const rhs = if (isBoolRes(rhs_uncasted))
try Node.bool_to_int.create(c.arena, rhs_uncasted)
else rhs_uncasted;
else
rhs_uncasted;
const payload = try c.arena.create(ast.Payload.BinOp);
payload.* = .{
@ -1415,7 +1357,7 @@ fn transBinaryOperator(
.rhs = rhs,
},
};
return maybeSuppressResult(c, scope, used, &payload.base);
return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));
}
fn transCompoundStmtInline(
@ -1459,13 +1401,11 @@ fn transCStyleCastExprClass(
}
fn transDeclStmtOne(
rp: RestorePoint,
c: *Context,
scope: *Scope,
decl: *const clang.Decl,
block_scope: *Scope.Block,
) TransError!*ast.Node {
const c = rp.c;
) TransError!Node {
switch (decl.getKind()) {
.Var => {
const var_decl = @ptrCast(*const clang.VarDecl, decl);
@ -1479,47 +1419,38 @@ fn transDeclStmtOne(
.Extern, .Static => {
// This is actually a global variable, put it in the global scope and reference it.
// `_ = mangled_name;`
try visitVarDecl(rp.c, var_decl, mangled_name);
return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name));
try visitVarDecl(c, var_decl, mangled_name);
return try maybeSuppressResult(c, scope, .unused, try Node.identifier.create(c.arena, mangled_name));
},
else => {},
}
const mut_tok = if (qual_type.isConstQualified())
try appendToken(c, .Keyword_const, "const")
else
try appendToken(c, .Keyword_var, "var");
const name_tok = try appendIdentifier(c, mangled_name);
const is_const = qual_type.isConstQualified();
_ = try appendToken(c, .Colon, ":");
const loc = decl.getLocation();
const type_node = try transQualTypeMaybeInitialized(rp, qual_type, decl_init, loc);
const type_node = try transQualTypeMaybeInitialized(c, qual_type, decl_init, loc);
const eq_token = try appendToken(c, .Equal, "=");
var init_node = if (decl_init) |expr|
if (expr.getStmtClass() == .StringLiteralClass)
try transStringLiteralAsArray(rp, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(rp.c, type_node))
try transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(c, type_node))
else
try transExprCoercing(rp, scope, expr, .used, .r_value)
try transExprCoercing(c, scope, expr, .used, .r_value)
else
try transCreateNodeUndefinedLiteral(c);
if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
builtin_node.params()[0] = init_node;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
init_node = &builtin_node.base;
init_node = try Node.bool_to_int.create(c.arena, init_node);
}
const semicolon_token = try appendToken(c, .Semicolon, ";");
const node = try ast.Node.VarDecl.create(c.arena, .{
.name_token = name_tok,
.mut_token = mut_tok,
.semicolon_token = semicolon_token,
}, .{
.eq_token = eq_token,
.type_node = type_node,
.init_node = init_node,
return Node.var_decl.create(c.arena, .{
.is_pub = false,
.is_const = is_const,
.is_extern = false,
.is_export = false,
.linksection_string = null,
.alignment = null,
.name = mangled_name,
.type = type_node,
.init = init_node,
});
return &node.base;
},
.Typedef => {
const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl);
@ -1529,7 +1460,7 @@ fn transDeclStmtOne(
const underlying_type = underlying_qual.getTypePtr();
const mangled_name = try block_scope.makeMangledName(c, name);
const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
const node = (try transCreateNodeTypedef(c, typedef_decl, false, mangled_name)) orelse
return error.UnsupportedTranslation;
return node;
},
@ -1543,14 +1474,14 @@ fn transDeclStmtOne(
}
}
fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.DeclStmt) TransError!*ast.Node {
const block_scope = scope.findBlockScope(rp.c) catch unreachable;
fn transDeclStmt(c: *Context, scope: *Scope, stmt: *const clang.DeclStmt) TransError!Node {
const block_scope = scope.findBlockScope(c) catch unreachable;
var it = stmt.decl_begin();
const end_it = stmt.decl_end();
assert(it != end_it);
while (true) : (it += 1) {
const node = try transDeclStmtOne(rp, scope, it[0], block_scope);
const node = try transDeclStmtOne(c, scope, it[0], block_scope);
if (it + 1 == end_it) {
return node;
@ -1562,15 +1493,15 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.DeclStmt) T
}
fn transDeclRefExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
expr: *const clang.DeclRefExpr,
lrvalue: LRValue,
) TransError!*ast.Node {
) TransError!Node {
const value_decl = expr.getDecl();
const name = try rp.c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin());
const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin());
const mangled_name = scope.getAlias(name);
return transCreateNodeIdentifier(rp.c, mangled_name);
return Node.identifier.create(c.arena, mangled_name);
}
fn transImplicitCastExpr(
@ -1642,52 +1573,29 @@ fn transImplicitCastExpr(
}
fn transBoolExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
expr: *const clang.Expr,
used: ResultUsed,
lrvalue: LRValue,
grouped: bool,
) TransError!*ast.Node {
) TransError!Node {
if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) {
var is_zero: bool = undefined;
if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, rp.c.clang_context))) {
return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) {
return revertAndWarn(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
}
return try transCreateNodeBoolLiteral(rp.c, !is_zero);
return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[is_zero] };
}
const lparen = if (grouped)
try appendToken(rp.c, .LParen, "(")
else
undefined;
var res = try transExpr(rp, scope, expr, used, lrvalue);
var res = try transExpr(c, scope, expr, used, lrvalue);
if (isBoolRes(res)) {
if (!grouped and res.tag == .GroupedExpression) {
const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res);
res = group.expr;
// get zig fmt to work properly
tokenSlice(rp.c, group.lparen)[0] = ')';
}
return res;
}
const ty = getExprQualType(rp.c, expr).getTypePtr();
const node = try finishBoolExpr(rp, scope, expr.getBeginLoc(), ty, res, used);
const ty = getExprQualType(c, expr).getTypePtr();
const node = try finishBoolExpr(c, scope, expr.getBeginLoc(), ty, res, used);
if (grouped) {
const rparen = try appendToken(rp.c, .RParen, ")");
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
grouped_expr.* = .{
.lparen = lparen,
.expr = node,
.rparen = rparen,
};
return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
} else {
return maybeSuppressResult(rp, scope, used, node);
}
return maybeSuppressResult(c, scope, used, node);
}
fn exprIsBooleanType(expr: *const clang.Expr) bool {
@ -1713,34 +1621,32 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool {
}
}
fn isBoolRes(res: *ast.Node) bool {
switch (res.tag) {
.BoolOr,
.BoolAnd,
.EqualEqual,
.BangEqual,
.LessThan,
.GreaterThan,
.LessOrEqual,
.GreaterOrEqual,
.BoolNot,
.BoolLiteral,
fn isBoolRes(res: Node) bool {
switch (res.tag()) {
.@"or",
.@"and",
.equal,
.note_equal,
.less_than,
.less_than_equal,
.greater_than,
.greater_than_equal,
.not,
.false_literal,
.true_literal,
=> return true,
.GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
else => return false,
}
}
fn finishBoolExpr(
rp: RestorePoint,
c: *Context,
scope: *Scope,
loc: clang.SourceLocation,
ty: *const clang.Type,
node: *ast.Node,
node: Node,
used: ResultUsed,
) TransError!*ast.Node {
) TransError!Node {
switch (ty.getTypeClass()) {
.Builtin => {
const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
@ -1772,42 +1678,39 @@ fn finishBoolExpr(
.WChar_S,
.Float16,
=> {
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
// node != 0
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init()});
},
.NullPtr => {
const op_token = try appendToken(rp.c, .EqualEqual, "==");
const rhs_node = try transCreateNodeNullLiteral(rp.c);
return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false);
// node == null
return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init()});
},
else => {},
}
},
.Pointer => {
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeNullLiteral(rp.c);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
// node == null
return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init()});
},
.Typedef => {
const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
const typedef_decl = typedef_ty.getDecl();
const underlying_type = typedef_decl.getUnderlyingType();
return finishBoolExpr(rp, scope, loc, underlying_type.getTypePtr(), node, used);
return finishBoolExpr(c, scope, loc, underlying_type.getTypePtr(), node, used);
},
.Enum => {
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
// node != 0
return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init()});
const op_token = try appendToken(c, .BangEqual, "!=");
},
.Elaborated => {
const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
const named_type = elaborated_ty.getNamedType();
return finishBoolExpr(rp, scope, loc, named_type.getTypePtr(), node, used);
return finishBoolExpr(c, scope, loc, named_type.getTypePtr(), node, used);
},
else => {},
}
return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
return fail(c, error.UnsupportedType, loc, "unsupported bool expression type", .{});
}
const SuppressCast = enum {
@ -4242,7 +4145,7 @@ fn transCreateNodeBoolInfixOp(
.rhs = rhs,
},
};
return maybeSuppressResult(c, scope, used, &payload.base);
return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));
}
fn transCreateNodePtrType(
@ -4654,7 +4557,7 @@ fn transCreateNodeShiftOp(
const lhs = try transExpr(c, scope, lhs_expr, .used, .l_value);
const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location);
const rhs = try transExpr(c, scope, rhs_expr, .used, .r_value);
const rhs = try transExprCoercing(c, scope, rhs_expr, .used, .r_value);
const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type });
const payload = try c.arena.create(ast.Payload.BinOp);
@ -4663,9 +4566,9 @@ fn transCreateNodeShiftOp(
.data = .{
.lhs = lhs,
.rhs = rhs_casted,
}
},
};
return &payload.base;
return Node.initPayload(&payload.base);
}
fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
@ -4961,7 +4864,7 @@ fn finishTransFnProto(
};
}
const link_section_string: ?[]const u8 = blk: {
const linksection_string = blk: {
if (fn_decl) |decl| {
var str_len: usize = undefined;
if (decl.getSectionAttribute(&str_len)) |str_ptr| {
@ -5004,24 +4907,19 @@ fn finishTransFnProto(
}
};
const fn_proto = try c.arena.create(ast.Payload.Func);
fn_proto.* = .{
.base = .{ .tag = .func },
.data = .{
.is_pub = is_pub,
.is_extern = is_extern,
.is_export = is_export,
.is_var_args = is_var_args,
.name = name,
.link_section_string = link_section_string,
.explicit_callconv = explicit_callconv,
.params = c.arena.dupe(ast.Payload.Func.Param, fn_params.items),
.return_type = return_node,
.body = null,
.alignment = alignment,
},
};
return fn_proto;
return Node.func.create(c.arena, .{
.is_pub = is_pub,
.is_extern = is_extern,
.is_export = is_export,
.is_var_args = is_var_args,
.name = name,
.linksection_string = linksection_string,
.explicit_callconv = explicit_callconv,
.params = try c.arena.dupe(ast.Payload.Func.Param, fn_params.items),
.return_type = return_node,
.body = null,
.alignment = alignment,
});
}
fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void {
@ -5054,6 +4952,19 @@ pub fn freeErrors(errors: []ClangErrMsg) void {
errors.ptr.delete(errors.len);
}
fn isZigPrimitiveType(name: []const u8) bool {
if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
for (name[1..]) |c| {
switch (c) {
'0'...'9' => {},
else => return false,
}
}
return true;
}
return @import("astgen.zig").simple_types.has(name);
}
const MacroCtx = struct {
source: []const u8,
list: []const CToken,

View File

@ -137,11 +137,16 @@ pub const Node = extern union {
single_pointer,
array_type,
/// @import("std").mem.zeroes(T)
std_mem_zeroes,
// pub const name = @compileError(msg);
fail_decl,
// var actual = mangled;
arg_redecl,
/// const name = init;
typedef,
/// pub const name = init;
pub_typedef,
pub const last_no_payload_tag = Tag.usingnamespace_builtins;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@ -257,11 +262,11 @@ pub const Node = extern union {
.container_init => Payload.ContainerInit,
.std_meta_cast => Payload.Infix,
.block => Payload.Block,
.c_pointer => Payload.Pointer,
.single_pointer => Payload.Pointer,
.c_pointer, .single_pointer => Payload.Pointer,
.array_type => Payload.Array,
.arg_redecl => Payload.ArgRedecl,
.log2_int_type => Payload.Log2IntType,
.typedef, .pub_typedef => Payload.Typedef,
};
}
@ -301,6 +306,11 @@ pub const Node = extern union {
return null;
}
pub fn initPayload(payload: *Payload) Node {
assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
return .{ .ptr_otherwise = payload };
}
};
pub const Payload = struct {
@ -383,13 +393,15 @@ pub const Payload = struct {
pub const VarDecl = struct {
base: Node = .{ .tag = .var_decl },
data: struct {
@"pub": bool,
@"const": bool,
@"extern": bool,
@"export": bool,
is_pub: bool,
is_const: bool,
is_extern: bool,
is_export: bool,
alignment: ?c_uint,
linksection_string: ?[]const u8,
name: []const u8,
type: Type,
init: Node,
type: Node,
init: ?Node,
},
};
@ -401,12 +413,12 @@ pub const Payload = struct {
is_export: bool,
is_var_args: bool,
name: []const u8,
link_section_string: ?[]const u8,
linksection_string: ?[]const u8,
explicit_callconv: ?std.builtin.CallingConvention,
params: []Param,
return_type: Node,
body: ?Node,
alignment: c_uint,
alignment: ?c_uint,
pub const Param = struct {
is_noalias: bool,
@ -501,6 +513,14 @@ pub const Payload = struct {
base: Node,
data: std.math.Log2Int(u64),
};
pub const Typedef = struct {
base: Node,
data: struct {
name: []const u8,
init: Node,
},
};
};
/// Converts the nodes into a Zig ast.