diff options
Diffstat (limited to 'src/parse.zig')
-rw-r--r-- | src/parse.zig | 106 |
1 files changed, 73 insertions, 33 deletions
diff --git a/src/parse.zig b/src/parse.zig index 6ed1b79..b509fe7 100644 --- a/src/parse.zig +++ b/src/parse.zig @@ -5,6 +5,38 @@ const root = @import("root"); const Lexer = root.Lexer; const Token = root.Lexer.Token; +fn Fmt(T: type) type { + return std.fmt.Formatter(struct { + fn format( + data: struct { T, []const u8, usize }, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + const self, const file_source, const indent = data; + return self.format(writer, file_source, indent); + } + }.format); +} + +pub fn fmt(tree: anytype, source: []const u8, indent: usize) Fmt(@TypeOf(tree)) { + return .{ .data = .{ tree, source, indent } }; +} + +pub const Block = struct { + loc: Lexer.Location, + stmts: []Stmt, + + fn format(self: Block, writer: anytype, source: []const u8, indent: usize) !void { + try writer.writeAll("{\n"); + for (self.stmts) |stmt| { + try writer.print("{}\n", .{fmt(stmt, source, indent + 4)}); + } + try writer.writeByteNTimes(' ', indent); + try writer.writeAll("}"); + } +}; + pub const Stmt = struct { loc: Lexer.Location, type: Type, @@ -12,6 +44,7 @@ pub const Stmt = struct { pub const Type = union(enum) { expr: *const Expr, declare_var: DeclareVar, + block: Block, pub const DeclareVar = struct { ident: Lexer.Location, @@ -19,21 +52,17 @@ pub const Stmt = struct { }; }; - pub fn fmt(self: Stmt, file_source: []const u8) Format { - return .{ .data = .{ self, file_source } }; + fn format(self: Stmt, writer: anytype, source: []const u8, indent: usize) !void { + try writer.writeByteNTimes(' ', indent); + return switch (self.type) { + .expr => |expr| writer.print("{};", .{fmt(expr, source, indent)}), + .block => |b| writer.print("{}", .{fmt(b, source, indent)}), + .declare_var => |declare_var| writer.print("let {s} = {};", .{ + declare_var.ident.getIdent(source), + fmt(declare_var.value, source, indent), + }), + }; } - - const Format = std.fmt.Formatter(struct { - fn format(data: struct { Stmt, []const u8 }, comptime f: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - const self, const file_source = data; - _ = f; - _ = options; - return switch (self.type) { - .expr => |expr| writer.print("{};", .{expr.fmt(file_source)}), - .declare_var => |declare_var| writer.print("let {s} = {};", .{ declare_var.ident.getIdent(file_source), declare_var.value.fmt(file_source) }), - }; - } - }.format); }; pub const Expr = struct { @@ -70,32 +99,36 @@ pub const Expr = struct { }; }; - pub fn fmt(self: Expr, file_source: []const u8) Format { - return .{ .data = .{ self, file_source } }; - } - - const Format = std.fmt.Formatter(struct { - fn format(data: struct { Expr, []const u8 }, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - const self, const file_source = data; - switch (self.type) { - .integer_literal => try writer.print("{}", .{self.loc.getInt(file_source)}), - .bin_op => |bin_op| try writer.print("({} {} {})", .{ bin_op.lhs.fmt(file_source), bin_op.op, bin_op.rhs.fmt(file_source) }), - .call => |call| try writer.print("{}({})", .{ call.proc.fmt(file_source), call.arg.fmt(file_source) }), - .identifier => try writer.print("{s}", .{self.loc.getIdent(file_source)}), - } + fn format(self: Expr, writer: anytype, source: []const u8, indent: usize) !void { + switch (self.type) { + .integer_literal => try writer.print("{}", .{self.loc.getInt(source)}), + .bin_op => |bin_op| { + try writer.print("{} {} {}", .{ fmt(bin_op.lhs, source, indent), bin_op.op, fmt(bin_op.rhs, source, indent) }); + }, + .call => |call| { + try writer.print("{}({})", .{ fmt(call.proc, source, indent), fmt(call.arg, source, indent) }); + }, + .identifier => try writer.print("{s}", .{self.loc.getIdent(source)}), } - }.format); + } }; -pub fn statements(allocator: Allocator, lexer: *Lexer) ![]Stmt { +const ParseError = error{ OutOfMemory, ExpectedRightParen, UnexpectedToken, ExpectedSemicolon }; + +pub fn block(allocator: Allocator, lexer: *Lexer) !Block { + const left_curly = try mustEat(lexer, .left_curly); var stmts: std.ArrayList(Stmt) = .init(allocator); - while (lexer.peek().type != .eof) { + while (lexer.peek().type != .right_curly) { try stmts.append(try statement(allocator, lexer)); } - return try stmts.toOwnedSlice(); + const right_curly = try mustEat(lexer, .right_curly); + return .{ + .loc = left_curly.loc.combine(right_curly.loc), + .stmts = try stmts.toOwnedSlice(), + }; } -pub fn statement(allocator: Allocator, lexer: *Lexer) !Stmt { +pub fn statement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt { switch (lexer.peek().type) { .let => { const let = lexer.next(); @@ -108,6 +141,13 @@ pub fn statement(allocator: Allocator, lexer: *Lexer) !Stmt { .type = .{ .declare_var = .{ .ident = ident.loc, .value = value } }, }; }, + .left_curly => { + const b = try block(allocator, lexer); + return .{ + .loc = b.loc, + .type = .{ .block = b }, + }; + }, else => { var expr = try expression(allocator, lexer); const semicolon = lexer.next(); @@ -120,7 +160,7 @@ pub fn statement(allocator: Allocator, lexer: *Lexer) !Stmt { } } -pub fn expression(allocator: Allocator, lexer: *Lexer) error{ OutOfMemory, ExpectedRightParen, UnexpectedToken }!*Expr { +pub fn expression(allocator: Allocator, lexer: *Lexer) ParseError!*Expr { return parseTerms(allocator, lexer); } |