diff --git a/examples/hello.v b/examples/hello.v index 352e921..cf7b836 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -1,5 +1,8 @@ const ( - AWOO = 2 + Cock = 1 + Ball = 2 + Deals = 3 + Businesses = 4 ) fn main(a int) {} diff --git a/src/ast.zig b/src/ast.zig index d909a5e..87d4164 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -3,6 +3,7 @@ const tokens = @import("tokens.zig"); const Token = tokens.Token; pub const NodeList = std.ArrayList(*Node); +pub const ExprList = std.ArrayList(*Expr); pub const ParamList = std.ArrayList(ParamDecl); pub const ConstList = std.ArrayList(SingleConst); @@ -10,9 +11,9 @@ pub const ConstList = std.ArrayList(SingleConst); pub const NodeType = enum { Root, FnDecl, - FnCall, ConstDecl, - String, + Block, + Expr, }; pub const ParamDecl = struct { @@ -28,11 +29,6 @@ pub const FnDecl = struct { body: NodeList, }; -pub const FnCall = struct { - func_name: Token, - arguments: NodeList, -}; - pub const SingleConst = struct { name: Token, @@ -40,12 +36,37 @@ pub const SingleConst = struct { value: Token, }; +pub const BinaryExpr = struct { + left: *Expr, + op: Token, + right: *Expr, +}; + +pub const UnaryExpr = struct { + op: Token, + right: *Expr, +}; + +pub const LiteralExpr = union(enum) { + Bool: bool, + Integer: []const u8, + Float: []const u8, + String: []const u8, +}; + +pub const Expr = union(enum) { + Binary: BinaryExpr, + Unary: UnaryExpr, + Literal: LiteralExpr, + Grouping: *Expr, +}; + pub const Node = union(NodeType) { Root: NodeList, FnDecl: FnDecl, ConstDecl: ConstList, - FnCall: FnCall, - String: Token, + Block: ExprList, + Expr: *Expr, }; pub fn mkRoot(allocator: *std.mem.Allocator) !*Node { diff --git a/src/parser.zig b/src/parser.zig index 900be10..8bbd3e4 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -10,7 +10,9 @@ const Scanner = scanners.Scanner; const Token = tokens.Token; const TokenType = tokens.TokenType; const Result = main.Result; + const Node = ast.Node; +const Expr = ast.Expr; pub const Parser = struct { allocator: *Allocator, @@ -107,6 +109,14 @@ pub const Parser = struct { return Result.CompileError; } + fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool { + for (ttypes) |ttype| { + if (self.peek().ttype == ttype) return true; + } + + return false; + } + fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList) !*ast.Node { var node = try self.allocator.create(Node); node.* = Node{ @@ -127,6 +137,120 @@ pub const Parser = struct { return node; } + fn mkBlock(self: *Parser, exprs: ast.ExprList) !*ast.Node { + var node = try self.allocator.create(Node); + node.* = Node{ .Block = exprs }; + return node; + } + + fn mkExpr(self: *Parser, expr: *Expr) !*ast.Node { + var node = try self.allocator.create(Node); + node.* = Node{ .Expr = expr }; + return node; + } + + fn mkGrouping(self: *Parser, expr: *Expr) !*ast.Expr { + var grouping = try self.allocator.create(Expr); + grouping.* = Expr{ .Grouping = expr }; + return grouping; + } + + fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Unary = ast.UnaryExpr{ + .op = op, + .right = right, + }, + }; + return expr; + } + + fn mkBinary(self: *Parser, left: *Expr, op: Token, right: *Expr) !*Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Binary = ast.BinaryExpr{ + .left = left, + .op = op, + .right = right, + }, + }; + + return expr; + } + + fn mkBool(self: *Parser, val: bool) !*ast.Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Literal = ast.LiteralExpr{ + .Bool = val, + }, + }; + + return expr; + } + + fn mkInteger(self: *Parser, val: []const u8) !*ast.Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Literal = ast.LiteralExpr{ + .Integer = val, + }, + }; + + return expr; + } + + fn mkFloat(self: *Parser, val: []const u8) !*ast.Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Literal = ast.LiteralExpr{ + .Float = val, + }, + }; + + return expr; + } + + fn mkString(self: *Parser, val: []const u8) !*ast.Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Literal = ast.LiteralExpr{ + .String = val, + }, + }; + + return expr; + } + + pub fn parse(self: *Parser) !*ast.Node { + self.tokens = try self.allocator.alloc(Token, 0); + var root = try ast.mkRoot(self.allocator); + + var token_opt: ?Token = null; + + while (true) { + if (token_opt == null) { + token_opt = try self.nextToken(); + } else { + token_opt = self.peek(); + } + + var token = token_opt.?; + if (token.ttype == .EOF) break; + + var node = try self.parseTopDecl(); + if (node == null) continue; + try root.Root.append(node.?); + } + + if (self.hadError) { + return error.ParseError; + } + + return root; + } + fn functionDecl(self: *Parser) !*ast.Node { // function body @@ -164,19 +288,7 @@ pub const Parser = struct { return node; } - fn block(self: *Parser) anyerror!*ast.Node { - - // 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 fnDecl(self: *@This()) !?*Node { + fn parseFnDecl(self: *@This()) !?*Node { var param_list = ast.ParamList.init(self.allocator); errdefer param_list.deinit(); @@ -197,15 +309,15 @@ pub const Parser = struct { _ = try self.consumeSingle(.RightParen); - _ = try self.consumeSingle(.LeftBrace); - // TODO block - _ = try self.consumeSingle(.RightBrace); + // TODO return type + + var block = try self.parseBlock(); std.debug.warn("!fn name: {}\n", name); return try self.mkFnDecl(name, param_list); } - fn constDecl(self: *@This()) !?*Node { + fn parseConstDecl(self: *@This()) !?*Node { var consts = ast.ConstList.init(self.allocator); errdefer consts.deinit(); @@ -230,10 +342,10 @@ pub const Parser = struct { return self.mkConstDecl(consts); } - fn topDecl(self: *@This()) !?*Node { + fn parseTopDecl(self: *@This()) !?*Node { return switch (self.peek().ttype) { - .Fn => try self.fnDecl(), - .Const => try self.constDecl(), + .Fn => try self.parseFnDecl(), + .Const => try self.parseConstDecl(), else => |ttype| blk: { self.doError("(basic) expected fn/const, got {}\n", ttype); @@ -242,31 +354,145 @@ pub const Parser = struct { }; } - pub fn parse(self: *Parser) !*ast.Node { - self.tokens = try self.allocator.alloc(Token, 0); - var root = try ast.mkRoot(self.allocator); + fn parseBlock(self: *@This()) !?*Node { + var exprs = ast.ExprList.init(self.allocator); + errdefer exprs.deinit(); + _ = try self.consumeSingle(.LeftBrace); - var token_opt: ?Token = null; + while (self.peek().ttype != .RightBrace) + try exprs.append((try self.parseExpr()).Expr); - while (true) { - if (token_opt == null) { - token_opt = try self.nextToken(); - } else { - token_opt = self.peek(); - } + _ = try self.consumeSingle(.RightBrace); - var token = token_opt.?; - if (token.ttype == .EOF) break; + return try self.mkBlock(exprs); + } - var node = try self.topDecl(); - if (node == null) continue; - try root.Root.append(node.?); + fn parseExpr(self: *@This()) anyerror!*Node { + var expr = try self.parseEquality(); + return self.mkExpr(expr); + } + + fn parseEquality(self: *@This()) !*Expr { + var expr = try self.parseComparison(); + + while (self.peek().ttype == .EqualEqual) { + var op = self.peek(); + var right = try self.parseComparison(); + + expr.* = ast.Expr{ + .Binary = ast.BinaryExpr{ + .left = expr, + .op = op, + .right = right, + }, + }; } - if (self.hadError) { - return error.ParseError; + return expr; + } + + fn parseComparison(self: *@This()) !*Expr { + var expr = try self.parseAddition(); + + while (self.compareAnyOf(&[_]TokenType{ + .Greater, + .GreaterEqual, + .Less, + .LessEqual, + })) { + var op = self.previous(); + var right = try self.parseAddition(); + + expr.* = ast.Expr{ + .Binary = ast.BinaryExpr{ + .left = expr, + .op = op, + .right = right, + }, + }; } - return root; + return expr; + } + + fn parseAddition(self: *@This()) !*Expr { + var expr = try self.parseMultiplication(); + + while (self.compareAnyOf(&[_]TokenType{ + .Minus, .Plus, + })) { + var op = self.previous(); + var right = try self.parseMultiplication(); + + expr.* = ast.Expr{ + .Binary = ast.BinaryExpr{ + .left = expr, + .op = op, + .right = right, + }, + }; + } + + return expr; + } + + fn parseMultiplication(self: *@This()) !*Expr { + var expr = try self.parseUnary(); + + while (self.compareAnyOf(&[_]TokenType{ + .Star, .Slash, + })) { + var op = self.previous(); + var right = try self.parseUnary(); + + expr.* = ast.Expr{ + .Binary = ast.BinaryExpr{ + .left = expr, + .op = op, + .right = right, + }, + }; + } + + return expr; + } + + fn parseUnary(self: *@This()) anyerror!*Expr { + if (self.compareAnyOf(&[_]TokenType{ .Bang, .Minus })) { + var op = self.previous(); + var right = try self.parseUnary(); + + return try self.mkUnary(op, right); + } + + return try self.parsePrimary(); + } + + fn parsePrimary(self: *@This()) !*Expr { + const curtype = self.peek().ttype; + const lexeme = self.peek().lexeme; + + _ = switch (curtype) { + .False => return try self.mkBool(false), + .True => return try self.mkBool(true), + + .Integer => return try self.mkInteger(lexeme), + .Float => return try self.mkFloat(lexeme), + .String => return try self.mkString(lexeme), + + .LeftParen => blk: { + var expr = (try self.parseExpr()).Expr; + _ = try self.consume(.RightParen, "Expected ')' after expression"); + break :blk try self.mkGrouping(expr); + }, + + else => blk: { + self.doError("expected false/true/int/float/string/leftparen, got {}", curtype); + return Result.CompileError; + }, + }; + + std.debug.warn("SHOULD NOT HAVE HAPPENED\n"); + return Result.CompileError; } };