chore: bump zig version to 0.16.0

This commit is contained in:
Brett Broadhurst 2026-04-15 13:20:17 -06:00
parent 96866ba9ae
commit e004d00990
Failed to generate hash of commit
13 changed files with 171 additions and 113 deletions

View file

@ -121,18 +121,20 @@ fn buildExamples(
optimize: std.builtin.OptimizeMode, optimize: std.builtin.OptimizeMode,
c_lib_: ?*std.Build.Step.Compile, c_lib_: ?*std.Build.Step.Compile,
) ![]const *std.Build.Step.Compile { ) ![]const *std.Build.Step.Compile {
const alloc = b.allocator; const gpa = b.allocator;
var steps: std.ArrayList(*std.Build.Step.Compile) = .empty; const io = b.graph.io;
defer steps.deinit(alloc);
var dir = try std.fs.cwd().openDir(try b.build_root.join( var steps: std.ArrayList(*std.Build.Step.Compile) = .empty;
b.allocator, defer steps.deinit(gpa);
var dir = try std.Io.Dir.cwd().openDir(io, try b.build_root.join(
gpa,
&.{"examples"}, &.{"examples"},
), .{ .iterate = true }); ), .{ .iterate = true });
defer dir.close(); defer dir.close(io);
var it = dir.iterate(); var it = dir.iterate();
while (try it.next()) |entry| { while (try it.next(io)) |entry| {
const index = std.mem.lastIndexOfScalar(u8, entry.name, '.') orelse continue; const index = std.mem.lastIndexOfScalar(u8, entry.name, '.') orelse continue;
if (index == 0) continue; if (index == 0) continue;
@ -159,11 +161,11 @@ fn buildExamples(
.root_module = b.createModule(.{ .root_module = b.createModule(.{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
.link_libc = true,
}), }),
}); });
exe.linkLibC(); exe.root_module.addIncludePath(b.path("include"));
exe.addIncludePath(b.path("include")); exe.root_module.addCSourceFile(.{
exe.addCSourceFile(.{
.file = b.path(b.fmt( .file = b.path(b.fmt(
"examples/{s}", "examples/{s}",
.{entry.name}, .{entry.name},
@ -176,10 +178,10 @@ fn buildExamples(
"-D_POSIX_C_SOURCE=199309L", "-D_POSIX_C_SOURCE=199309L",
}, },
}); });
exe.linkLibrary(c_lib); exe.root_module.linkLibrary(c_lib);
break :exe exe; break :exe exe;
}; };
try steps.append(alloc, exe); try steps.append(gpa, exe);
} }
return steps.toOwnedSlice(alloc); return steps.toOwnedSlice(gpa);
} }

View file

