From 5ba807d93f6935b7d08d2330b5a8c2621d37d0cc Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 22:41:25 -0300 Subject: [PATCH 1/3] add function calls --- examples/hello.v | 2 ++ src/ast.zig | 20 ++++++++++++++++++ src/parser.zig | 53 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/examples/hello.v b/examples/hello.v index 6bd25d9..8d31672 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -30,4 +30,6 @@ fn main(a int) int { loop a > 2 { println('skirts') } + + cock_and_ball_torture('cbt', 1, 2, 3) } diff --git a/src/ast.zig b/src/ast.zig index 05f0b25..8dbe32d 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -76,6 +76,7 @@ pub const ExprType = enum { Logical, Literal, Variable, + Call, Grouping, }; @@ -84,6 +85,12 @@ pub const VarDecl = struct { mutable: bool = false, }; +pub const CallExpr = struct { + callee: *Expr, + paren: Token, + arguments: ExprList, +}; + pub const Expr = union(ExprType) { Assign: AssignExpr, VarDecl: VarDecl, @@ -95,6 +102,7 @@ pub const Expr = union(ExprType) { Variable: Token, Grouping: *Expr, + Call: CallExpr, }; pub const Block = std.ArrayList(*Stmt); @@ -305,6 +313,18 @@ pub fn printExpr(expr: *Expr) void { std.debug.warn(")"); }, + .Call => |call| { + std.debug.warn("("); + printExpr(call.callee); + + for (call.arguments.toSlice()) |arg| { + std.debug.warn(" "); + printExpr(arg); + } + + std.debug.warn(")"); + }, + else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), } } diff --git a/src/parser.zig b/src/parser.zig index e171ea1..9c1ce16 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -241,6 +241,19 @@ pub const Parser = struct { return vardecl; } + fn mkCall(self: *@This(), callee: *Expr, paren: Token, args: ast.ExprList) !*Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Call = ast.CallExpr{ + .callee = callee, + .paren = paren, + .arguments = args, + }, + }; + + return expr; + } + fn mkBool(self: *Parser, val: bool) !*ast.Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ @@ -676,10 +689,48 @@ pub const Parser = struct { return try self.mkUnary(op, right); } - var expr = try self.parsePrimary(); + var expr = try self.parseCall(); return expr; } + fn parseCall(self: *@This()) !*Expr { + var expr = try self.parsePrimary(); + + while (true) { + if (self.check(.LeftParen)) { + _ = try self.consumeSingle(.LeftParen); + expr = try self.finishCall(expr); + } else { + break; + } + } + + return expr; + } + + fn finishCall(self: *@This(), callee: *Expr) !*Expr { + var args = ast.ExprList.init(self.allocator); + errdefer args.deinit(); + + if (!self.check(.RightParen)) { + + // emulating do-while really badly + var arg = (try self.parseExpr()).Expr; + try args.append(arg); + + while (self.check(.Comma)) { + _ = try self.consumeSingle(.Comma); + + arg = (try self.parseExpr()).Expr; + try args.append(arg); + } + } + + var paren = try self.consume(.RightParen, "Expected ')' after arguments"); + + return self.mkCall(callee, paren, args); + } + fn parsePrimary(self: *@This()) !*Expr { const curtype = self.peek().ttype; const lexeme = self.peek().lexeme; From 8f44cbea23f5b31b922a887a719a2e32c5358f75 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 22:55:53 -0300 Subject: [PATCH 2/3] parser: ensure calls only happen to Variables --- src/parser.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/parser.zig b/src/parser.zig index 9c1ce16..40404dd 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -694,10 +694,20 @@ pub const Parser = struct { } fn parseCall(self: *@This()) !*Expr { + // we parse a primary expression instead of consuming a .Identifier + // since parseCall is connected to the rest of the parser. doing + // identifiers would break the rest of the rules that want primaries. + + // nothing stops us from ensuring expr is a Variable though ;) var expr = try self.parsePrimary(); while (true) { if (self.check(.LeftParen)) { + if (ast.ExprType(expr.*) != .Variable) { + self.doError("cannot call non-variable{}", ast.ExprType(expr.*)); + return Result.CompileError; + } + _ = try self.consumeSingle(.LeftParen); expr = try self.finishCall(expr); } else { From c0c93183cb693afc291320b4b1114476a2b1fe30 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 23:16:13 -0300 Subject: [PATCH 3/3] add return statements --- examples/hello.v | 2 ++ src/ast.zig | 25 +++++++++++++++++++++++++ src/parser.zig | 11 +++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/examples/hello.v b/examples/hello.v index 8d31672..9a3e886 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -32,4 +32,6 @@ fn main(a int) int { } cock_and_ball_torture('cbt', 1, 2, 3) + + return 23 } diff --git a/src/ast.zig b/src/ast.zig index 8dbe32d..73b77cf 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -125,6 +125,13 @@ pub const Stmt = union(enum) { If: IfStmt, Loop: LoopStmt, + Return: ReturnStmt, + + pub const ReturnStmt = struct { + keyword: Token, + value: *Expr, + }; + pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt { var stmt = try allocator.create(Stmt); stmt.* = Stmt{ .Println = expr }; @@ -164,6 +171,18 @@ pub const Stmt = union(enum) { return stmt; } + + pub fn mkReturn(allocator: *std.mem.Allocator, tok: Token, value: *Expr) !*Stmt { + var stmt = try allocator.create(Stmt); + stmt.* = Stmt{ + .Return = ReturnStmt{ + .keyword = tok, + .value = value, + }, + }; + + return stmt; + } }; pub const Node = union(NodeType) { @@ -361,6 +380,12 @@ pub fn printStmt(ident: usize, stmt: *Stmt) void { std.debug.warn(")\n"); }, + .Return => |ret| { + std.debug.warn("(return "); + printExpr(ret.value); + std.debug.warn(")\n"); + }, + else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), } } diff --git a/src/parser.zig b/src/parser.zig index 40404dd..2a2bb7a 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -464,6 +464,7 @@ pub const Parser = struct { .If => try self.parseIfStmt(), .Loop => try self.parseLoop(), .Println => try self.parsePrintln(), + .Return => try self.parseReturn(), // TODO make newlines tokens and consume newline? else => try self.parseStmtExpr(), @@ -525,14 +526,20 @@ pub const Parser = struct { return try Stmt.mkLoop(self.allocator, expr, body); } + fn parseReturn(self: *@This()) !*Stmt { + const tok = try self.consumeSingle(.Return); + const expr = (try self.parseExpr()).Expr; + return try Stmt.mkReturn(self.allocator, tok, expr); + } + fn parsePrintln(self: *@This()) !*Stmt { _ = try self.consumeSingle(.Println); _ = try self.consumeSingle(.LeftParen); - var expr = try self.parseExpr(); + var expr = (try self.parseExpr()).Expr; _ = try self.consumeSingle(.RightParen); - return try Stmt.mkPrintln(self.allocator, expr.Expr); + return try Stmt.mkPrintln(self.allocator, expr); } fn parseStmtExpr(self: *@This()) !*Stmt {