From f9f6362c91d41e709c83b27097a6c7567af1626c Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 12:24:34 -0300 Subject: [PATCH 1/3] ast: add return type to FnDecl - ast: make FnDecl and Const print better as s-expressions --- src/ast.zig | 23 +++++++++++++---------- src/parser.zig | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 2b52cf5..4386b98 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -28,6 +28,7 @@ pub const ParamDecl = struct { pub const FnDecl = struct { func_name: Token, params: ParamList, + return_type: Token, body: StmtList, }; @@ -140,36 +141,38 @@ fn print(ident: usize, comptime fmt: []const u8, args: ...) void { pub fn printNode(node: *Node, ident: usize) void { switch (node.*) { .FnDecl => |decl| { - print(ident, "FnDecl name='{}'\n", decl.func_name.lexeme); + print(ident, "(fn {} (", decl.func_name.lexeme); for (decl.params.toSlice()) |param| { - print( - ident + 1, - "param: '{}' {}\n", - param.name.lexeme, - param.typ.lexeme, - ); + std.debug.warn("({} {}) ", param.name.lexeme, param.typ.lexeme); } + std.debug.warn(") (\n"); + for (decl.body.toSlice()) |stmt| { printIdent(ident + 1); printStmt(stmt); std.debug.warn("\n"); } + + print(ident, ")\n"); }, .ConstDecl => |consts| { - print(ident, "ConstDecl ({} consts)\n", consts.len); + print(ident, "(const (\n"); + for (consts.toSlice()) |const_decl| { print( ident + 1, - "{} = ", + "({} ", const_decl.name.lexeme, ); printExpr(const_decl.expr); - std.debug.warn("\n"); + std.debug.warn(")\n"); } + + print(ident, "))\n"); }, .Root => { diff --git a/src/parser.zig b/src/parser.zig index 7cd23e9..88ee9b3 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -120,12 +120,19 @@ pub const Parser = struct { return false; } - fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList, block: ast.StmtList) !*ast.Node { + fn mkFnDecl( + self: *Parser, + name: Token, + params: ast.ParamList, + return_type: Token, + block: ast.StmtList, + ) !*ast.Node { var node = try self.allocator.create(Node); node.* = Node{ .FnDecl = ast.FnDecl{ .func_name = name, .params = params, + .return_type = return_type, .body = block, }, }; @@ -348,6 +355,8 @@ pub const Parser = struct { while (self.peek().ttype != .RightParen) { const param_name = try self.consumeSingle(.Identifier); + + // TODO dedicated function to consume a type const param_type = try self.consumeSingle(.Identifier); try param_list.append(ast.ParamDecl{ @@ -358,13 +367,10 @@ pub const Parser = struct { _ = try self.consumeSingle(.RightParen); - // TODO return type + // TODO dedicated function to consume a type const return_type = try self.consumeSingle(.Identifier); - - var block = try self.parseBlock(); - - std.debug.warn("!fn name: {}\n", name); - return try self.mkFnDecl(name, param_list, block.Block); + var block_node = try self.parseBlock(); + return try self.mkFnDecl(name, param_list, return_type, block_node.Block); } fn parseConstDecl(self: *@This()) !?*Node { From 83910811fa1f396e46b6577acae166f0f4026164 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 12:31:57 -0300 Subject: [PATCH 2/3] ast: add IfStmt and IfBranch --- src/ast.zig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 4386b98..23b829d 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -20,8 +20,6 @@ pub const NodeType = enum { pub const ParamDecl = struct { name: Token, - - // TODO types typ: Token, }; @@ -81,26 +79,28 @@ pub const VarDecl = struct { pub const Expr = union(ExprType) { Assign: AssignExpr, VarDecl: VarDecl, + Binary: BinaryExpr, Unary: UnaryExpr, Literal: LiteralExpr, + Variable: Token, Grouping: *Expr, }; -// TODO -//pub const IfStmt = struct { -// condition: *Expr, -// then_branch: *StmtList, -// else_branch: *StmtList, -//}; +pub const IfBranch = std.ArrayList(Stmt); + +pub const IfStmt = struct { + condition: *Expr, + then_branch: IfBranch, + else_branch: IfBranch, +}; pub const Stmt = union(enum) { Expr: *Expr, Println: *Expr, - // TODO - //If: IfStmt, + If: IfStmt, pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt { var println = try allocator.create(Stmt); From 9b3e9e81399db1ede4588e9e81fa4c283e612b1a Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 13:02:40 -0300 Subject: [PATCH 3/3] add if statements --- examples/hello.v | 6 +++++ src/ast.zig | 66 ++++++++++++++++++++++++++++++++++++++---------- src/parser.zig | 41 +++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 14 deletions(-) diff --git a/examples/hello.v b/examples/hello.v index 8685e38..81b5f60 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -11,4 +11,10 @@ fn main(a int) int { 3 / (51 + 2) mut a := 1+2 a = 2 + + if a { + println(30) + } else { + println(50) + } } diff --git a/src/ast.zig b/src/ast.zig index 23b829d..27c0b8c 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -88,12 +88,12 @@ pub const Expr = union(ExprType) { Grouping: *Expr, }; -pub const IfBranch = std.ArrayList(Stmt); +pub const IfBranch = std.ArrayList(*Stmt); pub const IfStmt = struct { condition: *Expr, then_branch: IfBranch, - else_branch: IfBranch, + else_branch: ?IfBranch, }; pub const Stmt = union(enum) { @@ -107,6 +107,23 @@ pub const Stmt = union(enum) { println.* = Stmt{ .Println = expr }; return println; } + + pub fn mkIfStmt( + allocator: *std.mem.Allocator, + condition: *Expr, + then: IfBranch, + else_branch: ?IfBranch, + ) !*Stmt { + var println = try allocator.create(Stmt); + println.* = Stmt{ + .If = IfStmt{ + .condition = condition, + .then_branch = then, + .else_branch = else_branch, + }, + }; + return println; + } }; pub const Node = union(NodeType) { @@ -138,6 +155,22 @@ fn print(ident: usize, comptime fmt: []const u8, args: ...) void { std.debug.warn(fmt, args); } +fn printBlock(ident: usize, block: var, endNewline: bool) void { + std.debug.warn("(\n"); + + for (block.toSlice()) |stmt| { + printIdent(ident); + printStmt(ident, stmt); + std.debug.warn("\n"); + } + + if (endNewline) { + print(ident - 1, ")\n"); + } else { + print(ident - 1, ")"); + } +} + pub fn printNode(node: *Node, ident: usize) void { switch (node.*) { .FnDecl => |decl| { @@ -147,15 +180,8 @@ pub fn printNode(node: *Node, ident: usize) void { std.debug.warn("({} {}) ", param.name.lexeme, param.typ.lexeme); } - std.debug.warn(") (\n"); - - for (decl.body.toSlice()) |stmt| { - printIdent(ident + 1); - printStmt(stmt); - std.debug.warn("\n"); - } - - print(ident, ")\n"); + printBlock(ident + 1, decl.body, false); + std.debug.warn(")\n"); }, .ConstDecl => |consts| { @@ -189,7 +215,7 @@ pub fn printNode(node: *Node, ident: usize) void { .Stmt => |stmt| blk: { printIdent(ident); - printStmt(stmt); + printStmt(ident, stmt); std.debug.warn("\n"); }, @@ -250,10 +276,24 @@ pub fn printExpr(expr: *Expr) void { } } -pub fn printStmt(stmt: *Stmt) void { +pub fn printStmt(ident: usize, stmt: *Stmt) void { switch (stmt.*) { .Println => |expr| parenthetize("println", &[_]*Expr{expr}), .Expr => |expr| printExpr(expr), + + .If => |ifstmt| { + std.debug.warn("(if "); + printExpr(ifstmt.condition); + std.debug.warn(" "); + + printBlock(ident + 1, ifstmt.then_branch, false); + if (ifstmt.else_branch) |else_branch| { + std.debug.warn(" else "); + printBlock(ident + 1, else_branch, false); + } + + std.debug.warn(")\n"); + }, else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), } } diff --git a/src/parser.zig b/src/parser.zig index 88ee9b3..768bd0b 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -419,7 +419,6 @@ pub const Parser = struct { _ = try self.consumeSingle(.LeftBrace); while (self.peek().ttype != .RightBrace) { - std.debug.warn("get smt with cur {}\n", self.peek().ttype); var stmt = try self.parseDecl(); ast.printNode(try self.mkStmt(stmt), 0); try stmts.append(stmt); @@ -436,6 +435,7 @@ pub const Parser = struct { fn parseStmt(self: *@This()) anyerror!*Stmt { return switch (self.peek().ttype) { + .If => try self.parseIfStmt(), .Println => try self.parsePrintln(), // TODO make newlines tokens and consume newline? @@ -443,6 +443,45 @@ 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(); + + _ = 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 self.consumeSingle(.RightBrace); + + return branch; + } + + fn parseIfStmt(self: *@This()) !*Stmt { + _ = try self.consumeSingle(.If); + var condition = (try self.parseExpr()).Expr; + + const then_branch = try self.parseIfBranch(); + + var else_branch: ?ast.IfBranch = null; + + if (self.check(.Else)) { + _ = try self.consumeSingle(.Else); + else_branch = try self.parseIfBranch(); + } + + return try Stmt.mkIfStmt( + self.allocator, + condition, + then_branch, + else_branch, + ); + } + fn parsePrintln(self: *@This()) !*Stmt { _ = try self.consumeSingle(.Println);