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;