Compare commits

..

4 commits

Author SHA1 Message Date
b0e123f83a rm ast_printer 2019-07-01 15:02:14 -03:00
90f33e84fc remove old parser, work towards rewritten parser 2019-07-01 15:01:43 -03:00
fa47bd7a7e fix for latest zig 2019-06-29 23:50:43 -03:00
ff5a532c58 scanner: fix issues regarding peekNext 2019-06-06 01:28:10 -03:00
7 changed files with 59 additions and 305 deletions

3
examples/hello.v Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println("hello world!");
}

View file

@ -1,103 +1,25 @@
const std = @import("std");
const tokens = @import("tokens.zig"); const tokens = @import("tokens.zig");
const Token = tokens.Token; const Token = tokens.Token;
pub const ExprType = enum { pub const NodeList = std.ArrayList(*Node);
Unary,
Binary, pub const NodeType = enum {
Grouping, Root,
Number, FnDecl,
Bool,
Nil,
String,
}; };
pub const Expr = union(ExprType) { pub const FnDecl = struct {
Unary: UnaryExpr, func_name: []const u8,
Binary: BinaryExpr,
Grouping: Grouping,
Number: Number,
Bool: Bool,
Nil: Nil,
String: String,
}; };
pub const UnaryExpr = struct { pub const Node = union(NodeType) {
operator: Token, Root: NodeList,
right: *Expr, FnDecl: FnDecl,
}; };
pub fn mkUnary(operator: Token, right: *Expr) Expr { pub fn mkRoot(allocator: *std.mem.Allocator) !*Node {
return Expr{ var node = try allocator.create(Node);
.Unary = UnaryExpr{ node.* = Node{ .Root = NodeList.init(allocator) };
.operator = operator, return node;
.right = right,
},
};
} }
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;

View file

@ -1,32 +0,0 @@
const std = @import("std");
const ast = @import("ast.zig");
fn parenthesize(name: []const u8, exprs: []*ast.Expr) void {
std.debug.warn("({}", name);
for (exprs) |expr| {
std.debug.warn(" ");
printAst(expr);
}
std.debug.warn(")");
}
pub fn printAst(ast_expr: *ast.Expr) void {
switch (ast_expr.*) {
.Binary => |expr| parenthesize(expr.operator.lexeme, &[]*ast.Expr{ expr.left, expr.right }),
.Grouping => |expr| parenthesize("group", &[]*ast.Expr{expr.expression}),
.Unary => |expr| parenthesize(expr.operator.lexeme, &[]*ast.Expr{expr.right}),
.Number => |ast_num| {
switch (ast_num) {
.Integer32 => |num| std.debug.warn("{}", num),
.Integer64 => |num| std.debug.warn("{}", num),
.Unsigned32 => |num| std.debug.warn("{}", num),
.Unsigned64 => |num| std.debug.warn("{}", num),
.Float32 => |num| std.debug.warn("{}", num),
.Float64 => |num| std.debug.warn("{}", num),
}
},
else => unreachable,
}
}

View file

