diff options
| author | Vexu <git@vexu.eu> | 2020-11-16 20:45:53 +0200 |
|---|---|---|
| committer | Vexu <git@vexu.eu> | 2020-11-17 21:19:49 +0200 |
| commit | c1e19f4c0a62047c26d5baabe25887e533cc739f (patch) | |
| tree | 921e818474ece6846d958fabf1a99c0ab3cc3df8 /src | |
| parent | f173d078c780c9946742c4ce686ccd0dccdb7e98 (diff) | |
| download | zig-c1e19f4c0a62047c26d5baabe25887e533cc739f.tar.gz zig-c1e19f4c0a62047c26d5baabe25887e533cc739f.zip | |
stage2: initial container astgen
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 32 | ||||
| -rw-r--r-- | src/astgen.zig | 164 | ||||
| -rw-r--r-- | src/type.zig | 8 | ||||
| -rw-r--r-- | src/type/Enum.zig | 12 | ||||
| -rw-r--r-- | src/type/Struct.zig | 11 | ||||
| -rw-r--r-- | src/type/Union.zig | 9 | ||||
| -rw-r--r-- | src/zir.zig | 25 | ||||
| -rw-r--r-- | src/zir_sema.zig | 8 |
8 files changed, 228 insertions, 41 deletions
diff --git a/src/Module.zig b/src/Module.zig index 3e6be31be1..831aedf054 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -469,12 +469,12 @@ pub const Scope = struct { } } - pub fn getOwnerPkg(base: *Scope) *Package { + pub fn getFileScope(base: *Scope) *Scope.File { var cur = base; while (true) { cur = switch (cur.tag) { - .container => return @fieldParentPtr(Container, "base", cur).file_scope.pkg, - .file => return @fieldParentPtr(File, "base", cur).pkg, + .container => return @fieldParentPtr(Container, "base", cur).file_scope, + .file => return @fieldParentPtr(File, "base", cur), .zir_module => unreachable, // TODO are zir modules allowed to import packages? .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent, .local_val => @fieldParentPtr(LocalVal, "base", cur).parent, @@ -550,7 +550,7 @@ pub const Scope = struct { file_scope: *Scope.File, /// Direct children of the file. - decls: std.AutoArrayHashMapUnmanaged(*Decl, void), + decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, ty: Type, pub fn deinit(self: *Container, gpa: *Allocator) void { @@ -2273,8 +2273,15 @@ pub fn createAnonymousDecl( return new_decl; } -fn createContainerDecl(self: *Module, scope: *Scope, container_node: *std.zig.ast.Node.ContainerDecl) !*Decl { - const name = try self.getAnonTypeName(scope, container_node.kind_token); +pub fn createContainerDecl( + self: *Module, + scope: *Scope, + base_token: std.zig.ast.TokenIndex, + decl_arena: *std.heap.ArenaAllocator, + typed_value: TypedValue, +) !*Decl { + const scope_decl = scope.decl().?; + const name = try self.getAnonTypeName(scope, base_token); defer self.gpa.free(name); const name_hash = scope.namespace().fullyQualifiedNameHash(name); const src_hash: std.zig.SrcHash = undefined; @@ -2282,18 +2289,25 @@ fn createContainerDecl(self: *Module, scope: *Scope, container_node: *std.zig.as const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); decl_arena_state.* = decl_arena.state; + new_decl.typed_value = .{ + .most_recent = .{ + .typed_value = typed_value, + .arena = decl_arena_state, + }, + }; + new_decl.analysis = .complete; new_decl.generation = self.generation; return new_decl; } fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 { - const container = scope.getContainer(); - const tree = self.getAstTree(container); + const tree = scope.tree(); const base_name = switch (tree.token_ids[base_token]) { .Keyword_struct => "struct", .Keyword_enum => "enum", .Keyword_union => "union", + .Keyword_opaque => "opaque", else => unreachable, }; const loc = tree.tokenLocationLoc(0, tree.token_locs[base_token]); @@ -2487,7 +2501,7 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, } pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []const u8) !*Scope.File { - const cur_pkg = scope.getOwnerPkg(); + const cur_pkg = scope.getFileScope().pkg; const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse "."; const found_pkg = cur_pkg.table.get(target_string); diff --git a/src/astgen.zig b/src/astgen.zig index 37b1eab9a6..37436373f0 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -281,6 +281,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), .Switch => return switchExpr(mod, scope, rl, node.castTag(.Switch).?), + .ContainerDecl => return containerDecl(mod, scope, rl, node.castTag(.ContainerDecl).?), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}), @@ -294,7 +295,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}), .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), - .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), } } @@ -765,6 +765,168 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si return rlWrapPtr(mod, scope, rl, try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand)); } +fn containerField(mod: *Module, scope: *Scope, node: *ast.Node.ContainerField) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.firstToken()].start; + const name = try identifierTokenString(mod, scope, node.name_token); + + if (node.comptime_token == null and node.value_expr == null and node.align_expr == null) { + if (node.type_expr) |some| { + const ty = try typeExpr(mod, scope, some); + return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldTyped, .{ + .bytes = name, + .ty = ty, + }, .{}); + } else { + return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldNamed, .{ + .bytes = name, + }, .{}); + } + } + + const ty = if (node.type_expr) |some| try typeExpr(mod, scope, some) else null; + const alignment = if (node.align_expr) |some| try expr(mod, scope, .none, some) else null; + const init = if (node.value_expr) |some| try expr(mod, scope, .none, some) else null; + + return addZIRInst(mod, scope, src, zir.Inst.ContainerField, .{ + .bytes = name, + }, .{ + .ty = ty, + .init = init, + .alignment = alignment, + .is_comptime = node.comptime_token != null, + }); +} + +fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ContainerDecl) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.kind_token].start; + + var gen_scope: Scope.GenZIR = .{ + .parent = scope, + .decl = scope.decl().?, + .arena = scope.arena(), + .instructions = .{}, + }; + defer gen_scope.instructions.deinit(mod.gpa); + + var fields = std.ArrayList(*zir.Inst).init(mod.gpa); + defer fields.deinit(); + + for (node.fieldsAndDecls()) |fd| { + if (fd.castTag(.ContainerField)) |f| { + try fields.append(try containerField(mod, &gen_scope.base, f)); + } + } + + var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); + errdefer decl_arena.deinit(); + const arena = &decl_arena.allocator; + + var layout: std.builtin.TypeInfo.ContainerLayout = .Auto; + if (node.layout_token) |some| switch (tree.token_ids[some]) { + .Keyword_extern => layout = .Extern, + .Keyword_packed => layout = .Packed, + else => unreachable, + }; + + const container_type = switch (tree.token_ids[node.kind_token]) { + .Keyword_enum => blk: { + const tag_type: ?*zir.Inst = switch (node.init_arg_expr) { + .Type => |t| try typeExpr(mod, &gen_scope.base, t), + .None => null, + .Enum => unreachable, + }; + const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.EnumType, .{ + .fields = try arena.dupe(*zir.Inst, fields.items), + }, .{ + .layout = layout, + .tag_type = tag_type, + }); + const enum_type = try arena.create(Type.Payload.Enum); + enum_type.* = .{ + .analysis = .{ + .queued = .{ + .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) }, + .inst = inst, + }, + }, + .scope = .{ + .file_scope = scope.getFileScope(), + .ty = Type.initPayload(&enum_type.base), + }, + }; + break :blk Type.initPayload(&enum_type.base); + }, + .Keyword_struct => blk: { + assert(node.init_arg_expr == .None); + const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{ + .fields = try arena.dupe(*zir.Inst, fields.items), + }, .{ + .layout = layout, + }); + const struct_type = try arena.create(Type.Payload.Struct); + struct_type.* = .{ + .analysis = .{ + .queued = .{ + .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) }, + .inst = inst, + }, + }, + .scope = .{ + .file_scope = scope.getFileScope(), + .ty = Type.initPayload(&struct_type.base), + }, + }; + break :blk Type.initPayload(&struct_type.base); + }, + .Keyword_union => blk: { + const init_inst = switch (node.init_arg_expr) { + .Enum => |e| if (e) |t| try typeExpr(mod, &gen_scope.base, t) else null, + .None => null, + .Type => |t| try typeExpr(mod, &gen_scope.base, t), + }; + const init_kind: zir.Inst.UnionType.InitKind = switch (node.init_arg_expr) { + .Enum => .enum_type, + .None => .none, + .Type => .tag_type, + }; + const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.UnionType, .{ + .fields = try arena.dupe(*zir.Inst, fields.items), + }, .{ + .layout = layout, + .init_kind = init_kind, + .init_inst = init_inst, + }); + const union_type = try arena.create(Type.Payload.Union); + union_type.* = .{ + .analysis = .{ + .queued = .{ + .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) }, + .inst = inst, + }, + }, + .scope = .{ + .file_scope = scope.getFileScope(), + .ty = Type.initPayload(&union_type.base), + }, + }; + break :blk Type.initPayload(&union_type.base); + }, + .Keyword_opaque => return mod.fail(scope, src, "TODO opaque containers", .{}), + else => unreachable, + }; + const type_payload = try arena.create(Value.Payload.Ty); + type_payload.* = .{ + .ty = container_type, + }; + const decl = try mod.createContainerDecl(scope, node.kind_token, &decl_arena, .{ + .ty = Type.initTag(.type), + .val = Value.initPayload(&type_payload.base), + }); + return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{})); +} + fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.error_token].start; diff --git a/src/type.zig b/src/type.zig index 02a5245e40..0cde8644fd 100644 --- a/src/type.zig +++ b/src/type.zig @@ -923,7 +923,7 @@ pub const Type = extern union { @panic("TODO abiAlignment error union"); }, - .@"enum" => self.cast(Payload.Enum).?.abiAlignment(), + .@"enum" => self.cast(Payload.Enum).?.abiAlignment(target), .@"struct" => @panic("TODO"), .@"union" => @panic("TODO"), @@ -3221,9 +3221,9 @@ pub const Type = extern union { scope: *Module.Scope.Container, }; - pub const Enum = @import("value/Enum.zig"); - pub const Struct = @import("value/Struct.zig"); - pub const Union = @import("value/Union.zig"); + pub const Enum = @import("type/Enum.zig"); + pub const Struct = @import("type/Struct.zig"); + pub const Union = @import("type/Union.zig"); }; }; diff --git a/src/type/Enum.zig b/src/type/Enum.zig index 0042ddc8bf..1d937df7ce 100644 --- a/src/type/Enum.zig +++ b/src/type/Enum.zig @@ -1,8 +1,10 @@ const std = @import("std"); +const zir = @import("../zir.zig"); const Value = @import("../value.zig").Value; const Type = @import("../type.zig").Type; const Module = @import("../Module.zig"); const Scope = Module.Scope; +const Enum = @This(); base: Type.Payload = .{ .tag = .@"enum" }, @@ -12,6 +14,7 @@ analysis: union(enum) { resolved: Size, failed, }, +scope: Scope.Container, pub const Field = struct { value: Value, @@ -20,13 +23,10 @@ pub const Field = struct { pub const Zir = struct { body: zir.Module.Body, inst: *zir.Inst, - arena: std.heap.ArenaAllocator.State, }; pub const Size = struct { - is_zero_bits: bool, - alignment: u32, - size: u32, + tag_type: Type, fields: std.AutoArrayHashMap([]const u8, Field), }; @@ -45,11 +45,11 @@ pub fn resolve(self: *Enum, mod: *Module, scope: *Scope) !void { } // TODO should this resolve the type or assert that it has already been resolved? -pub fn abiAlignment(self: *Enum) u32 { +pub fn abiAlignment(self: *Enum, target: std.Target) u32 { switch (self.analysis) { .queued => unreachable, // alignment has not been resolved .in_progress => unreachable, // alignment has not been resolved .failed => unreachable, // type resolution failed - .resolved => |r| return r.tag_type.abiAlignment(), + .resolved => |r| return r.tag_type.abiAlignment(target), } } diff --git a/src/type/Struct.zig b/src/type/Struct.zig index bb1fe56995..2d4a160d0c 100644 --- a/src/type/Struct.zig +++ b/src/type/Struct.zig @@ -1,8 +1,10 @@ const std = @import("std"); +const zir = @import("../zir.zig"); const Value = @import("../value.zig").Value; const Type = @import("../type.zig").Type; const Module = @import("../Module.zig"); const Scope = Module.Scope; +const Struct = @This(); base: Type.Payload = .{ .tag = .@"struct" }, @@ -11,7 +13,7 @@ analysis: union(enum) { zero_bits_in_progress, zero_bits: Zero, in_progress, - alignment: Align, + // alignment: Align, resolved: Size, failed, }, @@ -24,7 +26,6 @@ pub const Field = struct { pub const Zir = struct { body: zir.Module.Body, inst: *zir.Inst, - arena: std.heap.ArenaAllocator.State, }; pub const Zero = struct { @@ -39,11 +40,11 @@ pub const Size = struct { fields: std.AutoArrayHashMap([]const u8, Field), }; -pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void { +pub fn resolveZeroBits(self: *Struct, mod: *Module, scope: *Scope) !void { const zir = switch (self.analysis) { .failed => return error.AnalysisFail, .zero_bits_in_progress => { - return mod.fail(scope, src, "union '{}' depends on itself", .{}); + return mod.fail(scope, src, "struct '{}' depends on itself", .{}); }, .queued => |zir| zir, else => return, @@ -53,5 +54,3 @@ pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void { // TODO } - -pub fn resolveSize(self: *Enum,)
\ No newline at end of file diff --git a/src/type/Union.zig b/src/type/Union.zig index bb1fe56995..f62c7e56fa 100644 --- a/src/type/Union.zig +++ b/src/type/Union.zig @@ -1,8 +1,10 @@ const std = @import("std"); +const zir = @import("../zir.zig"); const Value = @import("../value.zig").Value; const Type = @import("../type.zig").Type; const Module = @import("../Module.zig"); const Scope = Module.Scope; +const Union = @This(); base: Type.Payload = .{ .tag = .@"struct" }, @@ -11,7 +13,7 @@ analysis: union(enum) { zero_bits_in_progress, zero_bits: Zero, in_progress, - alignment: Align, + // alignment: Align, resolved: Size, failed, }, @@ -24,7 +26,6 @@ pub const Field = struct { pub const Zir = struct { body: zir.Module.Body, inst: *zir.Inst, - arena: std.heap.ArenaAllocator.State, }; pub const Zero = struct { @@ -39,7 +40,7 @@ pub const Size = struct { fields: std.AutoArrayHashMap([]const u8, Field), }; -pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void { +pub fn resolveZeroBits(self: *Union, mod: *Module, scope: *Scope) !void { const zir = switch (self.analysis) { .failed => return error.AnalysisFail, .zero_bits_in_progress => { @@ -53,5 +54,3 @@ pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void { // TODO } - -pub fn resolveSize(self: *Enum,)
\ No newline at end of file diff --git a/src/zir.zig b/src/zir.zig index 03b3a630a4..2017ad0f15 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -1084,12 +1084,13 @@ pub const Inst = struct { positionals: struct { bytes: []const u8, - ty: ?*Inst, - init: ?*Inst, - alignment: ?*Inst, - is_comptime: bool, }, - kw_args: struct {}, + kw_args: struct { + ty: ?*Inst = null, + init: ?*Inst = null, + alignment: ?*Inst = null, + is_comptime: bool = false, + }, }; pub const EnumType = struct { @@ -1125,13 +1126,17 @@ pub const Inst = struct { fields: []*Inst, }, kw_args: struct { - init_expr: union(enum) { - enum_type: ?*Inst, - tag_type: *Inst, - none, - }, + init_inst: ?*Inst = null, + init_kind: InitKind = .none, layout: std.builtin.TypeInfo.ContainerLayout = .Auto, }, + + // TODO error: values of type '(enum literal)' must be comptime known + pub const InitKind = enum { + enum_type, + tag_type, + none, + }; }; }; diff --git a/src/zir_sema.zig b/src/zir_sema.zig index 602da97f81..5729644061 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -139,6 +139,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), .booland => return analyzeInstBoolOp(mod, scope, old_inst.castTag(.booland).?), .boolor => return analyzeInstBoolOp(mod, scope, old_inst.castTag(.boolor).?), + + .container_field_named, + .container_field_typed, + .container_field, + .enum_type, + .union_type, + .struct_type, + => return mod.fail(scope, old_inst.src, "TODO analyze container instructions", .{}), } } |
