mirror of
https://github.com/ziglang/zig.git
synced 2026-01-02 03:25:01 +00:00
aro-translate-c: translate function types
This commit is contained in:
parent
0c6cb8d8c8
commit
a15feeb694
@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const CallingConvention = std.builtin.CallingConvention;
|
||||
const translate_c = @import("translate_c.zig");
|
||||
const aro = @import("aro");
|
||||
const Tree = aro.Tree;
|
||||
@ -99,6 +100,12 @@ fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []c
|
||||
try c.global_scope.nodes.append(try ZigTag.warning.create(c.arena, location_comment));
|
||||
}
|
||||
|
||||
fn warn(c: *Context, scope: *Scope, loc: TokenIndex, comptime format: []const u8, args: anytype) !void {
|
||||
const str = try c.locStr(loc);
|
||||
const value = try std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, .{str} ++ args);
|
||||
try scope.appendNode(try ZigTag.warning.create(c.arena, value));
|
||||
}
|
||||
|
||||
pub fn translate(
|
||||
gpa: mem.Allocator,
|
||||
comp: *Compilation,
|
||||
@ -299,12 +306,112 @@ fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {
|
||||
fn transRecordDecl(_: *Context, _: *Scope, _: NodeIndex) Error!void {
|
||||
@panic("TODO");
|
||||
}
|
||||
fn transFnDecl(_: *Context, _: NodeIndex) Error!void {
|
||||
@panic("TODO");
|
||||
|
||||
fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
|
||||
const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];
|
||||
const fn_ty = raw_ty.canonicalize(.standard);
|
||||
const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];
|
||||
if (c.decl_table.get(@intFromPtr(fn_ty.data.func))) |_|
|
||||
return; // Avoid processing this decl twice
|
||||
|
||||
const fn_name = c.tree.tokSlice(node_data.decl.name);
|
||||
if (c.global_scope.sym_table.contains(fn_name))
|
||||
return; // Avoid processing this decl twice
|
||||
|
||||
const fn_decl_loc = 0; // TODO
|
||||
const has_body = node_data.decl.node != .none;
|
||||
const is_always_inline = has_body and raw_ty.getAttribute(.always_inline) != null;
|
||||
const proto_ctx = FnProtoContext{
|
||||
.fn_name = fn_name,
|
||||
.is_inline = is_always_inline,
|
||||
.is_extern = !has_body,
|
||||
.is_export = switch (c.tree.nodes.items(.tag)[@intFromEnum(fn_decl)]) {
|
||||
.fn_proto,
|
||||
.fn_def => has_body and !is_always_inline,
|
||||
|
||||
.inline_fn_proto,
|
||||
.inline_fn_def,
|
||||
.inline_static_fn_proto,
|
||||
.inline_static_fn_def,
|
||||
.static_fn_proto,
|
||||
.static_fn_def => false,
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
|
||||
const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
};
|
||||
|
||||
if (!has_body) {
|
||||
return addTopLevelDecl(c, fn_name, proto_node);
|
||||
}
|
||||
const proto_payload = proto_node.castTag(.func).?;
|
||||
|
||||
// actual function definition with body
|
||||
const body_stmt = node_data.decl.node;
|
||||
_ = body_stmt;
|
||||
var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
|
||||
block_scope.return_type = fn_ty.data.func.return_type;
|
||||
defer block_scope.deinit();
|
||||
|
||||
var scope = &block_scope.base;
|
||||
_ = scope;
|
||||
|
||||
var param_id: c_uint = 0;
|
||||
for (proto_payload.data.params, fn_ty.data.func.params) |*param, param_info| {
|
||||
const param_name = param.name orelse {
|
||||
proto_payload.data.is_extern = true;
|
||||
proto_payload.data.is_export = false;
|
||||
proto_payload.data.is_inline = false;
|
||||
try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});
|
||||
return addTopLevelDecl(c, fn_name, proto_node);
|
||||
};
|
||||
|
||||
const is_const = param_info.ty.qual.@"const";
|
||||
|
||||
const mangled_param_name = try block_scope.makeMangledName(c, param_name);
|
||||
param.name = mangled_param_name;
|
||||
|
||||
if (!is_const) {
|
||||
const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});
|
||||
const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
|
||||
param.name = arg_name;
|
||||
|
||||
const redecl_node = try ZigTag.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
|
||||
try block_scope.statements.append(redecl_node);
|
||||
}
|
||||
try block_scope.discardVariable(c, mangled_param_name);
|
||||
|
||||
param_id += 1;
|
||||
}
|
||||
|
||||
// const casted_body = @as(*const clang.CompoundStmt, @ptrCast(body_stmt));
|
||||
// transCompoundStmtInline(c, casted_body, &block_scope) catch |err| switch (err) {
|
||||
// error.OutOfMemory => |e| return e,
|
||||
// error.UnsupportedTranslation,
|
||||
// error.UnsupportedType,
|
||||
// => {
|
||||
// proto_payload.data.is_extern = true;
|
||||
// proto_payload.data.is_export = false;
|
||||
// proto_payload.data.is_inline = false;
|
||||
// try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});
|
||||
// return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
|
||||
// },
|
||||
// };
|
||||
|
||||
proto_payload.data.body = try block_scope.complete(c);
|
||||
return addTopLevelDecl(c, fn_name, proto_node);
|
||||
}
|
||||
|
||||
fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void {
|
||||
const node_types = c.tree.nodes.items(.ty);
|
||||
const ty = node_types[@intFromEnum(enum_decl)];
|
||||
@ -393,8 +500,6 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
|
||||
}
|
||||
|
||||
fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) TypeError!ZigNode {
|
||||
_ = source_loc;
|
||||
_ = scope;
|
||||
const ty = raw_ty.canonicalize(.standard);
|
||||
switch (ty.specifier) {
|
||||
.void => return ZigTag.type.create(c.arena, "anyopaque"),
|
||||
@ -418,10 +523,112 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) T
|
||||
.long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
|
||||
.float80 => return ZigTag.type.create(c.arena, "f80"),
|
||||
.float128 => return ZigTag.type.create(c.arena, "f128"),
|
||||
else => @panic("TODO"),
|
||||
.func,
|
||||
.var_args_func,
|
||||
.old_style_func,
|
||||
=> return transFnType(c, scope, raw_ty, ty, source_loc, .{}),
|
||||
else => return error.UnsupportedType,
|
||||
}
|
||||
}
|
||||
|
||||
fn zigAlignment(bit_alignment: u29) u32 {
|
||||
return bit_alignment / 8;
|
||||
}
|
||||
|
||||
const FnProtoContext = struct {
|
||||
is_pub: bool = false,
|
||||
is_export: bool = false,
|
||||
is_extern: bool = false,
|
||||
is_inline: bool = false,
|
||||
fn_name: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
fn transFnType(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
raw_ty: Type,
|
||||
fn_ty: Type,
|
||||
source_loc: TokenIndex,
|
||||
ctx: FnProtoContext,
|
||||
) !ZigNode {
|
||||
const param_count: usize = fn_ty.data.func.params.len;
|
||||
var fn_params = try c.arena.alloc(ast.Payload.Param, param_count);
|
||||
|
||||
for (fn_ty.data.func.params, fn_params) |param_info, *param_node| {
|
||||
const param_ty = param_info.ty;
|
||||
const is_noalias = param_ty.qual.restrict;
|
||||
|
||||
const param_name: ?[]const u8 = if (param_info.name == .empty)
|
||||
null
|
||||
else
|
||||
c.mapper.lookup(param_info.name);
|
||||
|
||||
const type_node = try transType(c, scope, param_ty, param_info.name_tok);
|
||||
param_node.* = .{
|
||||
.is_noalias = is_noalias,
|
||||
.name = param_name,
|
||||
.type = type_node,
|
||||
};
|
||||
}
|
||||
|
||||
const linksection_string = blk: {
|
||||
if (raw_ty.getAttribute(.section)) |section| {
|
||||
break :blk section.name.slice(c.tree.strings);
|
||||
}
|
||||
break :blk null;
|
||||
};
|
||||
|
||||
const alignment = if (raw_ty.requestedAlignment(c.comp)) |alignment| zigAlignment(alignment) else null;
|
||||
|
||||
const explicit_callconv = null;
|
||||
// const explicit_callconv = if ((ctx.is_inline or ctx.is_export or ctx.is_extern) and ctx.cc == .C) null else ctx.cc;
|
||||
|
||||
const return_type_node = blk: {
|
||||
if (raw_ty.getAttribute(.noreturn) != null) {
|
||||
break :blk ZigTag.noreturn_type.init();
|
||||
} else {
|
||||
const return_ty = fn_ty.data.func.return_type;
|
||||
if (return_ty.is(.void)) {
|
||||
// convert primitive anyopaque to actual void (only for return type)
|
||||
break :blk ZigTag.void_type.init();
|
||||
} else {
|
||||
break :blk transType(c, scope, return_ty, source_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try warn(c, scope, source_loc, "unsupported function proto return type", .{});
|
||||
return err;
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const payload = try c.arena.create(ast.Payload.Func);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .func },
|
||||
.data = .{
|
||||
.is_pub = ctx.is_pub,
|
||||
.is_extern = ctx.is_extern,
|
||||
.is_export = ctx.is_export,
|
||||
.is_inline = ctx.is_inline,
|
||||
.is_var_args = switch (fn_ty.specifier) {
|
||||
.func => false,
|
||||
.var_args_func => true,
|
||||
.old_style_func => !ctx.is_export and !ctx.is_inline,
|
||||
else => unreachable,
|
||||
},
|
||||
.name = ctx.fn_name,
|
||||
.linksection_string = linksection_string,
|
||||
.explicit_callconv = explicit_callconv,
|
||||
.params = fn_params,
|
||||
.return_type = return_type_node,
|
||||
.body = null,
|
||||
.alignment = alignment,
|
||||
},
|
||||
};
|
||||
return ZigNode.initPayload(&payload.base);
|
||||
}
|
||||
|
||||
fn transStmt(c: *Context, node: NodeIndex) TransError!void {
|
||||
_ = try c.transExpr(node, .unused);
|
||||
}
|
||||
|
||||
@ -4924,8 +4924,6 @@ fn finishTransFnProto(
|
||||
const is_inline = if (fn_decl_context) |ctx| ctx.is_always_inline else false;
|
||||
const scope = &c.global_scope.base;
|
||||
|
||||
// TODO check for align attribute
|
||||
|
||||
const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;
|
||||
var fn_params = try std.ArrayList(ast.Payload.Param).initCapacity(c.gpa, param_count);
|
||||
defer fn_params.deinit();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user