mirror of
https://github.com/ziglang/zig.git
synced 2026-02-17 23:10:09 +00:00
translate-c: convert function translation
This commit is contained in:
parent
7514c0ad0d
commit
f36849fed2
@ -469,7 +469,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
return visitFnDecl(c, def);
|
||||
}
|
||||
|
||||
const rp = makeRestorePoint(c);
|
||||
const fn_decl_loc = fn_decl.getLocation();
|
||||
const has_body = fn_decl.hasBody();
|
||||
const storage_class = fn_decl.getStorageClass();
|
||||
@ -513,9 +512,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
decl_ctx.has_body = false;
|
||||
decl_ctx.storage_class = .Extern;
|
||||
decl_ctx.is_export = false;
|
||||
try emitWarning(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{});
|
||||
try warn(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{});
|
||||
}
|
||||
break :blk transFnProto(rp, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
|
||||
break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
|
||||
},
|
||||
@ -524,7 +523,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
},
|
||||
.FunctionNoProto => blk: {
|
||||
const fn_no_proto_type = @ptrCast(*const clang.FunctionType, fn_type);
|
||||
break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
|
||||
break :blk transFnNoProto(c, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
|
||||
},
|
||||
@ -535,13 +534,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
};
|
||||
|
||||
if (!decl_ctx.has_body) {
|
||||
const semi_tok = try appendToken(c, .Semicolon, ";");
|
||||
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
||||
}
|
||||
|
||||
// actual function definition with body
|
||||
const body_stmt = fn_decl.getBody();
|
||||
var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false);
|
||||
var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
|
||||
block_scope.return_type = return_qt;
|
||||
defer block_scope.deinit();
|
||||
|
||||
@ -559,34 +557,22 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
const is_const = qual_type.isConstQualified();
|
||||
|
||||
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 mut_tok = try appendToken(c, .Keyword_var, "var");
|
||||
const name_tok = try appendIdentifier(c, mangled_param_name);
|
||||
const eq_token = try appendToken(c, .Equal, "=");
|
||||
const init_node = try transCreateNodeIdentifier(c, arg_name);
|
||||
const semicolon_token = try appendToken(c, .Semicolon, ";");
|
||||
const node = try ast.Node.VarDecl.create(c.arena, .{
|
||||
.mut_token = mut_tok,
|
||||
.name_token = name_tok,
|
||||
.semicolon_token = semicolon_token,
|
||||
}, .{
|
||||
.eq_token = eq_token,
|
||||
.init_node = init_node,
|
||||
});
|
||||
try block_scope.statements.append(&node.base);
|
||||
param.name_token = try appendIdentifier(c, arg_name);
|
||||
_ = try appendToken(c, .Colon, ":");
|
||||
const redecl_node = try Node.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
|
||||
try block_scope.statements.append(redecl_node);
|
||||
}
|
||||
|
||||
param_id += 1;
|
||||
}
|
||||
|
||||
const casted_body = @ptrCast(*const clang.CompoundStmt, body_stmt);
|
||||
transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) {
|
||||
transCompoundStmtInline(c, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) {
|
||||
error.OutOfMemory => |e| return e,
|
||||
error.UnsupportedTranslation,
|
||||
error.UnsupportedType,
|
||||
@ -600,37 +586,31 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
if (block_scope.statements.items.len > 0) {
|
||||
var last = block_scope.statements.items[block_scope.statements.items.len - 1];
|
||||
while (true) {
|
||||
switch (last.tag) {
|
||||
.Block, .LabeledBlock => {
|
||||
const stmts = last.blockStatements();
|
||||
if (stmts.len == 0) break;
|
||||
switch (last.tag()) {
|
||||
.block => {
|
||||
const block = last.castTag(.block).?;
|
||||
if (block.data.stmts.len == 0) break;
|
||||
|
||||
last = stmts[stmts.len - 1];
|
||||
last = block.data.stmts[block.data.stmts.len - 1];
|
||||
},
|
||||
// no extra return needed
|
||||
.Return => break :blk,
|
||||
.@"return", .return_void => break :blk,
|
||||
else => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
|
||||
.ltoken = try appendToken(rp.c, .Keyword_return, "return"),
|
||||
.tag = .Return,
|
||||
}, .{
|
||||
.rhs = transZeroInitExpr(rp, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
|
||||
error.OutOfMemory => |e| return e,
|
||||
error.UnsupportedTranslation,
|
||||
error.UnsupportedType,
|
||||
=> return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
|
||||
},
|
||||
});
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
try block_scope.statements.append(&return_expr.base);
|
||||
const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
|
||||
error.OutOfMemory => |e| return e,
|
||||
error.UnsupportedTranslation,
|
||||
error.UnsupportedType,
|
||||
=> return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
|
||||
};
|
||||
const ret = try Node.@"return".create(c.arena, rhs);
|
||||
try block_scope.statements.append(ret);
|
||||
}
|
||||
|
||||
const body_node = try block_scope.complete(rp.c);
|
||||
proto_node.setBodyNode(body_node);
|
||||
proto_node.body = try block_scope.complete(c);
|
||||
return addTopLevelDecl(c, fn_name, &proto_node.base);
|
||||
}
|
||||
|
||||
@ -2440,16 +2420,16 @@ fn transInitListExpr(
|
||||
}
|
||||
|
||||
fn transZeroInitExpr(
|
||||
rp: RestorePoint,
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
source_loc: clang.SourceLocation,
|
||||
ty: *const clang.Type,
|
||||
) TransError!*ast.Node {
|
||||
) TransError!Node {
|
||||
switch (ty.getTypeClass()) {
|
||||
.Builtin => {
|
||||
const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
|
||||
switch (builtin_ty.getKind()) {
|
||||
.Bool => return try transCreateNodeBoolLiteral(rp.c, false),
|
||||
.Bool => return Node.false_literal.init(),
|
||||
.Char_U,
|
||||
.UChar,
|
||||
.Char_S,
|
||||
@ -2470,16 +2450,16 @@ fn transZeroInitExpr(
|
||||
.Float128,
|
||||
.Float16,
|
||||
.LongDouble,
|
||||
=> return transCreateNodeInt(rp.c, 0),
|
||||
else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
|
||||
=> return Node.zero_literal.init(),
|
||||
else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
|
||||
}
|
||||
},
|
||||
.Pointer => return transCreateNodeNullLiteral(rp.c),
|
||||
.Pointer => return Node.null_literal.init(),
|
||||
.Typedef => {
|
||||
const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
|
||||
const typedef_decl = typedef_ty.getDecl();
|
||||
return transZeroInitExpr(
|
||||
rp,
|
||||
c,
|
||||
scope,
|
||||
source_loc,
|
||||
typedef_decl.getUnderlyingType().getTypePtr(),
|
||||
@ -2488,7 +2468,7 @@ fn transZeroInitExpr(
|
||||
else => {},
|
||||
}
|
||||
|
||||
return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
|
||||
return fail(c, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
|
||||
}
|
||||
|
||||
fn transImplicitValueInitExpr(
|
||||
@ -3985,7 +3965,7 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc
|
||||
if (int_bit_width != 0) {
|
||||
// we can perform the log2 now.
|
||||
const cast_bit_width = math.log2_int(u64, int_bit_width);
|
||||
return Node.uint_type.create(c.arena, cast_bit_width);
|
||||
return Node.log2_int_type.create(c.arena, cast_bit_width);
|
||||
}
|
||||
|
||||
const zig_type = try transQualType(c, qt, source_loc);
|
||||
@ -4886,7 +4866,7 @@ const FnDeclContext = struct {
|
||||
};
|
||||
|
||||
fn transCC(
|
||||
rp: RestorePoint,
|
||||
c: *Context,
|
||||
fn_ty: *const clang.FunctionType,
|
||||
source_loc: clang.SourceLocation,
|
||||
) !CallingConvention {
|
||||
@ -4899,7 +4879,7 @@ fn transCC(
|
||||
.X86ThisCall => return CallingConvention.Thiscall,
|
||||
.AAPCS => return CallingConvention.AAPCS,
|
||||
.AAPCS_VFP => return CallingConvention.AAPCSVFP,
|
||||
else => return revertAndWarn(
|
||||
else => return fail(
|
||||
rp,
|
||||
error.UnsupportedType,
|
||||
source_loc,
|
||||
@ -4910,33 +4890,33 @@ fn transCC(
|
||||
}
|
||||
|
||||
fn transFnProto(
|
||||
rp: RestorePoint,
|
||||
c: *Context,
|
||||
fn_decl: ?*const clang.FunctionDecl,
|
||||
fn_proto_ty: *const clang.FunctionProtoType,
|
||||
source_loc: clang.SourceLocation,
|
||||
fn_decl_context: ?FnDeclContext,
|
||||
is_pub: bool,
|
||||
) !*ast.Node.FnProto {
|
||||
) !Node.FnProto {
|
||||
const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty);
|
||||
const cc = try transCC(rp, fn_ty, source_loc);
|
||||
const cc = try transCC(c, fn_ty, source_loc);
|
||||
const is_var_args = fn_proto_ty.isVariadic();
|
||||
return finishTransFnProto(rp, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
|
||||
return finishTransFnProto(c, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
|
||||
}
|
||||
|
||||
fn transFnNoProto(
|
||||
rp: RestorePoint,
|
||||
c: *Context,
|
||||
fn_ty: *const clang.FunctionType,
|
||||
source_loc: clang.SourceLocation,
|
||||
fn_decl_context: ?FnDeclContext,
|
||||
is_pub: bool,
|
||||
) !*ast.Node.FnProto {
|
||||
const cc = try transCC(rp, fn_ty, source_loc);
|
||||
) !Node.FnProto {
|
||||
const cc = try transCC(c, fn_ty, source_loc);
|
||||
const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true;
|
||||
return finishTransFnProto(rp, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
|
||||
return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
|
||||
}
|
||||
|
||||
fn finishTransFnProto(
|
||||
rp: RestorePoint,
|
||||
c: *Context,
|
||||
fn_decl: ?*const clang.FunctionDecl,
|
||||
fn_proto_ty: ?*const clang.FunctionProtoType,
|
||||
fn_ty: *const clang.FunctionType,
|
||||
@ -4945,128 +4925,77 @@ fn finishTransFnProto(
|
||||
is_var_args: bool,
|
||||
cc: CallingConvention,
|
||||
is_pub: bool,
|
||||
) !*ast.Node.FnProto {
|
||||
) !*ast.Payload.Func {
|
||||
const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
|
||||
const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
|
||||
|
||||
// TODO check for always_inline attribute
|
||||
// TODO check for align attribute
|
||||
|
||||
// pub extern fn name(...) T
|
||||
const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
|
||||
const extern_export_inline_tok = if (is_export)
|
||||
try appendToken(rp.c, .Keyword_export, "export")
|
||||
else if (is_extern)
|
||||
try appendToken(rp.c, .Keyword_extern, "extern")
|
||||
else
|
||||
null;
|
||||
const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
|
||||
const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;
|
||||
const lparen_tok = try appendToken(rp.c, .LParen, "(");
|
||||
|
||||
var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(rp.c.gpa);
|
||||
var fn_params = std.ArrayList(ast.Payload.Func.Param).init(c.gpa);
|
||||
defer fn_params.deinit();
|
||||
const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;
|
||||
try fn_params.ensureCapacity(param_count + 1); // +1 for possible var args node
|
||||
try fn_params.ensureCapacity(param_count);
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < param_count) : (i += 1) {
|
||||
const param_qt = fn_proto_ty.?.getParamType(@intCast(c_uint, i));
|
||||
const is_noalias = param_qt.isRestrictQualified();
|
||||
|
||||
const noalias_tok = if (param_qt.isRestrictQualified()) try appendToken(rp.c, .Keyword_noalias, "noalias") else null;
|
||||
const param_name: ?[]const u8 =
|
||||
if (fn_decl) |decl|
|
||||
blk: {
|
||||
const param = decl.getParamDecl(@intCast(c_uint, i));
|
||||
const param_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());
|
||||
if (param_name.len < 1)
|
||||
break :blk null;
|
||||
|
||||
const param_name_tok: ?ast.TokenIndex = blk: {
|
||||
if (fn_decl) |decl| {
|
||||
const param = decl.getParamDecl(@intCast(c_uint, i));
|
||||
const param_name: []const u8 = try rp.c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());
|
||||
if (param_name.len < 1)
|
||||
break :blk null;
|
||||
|
||||
const result = try appendIdentifier(rp.c, param_name);
|
||||
_ = try appendToken(rp.c, .Colon, ":");
|
||||
break :blk result;
|
||||
}
|
||||
break :blk null;
|
||||
};
|
||||
|
||||
const type_node = try transQualType(rp, param_qt, source_loc);
|
||||
break :blk param_name;
|
||||
} else null;
|
||||
const type_node = try transQualType(c, param_qt, source_loc);
|
||||
|
||||
fn_params.addOneAssumeCapacity().* = .{
|
||||
.doc_comments = null,
|
||||
.comptime_token = null,
|
||||
.noalias_token = noalias_tok,
|
||||
.name_token = param_name_tok,
|
||||
.param_type = .{ .type_expr = type_node },
|
||||
.is_noalias = is_noalias,
|
||||
.name = param_name,
|
||||
.type = type_node,
|
||||
};
|
||||
|
||||
if (i + 1 < param_count) {
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
}
|
||||
}
|
||||
|
||||
const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
|
||||
if (param_count > 0) {
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
}
|
||||
break :blk try appendToken(rp.c, .Ellipsis3, "...");
|
||||
} else null;
|
||||
|
||||
const rparen_tok = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
const linksection_expr = blk: {
|
||||
const link_section_string: ?[]const u8 = blk: {
|
||||
if (fn_decl) |decl| {
|
||||
var str_len: usize = undefined;
|
||||
if (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: c_uint = blk: {
|
||||
if (fn_decl) |decl| {
|
||||
const alignment = decl.getAlignedAttribute(rp.c.clang_context);
|
||||
const alignment = 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 callconv_expr = if ((is_export or is_extern) and cc == .C) null else blk: {
|
||||
_ = try appendToken(rp.c, .Keyword_callconv, "callconv");
|
||||
_ = try appendToken(rp.c, .LParen, "(");
|
||||
const expr = try transCreateNodeEnumLiteral(rp.c, @tagName(cc));
|
||||
_ = try appendToken(rp.c, .RParen, ")");
|
||||
break :blk expr;
|
||||
};
|
||||
const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc;
|
||||
|
||||
const return_type_node = blk: {
|
||||
if (fn_ty.getNoReturnAttr()) {
|
||||
break :blk try transCreateNodeIdentifier(rp.c, "noreturn");
|
||||
break :blk Node.noreturn_type.init();
|
||||
} else {
|
||||
const return_qt = fn_ty.getReturnType();
|
||||
if (isCVoid(return_qt)) {
|
||||
// convert primitive c_void to actual void (only for return type)
|
||||
break :blk try transCreateNodeIdentifier(rp.c, "void");
|
||||
break :blk Node.void_type.init();
|
||||
} else {
|
||||
break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
|
||||
break :blk transQualType(c, return_qt, source_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try emitWarning(rp.c, source_loc, "unsupported function proto return type", .{});
|
||||
try warn(c, source_loc, "unsupported function proto return type", .{});
|
||||
return err;
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
@ -5075,32 +5004,23 @@ fn finishTransFnProto(
|
||||
}
|
||||
};
|
||||
|
||||
// We need to reserve an undefined (but non-null) body node to set later.
|
||||
var body_node: ?*ast.Node = null;
|
||||
if (fn_decl_context) |ctx| {
|
||||
if (ctx.has_body) {
|
||||
// TODO: we should be able to use undefined here but
|
||||
// it causes a bug. This is undefined without zig language
|
||||
// being aware of it.
|
||||
body_node = @intToPtr(*ast.Node, 0x08);
|
||||
}
|
||||
}
|
||||
|
||||
const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{
|
||||
.params_len = fn_params.items.len,
|
||||
.return_type = .{ .Explicit = return_type_node },
|
||||
.fn_token = fn_tok,
|
||||
}, .{
|
||||
.visib_token = pub_tok,
|
||||
.name_token = name_tok,
|
||||
.extern_export_inline_token = extern_export_inline_tok,
|
||||
.align_expr = align_expr,
|
||||
.section_expr = linksection_expr,
|
||||
.callconv_expr = callconv_expr,
|
||||
.body_node = body_node,
|
||||
.var_args_token = var_args_token,
|
||||
});
|
||||
mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -5122,124 +5042,12 @@ fn fail(
|
||||
}
|
||||
|
||||
pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void {
|
||||
// location
|
||||
// pub const name = @compileError(msg);
|
||||
const pub_tok = try appendToken(c, .Keyword_pub, "pub");
|
||||
const const_tok = try appendToken(c, .Keyword_const, "const");
|
||||
const name_tok = try appendIdentifier(c, name);
|
||||
const eq_tok = try appendToken(c, .Equal, "=");
|
||||
const builtin_tok = try appendToken(c, .Builtin, "@compileError");
|
||||
const lparen_tok = try appendToken(c, .LParen, "(");
|
||||
const msg_tok = try appendTokenFmt(c, .StringLiteral, "\"" ++ format ++ "\"", args);
|
||||
const rparen_tok = try appendToken(c, .RParen, ")");
|
||||
const semi_tok = try appendToken(c, .Semicolon, ";");
|
||||
_ = try appendTokenFmt(c, .LineComment, "// {s}", .{c.locStr(loc)});
|
||||
|
||||
const msg_node = try c.arena.create(ast.Node.OneToken);
|
||||
msg_node.* = .{
|
||||
.base = .{ .tag = .StringLiteral },
|
||||
.token = msg_tok,
|
||||
};
|
||||
|
||||
const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
|
||||
call_node.* = .{
|
||||
.builtin_token = builtin_tok,
|
||||
.params_len = 1,
|
||||
.rparen_token = rparen_tok,
|
||||
};
|
||||
call_node.params()[0] = &msg_node.base;
|
||||
|
||||
const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
|
||||
.name_token = name_tok,
|
||||
.mut_token = const_tok,
|
||||
.semicolon_token = semi_tok,
|
||||
}, .{
|
||||
.visib_token = pub_tok,
|
||||
.eq_token = eq_tok,
|
||||
.init_node = &call_node.base,
|
||||
});
|
||||
try addTopLevelDecl(c, name, &var_decl_node.base);
|
||||
}
|
||||
|
||||
fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex {
|
||||
std.debug.assert(token_id != .Identifier); // use appendIdentifier
|
||||
return appendTokenFmt(c, token_id, "{s}", .{bytes});
|
||||
}
|
||||
|
||||
fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: anytype) !ast.TokenIndex {
|
||||
assert(token_id != .Invalid);
|
||||
|
||||
try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1);
|
||||
try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1);
|
||||
|
||||
const start_index = c.source_buffer.items.len;
|
||||
try c.source_buffer.writer().print(format ++ " ", args);
|
||||
|
||||
c.token_ids.appendAssumeCapacity(token_id);
|
||||
c.token_locs.appendAssumeCapacity(.{
|
||||
.start = start_index,
|
||||
.end = c.source_buffer.items.len - 1, // back up before the space
|
||||
});
|
||||
|
||||
return c.token_ids.items.len - 1;
|
||||
}
|
||||
|
||||
// TODO hook up with codegen
|
||||
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;
|
||||
}
|
||||
// void is invalid in c so it doesn't need to be checked.
|
||||
return mem.eql(u8, name, "comptime_float") or
|
||||
mem.eql(u8, name, "comptime_int") or
|
||||
mem.eql(u8, name, "bool") or
|
||||
mem.eql(u8, name, "isize") or
|
||||
mem.eql(u8, name, "usize") or
|
||||
mem.eql(u8, name, "f16") or
|
||||
mem.eql(u8, name, "f32") or
|
||||
mem.eql(u8, name, "f64") or
|
||||
mem.eql(u8, name, "f128") or
|
||||
mem.eql(u8, name, "c_longdouble") or
|
||||
mem.eql(u8, name, "noreturn") or
|
||||
mem.eql(u8, name, "type") or
|
||||
mem.eql(u8, name, "anyerror") or
|
||||
mem.eql(u8, name, "c_short") or
|
||||
mem.eql(u8, name, "c_ushort") or
|
||||
mem.eql(u8, name, "c_int") or
|
||||
mem.eql(u8, name, "c_uint") or
|
||||
mem.eql(u8, name, "c_long") or
|
||||
mem.eql(u8, name, "c_ulong") or
|
||||
mem.eql(u8, name, "c_longlong") or
|
||||
mem.eql(u8, name, "c_ulonglong");
|
||||
}
|
||||
|
||||
fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
|
||||
return appendTokenFmt(c, .Identifier, "{}", .{std.zig.fmtId(name)});
|
||||
}
|
||||
|
||||
fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
|
||||
const token_index = try appendIdentifier(c, name);
|
||||
const identifier = try c.arena.create(ast.Node.OneToken);
|
||||
identifier.* = .{
|
||||
.base = .{ .tag = .Identifier },
|
||||
.token = token_index,
|
||||
};
|
||||
return &identifier.base;
|
||||
}
|
||||
|
||||
fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
|
||||
const token_index = try appendTokenFmt(c, .Identifier, "{s}", .{name});
|
||||
const identifier = try c.arena.create(ast.Node.OneToken);
|
||||
identifier.* = .{
|
||||
.base = .{ .tag = .Identifier },
|
||||
.token = token_index,
|
||||
};
|
||||
return &identifier.base;
|
||||
const location_comment = std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)});
|
||||
try c.global_scope.nodes.append(try Node.warning.create(c.arena, location_comment));
|
||||
const fail_msg = std.fmt.allocPrint(c.arena, format, args);
|
||||
try c.global_scope.nodes.append(try Node.fail_decl.create(c.arena, fail_msg));
|
||||
}
|
||||
|
||||
pub fn freeErrors(errors: []ClangErrMsg) void {
|
||||
|
||||
@ -14,6 +14,10 @@ pub const Node = extern union {
|
||||
true_literal,
|
||||
false_literal,
|
||||
empty_block,
|
||||
return_void,
|
||||
zero_literal,
|
||||
void_type,
|
||||
noreturn_type,
|
||||
/// pub usingnamespace @import("std").c.builtins;
|
||||
usingnamespace_builtins,
|
||||
// After this, the tag requires a payload.
|
||||
@ -99,6 +103,7 @@ pub const Node = extern union {
|
||||
bit_or,
|
||||
bit_xor,
|
||||
|
||||
log2_int_type,
|
||||
/// @import("std").math.Log2Int(operand)
|
||||
std_math_Log2Int,
|
||||
/// @intCast(lhs, rhs)
|
||||
@ -132,7 +137,13 @@ pub const Node = extern union {
|
||||
single_pointer,
|
||||
array_type,
|
||||
|
||||
pub const last_no_payload_tag = Tag.false_literal;
|
||||
|
||||
// pub const name = @compileError(msg);
|
||||
fail_decl,
|
||||
// var actual = mangled;
|
||||
arg_redecl,
|
||||
|
||||
pub const last_no_payload_tag = Tag.usingnamespace_builtins;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
|
||||
pub fn Type(tag: Tag) ?type {
|
||||
@ -144,6 +155,10 @@ pub const Node = extern union {
|
||||
.false_litral,
|
||||
.empty_block,
|
||||
.usingnamespace_builtins,
|
||||
.return_void,
|
||||
.zero_literal,
|
||||
.void_type,
|
||||
.noreturn_type,
|
||||
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
|
||||
|
||||
.array_access,
|
||||
@ -227,6 +242,7 @@ pub const Node = extern union {
|
||||
.sizeof,
|
||||
.alignof,
|
||||
.type,
|
||||
.fail_decl,
|
||||
=> Payload.Value,
|
||||
.@"if" => Payload.If,
|
||||
.@"while" => Payload.While,
|
||||
@ -244,6 +260,8 @@ pub const Node = extern union {
|
||||
.c_pointer => Payload.Pointer,
|
||||
.single_pointer => Payload.Pointer,
|
||||
.array_type => Payload.Array,
|
||||
.arg_redecl => Payload.ArgRedecl,
|
||||
.log2_int_type => Payload.Log2IntType,
|
||||
};
|
||||
}
|
||||
|
||||
@ -265,6 +283,24 @@ pub const Node = extern union {
|
||||
return std.meta.fieldInfo(t.Type(), .data).field_type;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn tag(self: Node) Tag {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
||||
return @intToEnum(Tag, @intCast(@TagType(Tag), self.tag_if_small_enough));
|
||||
} else {
|
||||
return self.ptr_otherwise.tag;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn castTag(self: Node, comptime t: Tag) ?*t.Type() {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count)
|
||||
return null;
|
||||
|
||||
if (self.ptr_otherwise.tag == t)
|
||||
return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise);
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Payload = struct {
|
||||
@ -360,19 +396,22 @@ pub const Payload = struct {
|
||||
pub const Func = struct {
|
||||
base: Node = .{.func},
|
||||
data: struct {
|
||||
@"pub": bool,
|
||||
@"extern": bool,
|
||||
@"export": bool,
|
||||
is_pub: bool,
|
||||
is_extern: bool,
|
||||
is_export: bool,
|
||||
is_var_args: bool,
|
||||
name: []const u8,
|
||||
cc: std.builtin.CallingConvention,
|
||||
link_section_string: ?[]const u8,
|
||||
explicit_callconv: ?std.builtin.CallingConvention,
|
||||
params: []Param,
|
||||
return_type: Type,
|
||||
return_type: Node,
|
||||
body: ?Node,
|
||||
alignment: c_uint,
|
||||
|
||||
pub const Param = struct {
|
||||
@"noalias": bool,
|
||||
is_noalias: bool,
|
||||
name: ?[]const u8,
|
||||
type: Type,
|
||||
type: Node,
|
||||
};
|
||||
},
|
||||
};
|
||||
@ -449,6 +488,19 @@ pub const Payload = struct {
|
||||
is_volatile: bool,
|
||||
},
|
||||
};
|
||||
|
||||
pub const ArgRedecl = struct {
|
||||
base: Node,
|
||||
data: struct {
|
||||
actual: []const u8,
|
||||
mangled: []const u8,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Log2IntType = struct {
|
||||
base: Node,
|
||||
data: std.math.Log2Int(u64),
|
||||
};
|
||||
};
|
||||
|
||||
/// Converts the nodes into a Zig ast.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user