@ -67,8 +67,7 @@ fn runPrompt(allocator: *Allocator) !void {
} }
pub fn main() anyerror!void { pub fn main() anyerror!void {
var da = std.heap.DirectAllocator.init(); var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator);
var arena = std.heap.ArenaAllocator.init(&da.allocator);
defer arena.deinit(); defer arena.deinit();
var allocator = &arena.allocator; var allocator = &arena.allocator;

View file

@ -10,8 +10,7 @@ const Scanner = scanners.Scanner;
const Token = tokens.Token; const Token = tokens.Token;
const TokenType = tokens.TokenType; const TokenType = tokens.TokenType;
const Result = main.Result; const Result = main.Result;
const Node = ast.Node;
const Expr = ast.Expr;
pub const Parser = struct { pub const Parser = struct {
allocator: *Allocator, allocator: *Allocator,
@ -24,7 +23,7 @@ pub const Parser = struct {
return Parser{ .allocator = allocator, .scanner = scanner }; 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("parser error at line {}\n\t", self.scanner.line);
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
std.debug.warn("\n"); std.debug.warn("\n");
@ -50,20 +49,6 @@ pub const Parser = struct {
return Result.CompileError; 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 { fn isAtEnd(self: *Parser) bool {
return self.peek().ttype == .EOF; return self.peek().ttype == .EOF;
} }
@ -105,150 +90,50 @@ pub const Parser = struct {
return Result.CompileError; return Result.CompileError;
} }
fn equality(self: *Parser) !Expr { fn mkFnDecl(self: *Parser, name: []const u8) !*ast.Node {
var expr = try self.comparison(); var node = try self.allocator.create(Node.FnDecl);
node.* = Node.FnDecl{ .name = name };
while (self.match(&[]TokenType{ TokenType.BangEqual, TokenType.EqualEqual })) { return node;
var operator = self.previous();
var right = try self.comparison();
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 comparison(self: *Parser) !Expr { fn processToken(self: *Parser, token: Token) Result!ast.Node {
var expr = try self.addition(); switch (token.ttype) {
//.Fn => try self.functionDecl(),
while (self.match(&[]TokenType{ else => blk: {
TokenType.Greater, try self.doError("TODO handle {}\n", token.ttype);
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; 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 { pub fn parse(self: *Parser) !*ast.Node {
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); self.tokens = try self.allocator.alloc(Token, 0);
var i: usize = 0; var i: usize = 0;
var root = try ast.mkRoot(self.allocator);
while (true) { while (true) {
var tok_opt = try self.scanner.nextToken(); var tok_opt = try self.scanner.nextToken();
if (tok_opt) |token| { if (tok_opt) |token| {
self.tokens = try self.allocator.realloc(self.tokens, i + 1); self.tokens = try self.allocator.realloc(self.tokens, i + 1);
self.tokens[i] = token; self.tokens[i] = token;
i += 1; i += 1;
if (token.ttype == .EOF) break; 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 root;
//return Expr{ .Number = ast.Number{ .Integer32 = 69 } };
//return self.root;
var expr = self.expression() catch |parse_err| {
return null;
};
return &expr;
} }
}; };

View file

@ -44,22 +44,12 @@ pub const Runner = struct {
scanner = scanners.Scanner.init(self.allocator, code); scanner = scanners.Scanner.init(self.allocator, code);
var parser = Parser.init(self.allocator, &scanner); var parser = Parser.init(self.allocator, &scanner);
var expr_opt = try parser.parse(); var root = try parser.parse();
//var expr = ast.mkBinary( var it = root.Root.iterator();
// &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)),
//);
if (expr_opt) |expr_ptr| { while (it.next()) |node| {
printer.printAst(expr_ptr); std.debug.warn("{}\n", node.*);
std.debug.warn("\n");
} else {
return Result.CompileError;
} }
return Result.Ok; return Result.Ok;

View file

@ -24,7 +24,7 @@ fn isAlphaNumeric(char: u8) bool {
return isAlpha(char) or isDigit(char); return isAlpha(char) or isDigit(char);
} }
const keywords = [][]const u8{ const keywords = [_][]const u8{
"break", "break",
"const", "const",
"continue", "continue",
@ -51,7 +51,7 @@ const keywords = [][]const u8{
"None", "None",
}; };
const keyword_ttypes = []TokenType{ const keyword_ttypes = [_]TokenType{
.Break, .Break,
.Const, .Const,
.Continue, .Continue,
@ -186,35 +186,17 @@ pub const Scanner = struct {
/// Peek at the next character in the scanner /// Peek at the next character in the scanner
fn peekNext(self: *Scanner) u8 { fn peekNext(self: *Scanner) u8 {
if (self.current > self.source.len) return 0; if (self.current + 1 > self.source.len) return 0;
return self.source[self.current]; return self.source[self.current];
} }
/// Skip all whitespace, but increments Scanner.line when finding a newline.
fn skipWhitespace(self: *Scanner) void {
while (true) {
var c = self.peek();
switch (c) {
' ', '\r', '\t' => blk: {
_ = self.advance();
},
'\n' => blk: {
self.line += 1;
_ = self.advance();
},
else => return,
}
}
}
/// Consume a number. /// Consume a number.
/// Returns either an Integer or a Float token. Proper typing /// Returns either an Integer or a Float token. Proper typing
/// of the number (i32 i64 u32 u64 f32 f64) are for the parser. /// of the number (i32 i64 u32 u64 f32 f64) are for the parser.
fn doNumber(self: *Scanner) Token { fn doNumber(self: *Scanner) Token {
var ttype = TokenType.Integer; var ttype = TokenType.Integer;
while (isDigit(self.peek())) { while (isDigit(self.peekNext())) {
_ = self.advance(); _ = self.advance();
} }
@ -279,7 +261,6 @@ pub const Scanner = struct {
} }
pub fn nextToken(self: *Scanner) !?Token { pub fn nextToken(self: *Scanner) !?Token {
self.skipWhitespace();
self.start = self.current; self.start = self.current;
if (self.isAtEnd()) return self.makeToken(TokenType.EOF); if (self.isAtEnd()) return self.makeToken(TokenType.EOF);
@ -342,6 +323,12 @@ pub const Scanner = struct {
'\'' => try self.doString('\''), '\'' => try self.doString('\''),
'"' => try self.doString('"'), '"' => try self.doString('"'),
' ', '\r', '\t' => null,
'\n' => blk: {
self.line += 1;
break :blk null;
},
else => return ScannerError.Unexpected, else => return ScannerError.Unexpected,
}; };