From 8f55e2fa7059ef215a1b8369300f0a85103b079b Mon Sep 17 00:00:00 2001 From: Nic Gaffney Date: Thu, 18 Jul 2024 19:26:06 -0500 Subject: ASt progress --- src/ast.zig | 156 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 125 insertions(+), 31 deletions(-) (limited to 'src/ast.zig') 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; +} -- cgit v1.2.3