authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-07 23:13:40+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:37:08+02:00
logf36849fed24b54476ecadacb52d9a1b55ae14274
treefcbd3b09f84b36b76ebf3a960cdb86fe62ac91b8
parent7514c0ad0d327d2427009c26e5930540297e396e
signature Commit is signed but in an unrecognized format.

translate-c: convert function translation


2 files changed, 153 insertions(+), 293 deletions(-)

src/translate_c.zig+93-285
......@@ -469,7 +469,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
469469 return visitFnDecl(c, def);
470470 }
471471
472 const rp = makeRestorePoint(c);
473472 const fn_decl_loc = fn_decl.getLocation();
474473 const has_body = fn_decl.hasBody();
475474 const storage_class = fn_decl.getStorageClass();
......@@ -513,9 +512,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
513512 decl_ctx.has_body = false;
514513 decl_ctx.storage_class = .Extern;
515514 decl_ctx.is_export = false;
516 try emitWarning(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{});
515 try warn(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{});
517516 }
518 break :blk transFnProto(rp, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
517 break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
519518 error.UnsupportedType => {
520519 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
521520 },
......@@ -524,7 +523,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
524523 },
525524 .FunctionNoProto => blk: {
526525 const fn_no_proto_type = @ptrCast(*const clang.FunctionType, fn_type);
527 break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
526 break :blk transFnNoProto(c, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
528527 error.UnsupportedType => {
529528 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
530529 },
......@@ -535,13 +534,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
535534 };
536535
537536 if (!decl_ctx.has_body) {
538 const semi_tok = try appendToken(c, .Semicolon, ";");
539537 return addTopLevelDecl(c, fn_name, &proto_node.base);
540538 }
541539
542540 // actual function definition with body
543541 const body_stmt = fn_decl.getBody();
544 var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false);
542 var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
545543 block_scope.return_type = return_qt;
546544 defer block_scope.deinit();
547545
......@@ -559,34 +557,22 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
559557 const is_const = qual_type.isConstQualified();
560558
561559 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
560 param.name = mangled_param_name;
562561
563562 if (!is_const) {
564563 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});
565564 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
565 param.name = arg_name;
566566
567 const mut_tok = try appendToken(c, .Keyword_var, "var");
568 const name_tok = try appendIdentifier(c, mangled_param_name);
569 const eq_token = try appendToken(c, .Equal, "=");
570 const init_node = try transCreateNodeIdentifier(c, arg_name);
571 const semicolon_token = try appendToken(c, .Semicolon, ";");
572 const node = try ast.Node.VarDecl.create(c.arena, .{
573 .mut_token = mut_tok,
574 .name_token = name_tok,
575 .semicolon_token = semicolon_token,
576 }, .{
577 .eq_token = eq_token,
578 .init_node = init_node,
579 });
580 try block_scope.statements.append(&node.base);
581 param.name_token = try appendIdentifier(c, arg_name);
582 _ = try appendToken(c, .Colon, ":");
567 const redecl_node = try Node.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
568 try block_scope.statements.append(redecl_node);
583569 }
584570
585571 param_id += 1;
586572 }
587573
588574 const casted_body = @ptrCast(*const clang.CompoundStmt, body_stmt);
589 transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) {
575 transCompoundStmtInline(c, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) {
590576 error.OutOfMemory => |e| return e,
591577 error.UnsupportedTranslation,
592578 error.UnsupportedType,
......@@ -600,37 +586,31 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
600586 if (block_scope.statements.items.len > 0) {
601587 var last = block_scope.statements.items[block_scope.statements.items.len - 1];
602588 while (true) {
603 switch (last.tag) {
604 .Block, .LabeledBlock => {
605 const stmts = last.blockStatements();
606 if (stmts.len == 0) break;
589 switch (last.tag()) {
590 .block => {
591 const block = last.castTag(.block).?;
592 if (block.data.stmts.len == 0) break;
607593
608 last = stmts[stmts.len - 1];
594 last = block.data.stmts[block.data.stmts.len - 1];
609595 },
610596 // no extra return needed
611 .Return => break :blk,
597 .@"return", .return_void => break :blk,
612598 else => break,
613599 }
614600 }
615601 }
616602
617 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
618 .ltoken = try appendToken(rp.c, .Keyword_return, "return"),
619 .tag = .Return,
620 }, .{
621 .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
622 error.OutOfMemory => |e| return e,
623 error.UnsupportedTranslation,
624 error.UnsupportedType,
625 => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
626 },
627 });
628 _ = try appendToken(rp.c, .Semicolon, ";");
629 try block_scope.statements.append(&return_expr.base);
603 const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
604 error.OutOfMemory => |e| return e,
605 error.UnsupportedTranslation,
606 error.UnsupportedType,
607 => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
608 };
609 const ret = try Node.@"return".create(c.arena, rhs);
610 try block_scope.statements.append(ret);
630611 }
631612
632 const body_node = try block_scope.complete(rp.c);
633 proto_node.setBodyNode(body_node);
613 proto_node.body = try block_scope.complete(c);
634614 return addTopLevelDecl(c, fn_name, &proto_node.base);
635615}
636616
......@@ -2440,16 +2420,16 @@ fn transInitListExpr(
24402420}
24412421
24422422fn transZeroInitExpr(
2443 rp: RestorePoint,
2423 c: *Context,
24442424 scope: *Scope,
24452425 source_loc: clang.SourceLocation,
24462426 ty: *const clang.Type,
2447) TransError!*ast.Node {
2427) TransError!Node {
24482428 switch (ty.getTypeClass()) {
24492429 .Builtin => {
24502430 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
24512431 switch (builtin_ty.getKind()) {
2452 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),
2432 .Bool => return Node.false_literal.init(),
24532433 .Char_U,
24542434 .UChar,
24552435 .Char_S,
......@@ -2470,16 +2450,16 @@ fn transZeroInitExpr(
24702450 .Float128,
24712451 .Float16,
24722452 .LongDouble,
2473 => return transCreateNodeInt(rp.c, 0),
2474 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2453 => return Node.zero_literal.init(),
2454 else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
24752455 }
24762456 },
2477 .Pointer => return transCreateNodeNullLiteral(rp.c),
2457 .Pointer => return Node.null_literal.init(),
24782458 .Typedef => {
24792459 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
24802460 const typedef_decl = typedef_ty.getDecl();
24812461 return transZeroInitExpr(
2482 rp,
2462 c,
24832463 scope,
24842464 source_loc,
24852465 typedef_decl.getUnderlyingType().getTypePtr(),
......@@ -2488,7 +2468,7 @@ fn transZeroInitExpr(
24882468 else => {},
24892469 }
24902470
2491 return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
2471 return fail(c, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
24922472}
24932473
24942474fn transImplicitValueInitExpr(
......@@ -3985,7 +3965,7 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc
39853965 if (int_bit_width != 0) {
39863966 // we can perform the log2 now.
39873967 const cast_bit_width = math.log2_int(u64, int_bit_width);
3988 return Node.uint_type.create(c.arena, cast_bit_width);
3968 return Node.log2_int_type.create(c.arena, cast_bit_width);
39893969 }
39903970
39913971 const zig_type = try transQualType(c, qt, source_loc);
......@@ -4886,7 +4866,7 @@ const FnDeclContext = struct {
48864866};
48874867
48884868fn transCC(
4889 rp: RestorePoint,
4869 c: *Context,
48904870 fn_ty: *const clang.FunctionType,
48914871 source_loc: clang.SourceLocation,
48924872) !CallingConvention {
......@@ -4899,7 +4879,7 @@ fn transCC(
48994879 .X86ThisCall => return CallingConvention.Thiscall,
49004880 .AAPCS => return CallingConvention.AAPCS,
49014881 .AAPCS_VFP => return CallingConvention.AAPCSVFP,
4902 else => return revertAndWarn(
4882 else => return fail(
49034883 rp,
49044884 error.UnsupportedType,
49054885 source_loc,
......@@ -4910,33 +4890,33 @@ fn transCC(
49104890}
49114891
49124892fn transFnProto(
4913 rp: RestorePoint,
4893 c: *Context,
49144894 fn_decl: ?*const clang.FunctionDecl,
49154895 fn_proto_ty: *const clang.FunctionProtoType,
49164896 source_loc: clang.SourceLocation,
49174897 fn_decl_context: ?FnDeclContext,
49184898 is_pub: bool,
4919) !*ast.Node.FnProto {
4899) !Node.FnProto {
49204900 const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty);
4921 const cc = try transCC(rp, fn_ty, source_loc);
4901 const cc = try transCC(c, fn_ty, source_loc);
49224902 const is_var_args = fn_proto_ty.isVariadic();
4923 return finishTransFnProto(rp, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
4903 return finishTransFnProto(c, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
49244904}
49254905
49264906fn transFnNoProto(
4927 rp: RestorePoint,
4907 c: *Context,
49284908 fn_ty: *const clang.FunctionType,
49294909 source_loc: clang.SourceLocation,
49304910 fn_decl_context: ?FnDeclContext,
49314911 is_pub: bool,
4932) !*ast.Node.FnProto {
4933 const cc = try transCC(rp, fn_ty, source_loc);
4912) !Node.FnProto {
4913 const cc = try transCC(c, fn_ty, source_loc);
49344914 const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true;
4935 return finishTransFnProto(rp, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
4915 return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
49364916}
49374917
49384918fn finishTransFnProto(
4939 rp: RestorePoint,
4919 c: *Context,
49404920 fn_decl: ?*const clang.FunctionDecl,
49414921 fn_proto_ty: ?*const clang.FunctionProtoType,
49424922 fn_ty: *const clang.FunctionType,
......@@ -4945,128 +4925,77 @@ fn finishTransFnProto(
49454925 is_var_args: bool,
49464926 cc: CallingConvention,
49474927 is_pub: bool,
4948) !*ast.Node.FnProto {
4928) !*ast.Payload.Func {
49494929 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
49504930 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
49514931
49524932 // TODO check for always_inline attribute
49534933 // TODO check for align attribute
49544934
4955 // pub extern fn name(...) T
4956 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
4957 const extern_export_inline_tok = if (is_export)
4958 try appendToken(rp.c, .Keyword_export, "export")
4959 else if (is_extern)
4960 try appendToken(rp.c, .Keyword_extern, "extern")
4961 else
4962 null;
4963 const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
4964 const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;
4965 const lparen_tok = try appendToken(rp.c, .LParen, "(");
4966
4967 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(rp.c.gpa);
4935 var fn_params = std.ArrayList(ast.Payload.Func.Param).init(c.gpa);
49684936 defer fn_params.deinit();
49694937 const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;
4970 try fn_params.ensureCapacity(param_count + 1); // +1 for possible var args node
4938 try fn_params.ensureCapacity(param_count);
49714939
49724940 var i: usize = 0;
49734941 while (i < param_count) : (i += 1) {
49744942 const param_qt = fn_proto_ty.?.getParamType(@intCast(c_uint, i));
4943 const is_noalias = param_qt.isRestrictQualified();
49754944
4976 const noalias_tok = if (param_qt.isRestrictQualified()) try appendToken(rp.c, .Keyword_noalias, "noalias") else null;
4977
4978 const param_name_tok: ?ast.TokenIndex = blk: {
4979 if (fn_decl) |decl| {
4980 const param = decl.getParamDecl(@intCast(c_uint, i));
4981 const param_name: []const u8 = try rp.c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());
4982 if (param_name.len < 1)
4983 break :blk null;
4984
4985 const result = try appendIdentifier(rp.c, param_name);
4986 _ = try appendToken(rp.c, .Colon, ":");
4987 break :blk result;
4988 }
4989 break :blk null;
4990 };
4945 const param_name: ?[]const u8 =
4946 if (fn_decl) |decl|
4947 blk: {
4948 const param = decl.getParamDecl(@intCast(c_uint, i));
4949 const param_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());
4950 if (param_name.len < 1)
4951 break :blk null;
49914952
4992 const type_node = try transQualType(rp, param_qt, source_loc);
4953 break :blk param_name;
4954 } else null;
4955 const type_node = try transQualType(c, param_qt, source_loc);
49934956
49944957 fn_params.addOneAssumeCapacity().* = .{
4995 .doc_comments = null,
4996 .comptime_token = null,
4997 .noalias_token = noalias_tok,
4998 .name_token = param_name_tok,
4999 .param_type = .{ .type_expr = type_node },
4958 .is_noalias = is_noalias,
4959 .name = param_name,
4960 .type = type_node,
50004961 };
5001
5002 if (i + 1 < param_count) {
5003 _ = try appendToken(rp.c, .Comma, ",");
5004 }
50054962 }
50064963
5007 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
5008 if (param_count > 0) {
5009 _ = try appendToken(rp.c, .Comma, ",");
5010 }
5011 break :blk try appendToken(rp.c, .Ellipsis3, "...");
5012 } else null;
5013
5014 const rparen_tok = try appendToken(rp.c, .RParen, ")");
5015
5016 const linksection_expr = blk: {
4964 const link_section_string: ?[]const u8 = blk: {
50174965 if (fn_decl) |decl| {
50184966 var str_len: usize = undefined;
50194967 if (decl.getSectionAttribute(&str_len)) |str_ptr| {
5020 _ = try appendToken(rp.c, .Keyword_linksection, "linksection");
5021 _ = try appendToken(rp.c, .LParen, "(");
5022 const expr = try transCreateNodeStringLiteral(
5023 rp.c,
5024 try std.fmt.allocPrint(rp.c.arena, "\"{s}\"", .{str_ptr[0..str_len]}),
5025 );
5026 _ = try appendToken(rp.c, .RParen, ")");
5027
5028 break :blk expr;
4968 break :blk str_ptr[0..str_len];
50294969 }
50304970 }
50314971 break :blk null;
50324972 };
50334973
5034 const align_expr = blk: {
4974 const alignment: c_uint = blk: {
50354975 if (fn_decl) |decl| {
5036 const alignment = decl.getAlignedAttribute(rp.c.clang_context);
4976 const alignment = decl.getAlignedAttribute(c.clang_context);
50374977 if (alignment != 0) {
5038 _ = try appendToken(rp.c, .Keyword_align, "align");
5039 _ = try appendToken(rp.c, .LParen, "(");
50404978 // Clang reports the alignment in bits
5041 const expr = try transCreateNodeInt(rp.c, alignment / 8);
5042 _ = try appendToken(rp.c, .RParen, ")");
5043
5044 break :blk expr;
4979 break :blk alignment / 8;
50454980 }
50464981 }
50474982 break :blk null;
50484983 };
50494984
5050 const callconv_expr = if ((is_export or is_extern) and cc == .C) null else blk: {
5051 _ = try appendToken(rp.c, .Keyword_callconv, "callconv");
5052 _ = try appendToken(rp.c, .LParen, "(");
5053 const expr = try transCreateNodeEnumLiteral(rp.c, @tagName(cc));
5054 _ = try appendToken(rp.c, .RParen, ")");
5055 break :blk expr;
5056 };
4985 const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc;
50574986
50584987 const return_type_node = blk: {
50594988 if (fn_ty.getNoReturnAttr()) {
5060 break :blk try transCreateNodeIdentifier(rp.c, "noreturn");
4989 break :blk Node.noreturn_type.init();
50614990 } else {
50624991 const return_qt = fn_ty.getReturnType();
50634992 if (isCVoid(return_qt)) {
50644993 // convert primitive c_void to actual void (only for return type)
5065 break :blk try transCreateNodeIdentifier(rp.c, "void");
4994 break :blk Node.void_type.init();
50664995 } else {
5067 break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
4996 break :blk transQualType(c, return_qt, source_loc) catch |err| switch (err) {
50684997 error.UnsupportedType => {
5069 try emitWarning(rp.c, source_loc, "unsupported function proto return type", .{});
4998 try warn(c, source_loc, "unsupported function proto return type", .{});
50704999 return err;
50715000 },
50725001 error.OutOfMemory => |e| return e,
......@@ -5075,32 +5004,23 @@ fn finishTransFnProto(
50755004 }
50765005 };
50775006
5078 // We need to reserve an undefined (but non-null) body node to set later.
5079 var body_node: ?*ast.Node = null;
5080 if (fn_decl_context) |ctx| {
5081 if (ctx.has_body) {
5082 // TODO: we should be able to use undefined here but
5083 // it causes a bug. This is undefined without zig language
5084 // being aware of it.
5085 body_node = @intToPtr(*ast.Node, 0x08);
5086 }
5087 }
5088
5089 const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{
5090 .params_len = fn_params.items.len,
5091 .return_type = .{ .Explicit = return_type_node },
5092 .fn_token = fn_tok,
5093 }, .{
5094 .visib_token = pub_tok,
5095 .name_token = name_tok,
5096 .extern_export_inline_token = extern_export_inline_tok,
5097 .align_expr = align_expr,
5098 .section_expr = linksection_expr,
5099 .callconv_expr = callconv_expr,
5100 .body_node = body_node,
5101 .var_args_token = var_args_token,
5102 });
5103 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5007 const fn_proto = try c.arena.create(ast.Payload.Func);
5008 fn_proto.* = .{
5009 .base = .{ .tag = .func },
5010 .data = .{
5011 .is_pub = is_pub,
5012 .is_extern = is_extern,
5013 .is_export = is_export,
5014 .is_var_args = is_var_args,
5015 .name = name,
5016 .link_section_string = link_section_string,
5017 .explicit_callconv = explicit_callconv,
5018 .params = c.arena.dupe(ast.Payload.Func.Param, fn_params.items),
5019 .return_type = return_node,
5020 .body = null,
5021 .alignment = alignment,
5022 },
5023 };
51045024 return fn_proto;
51055025}
51065026
......@@ -5122,124 +5042,12 @@ fn fail(
51225042}
51235043
51245044pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void {
5045 // location
51255046 // pub const name = @compileError(msg);
5126 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
5127 const const_tok = try appendToken(c, .Keyword_const, "const");
5128 const name_tok = try appendIdentifier(c, name);
5129 const eq_tok = try appendToken(c, .Equal, "=");
5130 const builtin_tok = try appendToken(c, .Builtin, "@compileError");
5131 const lparen_tok = try appendToken(c, .LParen, "(");
5132 const msg_tok = try appendTokenFmt(c, .StringLiteral, "\"" ++ format ++ "\"", args);
5133 const rparen_tok = try appendToken(c, .RParen, ")");
5134 const semi_tok = try appendToken(c, .Semicolon, ";");
5135 _ = try appendTokenFmt(c, .LineComment, "// {s}", .{c.locStr(loc)});
5136
5137 const msg_node = try c.arena.create(ast.Node.OneToken);
5138 msg_node.* = .{
5139 .base = .{ .tag = .StringLiteral },
5140 .token = msg_tok,
5141 };
5142
5143 const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
5144 call_node.* = .{
5145 .builtin_token = builtin_tok,
5146 .params_len = 1,
5147 .rparen_token = rparen_tok,
5148 };
5149 call_node.params()[0] = &msg_node.base;
5150
5151 const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
5152 .name_token = name_tok,
5153 .mut_token = const_tok,
5154 .semicolon_token = semi_tok,
5155 }, .{
5156 .visib_token = pub_tok,
5157 .eq_token = eq_tok,
5158 .init_node = &call_node.base,
5159 });
5160 try addTopLevelDecl(c, name, &var_decl_node.base);
5161}
5162
5163fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex {
5164 std.debug.assert(token_id != .Identifier); // use appendIdentifier
5165 return appendTokenFmt(c, token_id, "{s}", .{bytes});
5166}
5167
5168fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: anytype) !ast.TokenIndex {
5169 assert(token_id != .Invalid);
5170
5171 try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1);
5172 try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1);
5173
5174 const start_index = c.source_buffer.items.len;
5175 try c.source_buffer.writer().print(format ++ " ", args);
5176
5177 c.token_ids.appendAssumeCapacity(token_id);
5178 c.token_locs.appendAssumeCapacity(.{
5179 .start = start_index,
5180 .end = c.source_buffer.items.len - 1, // back up before the space
5181 });
5182
5183 return c.token_ids.items.len - 1;
5184}
5185
5186// TODO hook up with codegen
5187fn isZigPrimitiveType(name: []const u8) bool {
5188 if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
5189 for (name[1..]) |c| {
5190 switch (c) {
5191 '0'...'9' => {},
5192 else => return false,
5193 }
5194 }
5195 return true;
5196 }
5197 // void is invalid in c so it doesn't need to be checked.
5198 return mem.eql(u8, name, "comptime_float") or
5199 mem.eql(u8, name, "comptime_int") or
5200 mem.eql(u8, name, "bool") or
5201 mem.eql(u8, name, "isize") or
5202 mem.eql(u8, name, "usize") or
5203 mem.eql(u8, name, "f16") or
5204 mem.eql(u8, name, "f32") or
5205 mem.eql(u8, name, "f64") or
5206 mem.eql(u8, name, "f128") or
5207 mem.eql(u8, name, "c_longdouble") or
5208 mem.eql(u8, name, "noreturn") or
5209 mem.eql(u8, name, "type") or
5210 mem.eql(u8, name, "anyerror") or
5211 mem.eql(u8, name, "c_short") or
5212 mem.eql(u8, name, "c_ushort") or
5213 mem.eql(u8, name, "c_int") or
5214 mem.eql(u8, name, "c_uint") or
5215 mem.eql(u8, name, "c_long") or
5216 mem.eql(u8, name, "c_ulong") or
5217 mem.eql(u8, name, "c_longlong") or
5218 mem.eql(u8, name, "c_ulonglong");
5219}
5220
5221fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
5222 return appendTokenFmt(c, .Identifier, "{}", .{std.zig.fmtId(name)});
5223}
5224
5225fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
5226 const token_index = try appendIdentifier(c, name);
5227 const identifier = try c.arena.create(ast.Node.OneToken);
5228 identifier.* = .{
5229 .base = .{ .tag = .Identifier },
5230 .token = token_index,
5231 };
5232 return &identifier.base;
5233}
5234
5235fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
5236 const token_index = try appendTokenFmt(c, .Identifier, "{s}", .{name});
5237 const identifier = try c.arena.create(ast.Node.OneToken);
5238 identifier.* = .{
5239 .base = .{ .tag = .Identifier },
5240 .token = token_index,
5241 };
5242 return &identifier.base;
5047 const location_comment = std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)});
5048 try c.global_scope.nodes.append(try Node.warning.create(c.arena, location_comment));
5049 const fail_msg = std.fmt.allocPrint(c.arena, format, args);
5050 try c.global_scope.nodes.append(try Node.fail_decl.create(c.arena, fail_msg));
52435051}
52445052
52455053pub fn freeErrors(errors: []ClangErrMsg) void {
src/translate_c/ast.zig+60-8
......@@ -14,6 +14,10 @@ pub const Node = extern union {
1414 true_literal,
1515 false_literal,
1616 empty_block,
17 return_void,
18 zero_literal,
19 void_type,
20 noreturn_type,
1721 /// pub usingnamespace @import("std").c.builtins;
1822 usingnamespace_builtins,
1923 // After this, the tag requires a payload.
......@@ -99,6 +103,7 @@ pub const Node = extern union {
99103 bit_or,
100104 bit_xor,
101105
106 log2_int_type,
102107 /// @import("std").math.Log2Int(operand)
103108 std_math_Log2Int,
104109 /// @intCast(lhs, rhs)
......@@ -132,7 +137,13 @@ pub const Node = extern union {
132137 single_pointer,
133138 array_type,
134139
135 pub const last_no_payload_tag = Tag.false_literal;
140
141 // pub const name = @compileError(msg);
142 fail_decl,
143 // var actual = mangled;
144 arg_redecl,
145
146 pub const last_no_payload_tag = Tag.usingnamespace_builtins;
136147 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
137148
138149 pub fn Type(tag: Tag) ?type {
......@@ -144,6 +155,10 @@ pub const Node = extern union {
144155 .false_litral,
145156 .empty_block,
146157 .usingnamespace_builtins,
158 .return_void,
159 .zero_literal,
160 .void_type,
161 .noreturn_type,
147162 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
148163
149164 .array_access,
......@@ -227,6 +242,7 @@ pub const Node = extern union {
227242 .sizeof,
228243 .alignof,
229244 .type,
245 .fail_decl,
230246 => Payload.Value,
231247 .@"if" => Payload.If,
232248 .@"while" => Payload.While,
......@@ -244,6 +260,8 @@ pub const Node = extern union {
244260 .c_pointer => Payload.Pointer,
245261 .single_pointer => Payload.Pointer,
246262 .array_type => Payload.Array,
263 .arg_redecl => Payload.ArgRedecl,
264 .log2_int_type => Payload.Log2IntType,
247265 };
248266 }
249267
......@@ -265,6 +283,24 @@ pub const Node = extern union {
265283 return std.meta.fieldInfo(t.Type(), .data).field_type;
266284 }
267285 };
286
287 pub fn tag(self: Node) Tag {
288 if (self.tag_if_small_enough < Tag.no_payload_count) {
289 return @intToEnum(Tag, @intCast(@TagType(Tag), self.tag_if_small_enough));
290 } else {
291 return self.ptr_otherwise.tag;
292 }
293 }
294
295 pub fn castTag(self: Node, comptime t: Tag) ?*t.Type() {
296 if (self.tag_if_small_enough < Tag.no_payload_count)
297 return null;
298
299 if (self.ptr_otherwise.tag == t)
300 return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise);
301
302 return null;
303 }
268304};
269305
270306pub const Payload = struct {
......@@ -360,19 +396,22 @@ pub const Payload = struct {
360396 pub const Func = struct {
361397 base: Node = .{.func},
362398 data: struct {
363 @"pub": bool,
364 @"extern": bool,
365 @"export": bool,
399 is_pub: bool,
400 is_extern: bool,
401 is_export: bool,
402 is_var_args: bool,
366403 name: []const u8,
367 cc: std.builtin.CallingConvention,
404 link_section_string: ?[]const u8,
405 explicit_callconv: ?std.builtin.CallingConvention,
368406 params: []Param,
369 return_type: Type,
407 return_type: Node,
370408 body: ?Node,
409 alignment: c_uint,
371410
372411 pub const Param = struct {
373 @"noalias": bool,
412 is_noalias: bool,
374413 name: ?[]const u8,
375 type: Type,
414 type: Node,
376415 };
377416 },
378417 };
......@@ -449,6 +488,19 @@ pub const Payload = struct {
449488 is_volatile: bool,
450489 },
451490 };
491
492 pub const ArgRedecl = struct {
493 base: Node,
494 data: struct {
495 actual: []const u8,
496 mangled: []const u8,
497 },
498 };
499
500 pub const Log2IntType = struct {
501 base: Node,
502 data: std.math.Log2Int(u64),
503 };
452504};
453505
454506/// Converts the nodes into a Zig ast.