@ -2,7 +2,7 @@
.name = .ink_zig, .name = .ink_zig,
.version = "0.0.0", .version = "0.0.0",
.fingerprint = 0xf2bf28592b4cdc24, .fingerprint = 0xf2bf28592b4cdc24,
.minimum_zig_version = "0.15.2", .minimum_zig_version = "0.16.0",
.dependencies = .{}, .dependencies = .{},
.paths = .{ .paths = .{
"build.zig", "build.zig",

View file

@ -4,8 +4,8 @@ const Ast = ink.Ast;
const Render = @This(); const Render = @This();
gpa: std.mem.Allocator, gpa: std.mem.Allocator,
tty_config: std.Io.tty.Config,
tree: *const Ast, tree: *const Ast,
terminal: std.Io.Terminal,
prefix: Prefix, prefix: Prefix,
lines: LineCache, lines: LineCache,
@ -147,43 +147,43 @@ const Prefix = struct {
fn writeType(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void { fn writeType(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
const tag = nodeTagToString(node.tag); const tag = nodeTagToString(node.tag);
try r.tty_config.setColor(writer, .magenta); try r.terminal.setColor(.magenta);
try r.tty_config.setColor(writer, .bold); try r.terminal.setColor(.bold);
try writer.writeAll(tag); try writer.writeAll(tag);
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
} }
fn writeLexeme(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void { fn writeLexeme(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("`{s}`", .{r.tree.nodeSlice(node)}); try writer.print("`{s}`", .{r.tree.nodeSlice(node)});
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
} }
fn writeLineSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void { fn writeLineSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
const line_start = r.lines.calculateLine(node.loc.start); const line_start = r.lines.calculateLine(node.loc.start);
const line_end = r.lines.calculateLine(node.loc.end); const line_end = r.lines.calculateLine(node.loc.end);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte('<'); try writer.writeByte('<');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("line:{d}", .{line_start + 1}); try writer.print("line:{d}", .{line_start + 1});
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte(','); try writer.writeByte(',');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try writer.writeByte(' '); try writer.writeByte(' ');
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("line:{d}", .{line_end + 1}); try writer.print("line:{d}", .{line_end + 1});
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte('>'); try writer.writeByte('>');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
} }
fn writeColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void { fn writeColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
@ -192,27 +192,27 @@ fn writeColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !v
const column_start = (node.loc.start - line_range.start); const column_start = (node.loc.start - line_range.start);
const column_end = (node.loc.end - line_range.start); const column_end = (node.loc.end - line_range.start);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte('<'); try writer.writeByte('<');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("col:{d}", .{column_start + 1}); try writer.print("col:{d}", .{column_start + 1});
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte(','); try writer.writeByte(',');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try writer.writeByte(' '); try writer.writeByte(' ');
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("col:{d}", .{column_end + 1}); try writer.print("col:{d}", .{column_end + 1});
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte('>'); try writer.writeByte('>');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
} }
fn writeLineColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void { fn writeLineColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
@ -221,26 +221,26 @@ fn writeLineColumnSpan(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node
const column_start = (node.loc.start - line_range.start); const column_start = (node.loc.start - line_range.start);
const column_end = (node.loc.end - line_range.start); const column_end = (node.loc.end - line_range.start);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte('<'); try writer.writeByte('<');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("line:{d}", .{line_start + 1}); try writer.print("line:{d}", .{line_start + 1});
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte(','); try writer.writeByte(',');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try writer.writeByte(' '); try writer.writeByte(' ');
try r.tty_config.setColor(writer, .yellow); try r.terminal.setColor(.yellow);
try writer.print("col:{d}:{d}", .{ column_start + 1, column_end + 1 }); try writer.print("col:{d}:{d}", .{ column_start + 1, column_end + 1 });
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
try r.tty_config.setColor(writer, .white); try r.terminal.setColor(.white);
try writer.writeByte('>'); try writer.writeByte('>');
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
} }
const NodeOptions = struct { const NodeOptions = struct {
@ -255,14 +255,14 @@ fn renderAstNode(
options: NodeOptions, options: NodeOptions,
) !void { ) !void {
if (!options.is_root) { if (!options.is_root) {
try r.tty_config.setColor(writer, .blue); try r.terminal.setColor(.blue);
try r.prefix.writeIndent(writer); try r.prefix.writeIndent(writer);
if (options.is_last) { if (options.is_last) {
try writer.writeAll("`--"); try writer.writeAll("`--");
} else { } else {
try writer.writeAll("|--"); try writer.writeAll("|--");
} }
try r.tty_config.setColor(writer, .reset); try r.terminal.setColor(.reset);
} }
try r.writeType(writer, node); try r.writeType(writer, node);
@ -473,7 +473,10 @@ pub fn renderTree(
var r: Render = .{ var r: Render = .{
.gpa = gpa, .gpa = gpa,
.tree = ast, .tree = ast,
.tty_config = if (options.use_color) .escape_codes else .no_color, .terminal = .{
.writer = writer,
.mode = if (options.use_color) .escape_codes else .no_color,
},
.prefix = .{}, .prefix = .{},
.lines = try LineCache.build(gpa, ast.source), .lines = try LineCache.build(gpa, ast.source),
}; };

View file

@ -748,7 +748,7 @@ fn stringExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.In
const result = switch (sub_node.tag) { const result = switch (sub_node.tag) {
.inline_logic_expr => try inlineLogicExpr(gi, scope, sub_node), .inline_logic_expr => try inlineLogicExpr(gi, scope, sub_node),
.string_literal => try stringLiteral(gi, sub_node), .string_literal => try stringLiteral(gi, sub_node),
inline else => |_| unreachable, inline else => unreachable,
}; };
try gi.astgen.scratch.append(gpa, @intFromEnum(result)); try gi.astgen.scratch.append(gpa, @intFromEnum(result));
} }
@ -803,7 +803,7 @@ fn expr(gi: *GenIr, scope: *Scope, optional_node: ?*const Ast.Node) InnerError!I
.logical_lesser_or_equal_expr => return binaryOp(gi, scope, node, .cmp_lte), .logical_lesser_or_equal_expr => return binaryOp(gi, scope, node, .cmp_lte),
.call_expr => return callExpr(gi, scope, node, .call), .call_expr => return callExpr(gi, scope, node, .call),
.selector_expr => return fieldAccess(gi, scope, node), .selector_expr => return fieldAccess(gi, scope, node),
inline else => |_| unreachable, inline else => unreachable,
} }
} }

View file

@ -734,15 +734,15 @@ fn irStore(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void
switch (lhs) { switch (lhs) {
.none => unreachable, .none => unreachable,
.stack => {}, .stack => {},
.value => |_| return sema.fail(src, "could not assign to constant value", .{}), .value => return sema.fail(src, "could not assign to constant value", .{}),
.variable => |index| { .variable => |index| {
const local_index = try builder.getOrPutConstantIndex(index); const local_index = try builder.getOrPutConstantIndex(index);
try builder.addConstOp(.store_global, @intCast(local_index)); try builder.addConstOp(.store_global, @intCast(local_index));
}, },
.temp => |temp| try builder.addConstOp(.store, @intCast(temp)), .temp => |temp| try builder.addConstOp(.store, @intCast(temp)),
.knot => |_| return sema.fail(src, "could not assign to knot", .{}), .knot => return sema.fail(src, "could not assign to knot", .{}),
.stitch => |_| return sema.fail(src, "could not assign to stitch", .{}), .stitch => return sema.fail(src, "could not assign to stitch", .{}),
.function => |_| return sema.fail(src, "could not assign to function", .{}), .function => return sema.fail(src, "could not assign to function", .{}),
} }
try builder.addByteOp(.pop); try builder.addByteOp(.pop);

View file

@ -282,15 +282,15 @@ pub fn dumpValue(_: Dumper, w: *std.Io.Writer, value: *const Value) !void {
"<{s}>", "<{s}>",
.{value.tagBytes()}, .{value.tagBytes()},
), ),
.bool => |_| try w.print( .bool => try w.print(
"<{s} value={f}>", "<{s} value={f}>",
.{ value.tagBytes(), value }, .{ value.tagBytes(), value },
), ),
.int => |_| try w.print( .int => try w.print(
"<{s} value={f}, address={*}>", "<{s} value={f}, address={*}>",
.{ value.tagBytes(), value, value }, .{ value.tagBytes(), value, value },
), ),
.float => |_| try w.print( .float => try w.print(
"<{s} value={f}, address={*}>", "<{s} value={f}, address={*}>",
.{ value.tagBytes(), value, value }, .{ value.tagBytes(), value, value },
), ),

View file

@ -44,22 +44,31 @@ pub fn eql(lhs: *Object, rhs: *Object) bool {
const rhs_object: *Object.String = @ptrCast(rhs); const rhs_object: *Object.String = @ptrCast(rhs);
break :blk std.mem.eql(u8, lhs_object.toSlice(), rhs_object.toSlice()); break :blk std.mem.eql(u8, lhs_object.toSlice(), rhs_object.toSlice());
}, },
.code => |_| false, .code => false,
.knot => |_| false, .knot => false,
.string_builder => |_| false, .string_builder => false,
}; };
} }
pub fn destroy(obj: *Object, story: *Story) void { pub fn destroy(obj: *Object, story: *Story) void {
inline for (comptime std.meta.fields(Tag)) |field| { switch (obj.tag) {
const tag = @field(Tag, field.name); .string => {
if (obj.tag == tag) { const typed_obj: *String = @alignCast(@fieldParentPtr("base", obj));
const typed_obj: *Tag.ObjectType(tag) = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story); typed_obj.destroy(story);
return; },
.code => {
const typed_obj: *Code = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story);
},
.knot => {
const typed_obj: *Knot = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story);
},
.string_builder => {
const typed_obj: *StringBuilder = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story);
},
} }
}
unreachable;
} }
pub const String = struct { pub const String = struct {
@ -96,9 +105,12 @@ pub const String = struct {
} }
pub fn destroy(obj: *String, story: *Story) void { pub fn destroy(obj: *String, story: *Story) void {
const alloc_len = @sizeOf(Type) + obj.length + 1;
const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj); const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj);
story.gpa.free(base[0..alloc_len]); story.gpa.free(base[0..allocLen(obj)]);
}
fn allocLen(obj: *String) usize {
return @sizeOf(Type) + obj.length + 1;
} }
pub fn toSlice(obj: *const Object.String) []const u8 { pub fn toSlice(obj: *const Object.String) []const u8 {
@ -184,7 +196,11 @@ pub const Code = struct {
gpa.free(obj.bytecode); gpa.free(obj.bytecode);
const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj); const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj);
gpa.free(base[0..@sizeOf(Type)]); gpa.free(base[0..allocLen(obj)]);
}
fn allocLen(_: *Code) usize {
return @sizeOf(Type);
} }
}; };
@ -225,9 +241,12 @@ pub const Knot = struct {
const gpa = story.gpa; const gpa = story.gpa;
obj.members.deinit(gpa); obj.members.deinit(gpa);
const alloc_len = @sizeOf(Type);
const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj); const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj);
gpa.free(base[0..alloc_len]); gpa.free(base[0..allocLen(obj)]);
}
fn allocLen(_: *Knot) usize {
return @sizeOf(Type);
} }
}; };
@ -251,9 +270,12 @@ pub const StringBuilder = struct {
pub fn destroy(obj: *StringBuilder, story: *Story) void { pub fn destroy(obj: *StringBuilder, story: *Story) void {
obj.inner.deinit(); obj.inner.deinit();
const alloc_len = @sizeOf(Type);
const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj); const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj);
story.gpa.free(base[0..alloc_len]); story.gpa.free(base[0..allocLen(obj)]);
}
fn allocLen(_: *StringBuilder) usize {
return @sizeOf(Type);
} }
pub fn append(obj: *StringBuilder, value: Story.Value) error{OutOfMemory}!void { pub fn append(obj: *StringBuilder, value: Story.Value) error{OutOfMemory}!void {

View file

@ -4,6 +4,8 @@ const ink = @import("../root.zig");
const Story = ink.Story; const Story = ink.Story;
const Compilation = ink.Compilation; const Compilation = ink.Compilation;
var threaded_io: std.Io.Threaded = .init_single_threaded;
test "fixture - variable arithmetic" { test "fixture - variable arithmetic" {
try testRuntimeFixture("variable-arithmetic"); try testRuntimeFixture("variable-arithmetic");
} }
@ -343,12 +345,13 @@ fn testRuntimeFixture(comptime fixture: []const u8) !void {
const input_bytes = @embedFile(test_root ++ fixture ++ "/input.txt"); const input_bytes = @embedFile(test_root ++ fixture ++ "/input.txt");
var stderr_buffer: [1024]u8 = undefined; var stderr_buffer: [1024]u8 = undefined;
const gpa = std.testing.allocator; const gpa = std.testing.allocator;
const stderr = std.fs.File.stderr(); const stderr = std.Io.File.stderr();
const io = threaded_io.io();
var io_r = std.Io.Reader.fixed(input_bytes); var io_r = std.Io.Reader.fixed(input_bytes);
var io_w = std.Io.Writer.Allocating.init(gpa); var io_w = std.Io.Writer.Allocating.init(gpa);
defer io_w.deinit(); defer io_w.deinit();
var stderr_writer = stderr.writer(&stderr_buffer); var stderr_writer = stderr.writer(io, &stderr_buffer);
try testRunner(gpa, source_bytes, .{ try testRunner(gpa, source_bytes, .{
.input_reader = &io_r, .input_reader = &io_r,

View file

@ -6,6 +6,7 @@ const Ast = ink.Ast;
const AstGen = ink.AstGen; const AstGen = ink.AstGen;
const Ir = ink.Ir; const Ir = ink.Ir;
var threaded_io: std.Io.Threaded = .init_single_threaded;
var global_allocator: std.heap.DebugAllocator(.{}) = .init; var global_allocator: std.heap.DebugAllocator(.{}) = .init;
var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined; var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
@ -75,12 +76,13 @@ fn loadStory(gpa: std.mem.Allocator, options: LoadStoryOptions) !*Story {
pub export fn ink_load_story_options( pub export fn ink_load_story_options(
options: *const InkLoadOpts, options: *const InkLoadOpts,
) callconv(.c) ?*Story { ) callconv(.c) ?*Story {
const io = threaded_io.io();
const gpa = global_allocator.allocator(); const gpa = global_allocator.allocator();
const source_bytes = options.source_bytes[0..options.source_length :0]; const source_bytes = options.source_bytes[0..options.source_length :0];
const filename = options.filename[0..options.filename_length :0]; const filename = options.filename[0..options.filename_length :0];
const stack_size = 128; const stack_size = 128;
const stderr = std.fs.File.stderr(); const stderr = std.Io.File.stderr();
var stderr_writer = stderr.writer(&stdout_buffer); var stderr_writer = stderr.writer(io, &stdout_buffer);
return loadStory(gpa, .{ return loadStory(gpa, .{
.filename = filename, .filename = filename,

View file

@ -168,7 +168,7 @@ fn testEqual(source_bytes: [:0]const u8, expected_error: []const u8) !void {
var arena_allocator = std.heap.ArenaAllocator.init(gpa); var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit(); defer arena_allocator.deinit();
var allocating = std.io.Writer.Allocating.init(gpa); var allocating = std.Io.Writer.Allocating.init(gpa);
defer allocating.deinit(); defer allocating.deinit();
const io_w = &allocating.writer; const io_w = &allocating.writer;

View file

@ -38,24 +38,19 @@ const FileExtension = enum {
inkc, inkc,
}; };
pub fn main() !void { pub fn main(init: std.process.Init) !void {
const gpa = debug_allocator.allocator(); const gpa = init.gpa;
defer _ = debug_allocator.deinit(); const io = init.io;
const arena = init.arena.allocator();
var arena_allocator = std.heap.ArenaAllocator.init(gpa); const args = try init.minimal.args.toSlice(arena);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const args = try std.process.argsAlloc(gpa);
defer std.process.argsFree(gpa, args);
if (args.len < 2) { if (args.len < 2) {
fatal("Not enough arguments!", .{}); fatal("Not enough arguments!", .{});
} }
return mainArgs(gpa, arena, args); return mainArgs(io, gpa, arena, args);
} }
fn mainArgs( fn mainArgs(
io: std.Io,
gpa: std.mem.Allocator, gpa: std.mem.Allocator,
arena: std.mem.Allocator, arena: std.mem.Allocator,
args_list: []const [:0]const u8, args_list: []const [:0]const u8,
@ -106,20 +101,20 @@ fn mainArgs(
const filename = source_path orelse "<STDIN>"; const filename = source_path orelse "<STDIN>";
const source_bytes: [:0]const u8 = s: { const source_bytes: [:0]const u8 = s: {
var f = if (source_path) |p| file: { var f = if (source_path) |p| file: {
break :file std.fs.cwd().openFile(p, .{}) catch |err| { break :file std.Io.Dir.cwd().openFile(io, p, .{}) catch |err| {
fatal("unable to open file '{s}': {s}", .{ p, @errorName(err) }); fatal("unable to open file '{s}': {s}", .{ p, @errorName(err) });
}; };
} else std.fs.File.stdin(); } else std.Io.File.stdin();
defer if (source_path != null) f.close(); defer if (source_path != null) f.close(io);
var file_reader: std.fs.File.Reader = f.reader(&stdin_buffer); var file_reader: std.Io.File.Reader = f.reader(io, &stdin_buffer);
break :s ink.readSourceFileToEndAlloc(arena, &file_reader) catch |err| { break :s ink.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
fatal("unable to load file '{s}': {s}", .{ filename, @errorName(err) }); fatal("unable to load file '{s}': {s}", .{ filename, @errorName(err) });
}; };
}; };
const stderr = std.fs.File.stderr(); const stderr = std.Io.File.stderr();
var stderr_writer = stderr.writer(&stderr_buffer); var stderr_writer = stderr.writer(io, &stderr_buffer);
const io_w = &stderr_writer.interface; const io_w = &stderr_writer.interface;
const stack_size = 128; const stack_size = 128;
@ -175,7 +170,7 @@ fn mainArgs(
if (dump_trace) { if (dump_trace) {
story.dump_writer = io_w; story.dump_writer = io_w;
} }
return if (!compile_only) run(gpa, &story); return if (!compile_only) run(io, gpa, &story);
} }
}, },
.inkc => { .inkc => {
@ -183,16 +178,16 @@ fn mainArgs(
.stack_size = stack_size, .stack_size = stack_size,
}); });
defer story.deinit(); defer story.deinit();
return if (!compile_only) run(gpa, &story); return if (!compile_only) run(io, gpa, &story);
}, },
} }
} }
fn run(_: std.mem.Allocator, story: *Story) !void { fn run(io: std.Io, _: std.mem.Allocator, story: *Story) !void {
const stdin = std.fs.File.stdin(); const stdin = std.Io.File.stdin();
var stdin_reader = stdin.reader(&stdin_buffer); var stdin_reader = stdin.reader(io, &stdin_buffer);
const stdout = std.fs.File.stdin(); const stdout = std.Io.File.stdin();
var stdout_writer = stdout.writer(&stdout_buffer); var stdout_writer = stdout.writer(io, &stdout_buffer);
const reader = &stdin_reader.interface; const reader = &stdin_reader.interface;
const writer = &stdout_writer.interface; const writer = &stdout_writer.interface;

View file

@ -280,7 +280,7 @@ fn testEqual(source_bytes: [:0]const u8, expected_ast: []const u8) !void {
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = arena_allocator.allocator(); const arena = arena_allocator.allocator();
var allocating = std.io.Writer.Allocating.init(gpa); var allocating = std.Io.Writer.Allocating.init(gpa);
defer allocating.deinit(); defer allocating.deinit();
const ast = try Ast.parse(gpa, arena, source_bytes, "<STDIN>", 0); const ast = try Ast.parse(gpa, arena, source_bytes, "<STDIN>", 0);

View file

@ -8,13 +8,44 @@ pub const Compilation = @import("compile.zig").Compilation;
pub const max_src_size = std.math.maxInt(u32); pub const max_src_size = std.math.maxInt(u32);
// std.zig.readSourceFileToEndAlloc leaks in 0.15.2.
// Use an arena allocator for now.
pub fn readSourceFileToEndAlloc( pub fn readSourceFileToEndAlloc(
gpa: std.mem.Allocator, gpa: std.mem.Allocator,
file_reader: *std.fs.File.Reader, file_reader: *std.Io.File.Reader,
) ![:0]u8 { ) ![:0]u8 {
return std.zig.readSourceFileToEndAlloc(gpa, file_reader); var buffer: std.ArrayList(u8) = .empty;
defer buffer.deinit(gpa);
if (file_reader.getSize()) |size| {
const casted_size = std.math.cast(u32, size) orelse return error.StreamTooLong;
// +1 to avoid resizing for the null byte added in toOwnedSliceSentinel below.
try buffer.ensureTotalCapacityPrecise(gpa, casted_size + 1);
} else |_| {}
try file_reader.interface.appendRemaining(gpa, &buffer, .limited(max_src_size));
// Detect unsupported file types with their Byte Order Mark
const unsupported_boms = [_][]const u8{
"\xff\xfe\x00\x00", // UTF-32 little endian
"\xfe\xff\x00\x00", // UTF-32 big endian
"\xfe\xff", // UTF-16 big endian
};
for (unsupported_boms) |bom| {
if (std.mem.startsWith(u8, buffer.items, bom)) {
return error.UnsupportedEncoding;
}
}
// If the file starts with a UTF-16 little endian BOM, translate it to UTF-8
if (std.mem.startsWith(u8, buffer.items, "\xff\xfe")) {
if (buffer.items.len % 2 != 0) return error.InvalidEncoding;
return std.unicode.utf16LeToUtf8AllocZ(gpa, @ptrCast(@alignCast(buffer.items))) catch |err| switch (err) {
error.DanglingSurrogateHalf => error.UnsupportedEncoding,
error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding,
error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding,
else => |e| return e,
};
}
return buffer.toOwnedSliceSentinel(gpa, 0);
} }
test { test {