vig/src/parser.zig

255 lines
7.1 KiB
Zig

const std = @import("std");
const scanners = @import("scanner.zig");
const main = @import("main.zig");
const ast = @import("ast.zig");
const tokens = @import("tokens.zig");
const err = @import("errors.zig");
const Allocator = std.mem.Allocator;
const Scanner = scanners.Scanner;
const Token = tokens.Token;
const TokenType = tokens.TokenType;
const Result = main.Result;
const Expr = ast.Expr;
pub const Parser = struct {
allocator: *Allocator,
scanner: *Scanner,
tokens: []Token = undefined,
current: usize = 0,
pub fn init(allocator: *Allocator, scanner: *Scanner) Parser {
return Parser{ .allocator = allocator, .scanner = scanner };
}
fn doError(self: *Parser, comptime fmt: []const u8, args: ...) !void {
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 {
return self.tokens[self.current];
}
fn previous(self: *Parser) Token {
return self.tokens[self.current - 1];
}
fn tokenError(self: *Parser, token: Token, msg: []const u8) Result!void {
if (token.ttype == .EOF) {
err.report(token.line, " at end", msg);
} else {
err.reportFmt(token.line, " at '{}': {}", token.lexeme, msg);
}
return Result.CompileError;
}
fn synchronize(self: *Parser) void {
_ = self.advance();
while (!self.isAtEnd()) {
if (self.previous().ttype == .Semicolon) return;
switch (self.peek().ttype) {
.Struct, .Fn, .For, .If, .Return => return,
else => {},
}
_ = self.advance();
}
}
fn isAtEnd(self: *Parser) bool {
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 match(self: *Parser, ttypes: []TokenType) bool {
for (ttypes) |ttype| {
if (self.check(ttype)) {
_ = self.advance();
return true;
}
}
return false;
}
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 equality(self: *Parser) !Expr {
var expr = try self.comparison();
while (self.match(&[]TokenType{ TokenType.BangEqual, TokenType.EqualEqual })) {
var operator = self.previous();
var right = try self.comparison();
expr = ast.mkBinary(&expr, operator, &right);
}
return expr;
}
fn comparison(self: *Parser) !Expr {
var expr = try self.addition();
while (self.match(&[]TokenType{
TokenType.Greater,
TokenType.GreaterEqual,
TokenType.Less,
TokenType.LessEqual,
})) {
var operator = self.previous();
var right = try self.addition();
expr = ast.mkBinary(&expr, operator, &right);
}
return expr;
}
fn addition(self: *Parser) !Expr {
var expr = try self.multiplication();
while (self.match(&[]TokenType{ TokenType.Minus, TokenType.Plus })) {
var operator = self.previous();
var right = try self.multiplication();
expr = ast.mkBinary(&expr, operator, &right);
}
return expr;
}
fn multiplication(self: *Parser) anyerror!Expr {
var expr = try self.unary();
while (self.match(&[]TokenType{ TokenType.Slash, TokenType.Star })) {
var operator = self.previous();
var right = try self.unary();
expr = ast.mkBinary(&expr, operator, &right);
}
return expr;
}
fn unary(self: *Parser) anyerror!Expr {
if (self.match(&[]TokenType{ TokenType.Bang, TokenType.Minus })) {
var operator = self.previous();
var right = try self.unary();
return ast.mkUnary(operator, &right);
}
return try self.primary();
}
fn doInt(self: *Parser) !Expr {
var token = self.previous();
// try to parse it as an i32 first, if that fails, do i64.
var num_32 = std.fmt.parseInt(i32, token.lexeme, 10) catch |pi_err| {
if (pi_err == error.Overflow) {
var num_64 = std.fmt.parseInt(i64, token.lexeme, 10) catch |pi_err2| {
if (pi_err2 == error.Overflow) {
try self.tokenError(token, "Failed to parse number: overflow");
return Result.CompileError;
} else {
return pi_err2;
}
};
return ast.mkNum(i64, num_64);
} else {
return pi_err;
}
};
return ast.mkNum(i32, num_32);
}
fn primary(self: *Parser) !Expr {
if (self.matchSingle(TokenType.False)) return ast.Expr{ .Bool = false };
if (self.matchSingle(TokenType.True)) return ast.Expr{ .Bool = true };
if (self.matchSingle(TokenType.None)) return ast.Expr{ .Nil = {} };
if (self.matchSingle(TokenType.Integer)) {
return try self.doInt();
}
if (self.matchSingle(TokenType.String)) {
var lexeme = self.previous().lexeme;
var slice = try self.allocator.alloc(u8, lexeme.len);
std.mem.copy(u8, slice, lexeme);
return ast.Expr{ .String = slice };
}
if (self.matchSingle(TokenType.LeftParen)) {
var expr = try self.expression();
_ = try self.consume(.RightParen, "Expect ')' after expression");
return ast.mkGrouping(&expr);
}
try self.tokenError(self.peek(), "Expect expression");
return Result.CompileError;
}
fn expression(self: *Parser) !Expr {
return try self.equality();
}
pub fn parse(self: *Parser) !?*Expr {
self.tokens = try self.allocator.alloc(Token, 0);
var i: usize = 0;
while (true) {
var tok_opt = try self.scanner.nextToken();
if (tok_opt) |token| {
self.tokens = try self.allocator.realloc(self.tokens, i + 1);
self.tokens[i] = token;
i += 1;
if (token.ttype == .EOF) break;
}
}
std.debug.warn("{} tokens\n", i);
//return Expr{ .Number = ast.Number{ .Integer32 = 69 } };
//return self.root;
var expr = self.expression() catch |parse_err| {
return null;
};
return &expr;
}
};