diff --git a/README.md b/README.md index eed189f..054b284 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,11 @@ a vlang parser in zig because i can +## variations + + - `for` is split between `for` and `loop` because my fucking god i cant stand + having *four* different variations of `for`. + ## how ``` diff --git a/examples/hello.v b/examples/hello.v index fa6b3ba..6bd25d9 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -20,4 +20,14 @@ fn main(a int) int { a && b a || b + + loop {} + loop { + println('Ballse') + } + + loop a > 2 {} + loop a > 2 { + println('skirts') + } } diff --git a/src/ast.zig b/src/ast.zig index f048ac1..05f0b25 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -97,12 +97,17 @@ pub const Expr = union(ExprType) { Grouping: *Expr, }; -pub const IfBranch = std.ArrayList(*Stmt); +pub const Block = std.ArrayList(*Stmt); pub const IfStmt = struct { condition: *Expr, - then_branch: IfBranch, - else_branch: ?IfBranch, + then_branch: Block, + else_branch: ?Block, +}; + +pub const LoopStmt = struct { + condition: ?*Expr, + then_branch: Block, }; pub const Stmt = union(enum) { @@ -110,28 +115,46 @@ pub const Stmt = union(enum) { Println: *Expr, If: IfStmt, + Loop: LoopStmt, pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt { - var println = try allocator.create(Stmt); - println.* = Stmt{ .Println = expr }; - return println; + var stmt = try allocator.create(Stmt); + stmt.* = Stmt{ .Println = expr }; + return stmt; } pub fn mkIfStmt( allocator: *std.mem.Allocator, condition: *Expr, - then: IfBranch, - else_branch: ?IfBranch, + then: Block, + else_branch: ?Block, ) !*Stmt { - var println = try allocator.create(Stmt); - println.* = Stmt{ + var stmt = try allocator.create(Stmt); + stmt.* = Stmt{ .If = IfStmt{ .condition = condition, .then_branch = then, .else_branch = else_branch, }, }; - return println; + + return stmt; + } + + pub fn mkLoop( + allocator: *std.mem.Allocator, + condition: ?*Expr, + then: Block, + ) !*Stmt { + var stmt = try allocator.create(Stmt); + stmt.* = Stmt{ + .Loop = LoopStmt{ + .condition = condition, + .then_branch = then, + }, + }; + + return stmt; } }; @@ -304,6 +327,20 @@ pub fn printStmt(ident: usize, stmt: *Stmt) void { std.debug.warn(")\n"); }, + + .Loop => |loop| { + std.debug.warn("(loop "); + if (loop.condition) |cond| { + printExpr(cond); + } else { + std.debug.warn("true"); + } + std.debug.warn(" "); + + printBlock(ident + 1, loop.then_branch, false); + std.debug.warn(")\n"); + }, + else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), } } diff --git a/src/parser.zig b/src/parser.zig index 21a3015..e171ea1 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -449,6 +449,7 @@ pub const Parser = struct { fn parseStmt(self: *@This()) anyerror!*Stmt { return switch (self.peek().ttype) { .If => try self.parseIfStmt(), + .Loop => try self.parseLoop(), .Println => try self.parsePrintln(), // TODO make newlines tokens and consume newline? @@ -456,35 +457,35 @@ pub const Parser = struct { }; } - /// Copy of parseBlock for if branches - fn parseIfBranch(self: *@This()) !ast.IfBranch { - var branch = ast.IfBranch.init(self.allocator); - errdefer branch.deinit(); + /// Copy of parseBlock for blocks in statements + fn parseStmtBlock(self: *@This()) !ast.Block { + var block = ast.Block.init(self.allocator); + errdefer block.deinit(); _ = try self.consumeSingle(.LeftBrace); while (self.peek().ttype != .RightBrace) { var stmt = try self.parseDecl(); ast.printNode(try self.mkStmt(stmt), 0); - try branch.append(stmt); + try block.append(stmt); } _ = try self.consumeSingle(.RightBrace); - return branch; + return block; } fn parseIfStmt(self: *@This()) !*Stmt { _ = try self.consumeSingle(.If); var condition = (try self.parseExpr()).Expr; - const then_branch = try self.parseIfBranch(); + const then_branch = try self.parseStmtBlock(); - var else_branch: ?ast.IfBranch = null; + var else_branch: ?ast.Block = null; if (self.check(.Else)) { _ = try self.consumeSingle(.Else); - else_branch = try self.parseIfBranch(); + else_branch = try self.parseStmtBlock(); } return try Stmt.mkIfStmt( @@ -495,6 +496,22 @@ pub const Parser = struct { ); } + fn parseLoop(self: *@This()) !*Stmt { + _ = try self.consumeSingle(.Loop); + var expr: ?*Expr = null; + var body: ast.Block = undefined; + + // infinite loop + if (self.check(.LeftBrace)) { + body = try self.parseStmtBlock(); + } else { + expr = (try self.parseExpr()).Expr; + body = try self.parseStmtBlock(); + } + + return try Stmt.mkLoop(self.allocator, expr, body); + } + fn parsePrintln(self: *@This()) !*Stmt { _ = try self.consumeSingle(.Println); diff --git a/src/scanner.zig b/src/scanner.zig index 23c442b..2ee42d1 100644 --- a/src/scanner.zig +++ b/src/scanner.zig @@ -50,6 +50,7 @@ const keywords = [_][]const u8{ "false", "None", "println", + "loop", }; const keyword_ttypes = [_]TokenType{ @@ -78,6 +79,7 @@ const keyword_ttypes = [_]TokenType{ .False, .None, .Println, + .Loop, }; fn getKeyword(keyword: []const u8) ?TokenType { diff --git a/src/tokens.zig b/src/tokens.zig index 8b45d54..360c6b6 100644 --- a/src/tokens.zig +++ b/src/tokens.zig @@ -55,6 +55,7 @@ pub const TokenType = enum { Enum, Fn, For, + Loop, Go, Goto, If,