diff --git a/README.md b/README.md index a6ce3e3..d07eb4b 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ negatively charged towards ## wip + - no `for` yet - no `map` yet - no `in` yet (probably will be dropped) - no `module`, `import` yet diff --git a/examples/hello.v b/examples/hello.v index 2352b8e..b0f03c1 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -17,8 +17,6 @@ fn main(a int) int { mut a := 1+2 a = 2 - a = 1 && 0 - if a { println(30) } else { @@ -65,9 +63,6 @@ fn main(a int) int { str.len /= 1 awoo := [1, 2, a(), b + 2, c(31) * d] - - for a in b {} - for idx, a in b {} } fn (v Typ) voidfunc() {} diff --git a/src/ast.zig b/src/ast.zig index 5818a37..773d9c5 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -158,20 +158,12 @@ pub const LoopStmt = struct { then_branch: Block, }; -pub const ForStmt = struct { - index: ?Token, - value: Token, - array: Token, - block: Block, -}; - pub const Stmt = union(enum) { Expr: *Expr, Println: *Expr, If: IfStmt, Loop: LoopStmt, - For: ForStmt, Return: ReturnStmt, @@ -220,20 +212,6 @@ pub const Stmt = union(enum) { return stmt; } - pub fn mkFor(allocator: *std.mem.Allocator, index: ?Token, value: Token, array: Token, block: Block) !*Stmt { - var stmt = try allocator.create(Stmt); - stmt.* = Stmt{ - .For = ForStmt{ - .index = index, - .value = value, - .array = array, - .block = block, - }, - }; - - return stmt; - } - pub fn mkReturn(allocator: *std.mem.Allocator, tok: Token, value: *Expr) !*Stmt { var stmt = try allocator.create(Stmt); stmt.* = Stmt{ diff --git a/src/ast_printer.zig b/src/ast_printer.zig index f89adff..6360035 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -9,28 +9,28 @@ const warn = std.debug.warn; fn printIdent(ident: usize) void { var i: usize = 0; while (i < ident) : (i += 1) { - std.debug.warn("\t", .{}); + std.debug.warn("\t"); } } -fn print(ident: usize, comptime fmt: []const u8, args: anytype) void { +fn print(ident: usize, comptime fmt: []const u8, args: ...) void { printIdent(ident); std.debug.warn(fmt, args); } -fn printBlock(ident: usize, block: anytype, endNewline: bool) void { - std.debug.warn("(\n", .{}); +fn printBlock(ident: usize, block: var, endNewline: bool) void { + std.debug.warn("(\n"); - for (block.items) |stmt| { + for (block.toSlice()) |stmt| { printIdent(ident); printStmt(ident, stmt); - std.debug.warn("\n", .{}); + std.debug.warn("\n"); } if (endNewline) { - print(ident - 1, ")\n", .{}); + print(ident - 1, ")\n"); } else { - print(ident - 1, ")", .{}); + print(ident - 1, ")"); } } @@ -48,51 +48,55 @@ pub fn printNode(node: *Node, ident: usize) void { const typ = method.typ.lexeme; if (method.mutable) { - warn("(method mut {} {} {} {} ", .{ vari, typ, name, ret_type }); + warn("(method mut {} {} {} {} ", vari, typ, name, ret_type); } else { - warn("(method {} {} {} {} ", .{ vari, typ, name, ret_type }); + warn("(method {} {} {} {} ", vari, typ, name, ret_type); } } else { - warn("(fn {} {} (", .{ name, ret_type }); + warn("(fn {} {} (", name, ret_type); } - for (decl.params.items) |param| { - warn("({} {}) ", .{ param.name.lexeme, param.typ.lexeme }); + for (decl.params.toSlice()) |param| { + warn("({} {}) ", param.name.lexeme, param.typ.lexeme); } printBlock(ident + 1, decl.body, false); - warn(")\n", .{}); + warn(")\n"); }, .ConstDecl => |consts| { - print(ident, "(const (\n", .{}); + print(ident, "(const (\n"); - for (consts.items) |const_decl| { - print(ident + 1, "({} ", .{ + for (consts.toSlice()) |const_decl| { + print( + ident + 1, + "({} ", const_decl.name.lexeme, - }); + ); printExpr(const_decl.expr); - std.debug.warn(")\n", .{}); + std.debug.warn(")\n"); } - print(ident, "))\n", .{}); + print(ident, "))\n"); }, .Enum => |decl| { - print(ident, "(enum {} (\n", .{decl.name.lexeme}); + print(ident, "(enum {} (\n", decl.name.lexeme); - for (decl.fields.items) |field| { - print(ident + 1, "{}\n", .{ + for (decl.fields.toSlice()) |field| { + print( + ident + 1, + "{}\n", field.lexeme, - }); + ); } - print(ident, "))\n", .{}); + print(ident, "))\n"); }, .Root => { - for (node.Root.items) |child| { + for (node.Root.toSlice()) |child| { printNode(child, ident + 1); } }, @@ -100,129 +104,129 @@ pub fn printNode(node: *Node, ident: usize) void { .Stmt => |stmt| { printIdent(ident); printStmt(ident, stmt); - std.debug.warn("\n", .{}); + std.debug.warn("\n"); }, .Struct => |struc| { - print(ident, "(struct {} (\n", .{struc.name.lexeme}); - for (struc.fields.items) |field| { + print(ident, "(struct {} (\n", struc.name.lexeme); + for (struc.fields.toSlice()) |field| { printIdent(ident + 1); if (field.mutable) { - std.debug.warn("(mut ", .{}); + std.debug.warn("(mut "); } else { - std.debug.warn("(", .{}); + std.debug.warn("("); } if (field.public) { - std.debug.warn("pub ", .{}); + std.debug.warn("pub "); } if (field.mutable_outside) { - std.debug.warn("MUT_OUT ", .{}); + std.debug.warn("MUT_OUT "); } - std.debug.warn("{} {})\n", .{ field.name.lexeme, field.typ.lexeme }); + std.debug.warn("{} {})\n", field.name.lexeme, field.typ.lexeme); } - print(ident, "))\n", .{}); + print(ident, "))\n"); }, else => { - print(ident, "unknown node: {}\n", .{node}); + print(ident, "unknown node: {}\n", node); }, } } -fn parenthetize(name: []const u8, exprs: []*const Expr) void { - std.debug.warn("({}", .{name}); +fn parenthetize(name: []const u8, exprs: []*Expr) void { + std.debug.warn("({}", name); for (exprs) |expr| { - std.debug.warn(" ", .{}); + std.debug.warn(" "); printExpr(expr); } - std.debug.warn(")", .{}); + std.debug.warn(")"); } -pub fn printExpr(expr: *const Expr) void { +pub fn printExpr(expr: *Expr) void { switch (expr.*) { - .Binary => |binary| parenthetize(binary.op.lexeme, &[_]*const Expr{ binary.left, binary.right }), - .Logical => |binary| parenthetize(binary.op.lexeme, &[_]*const Expr{ binary.left, binary.right }), - .Unary => |unary| parenthetize(unary.op.lexeme, &[_]*const Expr{unary.right}), - .Grouping => |expr_ptr| parenthetize("group", &[_]*const Expr{expr_ptr}), + .Binary => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), + .Logical => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), + .Unary => |unary| parenthetize(unary.op.lexeme, &[_]*Expr{unary.right}), + .Grouping => |expr_ptr| parenthetize("group", &[_]*Expr{expr_ptr}), .Literal => |literal| { switch (literal) { - .Bool => |val| std.debug.warn("{}", .{val}), - .Integer => |val| std.debug.warn("{}", .{val}), - .Float => |val| std.debug.warn("{}", .{val}), - .String => |val| std.debug.warn("'{}'", .{val}), + .Bool => |val| std.debug.warn("{}", val), + .Integer => |val| std.debug.warn("{}", val), + .Float => |val| std.debug.warn("{}", val), + .String => |val| std.debug.warn("'{}'", val), .Array => |exprs| { - parenthetize("array", exprs.items); + parenthetize("array", exprs.toSlice()); }, - else => |typ| std.debug.warn("UnknownLiteral-{}", .{typ}), + else => |typ| std.debug.warn("UnknownLiteral-{}", typ), } }, - .Variable => |token| std.debug.warn("{}", .{token.lexeme}), + .Variable => |token| std.debug.warn("{}", token.lexeme), .VarDecl => |decl| { if (decl.mutable) { - std.debug.warn("(mut ", .{}); + std.debug.warn("(mut "); } else { - std.debug.warn("(", .{}); + std.debug.warn("("); } - std.debug.warn("let {} ", .{decl.assign.name.lexeme}); + std.debug.warn("let {} ", decl.assign.name.lexeme); printExpr(decl.assign.value); - std.debug.warn(")", .{}); + std.debug.warn(")"); }, .Assign => |assign| { - std.debug.warn("(set ", .{}); - std.debug.warn("{} ", .{assign.name.lexeme}); + std.debug.warn("(set "); + std.debug.warn("{} ", assign.name.lexeme); printExpr(assign.value); - std.debug.warn(")", .{}); + std.debug.warn(")"); }, .Call => |call| { - std.debug.warn("(", .{}); + std.debug.warn("("); printExpr(call.callee); - for (call.arguments.items) |arg| { - std.debug.warn(" ", .{}); + for (call.arguments.toSlice()) |arg| { + std.debug.warn(" "); printExpr(arg); } - std.debug.warn(")", .{}); + std.debug.warn(")"); }, .Struct => |val| { - std.debug.warn("({} (", .{val.name.lexeme}); + std.debug.warn("({} (", val.name.lexeme); - for (val.inits.items) |init| { - std.debug.warn(" ({} ", .{init.field.lexeme}); + for (val.inits.toSlice()) |init| { + std.debug.warn(" ({} ", init.field.lexeme); printExpr(init.expr); - std.debug.warn(")", .{}); + std.debug.warn(")"); } - std.debug.warn("))", .{}); + std.debug.warn("))"); }, .Get => |get| { - warn("(", .{}); + warn("("); printExpr(get.struc); - warn("{}", .{get.name.lexeme}); + warn(".{})", get.name.lexeme); }, .Set => |set| { - warn("(set ", .{}); + warn("(set "); printExpr(set.struc); - warn(" {} ", .{set.field.lexeme}); + warn(" {} ", set.field.lexeme); printExpr(set.value); - warn(")", .{}); + warn(")"); }, - else => std.debug.warn("UnknownExpr-{}", .{@tagName(expr.*)}), + else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), } } @@ -232,53 +236,38 @@ pub fn printStmt(ident: usize, stmt: *Stmt) void { .Expr => |expr| printExpr(expr), .If => |ifstmt| { - std.debug.warn("(if ", .{}); + std.debug.warn("(if "); printExpr(ifstmt.condition); - std.debug.warn(" ", .{}); + std.debug.warn(" "); printBlock(ident + 1, ifstmt.then_branch, false); if (ifstmt.else_branch) |else_branch| { - std.debug.warn(" else ", .{}); + std.debug.warn(" else "); printBlock(ident + 1, else_branch, false); } - std.debug.warn(")\n", .{}); + std.debug.warn(")\n"); }, .Loop => |loop| { - std.debug.warn("(loop ", .{}); + std.debug.warn("(loop "); if (loop.condition) |cond| { printExpr(cond); } else { - std.debug.warn("true", .{}); + std.debug.warn("true"); } - std.debug.warn(" ", .{}); + std.debug.warn(" "); printBlock(ident + 1, loop.then_branch, false); - std.debug.warn(")\n", .{}); - }, - - .For => |forstmt| { - std.debug.warn("(for ", .{}); - - if (forstmt.index) |index| { - std.debug.warn("({} {}) ", .{ index.lexeme, forstmt.value.lexeme }); - } else { - std.debug.warn("{} ", .{forstmt.value.lexeme}); - } - - std.debug.warn("{} ", .{forstmt.array.lexeme}); - - printBlock(ident + 1, forstmt.block, false); - std.debug.warn(")\n", .{}); + std.debug.warn(")\n"); }, .Return => |ret| { - std.debug.warn("(return ", .{}); + std.debug.warn("(return "); printExpr(ret.value); - std.debug.warn(")\n", .{}); + std.debug.warn(")\n"); }, - else => std.debug.warn("UnknownStmt-{}", .{@tagName(stmt.*)}), + else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), } } diff --git a/src/errors.zig b/src/errors.zig index 8de1442..201afb0 100644 --- a/src/errors.zig +++ b/src/errors.zig @@ -1,14 +1,14 @@ const std = @import("std"); pub fn report(line: usize, where: []const u8, message: []const u8) void { - std.debug.warn("[line {}] Error{}: {}", .{ line, where, message }); + std.debug.warn("[line {}] Error{}: {}", line, where, message); } pub fn reportN(line: usize, message: []const u8) void { report(line, "", message); } -pub fn reportFmt(line: usize, comptime fmt: []const u8, args: anytype) void { - std.debug.warn("[line {}] Error", .{line}); +pub fn reportFmt(line: usize, comptime fmt: []const u8, args: ...) void { + std.debug.warn("[line {}] Error", line); std.debug.warn(fmt, args); - std.debug.warn("\n", .{}); + std.debug.warn("\n"); } diff --git a/src/main.zig b/src/main.zig index f2c6156..bc07abc 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,16 +10,18 @@ pub const Result = error{ CompileError, }; -fn run(allocator: *Allocator, data: []const u8) !void { - var stdout_file = std.io.getStdOut(); - const stdout = stdout_file.outStream(); +pub const StdOut = *std.io.OutStream(std.fs.File.WriteError); + +fn run(allocator: *Allocator, data: []u8) !void { + var stdout_file = try std.io.getStdOut(); + const stdout = &stdout_file.outStream().stream; var runner = runners.Runner.init(allocator, stdout); return runner.execute(data); } fn runFile(allocator: *Allocator, path: []const u8) !void { - var file = try std.fs.cwd().openFile(path, .{}); + var file = try std.fs.File.openRead(path); defer file.close(); const total_bytes = try file.getEndPos(); @@ -37,32 +39,26 @@ fn runFile(allocator: *Allocator, path: []const u8) !void { } fn runPrompt(allocator: *Allocator) !void { - var stdout_file = std.io.getStdOut(); - const stdout = stdout_file.outStream(); - - var stdin_file = std.io.getStdIn(); - const stdin = stdin_file.inStream(); - - var line_buf: [1024]u8 = undefined; + var stdout_file = try std.io.getStdOut(); + const stdout = &stdout_file.outStream().stream; while (true) { - try stdout.print("> ", .{}); + try stdout.print("> "); + var buffer = try std.Buffer.init(allocator, ""[0..]); - const amt = try stdin.read(&line_buf); - if (amt == line_buf.len) { - try stdout.print("Input too long.\n", .{}); - continue; - } - const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n"); + var line = std.io.readLine(&buffer) catch |err| { + if (err == error.EndOfStream) return; + return err; + }; run(allocator, line) catch |err| { switch (err) { Result.Ok => {}, Result.ScannerError => blk: { - try stdout.print("scanner error.\n", .{}); + try stdout.print("scanner error.\n"); }, Result.CompileError => blk: { - try stdout.print("compile error.\n", .{}); + try stdout.print("compile error.\n"); }, else => return err, } @@ -71,12 +67,12 @@ fn runPrompt(allocator: *Allocator) !void { } pub fn main() anyerror!void { - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator); defer arena.deinit(); var allocator = &arena.allocator; - var stdout_file = std.io.getStdOut(); - var stdout = stdout_file.outStream(); + var stdout_file = try std.io.getStdOut(); + var stdout = &stdout_file.outStream().stream; var args_it = std.process.args(); diff --git a/src/parser.zig b/src/parser.zig index 00dd7c6..197b69f 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -43,27 +43,27 @@ pub const Parser = struct { self.tokens.deinit(); } - fn doError(self: *Parser, comptime fmt: []const u8, args: anytype) void { + fn doError(self: *Parser, comptime fmt: []const u8, args: ...) void { self.hadError = true; - 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("\n", .{}); + std.debug.warn("\n"); } fn peek(self: *Parser) Token { - return self.tokens.items[self.tokens.items.len - 1]; + return self.tokens.at(self.tokens.len - 1); } fn previous(self: *Parser) Token { - return self.tokens.items[self.tokens.items.len - 2]; + return self.tokens.at(self.tokens.len - 2); } 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 }); + err.reportFmt(token.line, " at '{}': {}", token.lexeme, msg); } return Result.CompileError; @@ -90,7 +90,7 @@ pub const Parser = struct { } try self.tokens.append(token); - std.debug.warn("skip to {}\n", .{token}); + std.debug.warn("skip to {}\n", token); return token; } @@ -117,17 +117,19 @@ pub const Parser = struct { // TODO maybe this could be entirely comptime? var buf_main: [1000]u8 = undefined; - var buf = try std.fmt.bufPrint(buf_main[0..], "expected {}, got {}", .{ + var buf = try std.fmt.bufPrint( + buf_main[0..], + "expected {}, got {}", ttype, self.peek().ttype, - }); + ); try self.tokenError(self.peek(), buf); return Result.CompileError; } /// check() against multiple tokens - fn compareAnyOf(self: *@This(), ttypes: []const TokenType) bool { + fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool { for (ttypes) |ttype| { if (self.check(ttype)) return true; } @@ -189,7 +191,7 @@ pub const Parser = struct { } fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr { - std.debug.warn("Unary\n", .{}); + std.debug.warn("Unary\n"); var expr = try self.allocator.create(Expr); expr.* = Expr{ @@ -607,7 +609,7 @@ pub const Parser = struct { .Enum => try self.parseEnumDecl(), else => |ttype| blk: { - self.doError("expected Fn, Const, Struct, got {}\n", .{ttype}); + self.doError("expected Fn, Const, Struct, got {}\n", ttype); return Result.CompileError; }, }; @@ -634,7 +636,6 @@ pub const Parser = struct { return switch (self.peek().ttype) { .If => try self.parseIfStmt(), .Loop => try self.parseLoop(), - .For => try self.parseForStmt(), .Println => try self.parsePrintln(), .Return => try self.parseReturn(), else => try self.parseStmtExpr(), @@ -674,42 +675,6 @@ pub const Parser = struct { ); } - fn parseForStmt(self: *@This()) !*Stmt { - // There are two types of for in vig's V subset: - // - for x in y - // - for idx, x in y - _ = try self.consumeSingle(.For); - - var index_var: ?Token = null; - var value_var: Token = undefined; - - const subject_1 = try self.consumeSingle(.Identifier); - - if (self.check(.Comma)) { - _ = try self.consumeSingle(.Comma); - - const subject_2 = try self.consumeSingle(.Identifier); - index_var = subject_1; - value_var = subject_2; - } else { - value_var = subject_1; - } - - _ = try self.consumeSingle(.In); - - // MUST be identifier - var array = try self.consumeSingle(.Identifier); - var block = try self.parseStmtBlock(); - - return try Stmt.mkFor( - self.allocator, - index_var, - value_var, - array, - block, - ); - } - fn parseLoop(self: *@This()) !*Stmt { _ = try self.consumeSingle(.Loop); var expr: ?*Expr = null; @@ -837,7 +802,7 @@ pub const Parser = struct { .Get => |get| { switch (op.ttype) { .ColonEqual => { - self.doError("can not initialize struct field", .{}); + self.doError("can not initialize struct field"); return Result.CompileError; }, @@ -857,7 +822,7 @@ pub const Parser = struct { }, else => |expr_typ| { - self.doError("Invalid assignment target {}", .{expr_typ}); + self.doError("Invalid assignment target {}", expr_typ); return Result.CompileError; }, } @@ -1027,8 +992,8 @@ pub const Parser = struct { fn finishStructVal(self: *@This(), expr: *Expr) !*Expr { // {a: 10 b: 10} // for this to work properly, must be Variable, since its a type. - if (@as(ast.ExprType, expr.*) != .Variable) { - self.doError("Expected variable for struct type, got {}", .{@as(ast.ExprType, expr.*)}); + if (ast.ExprType(expr.*) != .Variable) { + self.doError("Expected variable for struct type, got {}", ast.ExprType(expr.*)); return Result.CompileError; } @@ -1093,7 +1058,7 @@ pub const Parser = struct { }, else => blk: { - self.doError("expected literal, got {}", .{curtype}); + self.doError("expected literal, got {}", curtype); return Result.CompileError; }, }; diff --git a/src/runner.zig b/src/runner.zig index 34f2b7a..9c9f0f5 100644 --- a/src/runner.zig +++ b/src/runner.zig @@ -13,31 +13,32 @@ const Parser = parsers.Parser; pub const Runner = struct { allocator: *Allocator, - stdout: std.fs.File.OutStream, + stdout: main.StdOut, - pub fn init(allocator: *Allocator, stdout: anytype) Runner { - return .{ .allocator = allocator, .stdout = stdout }; + pub fn init(allocator: *Allocator, stdout: main.StdOut) Runner { + return Runner{ .allocator = allocator, .stdout = stdout }; } fn testScanner(self: *Runner, scanner: *scanners.Scanner) !void { while (true) { var tok_opt = scanner.nextToken() catch |err| { - try self.stdout.print("error at '{}': {}\n", .{ + try self.stdout.print( + "error at '{}': {}\n", scanner.currentLexeme(), err, - }); + ); return Result.ScannerError; }; if (tok_opt) |tok| { if (tok.ttype == .EOF) break; - try self.stdout.print("{x}\n", .{tok}); + try self.stdout.print("{x}\n", tok); } } } - pub fn execute(self: *Runner, code: []const u8) !void { + pub fn execute(self: *Runner, code: []u8) !void { var scanner = scanners.Scanner.init(self.allocator, code); try self.testScanner(&scanner); @@ -45,9 +46,9 @@ pub const Runner = struct { var parser = Parser.init(self.allocator, &scanner); var root = try parser.parse(); - // var it = root.Root.iterator(); + var it = root.Root.iterator(); - std.debug.warn("parse tree\n", .{}); + std.debug.warn("parse tree\n"); printer.printNode(root, 0); return Result.Ok; diff --git a/src/scanner.zig b/src/scanner.zig index 907dd48..0261a7a 100644 --- a/src/scanner.zig +++ b/src/scanner.zig @@ -97,13 +97,13 @@ fn getKeyword(keyword: []const u8) ?TokenType { /// Scanner for vlang tokens. pub const Scanner = struct { allocator: *Allocator, - source: []const u8, + source: []u8, start: usize = 0, current: usize = 0, line: usize = 1, - pub fn init(allocator: *Allocator, source: []const u8) Scanner { + pub fn init(allocator: *Allocator, source: []u8) Scanner { return Scanner{ .allocator = allocator, .source = source }; }