Compare commits

...

2 commits

Author SHA1 Message Date
c80f887597 update to latest zig 2020-07-23 16:38:26 -03:00
38f0b04351 updates for latest zig 2020-04-10 16:48:10 -03:00
6 changed files with 141 additions and 144 deletions

View file

@ -9,28 +9,28 @@ const warn = std.debug.warn;
fn printIdent(ident: usize) void { fn printIdent(ident: usize) void {
var i: usize = 0; var i: usize = 0;
while (i < ident) : (i += 1) { while (i < ident) : (i += 1) {
std.debug.warn("\t"); std.debug.warn("\t", .{});
} }
} }
fn print(ident: usize, comptime fmt: []const u8, args: ...) void { fn print(ident: usize, comptime fmt: []const u8, args: anytype) void {
printIdent(ident); printIdent(ident);
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
} }
fn printBlock(ident: usize, block: var, endNewline: bool) void { fn printBlock(ident: usize, block: anytype, endNewline: bool) void {
std.debug.warn("(\n"); std.debug.warn("(\n", .{});
for (block.toSlice()) |stmt| { for (block.items) |stmt| {
printIdent(ident); printIdent(ident);
printStmt(ident, stmt); printStmt(ident, stmt);
std.debug.warn("\n"); std.debug.warn("\n", .{});
} }
if (endNewline) { if (endNewline) {
print(ident - 1, ")\n"); print(ident - 1, ")\n", .{});
} else { } else {
print(ident - 1, ")"); print(ident - 1, ")", .{});
} }
} }
@ -48,55 +48,51 @@ pub fn printNode(node: *Node, ident: usize) void {
const typ = method.typ.lexeme; const typ = method.typ.lexeme;
if (method.mutable) { if (method.mutable) {
warn("(method mut {} {} {} {} ", vari, typ, name, ret_type); warn("(method mut {} {} {} {} ", .{ vari, typ, name, ret_type });
} else { } else {
warn("(method {} {} {} {} ", vari, typ, name, ret_type); warn("(method {} {} {} {} ", .{ vari, typ, name, ret_type });
} }
} else { } else {
warn("(fn {} {} (", name, ret_type); warn("(fn {} {} (", .{ name, ret_type });
} }
for (decl.params.toSlice()) |param| { for (decl.params.items) |param| {
warn("({} {}) ", param.name.lexeme, param.typ.lexeme); warn("({} {}) ", .{ param.name.lexeme, param.typ.lexeme });
} }
printBlock(ident + 1, decl.body, false); printBlock(ident + 1, decl.body, false);
warn(")\n"); warn(")\n", .{});
}, },
.ConstDecl => |consts| { .ConstDecl => |consts| {
print(ident, "(const (\n"); print(ident, "(const (\n", .{});
for (consts.toSlice()) |const_decl| { for (consts.items) |const_decl| {
print( print(ident + 1, "({} ", .{
ident + 1,
"({} ",
const_decl.name.lexeme, const_decl.name.lexeme,
); });
printExpr(const_decl.expr); printExpr(const_decl.expr);
std.debug.warn(")\n"); std.debug.warn(")\n", .{});
} }
print(ident, "))\n"); print(ident, "))\n", .{});
}, },
.Enum => |decl| { .Enum => |decl| {
print(ident, "(enum {} (\n", decl.name.lexeme); print(ident, "(enum {} (\n", .{decl.name.lexeme});
for (decl.fields.toSlice()) |field| { for (decl.fields.items) |field| {
print( print(ident + 1, "{}\n", .{
ident + 1,
"{}\n",
field.lexeme, field.lexeme,
); });
} }
print(ident, "))\n"); print(ident, "))\n", .{});
}, },
.Root => { .Root => {
for (node.Root.toSlice()) |child| { for (node.Root.items) |child| {
printNode(child, ident + 1); printNode(child, ident + 1);
} }
}, },
@ -104,129 +100,129 @@ pub fn printNode(node: *Node, ident: usize) void {
.Stmt => |stmt| { .Stmt => |stmt| {
printIdent(ident); printIdent(ident);
printStmt(ident, stmt); printStmt(ident, stmt);
std.debug.warn("\n"); std.debug.warn("\n", .{});
}, },
.Struct => |struc| { .Struct => |struc| {
print(ident, "(struct {} (\n", struc.name.lexeme); print(ident, "(struct {} (\n", .{struc.name.lexeme});
for (struc.fields.toSlice()) |field| { for (struc.fields.items) |field| {
printIdent(ident + 1); printIdent(ident + 1);
if (field.mutable) { if (field.mutable) {
std.debug.warn("(mut "); std.debug.warn("(mut ", .{});
} else { } else {
std.debug.warn("("); std.debug.warn("(", .{});
} }
if (field.public) { if (field.public) {
std.debug.warn("pub "); std.debug.warn("pub ", .{});
} }
if (field.mutable_outside) { 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 => { else => {
print(ident, "unknown node: {}\n", node); print(ident, "unknown node: {}\n", .{node});
}, },
} }
} }
fn parenthetize(name: []const u8, exprs: []*Expr) void { fn parenthetize(name: []const u8, exprs: []*const Expr) void {
std.debug.warn("({}", name); std.debug.warn("({}", .{name});
for (exprs) |expr| { for (exprs) |expr| {
std.debug.warn(" "); std.debug.warn(" ", .{});
printExpr(expr); printExpr(expr);
} }
std.debug.warn(")"); std.debug.warn(")", .{});
} }
pub fn printExpr(expr: *Expr) void { pub fn printExpr(expr: *const Expr) void {
switch (expr.*) { switch (expr.*) {
.Binary => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), .Binary => |binary| parenthetize(binary.op.lexeme, &[_]*const Expr{ binary.left, binary.right }),
.Logical => |binary| parenthetize(binary.op.lexeme, &[_]*Expr{ binary.left, binary.right }), .Logical => |binary| parenthetize(binary.op.lexeme, &[_]*const Expr{ binary.left, binary.right }),
.Unary => |unary| parenthetize(unary.op.lexeme, &[_]*Expr{unary.right}), .Unary => |unary| parenthetize(unary.op.lexeme, &[_]*const Expr{unary.right}),
.Grouping => |expr_ptr| parenthetize("group", &[_]*Expr{expr_ptr}), .Grouping => |expr_ptr| parenthetize("group", &[_]*const Expr{expr_ptr}),
.Literal => |literal| { .Literal => |literal| {
switch (literal) { switch (literal) {
.Bool => |val| std.debug.warn("{}", val), .Bool => |val| std.debug.warn("{}", .{val}),
.Integer => |val| std.debug.warn("{}", val), .Integer => |val| std.debug.warn("{}", .{val}),
.Float => |val| std.debug.warn("{}", val), .Float => |val| std.debug.warn("{}", .{val}),
.String => |val| std.debug.warn("'{}'", val), .String => |val| std.debug.warn("'{}'", .{val}),
.Array => |exprs| { .Array => |exprs| {
parenthetize("array", exprs.toSlice()); parenthetize("array", exprs.items);
}, },
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| { .VarDecl => |decl| {
if (decl.mutable) { if (decl.mutable) {
std.debug.warn("(mut "); std.debug.warn("(mut ", .{});
} else { } 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); printExpr(decl.assign.value);
std.debug.warn(")"); std.debug.warn(")", .{});
}, },
.Assign => |assign| { .Assign => |assign| {
std.debug.warn("(set "); std.debug.warn("(set ", .{});
std.debug.warn("{} ", assign.name.lexeme); std.debug.warn("{} ", .{assign.name.lexeme});
printExpr(assign.value); printExpr(assign.value);
std.debug.warn(")"); std.debug.warn(")", .{});
}, },
.Call => |call| { .Call => |call| {
std.debug.warn("("); std.debug.warn("(", .{});
printExpr(call.callee); printExpr(call.callee);
for (call.arguments.toSlice()) |arg| { for (call.arguments.items) |arg| {
std.debug.warn(" "); std.debug.warn(" ", .{});
printExpr(arg); printExpr(arg);
} }
std.debug.warn(")"); std.debug.warn(")", .{});
}, },
.Struct => |val| { .Struct => |val| {
std.debug.warn("({} (", val.name.lexeme); std.debug.warn("({} (", .{val.name.lexeme});
for (val.inits.toSlice()) |init| { for (val.inits.items) |init| {
std.debug.warn(" ({} ", init.field.lexeme); std.debug.warn(" ({} ", .{init.field.lexeme});
printExpr(init.expr); printExpr(init.expr);
std.debug.warn(")"); std.debug.warn(")", .{});
} }
std.debug.warn("))"); std.debug.warn("))", .{});
}, },
.Get => |get| { .Get => |get| {
warn("("); warn("(", .{});
printExpr(get.struc); printExpr(get.struc);
warn(".{})", get.name.lexeme); warn("{}", .{get.name.lexeme});
}, },
.Set => |set| { .Set => |set| {
warn("(set "); warn("(set ", .{});
printExpr(set.struc); printExpr(set.struc);
warn(" {} ", set.field.lexeme); warn(" {} ", .{set.field.lexeme});
printExpr(set.value); printExpr(set.value);
warn(")"); warn(")", .{});
}, },
else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), else => std.debug.warn("UnknownExpr-{}", .{@tagName(expr.*)}),
} }
} }
@ -236,53 +232,53 @@ pub fn printStmt(ident: usize, stmt: *Stmt) void {
.Expr => |expr| printExpr(expr), .Expr => |expr| printExpr(expr),
.If => |ifstmt| { .If => |ifstmt| {
std.debug.warn("(if "); std.debug.warn("(if ", .{});
printExpr(ifstmt.condition); printExpr(ifstmt.condition);
std.debug.warn(" "); std.debug.warn(" ", .{});
printBlock(ident + 1, ifstmt.then_branch, false); printBlock(ident + 1, ifstmt.then_branch, false);
if (ifstmt.else_branch) |else_branch| { if (ifstmt.else_branch) |else_branch| {
std.debug.warn(" else "); std.debug.warn(" else ", .{});
printBlock(ident + 1, else_branch, false); printBlock(ident + 1, else_branch, false);
} }
std.debug.warn(")\n"); std.debug.warn(")\n", .{});
}, },
.Loop => |loop| { .Loop => |loop| {
std.debug.warn("(loop "); std.debug.warn("(loop ", .{});
if (loop.condition) |cond| { if (loop.condition) |cond| {
printExpr(cond); printExpr(cond);
} else { } else {
std.debug.warn("true"); std.debug.warn("true", .{});
} }
std.debug.warn(" "); std.debug.warn(" ", .{});
printBlock(ident + 1, loop.then_branch, false); printBlock(ident + 1, loop.then_branch, false);
std.debug.warn(")\n"); std.debug.warn(")\n", .{});
}, },
.For => |forstmt| { .For => |forstmt| {
std.debug.warn("(for "); std.debug.warn("(for ", .{});
if (forstmt.index) |index| { if (forstmt.index) |index| {
std.debug.warn("({} {}) ", index.lexeme, forstmt.value.lexeme); std.debug.warn("({} {}) ", .{ index.lexeme, forstmt.value.lexeme });
} else { } else {
std.debug.warn("{} ", forstmt.value.lexeme); std.debug.warn("{} ", .{forstmt.value.lexeme});
} }
std.debug.warn("{} ", forstmt.array.lexeme); std.debug.warn("{} ", .{forstmt.array.lexeme});
printBlock(ident + 1, forstmt.block, false); printBlock(ident + 1, forstmt.block, false);
std.debug.warn(")\n"); std.debug.warn(")\n", .{});
}, },
.Return => |ret| { .Return => |ret| {
std.debug.warn("(return "); std.debug.warn("(return ", .{});
printExpr(ret.value); 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.*)}),
} }
} }

