diff --git a/examples/hello.v b/examples/hello.v new file mode 100644 index 0000000..46cc8fd --- /dev/null +++ b/examples/hello.v @@ -0,0 +1,3 @@ +fn main() { + println("hello world!"); +} diff --git a/src/ast.zig b/src/ast.zig index c9d44e8..4de4f03 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -1,103 +1,25 @@ +const std = @import("std"); const tokens = @import("tokens.zig"); const Token = tokens.Token; -pub const ExprType = enum { - Unary, - Binary, - Grouping, - Number, - Bool, - Nil, - String, +pub const NodeList = std.ArrayList(*Node); + +pub const NodeType = enum { + Root, + FnDecl, }; -pub const Expr = union(ExprType) { - Unary: UnaryExpr, - Binary: BinaryExpr, - Grouping: Grouping, - Number: Number, - Bool: Bool, - Nil: Nil, - String: String, +pub const FnDecl = struct { + func_name: []const u8, }; -pub const UnaryExpr = struct { - operator: Token, - right: *Expr, +pub const Node = union(NodeType) { + Root: NodeList, + FnDecl: FnDecl, }; -pub fn mkUnary(operator: Token, right: *Expr) Expr { - return Expr{ - .Unary = UnaryExpr{ - .operator = operator, - .right = right, - }, - }; +pub fn mkRoot(allocator: *std.mem.Allocator) !*Node { + var node = try allocator.create(Node); + node.* = Node{ .Root = NodeList.init(allocator) }; + return node; } - -pub const BinaryExpr = struct { - left: *Expr, - operator: Token, - right: *Expr, -}; - -pub fn mkBinary(left: *Expr, operator: Token, right: *Expr) Expr { - return Expr{ - .Binary = BinaryExpr{ - .left = left, - .operator = operator, - .right = right, - }, - }; -} - -pub const Grouping = struct { - expression: *Expr, -}; - -pub fn mkGrouping(expression: *Expr) Expr { - return Expr{ - .Grouping = Grouping{ - .expression = expression, - }, - }; -} - -/// Represents the default number literals in V. -pub const NumberType = enum { - Integer32, - Integer64, - Unsigned32, - Unsigned64, - Float32, - Float64, -}; - -/// "translation" of V number types to Zig number types for nicer -/// representation. -pub const Number = union(NumberType) { - Integer32: i32, - Integer64: i64, - Unsigned32: u32, - Unsigned64: u64, - Float32: f32, - Float64: f64, -}; - -pub fn mkNum(comptime T: type, num: T) Expr { - var expr = switch (T) { - i32 => Expr{ .Number = Number{ .Integer32 = num } }, - i64 => Expr{ .Number = Number{ .Integer64 = num } }, - u32 => Expr{ .Number = Number{ .Unsigned32 = num } }, - u64 => Expr{ .Number = Number{ .Unsigned64 = num } }, - f32 => Expr{ .Number = Number{ .Float32 = num } }, - f64 => Expr{ .Number = Number{ .Float64 = num } }, - else => unreachable, - }; - - return expr; -} - -pub const Bool = bool; -pub const Nil = void; -pub const String = []u8; diff --git a/src/parser.zig b/src/parser.zig index 127a34d..e43588e 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -10,8 +10,7 @@ const Scanner = scanners.Scanner; const Token = tokens.Token; const TokenType = tokens.TokenType; const Result = main.Result; - -const Expr = ast.Expr; +const Node = ast.Node; pub const Parser = struct { allocator: *Allocator, @@ -24,7 +23,7 @@ pub const Parser = struct { return Parser{ .allocator = allocator, .scanner = scanner }; } - fn doError(self: *Parser, comptime fmt: []const u8, args: ...) !void { + fn doError(self: *Parser, comptime fmt: []const u8, args: ...) Result!void { std.debug.warn("parser error at line {}\n\t", self.scanner.line); std.debug.warn(fmt, args); std.debug.warn("\n"); @@ -50,20 +49,6 @@ pub const Parser = struct { 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; } @@ -105,150 +90,50 @@ pub const Parser = struct { 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 mkFnDecl(self: *Parser, name: []const u8) !*ast.Node { + var node = try self.allocator.create(Node.FnDecl); + node.* = Node.FnDecl{ .name = name }; + return node; } - 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 functionDecl(self: *Parser) !*ast.Node { + // get the name + var name = try self.consume(.Identifier, "expected function name"); + return try self.mkFnDecl(name); } - 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); + 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 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 { + 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 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; + + var node = try self.processToken(token); + try root.Root.append(&node); + } else { + continue; } } - 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; + return root; } }; diff --git a/src/runner.zig b/src/runner.zig index c33eef5..e0f6493 100644 --- a/src/runner.zig +++ b/src/runner.zig @@ -44,22 +44,12 @@ pub const Runner = struct { scanner = scanners.Scanner.init(self.allocator, code); var parser = Parser.init(self.allocator, &scanner); - var expr_opt = try parser.parse(); + var root = try parser.parse(); - //var expr = ast.mkBinary( - // &ast.mkUnary( - // tokens.Token{ .ttype = .Minus, .lexeme = "-", .line = 1 }, - // &ast.mkNum(i32, 123), - // ), - // tokens.Token{ .ttype = .Star, .lexeme = "*", .line = 1 }, - // &ast.mkGrouping(&ast.mkNum(f32, 45.67)), - //); + var it = root.Root.iterator(); - if (expr_opt) |expr_ptr| { - printer.printAst(expr_ptr); - std.debug.warn("\n"); - } else { - return Result.CompileError; + while (it.next()) |node| { + std.debug.warn("{}\n", node.*); } return Result.Ok;