aboutsummaryrefslogtreecommitdiff
path: root/src/parse.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.zig')
-rw-r--r--src/parse.zig106
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);
}