| author | |
| committer | |
| log | 3908b4fdee64c0ec6ef4d65e5b31210d4fea4423 |
| tree | a3dcf9412afff29c8f58ebaafdcd935106cd82f0 |
| parent | 1d85b588eab27830409a62e88bd8444db58787a4 |
also we are successfully analyzing the return type of main6 files changed, 343 insertions(+), 155 deletions(-)
src-self-hosted/compilation.zig+153-112| ... | ... | @@ -21,7 +21,6 @@ const Scope = @import("scope.zig").Scope; |
| 21 | 21 | const Decl = @import("decl.zig").Decl; |
| 22 | 22 | const ir = @import("ir.zig"); |
| 23 | 23 | const Visib = @import("visib.zig").Visib; |
| 24 | const ParsedFile = @import("parsed_file.zig").ParsedFile; | |
| 25 | 24 | const Value = @import("value.zig").Value; |
| 26 | 25 | const Type = Value.Type; |
| 27 | 26 | const Span = errmsg.Span; |
| ... | ... | @@ -470,6 +469,35 @@ pub const Compilation = struct { |
| 470 | 469 | return comp; |
| 471 | 470 | } |
| 472 | 471 | |
| 472 | /// it does ref the result because it could be an arbitrary integer size | |
| 473 | pub fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type { | |
| 474 | if (name.len >= 2) { | |
| 475 | switch (name[0]) { | |
| 476 | 'i', 'u' => blk: { | |
| 477 | for (name[1..]) |byte| | |
| 478 | switch (byte) { | |
| 479 | '0'...'9' => {}, | |
| 480 | else => break :blk, | |
| 481 | }; | |
| 482 | const is_signed = name[0] == 'i'; | |
| 483 | const bit_count = std.fmt.parseUnsigned(u32, name[1..], 10) catch |err| switch (err) { | |
| 484 | error.Overflow => return error.Overflow, | |
| 485 | error.InvalidCharacter => unreachable, // we just checked the characters above | |
| 486 | }; | |
| 487 | @panic("get int type - need to make everything async"); | |
| 488 | }, | |
| 489 | else => {}, | |
| 490 | } | |
| 491 | } | |
| 492 | ||
| 493 | if (comp.primitive_type_table.get(name)) |entry| { | |
| 494 | entry.value.base.ref(); | |
| 495 | return entry.value; | |
| 496 | } | |
| 497 | ||
| 498 | return null; | |
| 499 | } | |
| 500 | ||
| 473 | 501 | fn initTypes(comp: *Compilation) !void { |
| 474 | 502 | comp.meta_type = try comp.arena().create(Type.MetaType{ |
| 475 | 503 | .base = Type{ |
| ... | ... | @@ -671,82 +699,81 @@ pub const Compilation = struct { |
| 671 | 699 | } |
| 672 | 700 | |
| 673 | 701 | async fn compileAndLink(self: *Compilation) !void { |
| 674 | const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path"); | |
| 675 | // TODO async/await os.path.real | |
| 676 | const root_src_real_path = os.path.real(self.gpa(), root_src_path) catch |err| { | |
| 677 | try printError("unable to get real path '{}': {}", root_src_path, err); | |
| 678 | return err; | |
| 679 | }; | |
| 680 | errdefer self.gpa().free(root_src_real_path); | |
| 681 | ||
| 682 | // TODO async/await readFileAlloc() | |
| 683 | const source_code = io.readFileAlloc(self.gpa(), root_src_real_path) catch |err| { | |
| 684 | try printError("unable to open '{}': {}", root_src_real_path, err); | |
| 685 | return err; | |
| 686 | }; | |
| 687 | errdefer self.gpa().free(source_code); | |
| 702 | if (self.root_src_path) |root_src_path| { | |
| 703 | // TODO async/await os.path.real | |
| 704 | const root_src_real_path = os.path.real(self.gpa(), root_src_path) catch |err| { | |
| 705 | try printError("unable to get real path '{}': {}", root_src_path, err); | |
| 706 | return err; | |
| 707 | }; | |
| 708 | const root_scope = blk: { | |
| 709 | errdefer self.gpa().free(root_src_real_path); | |
| 688 | 710 | |
| 689 | const parsed_file = try self.gpa().create(ParsedFile{ | |
| 690 | .tree = undefined, | |
| 691 | .realpath = root_src_real_path, | |
| 692 | }); | |
| 693 | errdefer self.gpa().destroy(parsed_file); | |
| 711 | // TODO async/await readFileAlloc() | |
| 712 | const source_code = io.readFileAlloc(self.gpa(), root_src_real_path) catch |err| { | |
| 713 | try printError("unable to open '{}': {}", root_src_real_path, err); | |
| 714 | return err; | |
| 715 | }; | |
| 716 | errdefer self.gpa().free(source_code); | |
| 694 | 717 | |
| 695 | parsed_file.tree = try std.zig.parse(self.gpa(), source_code); | |
| 696 | errdefer parsed_file.tree.deinit(); | |
| 718 | var tree = try std.zig.parse(self.gpa(), source_code); | |
| 719 | errdefer tree.deinit(); | |
| 697 | 720 | |
| 698 | const tree = &parsed_file.tree; | |
| 721 | break :blk try Scope.Root.create(self, tree, root_src_real_path); | |
| 722 | }; | |
| 723 | defer root_scope.base.deref(self); | |
| 699 | 724 | |
| 700 | // create empty struct for it | |
| 701 | const decls = try Scope.Decls.create(self, null); | |
| 702 | defer decls.base.deref(self); | |
| 725 | const tree = &root_scope.tree; | |
| 703 | 726 | |
| 704 | var decl_group = event.Group(BuildError!void).init(self.loop); | |
| 705 | errdefer decl_group.cancelAll(); | |
| 727 | const decls = try Scope.Decls.create(self, &root_scope.base); | |
| 728 | defer decls.base.deref(self); | |
| 706 | 729 | |
| 707 | var it = tree.root_node.decls.iterator(0); | |
| 708 | while (it.next()) |decl_ptr| { | |
| 709 | const decl = decl_ptr.*; | |
| 710 | switch (decl.id) { | |
| 711 | ast.Node.Id.Comptime => { | |
| 712 | const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl); | |
| 730 | var decl_group = event.Group(BuildError!void).init(self.loop); | |
| 731 | errdefer decl_group.cancelAll(); | |
| 713 | 732 | |
| 714 | try decl_group.call(addCompTimeBlock, self, parsed_file, &decls.base, comptime_node); | |
| 715 | }, | |
| 716 | ast.Node.Id.VarDecl => @panic("TODO"), | |
| 717 | ast.Node.Id.FnProto => { | |
| 718 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); | |
| 719 | ||
| 720 | const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else { | |
| 721 | try self.addCompileError(parsed_file, Span{ | |
| 722 | .first = fn_proto.fn_token, | |
| 723 | .last = fn_proto.fn_token + 1, | |
| 724 | }, "missing function name"); | |
| 725 | continue; | |
| 726 | }; | |
| 733 | var it = tree.root_node.decls.iterator(0); | |
| 734 | while (it.next()) |decl_ptr| { | |
| 735 | const decl = decl_ptr.*; | |
| 736 | switch (decl.id) { | |
| 737 | ast.Node.Id.Comptime => { | |
| 738 | const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl); | |
| 727 | 739 | |
| 728 | const fn_decl = try self.gpa().create(Decl.Fn{ | |
| 729 | .base = Decl{ | |
| 730 | .id = Decl.Id.Fn, | |
| 731 | .name = name, | |
| 732 | .visib = parseVisibToken(tree, fn_proto.visib_token), | |
| 733 | .resolution = event.Future(BuildError!void).init(self.loop), | |
| 734 | .resolution_in_progress = 0, | |
| 735 | .parsed_file = parsed_file, | |
| 736 | .parent_scope = &decls.base, | |
| 737 | }, | |
| 738 | .value = Decl.Fn.Val{ .Unresolved = {} }, | |
| 739 | .fn_proto = fn_proto, | |
| 740 | }); | |
| 741 | errdefer self.gpa().destroy(fn_decl); | |
| 742 | ||
| 743 | try decl_group.call(addTopLevelDecl, self, &fn_decl.base); | |
| 744 | }, | |
| 745 | ast.Node.Id.TestDecl => @panic("TODO"), | |
| 746 | else => unreachable, | |
| 740 | try decl_group.call(addCompTimeBlock, self, &decls.base, comptime_node); | |
| 741 | }, | |
| 742 | ast.Node.Id.VarDecl => @panic("TODO"), | |
| 743 | ast.Node.Id.FnProto => { | |
| 744 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); | |
| 745 | ||
| 746 | const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else { | |
| 747 | try self.addCompileError(root_scope, Span{ | |
| 748 | .first = fn_proto.fn_token, | |
| 749 | .last = fn_proto.fn_token + 1, | |
| 750 | }, "missing function name"); | |
| 751 | continue; | |
| 752 | }; | |
| 753 | ||
| 754 | const fn_decl = try self.gpa().create(Decl.Fn{ | |
| 755 | .base = Decl{ | |
| 756 | .id = Decl.Id.Fn, | |
| 757 | .name = name, | |
| 758 | .visib = parseVisibToken(tree, fn_proto.visib_token), | |
| 759 | .resolution = event.Future(BuildError!void).init(self.loop), | |
| 760 | .resolution_in_progress = 0, | |
| 761 | .parent_scope = &decls.base, | |
| 762 | }, | |
| 763 | .value = Decl.Fn.Val{ .Unresolved = {} }, | |
| 764 | .fn_proto = fn_proto, | |
| 765 | }); | |
| 766 | errdefer self.gpa().destroy(fn_decl); | |
| 767 | ||
| 768 | try decl_group.call(addTopLevelDecl, self, &fn_decl.base); | |
| 769 | }, | |
| 770 | ast.Node.Id.TestDecl => @panic("TODO"), | |
| 771 | else => unreachable, | |
| 772 | } | |
| 747 | 773 | } |
| 774 | try await (async decl_group.wait() catch unreachable); | |
| 748 | 775 | } |
| 749 | try await (async decl_group.wait() catch unreachable); | |
| 776 | ||
| 750 | 777 | try await (async self.prelink_group.wait() catch unreachable); |
| 751 | 778 | |
| 752 | 779 | const any_prelink_errors = blk: { |
| ... | ... | @@ -764,23 +791,15 @@ pub const Compilation = struct { |
| 764 | 791 | /// caller takes ownership of resulting Code |
| 765 | 792 | async fn genAndAnalyzeCode( |
| 766 | 793 | comp: *Compilation, |
| 767 | parsed_file: *ParsedFile, | |
| 768 | 794 | scope: *Scope, |
| 769 | 795 | node: *ast.Node, |
| 770 | 796 | expected_type: ?*Type, |
| 771 | ) !?*ir.Code { | |
| 772 | const unanalyzed_code = (await (async ir.gen( | |
| 797 | ) !*ir.Code { | |
| 798 | const unanalyzed_code = try await (async ir.gen( | |
| 773 | 799 | comp, |
| 774 | 800 | node, |
| 775 | 801 | scope, |
| 776 | parsed_file, | |
| 777 | ) catch unreachable)) catch |err| switch (err) { | |
| 778 | // This poison value should not cause the errdefers to run. It simply means | |
| 779 | // that self.compile_errors is populated. | |
| 780 | // TODO https://github.com/ziglang/zig/issues/769 | |
| 781 | error.SemanticAnalysisFailed => return null, | |
| 782 | else => return err, | |
| 783 | }; | |
| 802 | ) catch unreachable); | |
| 784 | 803 | defer unanalyzed_code.destroy(comp.gpa()); |
| 785 | 804 | |
| 786 | 805 | if (comp.verbose_ir) { |
| ... | ... | @@ -788,44 +807,46 @@ pub const Compilation = struct { |
| 788 | 807 | unanalyzed_code.dump(); |
| 789 | 808 | } |
| 790 | 809 | |
| 791 | const analyzed_code = (await (async ir.analyze( | |
| 810 | const analyzed_code = try await (async ir.analyze( | |
| 792 | 811 | comp, |
| 793 | parsed_file, | |
| 794 | 812 | unanalyzed_code, |
| 795 | 813 | expected_type, |
| 796 | ) catch unreachable)) catch |err| switch (err) { | |
| 797 | // This poison value should not cause the errdefers to run. It simply means | |
| 798 | // that self.compile_errors is populated. | |
| 799 | // TODO https://github.com/ziglang/zig/issues/769 | |
| 800 | error.SemanticAnalysisFailed => return null, | |
| 801 | else => return err, | |
| 802 | }; | |
| 814 | ) catch unreachable); | |
| 803 | 815 | errdefer analyzed_code.destroy(comp.gpa()); |
| 804 | 816 | |
| 817 | if (comp.verbose_ir) { | |
| 818 | std.debug.warn("analyzed:\n"); | |
| 819 | analyzed_code.dump(); | |
| 820 | } | |
| 821 | ||
| 805 | 822 | return analyzed_code; |
| 806 | 823 | } |
| 807 | 824 | |
| 808 | 825 | async fn addCompTimeBlock( |
| 809 | 826 | comp: *Compilation, |
| 810 | parsed_file: *ParsedFile, | |
| 811 | 827 | scope: *Scope, |
| 812 | 828 | comptime_node: *ast.Node.Comptime, |
| 813 | 829 | ) !void { |
| 814 | 830 | const void_type = Type.Void.get(comp); |
| 815 | 831 | defer void_type.base.base.deref(comp); |
| 816 | 832 | |
| 817 | const analyzed_code = (try await (async genAndAnalyzeCode( | |
| 833 | const analyzed_code = (await (async genAndAnalyzeCode( | |
| 818 | 834 | comp, |
| 819 | parsed_file, | |
| 820 | 835 | scope, |
| 821 | 836 | comptime_node.expr, |
| 822 | 837 | &void_type.base, |
| 823 | ) catch unreachable)) orelse return; | |
| 838 | ) catch unreachable)) catch |err| switch (err) { | |
| 839 | // This poison value should not cause the errdefers to run. It simply means | |
| 840 | // that comp.compile_errors is populated. | |
| 841 | error.SemanticAnalysisFailed => return {}, | |
| 842 | else => return err, | |
| 843 | }; | |
| 824 | 844 | analyzed_code.destroy(comp.gpa()); |
| 825 | 845 | } |
| 826 | 846 | |
| 827 | 847 | async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void { |
| 828 | const is_export = decl.isExported(&decl.parsed_file.tree); | |
| 848 | const tree = &decl.findRootScope().tree; | |
| 849 | const is_export = decl.isExported(tree); | |
| 829 | 850 | |
| 830 | 851 | if (is_export) { |
| 831 | 852 | try self.prelink_group.call(verifyUniqueSymbol, self, decl); |
| ... | ... | @@ -833,24 +854,24 @@ pub const Compilation = struct { |
| 833 | 854 | } |
| 834 | 855 | } |
| 835 | 856 | |
| 836 | fn addCompileError(self: *Compilation, parsed_file: *ParsedFile, span: Span, comptime fmt: []const u8, args: ...) !void { | |
| 837 | const text = try std.fmt.allocPrint(self.loop.allocator, fmt, args); | |
| 838 | errdefer self.loop.allocator.free(text); | |
| 857 | fn addCompileError(self: *Compilation, root: *Scope.Root, span: Span, comptime fmt: []const u8, args: ...) !void { | |
| 858 | const text = try std.fmt.allocPrint(self.gpa(), fmt, args); | |
| 859 | errdefer self.gpa().free(text); | |
| 839 | 860 | |
| 840 | try self.prelink_group.call(addCompileErrorAsync, self, parsed_file, span, text); | |
| 861 | try self.prelink_group.call(addCompileErrorAsync, self, root, span, text); | |
| 841 | 862 | } |
| 842 | 863 | |
| 843 | 864 | async fn addCompileErrorAsync( |
| 844 | 865 | self: *Compilation, |
| 845 | parsed_file: *ParsedFile, | |
| 866 | root: *Scope.Root, | |
| 846 | 867 | span: Span, |
| 847 | 868 | text: []u8, |
| 848 | 869 | ) !void { |
| 849 | 870 | const msg = try self.loop.allocator.create(errmsg.Msg{ |
| 850 | .path = parsed_file.realpath, | |
| 871 | .path = root.realpath, | |
| 851 | 872 | .text = text, |
| 852 | 873 | .span = span, |
| 853 | .tree = &parsed_file.tree, | |
| 874 | .tree = &root.tree, | |
| 854 | 875 | }); |
| 855 | 876 | errdefer self.loop.allocator.destroy(msg); |
| 856 | 877 | |
| ... | ... | @@ -866,7 +887,7 @@ pub const Compilation = struct { |
| 866 | 887 | |
| 867 | 888 | if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| { |
| 868 | 889 | try self.addCompileError( |
| 869 | decl.parsed_file, | |
| 890 | decl.findRootScope(), | |
| 870 | 891 | decl.getSpan(), |
| 871 | 892 | "exported symbol collision: '{}'", |
| 872 | 893 | decl.name, |
| ... | ... | @@ -988,6 +1009,24 @@ pub const Compilation = struct { |
| 988 | 1009 | fn registerGarbage(comp: *Compilation, comptime T: type, node: *std.atomic.Stack(*T).Node) void { |
| 989 | 1010 | // TODO put the garbage somewhere |
| 990 | 1011 | } |
| 1012 | ||
| 1013 | /// Returns a value which has been ref()'d once | |
| 1014 | async fn analyzeConstValue(comp: *Compilation, scope: *Scope, node: *ast.Node, expected_type: *Type) !*Value { | |
| 1015 | const analyzed_code = try await (async comp.genAndAnalyzeCode(scope, node, expected_type) catch unreachable); | |
| 1016 | defer analyzed_code.destroy(comp.gpa()); | |
| 1017 | ||
| 1018 | return analyzed_code.getCompTimeResult(comp); | |
| 1019 | } | |
| 1020 | ||
| 1021 | async fn analyzeTypeExpr(comp: *Compilation, scope: *Scope, node: *ast.Node) !*Type { | |
| 1022 | const meta_type = &Type.MetaType.get(comp).base; | |
| 1023 | defer meta_type.base.deref(comp); | |
| 1024 | ||
| 1025 | const result_val = try await (async comp.analyzeConstValue(scope, node, meta_type) catch unreachable); | |
| 1026 | errdefer result_val.base.deref(comp); | |
| 1027 | ||
| 1028 | return result_val.cast(Type).?; | |
| 1029 | } | |
| 991 | 1030 | }; |
| 992 | 1031 | |
| 993 | 1032 | fn printError(comptime format: []const u8, args: ...) !void { |
| ... | ... | @@ -1011,7 +1050,12 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib |
| 1011 | 1050 | pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void { |
| 1012 | 1051 | if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*; |
| 1013 | 1052 | |
| 1014 | decl.resolution.data = await (async generateDecl(comp, decl) catch unreachable); | |
| 1053 | decl.resolution.data = (await (async generateDecl(comp, decl) catch unreachable)) catch |err| switch (err) { | |
| 1054 | // This poison value should not cause the errdefers to run. It simply means | |
| 1055 | // that comp.compile_errors is populated. | |
| 1056 | error.SemanticAnalysisFailed => {}, | |
| 1057 | else => err, | |
| 1058 | }; | |
| 1015 | 1059 | decl.resolution.resolve(); |
| 1016 | 1060 | return decl.resolution.data; |
| 1017 | 1061 | } |
| ... | ... | @@ -1034,9 +1078,12 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1034 | 1078 | const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope); |
| 1035 | 1079 | defer fndef_scope.base.deref(comp); |
| 1036 | 1080 | |
| 1037 | // TODO actually look at the return type of the AST | |
| 1038 | const return_type = &Type.Void.get(comp).base; | |
| 1039 | defer return_type.base.deref(comp); | |
| 1081 | const return_type_node = switch (fn_decl.fn_proto.return_type) { | |
| 1082 | ast.Node.FnProto.ReturnType.Explicit => |n| n, | |
| 1083 | ast.Node.FnProto.ReturnType.InferErrorSet => |n| n, | |
| 1084 | }; | |
| 1085 | const return_type = try await (async comp.analyzeTypeExpr(&fndef_scope.base, return_type_node) catch unreachable); | |
| 1086 | return_type.base.deref(comp); | |
| 1040 | 1087 | |
| 1041 | 1088 | const is_var_args = false; |
| 1042 | 1089 | const params = ([*]Type.Fn.Param)(undefined)[0..0]; |
| ... | ... | @@ -1050,19 +1097,13 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 1050 | 1097 | const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name); |
| 1051 | 1098 | fn_decl.value = Decl.Fn.Val{ .Ok = fn_val }; |
| 1052 | 1099 | |
| 1053 | const analyzed_code = (try await (async comp.genAndAnalyzeCode( | |
| 1054 | fn_decl.base.parsed_file, | |
| 1100 | const analyzed_code = try await (async comp.genAndAnalyzeCode( | |
| 1055 | 1101 | &fndef_scope.base, |
| 1056 | 1102 | body_node, |
| 1057 | 1103 | return_type, |
| 1058 | ) catch unreachable)) orelse return; | |
| 1104 | ) catch unreachable); | |
| 1059 | 1105 | errdefer analyzed_code.destroy(comp.gpa()); |
| 1060 | 1106 | |
| 1061 | if (comp.verbose_ir) { | |
| 1062 | std.debug.warn("analyzed:\n"); | |
| 1063 | analyzed_code.dump(); | |
| 1064 | } | |
| 1065 | ||
| 1066 | 1107 | // Kick off rendering to LLVM module, but it doesn't block the fn decl |
| 1067 | 1108 | // analysis from being complete. |
| 1068 | 1109 | try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code); |
src-self-hosted/decl.zig+4-2| ... | ... | @@ -3,7 +3,6 @@ const Allocator = mem.Allocator; |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | const ast = std.zig.ast; |
| 5 | 5 | const Visib = @import("visib.zig").Visib; |
| 6 | const ParsedFile = @import("parsed_file.zig").ParsedFile; | |
| 7 | 6 | const event = std.event; |
| 8 | 7 | const Value = @import("value.zig").Value; |
| 9 | 8 | const Token = std.zig.Token; |
| ... | ... | @@ -17,7 +16,6 @@ pub const Decl = struct { |
| 17 | 16 | visib: Visib, |
| 18 | 17 | resolution: event.Future(Compilation.BuildError!void), |
| 19 | 18 | resolution_in_progress: u8, |
| 20 | parsed_file: *ParsedFile, | |
| 21 | 19 | parent_scope: *Scope, |
| 22 | 20 | |
| 23 | 21 | pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | ... | @@ -48,6 +46,10 @@ pub const Decl = struct { |
| 48 | 46 | } |
| 49 | 47 | } |
| 50 | 48 | |
| 49 | pub fn findRootScope(base: *const Decl) *Scope.Root { | |
| 50 | return base.parent_scope.findRoot(); | |
| 51 | } | |
| 52 | ||
| 51 | 53 | pub const Id = enum { |
| 52 | 54 | Var, |
| 53 | 55 | Fn, |
src-self-hosted/ir.zig+121-20| ... | ... | @@ -8,7 +8,6 @@ const Value = @import("value.zig").Value; |
| 8 | 8 | const Type = Value.Type; |
| 9 | 9 | const assert = std.debug.assert; |
| 10 | 10 | const Token = std.zig.Token; |
| 11 | const ParsedFile = @import("parsed_file.zig").ParsedFile; | |
| 12 | 11 | const Span = @import("errmsg.zig").Span; |
| 13 | 12 | const llvm = @import("llvm.zig"); |
| 14 | 13 | const ObjectFile = @import("codegen.zig").ObjectFile; |
| ... | ... | @@ -611,6 +610,33 @@ pub const Code = struct { |
| 611 | 610 | } |
| 612 | 611 | } |
| 613 | 612 | } |
| 613 | ||
| 614 | /// returns a ref-incremented value, or adds a compile error | |
| 615 | pub fn getCompTimeResult(self: *Code, comp: *Compilation) !*Value { | |
| 616 | const bb = self.basic_block_list.at(0); | |
| 617 | for (bb.instruction_list.toSliceConst()) |inst| { | |
| 618 | if (inst.cast(Inst.Return)) |ret_inst| { | |
| 619 | const ret_value = ret_inst.params.return_value; | |
| 620 | if (ret_value.isCompTime()) { | |
| 621 | return ret_value.val.KnownValue.getRef(); | |
| 622 | } | |
| 623 | try comp.addCompileError( | |
| 624 | ret_value.scope.findRoot(), | |
| 625 | ret_value.span, | |
| 626 | "unable to evaluate constant expression", | |
| 627 | ); | |
| 628 | return error.SemanticAnalysisFailed; | |
| 629 | } else if (inst.hasSideEffects()) { | |
| 630 | try comp.addCompileError( | |
| 631 | inst.scope.findRoot(), | |
| 632 | inst.span, | |
| 633 | "unable to evaluate constant expression", | |
| 634 | ); | |
| 635 | return error.SemanticAnalysisFailed; | |
| 636 | } | |
| 637 | } | |
| 638 | unreachable; | |
| 639 | } | |
| 614 | 640 | }; |
| 615 | 641 | |
| 616 | 642 | pub const Builder = struct { |
| ... | ... | @@ -618,14 +644,14 @@ pub const Builder = struct { |
| 618 | 644 | code: *Code, |
| 619 | 645 | current_basic_block: *BasicBlock, |
| 620 | 646 | next_debug_id: usize, |
| 621 | parsed_file: *ParsedFile, | |
| 647 | root_scope: *Scope.Root, | |
| 622 | 648 | is_comptime: bool, |
| 623 | 649 | is_async: bool, |
| 624 | 650 | begin_scope: ?*Scope, |
| 625 | 651 | |
| 626 | 652 | pub const Error = Analyze.Error; |
| 627 | 653 | |
| 628 | pub fn init(comp: *Compilation, parsed_file: *ParsedFile, begin_scope: ?*Scope) !Builder { | |
| 654 | pub fn init(comp: *Compilation, root_scope: *Scope.Root, begin_scope: ?*Scope) !Builder { | |
| 629 | 655 | const code = try comp.gpa().create(Code{ |
| 630 | 656 | .basic_block_list = undefined, |
| 631 | 657 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), |
| ... | ... | @@ -636,7 +662,7 @@ pub const Builder = struct { |
| 636 | 662 | |
| 637 | 663 | return Builder{ |
| 638 | 664 | .comp = comp, |
| 639 | .parsed_file = parsed_file, | |
| 665 | .root_scope = root_scope, | |
| 640 | 666 | .current_basic_block = undefined, |
| 641 | 667 | .code = code, |
| 642 | 668 | .next_debug_id = 0, |
| ... | ... | @@ -718,7 +744,10 @@ pub const Builder = struct { |
| 718 | 744 | ast.Node.Id.UndefinedLiteral => return error.Unimplemented, |
| 719 | 745 | ast.Node.Id.ThisLiteral => return error.Unimplemented, |
| 720 | 746 | ast.Node.Id.Unreachable => return error.Unimplemented, |
| 721 | ast.Node.Id.Identifier => return error.Unimplemented, | |
| 747 | ast.Node.Id.Identifier => { | |
| 748 | const identifier = @fieldParentPtr(ast.Node.Identifier, "base", node); | |
| 749 | return irb.genIdentifier(identifier, scope, lval); | |
| 750 | }, | |
| 722 | 751 | ast.Node.Id.GroupedExpression => { |
| 723 | 752 | const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node); |
| 724 | 753 | return irb.genNode(grouped_expr.expr, scope, lval); |
| ... | ... | @@ -761,16 +790,17 @@ pub const Builder = struct { |
| 761 | 790 | Scope.Id.CompTime => return true, |
| 762 | 791 | Scope.Id.FnDef => return false, |
| 763 | 792 | Scope.Id.Decls => unreachable, |
| 793 | Scope.Id.Root => unreachable, | |
| 764 | 794 | Scope.Id.Block, |
| 765 | 795 | Scope.Id.Defer, |
| 766 | 796 | Scope.Id.DeferExpr, |
| 767 | => scope = scope.parent orelse return false, | |
| 797 | => scope = scope.parent.?, | |
| 768 | 798 | } |
| 769 | 799 | } |
| 770 | 800 | } |
| 771 | 801 | |
| 772 | 802 | pub fn genIntLit(irb: *Builder, int_lit: *ast.Node.IntegerLiteral, scope: *Scope) !*Inst { |
| 773 | const int_token = irb.parsed_file.tree.tokenSlice(int_lit.token); | |
| 803 | const int_token = irb.root_scope.tree.tokenSlice(int_lit.token); | |
| 774 | 804 | |
| 775 | 805 | var base: u8 = undefined; |
| 776 | 806 | var rest: []const u8 = undefined; |
| ... | ... | @@ -845,7 +875,7 @@ pub const Builder = struct { |
| 845 | 875 | |
| 846 | 876 | if (statement_node.cast(ast.Node.Defer)) |defer_node| { |
| 847 | 877 | // defer starts a new scope |
| 848 | const defer_token = irb.parsed_file.tree.tokens.at(defer_node.defer_token); | |
| 878 | const defer_token = irb.root_scope.tree.tokens.at(defer_node.defer_token); | |
| 849 | 879 | const kind = switch (defer_token.id) { |
| 850 | 880 | Token.Id.Keyword_defer => Scope.Defer.Kind.ScopeExit, |
| 851 | 881 | Token.Id.Keyword_errdefer => Scope.Defer.Kind.ErrorExit, |
| ... | ... | @@ -928,7 +958,7 @@ pub const Builder = struct { |
| 928 | 958 | const src_span = Span.token(control_flow_expr.ltoken); |
| 929 | 959 | if (scope.findFnDef() == null) { |
| 930 | 960 | try irb.comp.addCompileError( |
| 931 | irb.parsed_file, | |
| 961 | irb.root_scope, | |
| 932 | 962 | src_span, |
| 933 | 963 | "return expression outside function definition", |
| 934 | 964 | ); |
| ... | ... | @@ -938,7 +968,7 @@ pub const Builder = struct { |
| 938 | 968 | if (scope.findDeferExpr()) |scope_defer_expr| { |
| 939 | 969 | if (!scope_defer_expr.reported_err) { |
| 940 | 970 | try irb.comp.addCompileError( |
| 941 | irb.parsed_file, | |
| 971 | irb.root_scope, | |
| 942 | 972 | src_span, |
| 943 | 973 | "cannot return from defer expression", |
| 944 | 974 | ); |
| ... | ... | @@ -1012,6 +1042,69 @@ pub const Builder = struct { |
| 1012 | 1042 | } |
| 1013 | 1043 | } |
| 1014 | 1044 | |
| 1045 | pub fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst { | |
| 1046 | const src_span = Span.token(identifier.token); | |
| 1047 | const name = irb.root_scope.tree.tokenSlice(identifier.token); | |
| 1048 | ||
| 1049 | //if (buf_eql_str(variable_name, "_") && lval == LValPtr) { | |
| 1050 | // IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, node); | |
| 1051 | // const_instruction->base.value.type = get_pointer_to_type(irb->codegen, | |
| 1052 | // irb->codegen->builtin_types.entry_void, false); | |
| 1053 | // const_instruction->base.value.special = ConstValSpecialStatic; | |
| 1054 | // const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard; | |
| 1055 | // return &const_instruction->base; | |
| 1056 | //} | |
| 1057 | ||
| 1058 | if (irb.comp.getPrimitiveType(name)) |result| { | |
| 1059 | if (result) |primitive_type| { | |
| 1060 | defer primitive_type.base.deref(irb.comp); | |
| 1061 | switch (lval) { | |
| 1062 | LVal.Ptr => return error.Unimplemented, | |
| 1063 | LVal.None => return irb.buildConstValue(scope, src_span, &primitive_type.base), | |
| 1064 | } | |
| 1065 | } | |
| 1066 | } else |err| switch (err) { | |
| 1067 | error.Overflow => { | |
| 1068 | try irb.comp.addCompileError(irb.root_scope, src_span, "integer too large"); | |
| 1069 | return error.SemanticAnalysisFailed; | |
| 1070 | }, | |
| 1071 | } | |
| 1072 | //TypeTableEntry *primitive_type = get_primitive_type(irb->codegen, variable_name); | |
| 1073 | //if (primitive_type != nullptr) { | |
| 1074 | // IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); | |
| 1075 | // if (lval == LValPtr) { | |
| 1076 | // return ir_build_ref(irb, scope, node, value, false, false); | |
| 1077 | // } else { | |
| 1078 | // return value; | |
| 1079 | // } | |
| 1080 | //} | |
| 1081 | ||
| 1082 | //VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name); | |
| 1083 | //if (var) { | |
| 1084 | // IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var); | |
| 1085 | // if (lval == LValPtr) | |
| 1086 | // return var_ptr; | |
| 1087 | // else | |
| 1088 | // return ir_build_load_ptr(irb, scope, node, var_ptr); | |
| 1089 | //} | |
| 1090 | ||
| 1091 | //Tld *tld = find_decl(irb->codegen, scope, variable_name); | |
| 1092 | //if (tld) | |
| 1093 | // return ir_build_decl_ref(irb, scope, node, tld, lval); | |
| 1094 | ||
| 1095 | //if (node->owner->any_imports_failed) { | |
| 1096 | // // skip the error message since we had a failing import in this file | |
| 1097 | // // if an import breaks we don't need redundant undeclared identifier errors | |
| 1098 | // return irb->codegen->invalid_instruction; | |
| 1099 | //} | |
| 1100 | ||
| 1101 | // TODO put a variable of same name with invalid type in global scope | |
| 1102 | // so that future references to this same name will find a variable with an invalid type | |
| 1103 | ||
| 1104 | try irb.comp.addCompileError(irb.root_scope, src_span, "unknown identifier '{}'", name); | |
| 1105 | return error.SemanticAnalysisFailed; | |
| 1106 | } | |
| 1107 | ||
| 1015 | 1108 | const DeferCounts = struct { |
| 1016 | 1109 | scope_exit: usize, |
| 1017 | 1110 | error_exit: usize, |
| ... | ... | @@ -1035,10 +1128,11 @@ pub const Builder = struct { |
| 1035 | 1128 | |
| 1036 | 1129 | Scope.Id.CompTime, |
| 1037 | 1130 | Scope.Id.Block, |
| 1131 | Scope.Id.Decls, | |
| 1132 | Scope.Id.Root, | |
| 1038 | 1133 | => scope = scope.parent orelse break, |
| 1039 | 1134 | |
| 1040 | 1135 | Scope.Id.DeferExpr => unreachable, |
| 1041 | Scope.Id.Decls => unreachable, | |
| 1042 | 1136 | } |
| 1043 | 1137 | } |
| 1044 | 1138 | return result; |
| ... | ... | @@ -1081,6 +1175,7 @@ pub const Builder = struct { |
| 1081 | 1175 | }, |
| 1082 | 1176 | Scope.Id.FnDef, |
| 1083 | 1177 | Scope.Id.Decls, |
| 1178 | Scope.Id.Root, | |
| 1084 | 1179 | => return is_noreturn, |
| 1085 | 1180 | |
| 1086 | 1181 | Scope.Id.CompTime, |
| ... | ... | @@ -1188,6 +1283,12 @@ pub const Builder = struct { |
| 1188 | 1283 | return inst; |
| 1189 | 1284 | } |
| 1190 | 1285 | |
| 1286 | fn buildConstValue(self: *Builder, scope: *Scope, span: Span, v: *Value) !*Inst { | |
| 1287 | const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{}); | |
| 1288 | inst.val = IrVal{ .KnownValue = v.getRef() }; | |
| 1289 | return inst; | |
| 1290 | } | |
| 1291 | ||
| 1191 | 1292 | /// If the code is explicitly set to be comptime, then builds a const bool, |
| 1192 | 1293 | /// otherwise builds a TestCompTime instruction. |
| 1193 | 1294 | fn buildTestCompTime(self: *Builder, scope: *Scope, span: Span, target: *Inst) !*Inst { |
| ... | ... | @@ -1259,8 +1360,8 @@ const Analyze = struct { |
| 1259 | 1360 | OutOfMemory, |
| 1260 | 1361 | }; |
| 1261 | 1362 | |
| 1262 | pub fn init(comp: *Compilation, parsed_file: *ParsedFile, explicit_return_type: ?*Type) !Analyze { | |
| 1263 | var irb = try Builder.init(comp, parsed_file, null); | |
| 1363 | pub fn init(comp: *Compilation, root_scope: *Scope.Root, explicit_return_type: ?*Type) !Analyze { | |
| 1364 | var irb = try Builder.init(comp, root_scope, null); | |
| 1264 | 1365 | errdefer irb.abort(); |
| 1265 | 1366 | |
| 1266 | 1367 | return Analyze{ |
| ... | ... | @@ -1338,7 +1439,7 @@ const Analyze = struct { |
| 1338 | 1439 | } |
| 1339 | 1440 | |
| 1340 | 1441 | fn addCompileError(self: *Analyze, span: Span, comptime fmt: []const u8, args: ...) !void { |
| 1341 | return self.irb.comp.addCompileError(self.irb.parsed_file, span, fmt, args); | |
| 1442 | return self.irb.comp.addCompileError(self.irb.root_scope, span, fmt, args); | |
| 1342 | 1443 | } |
| 1343 | 1444 | |
| 1344 | 1445 | fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Inst) Analyze.Error!*Type { |
| ... | ... | @@ -1800,9 +1901,8 @@ pub async fn gen( |
| 1800 | 1901 | comp: *Compilation, |
| 1801 | 1902 | body_node: *ast.Node, |
| 1802 | 1903 | scope: *Scope, |
| 1803 | parsed_file: *ParsedFile, | |
| 1804 | 1904 | ) !*Code { |
| 1805 | var irb = try Builder.init(comp, parsed_file, scope); | |
| 1905 | var irb = try Builder.init(comp, scope.findRoot(), scope); | |
| 1806 | 1906 | errdefer irb.abort(); |
| 1807 | 1907 | |
| 1808 | 1908 | const entry_block = try irb.createBasicBlock(scope, c"Entry"); |
| ... | ... | @@ -1818,11 +1918,12 @@ pub async fn gen( |
| 1818 | 1918 | return irb.finish(); |
| 1819 | 1919 | } |
| 1820 | 1920 | |
| 1821 | pub async fn analyze(comp: *Compilation, parsed_file: *ParsedFile, old_code: *Code, expected_type: ?*Type) !*Code { | |
| 1822 | var ira = try Analyze.init(comp, parsed_file, expected_type); | |
| 1823 | errdefer ira.abort(); | |
| 1824 | ||
| 1921 | pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code { | |
| 1825 | 1922 | const old_entry_bb = old_code.basic_block_list.at(0); |
| 1923 | const root_scope = old_entry_bb.scope.findRoot(); | |
| 1924 | ||
| 1925 | var ira = try Analyze.init(comp, root_scope, expected_type); | |
| 1926 | errdefer ira.abort(); | |
| 1826 | 1927 | |
| 1827 | 1928 | const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null); |
| 1828 | 1929 | new_entry_bb.ref(); |
src-self-hosted/parsed_file.zig deleted-6| ... | ... | @@ -1,6 +0,0 @@ |
| 1 | const ast = @import("std").zig.ast; | |
| 2 | ||
| 3 | pub const ParsedFile = struct { | |
| 4 | tree: ast.Tree, | |
| 5 | realpath: []const u8, | |
| 6 | }; |
src-self-hosted/scope.zig+60-15| ... | ... | @@ -8,6 +8,7 @@ const ast = std.zig.ast; |
| 8 | 8 | const Value = @import("value.zig").Value; |
| 9 | 9 | const ir = @import("ir.zig"); |
| 10 | 10 | const Span = @import("errmsg.zig").Span; |
| 11 | const assert = std.debug.assert; | |
| 11 | 12 | |
| 12 | 13 | pub const Scope = struct { |
| 13 | 14 | id: Id, |
| ... | ... | @@ -23,7 +24,8 @@ pub const Scope = struct { |
| 23 | 24 | if (base.ref_count == 0) { |
| 24 | 25 | if (base.parent) |parent| parent.deref(comp); |
| 25 | 26 | switch (base.id) { |
| 26 | Id.Decls => @fieldParentPtr(Decls, "base", base).destroy(), | |
| 27 | Id.Root => @fieldParentPtr(Root, "base", base).destroy(comp), | |
| 28 | Id.Decls => @fieldParentPtr(Decls, "base", base).destroy(comp), | |
| 27 | 29 | Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp), |
| 28 | 30 | Id.FnDef => @fieldParentPtr(FnDef, "base", base).destroy(comp), |
| 29 | 31 | Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp), |
| ... | ... | @@ -33,6 +35,15 @@ pub const Scope = struct { |
| 33 | 35 | } |
| 34 | 36 | } |
| 35 | 37 | |
| 38 | pub fn findRoot(base: *Scope) *Root { | |
| 39 | var scope = base; | |
| 40 | while (scope.parent) |parent| { | |
| 41 | scope = parent; | |
| 42 | } | |
| 43 | assert(scope.id == Id.Root); | |
| 44 | return @fieldParentPtr(Root, "base", scope); | |
| 45 | } | |
| 46 | ||
| 36 | 47 | pub fn findFnDef(base: *Scope) ?*FnDef { |
| 37 | 48 | var scope = base; |
| 38 | 49 | while (true) { |
| ... | ... | @@ -44,6 +55,7 @@ pub const Scope = struct { |
| 44 | 55 | Id.Defer, |
| 45 | 56 | Id.DeferExpr, |
| 46 | 57 | Id.CompTime, |
| 58 | Id.Root, | |
| 47 | 59 | => scope = scope.parent orelse return null, |
| 48 | 60 | } |
| 49 | 61 | } |
| ... | ... | @@ -62,12 +74,14 @@ pub const Scope = struct { |
| 62 | 74 | Id.Block, |
| 63 | 75 | Id.Defer, |
| 64 | 76 | Id.CompTime, |
| 77 | Id.Root, | |
| 65 | 78 | => scope = scope.parent orelse return null, |
| 66 | 79 | } |
| 67 | 80 | } |
| 68 | 81 | } |
| 69 | 82 | |
| 70 | 83 | pub const Id = enum { |
| 84 | Root, | |
| 71 | 85 | Decls, |
| 72 | 86 | Block, |
| 73 | 87 | FnDef, |
| ... | ... | @@ -76,12 +90,43 @@ pub const Scope = struct { |
| 76 | 90 | DeferExpr, |
| 77 | 91 | }; |
| 78 | 92 | |
| 93 | pub const Root = struct { | |
| 94 | base: Scope, | |
| 95 | tree: ast.Tree, | |
| 96 | realpath: []const u8, | |
| 97 | ||
| 98 | /// Creates a Root scope with 1 reference | |
| 99 | /// Takes ownership of realpath | |
| 100 | /// Caller must set tree | |
| 101 | pub fn create(comp: *Compilation, tree: ast.Tree, realpath: []u8) !*Root { | |
| 102 | const self = try comp.gpa().create(Root{ | |
| 103 | .base = Scope{ | |
| 104 | .id = Id.Root, | |
| 105 | .parent = null, | |
| 106 | .ref_count = 1, | |
| 107 | }, | |
| 108 | .tree = tree, | |
| 109 | .realpath = realpath, | |
| 110 | }); | |
| 111 | errdefer comp.gpa().destroy(self); | |
| 112 | ||
| 113 | return self; | |
| 114 | } | |
| 115 | ||
| 116 | pub fn destroy(self: *Root, comp: *Compilation) void { | |
| 117 | comp.gpa().free(self.tree.source); | |
| 118 | self.tree.deinit(); | |
| 119 | comp.gpa().free(self.realpath); | |
| 120 | comp.gpa().destroy(self); | |
| 121 | } | |
| 122 | }; | |
| 123 | ||
| 79 | 124 | pub const Decls = struct { |
| 80 | 125 | base: Scope, |
| 81 | 126 | table: Decl.Table, |
| 82 | 127 | |
| 83 | 128 | /// Creates a Decls scope with 1 reference |
| 84 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Decls { | |
| 129 | pub fn create(comp: *Compilation, parent: *Scope) !*Decls { | |
| 85 | 130 | const self = try comp.gpa().create(Decls{ |
| 86 | 131 | .base = Scope{ |
| 87 | 132 | .id = Id.Decls, |
| ... | ... | @@ -95,14 +140,14 @@ pub const Scope = struct { |
| 95 | 140 | self.table = Decl.Table.init(comp.gpa()); |
| 96 | 141 | errdefer self.table.deinit(); |
| 97 | 142 | |
| 98 | if (parent) |p| p.ref(); | |
| 143 | parent.ref(); | |
| 99 | 144 | |
| 100 | 145 | return self; |
| 101 | 146 | } |
| 102 | 147 | |
| 103 | pub fn destroy(self: *Decls) void { | |
| 148 | pub fn destroy(self: *Decls, comp: *Compilation) void { | |
| 104 | 149 | self.table.deinit(); |
| 105 | self.table.allocator.destroy(self); | |
| 150 | comp.gpa().destroy(self); | |
| 106 | 151 | } |
| 107 | 152 | }; |
| 108 | 153 | |
| ... | ... | @@ -143,7 +188,7 @@ pub const Scope = struct { |
| 143 | 188 | }; |
| 144 | 189 | |
| 145 | 190 | /// Creates a Block scope with 1 reference |
| 146 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Block { | |
| 191 | pub fn create(comp: *Compilation, parent: *Scope) !*Block { | |
| 147 | 192 | const self = try comp.gpa().create(Block{ |
| 148 | 193 | .base = Scope{ |
| 149 | 194 | .id = Id.Block, |
| ... | ... | @@ -158,7 +203,7 @@ pub const Scope = struct { |
| 158 | 203 | }); |
| 159 | 204 | errdefer comp.gpa().destroy(self); |
| 160 | 205 | |
| 161 | if (parent) |p| p.ref(); | |
| 206 | parent.ref(); | |
| 162 | 207 | return self; |
| 163 | 208 | } |
| 164 | 209 | |
| ... | ... | @@ -175,7 +220,7 @@ pub const Scope = struct { |
| 175 | 220 | |
| 176 | 221 | /// Creates a FnDef scope with 1 reference |
| 177 | 222 | /// Must set the fn_val later |
| 178 | pub fn create(comp: *Compilation, parent: ?*Scope) !*FnDef { | |
| 223 | pub fn create(comp: *Compilation, parent: *Scope) !*FnDef { | |
| 179 | 224 | const self = try comp.gpa().create(FnDef{ |
| 180 | 225 | .base = Scope{ |
| 181 | 226 | .id = Id.FnDef, |
| ... | ... | @@ -185,7 +230,7 @@ pub const Scope = struct { |
| 185 | 230 | .fn_val = undefined, |
| 186 | 231 | }); |
| 187 | 232 | |
| 188 | if (parent) |p| p.ref(); | |
| 233 | parent.ref(); | |
| 189 | 234 | |
| 190 | 235 | return self; |
| 191 | 236 | } |
| ... | ... | @@ -199,7 +244,7 @@ pub const Scope = struct { |
| 199 | 244 | base: Scope, |
| 200 | 245 | |
| 201 | 246 | /// Creates a CompTime scope with 1 reference |
| 202 | pub fn create(comp: *Compilation, parent: ?*Scope) !*CompTime { | |
| 247 | pub fn create(comp: *Compilation, parent: *Scope) !*CompTime { | |
| 203 | 248 | const self = try comp.gpa().create(CompTime{ |
| 204 | 249 | .base = Scope{ |
| 205 | 250 | .id = Id.CompTime, |
| ... | ... | @@ -208,7 +253,7 @@ pub const Scope = struct { |
| 208 | 253 | }, |
| 209 | 254 | }); |
| 210 | 255 | |
| 211 | if (parent) |p| p.ref(); | |
| 256 | parent.ref(); | |
| 212 | 257 | return self; |
| 213 | 258 | } |
| 214 | 259 | |
| ... | ... | @@ -230,7 +275,7 @@ pub const Scope = struct { |
| 230 | 275 | /// Creates a Defer scope with 1 reference |
| 231 | 276 | pub fn create( |
| 232 | 277 | comp: *Compilation, |
| 233 | parent: ?*Scope, | |
| 278 | parent: *Scope, | |
| 234 | 279 | kind: Kind, |
| 235 | 280 | defer_expr_scope: *DeferExpr, |
| 236 | 281 | ) !*Defer { |
| ... | ... | @@ -247,7 +292,7 @@ pub const Scope = struct { |
| 247 | 292 | |
| 248 | 293 | defer_expr_scope.base.ref(); |
| 249 | 294 | |
| 250 | if (parent) |p| p.ref(); | |
| 295 | parent.ref(); | |
| 251 | 296 | return self; |
| 252 | 297 | } |
| 253 | 298 | |
| ... | ... | @@ -263,7 +308,7 @@ pub const Scope = struct { |
| 263 | 308 | reported_err: bool, |
| 264 | 309 | |
| 265 | 310 | /// Creates a DeferExpr scope with 1 reference |
| 266 | pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr { | |
| 311 | pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr { | |
| 267 | 312 | const self = try comp.gpa().create(DeferExpr{ |
| 268 | 313 | .base = Scope{ |
| 269 | 314 | .id = Id.DeferExpr, |
| ... | ... | @@ -275,7 +320,7 @@ pub const Scope = struct { |
| 275 | 320 | }); |
| 276 | 321 | errdefer comp.gpa().destroy(self); |
| 277 | 322 | |
| 278 | if (parent) |p| p.ref(); | |
| 323 | parent.ref(); | |
| 279 | 324 | return self; |
| 280 | 325 | } |
| 281 | 326 |
src-self-hosted/value.zig+5| ... | ... | @@ -39,6 +39,11 @@ pub const Value = struct { |
| 39 | 39 | return base; |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | pub fn cast(base: *Value, comptime T: type) ?*T { | |
| 43 | if (base.id != @field(Id, @typeName(T))) return null; | |
| 44 | return @fieldParentPtr(T, "base", base); | |
| 45 | } | |
| 46 | ||
| 42 | 47 | pub fn dump(base: *const Value) void { |
| 43 | 48 | std.debug.warn("{}", @tagName(base.id)); |
| 44 | 49 | } |