ir: parse fn body
This commit is contained in:
parent
018daa028e
commit
59154a1c51
|
@ -99,40 +99,45 @@ pub const ErrorMsg = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Tree = struct {
|
pub const Tree = struct {
|
||||||
decls: std.ArrayList(*Inst),
|
decls: []*Inst,
|
||||||
errors: std.ArrayList(ErrorMsg),
|
errors: []ErrorMsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ParseContext = struct {
|
const ParseContext = struct {
|
||||||
allocator: *Allocator,
|
allocator: *Allocator,
|
||||||
i: usize,
|
i: usize,
|
||||||
source: []const u8,
|
source: []const u8,
|
||||||
errors: *std.ArrayList(ErrorMsg),
|
errors: std.ArrayList(ErrorMsg),
|
||||||
|
decls: std.ArrayList(*Inst),
|
||||||
|
global_name_map: *std.StringHashMap(usize),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!Tree {
|
pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!Tree {
|
||||||
var tree: Tree = .{
|
var global_name_map = std.StringHashMap(usize).init(allocator);
|
||||||
.decls = std.ArrayList(*Inst).init(allocator),
|
defer global_name_map.deinit();
|
||||||
.errors = std.ArrayList(ErrorMsg).init(allocator),
|
|
||||||
};
|
|
||||||
var ctx: ParseContext = .{
|
var ctx: ParseContext = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.i = 0,
|
.i = 0,
|
||||||
.source = source,
|
.source = source,
|
||||||
.errors = &tree.errors,
|
.decls = std.ArrayList(*Inst).init(allocator),
|
||||||
|
.errors = std.ArrayList(ErrorMsg).init(allocator),
|
||||||
|
.global_name_map = &global_name_map,
|
||||||
};
|
};
|
||||||
parseRoot(&ctx, &tree) catch |err| switch (err) {
|
parseRoot(&ctx) catch |err| switch (err) {
|
||||||
error.ParseFailure => {
|
error.ParseFailure => {
|
||||||
assert(tree.errors.items.len != 0);
|
assert(ctx.errors.items.len != 0);
|
||||||
},
|
},
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
return tree;
|
return Tree{
|
||||||
|
.decls = ctx.decls.toOwnedSlice(),
|
||||||
|
.errors = ctx.errors.toOwnedSlice(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parseRoot(ctx: *ParseContext, tree: *Tree) !void {
|
pub fn parseRoot(ctx: *ParseContext) !void {
|
||||||
// The IR format is designed so that it can be tokenized and parsed at the same time.
|
// The IR format is designed so that it can be tokenized and parsed at the same time.
|
||||||
var global_name_map = std.StringHashMap(usize).init(ctx.allocator);
|
|
||||||
while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
|
while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
|
||||||
';' => _ = try skipToAndOver(ctx, '\n'),
|
';' => _ = try skipToAndOver(ctx, '\n'),
|
||||||
'@' => {
|
'@' => {
|
||||||
|
@ -145,11 +150,11 @@ pub fn parseRoot(ctx: *ParseContext, tree: *Tree) !void {
|
||||||
}
|
}
|
||||||
try requireEatBytes(ctx, "= ");
|
try requireEatBytes(ctx, "= ");
|
||||||
const inst = try parseInstruction(ctx);
|
const inst = try parseInstruction(ctx);
|
||||||
const ident_index = tree.decls.items.len;
|
const ident_index = ctx.decls.items.len;
|
||||||
if (try global_name_map.put(ident, ident_index)) |_| {
|
if (try ctx.global_name_map.put(ident, ident_index)) |_| {
|
||||||
return parseError(ctx, "redefinition of identifier '{}'", .{ident});
|
return parseError(ctx, "redefinition of identifier '{}'", .{ident});
|
||||||
}
|
}
|
||||||
try tree.decls.append(inst);
|
try ctx.decls.append(inst);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
' ', '\n' => continue,
|
' ', '\n' => continue,
|
||||||
|
@ -201,7 +206,7 @@ fn parseType(ctx: *ParseContext) !*Value {
|
||||||
return parseError(ctx, "TODO parse type", .{});
|
return parseError(ctx, "TODO parse type", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseInstruction(ctx: *ParseContext) !*Inst {
|
fn parseInstruction(ctx: *ParseContext) error{ OutOfMemory, ParseFailure }!*Inst {
|
||||||
switch (ctx.source[ctx.i]) {
|
switch (ctx.source[ctx.i]) {
|
||||||
'"' => return parseStringLiteralConst(ctx),
|
'"' => return parseStringLiteralConst(ctx),
|
||||||
'0'...'9' => return parseIntegerLiteralConst(ctx),
|
'0'...'9' => return parseIntegerLiteralConst(ctx),
|
||||||
|
@ -260,19 +265,54 @@ fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {
|
||||||
return parseError(ctx, "unexpected EOF in enum parameter", .{});
|
return parseError(ctx, "unexpected EOF in enum parameter", .{});
|
||||||
}
|
}
|
||||||
switch (T) {
|
switch (T) {
|
||||||
Inst.Fn.Body => {
|
Inst.Fn.Body => return parseBody(ctx),
|
||||||
var instructions = std.ArrayList(*Inst).init(ctx.allocator);
|
|
||||||
try requireEatBytes(ctx, "{");
|
|
||||||
return T{
|
|
||||||
.instructions = instructions.toOwnedSlice(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),
|
Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),
|
||||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||||
}
|
}
|
||||||
return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
|
return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parseBody(ctx: *ParseContext) !Inst.Fn.Body {
|
||||||
|
var instructions = std.ArrayList(*Inst).init(ctx.allocator);
|
||||||
|
defer instructions.deinit();
|
||||||
|
|
||||||
|
var name_map = std.StringHashMap(usize).init(ctx.allocator);
|
||||||
|
defer name_map.deinit();
|
||||||
|
|
||||||
|
try requireEatBytes(ctx, "{");
|
||||||
|
skipSpace(ctx);
|
||||||
|
|
||||||
|
while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
|
||||||
|
';' => _ = try skipToAndOver(ctx, '\n'),
|
||||||
|
'%' => {
|
||||||
|
const at_start = ctx.i;
|
||||||
|
const ident = try skipToAndOver(ctx, ' ');
|
||||||
|
var ty: ?*Value = null;
|
||||||
|
if (eatByte(ctx, ':')) {
|
||||||
|
skipSpace(ctx);
|
||||||
|
ty = try parseType(ctx);
|
||||||
|
skipSpace(ctx);
|
||||||
|
}
|
||||||
|
skipSpace(ctx);
|
||||||
|
try requireEatBytes(ctx, "=");
|
||||||
|
skipSpace(ctx);
|
||||||
|
const inst = try parseInstruction(ctx);
|
||||||
|
const ident_index = instructions.items.len;
|
||||||
|
if (try name_map.put(ident, ident_index)) |_| {
|
||||||
|
return parseError(ctx, "redefinition of identifier '{}'", .{ident});
|
||||||
|
}
|
||||||
|
try instructions.append(inst);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
' ', '\n' => continue,
|
||||||
|
else => |byte| return parseError(ctx, "unexpected byte: '{c}'", .{byte}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Inst.Fn.Body{
|
||||||
|
.instructions = instructions.toOwnedSlice(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
|
fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
|
||||||
const start = ctx.i;
|
const start = ctx.i;
|
||||||
ctx.i += 1; // skip over '"'
|
ctx.i += 1; // skip over '"'
|
||||||
|
@ -333,8 +373,8 @@ pub fn main() anyerror!void {
|
||||||
const source = try std.fs.cwd().readFileAlloc(allocator, src_path, std.math.maxInt(u32));
|
const source = try std.fs.cwd().readFileAlloc(allocator, src_path, std.math.maxInt(u32));
|
||||||
|
|
||||||
const tree = try parse(allocator, source);
|
const tree = try parse(allocator, source);
|
||||||
if (tree.errors.items.len != 0) {
|
if (tree.errors.len != 0) {
|
||||||
for (tree.errors.items) |err_msg| {
|
for (tree.errors) |err_msg| {
|
||||||
const loc = findLineColumn(source, err_msg.byte_offset);
|
const loc = findLineColumn(source, err_msg.byte_offset);
|
||||||
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user