const ArenaAllocator = std.heap.ArenaAllocator;
const Allocator = std.mem.Allocator;
const Interpreter = @This();
+const Stmt = @import("stmt.zig").Stmt;
const Expr = @import("expr.zig").Expr;
const Token = @import("Token.zig");
const Literal = Token.Literal;
self.arena.deinit();
}
-pub fn interpret(self: *Interpreter, expression: *const Expr) !void {
+pub fn interpret(self: *Interpreter, statements: []const *const Stmt) !void {
self.allocator = self.arena.allocator();
- var err_payload: ErrorPayload = undefined;
- if (self.evaluate(expression, &err_payload)) |value| {
- const stringified = try self.stringify(value);
- try self.stdout.print("{s}\n", .{stringified});
- } else |err| switch (err) {
- error.RuntimeError => try lox.runtimeError(err_payload),
- else => return err,
+ for (statements) |statement| {
+ var err_payload: ErrorPayload = undefined;
+ self.execute(statement, &err_payload) catch |err| switch (err) {
+ error.RuntimeError => try lox.runtimeError(err_payload),
+ else => return err,
+ };
}
}
};
}
+fn execute(self: *Interpreter, stmt: *const Stmt, err_payload: *ErrorPayload) !void {
+ try switch (stmt.*) {
+ .print => |print| self.visitPrintStmt(print, err_payload),
+ .expression => |expression| self.visitExpressionStmt(expression, err_payload),
+ };
+}
+
+fn visitExpressionStmt(self: *Interpreter, stmt: Stmt.Expression, err_payload: *ErrorPayload) !void {
+ _ = try self.evaluate(stmt.expression, err_payload);
+}
+
+fn visitPrintStmt(self: *Interpreter, stmt: Stmt.Print, err_payload: *ErrorPayload) !void {
+ const value = try self.evaluate(stmt.expression, err_payload);
+ try self.stdout.print("{s}\n", .{try self.stringify(value)});
+}
+
fn visitBinaryExpr(self: *Interpreter, expr: Expr.Binary, err_payload: *ErrorPayload) !Literal {
const left = try self.evaluate(expr.left, err_payload);
const right = try self.evaluate(expr.right, err_payload);
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 |err2| switch (err2) {
- error.ParseError => return null,
- else => return err2,
- };
+ 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 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 }) };
--- /dev/null
+const Expr = @import("expr.zig").Expr;
+
+pub const Stmt = union(enum) {
+ expression: Expression,
+ print: Print,
+
+ pub const Expression = struct {
+ expression: *const Expr,
+
+ pub fn init(expression: *const Expr) Expression {
+ return .{
+ .expression = expression,
+ };
+ }
+ };
+
+ pub const Print = struct {
+ expression: *const Expr,
+
+ pub fn init(expression: *const Expr) Print {
+ return .{
+ .expression = expression,
+ };
+ }
+ };
+};