diff --git a/src/ast.zig b/src/ast.zig index a2b1834..4de4f03 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -10,7 +10,7 @@ pub const NodeType = enum { }; pub const FnDecl = struct { - func_name: Token, + func_name: []const u8, }; pub const Node = union(NodeType) { diff --git a/src/parser.zig b/src/parser.zig index 76b8c59..e43588e 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -17,6 +17,7 @@ pub const Parser = struct { scanner: *Scanner, tokens: []Token = undefined, + current: usize = 0, pub fn init(allocator: *Allocator, scanner: *Scanner) Parser { return Parser{ .allocator = allocator, .scanner = scanner }; @@ -31,11 +32,11 @@ pub const Parser = struct { } fn peek(self: *Parser) Token { - return self.tokens[self.tokens.len - 1]; + return self.tokens[self.current]; } fn previous(self: *Parser) Token { - return self.tokens[self.tokens.len - 2]; + return self.tokens[self.current - 1]; } fn tokenError(self: *Parser, token: Token, msg: []const u8) Result!void { @@ -52,98 +53,85 @@ pub const Parser = struct { return self.peek().ttype == .EOF; } + fn advance(self: *Parser) Token { + if (!self.isAtEnd()) self.current += 1; + return self.previous(); + } + fn check(self: *Parser, ttype: TokenType) bool { if (self.isAtEnd()) return false; return self.peek().ttype == ttype; } - fn nextToken(self: *Parser) !Token { - var token: Token = undefined; - - while (true) { - var next_token_opt = try self.scanner.nextToken(); - if (next_token_opt) |token_nice| { - token = token_nice; - break; + fn match(self: *Parser, ttypes: []TokenType) bool { + for (ttypes) |ttype| { + if (self.check(ttype)) { + _ = self.advance(); + return true; } } - self.tokens = try self.allocator.realloc( - self.tokens, - self.tokens.len + 1, - ); - - self.tokens[self.tokens.len - 1] = token; - return token; + return false; } - fn consume(self: *Parser, ttype: TokenType, comptime msg: []const u8) !Token { - if (self.check(ttype)) return try self.nextToken(); + fn matchSingle(self: *Parser, ttype: TokenType) bool { + if (self.check(ttype)) { + _ = self.advance(); + return true; + } + + return false; + } + + fn consume(self: *Parser, ttype: TokenType, comptime msg: []const u8) Result!Token { + if (self.check(ttype)) return self.advance(); try self.tokenError(self.peek(), msg); return Result.CompileError; } - fn consumeSingle(self: *Parser, ttype: TokenType) !Token { - std.debug.warn("consume {}, has {}\n", ttype, self.peek().ttype); - - if (self.check(ttype)) { - var cur = self.peek(); - _ = try self.nextToken(); - std.debug.warn("now has {}\n", self.peek()); - return cur; - } - - var buf_main: [1000]u8 = undefined; - var buf = try std.fmt.bufPrint( - buf_main[0..], - "expected {}, got {}", - ttype, - self.peek().ttype, - ); - try self.tokenError(self.peek(), buf); - - return Result.CompileError; - } - - fn mkFnDecl(self: *Parser, name: Token) !*ast.Node { - var node = try self.allocator.create(Node); - node.* = Node{ .FnDecl = ast.FnDecl{ .func_name = name } }; + fn mkFnDecl(self: *Parser, name: []const u8) !*ast.Node { + var node = try self.allocator.create(Node.FnDecl); + node.* = Node.FnDecl{ .name = name }; return node; } fn functionDecl(self: *Parser) !*ast.Node { - _ = try self.consumeSingle(.Fn); - var name = try self.consumeSingle(.Identifier); - _ = try self.consumeSingle(.LeftParen); - + // get the name + var name = try self.consume(.Identifier, "expected function name"); return try self.mkFnDecl(name); } - fn processToken(self: *Parser, token: Token) !*ast.Node { - var node = switch (token.ttype) { - .Fn => try self.functionDecl(), + fn processToken(self: *Parser, token: Token) Result!ast.Node { + switch (token.ttype) { + //.Fn => try self.functionDecl(), else => blk: { try self.doError("TODO handle {}\n", token.ttype); return Result.CompileError; }, - }; - - return node; + } } pub fn parse(self: *Parser) !*ast.Node { self.tokens = try self.allocator.alloc(Token, 0); + var i: usize = 0; var root = try ast.mkRoot(self.allocator); while (true) { - var token = try self.nextToken(); + var tok_opt = try self.scanner.nextToken(); - if (token.ttype == .EOF) break; + if (tok_opt) |token| { + self.tokens = try self.allocator.realloc(self.tokens, i + 1); + self.tokens[i] = token; + i += 1; - var node = try self.processToken(token); - std.debug.warn("{}\n", node.*); - try root.Root.append(node); + if (token.ttype == .EOF) break; + + var node = try self.processToken(token); + try root.Root.append(&node); + } else { + continue; + } } return root; diff --git a/src/scanner.zig b/src/scanner.zig index 613b096..491f1f2 100644 --- a/src/scanner.zig +++ b/src/scanner.zig @@ -110,10 +110,6 @@ pub const Scanner = struct { return self.source[self.current - 1]; } - fn rollback(self: *Scanner) void { - self.current -= 1; - } - pub fn currentLexeme(self: *Scanner) []const u8 { return self.source[self.start..self.current]; } @@ -249,9 +245,6 @@ pub const Scanner = struct { _ = self.advance(); } - // ugly hack. - self.rollback(); - // after reading the identifier, we check // if it is any of our keywords, if it is, then we add // the specificed keyword type. if not, just .IDENTIFIER