authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-19 15:11:39-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-19 15:11:39-04:00
log3908b4fdee64c0ec6ef4d65e5b31210d4fea4423
treea3dcf9412afff29c8f58ebaafdcd935106cd82f0
parent1d85b588eab27830409a62e88bd8444db58787a4

self-hosted: refactor ParsedFile out of existence

also we are successfully analyzing the return type of main

6 files changed, 343 insertions(+), 155 deletions(-)

src-self-hosted/compilation.zig+153-112
......@@ -21,7 +21,6 @@ const Scope = @import("scope.zig").Scope;
2121const Decl = @import("decl.zig").Decl;
2222const ir = @import("ir.zig");
2323const Visib = @import("visib.zig").Visib;
24const ParsedFile = @import("parsed_file.zig").ParsedFile;
2524const Value = @import("value.zig").Value;
2625const Type = Value.Type;
2726const Span = errmsg.Span;
......@@ -470,6 +469,35 @@ pub const Compilation = struct {
470469 return comp;
471470 }
472471
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
473501 fn initTypes(comp: *Compilation) !void {
474502 comp.meta_type = try comp.arena().create(Type.MetaType{
475503 .base = Type{
......@@ -671,82 +699,81 @@ pub const Compilation = struct {
671699 }
672700
673701 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);
688710
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);
694717
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();
697720
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);
699724
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;
703726
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);
706729
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();
713732
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);
727739
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 }
747773 }
774 try await (async decl_group.wait() catch unreachable);
748775 }
749 try await (async decl_group.wait() catch unreachable);
776
750777 try await (async self.prelink_group.wait() catch unreachable);
751778
752779 const any_prelink_errors = blk: {
......@@ -764,23 +791,15 @@ pub const Compilation = struct {
764791 /// caller takes ownership of resulting Code
765792 async fn genAndAnalyzeCode(
766793 comp: *Compilation,
767 parsed_file: *ParsedFile,
768794 scope: *Scope,
769795 node: *ast.Node,
770796 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(
773799 comp,
774800 node,
775801 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);
784803 defer unanalyzed_code.destroy(comp.gpa());
785804
786805 if (comp.verbose_ir) {
......@@ -788,44 +807,46 @@ pub const Compilation = struct {
788807 unanalyzed_code.dump();
789808 }
790809
791 const analyzed_code = (await (async ir.analyze(
810 const analyzed_code = try await (async ir.analyze(
792811 comp,
793 parsed_file,
794812 unanalyzed_code,
795813 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);
803815 errdefer analyzed_code.destroy(comp.gpa());
804816
817 if (comp.verbose_ir) {
818 std.debug.warn("analyzed:\n");
819 analyzed_code.dump();
820 }
821
805822 return analyzed_code;
806823 }
807824
808825 async fn addCompTimeBlock(
809826 comp: *Compilation,
810 parsed_file: *ParsedFile,
811827 scope: *Scope,
812828 comptime_node: *ast.Node.Comptime,
813829 ) !void {
814830 const void_type = Type.Void.get(comp);
815831 defer void_type.base.base.deref(comp);
816832
817 const analyzed_code = (try await (async genAndAnalyzeCode(
833 const analyzed_code = (await (async genAndAnalyzeCode(
818834 comp,
819 parsed_file,
820835 scope,
821836 comptime_node.expr,
822837 &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 };
824844 analyzed_code.destroy(comp.gpa());
825845 }
826846
827847 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);
829850
830851 if (is_export) {
831852 try self.prelink_group.call(verifyUniqueSymbol, self, decl);
......@@ -833,24 +854,24 @@ pub const Compilation = struct {
833854 }
834855 }
835856
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);
839860
840 try self.prelink_group.call(addCompileErrorAsync, self, parsed_file, span, text);
861 try self.prelink_group.call(addCompileErrorAsync, self, root, span, text);
841862 }
842863
843864 async fn addCompileErrorAsync(
844865 self: *Compilation,
845 parsed_file: *ParsedFile,
866 root: *Scope.Root,
846867 span: Span,
847868 text: []u8,
848869 ) !void {
849870 const msg = try self.loop.allocator.create(errmsg.Msg{
850 .path = parsed_file.realpath,
871 .path = root.realpath,
851872 .text = text,
852873 .span = span,
853 .tree = &parsed_file.tree,
874 .tree = &root.tree,
854875 });
855876 errdefer self.loop.allocator.destroy(msg);
856877
......@@ -866,7 +887,7 @@ pub const Compilation = struct {
866887
867888 if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| {
868889 try self.addCompileError(
869 decl.parsed_file,
890 decl.findRootScope(),
870891 decl.getSpan(),
871892 "exported symbol collision: '{}'",
872893 decl.name,
......@@ -988,6 +1009,24 @@ pub const Compilation = struct {
9881009 fn registerGarbage(comp: *Compilation, comptime T: type, node: *std.atomic.Stack(*T).Node) void {
9891010 // TODO put the garbage somewhere
9901011 }
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 }
9911030};
9921031
9931032fn printError(comptime format: []const u8, args: ...) !void {
......@@ -1011,7 +1050,12 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib
10111050pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {
10121051 if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*;
10131052
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 };
10151059 decl.resolution.resolve();
10161060 return decl.resolution.data;
10171061}
......@@ -1034,9 +1078,12 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
10341078 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);
10351079 defer fndef_scope.base.deref(comp);
10361080
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);
10401087
10411088 const is_var_args = false;
10421089 const params = ([*]Type.Fn.Param)(undefined)[0..0];
......@@ -1050,19 +1097,13 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
10501097 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
10511098 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };
10521099
1053 const analyzed_code = (try await (async comp.genAndAnalyzeCode(
1054 fn_decl.base.parsed_file,
1100 const analyzed_code = try await (async comp.genAndAnalyzeCode(
10551101 &fndef_scope.base,
10561102 body_node,
10571103 return_type,
1058 ) catch unreachable)) orelse return;
1104 ) catch unreachable);
10591105 errdefer analyzed_code.destroy(comp.gpa());
10601106
1061 if (comp.verbose_ir) {
1062 std.debug.warn("analyzed:\n");
1063 analyzed_code.dump();
1064 }
1065
10661107 // Kick off rendering to LLVM module, but it doesn't block the fn decl
10671108 // analysis from being complete.
10681109 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;
33const mem = std.mem;
44const ast = std.zig.ast;
55const Visib = @import("visib.zig").Visib;
6const ParsedFile = @import("parsed_file.zig").ParsedFile;
76const event = std.event;
87const Value = @import("value.zig").Value;
98const Token = std.zig.Token;
......@@ -17,7 +16,6 @@ pub const Decl = struct {
1716 visib: Visib,
1817 resolution: event.Future(Compilation.BuildError!void),
1918 resolution_in_progress: u8,
20 parsed_file: *ParsedFile,
2119 parent_scope: *Scope,
2220
2321 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);
......@@ -48,6 +46,10 @@ pub const Decl = struct {
4846 }
4947 }
5048
49 pub fn findRootScope(base: *const Decl) *Scope.Root {
50 return base.parent_scope.findRoot();
51 }
52
5153 pub const Id = enum {
5254 Var,
5355 Fn,
src-self-hosted/ir.zig+121-20
......@@ -8,7 +8,6 @@ const Value = @import("value.zig").Value;
88const Type = Value.Type;
99const assert = std.debug.assert;
1010const Token = std.zig.Token;
11const ParsedFile = @import("parsed_file.zig").ParsedFile;
1211const Span = @import("errmsg.zig").Span;
1312const llvm = @import("llvm.zig");
1413const ObjectFile = @import("codegen.zig").ObjectFile;
......@@ -611,6 +610,33 @@ pub const Code = struct {
611610 }
612611 }
613612 }
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 }
614640};
615641
616642pub const Builder = struct {
......@@ -618,14 +644,14 @@ pub const Builder = struct {
618644 code: *Code,
619645 current_basic_block: *BasicBlock,
620646 next_debug_id: usize,
621 parsed_file: *ParsedFile,
647 root_scope: *Scope.Root,
622648 is_comptime: bool,
623649 is_async: bool,
624650 begin_scope: ?*Scope,
625651
626652 pub const Error = Analyze.Error;
627653
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 {
629655 const code = try comp.gpa().create(Code{
630656 .basic_block_list = undefined,
631657 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
......@@ -636,7 +662,7 @@ pub const Builder = struct {
636662
637663 return Builder{
638664 .comp = comp,
639 .parsed_file = parsed_file,
665 .root_scope = root_scope,
640666 .current_basic_block = undefined,
641667 .code = code,
642668 .next_debug_id = 0,
......@@ -718,7 +744,10 @@ pub const Builder = struct {
718744 ast.Node.Id.UndefinedLiteral => return error.Unimplemented,
719745 ast.Node.Id.ThisLiteral => return error.Unimplemented,
720746 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 },
722751 ast.Node.Id.GroupedExpression => {
723752 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
724753 return irb.genNode(grouped_expr.expr, scope, lval);
......@@ -761,16 +790,17 @@ pub const Builder = struct {
761790 Scope.Id.CompTime => return true,
762791 Scope.Id.FnDef => return false,
763792 Scope.Id.Decls => unreachable,
793 Scope.Id.Root => unreachable,
764794 Scope.Id.Block,
765795 Scope.Id.Defer,
766796 Scope.Id.DeferExpr,
767 => scope = scope.parent orelse return false,
797 => scope = scope.parent.?,
768798 }
769799 }
770800 }
771801
772802 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);
774804
775805 var base: u8 = undefined;
776806 var rest: []const u8 = undefined;
......@@ -845,7 +875,7 @@ pub const Builder = struct {
845875
846876 if (statement_node.cast(ast.Node.Defer)) |defer_node| {
847877 // 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);
849879 const kind = switch (defer_token.id) {
850880 Token.Id.Keyword_defer => Scope.Defer.Kind.ScopeExit,
851881 Token.Id.Keyword_errdefer => Scope.Defer.Kind.ErrorExit,
......@@ -928,7 +958,7 @@ pub const Builder = struct {
928958 const src_span = Span.token(control_flow_expr.ltoken);
929959 if (scope.findFnDef() == null) {
930960 try irb.comp.addCompileError(
931 irb.parsed_file,
961 irb.root_scope,
932962 src_span,
933963 "return expression outside function definition",
934964 );
......@@ -938,7 +968,7 @@ pub const Builder = struct {
938968 if (scope.findDeferExpr()) |scope_defer_expr| {
939969 if (!scope_defer_expr.reported_err) {
940970 try irb.comp.addCompileError(
941 irb.parsed_file,
971 irb.root_scope,
942972 src_span,
943973 "cannot return from defer expression",
944974 );
......@@ -1012,6 +1042,69 @@ pub const Builder = struct {
10121042 }
10131043 }
10141044
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
10151108 const DeferCounts = struct {
10161109 scope_exit: usize,
10171110 error_exit: usize,
......@@ -1035,10 +1128,11 @@ pub const Builder = struct {
10351128
10361129 Scope.Id.CompTime,
10371130 Scope.Id.Block,
1131 Scope.Id.Decls,
1132 Scope.Id.Root,
10381133 => scope = scope.parent orelse break,
10391134
10401135 Scope.Id.DeferExpr => unreachable,
1041 Scope.Id.Decls => unreachable,
10421136 }
10431137 }
10441138 return result;
......@@ -1081,6 +1175,7 @@ pub const Builder = struct {
10811175 },
10821176 Scope.Id.FnDef,
10831177 Scope.Id.Decls,
1178 Scope.Id.Root,
10841179 => return is_noreturn,
10851180
10861181 Scope.Id.CompTime,
......@@ -1188,6 +1283,12 @@ pub const Builder = struct {
11881283 return inst;
11891284 }
11901285
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
11911292 /// If the code is explicitly set to be comptime, then builds a const bool,
11921293 /// otherwise builds a TestCompTime instruction.
11931294 fn buildTestCompTime(self: *Builder, scope: *Scope, span: Span, target: *Inst) !*Inst {
......@@ -1259,8 +1360,8 @@ const Analyze = struct {
12591360 OutOfMemory,
12601361 };
12611362
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);
12641365 errdefer irb.abort();
12651366
12661367 return Analyze{
......@@ -1338,7 +1439,7 @@ const Analyze = struct {
13381439 }
13391440
13401441 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);
13421443 }
13431444
13441445 fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Inst) Analyze.Error!*Type {
......@@ -1800,9 +1901,8 @@ pub async fn gen(
18001901 comp: *Compilation,
18011902 body_node: *ast.Node,
18021903 scope: *Scope,
1803 parsed_file: *ParsedFile,
18041904) !*Code {
1805 var irb = try Builder.init(comp, parsed_file, scope);
1905 var irb = try Builder.init(comp, scope.findRoot(), scope);
18061906 errdefer irb.abort();
18071907
18081908 const entry_block = try irb.createBasicBlock(scope, c"Entry");
......@@ -1818,11 +1918,12 @@ pub async fn gen(
18181918 return irb.finish();
18191919}
18201920
1821pub 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
1921pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code {
18251922 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();
18261927
18271928 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);
18281929 new_entry_bb.ref();
src-self-hosted/parsed_file.zig deleted-6
......@@ -1,6 +0,0 @@
1const ast = @import("std").zig.ast;
2
3pub 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;
88const Value = @import("value.zig").Value;
99const ir = @import("ir.zig");
1010const Span = @import("errmsg.zig").Span;
11const assert = std.debug.assert;
1112
1213pub const Scope = struct {
1314 id: Id,
......@@ -23,7 +24,8 @@ pub const Scope = struct {
2324 if (base.ref_count == 0) {
2425 if (base.parent) |parent| parent.deref(comp);
2526 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),
2729 Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp),
2830 Id.FnDef => @fieldParentPtr(FnDef, "base", base).destroy(comp),
2931 Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),
......@@ -33,6 +35,15 @@ pub const Scope = struct {
3335 }
3436 }
3537
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
3647 pub fn findFnDef(base: *Scope) ?*FnDef {
3748 var scope = base;
3849 while (true) {
......@@ -44,6 +55,7 @@ pub const Scope = struct {
4455 Id.Defer,
4556 Id.DeferExpr,
4657 Id.CompTime,
58 Id.Root,
4759 => scope = scope.parent orelse return null,
4860 }
4961 }
......@@ -62,12 +74,14 @@ pub const Scope = struct {
6274 Id.Block,
6375 Id.Defer,
6476 Id.CompTime,
77 Id.Root,
6578 => scope = scope.parent orelse return null,
6679 }
6780 }
6881 }
6982
7083 pub const Id = enum {
84 Root,
7185 Decls,
7286 Block,
7387 FnDef,
......@@ -76,12 +90,43 @@ pub const Scope = struct {
7690 DeferExpr,
7791 };
7892
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
79124 pub const Decls = struct {
80125 base: Scope,
81126 table: Decl.Table,
82127
83128 /// 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 {
85130 const self = try comp.gpa().create(Decls{
86131 .base = Scope{
87132 .id = Id.Decls,
......@@ -95,14 +140,14 @@ pub const Scope = struct {
95140 self.table = Decl.Table.init(comp.gpa());
96141 errdefer self.table.deinit();
97142
98 if (parent) |p| p.ref();
143 parent.ref();
99144
100145 return self;
101146 }
102147
103 pub fn destroy(self: *Decls) void {
148 pub fn destroy(self: *Decls, comp: *Compilation) void {
104149 self.table.deinit();
105 self.table.allocator.destroy(self);
150 comp.gpa().destroy(self);
106151 }
107152 };
108153
......@@ -143,7 +188,7 @@ pub const Scope = struct {
143188 };
144189
145190 /// 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 {
147192 const self = try comp.gpa().create(Block{
148193 .base = Scope{
149194 .id = Id.Block,
......@@ -158,7 +203,7 @@ pub const Scope = struct {
158203 });
159204 errdefer comp.gpa().destroy(self);
160205
161 if (parent) |p| p.ref();
206 parent.ref();
162207 return self;
163208 }
164209
......@@ -175,7 +220,7 @@ pub const Scope = struct {
175220
176221 /// Creates a FnDef scope with 1 reference
177222 /// Must set the fn_val later
178 pub fn create(comp: *Compilation, parent: ?*Scope) !*FnDef {
223 pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
179224 const self = try comp.gpa().create(FnDef{
180225 .base = Scope{
181226 .id = Id.FnDef,
......@@ -185,7 +230,7 @@ pub const Scope = struct {
185230 .fn_val = undefined,
186231 });
187232
188 if (parent) |p| p.ref();
233 parent.ref();
189234
190235 return self;
191236 }
......@@ -199,7 +244,7 @@ pub const Scope = struct {
199244 base: Scope,
200245
201246 /// 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 {
203248 const self = try comp.gpa().create(CompTime{
204249 .base = Scope{
205250 .id = Id.CompTime,
......@@ -208,7 +253,7 @@ pub const Scope = struct {
208253 },
209254 });
210255
211 if (parent) |p| p.ref();
256 parent.ref();
212257 return self;
213258 }
214259
......@@ -230,7 +275,7 @@ pub const Scope = struct {
230275 /// Creates a Defer scope with 1 reference
231276 pub fn create(
232277 comp: *Compilation,
233 parent: ?*Scope,
278 parent: *Scope,
234279 kind: Kind,
235280 defer_expr_scope: *DeferExpr,
236281 ) !*Defer {
......@@ -247,7 +292,7 @@ pub const Scope = struct {
247292
248293 defer_expr_scope.base.ref();
249294
250 if (parent) |p| p.ref();
295 parent.ref();
251296 return self;
252297 }
253298
......@@ -263,7 +308,7 @@ pub const Scope = struct {
263308 reported_err: bool,
264309
265310 /// 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 {
267312 const self = try comp.gpa().create(DeferExpr{
268313 .base = Scope{
269314 .id = Id.DeferExpr,
......@@ -275,7 +320,7 @@ pub const Scope = struct {
275320 });
276321 errdefer comp.gpa().destroy(self);
277322
278 if (parent) |p| p.ref();
323 parent.ref();
279324 return self;
280325 }
281326
src-self-hosted/value.zig+5
......@@ -39,6 +39,11 @@ pub const Value = struct {
3939 return base;
4040 }
4141
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
4247 pub fn dump(base: *const Value) void {
4348 std.debug.warn("{}", @tagName(base.id));
4449 }