const std = @import("std");
const ArenaAllocator = std.heap.ArenaAllocator;
const Allocator = std.mem.Allocator;
+const ArrayList = std.ArrayList;
const Token = @import("Token.zig");
const Parser = @This();
+const Stmt = @import("stmt.zig").Stmt;
const Expr = @import("expr.zig").Expr;
const TokenType = @import("token_type.zig").TokenType;
const lox = @import("main.zig");
self.arena.deinit();
}
-pub fn parse(self: *Parser) !?*Expr {
+pub fn parse(self: *Parser) ![]const *const Stmt {
self.allocator = self.arena.allocator();
- return self.expression() catch |err| switch (err) {
- error.ParseError => return null,
- else => return err,
- };
+ var statements: ArrayList(*const Stmt) = .empty;
+
+ while (!self.isAtEnd()) {
+ try statements.append(self.allocator, try self.statement());
+ }
+
+ return statements.toOwnedSlice(self.allocator);
}
-fn expression(self: *Parser) (Allocator.Error || std.Io.Writer.Error || error{ParseError})!*Expr {
+fn expression(self: *Parser) (Allocator.Error || std.Io.Writer.Error || error{ParseError})!*const Expr {
return self.equality();
}
-fn equality(self: *Parser) !*Expr {
+fn statement(self: *Parser) !*const Stmt {
+ if (self.match(&.{.print})) {
+ return self.printStatement();
+ }
+
+ return self.expressionStatement();
+}
+
+fn printStatement(self: *Parser) !*const Stmt {
+ const value = try self.expression();
+ _ = try self.consume(.semicolon, "Expect ';' after value.");
+ const stmt = try self.allocator.create(Stmt);
+ stmt.* = .{ .print = .init(value) };
+ return stmt;
+}
+
+fn expressionStatement(self: *Parser) !*const Stmt {
+ const expr = try self.expression();
+ _ = try self.consume(.semicolon, "Expect ';' after expression.");
+ const stmt = try self.allocator.create(Stmt);
+ stmt.* = .{ .expression = .init(expr) };
+ return stmt;
+}
+
+fn equality(self: *Parser) !*const Expr {
var expr = try self.comparison();
while (self.match(&.{ .bang_equal, .equal_equal })) {
return expr;
}
-fn comparison(self: *Parser) !*Expr {
+fn comparison(self: *Parser) !*const Expr {
var expr = try self.term();
while (self.match(&.{ .greater, .greater_equal, .less, .less_equal })) {
return expr;
}
-fn term(self: *Parser) !*Expr {
+fn term(self: *Parser) !*const Expr {
var expr = try self.factor();
while (self.match(&.{ .plus, .minus })) {
return expr;
}
-fn factor(self: *Parser) !*Expr {
+fn factor(self: *Parser) !*const Expr {
var expr = try self.unary();
while (self.match(&.{ .slash, .star })) {
return expr;
}
-fn unary(self: *Parser) !*Expr {
+fn unary(self: *Parser) !*const Expr {
if (self.match(&.{ .bang, .minus })) {
const operator = self.previous();
const right = try self.unary();
return expr;
}
- return try self.primary();
+ return self.primary();
}
-fn primary(self: *Parser) !*Expr {
+fn primary(self: *Parser) !*const Expr {
if (self.match(&.{.false})) {
const expr = try self.allocator.create(Expr);
expr.* = .{ .literal = .init(.{ .boolean = false }) };