View file

@ -1,14 +1,14 @@
const std = @import("std"); const std = @import("std");
pub fn report(line: usize, where: []const u8, message: []const u8) void { 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 { pub fn reportN(line: usize, message: []const u8) void {
report(line, "", message); report(line, "", message);
} }
pub fn reportFmt(line: usize, comptime fmt: []const u8, args: ...) void { pub fn reportFmt(line: usize, comptime fmt: []const u8, args: anytype) void {
std.debug.warn("[line {}] Error", line); std.debug.warn("[line {}] Error", .{line});
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
std.debug.warn("\n"); std.debug.warn("\n", .{});
} }

View file

@ -10,18 +10,16 @@ pub const Result = error{
CompileError, CompileError,
}; };
pub const StdOut = *std.io.OutStream(std.fs.File.WriteError); fn run(allocator: *Allocator, data: []const u8) !void {
fn run(allocator: *Allocator, data: []u8) !void {
var stdout_file = std.io.getStdOut(); var stdout_file = std.io.getStdOut();
const stdout = &stdout_file.outStream().stream; const stdout = stdout_file.outStream();
var runner = runners.Runner.init(allocator, stdout); var runner = runners.Runner.init(allocator, stdout);
return runner.execute(data); return runner.execute(data);
} }
fn runFile(allocator: *Allocator, path: []const u8) !void { fn runFile(allocator: *Allocator, path: []const u8) !void {
var file = try std.fs.File.openRead(path); var file = try std.fs.cwd().openFile(path, .{});
defer file.close(); defer file.close();
const total_bytes = try file.getEndPos(); const total_bytes = try file.getEndPos();
@ -40,25 +38,31 @@ fn runFile(allocator: *Allocator, path: []const u8) !void {
fn runPrompt(allocator: *Allocator) !void { fn runPrompt(allocator: *Allocator) !void {
var stdout_file = std.io.getStdOut(); var stdout_file = std.io.getStdOut();
const stdout = &stdout_file.outStream().stream; const stdout = stdout_file.outStream();
var stdin_file = std.io.getStdIn();
const stdin = stdin_file.inStream();
var line_buf: [1024]u8 = undefined;
while (true) { while (true) {
try stdout.print("> "); try stdout.print("> ", .{});
var buffer = try std.Buffer.init(allocator, ""[0..]);
var line = std.io.readLine(&buffer) catch |err| { const amt = try stdin.read(&line_buf);
if (err == error.EndOfStream) return; if (amt == line_buf.len) {
return err; try stdout.print("Input too long.\n", .{});
}; continue;
}
const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n");
run(allocator, line) catch |err| { run(allocator, line) catch |err| {
switch (err) { switch (err) {
Result.Ok => {}, Result.Ok => {},
Result.ScannerError => blk: { Result.ScannerError => blk: {
try stdout.print("scanner error.\n"); try stdout.print("scanner error.\n", .{});
}, },
Result.CompileError => blk: { Result.CompileError => blk: {
try stdout.print("compile error.\n"); try stdout.print("compile error.\n", .{});
}, },
else => return err, else => return err,
} }
@ -67,12 +71,12 @@ fn runPrompt(allocator: *Allocator) !void {
} }
pub fn main() anyerror!void { pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); defer arena.deinit();
var allocator = &arena.allocator; var allocator = &arena.allocator;
var stdout_file = std.io.getStdOut(); var stdout_file = std.io.getStdOut();
var stdout = &stdout_file.outStream().stream; var stdout = stdout_file.outStream();
var args_it = std.process.args(); var args_it = std.process.args();

View file

@ -43,27 +43,27 @@ pub const Parser = struct {
self.tokens.deinit(); self.tokens.deinit();
} }
fn doError(self: *Parser, comptime fmt: []const u8, args: ...) void { fn doError(self: *Parser, comptime fmt: []const u8, args: anytype) void {
self.hadError = true; 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(fmt, args);
std.debug.warn("\n"); std.debug.warn("\n", .{});
} }
fn peek(self: *Parser) Token { fn peek(self: *Parser) Token {
return self.tokens.at(self.tokens.len - 1); return self.tokens.items[self.tokens.items.len - 1];
} }
fn previous(self: *Parser) Token { fn previous(self: *Parser) Token {
return self.tokens.at(self.tokens.len - 2); return self.tokens.items[self.tokens.items.len - 2];
} }
fn tokenError(self: *Parser, token: Token, msg: []const u8) Result!void { fn tokenError(self: *Parser, token: Token, msg: []const u8) Result!void {
if (token.ttype == .EOF) { if (token.ttype == .EOF) {
err.report(token.line, " at end", msg); err.report(token.line, " at end", msg);
} else { } else {
err.reportFmt(token.line, " at '{}': {}", token.lexeme, msg); err.reportFmt(token.line, " at '{}': {}", .{ token.lexeme, msg });
} }
return Result.CompileError; return Result.CompileError;
@ -90,7 +90,7 @@ pub const Parser = struct {
} }
try self.tokens.append(token); try self.tokens.append(token);
std.debug.warn("skip to {}\n", token); std.debug.warn("skip to {}\n", .{token});
return token; return token;
} }
@ -117,19 +117,17 @@ pub const Parser = struct {
// TODO maybe this could be entirely comptime? // TODO maybe this could be entirely comptime?
var buf_main: [1000]u8 = undefined; var buf_main: [1000]u8 = undefined;
var buf = try std.fmt.bufPrint( var buf = try std.fmt.bufPrint(buf_main[0..], "expected {}, got {}", .{
buf_main[0..],
"expected {}, got {}",
ttype, ttype,
self.peek().ttype, self.peek().ttype,
); });
try self.tokenError(self.peek(), buf); try self.tokenError(self.peek(), buf);
return Result.CompileError; return Result.CompileError;
} }
/// check() against multiple tokens /// check() against multiple tokens
fn compareAnyOf(self: *@This(), ttypes: []TokenType) bool { fn compareAnyOf(self: *@This(), ttypes: []const TokenType) bool {
for (ttypes) |ttype| { for (ttypes) |ttype| {
if (self.check(ttype)) return true; if (self.check(ttype)) return true;
} }
@ -191,7 +189,7 @@ pub const Parser = struct {
} }
fn mkUnary(self: *Parser, op: Token, right: *Expr) !*Expr { 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); var expr = try self.allocator.create(Expr);
expr.* = Expr{ expr.* = Expr{
@ -609,7 +607,7 @@ pub const Parser = struct {
.Enum => try self.parseEnumDecl(), .Enum => try self.parseEnumDecl(),
else => |ttype| blk: { else => |ttype| blk: {
self.doError("expected Fn, Const, Struct, got {}\n", ttype); self.doError("expected Fn, Const, Struct, got {}\n", .{ttype});
return Result.CompileError; return Result.CompileError;
}, },
}; };
@ -839,7 +837,7 @@ pub const Parser = struct {
.Get => |get| { .Get => |get| {
switch (op.ttype) { switch (op.ttype) {
.ColonEqual => { .ColonEqual => {
self.doError("can not initialize struct field"); self.doError("can not initialize struct field", .{});
return Result.CompileError; return Result.CompileError;
}, },
@ -859,7 +857,7 @@ pub const Parser = struct {
}, },
else => |expr_typ| { else => |expr_typ| {
self.doError("Invalid assignment target {}", expr_typ); self.doError("Invalid assignment target {}", .{expr_typ});
return Result.CompileError; return Result.CompileError;
}, },
} }
@ -1030,7 +1028,7 @@ pub const Parser = struct {
// <expr>{a: 10 b: 10} // <expr>{a: 10 b: 10}
// for this to work properly, <expr> must be Variable, since its a type. // for this to work properly, <expr> must be Variable, since its a type.
if (@as(ast.ExprType, expr.*) != .Variable) { if (@as(ast.ExprType, expr.*) != .Variable) {
self.doError("Expected variable for struct type, got {}", @as(ast.ExprType, expr.*)); self.doError("Expected variable for struct type, got {}", .{@as(ast.ExprType, expr.*)});
return Result.CompileError; return Result.CompileError;
} }
@ -1095,7 +1093,7 @@ pub const Parser = struct {
}, },
else => blk: { else => blk: {
self.doError("expected literal, got {}", curtype); self.doError("expected literal, got {}", .{curtype});
return Result.CompileError; return Result.CompileError;
}, },
}; };

View file

@ -13,32 +13,31 @@ const Parser = parsers.Parser;
pub const Runner = struct { pub const Runner = struct {
allocator: *Allocator, allocator: *Allocator,
stdout: main.StdOut, stdout: std.fs.File.OutStream,
pub fn init(allocator: *Allocator, stdout: main.StdOut) Runner { pub fn init(allocator: *Allocator, stdout: anytype) Runner {
return Runner{ .allocator = allocator, .stdout = stdout }; return .{ .allocator = allocator, .stdout = stdout };
} }
fn testScanner(self: *Runner, scanner: *scanners.Scanner) !void { fn testScanner(self: *Runner, scanner: *scanners.Scanner) !void {
while (true) { while (true) {
var tok_opt = scanner.nextToken() catch |err| { var tok_opt = scanner.nextToken() catch |err| {
try self.stdout.print( try self.stdout.print("error at '{}': {}\n", .{
"error at '{}': {}\n",
scanner.currentLexeme(), scanner.currentLexeme(),
err, err,
); });
return Result.ScannerError; return Result.ScannerError;
}; };
if (tok_opt) |tok| { if (tok_opt) |tok| {
if (tok.ttype == .EOF) break; 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: []u8) !void { pub fn execute(self: *Runner, code: []const u8) !void {
var scanner = scanners.Scanner.init(self.allocator, code); var scanner = scanners.Scanner.init(self.allocator, code);
try self.testScanner(&scanner); try self.testScanner(&scanner);
@ -46,9 +45,9 @@ pub const Runner = struct {
var parser = Parser.init(self.allocator, &scanner); var parser = Parser.init(self.allocator, &scanner);
var root = try parser.parse(); 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); printer.printNode(root, 0);
return Result.Ok; return Result.Ok;

View file

@ -97,13 +97,13 @@ fn getKeyword(keyword: []const u8) ?TokenType {
/// Scanner for vlang tokens. /// Scanner for vlang tokens.
pub const Scanner = struct { pub const Scanner = struct {
allocator: *Allocator, allocator: *Allocator,
source: []u8, source: []const u8,
start: usize = 0, start: usize = 0,
current: usize = 0, current: usize = 0,
line: usize = 1, line: usize = 1,
pub fn init(allocator: *Allocator, source: []u8) Scanner { pub fn init(allocator: *Allocator, source: []const u8) Scanner {
return Scanner{ .allocator = allocator, .source = source }; return Scanner{ .allocator = allocator, .source = source };
} }