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 {...@@ -469,7 +469,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
469 return visitFnDecl(c, def);469 return visitFnDecl(c, def);
470 }470 }
471471
472 const rp = makeRestorePoint(c);
473 const fn_decl_loc = fn_decl.getLocation();472 const fn_decl_loc = fn_decl.getLocation();
474 const has_body = fn_decl.hasBody();473 const has_body = fn_decl.hasBody();
475 const storage_class = fn_decl.getStorageClass();474 const storage_class = fn_decl.getStorageClass();
...@@ -513,9 +512,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -513,9 +512,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
513 decl_ctx.has_body = false;512 decl_ctx.has_body = false;
514 decl_ctx.storage_class = .Extern;513 decl_ctx.storage_class = .Extern;
515 decl_ctx.is_export = false;514 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", .{});
517 }516 }
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) {
519 error.UnsupportedType => {518 error.UnsupportedType => {
520 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});519 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
521 },520 },
...@@ -524,7 +523,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -524,7 +523,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
524 },523 },
525 .FunctionNoProto => blk: {524 .FunctionNoProto => blk: {
526 const fn_no_proto_type = @ptrCast(*const clang.FunctionType, fn_type);525 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) {
528 error.UnsupportedType => {527 error.UnsupportedType => {
529 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});528 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
530 },529 },
...@@ -535,13 +534,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -535,13 +534,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
535 };534 };
536535
537 if (!decl_ctx.has_body) {536 if (!decl_ctx.has_body) {
538 const semi_tok = try appendToken(c, .Semicolon, ";");
539 return addTopLevelDecl(c, fn_name, &proto_node.base);537 return addTopLevelDecl(c, fn_name, &proto_node.base);
540 }538 }
541539
542 // actual function definition with body540 // actual function definition with body
543 const body_stmt = fn_decl.getBody();541 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);
545 block_scope.return_type = return_qt;543 block_scope.return_type = return_qt;
546 defer block_scope.deinit();544 defer block_scope.deinit();
547545
...@@ -559,34 +557,22 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -559,34 +557,22 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
559 const is_const = qual_type.isConstQualified();557 const is_const = qual_type.isConstQualified();
560558
561 const mangled_param_name = try block_scope.makeMangledName(c, param_name);559 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
560 param.name = mangled_param_name;
562561
563 if (!is_const) {562 if (!is_const) {
564 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});563 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});
565 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);564 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");567 const redecl_node = try Node.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
568 const name_tok = try appendIdentifier(c, mangled_param_name);568 try block_scope.statements.append(redecl_node);
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, ":");
583 }569 }
584570
585 param_id += 1;571 param_id += 1;
586 }572 }
587573
588 const casted_body = @ptrCast(*const clang.CompoundStmt, body_stmt);574 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) {
590 error.OutOfMemory => |e| return e,576 error.OutOfMemory => |e| return e,
591 error.UnsupportedTranslation,577 error.UnsupportedTranslation,
592 error.UnsupportedType,578 error.UnsupportedType,
...@@ -600,37 +586,31 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -600,37 +586,31 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
600 if (block_scope.statements.items.len > 0) {586 if (block_scope.statements.items.len > 0) {
601 var last = block_scope.statements.items[block_scope.statements.items.len - 1];587 var last = block_scope.statements.items[block_scope.statements.items.len - 1];
602 while (true) {588 while (true) {
603 switch (last.tag) {589 switch (last.tag()) {
604 .Block, .LabeledBlock => {590 .block => {
605 const stmts = last.blockStatements();591 const block = last.castTag(.block).?;
606 if (stmts.len == 0) break;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];
609 },595 },
610 // no extra return needed596 // no extra return needed
611 .Return => break :blk,597 .@"return", .return_void => break :blk,
612 else => break,598 else => break,
613 }599 }
614 }600 }
615 }601 }
616602
617 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{603 const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
618 .ltoken = try appendToken(rp.c, .Keyword_return, "return"),604 error.OutOfMemory => |e| return e,
619 .tag = .Return,605 error.UnsupportedTranslation,
620 }, .{606 error.UnsupportedType,
621 .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {607 => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
622 error.OutOfMemory => |e| return e,608 };
623 error.UnsupportedTranslation,609 const ret = try Node.@"return".create(c.arena, rhs);
624 error.UnsupportedType,610 try block_scope.statements.append(ret);
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);
630 }611 }
631612
632 const body_node = try block_scope.complete(rp.c);613 proto_node.body = try block_scope.complete(c);
633 proto_node.setBodyNode(body_node);
634 return addTopLevelDecl(c, fn_name, &proto_node.base);614 return addTopLevelDecl(c, fn_name, &proto_node.base);
635}615}
636616
...@@ -2440,16 +2420,16 @@ fn transInitListExpr(...@@ -2440,16 +2420,16 @@ fn transInitListExpr(
2440}2420}
24412421
2442fn transZeroInitExpr(2422fn transZeroInitExpr(
2443 rp: RestorePoint,2423 c: *Context,
2444 scope: *Scope,2424 scope: *Scope,
2445 source_loc: clang.SourceLocation,2425 source_loc: clang.SourceLocation,
2446 ty: *const clang.Type,2426 ty: *const clang.Type,
2447) TransError!*ast.Node {2427) TransError!Node {
2448 switch (ty.getTypeClass()) {2428 switch (ty.getTypeClass()) {
2449 .Builtin => {2429 .Builtin => {
2450 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);2430 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
2451 switch (builtin_ty.getKind()) {2431 switch (builtin_ty.getKind()) {
2452 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),2432 .Bool => return Node.false_literal.init(),
2453 .Char_U,2433 .Char_U,
2454 .UChar,2434 .UChar,
2455 .Char_S,2435 .Char_S,
...@@ -2470,16 +2450,16 @@ fn transZeroInitExpr(...@@ -2470,16 +2450,16 @@ fn transZeroInitExpr(
2470 .Float128,2450 .Float128,
2471 .Float16,2451 .Float16,
2472 .LongDouble,2452 .LongDouble,
2473 => return transCreateNodeInt(rp.c, 0),2453 => return Node.zero_literal.init(),
2474 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),2454 else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2475 }2455 }
2476 },2456 },
2477 .Pointer => return transCreateNodeNullLiteral(rp.c),2457 .Pointer => return Node.null_literal.init(),
2478 .Typedef => {2458 .Typedef => {
2479 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);2459 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
2480 const typedef_decl = typedef_ty.getDecl();2460 const typedef_decl = typedef_ty.getDecl();
2481 return transZeroInitExpr(2461 return transZeroInitExpr(
2482 rp,2462 c,
2483 scope,2463 scope,
2484 source_loc,2464 source_loc,
2485 typedef_decl.getUnderlyingType().getTypePtr(),2465 typedef_decl.getUnderlyingType().getTypePtr(),
...@@ -2488,7 +2468,7 @@ fn transZeroInitExpr(...@@ -2488,7 +2468,7 @@ fn transZeroInitExpr(
2488 else => {},2468 else => {},
2489 }2469 }
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", .{});
2492}2472}
24932473
2494fn transImplicitValueInitExpr(2474fn transImplicitValueInitExpr(
...@@ -3985,7 +3965,7 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc...@@ -3985,7 +3965,7 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc
3985 if (int_bit_width != 0) {3965 if (int_bit_width != 0) {
3986 // we can perform the log2 now.3966 // we can perform the log2 now.
3987 const cast_bit_width = math.log2_int(u64, int_bit_width);3967 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);
3989 }3969 }
39903970
3991 const zig_type = try transQualType(c, qt, source_loc);3971 const zig_type = try transQualType(c, qt, source_loc);
...@@ -4886,7 +4866,7 @@ const FnDeclContext = struct {...@@ -4886,7 +4866,7 @@ const FnDeclContext = struct {
4886};4866};
48874867
4888fn transCC(4868fn transCC(
4889 rp: RestorePoint,4869 c: *Context,
4890 fn_ty: *const clang.FunctionType,4870 fn_ty: *const clang.FunctionType,
4891 source_loc: clang.SourceLocation,4871 source_loc: clang.SourceLocation,
4892) !CallingConvention {4872) !CallingConvention {
...@@ -4899,7 +4879,7 @@ fn transCC(...@@ -4899,7 +4879,7 @@ fn transCC(
4899 .X86ThisCall => return CallingConvention.Thiscall,4879 .X86ThisCall => return CallingConvention.Thiscall,
4900 .AAPCS => return CallingConvention.AAPCS,4880 .AAPCS => return CallingConvention.AAPCS,
4901 .AAPCS_VFP => return CallingConvention.AAPCSVFP,4881 .AAPCS_VFP => return CallingConvention.AAPCSVFP,
4902 else => return revertAndWarn(4882 else => return fail(
4903 rp,4883 rp,
4904 error.UnsupportedType,4884 error.UnsupportedType,
4905 source_loc,4885 source_loc,
...@@ -4910,33 +4890,33 @@ fn transCC(...@@ -4910,33 +4890,33 @@ fn transCC(
4910}4890}
49114891
4912fn transFnProto(4892fn transFnProto(
4913 rp: RestorePoint,4893 c: *Context,
4914 fn_decl: ?*const clang.FunctionDecl,4894 fn_decl: ?*const clang.FunctionDecl,
4915 fn_proto_ty: *const clang.FunctionProtoType,4895 fn_proto_ty: *const clang.FunctionProtoType,
4916 source_loc: clang.SourceLocation,4896 source_loc: clang.SourceLocation,
4917 fn_decl_context: ?FnDeclContext,4897 fn_decl_context: ?FnDeclContext,
4918 is_pub: bool,4898 is_pub: bool,
4919) !*ast.Node.FnProto {4899) !Node.FnProto {
4920 const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty);4900 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);
4922 const is_var_args = fn_proto_ty.isVariadic();4902 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);
4924}4904}
49254905
4926fn transFnNoProto(4906fn transFnNoProto(
4927 rp: RestorePoint,4907 c: *Context,
4928 fn_ty: *const clang.FunctionType,4908 fn_ty: *const clang.FunctionType,
4929 source_loc: clang.SourceLocation,4909 source_loc: clang.SourceLocation,
4930 fn_decl_context: ?FnDeclContext,4910 fn_decl_context: ?FnDeclContext,
4931 is_pub: bool,4911 is_pub: bool,
4932) !*ast.Node.FnProto {4912) !Node.FnProto {
4933 const cc = try transCC(rp, fn_ty, source_loc);4913 const cc = try transCC(c, fn_ty, source_loc);
4934 const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true;4914 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);
4936}4916}
49374917
4938fn finishTransFnProto(4918fn finishTransFnProto(
4939 rp: RestorePoint,4919 c: *Context,
4940 fn_decl: ?*const clang.FunctionDecl,4920 fn_decl: ?*const clang.FunctionDecl,
4941 fn_proto_ty: ?*const clang.FunctionProtoType,4921 fn_proto_ty: ?*const clang.FunctionProtoType,
4942 fn_ty: *const clang.FunctionType,4922 fn_ty: *const clang.FunctionType,
...@@ -4945,128 +4925,77 @@ fn finishTransFnProto(...@@ -4945,128 +4925,77 @@ fn finishTransFnProto(
4945 is_var_args: bool,4925 is_var_args: bool,
4946 cc: CallingConvention,4926 cc: CallingConvention,
4947 is_pub: bool,4927 is_pub: bool,
4948) !*ast.Node.FnProto {4928) !*ast.Payload.Func {
4949 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;4929 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
4950 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;4930 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
49514931
4952 // TODO check for always_inline attribute4932 // TODO check for always_inline attribute
4953 // TODO check for align attribute4933 // TODO check for align attribute
49544934
4955 // pub extern fn name(...) T4935 var fn_params = std.ArrayList(ast.Payload.Func.Param).init(c.gpa);
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);
4968 defer fn_params.deinit();4936 defer fn_params.deinit();
4969 const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;4937 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 node4938 try fn_params.ensureCapacity(param_count);
49714939
4972 var i: usize = 0;4940 var i: usize = 0;
4973 while (i < param_count) : (i += 1) {4941 while (i < param_count) : (i += 1) {
4974 const param_qt = fn_proto_ty.?.getParamType(@intCast(c_uint, i));4942 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;4945 const param_name: ?[]const u8 =
49774946 if (fn_decl) |decl|
4978 const param_name_tok: ?ast.TokenIndex = blk: {4947 blk: {
4979 if (fn_decl) |decl| {4948 const param = decl.getParamDecl(@intCast(c_uint, i));
4980 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());
4981 const param_name: []const u8 = try rp.c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());4950 if (param_name.len < 1)
4982 if (param_name.len < 1)4951 break :blk null;
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 };
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
4994 fn_params.addOneAssumeCapacity().* = .{4957 fn_params.addOneAssumeCapacity().* = .{
4995 .doc_comments = null,4958 .is_noalias = is_noalias,
4996 .comptime_token = null,4959 .name = param_name,
4997 .noalias_token = noalias_tok,4960 .type = type_node,
4998 .name_token = param_name_tok,
4999 .param_type = .{ .type_expr = type_node },
5000 };4961 };
5001
5002 if (i + 1 < param_count) {
5003 _ = try appendToken(rp.c, .Comma, ",");
5004 }
5005 }4962 }
50064963
5007 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {4964 const link_section_string: ?[]const u8 = 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: {
5017 if (fn_decl) |decl| {4965 if (fn_decl) |decl| {
5018 var str_len: usize = undefined;4966 var str_len: usize = undefined;
5019 if (decl.getSectionAttribute(&str_len)) |str_ptr| {4967 if (decl.getSectionAttribute(&str_len)) |str_ptr| {
5020 _ = try appendToken(rp.c, .Keyword_linksection, "linksection");4968 break :blk str_ptr[0..str_len];
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;
5029 }4969 }
5030 }4970 }
5031 break :blk null;4971 break :blk null;
5032 };4972 };
50334973
5034 const align_expr = blk: {4974 const alignment: c_uint = blk: {
5035 if (fn_decl) |decl| {4975 if (fn_decl) |decl| {
5036 const alignment = decl.getAlignedAttribute(rp.c.clang_context);4976 const alignment = decl.getAlignedAttribute(c.clang_context);
5037 if (alignment != 0) {4977 if (alignment != 0) {
5038 _ = try appendToken(rp.c, .Keyword_align, "align");
5039 _ = try appendToken(rp.c, .LParen, "(");
5040 // Clang reports the alignment in bits4978 // Clang reports the alignment in bits
5041 const expr = try transCreateNodeInt(rp.c, alignment / 8);4979 break :blk alignment / 8;
5042 _ = try appendToken(rp.c, .RParen, ")");
5043
5044 break :blk expr;
5045 }4980 }
5046 }4981 }
5047 break :blk null;4982 break :blk null;
5048 };4983 };
50494984
5050 const callconv_expr = if ((is_export or is_extern) and cc == .C) null else blk: {4985 const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc;
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 };
50574986
5058 const return_type_node = blk: {4987 const return_type_node = blk: {
5059 if (fn_ty.getNoReturnAttr()) {4988 if (fn_ty.getNoReturnAttr()) {
5060 break :blk try transCreateNodeIdentifier(rp.c, "noreturn");4989 break :blk Node.noreturn_type.init();
5061 } else {4990 } else {
5062 const return_qt = fn_ty.getReturnType();4991 const return_qt = fn_ty.getReturnType();
5063 if (isCVoid(return_qt)) {4992 if (isCVoid(return_qt)) {
5064 // convert primitive c_void to actual void (only for return type)4993 // 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();
5066 } else {4995 } 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) {
5068 error.UnsupportedType => {4997 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", .{});
5070 return err;4999 return err;
5071 },5000 },
5072 error.OutOfMemory => |e| return e,5001 error.OutOfMemory => |e| return e,
...@@ -5075,32 +5004,23 @@ fn finishTransFnProto(...@@ -5075,32 +5004,23 @@ fn finishTransFnProto(
5075 }5004 }
5076 };5005 };
50775006
5078 // We need to reserve an undefined (but non-null) body node to set later.5007 const fn_proto = try c.arena.create(ast.Payload.Func);
5079 var body_node: ?*ast.Node = null;5008 fn_proto.* = .{
5080 if (fn_decl_context) |ctx| {5009 .base = .{ .tag = .func },
5081 if (ctx.has_body) {5010 .data = .{
5082 // TODO: we should be able to use undefined here but5011 .is_pub = is_pub,
5083 // it causes a bug. This is undefined without zig language5012 .is_extern = is_extern,
5084 // being aware of it.5013 .is_export = is_export,
5085 body_node = @intToPtr(*ast.Node, 0x08);5014 .is_var_args = is_var_args,
5086 }5015 .name = name,
5087 }5016 .link_section_string = link_section_string,
50885017 .explicit_callconv = explicit_callconv,
5089 const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{5018 .params = c.arena.dupe(ast.Payload.Func.Param, fn_params.items),
5090 .params_len = fn_params.items.len,5019 .return_type = return_node,
5091 .return_type = .{ .Explicit = return_type_node },5020 .body = null,
5092 .fn_token = fn_tok,5021 .alignment = alignment,
5093 }, .{5022 },
5094 .visib_token = pub_tok,5023 };
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);
5104 return fn_proto;5024 return fn_proto;
5105}5025}
51065026
...@@ -5122,124 +5042,12 @@ fn fail(...@@ -5122,124 +5042,12 @@ fn fail(
5122}5042}
51235043
5124pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void {5044pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void {
5045 // location
5125 // pub const name = @compileError(msg);5046 // pub const name = @compileError(msg);
5126 const pub_tok = try appendToken(c, .Keyword_pub, "pub");5047 const location_comment = std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)});
5127 const const_tok = try appendToken(c, .Keyword_const, "const");5048 try c.global_scope.nodes.append(try Node.warning.create(c.arena, location_comment));
5128 const name_tok = try appendIdentifier(c, name);5049 const fail_msg = std.fmt.allocPrint(c.arena, format, args);
5129 const eq_tok = try appendToken(c, .Equal, "=");5050 try c.global_scope.nodes.append(try Node.fail_decl.create(c.arena, fail_msg));
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;
5243}5051}
52445052
5245pub fn freeErrors(errors: []ClangErrMsg) void {5053pub fn freeErrors(errors: []ClangErrMsg) void {
src/translate_c/ast.zig+60-8
...@@ -14,6 +14,10 @@ pub const Node = extern union {...@@ -14,6 +14,10 @@ pub const Node = extern union {
14 true_literal,14 true_literal,
15 false_literal,15 false_literal,
16 empty_block,16 empty_block,
17 return_void,
18 zero_literal,
19 void_type,
20 noreturn_type,
17 /// pub usingnamespace @import("std").c.builtins;21 /// pub usingnamespace @import("std").c.builtins;
18 usingnamespace_builtins,22 usingnamespace_builtins,
19 // After this, the tag requires a payload.23 // After this, the tag requires a payload.
...@@ -99,6 +103,7 @@ pub const Node = extern union {...@@ -99,6 +103,7 @@ pub const Node = extern union {
99 bit_or,103 bit_or,
100 bit_xor,104 bit_xor,
101105
106 log2_int_type,
102 /// @import("std").math.Log2Int(operand)107 /// @import("std").math.Log2Int(operand)
103 std_math_Log2Int,108 std_math_Log2Int,
104 /// @intCast(lhs, rhs)109 /// @intCast(lhs, rhs)
...@@ -132,7 +137,13 @@ pub const Node = extern union {...@@ -132,7 +137,13 @@ pub const Node = extern union {
132 single_pointer,137 single_pointer,
133 array_type,138 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;
136 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;147 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
137148
138 pub fn Type(tag: Tag) ?type {149 pub fn Type(tag: Tag) ?type {
...@@ -144,6 +155,10 @@ pub const Node = extern union {...@@ -144,6 +155,10 @@ pub const Node = extern union {
144 .false_litral,155 .false_litral,
145 .empty_block,156 .empty_block,
146 .usingnamespace_builtins,157 .usingnamespace_builtins,
158 .return_void,
159 .zero_literal,
160 .void_type,
161 .noreturn_type,
147 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),162 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
148163
149 .array_access,164 .array_access,
...@@ -227,6 +242,7 @@ pub const Node = extern union {...@@ -227,6 +242,7 @@ pub const Node = extern union {
227 .sizeof,242 .sizeof,
228 .alignof,243 .alignof,
229 .type,244 .type,
245 .fail_decl,
230 => Payload.Value,246 => Payload.Value,
231 .@"if" => Payload.If,247 .@"if" => Payload.If,
232 .@"while" => Payload.While,248 .@"while" => Payload.While,
...@@ -244,6 +260,8 @@ pub const Node = extern union {...@@ -244,6 +260,8 @@ pub const Node = extern union {
244 .c_pointer => Payload.Pointer,260 .c_pointer => Payload.Pointer,
245 .single_pointer => Payload.Pointer,261 .single_pointer => Payload.Pointer,
246 .array_type => Payload.Array,262 .array_type => Payload.Array,
263 .arg_redecl => Payload.ArgRedecl,
264 .log2_int_type => Payload.Log2IntType,
247 };265 };
248 }266 }
249267
...@@ -265,6 +283,24 @@ pub const Node = extern union {...@@ -265,6 +283,24 @@ pub const Node = extern union {
265 return std.meta.fieldInfo(t.Type(), .data).field_type;283 return std.meta.fieldInfo(t.Type(), .data).field_type;
266 }284 }
267 };285 };
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 }
268};304};
269305
270pub const Payload = struct {306pub const Payload = struct {
...@@ -360,19 +396,22 @@ pub const Payload = struct {...@@ -360,19 +396,22 @@ pub const Payload = struct {
360 pub const Func = struct {396 pub const Func = struct {
361 base: Node = .{.func},397 base: Node = .{.func},
362 data: struct {398 data: struct {
363 @"pub": bool,399 is_pub: bool,
364 @"extern": bool,400 is_extern: bool,
365 @"export": bool,401 is_export: bool,
402 is_var_args: bool,
366 name: []const u8,403 name: []const u8,
367 cc: std.builtin.CallingConvention,404 link_section_string: ?[]const u8,
405 explicit_callconv: ?std.builtin.CallingConvention,
368 params: []Param,406 params: []Param,
369 return_type: Type,407 return_type: Node,
370 body: ?Node,408 body: ?Node,
409 alignment: c_uint,
371410
372 pub const Param = struct {411 pub const Param = struct {
373 @"noalias": bool,412 is_noalias: bool,
374 name: ?[]const u8,413 name: ?[]const u8,
375 type: Type,414 type: Node,
376 };415 };
377 },416 },
378 };417 };
...@@ -449,6 +488,19 @@ pub const Payload = struct {...@@ -449,6 +488,19 @@ pub const Payload = struct {
449 is_volatile: bool,488 is_volatile: bool,
450 },489 },
451 };490 };
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 };
452};504};
453505
454/// Converts the nodes into a Zig ast.506/// Converts the nodes into a Zig ast.