| ... | @@ -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 | } |
| 471 | | 471 | |
| 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 | }; |
| 536 | | 535 | |
| 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 | } |
| 541 | | 539 | |
| 542 | // actual function definition with body | 540 | // 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(); |
| 547 | | 545 | |
| ... | @@ -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(); |
| 560 | | 558 | |
| 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; |
| 562 | | 561 | |
| 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; |
| 566 | | 566 | |
| 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 | } |
| 584 | | 570 | |
| 585 | param_id += 1; | 571 | param_id += 1; |
| 586 | } | 572 | } |
| 587 | | 573 | |
| 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; |
| 607 | | 593 | |
| 608 | last = stmts[stmts.len - 1]; | 594 | last = block.data.stmts[block.data.stmts.len - 1]; |
| 609 | }, | 595 | }, |
| 610 | // no extra return needed | 596 | // 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 | } |
| 616 | | 602 | |
| 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 | } |
| 631 | | 612 | |
| 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 | } |
| 636 | | 616 | |
| ... | @@ -2440,16 +2420,16 @@ fn transInitListExpr( | ... | @@ -2440,16 +2420,16 @@ fn transInitListExpr( |
| 2440 | } | 2420 | } |
| 2441 | | 2421 | |
| 2442 | fn transZeroInitExpr( | 2422 | fn 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 | } |
| 2490 | | 2470 | |
| 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 | } |
| 2493 | | 2473 | |
| 2494 | fn transImplicitValueInitExpr( | 2474 | fn 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 | } |
| 3990 | | 3970 | |
| 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 | }; |
| 4887 | | 4867 | |
| 4888 | fn transCC( | 4868 | fn 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 | } |
| 4911 | | 4891 | |
| 4912 | fn transFnProto( | 4892 | fn 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 | } |
| 4925 | | 4905 | |
| 4926 | fn transFnNoProto( | 4906 | fn 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 | } |
| 4937 | | 4917 | |
| 4938 | fn finishTransFnProto( | 4918 | fn 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; |
| 4951 | | 4931 | |
| 4952 | // TODO check for always_inline attribute | 4932 | // TODO check for always_inline attribute |
| 4953 | // TODO check for align attribute | 4933 | // TODO check for align attribute |
| 4954 | | 4934 | |
| 4955 | // pub extern fn name(...) T | 4935 | 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 node | 4938 | try fn_params.ensureCapacity(param_count); |
| 4971 | | 4939 | |
| 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(); |
| 4975 | | 4944 | |
| 4976 | const noalias_tok = if (param_qt.isRestrictQualified()) try appendToken(rp.c, .Keyword_noalias, "noalias") else null; | 4945 | const param_name: ?[]const u8 = |
| 4977 | | 4946 | 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 | }; | | |
| 4991 | | 4952 | |
| 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); |
| 4993 | | 4956 | |
| 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 | } |
| 5006 | | 4963 | |
| 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 | }; |
| 5033 | | 4973 | |
| 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 bits | 4978 | // 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 | }; |
| 5049 | | 4984 | |
| 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 | }; | | |
| 5057 | | 4986 | |
| 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 | }; |
| 5077 | | 5006 | |
| 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 but | 5011 | .is_pub = is_pub, |
| 5083 | // it causes a bug. This is undefined without zig language | 5012 | .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, |
| 5088 | | 5017 | .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 | } |
| 5106 | | 5026 | |
| ... | @@ -5122,124 +5042,12 @@ fn fail( | ... | @@ -5122,124 +5042,12 @@ fn fail( |
| 5122 | } | 5042 | } |
| 5123 | | 5043 | |
| 5124 | pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void { | 5044 | pub 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 | | | |
| 5163 | fn 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 | | | |
| 5168 | fn 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 | | |
| 5187 | fn 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 | | | |
| 5221 | fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { | | |
| 5222 | return appendTokenFmt(c, .Identifier, "{}", .{std.zig.fmtId(name)}); | | |
| 5223 | } | | |
| 5224 | | | |
| 5225 | fn 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 | | | |
| 5235 | fn 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 | } |
| 5244 | | 5052 | |
| 5245 | pub fn freeErrors(errors: []ClangErrMsg) void { | 5053 | pub fn freeErrors(errors: []ClangErrMsg) void { |