summaryrefslogtreecommitdiff
path: root/src/ast.zig
diff options
context:
space:
mode:
authorNic Gaffney <gaffney_nic@protonmail.com>2024-07-18 19:26:06 -0500
committerNic Gaffney <gaffney_nic@protonmail.com>2024-07-18 19:26:06 -0500
commit8f55e2fa7059ef215a1b8369300f0a85103b079b (patch)
treec973088671120e8b0f1daa43b12359e877d77411 /src/ast.zig
parent0079d26b9d5a95b46c3a73f0aa5409a584d0bb1b (diff)
downloadcalico-8f55e2fa7059ef215a1b8369300f0a85103b079b.tar.gz
ASt progress
Diffstat (limited to 'src/ast.zig')
-rw-r--r--src/ast.zig156
1 files changed, 125 insertions, 31 deletions
diff --git a/src/ast.zig b/src/ast.zig
index 2f8f209..e8f3a8e 100644
--- a/src/ast.zig
+++ b/src/ast.zig
@@ -4,64 +4,158 @@ const tok = @import("tokenize.zig");
const SyntaxError = error{SyntaxError};
const expectedToken = error{ExpectedToken};
-pub const BinOp = enum {
- Add,
- Sub,
- Mul,
- Div,
+pub const BinOp = enum(u32) {
+ Add = 0b000,
+ Sub = 0b001,
+ Mul = 0b100,
+ Div = 0b101,
+ Mod = 0b110,
+
+ fn init(typ: tok.TokenType) ?BinOp {
+ return switch (typ) {
+ .plus => .Add,
+ .minus => .Sub,
+ .star => .Mul,
+ .slash => .Div,
+ else => null,
+ };
+ }
+
+ fn greater(self: BinOp, other: ?BinOp) bool {
+ if (other == null) return true;
+ return (@intFromEnum(self) >> 2) > (@intFromEnum(other.?) >> 2);
+ }
};
pub const Literal = union(enum) {
Int: i32,
};
+pub const AstExpr = struct {
+ kind: ExprKind,
+ allocator: std.mem.Allocator,
+ pub fn init(allocator: std.mem.Allocator) !*AstExpr {
+ const value = try allocator.create(AstExpr);
+ value.* = .{
+ .kind = .Void,
+ .allocator = allocator,
+ };
+ return value;
+ }
+ pub fn deinit(self: *AstExpr) void {
+ self.allocator.free(self);
+ }
+};
+
+pub const AstStmt = struct {
+ kind: StmtKind,
+ allocator: std.mem.Allocator,
+ pub fn init(allocator: std.mem.Allocator) !*AstStmt {
+ const value = try allocator.create(AstStmt);
+ value.* = .{
+ .kind = .Void,
+ .allocator = allocator,
+ };
+ return value;
+ }
+ pub fn deinit(self: *AstStmt) void {
+ self.allocator.free(self);
+ }
+};
+
pub const Ast = union(enum) {
- Expr: struct {
- kind: ExprKind,
- },
- Stmt: struct {
- kind: StmtKind,
- },
+ Expr: AstExpr,
+ Stmt: AstStmt,
};
const StmtKind = union(enum) {
- exit: Ast.Expr,
+ exit: AstExpr,
+ Void,
};
const ExprKind = union(enum) {
Literal: Literal,
BinaryOp: struct {
op: BinOp,
- left: Ast.Expr,
- right: Ast.Expr,
+ left: *AstExpr,
+ right: *AstExpr,
},
+ Void,
};
-fn checkType(token: tok.Token, typ: tok.TokenType) bool {
- return switch (token) {
- typ => true,
- else => false,
- };
-}
-
const AstParser = struct {
tokens: tok.Iterator(tok.Token),
- fn parseStmt(self: *AstParser) !Ast.Stmt {
- return switch (self.tokens.peek().?) {
- .ret => try self.exitStmt(),
+ arena: std.heap.ArenaAllocator,
+ allocator: std.mem.Allocator,
+
+ fn init(allocator: *std.heap.ArenaAllocator, tokens: tok.Iterator(tok.Token)) AstParser {
+ return AstParser{
+ .tokens = tokens,
+ .arena = allocator.*,
+ .allocator = allocator.allocator(),
};
}
- fn parseExpr(self: *AstParser) !Ast.Expr {
+ fn deinit(self: *AstParser) void {
+ self.arena.deinit();
+ }
+ fn parseStmt(self: *AstParser) !AstStmt {
+ return switch (self.tokens.peek().?) {
+ .ret => self.exitStmt(),
+ else => error.SyntaxError,
+ };
}
- fn exitStmt(self: *AstParser) !Ast.Stmt {
- if (!checkType(self.tokens.consume().?, tok.TokenType.ret)) return expectedToken;
- const value = self.parseExpr();
+ fn parseExpr(self: *AstParser, lastOp: ?BinOp) !*AstExpr {
+ if (!tok.checkType(self.tokens.peek().?, tok.TokenType.intLit)) return error.ExpectedToken;
+ const kind = ExprKind{ .Literal = .{ .Int = self.tokens.consume().?.intLit } };
+ var lhs = try AstExpr.init(self.allocator);
+ lhs.*.kind = kind;
+ while (self.tokens.peek()) |tokn| {
+ const op = BinOp.init(tokn);
+ if (op != null and op.?.greater(lastOp)) {
+ self.tokens.skip();
+ const rhs = try self.parseExpr(op);
+ const newkind = ExprKind{ .BinaryOp = .{
+ .op = op.?,
+ .left = lhs,
+ .right = rhs,
+ } };
+ lhs = try AstExpr.init(self.allocator);
+ lhs.*.kind = newkind;
+ }
+ return lhs;
+ }
+ return lhs;
+ }
- if (!checkType(self.tokens.consume().?, tok.TokenType.semiCol)) return expectedToken;
- const kind = StmtKind{ .exit = value };
- return Ast.Stmt{ .kind = kind };
+ fn exitStmt(self: *AstParser) !AstStmt {
+ if (!tok.checkType(self.tokens.consume().?, tok.TokenType.ret))
+ return error.ExpectedToken;
+ const value = try self.parseExpr(null);
+
+ if (!tok.checkType(self.tokens.consume().?, tok.TokenType.semiCol)) return error.ExpectedToken;
+ const kind = StmtKind{ .exit = value.* };
+ const stmt = try AstStmt.init(self.allocator);
+ stmt.kind = kind;
+ return stmt.*;
}
};
+
+test "AstParse" {
+ std.testing.log_level = std.log.Level.info;
+ const expect = std.testing.expect;
+ const testSource: []const u8 = "exit 120 + 150;";
+ var toks = tok.Tokenizer.init(std.testing.allocator, testSource);
+ defer toks.deinit();
+ var arrtoks = try toks.tokenize();
+ const slice = try arrtoks.toOwnedSlice();
+ const iter = tok.Iterator(tok.Token).init(slice);
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ var parser = AstParser.init(&arena, iter);
+ defer parser.deinit();
+ const stmt = try parser.parseStmt();
+ _ = stmt;
+ _ = expect;
+}