authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-22 14:24:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-22 14:24:22-07:00
log130ad08001f73d62e0c6daf3848da4f7aedff614
tree9e2eac02e280dbe4c68bc9e413210f226b544ed0
parent389020009a9afea3cc01e8e408aa33dbc63c156c

AstGen: implement function prototypes


1 files changed, 116 insertions(+), 7 deletions(-)

src/AstGen.zig+116-7
...@@ -861,12 +861,121 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -861,12 +861,121 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
861 => return structInitExpr(gz, scope, rl, node, tree.structInit(node)),861 => return structInitExpr(gz, scope, rl, node, tree.structInit(node)),
862862
863 .@"anytype" => return astgen.failNode(node, "TODO implement astgen.expr for .anytype", .{}),863 .@"anytype" => return astgen.failNode(node, "TODO implement astgen.expr for .anytype", .{}),
864 .fn_proto_simple,864
865 .fn_proto_multi,865 .fn_proto_simple => {
866 .fn_proto_one,866 var params: [1]ast.Node.Index = undefined;
867 .fn_proto,867 return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(&params, node));
868 => return astgen.failNode(node, "TODO implement astgen.expr for function prototypes", .{}),868 },
869 .fn_proto_multi => {
870 return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node));
871 },
872 .fn_proto_one => {
873 var params: [1]ast.Node.Index = undefined;
874 return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(&params, node));
875 },
876 .fn_proto => {
877 return fnProtoExpr(gz, scope, rl, tree.fnProto(node));
878 },
879 }
880}
881
882pub fn fnProtoExpr(
883 gz: *GenZir,
884 scope: *Scope,
885 rl: ResultLoc,
886 fn_proto: ast.full.FnProto,
887) InnerError!Zir.Inst.Ref {
888 const astgen = gz.astgen;
889 const gpa = astgen.gpa;
890 const tree = &astgen.file.tree;
891 const token_tags = tree.tokens.items(.tag);
892
893 const is_extern = blk: {
894 const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false;
895 break :blk token_tags[maybe_extern_token] == .keyword_extern;
896 };
897 assert(!is_extern);
898
899 // The AST params array does not contain anytype and ... parameters.
900 // We must iterate to count how many param types to allocate.
901 const param_count = blk: {
902 var count: usize = 0;
903 var it = fn_proto.iterate(tree.*);
904 while (it.next()) |param| {
905 if (param.anytype_ellipsis3) |token| switch (token_tags[token]) {
906 .ellipsis3 => break,
907 .keyword_anytype => {},
908 else => unreachable,
909 };
910 count += 1;
911 }
912 break :blk count;
913 };
914 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
915 defer gpa.free(param_types);
916
917 var is_var_args = false;
918 {
919 var param_type_i: usize = 0;
920 var it = fn_proto.iterate(tree.*);
921 while (it.next()) |param| : (param_type_i += 1) {
922 if (param.anytype_ellipsis3) |token| {
923 switch (token_tags[token]) {
924 .keyword_anytype => {
925 param_types[param_type_i] = .none;
926 continue;
927 },
928 .ellipsis3 => {
929 is_var_args = true;
930 break;
931 },
932 else => unreachable,
933 }
934 }
935 const param_type_node = param.type_expr;
936 assert(param_type_node != 0);
937 param_types[param_type_i] =
938 try expr(gz, scope, .{ .ty = .type_type }, param_type_node);
939 }
940 assert(param_type_i == param_count);
941 }
942
943 assert(fn_proto.ast.align_expr == 0); // caught by the parser
944 assert(fn_proto.ast.section_expr == 0); // caught by the parser
945
946 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
947 const is_inferred_error = token_tags[maybe_bang] == .bang;
948 if (is_inferred_error) {
949 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
869 }950 }
951 const return_type_inst = try AstGen.expr(
952 gz,
953 scope,
954 .{ .ty = .type_type },
955 fn_proto.ast.return_type,
956 );
957
958 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
959 try AstGen.expr(
960 gz,
961 scope,
962 .{ .ty = .calling_convention_type },
963 fn_proto.ast.callconv_expr,
964 )
965 else
966 Zir.Inst.Ref.none;
967
968 const result = try gz.addFunc(.{
969 .src_node = fn_proto.ast.proto_node,
970 .ret_ty = return_type_inst,
971 .param_types = param_types,
972 .body = &[0]Zir.Inst.Index{},
973 .cc = cc,
974 .lib_name = 0,
975 .is_var_args = is_var_args,
976 .is_inferred_error = false,
977 });
978 return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node);
870}979}
871980
872pub fn arrayInitExpr(981pub fn arrayInitExpr(
...@@ -2506,11 +2615,11 @@ fn fnDecl(...@@ -2506,11 +2615,11 @@ fn fnDecl(
2506 Zir.Inst.Ref.none;2615 Zir.Inst.Ref.none;
25072616
2508 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {2617 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
2509 if (is_extern) {2618 if (!is_extern) {
2510 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});2619 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
2511 }2620 }
2512 if (is_inferred_error) {2621 if (is_inferred_error) {
2513 return astgen.failTok(maybe_bang, "function prototype requires explicit error set", .{});2622 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
2514 }2623 }
2515 break :func try decl_gz.addFunc(.{2624 break :func try decl_gz.addFunc(.{
2516 .src_node = fn_proto.ast.proto_node,2625 .src_node = fn_proto.ast.proto_node,