aboutsummaryrefslogtreecommitdiff
path: root/src/parse.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.zig')
-rw-r--r--src/parse.zig54
1 files changed, 39 insertions, 15 deletions
diff --git a/src/parse.zig b/src/parse.zig
index 901ce0d..1dda517 100644
--- a/src/parse.zig
+++ b/src/parse.zig
@@ -5,6 +5,15 @@ const root = @import("root");
const Lexer = root.Lexer;
const Token = root.Lexer.Token;
+pub const Stmt = struct {
+ loc: Lexer.Location,
+ type: Type,
+
+ pub const Type = union(enum) {
+ expr: *const Expr,
+ };
+};
+
pub const Expr = struct {
loc: Lexer.Location,
type: Type,
@@ -12,7 +21,6 @@ pub const Expr = struct {
pub const Type = union(enum) {
integer_literal,
bin_op: BinOp,
- invalid: Token,
call: Call,
identifier,
@@ -48,14 +56,30 @@ pub const Expr = struct {
switch (self.type) {
.integer_literal => try writer.print("<int>", .{}),
.bin_op => |bin_op| try writer.print("({} {} {})", .{ bin_op.lhs, bin_op.op, bin_op.rhs }),
- .invalid => try writer.print("<invalid>", .{}),
.call => |call| try writer.print("({} {})", .{ call.proc, call.arg }),
.identifier => try writer.print("<identifier>", .{}),
}
}
};
-pub fn expression(allocator: Allocator, lexer: *Lexer) error{OutOfMemory}!*Expr {
+pub fn statements(allocator: Allocator, lexer: *Lexer) ![]Stmt {
+ var stmts: std.ArrayList(Stmt) = .init(allocator);
+ while (lexer.peek().type != .eof) {
+ try stmts.append(try statement(allocator, lexer));
+ }
+ return try stmts.toOwnedSlice();
+}
+
+pub fn statement(allocator: Allocator, lexer: *Lexer) !Stmt {
+ var expr = try expression(allocator, lexer);
+ const semicolon: Lexer.Token = if (lexer.peek().type == .semicolon) lexer.next() else return error.ExpectedSemicolon;
+ return .{
+ .loc = expr.loc.combine(semicolon.loc),
+ .type = .{ .expr = expr },
+ };
+}
+
+pub fn expression(allocator: Allocator, lexer: *Lexer) error{ OutOfMemory, ExpectedRightParen, UnexpectedToken }!*Expr {
return addExpr(allocator, lexer);
}
@@ -70,7 +94,7 @@ pub fn addExpr(allocator: Allocator, lexer: *Lexer) !*Expr {
_ = lexer.next();
const rhs = try callExpr(allocator, lexer);
- lhs = try allocate(allocator, .{
+ lhs = try allocate(Expr, allocator, .{
.loc = lhs.loc.combine(rhs.loc),
.type = .{ .bin_op = .{ .lhs = lhs, .op = op, .rhs = rhs } },
});
@@ -82,11 +106,11 @@ pub fn callExpr(allocator: Allocator, lexer: *Lexer) !*Expr {
var proc = try primaryExpr(allocator, lexer);
while (true) {
switch (lexer.peek().type) {
- .left_paren, .integer_literal => {},
+ .left_paren, .integer_literal, .identifier => {},
else => break,
}
const arg = try primaryExpr(allocator, lexer);
- proc = try allocate(allocator, .{
+ proc = try allocate(Expr, allocator, .{
.loc = proc.loc.combine(arg.loc),
.type = .{ .call = .{ .proc = proc, .arg = arg } },
});
@@ -97,25 +121,25 @@ pub fn callExpr(allocator: Allocator, lexer: *Lexer) !*Expr {
pub fn primaryExpr(allocator: Allocator, lexer: *Lexer) !*Expr {
const token = lexer.next();
// std.debug.print("term {}\n", .{token});
- return allocate(allocator, switch (token.type) {
+ return allocate(Expr, allocator, switch (token.type) {
.left_paren => {
const res = expression(allocator, lexer);
const right_paren = lexer.next();
if (right_paren.type != .right_paren)
- return allocate(allocator, .{
- .loc = right_paren.loc,
- .type = .{ .invalid = right_paren },
- });
+ return error.ExpectedRightParen;
return res;
},
.integer_literal => .{ .loc = token.loc, .type = .integer_literal },
.identifier => .{ .loc = token.loc, .type = .identifier },
- else => .{ .loc = token.loc, .type = .{ .invalid = token } },
+ else => |t| {
+ std.debug.print("Expected '(', integer literal, or identifier. Got {}\n", .{t});
+ return error.UnexpectedToken;
+ },
});
}
-fn allocate(allocator: Allocator, expr: Expr) !*Expr {
- const res = try allocator.create(Expr);
- res.* = expr;
+fn allocate(T: type, allocator: Allocator, t: T) !*T {
+ const res = try allocator.create(T);
+ res.* = t;
return res;
}