authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 00:56:30-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 00:56:30-04:00
log4c7507ccebc8b1c03643219dfa45ece668c62993
treea81a6c2ff09574d44ac409f810b7be0ba417ba21
parentcc1c2bd5684a6195e9535fff38ca54ffb70ebe5a

ir: semantic analysis skeleton


4 files changed, 315 insertions(+), 135 deletions(-)

src-self-hosted/ir.zig+197-81
...@@ -8,106 +8,221 @@ const text = @import("ir/text.zig");...@@ -8,106 +8,221 @@ const text = @import("ir/text.zig");
88
9/// These are in-memory, analyzed instructions. See `text.Inst` for the representation9/// These are in-memory, analyzed instructions. See `text.Inst` for the representation
10/// of instructions that correspond to the ZIR text format.10/// of instructions that correspond to the ZIR text format.
11/// This struct owns the `Value` and `Type` memory. When the struct is deallocated,
12/// so are the `Value` and `Type`. The value of a constant must be copied into
13/// a memory location for the value to survive after a const instruction.
11pub const Inst = struct {14pub const Inst = struct {
12 pub fn ty(base: *Inst) ?Type {15 tag: Tag,
13 switch (base.tag) {16 ty: Type,
14 .constant => return base.cast(Constant).?.ty,17 src_offset: usize,
15 .@"asm" => return base.cast(Assembly).?.ty,18
16 .@"fn" => return base.cast(Fn).?.ty,19 pub const Tag = enum {
1720 unreach,
18 .ptrtoint => return Type.initTag(.@"usize"),21 constant,
19 .@"unreachable" => return Type.initTag(.@"noreturn"),22 assembly,
20 .@"export" => return Type.initTag(.@"void"),23 };
21 .fntype, .primitive => return Type.initTag(.@"type"),24
2225 pub fn cast(base: *Inst, comptime T: type) ?*T {
23 .fieldptr,26 if (base.tag != T.base_tag)
24 .deref,27 return null;
25 => return null,28
26 }29 return @fieldParentPtr(T, "base", base);
27 }30 }
2831
29 /// This struct owns the `Value` memory. When the struct is deallocated,
30 /// so is the `Value`. The value of a constant must be copied into
31 /// a memory location for the value to survive after a const instruction.
32 pub const Constant = struct {32 pub const Constant = struct {
33 base: Inst = Inst{ .tag = .constant },33 pub const base_tag = Tag.constant;
34 ty: Type,34 base: Inst,
3535
36 positionals: struct {36 val: Value,
37 value: Value,37 };
38 },38
39 kw_args: struct {},39 pub const Assembly = struct {
40 pub const base_tag = Tag.assembly;
41 base: Inst,
42
43 asm_source: []const u8,
44 is_volatile: bool,
45 output: []const u8,
46 inputs: []const []const u8,
47 clobbers: []const []const u8,
48 args: []const []const u8,
40 };49 };
41};50};
4251
43const Analyze = struct {52const TypedValue = struct {
44 allocator: *Allocator,53 ty: Type,
45 old_tree: *const Module,54 val: Value,
46 errors: std.ArrayList(ErrorMsg),55};
47 decls: std.ArrayList(*Inst),
4856
49 const NewInst = struct {57pub const Module = struct {
50 ptr: *Inst,58 exports: []Export,
59 errors: []ErrorMsg,
60 arena: std.heap.ArenaAllocator,
61
62 pub const Export = struct {
63 name: []const u8,
64 typed_value: TypedValue,
51 };65 };
66
67 pub fn deinit(self: *Module, allocator: *Allocator) void {
68 allocator.free(self.exports);
69 allocator.free(self.errors);
70 self.arena.deinit();
71 self.* = undefined;
72 }
73
74 pub fn emit_zir(self: Module, allocator: *Allocator) !text.Module {
75 return error.TodoImplementEmitToZIR;
76 }
52};77};
5378
54pub fn analyze(allocator: *Allocator, old_tree: Module) !Module {79pub const ErrorMsg = struct {
80 byte_offset: usize,
81 msg: []const u8,
82};
83
84pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
55 var ctx = Analyze{85 var ctx = Analyze{
56 .allocator = allocator,86 .allocator = allocator,
57 .old_tree = &old_tree,87 .arena = std.heap.ArenaAllocator.init(allocator),
58 .decls = std.ArrayList(*Inst).init(allocator),88 .old_module = &old_module,
59 .errors = std.ArrayList(ErrorMsg).init(allocator),89 .errors = std.ArrayList(ErrorMsg).init(allocator),
60 .inst_table = std.HashMap(*Inst, Analyze.InstData).init(allocator),90 .inst_table = std.AutoHashMap(*text.Inst, Analyze.NewInst).init(allocator),
91 .exports = std.ArrayList(Module.Export).init(allocator),
61 };92 };
62 defer ctx.decls.deinit();
63 defer ctx.errors.deinit();93 defer ctx.errors.deinit();
64 defer inst_table.deinit();94 defer ctx.inst_table.deinit();
95 defer ctx.exports.deinit();
6596
66 analyzeRoot(&ctx) catch |err| switch (err) {97 ctx.analyzeRoot() catch |err| switch (err) {
67 error.AnalyzeFailure => {98 error.AnalysisFail => {
68 assert(ctx.errors.items.len != 0);99 assert(ctx.errors.items.len != 0);
69 },100 },
70 else => |e| return e,101 else => |e| return e,
71 };102 };
72 return Module{103 return Module{
73 .decls = ctx.decls.toOwnedSlice(),104 .exports = ctx.exports.toOwnedSlice(),
74 .errors = ctx.errors.toOwnedSlice(),105 .errors = ctx.errors.toOwnedSlice(),
106 .arena = ctx.arena,
75 };107 };
76}108}
77109
78fn analyzeRoot(ctx: *Analyze) !void {110const Analyze = struct {
79 for (old_tree.decls) |decl| {111 allocator: *Allocator,
80 if (decl.cast(Inst.Export)) |export_inst| {112 arena: std.heap.ArenaAllocator,
81 try analyzeExport(ctx, export_inst);113 old_module: *const text.Module,
114 errors: std.ArrayList(ErrorMsg),
115 inst_table: std.AutoHashMap(*text.Inst, NewInst),
116 exports: std.ArrayList(Module.Export),
117
118 const NewInst = struct {
119 /// null means a semantic analysis error happened
120 ptr: ?*Inst,
121 };
122
123 const InnerError = error{ OutOfMemory, AnalysisFail };
124
125 fn analyzeRoot(self: *Analyze) !void {
126 for (self.old_module.decls) |decl| {
127 if (decl.cast(text.Inst.Export)) |export_inst| {
128 try analyzeExport(self, export_inst);
129 }
82 }130 }
83 }131 }
84}
85132
86fn analyzeExport(ctx: *Analyze, export_inst: *Inst.Export) !void {133 fn resolveInst(self: *Analyze, old_inst: *text.Inst) InnerError!*Inst {
87 const old_decl = export_inst.positionals.value;134 if (self.inst_table.get(old_inst)) |kv| {
88 const new_info = ctx.inst_table.get(old_exp_target) orelse blk: {135 return kv.value.ptr orelse return error.AnalysisFail;
89 const new_decl = try analyzeDecl(ctx, old_decl);136 } else {
90 const new_info: Analyze.NewInst = .{ .ptr = new_decl };137 const new_inst = self.analyzeDecl(old_inst) catch |err| switch (err) {
91 try ctx.inst_table.put(old_decl, new_info);138 error.AnalysisFail => {
92 break :blk new_info;139 try self.inst_table.putNoClobber(old_inst, .{ .ptr = null });
93 };140 return error.AnalysisFail;
141 },
142 else => |e| return e,
143 };
144 try self.inst_table.putNoClobber(old_inst, .{ .ptr = new_inst });
145 return new_inst;
146 }
147 }
94148
95 //const exp_type = new_info.ptr.ty();149 fn resolveInstConst(self: *Analyze, old_inst: *text.Inst) InnerError!TypedValue {
96 //switch (exp_type.zigTypeTag()) {150 const new_inst = try self.resolveInst(old_inst);
97 // .Fn => {151 const val = try self.resolveConstValue(new_inst);
98 // if () |kv| {152 return TypedValue{
99 // kv.value153 .ty = new_inst.ty,
100 // }154 .val = val,
101 // return analyzeExportFn(ctx, exp_target.cast(Inst.,155 };
102 // },156 }
103 // else => return ctx.fail("unable to export type '{}'", .{exp_type}),157
104 //}158 fn resolveConstValue(self: *Analyze, base: *Inst) !Value {
105}159 const const_inst = base.cast(Inst.Constant) orelse
160 return self.fail(base.src_offset, "unable to resolve comptime value", .{});
161 return const_inst.val;
162 }
163
164 fn resolveConstString(self: *Analyze, old_inst: *text.Inst) ![]u8 {
165 const new_inst = try self.resolveInst(old_inst);
166 const wanted_type = Type.initTag(.const_slice_u8);
167 const coerced_inst = try self.coerce(wanted_type, new_inst);
168 const val = try self.resolveConstValue(coerced_inst);
169 return val.toAllocatedBytes(&self.arena.allocator);
170 }
171
172 fn analyzeExport(self: *Analyze, export_inst: *text.Inst.Export) !void {
173 const symbol_name = try self.resolveConstString(export_inst.positionals.symbol_name);
174 const typed_value = try self.resolveInstConst(export_inst.positionals.value);
175
176 switch (typed_value.ty.zigTypeTag()) {
177 .Fn => {},
178 else => return self.fail(
179 export_inst.positionals.value.src_offset,
180 "unable to export type '{}'",
181 .{typed_value.ty},
182 ),
183 }
184 try self.exports.append(.{
185 .name = symbol_name,
186 .typed_value = typed_value,
187 });
188 }
189
190 fn analyzeDecl(self: *Analyze, old_inst: *text.Inst) !*Inst {
191 switch (old_inst.tag) {
192 .str => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
193 .int => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
194 .ptrtoint => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
195 .fieldptr => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
196 .deref => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
197 .as => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
198 .@"asm" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
199 .@"unreachable" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
200 .@"fn" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
201 .@"export" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
202 .primitive => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
203 .fntype => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
204 }
205 }
206
207 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
208 return self.fail(inst.src_offset, "TODO implement type coercion", .{});
209 }
210
211 fn fail(self: *Analyze, src_offset: usize, comptime format: []const u8, args: var) InnerError {
212 @setCold(true);
213 const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args);
214 (try self.errors.addOne()).* = .{
215 .byte_offset = src_offset,
216 .msg = msg,
217 };
218 return error.AnalysisFail;
219 }
220};
106221
107pub fn main() anyerror!void {222pub fn main() anyerror!void {
108 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);223 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
109 defer arena.deinit();224 defer arena.deinit();
110 const allocator = &arena.allocator;225 const allocator = if (std.builtin.link_libc) std.heap.c_allocator else &arena.allocator;
111226
112 const args = try std.process.argsAlloc(allocator);227 const args = try std.process.argsAlloc(allocator);
113228
...@@ -116,11 +231,11 @@ pub fn main() anyerror!void {...@@ -116,11 +231,11 @@ pub fn main() anyerror!void {
116231
117 const source = try std.fs.cwd().readFileAllocOptions(allocator, src_path, std.math.maxInt(u32), 1, 0);232 const source = try std.fs.cwd().readFileAllocOptions(allocator, src_path, std.math.maxInt(u32), 1, 0);
118233
119 var tree = try text.parse(allocator, source);234 var zir_module = try text.parse(allocator, source);
120 defer tree.deinit();235 defer zir_module.deinit(allocator);
121236
122 if (tree.errors.len != 0) {237 if (zir_module.errors.len != 0) {
123 for (tree.errors) |err_msg| {238 for (zir_module.errors) |err_msg| {
124 const loc = findLineColumn(source, err_msg.byte_offset);239 const loc = findLineColumn(source, err_msg.byte_offset);
125 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });240 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
126 }241 }
...@@ -128,21 +243,22 @@ pub fn main() anyerror!void {...@@ -128,21 +243,22 @@ pub fn main() anyerror!void {
128 std.process.exit(1);243 std.process.exit(1);
129 }244 }
130245
131 tree.dump();246 var analyzed_module = try analyze(allocator, zir_module);
247 defer analyzed_module.deinit(allocator);
132248
133 //const new_tree = try analyze(allocator, tree);249 if (analyzed_module.errors.len != 0) {
134 //defer new_tree.deinit();250 for (analyzed_module.errors) |err_msg| {
251 const loc = findLineColumn(source, err_msg.byte_offset);
252 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
253 }
254 if (debug_error_trace) return error.ParseFailure;
255 std.process.exit(1);
256 }
135257
136 //if (new_tree.errors.len != 0) {258 var new_zir_module = try analyzed_module.emit_zir(allocator);
137 // for (new_tree.errors) |err_msg| {259 defer new_zir_module.deinit(allocator);
138 // const loc = findLineColumn(source, err_msg.byte_offset);
139 // std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
140 // }
141 // if (debug_error_trace) return error.ParseFailure;
142 // std.process.exit(1);
143 //}
144260
145 //new_tree.dump();261 new_zir_module.dump();
146}262}
147263
148fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {264fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
src-self-hosted/ir/text.zig+46-23
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1//! This file has to do with parsing and rendering the ZIR text format.1//! This file has to do with parsing and rendering the ZIR text format.
2
2const std = @import("std");3const std = @import("std");
3const mem = std.mem;4const mem = std.mem;
4const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
...@@ -11,6 +12,7 @@ const BigInt = std.math.big.Int;...@@ -11,6 +12,7 @@ const BigInt = std.math.big.Int;
11/// in-memory, analyzed instructions with types and values.12/// in-memory, analyzed instructions with types and values.
12pub const Inst = struct {13pub const Inst = struct {
13 tag: Tag,14 tag: Tag,
15 src_offset: usize,
1416
15 /// These names are used directly as the instruction names in the text format.17 /// These names are used directly as the instruction names in the text format.
16 pub const Tag = enum {18 pub const Tag = enum {
...@@ -46,15 +48,15 @@ pub const Inst = struct {...@@ -46,15 +48,15 @@ pub const Inst = struct {
46 }48 }
4749
48 pub fn cast(base: *Inst, comptime T: type) ?*T {50 pub fn cast(base: *Inst, comptime T: type) ?*T {
49 const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;51 if (base.tag != T.base_tag)
50 if (base.tag != expected_tag)
51 return null;52 return null;
5253
53 return @fieldParentPtr(T, "base", base);54 return @fieldParentPtr(T, "base", base);
54 }55 }
5556
56 pub const Str = struct {57 pub const Str = struct {
57 base: Inst = Inst{ .tag = .str },58 pub const base_tag = Tag.str;
59 base: Inst,
5860
59 positionals: struct {61 positionals: struct {
60 bytes: []u8,62 bytes: []u8,
...@@ -63,7 +65,8 @@ pub const Inst = struct {...@@ -63,7 +65,8 @@ pub const Inst = struct {
63 };65 };
6466
65 pub const Int = struct {67 pub const Int = struct {
66 base: Inst = Inst{ .tag = .int },68 pub const base_tag = Tag.int;
69 base: Inst,
6770
68 positionals: struct {71 positionals: struct {
69 int: BigInt,72 int: BigInt,
...@@ -72,7 +75,8 @@ pub const Inst = struct {...@@ -72,7 +75,8 @@ pub const Inst = struct {
72 };75 };
7376
74 pub const PtrToInt = struct {77 pub const PtrToInt = struct {
75 base: Inst = Inst{ .tag = .ptrtoint },78 pub const base_tag = Tag.ptrtoint;
79 base: Inst,
7680
77 positionals: struct {81 positionals: struct {
78 ptr: *Inst,82 ptr: *Inst,
...@@ -81,7 +85,8 @@ pub const Inst = struct {...@@ -81,7 +85,8 @@ pub const Inst = struct {
81 };85 };
8286
83 pub const FieldPtr = struct {87 pub const FieldPtr = struct {
84 base: Inst = Inst{ .tag = .fieldptr },88 pub const base_tag = Tag.fieldptr;
89 base: Inst,
8590
86 positionals: struct {91 positionals: struct {
87 object_ptr: *Inst,92 object_ptr: *Inst,
...@@ -91,7 +96,8 @@ pub const Inst = struct {...@@ -91,7 +96,8 @@ pub const Inst = struct {
91 };96 };
9297
93 pub const Deref = struct {98 pub const Deref = struct {
94 base: Inst = Inst{ .tag = .deref },99 pub const base_tag = Tag.deref;
100 base: Inst,
95101
96 positionals: struct {102 positionals: struct {
97 ptr: *Inst,103 ptr: *Inst,
...@@ -100,7 +106,8 @@ pub const Inst = struct {...@@ -100,7 +106,8 @@ pub const Inst = struct {
100 };106 };
101107
102 pub const As = struct {108 pub const As = struct {
103 base: Inst = Inst{ .tag = .as },109 pub const base_tag = Tag.as;
110 base: Inst,
104111
105 positionals: struct {112 positionals: struct {
106 dest_type: *Inst,113 dest_type: *Inst,
...@@ -110,7 +117,8 @@ pub const Inst = struct {...@@ -110,7 +117,8 @@ pub const Inst = struct {
110 };117 };
111118
112 pub const Assembly = struct {119 pub const Assembly = struct {
113 base: Inst = Inst{ .tag = .@"asm" },120 pub const base_tag = Tag.@"asm";
121 base: Inst,
114122
115 positionals: struct {123 positionals: struct {
116 asm_source: *Inst,124 asm_source: *Inst,
...@@ -126,14 +134,16 @@ pub const Inst = struct {...@@ -126,14 +134,16 @@ pub const Inst = struct {
126 };134 };
127135
128 pub const Unreachable = struct {136 pub const Unreachable = struct {
129 base: Inst = Inst{ .tag = .@"unreachable" },137 pub const base_tag = Tag.@"unreachable";
138 base: Inst,
130139
131 positionals: struct {},140 positionals: struct {},
132 kw_args: struct {},141 kw_args: struct {},
133 };142 };
134143
135 pub const Fn = struct {144 pub const Fn = struct {
136 base: Inst = Inst{ .tag = .@"fn" },145 pub const base_tag = Tag.@"fn";
146 base: Inst,
137147
138 positionals: struct {148 positionals: struct {
139 fn_type: *Inst,149 fn_type: *Inst,
...@@ -147,7 +157,8 @@ pub const Inst = struct {...@@ -147,7 +157,8 @@ pub const Inst = struct {
147 };157 };
148158
149 pub const Export = struct {159 pub const Export = struct {
150 base: Inst = Inst{ .tag = .@"export" },160 pub const base_tag = Tag.@"export";
161 base: Inst,
151162
152 positionals: struct {163 positionals: struct {
153 symbol_name: *Inst,164 symbol_name: *Inst,
...@@ -157,7 +168,8 @@ pub const Inst = struct {...@@ -157,7 +168,8 @@ pub const Inst = struct {
157 };168 };
158169
159 pub const Primitive = struct {170 pub const Primitive = struct {
160 base: Inst = Inst{ .tag = .primitive },171 pub const base_tag = Tag.primitive;
172 base: Inst,
161173
162 positionals: struct {174 positionals: struct {
163 tag: BuiltinType,175 tag: BuiltinType,
...@@ -192,7 +204,8 @@ pub const Inst = struct {...@@ -192,7 +204,8 @@ pub const Inst = struct {
192 };204 };
193205
194 pub const FnType = struct {206 pub const FnType = struct {
195 base: Inst = Inst{ .tag = .fntype },207 pub const base_tag = Tag.fntype;
208 base: Inst,
196209
197 positionals: struct {210 positionals: struct {
198 param_types: []*Inst,211 param_types: []*Inst,
...@@ -212,9 +225,12 @@ pub const ErrorMsg = struct {...@@ -212,9 +225,12 @@ pub const ErrorMsg = struct {
212pub const Module = struct {225pub const Module = struct {
213 decls: []*Inst,226 decls: []*Inst,
214 errors: []ErrorMsg,227 errors: []ErrorMsg,
228 arena: std.heap.ArenaAllocator,
215229
216 pub fn deinit(self: *Module) void {230 pub fn deinit(self: *Module, allocator: *Allocator) void {
217 // TODO resource deallocation231 allocator.free(self.decls);
232 allocator.free(self.errors);
233 self.arena.deinit();
218 self.* = undefined;234 self.* = undefined;
219 }235 }
220236
...@@ -225,6 +241,8 @@ pub const Module = struct {...@@ -225,6 +241,8 @@ pub const Module = struct {
225241
226 const InstPtrTable = std.AutoHashMap(*Inst, struct { index: usize, fn_body: ?*Inst.Fn.Body });242 const InstPtrTable = std.AutoHashMap(*Inst, struct { index: usize, fn_body: ?*Inst.Fn.Body });
227243
244 /// The allocator is used for temporary storage, but this function always returns
245 /// with no resources allocated.
228 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {246 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {
229 // First, build a map of *Inst to @ or % indexes247 // First, build a map of *Inst to @ or % indexes
230 var inst_table = InstPtrTable.init(allocator);248 var inst_table = InstPtrTable.init(allocator);
...@@ -359,6 +377,7 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module...@@ -359,6 +377,7 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
359377
360 var parser: Parser = .{378 var parser: Parser = .{
361 .allocator = allocator,379 .allocator = allocator,
380 .arena = std.heap.ArenaAllocator.init(allocator),
362 .i = 0,381 .i = 0,
363 .source = source,382 .source = source,
364 .decls = std.ArrayList(*Inst).init(allocator),383 .decls = std.ArrayList(*Inst).init(allocator),
...@@ -374,11 +393,13 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module...@@ -374,11 +393,13 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
374 return Module{393 return Module{
375 .decls = parser.decls.toOwnedSlice(),394 .decls = parser.decls.toOwnedSlice(),
376 .errors = parser.errors.toOwnedSlice(),395 .errors = parser.errors.toOwnedSlice(),
396 .arena = parser.arena,
377 };397 };
378}398}
379399
380const Parser = struct {400const Parser = struct {
381 allocator: *Allocator,401 allocator: *Allocator,
402 arena: std.heap.ArenaAllocator,
382 i: usize,403 i: usize,
383 source: [:0]const u8,404 source: [:0]const u8,
384 errors: std.ArrayList(ErrorMsg),405 errors: std.ArrayList(ErrorMsg),
...@@ -439,7 +460,7 @@ const Parser = struct {...@@ -439,7 +460,7 @@ const Parser = struct {
439 self.i += 1;460 self.i += 1;
440 const span = self.source[start..self.i];461 const span = self.source[start..self.i];
441 var bad_index: usize = undefined;462 var bad_index: usize = undefined;
442 const parsed = std.zig.parseStringLiteral(self.allocator, span, &bad_index) catch |err| switch (err) {463 const parsed = std.zig.parseStringLiteral(&self.arena.allocator, span, &bad_index) catch |err| switch (err) {
443 error.InvalidCharacter => {464 error.InvalidCharacter => {
444 self.i = start + bad_index;465 self.i = start + bad_index;
445 const bad_byte = self.source[self.i];466 const bad_byte = self.source[self.i];
...@@ -466,7 +487,7 @@ const Parser = struct {...@@ -466,7 +487,7 @@ const Parser = struct {
466 else => break,487 else => break,
467 };488 };
468 const number_text = self.source[start..self.i];489 const number_text = self.source[start..self.i];
469 var result = try BigInt.init(self.allocator);490 var result = try BigInt.init(&self.arena.allocator);
470 result.setString(10, number_text) catch |err| {491 result.setString(10, number_text) catch |err| {
471 self.i = start;492 self.i = start;
472 switch (err) {493 switch (err) {
...@@ -551,7 +572,7 @@ const Parser = struct {...@@ -551,7 +572,7 @@ const Parser = struct {
551572
552 fn fail(self: *Parser, comptime format: []const u8, args: var) InnerError {573 fn fail(self: *Parser, comptime format: []const u8, args: var) InnerError {
553 @setCold(true);574 @setCold(true);
554 const msg = try std.fmt.allocPrint(self.allocator, format, args);575 const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args);
555 (try self.errors.addOne()).* = .{576 (try self.errors.addOne()).* = .{
556 .byte_offset = self.i,577 .byte_offset = self.i,
557 .msg = msg,578 .msg = msg,
...@@ -576,8 +597,11 @@ const Parser = struct {...@@ -576,8 +597,11 @@ const Parser = struct {
576 comptime InstType: type,597 comptime InstType: type,
577 body_ctx: ?*Body,598 body_ctx: ?*Body,
578 ) !*Inst {599 ) !*Inst {
579 const inst_specific = try self.allocator.create(InstType);600 const inst_specific = try self.arena.allocator.create(InstType);
580 inst_specific.base = std.meta.fieldInfo(InstType, "base").default_value.?;601 inst_specific.base = .{
602 .src_offset = self.i,
603 .tag = InstType.base_tag,
604 };
581605
582 if (@hasField(InstType, "ty")) {606 if (@hasField(InstType, "ty")) {
583 inst_specific.ty = opt_type orelse {607 inst_specific.ty = opt_type orelse {
...@@ -657,8 +681,7 @@ const Parser = struct {...@@ -657,8 +681,7 @@ const Parser = struct {
657 skipSpace(self);681 skipSpace(self);
658 if (eatByte(self, ']')) return &[0]*Inst{};682 if (eatByte(self, ']')) return &[0]*Inst{};
659683
660 var instructions = std.ArrayList(*Inst).init(self.allocator);684 var instructions = std.ArrayList(*Inst).init(&self.arena.allocator);
661 defer instructions.deinit();
662 while (true) {685 while (true) {
663 skipSpace(self);686 skipSpace(self);
664 try instructions.append(try parseParameterInst(self, body_ctx));687 try instructions.append(try parseParameterInst(self, body_ctx));
src-self-hosted/type.zig+63-31
...@@ -18,9 +18,39 @@ pub const Type = extern union {...@@ -18,9 +18,39 @@ pub const Type = extern union {
1818
19 pub fn zigTypeTag(self: Type) std.builtin.TypeId {19 pub fn zigTypeTag(self: Type) std.builtin.TypeId {
20 switch (self.tag()) {20 switch (self.tag()) {
21 .@"u8", .@"usize" => return .Int,21 .@"u8",
22 .array_u8, .array_u8_sentinel_0 => return .Array,22 .@"i8",
23 .@"isize",
24 .@"usize",
25 .@"c_short",
26 .@"c_ushort",
27 .@"c_int",
28 .@"c_uint",
29 .@"c_long",
30 .@"c_ulong",
31 .@"c_longlong",
32 .@"c_ulonglong",
33 .@"c_longdouble",
34 => return .Int,
35
36 .@"f16",
37 .@"f32",
38 .@"f64",
39 .@"f128",
40 => return .Float,
41
42 .@"c_void" => return .Opaque,
43 .@"bool" => return .Bool,
44 .@"void" => return .Void,
45 .@"type" => return .Type,
46 .@"anyerror" => return .ErrorSet,
47 .@"comptime_int" => return .ComptimeInt,
48 .@"comptime_float" => return .ComptimeFloat,
49 .@"noreturn" => return .NoReturn,
50
51 .array, .array_u8_sentinel_0 => return .Array,
23 .single_const_pointer => return .Pointer,52 .single_const_pointer => return .Pointer,
53 .const_slice_u8 => return .Pointer,
24 }54 }
25 }55 }
2656
...@@ -51,35 +81,36 @@ pub const Type = extern union {...@@ -51,35 +81,36 @@ pub const Type = extern union {
51 comptime assert(fmt.len == 0);81 comptime assert(fmt.len == 0);
52 var ty = self;82 var ty = self;
53 while (true) {83 while (true) {
54 switch (ty.tag()) {84 const t = ty.tag();
55 @"u8",85 switch (t) {
56 @"i8",86 .@"u8",
57 @"isize",87 .@"i8",
58 @"usize",88 .@"isize",
59 @"noreturn",89 .@"usize",
60 @"void",90 .@"c_short",
61 @"c_short",91 .@"c_ushort",
62 @"c_ushort",92 .@"c_int",
63 @"c_int",93 .@"c_uint",
64 @"c_uint",94 .@"c_long",
65 @"c_long",95 .@"c_ulong",
66 @"c_ulong",96 .@"c_longlong",
67 @"c_longlong",97 .@"c_ulonglong",
68 @"c_ulonglong",98 .@"c_longdouble",
69 @"c_longdouble",99 .@"c_void",
70 @"c_void",100 .@"f16",
71 @"f16",101 .@"f32",
72 @"f32",102 .@"f64",
73 @"f64",103 .@"f128",
74 @"f128",104 .@"bool",
75 @"bool",105 .@"void",
76 @"void",106 .@"type",
77 @"type",107 .@"anyerror",
78 @"anyerror",108 .@"comptime_int",
79 @"comptime_int",109 .@"comptime_float",
80 @"comptime_float",110 .@"noreturn",
81 @"noreturn",111 => return out_stream.writeAll(@tagName(t)),
82 => |t| return out_stream.writeAll(@tagName(t)),112
113 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
83114
84 .array_u8_sentinel_0 => {115 .array_u8_sentinel_0 => {
85 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);116 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
...@@ -110,6 +141,7 @@ pub const Type = extern union {...@@ -110,6 +141,7 @@ pub const Type = extern union {
110 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.141 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
111 pub const Tag = enum {142 pub const Tag = enum {
112 // The first section of this enum are tags that require no payload.143 // The first section of this enum are tags that require no payload.
144 const_slice_u8,
113 @"u8",145 @"u8",
114 @"i8",146 @"i8",
115 @"isize",147 @"isize",
src-self-hosted/value.zig+9
...@@ -91,6 +91,15 @@ pub const Value = extern union {...@@ -91,6 +91,15 @@ pub const Value = extern union {
91 }91 }
92 }92 }
9393
94 /// Asserts that the value is representable as an array of bytes.
95 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
96 pub fn toAllocatedBytes(self: Value, allocator: *std.mem.Allocator) error{OutOfMemory}![]u8 {
97 if (self.cast(Payload.Bytes)) |bytes| {
98 return std.mem.dupe(allocator, u8, bytes.data);
99 }
100 unreachable;
101 }
102
94 /// This type is not copyable since it may contain pointers to its inner data.103 /// This type is not copyable since it may contain pointers to its inner data.
95 pub const Payload = struct {104 pub const Payload = struct {
96 tag: Tag,105 tag: Tag,