diff --git a/examples/hello.v b/examples/hello.v index b0f03c1..652d5a0 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -63,6 +63,9 @@ fn main(a int) int { str.len /= 1 awoo := [1, 2, a(), b + 2, c(31) * d] + + for a in b {} + for idx, a in b {} } fn (v Typ) voidfunc() {} diff --git a/src/ast.zig b/src/ast.zig index 773d9c5..5818a37 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -158,12 +158,20 @@ pub const LoopStmt = struct { then_branch: Block, }; +pub const ForStmt = struct { + index: ?Token, + value: Token, + array: Token, + block: Block, +}; + pub const Stmt = union(enum) { Expr: *Expr, Println: *Expr, If: IfStmt, Loop: LoopStmt, + For: ForStmt, Return: ReturnStmt, @@ -212,6 +220,20 @@ pub const Stmt = union(enum) { return stmt; } + pub fn mkFor(allocator: *std.mem.Allocator, index: ?Token, value: Token, array: Token, block: Block) !*Stmt { + var stmt = try allocator.create(Stmt); + stmt.* = Stmt{ + .For = ForStmt{ + .index = index, + .value = value, + .array = array, + .block = block, + }, + }; + + return stmt; + } + pub fn mkReturn(allocator: *std.mem.Allocator, tok: Token, value: *Expr) !*Stmt { var stmt = try allocator.create(Stmt); stmt.* = Stmt{ diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 6360035..b770f4e 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -262,6 +262,21 @@ pub fn printStmt(ident: usize, stmt: *Stmt) void { std.debug.warn(")\n"); }, + .For => |forstmt| { + std.debug.warn("(for "); + + if (forstmt.index) |index| { + std.debug.warn("({} {}) ", index.lexeme, forstmt.value.lexeme); + } else { + std.debug.warn("{} ", forstmt.value.lexeme); + } + + std.debug.warn("{} ", forstmt.array.lexeme); + + printBlock(ident + 1, forstmt.block, false); + std.debug.warn(")\n"); + }, + .Return => |ret| { std.debug.warn("(return "); printExpr(ret.value); diff --git a/src/parser.zig b/src/parser.zig index 197b69f..afe1ad6 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -636,6 +636,7 @@ pub const Parser = struct { return switch (self.peek().ttype) { .If => try self.parseIfStmt(), .Loop => try self.parseLoop(), + .For => try self.parseForStmt(), .Println => try self.parsePrintln(), .Return => try self.parseReturn(), else => try self.parseStmtExpr(), @@ -675,6 +676,42 @@ pub const Parser = struct { ); } + fn parseForStmt(self: *@This()) !*Stmt { + // There are two types of for in vig's V subset: + // - for x in y + // - for idx, x in y + _ = try self.consumeSingle(.For); + + var index_var: ?Token = null; + var value_var: Token = undefined; + + const subject_1 = try self.consumeSingle(.Identifier); + + if (self.check(.Comma)) { + _ = try self.consumeSingle(.Comma); + + const subject_2 = try self.consumeSingle(.Identifier); + index_var = subject_1; + value_var = subject_2; + } else { + value_var = subject_1; + } + + _ = try self.consumeSingle(.In); + + // MUST be identifier + var array = try self.consumeSingle(.Identifier); + var block = try self.parseStmtBlock(); + + return try Stmt.mkFor( + self.allocator, + index_var, + value_var, + array, + block, + ); + } + fn parseLoop(self: *@This()) !*Stmt { _ = try self.consumeSingle(.Loop); var expr: ?*Expr = null;