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,
c_lib_: ?*std.Build.Step.Compile,
) ![]const *std.Build.Step.Compile {
const alloc = b.allocator;
var steps: std.ArrayList(*std.Build.Step.Compile) = .empty;
defer steps.deinit(alloc);
const gpa = b.allocator;
const io = b.graph.io;
var dir = try std.fs.cwd().openDir(try b.build_root.join(
b.allocator,
var steps: std.ArrayList(*std.Build.Step.Compile) = .empty;
defer steps.deinit(gpa);
var dir = try std.Io.Dir.cwd().openDir(io, try b.build_root.join(
gpa,
&.{"examples"},
), .{ .iterate = true });
defer dir.close();
defer dir.close(io);
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;
if (index == 0) continue;
@ -159,11 +161,11 @@ fn buildExamples(
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
exe.linkLibC();
exe.addIncludePath(b.path("include"));
exe.addCSourceFile(.{
exe.root_module.addIncludePath(b.path("include"));
exe.root_module.addCSourceFile(.{
.file = b.path(b.fmt(
"examples/{s}",
.{entry.name},
@ -176,10 +178,10 @@ fn buildExamples(
"-D_POSIX_C_SOURCE=199309L",
},
});
exe.linkLibrary(c_lib);
exe.root_module.linkLibrary(c_lib);
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,
.version = "0.0.0",
.fingerprint = 0xf2bf28592b4cdc24,
.minimum_zig_version = "0.15.2",
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{
"build.zig",

View file

@ -4,8 +4,8 @@ const Ast = ink.Ast;
const Render = @This();
gpa: std.mem.Allocator,
tty_config: std.Io.tty.Config,
tree: *const Ast,
terminal: std.Io.Terminal,
prefix: Prefix,
lines: LineCache,
@ -147,43 +147,43 @@ const Prefix = struct {
fn writeType(r: *Render, writer: *std.Io.Writer, node: *const Ast.Node) !void {
const tag = nodeTagToString(node.tag);
try r.tty_config.setColor(writer, .magenta);
try r.tty_config.setColor(writer, .bold);
try r.terminal.setColor(.magenta);
try r.terminal.setColor(.bold);
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 {
try r.tty_config.setColor(writer, .yellow);
try r.terminal.setColor(.yellow);
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 {
const line_start = r.lines.calculateLine(node.loc.start);
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 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 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 r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
try writer.writeByte(' ');
try r.tty_config.setColor(writer, .yellow);
try r.terminal.setColor(.yellow);
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 r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
}
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_end = (node.loc.end - line_range.start);
try r.tty_config.setColor(writer, .white);
try r.terminal.setColor(.white);
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 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 r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
try writer.writeByte(' ');
try r.tty_config.setColor(writer, .yellow);
try r.terminal.setColor(.yellow);
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 r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
}
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_end = (node.loc.end - line_range.start);
try r.tty_config.setColor(writer, .white);
try r.terminal.setColor(.white);
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 r.tty_config.setColor(writer, .white);
try r.terminal.setColor(.white);
try writer.writeByte(',');
try r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
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 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 r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
}
const NodeOptions = struct {
@ -255,14 +255,14 @@ fn renderAstNode(
options: NodeOptions,
) !void {
if (!options.is_root) {
try r.tty_config.setColor(writer, .blue);
try r.terminal.setColor(.blue);
try r.prefix.writeIndent(writer);
if (options.is_last) {
try writer.writeAll("`--");
} else {
try writer.writeAll("|--");
}
try r.tty_config.setColor(writer, .reset);
try r.terminal.setColor(.reset);
}
try r.writeType(writer, node);
@ -473,7 +473,10 @@ pub fn renderTree(
var r: Render = .{
.gpa = gpa,
.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 = .{},
.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) {
.inline_logic_expr => try inlineLogicExpr(gi, scope, sub_node),
.string_literal => try stringLiteral(gi, sub_node),
inline else => |_| unreachable,
inline else => unreachable,
};
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),
.call_expr => return callExpr(gi, scope, node, .call),
.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) {
.none => unreachable,
.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| {
const local_index = try builder.getOrPutConstantIndex(index);
try builder.addConstOp(.store_global, @intCast(local_index));
},
.temp => |temp| try builder.addConstOp(.store, @intCast(temp)),
.knot => |_| return sema.fail(src, "could not assign to knot", .{}),
.stitch => |_| return sema.fail(src, "could not assign to stitch", .{}),
.function => |_| return sema.fail(src, "could not assign to function", .{}),
.knot => return sema.fail(src, "could not assign to knot", .{}),
.stitch => return sema.fail(src, "could not assign to stitch", .{}),
.function => return sema.fail(src, "could not assign to function", .{}),
}
try builder.addByteOp(.pop);

View file

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

View file

@ -44,23 +44,32 @@ pub fn eql(lhs: *Object, rhs: *Object) bool {
const rhs_object: *Object.String = @ptrCast(rhs);
break :blk std.mem.eql(u8, lhs_object.toSlice(), rhs_object.toSlice());
},
.code => |_| false,
.knot => |_| false,
.string_builder => |_| false,
.code => false,
.knot => false,
.string_builder => false,
};
}
pub fn destroy(obj: *Object, story: *Story) void {
inline for (comptime std.meta.fields(Tag)) |field| {
const tag = @field(Tag, field.name);
if (obj.tag == tag) {
const typed_obj: *Tag.ObjectType(tag) = @alignCast(@fieldParentPtr("base", obj));
switch (obj.tag) {
.string => {
const typed_obj: *String = @alignCast(@fieldParentPtr("base", obj));
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 {
base: Object,
@ -96,9 +105,12 @@ pub const String = struct {
}
pub fn destroy(obj: *String, story: *Story) void {
const alloc_len = @sizeOf(Type) + obj.length + 1;
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 {
@ -184,7 +196,11 @@ pub const Code = struct {
gpa.free(obj.bytecode);
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;
obj.members.deinit(gpa);
const alloc_len = @sizeOf(Type);
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 {
obj.inner.deinit();
const alloc_len = @sizeOf(Type);
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 {

View file

@ -4,6 +4,8 @@ const ink = @import("../root.zig");
const Story = ink.Story;
const Compilation = ink.Compilation;
var threaded_io: std.Io.Threaded = .init_single_threaded;
test "fixture - 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");
var stderr_buffer: [1024]u8 = undefined;
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_w = std.Io.Writer.Allocating.init(gpa);
defer io_w.deinit();
var stderr_writer = stderr.writer(&stderr_buffer);
var stderr_writer = stderr.writer(io, &stderr_buffer);
try testRunner(gpa, source_bytes, .{
.input_reader = &io_r,

View file

@ -6,6 +6,7 @@ const Ast = ink.Ast;
const AstGen = ink.AstGen;
const Ir = ink.Ir;
var threaded_io: std.Io.Threaded = .init_single_threaded;
var global_allocator: std.heap.DebugAllocator(.{}) = .init;
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(
options: *const InkLoadOpts,
) callconv(.c) ?*Story {
const io = threaded_io.io();
const gpa = global_allocator.allocator();
const source_bytes = options.source_bytes[0..options.source_length :0];
const filename = options.filename[0..options.filename_length :0];
const stack_size = 128;
const stderr = std.fs.File.stderr();
var stderr_writer = stderr.writer(&stdout_buffer);
const stderr = std.Io.File.stderr();
var stderr_writer = stderr.writer(io, &stdout_buffer);
return loadStory(gpa, .{
.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);
defer arena_allocator.deinit();
var allocating = std.io.Writer.Allocating.init(gpa);
var allocating = std.Io.Writer.Allocating.init(gpa);
defer allocating.deinit();
const io_w = &allocating.writer;

View file

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