authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-18 20:04:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-19 19:31:50-04:00
log59154a1c51eae06c961b1ec9526901a93cdddf4b
tree637f41c9aa379e17048c92e2e160fce6c883ea50
parent018daa028e2705a6a5d7621cccd277a490f17646

ir: parse fn body


1 files changed, 66 insertions(+), 26 deletions(-)

src-self-hosted/ir.zig+66-26
...@@ -99,40 +99,45 @@ pub const ErrorMsg = struct {...@@ -99,40 +99,45 @@ pub const ErrorMsg = struct {
99};99};
100100
101pub const Tree = struct {101pub const Tree = struct {
102 decls: std.ArrayList(*Inst),102 decls: []*Inst,
103 errors: std.ArrayList(ErrorMsg),103 errors: []ErrorMsg,
104};104};
105105
106const ParseContext = struct {106const ParseContext = struct {
107 allocator: *Allocator,107 allocator: *Allocator,
108 i: usize,108 i: usize,
109 source: []const u8,109 source: []const u8,
110 errors: *std.ArrayList(ErrorMsg),110 errors: std.ArrayList(ErrorMsg),
111 decls: std.ArrayList(*Inst),
112 global_name_map: *std.StringHashMap(usize),
111};113};
112114
113pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!Tree {115pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!Tree {
114 var tree: Tree = .{116 var global_name_map = std.StringHashMap(usize).init(allocator);
115 .decls = std.ArrayList(*Inst).init(allocator),117 defer global_name_map.deinit();
116 .errors = std.ArrayList(ErrorMsg).init(allocator),118
117 };
118 var ctx: ParseContext = .{119 var ctx: ParseContext = .{
119 .allocator = allocator,120 .allocator = allocator,
120 .i = 0,121 .i = 0,
121 .source = source,122 .source = source,
122 .errors = &tree.errors,123 .decls = std.ArrayList(*Inst).init(allocator),
124 .errors = std.ArrayList(ErrorMsg).init(allocator),
125 .global_name_map = &global_name_map,
123 };126 };
124 parseRoot(&ctx, &tree) catch |err| switch (err) {127 parseRoot(&ctx) catch |err| switch (err) {
125 error.ParseFailure => {128 error.ParseFailure => {
126 assert(tree.errors.items.len != 0);129 assert(ctx.errors.items.len != 0);
127 },130 },
128 else => |e| return e,131 else => |e| return e,
129 };132 };
130 return tree;133 return Tree{
134 .decls = ctx.decls.toOwnedSlice(),
135 .errors = ctx.errors.toOwnedSlice(),
136 };
131}137}
132138
133pub fn parseRoot(ctx: *ParseContext, tree: *Tree) !void {139pub fn parseRoot(ctx: *ParseContext) !void {
134 // The IR format is designed so that it can be tokenized and parsed at the same time.140 // The IR format is designed so that it can be tokenized and parsed at the same time.
135 var global_name_map = std.StringHashMap(usize).init(ctx.allocator);
136 while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {141 while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
137 ';' => _ = try skipToAndOver(ctx, '\n'),142 ';' => _ = try skipToAndOver(ctx, '\n'),
138 '@' => {143 '@' => {
...@@ -145,11 +150,11 @@ pub fn parseRoot(ctx: *ParseContext, tree: *Tree) !void {...@@ -145,11 +150,11 @@ pub fn parseRoot(ctx: *ParseContext, tree: *Tree) !void {
145 }150 }
146 try requireEatBytes(ctx, "= ");151 try requireEatBytes(ctx, "= ");
147 const inst = try parseInstruction(ctx);152 const inst = try parseInstruction(ctx);
148 const ident_index = tree.decls.items.len;153 const ident_index = ctx.decls.items.len;
149 if (try global_name_map.put(ident, ident_index)) |_| {154 if (try ctx.global_name_map.put(ident, ident_index)) |_| {
150 return parseError(ctx, "redefinition of identifier '{}'", .{ident});155 return parseError(ctx, "redefinition of identifier '{}'", .{ident});
151 }156 }
152 try tree.decls.append(inst);157 try ctx.decls.append(inst);
153 continue;158 continue;
154 },159 },
155 ' ', '\n' => continue,160 ' ', '\n' => continue,
...@@ -201,7 +206,7 @@ fn parseType(ctx: *ParseContext) !*Value {...@@ -201,7 +206,7 @@ fn parseType(ctx: *ParseContext) !*Value {
201 return parseError(ctx, "TODO parse type", .{});206 return parseError(ctx, "TODO parse type", .{});
202}207}
203208
204fn parseInstruction(ctx: *ParseContext) !*Inst {209fn parseInstruction(ctx: *ParseContext) error{ OutOfMemory, ParseFailure }!*Inst {
205 switch (ctx.source[ctx.i]) {210 switch (ctx.source[ctx.i]) {
206 '"' => return parseStringLiteralConst(ctx),211 '"' => return parseStringLiteralConst(ctx),
207 '0'...'9' => return parseIntegerLiteralConst(ctx),212 '0'...'9' => return parseIntegerLiteralConst(ctx),
...@@ -260,19 +265,54 @@ fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {...@@ -260,19 +265,54 @@ fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {
260 return parseError(ctx, "unexpected EOF in enum parameter", .{});265 return parseError(ctx, "unexpected EOF in enum parameter", .{});
261 }266 }
262 switch (T) {267 switch (T) {
263 Inst.Fn.Body => {268 Inst.Fn.Body => return parseBody(ctx),
264 var instructions = std.ArrayList(*Inst).init(ctx.allocator);
265 try requireEatBytes(ctx, "{");
266 return T{
267 .instructions = instructions.toOwnedSlice(),
268 };
269 },
270 Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),269 Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),
271 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),270 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
272 }271 }
273 return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});272 return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
274}273}
275274
275fn parseBody(ctx: *ParseContext) !Inst.Fn.Body {
276 var instructions = std.ArrayList(*Inst).init(ctx.allocator);
277 defer instructions.deinit();
278
279 var name_map = std.StringHashMap(usize).init(ctx.allocator);
280 defer name_map.deinit();
281
282 try requireEatBytes(ctx, "{");
283 skipSpace(ctx);
284
285 while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
286 ';' => _ = try skipToAndOver(ctx, '\n'),
287 '%' => {
288 const at_start = ctx.i;
289 const ident = try skipToAndOver(ctx, ' ');
290 var ty: ?*Value = null;
291 if (eatByte(ctx, ':')) {
292 skipSpace(ctx);
293 ty = try parseType(ctx);
294 skipSpace(ctx);
295 }
296 skipSpace(ctx);
297 try requireEatBytes(ctx, "=");
298 skipSpace(ctx);
299 const inst = try parseInstruction(ctx);
300 const ident_index = instructions.items.len;
301 if (try name_map.put(ident, ident_index)) |_| {
302 return parseError(ctx, "redefinition of identifier '{}'", .{ident});
303 }
304 try instructions.append(inst);
305 continue;
306 },
307 ' ', '\n' => continue,
308 else => |byte| return parseError(ctx, "unexpected byte: '{c}'", .{byte}),
309 };
310
311 return Inst.Fn.Body{
312 .instructions = instructions.toOwnedSlice(),
313 };
314}
315
276fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {316fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
277 const start = ctx.i;317 const start = ctx.i;
278 ctx.i += 1; // skip over '"'318 ctx.i += 1; // skip over '"'
...@@ -333,8 +373,8 @@ pub fn main() anyerror!void {...@@ -333,8 +373,8 @@ pub fn main() anyerror!void {
333 const source = try std.fs.cwd().readFileAlloc(allocator, src_path, std.math.maxInt(u32));373 const source = try std.fs.cwd().readFileAlloc(allocator, src_path, std.math.maxInt(u32));
334374
335 const tree = try parse(allocator, source);375 const tree = try parse(allocator, source);
336 if (tree.errors.items.len != 0) {376 if (tree.errors.len != 0) {
337 for (tree.errors.items) |err_msg| {377 for (tree.errors) |err_msg| {
338 const loc = findLineColumn(source, err_msg.byte_offset);378 const loc = findLineColumn(source, err_msg.byte_offset);
339 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });379 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
340 }380 }