diff --git a/examples/hello.v b/examples/hello.v index 93536f3..f328e4d 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -1,3 +1 @@ -fn main(a int) { - // println("hello world!"); -} +fn main() {} diff --git a/src/ast.zig b/src/ast.zig index 365ef26..52f25a9 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -5,9 +5,12 @@ const Token = tokens.Token; pub const NodeList = std.ArrayList(*Node); pub const ParamList = std.ArrayList(*ParamDecl); +// TODO convert FnCall to something like PrefixOp / InfixOp / SuffixOp pub const NodeType = enum { Root, FnDecl, + FnCall, + String, }; pub const ParamDecl = struct { @@ -23,9 +26,16 @@ pub const FnDecl = struct { body: NodeList, }; +pub const FnCall = struct { + func_name: Token, + arguments: NodeList, +}; + pub const Node = union(NodeType) { Root: NodeList, FnDecl: FnDecl, + FnCall: FnCall, + String: Token, }; pub fn mkRoot(allocator: *std.mem.Allocator) !*Node { diff --git a/src/parser.zig b/src/parser.zig index 14144df..f07ebc3 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -18,16 +18,18 @@ pub const Parser = struct { tokens: []Token = undefined, + hadError: bool = false, + pub fn init(allocator: *Allocator, scanner: *Scanner) Parser { return Parser{ .allocator = allocator, .scanner = scanner }; } - fn doError(self: *Parser, comptime fmt: []const u8, args: ...) Result!void { + fn doError(self: *Parser, comptime fmt: []const u8, args: ...) void { + self.hadError = true; + std.debug.warn("parser error at line {}\n\t", self.scanner.line); std.debug.warn(fmt, args); std.debug.warn("\n"); - - return Result.CompileError; } fn peek(self: *Parser) Token { @@ -152,11 +154,18 @@ pub const Parser = struct { // function body _ = try self.nextToken(); _ = try self.consumeSingle(.LeftBrace); + var body = ast.NodeList.init(self.allocator); + while (true) { var tok = self.peek(); if (tok.ttype == .RightBrace) break; - // TODO statements? - //var node = self.processToken(tok); + + // TODO statements + //var node = try self.processToken(tok); + //std.debug.warn("stmt:{}\n", node); + //try body.append(node); + + tok = try self.nextToken(); } _ = try self.consumeSingle(.RightBrace); @@ -164,9 +173,38 @@ pub const Parser = struct { return try self.mkFnDecl(name, param_list); } - fn processToken(self: *Parser, token: Token) !*ast.Node { + fn functionCall(self: *Parser) !*ast.Node { + var identifier = try self.consumeSingle(.Identifier); + _ = try self.consumeSingle(.LeftParen); + + // arguments + var args = ast.NodeList.init(self.allocator); + + while (true) { + var tok = self.peek(); + + switch (tok.ttype) { + .RightParen => break, + .String => blk: { + var node = try self.allocator.create(Node); + node.* = Node{ .String = tok }; + try args.append(node); + }, + else => {}, + } + + tok = try self.nextToken(); + } + + _ = try self.consumeSingle(.RightParen); + + return Node{ .FnCall = ast.FnCall{ .func_name = identifier, .arguments = args } }; + } + + fn processToken(self: *Parser, token: Token) anyerror!*ast.Node { var node = switch (token.ttype) { .Fn => try self.functionDecl(), + .Identifier => try self.functionCall(), else => blk: { try self.doError("TODO handle {}\n", token.ttype); return Result.CompileError; @@ -176,18 +214,53 @@ pub const Parser = struct { return node; } + fn block(self: *Parser) anyerror!*ast.Node { + + // TODO if(self.accept(.Const)) + + // while receiving functions, process more + while (self.accept(.Fn)) { + try self.consumeSingle(.LeftParen); + try self.consumeSingle(.RightParen); + var block = try self.block(); + } + + self.statement(); + } + + fn topDecl(self: *@This()) !?*Node { + return switch (self.peek().ttype) { + .Fn => blk: { + _ = try self.consumeSingle(.Fn); + var name = try self.consumeSingle(.Identifier); + std.debug.warn("!fn name: {}\n", name); + break :blk try self.mkFnDecl( + name, + ast.ParamList.init(self.allocator), + ); + }, + else => |ttype| blk: { + self.doError("expected fn, got {}\n", ttype); + break :blk null; + }, + }; + } + pub fn parse(self: *Parser) !*ast.Node { self.tokens = try self.allocator.alloc(Token, 0); var root = try ast.mkRoot(self.allocator); while (true) { var token = try self.nextToken(); - if (token.ttype == .EOF) break; - var node = try self.processToken(token); - std.debug.warn("node: {}\n", node.*); - try root.Root.append(node); + var node = try self.topDecl(); + if (node == null) continue; + try root.Root.append(node.?); + } + + if (self.hadError) { + return error.ParseError; } return root;