mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
compiler,std: implement ZON support
This commit allows using ZON (Zig Object Notation) in a few ways. * `@import` can be used to load ZON at comptime and convert it to a normal Zig value. In this case, `@import` must have a result type. * `std.zon.parse` can be used to parse ZON at runtime, akin to the parsing logic in `std.json`. * `std.zon.stringify` can be used to convert arbitrary data structures to ZON at runtime, again akin to `std.json`.
This commit is contained in:
parent
953355ebea
commit
13c6eb0d71
@ -406,7 +406,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index];
|
const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index];
|
||||||
|
|
||||||
const fmt_include_paths = &.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" };
|
const fmt_include_paths = &.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" };
|
||||||
const fmt_exclude_paths = &.{"test/cases"};
|
const fmt_exclude_paths = &.{ "test/cases", "test/behavior/zon" };
|
||||||
const do_fmt = b.addFmt(.{
|
const do_fmt = b.addFmt(.{
|
||||||
.paths = fmt_include_paths,
|
.paths = fmt_include_paths,
|
||||||
.exclude_paths = fmt_exclude_paths,
|
.exclude_paths = fmt_exclude_paths,
|
||||||
|
|||||||
2
lib/compiler/aro/aro/Value.zig
vendored
2
lib/compiler/aro/aro/Value.zig
vendored
@ -473,7 +473,7 @@ pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {
|
|||||||
if (comp.interner.get(v.ref()) != .int) return null;
|
if (comp.interner.get(v.ref()) != .int) return null;
|
||||||
var space: BigIntSpace = undefined;
|
var space: BigIntSpace = undefined;
|
||||||
const big_int = v.toBigInt(&space, comp);
|
const big_int = v.toBigInt(&space, comp);
|
||||||
return big_int.to(T) catch null;
|
return big_int.toInt(T) catch null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComplexOp = enum {
|
const ComplexOp = enum {
|
||||||
|
|||||||
4
lib/compiler/aro/backend/Interner.zig
vendored
4
lib/compiler/aro/backend/Interner.zig
vendored
@ -628,13 +628,13 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
|
|||||||
if (data.fitsInTwosComp(.unsigned, 32)) {
|
if (data.fitsInTwosComp(.unsigned, 32)) {
|
||||||
i.items.appendAssumeCapacity(.{
|
i.items.appendAssumeCapacity(.{
|
||||||
.tag = .u32,
|
.tag = .u32,
|
||||||
.data = data.to(u32) catch unreachable,
|
.data = data.toInt(u32) catch unreachable,
|
||||||
});
|
});
|
||||||
break :int;
|
break :int;
|
||||||
} else if (data.fitsInTwosComp(.signed, 32)) {
|
} else if (data.fitsInTwosComp(.signed, 32)) {
|
||||||
i.items.appendAssumeCapacity(.{
|
i.items.appendAssumeCapacity(.{
|
||||||
.tag = .i32,
|
.tag = .i32,
|
||||||
.data = @bitCast(data.to(i32) catch unreachable),
|
.data = @bitCast(data.toInt(i32) catch unreachable),
|
||||||
});
|
});
|
||||||
break :int;
|
break :int;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2175,10 +2175,13 @@ pub const Const = struct {
|
|||||||
TargetTooSmall,
|
TargetTooSmall,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Convert self to type T.
|
/// Deprecated; use `toInt`.
|
||||||
|
pub const to = toInt;
|
||||||
|
|
||||||
|
/// Convert self to integer type T.
|
||||||
///
|
///
|
||||||
/// Returns an error if self cannot be narrowed into the requested type without truncation.
|
/// Returns an error if self cannot be narrowed into the requested type without truncation.
|
||||||
pub fn to(self: Const, comptime T: type) ConvertError!T {
|
pub fn toInt(self: Const, comptime T: type) ConvertError!T {
|
||||||
switch (@typeInfo(T)) {
|
switch (@typeInfo(T)) {
|
||||||
.int => |info| {
|
.int => |info| {
|
||||||
// Make sure -0 is handled correctly.
|
// Make sure -0 is handled correctly.
|
||||||
@ -2216,7 +2219,26 @@ pub const Const = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => @compileError("cannot convert Const to type " ++ @typeName(T)),
|
else => @compileError("expected int type, found '" ++ @typeName(T) ++ "'"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert self to float type T.
|
||||||
|
pub fn toFloat(self: Const, comptime T: type) T {
|
||||||
|
if (self.limbs.len == 0) return 0;
|
||||||
|
|
||||||
|
const base = std.math.maxInt(std.math.big.Limb) + 1;
|
||||||
|
var result: f128 = 0;
|
||||||
|
var i: usize = self.limbs.len;
|
||||||
|
while (i != 0) {
|
||||||
|
i -= 1;
|
||||||
|
const limb: f128 = @floatFromInt(self.limbs[i]);
|
||||||
|
result = @mulAdd(f128, base, result, limb);
|
||||||
|
}
|
||||||
|
if (self.positive) {
|
||||||
|
return @floatCast(result);
|
||||||
|
} else {
|
||||||
|
return @floatCast(-result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2775,11 +2797,19 @@ pub const Managed = struct {
|
|||||||
|
|
||||||
pub const ConvertError = Const.ConvertError;
|
pub const ConvertError = Const.ConvertError;
|
||||||
|
|
||||||
/// Convert self to type T.
|
/// Deprecated; use `toInt`.
|
||||||
|
pub const to = toInt;
|
||||||
|
|
||||||
|
/// Convert self to integer type T.
|
||||||
///
|
///
|
||||||
/// Returns an error if self cannot be narrowed into the requested type without truncation.
|
/// Returns an error if self cannot be narrowed into the requested type without truncation.
|
||||||
pub fn to(self: Managed, comptime T: type) ConvertError!T {
|
pub fn toInt(self: Managed, comptime T: type) ConvertError!T {
|
||||||
return self.toConst().to(T);
|
return self.toConst().toInt(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert self to float type T.
|
||||||
|
pub fn toFloat(self: Managed, comptime T: type) T {
|
||||||
|
return self.toConst().toFloat(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set self from the string representation `value`.
|
/// Set self from the string representation `value`.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -518,28 +518,28 @@ test "set" {
|
|||||||
defer a.deinit();
|
defer a.deinit();
|
||||||
|
|
||||||
try a.setInt(5);
|
try a.setInt(5);
|
||||||
try testing.expect((try a.p.to(u32)) == 5);
|
try testing.expect((try a.p.toInt(u32)) == 5);
|
||||||
try testing.expect((try a.q.to(u32)) == 1);
|
try testing.expect((try a.q.toInt(u32)) == 1);
|
||||||
|
|
||||||
try a.setRatio(7, 3);
|
try a.setRatio(7, 3);
|
||||||
try testing.expect((try a.p.to(u32)) == 7);
|
try testing.expect((try a.p.toInt(u32)) == 7);
|
||||||
try testing.expect((try a.q.to(u32)) == 3);
|
try testing.expect((try a.q.toInt(u32)) == 3);
|
||||||
|
|
||||||
try a.setRatio(9, 3);
|
try a.setRatio(9, 3);
|
||||||
try testing.expect((try a.p.to(i32)) == 3);
|
try testing.expect((try a.p.toInt(i32)) == 3);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
try a.setRatio(-9, 3);
|
try a.setRatio(-9, 3);
|
||||||
try testing.expect((try a.p.to(i32)) == -3);
|
try testing.expect((try a.p.toInt(i32)) == -3);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
try a.setRatio(9, -3);
|
try a.setRatio(9, -3);
|
||||||
try testing.expect((try a.p.to(i32)) == -3);
|
try testing.expect((try a.p.toInt(i32)) == -3);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
try a.setRatio(-9, -3);
|
try a.setRatio(-9, -3);
|
||||||
try testing.expect((try a.p.to(i32)) == 3);
|
try testing.expect((try a.p.toInt(i32)) == 3);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "setFloat" {
|
test "setFloat" {
|
||||||
@ -547,24 +547,24 @@ test "setFloat" {
|
|||||||
defer a.deinit();
|
defer a.deinit();
|
||||||
|
|
||||||
try a.setFloat(f64, 2.5);
|
try a.setFloat(f64, 2.5);
|
||||||
try testing.expect((try a.p.to(i32)) == 5);
|
try testing.expect((try a.p.toInt(i32)) == 5);
|
||||||
try testing.expect((try a.q.to(i32)) == 2);
|
try testing.expect((try a.q.toInt(i32)) == 2);
|
||||||
|
|
||||||
try a.setFloat(f32, -2.5);
|
try a.setFloat(f32, -2.5);
|
||||||
try testing.expect((try a.p.to(i32)) == -5);
|
try testing.expect((try a.p.toInt(i32)) == -5);
|
||||||
try testing.expect((try a.q.to(i32)) == 2);
|
try testing.expect((try a.q.toInt(i32)) == 2);
|
||||||
|
|
||||||
try a.setFloat(f32, 3.141593);
|
try a.setFloat(f32, 3.141593);
|
||||||
|
|
||||||
// = 3.14159297943115234375
|
// = 3.14159297943115234375
|
||||||
try testing.expect((try a.p.to(u32)) == 3294199);
|
try testing.expect((try a.p.toInt(u32)) == 3294199);
|
||||||
try testing.expect((try a.q.to(u32)) == 1048576);
|
try testing.expect((try a.q.toInt(u32)) == 1048576);
|
||||||
|
|
||||||
try a.setFloat(f64, 72.141593120712409172417410926841290461290467124);
|
try a.setFloat(f64, 72.141593120712409172417410926841290461290467124);
|
||||||
|
|
||||||
// = 72.1415931207124145885245525278151035308837890625
|
// = 72.1415931207124145885245525278151035308837890625
|
||||||
try testing.expect((try a.p.to(u128)) == 5076513310880537);
|
try testing.expect((try a.p.toInt(u128)) == 5076513310880537);
|
||||||
try testing.expect((try a.q.to(u128)) == 70368744177664);
|
try testing.expect((try a.q.toInt(u128)) == 70368744177664);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "setFloatString" {
|
test "setFloatString" {
|
||||||
@ -574,8 +574,8 @@ test "setFloatString" {
|
|||||||
try a.setFloatString("72.14159312071241458852455252781510353");
|
try a.setFloatString("72.14159312071241458852455252781510353");
|
||||||
|
|
||||||
// = 72.1415931207124145885245525278151035308837890625
|
// = 72.1415931207124145885245525278151035308837890625
|
||||||
try testing.expect((try a.p.to(u128)) == 7214159312071241458852455252781510353);
|
try testing.expect((try a.p.toInt(u128)) == 7214159312071241458852455252781510353);
|
||||||
try testing.expect((try a.q.to(u128)) == 100000000000000000000000000000000000);
|
try testing.expect((try a.q.toInt(u128)) == 100000000000000000000000000000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "toFloat" {
|
test "toFloat" {
|
||||||
@ -612,8 +612,8 @@ test "copy" {
|
|||||||
defer b.deinit();
|
defer b.deinit();
|
||||||
|
|
||||||
try a.copyInt(b);
|
try a.copyInt(b);
|
||||||
try testing.expect((try a.p.to(u32)) == 5);
|
try testing.expect((try a.p.toInt(u32)) == 5);
|
||||||
try testing.expect((try a.q.to(u32)) == 1);
|
try testing.expect((try a.q.toInt(u32)) == 1);
|
||||||
|
|
||||||
var c = try Int.initSet(testing.allocator, 7);
|
var c = try Int.initSet(testing.allocator, 7);
|
||||||
defer c.deinit();
|
defer c.deinit();
|
||||||
@ -621,8 +621,8 @@ test "copy" {
|
|||||||
defer d.deinit();
|
defer d.deinit();
|
||||||
|
|
||||||
try a.copyRatio(c, d);
|
try a.copyRatio(c, d);
|
||||||
try testing.expect((try a.p.to(u32)) == 7);
|
try testing.expect((try a.p.toInt(u32)) == 7);
|
||||||
try testing.expect((try a.q.to(u32)) == 3);
|
try testing.expect((try a.q.toInt(u32)) == 3);
|
||||||
|
|
||||||
var e = try Int.initSet(testing.allocator, 9);
|
var e = try Int.initSet(testing.allocator, 9);
|
||||||
defer e.deinit();
|
defer e.deinit();
|
||||||
@ -630,8 +630,8 @@ test "copy" {
|
|||||||
defer f.deinit();
|
defer f.deinit();
|
||||||
|
|
||||||
try a.copyRatio(e, f);
|
try a.copyRatio(e, f);
|
||||||
try testing.expect((try a.p.to(u32)) == 3);
|
try testing.expect((try a.p.toInt(u32)) == 3);
|
||||||
try testing.expect((try a.q.to(u32)) == 1);
|
try testing.expect((try a.q.toInt(u32)) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "negate" {
|
test "negate" {
|
||||||
@ -639,16 +639,16 @@ test "negate" {
|
|||||||
defer a.deinit();
|
defer a.deinit();
|
||||||
|
|
||||||
try a.setInt(-50);
|
try a.setInt(-50);
|
||||||
try testing.expect((try a.p.to(i32)) == -50);
|
try testing.expect((try a.p.toInt(i32)) == -50);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
a.negate();
|
a.negate();
|
||||||
try testing.expect((try a.p.to(i32)) == 50);
|
try testing.expect((try a.p.toInt(i32)) == 50);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
a.negate();
|
a.negate();
|
||||||
try testing.expect((try a.p.to(i32)) == -50);
|
try testing.expect((try a.p.toInt(i32)) == -50);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "abs" {
|
test "abs" {
|
||||||
@ -656,16 +656,16 @@ test "abs" {
|
|||||||
defer a.deinit();
|
defer a.deinit();
|
||||||
|
|
||||||
try a.setInt(-50);
|
try a.setInt(-50);
|
||||||
try testing.expect((try a.p.to(i32)) == -50);
|
try testing.expect((try a.p.toInt(i32)) == -50);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
a.abs();
|
a.abs();
|
||||||
try testing.expect((try a.p.to(i32)) == 50);
|
try testing.expect((try a.p.toInt(i32)) == 50);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
|
|
||||||
a.abs();
|
a.abs();
|
||||||
try testing.expect((try a.p.to(i32)) == 50);
|
try testing.expect((try a.p.toInt(i32)) == 50);
|
||||||
try testing.expect((try a.q.to(i32)) == 1);
|
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "swap" {
|
test "swap" {
|
||||||
@ -677,19 +677,19 @@ test "swap" {
|
|||||||
try a.setRatio(50, 23);
|
try a.setRatio(50, 23);
|
||||||
try b.setRatio(17, 3);
|
try b.setRatio(17, 3);
|
||||||
|
|
||||||
try testing.expect((try a.p.to(u32)) == 50);
|
try testing.expect((try a.p.toInt(u32)) == 50);
|
||||||
try testing.expect((try a.q.to(u32)) == 23);
|
try testing.expect((try a.q.toInt(u32)) == 23);
|
||||||
|
|
||||||
try testing.expect((try b.p.to(u32)) == 17);
|
try testing.expect((try b.p.toInt(u32)) == 17);
|
||||||
try testing.expect((try b.q.to(u32)) == 3);
|
try testing.expect((try b.q.toInt(u32)) == 3);
|
||||||
|
|
||||||
a.swap(&b);
|
a.swap(&b);
|
||||||
|
|
||||||
try testing.expect((try a.p.to(u32)) == 17);
|
try testing.expect((try a.p.toInt(u32)) == 17);
|
||||||
try testing.expect((try a.q.to(u32)) == 3);
|
try testing.expect((try a.q.toInt(u32)) == 3);
|
||||||
|
|
||||||
try testing.expect((try b.p.to(u32)) == 50);
|
try testing.expect((try b.p.toInt(u32)) == 50);
|
||||||
try testing.expect((try b.q.to(u32)) == 23);
|
try testing.expect((try b.q.toInt(u32)) == 23);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "order" {
|
test "order" {
|
||||||
|
|||||||
@ -93,6 +93,7 @@ pub const valgrind = @import("valgrind.zig");
|
|||||||
pub const wasm = @import("wasm.zig");
|
pub const wasm = @import("wasm.zig");
|
||||||
pub const zig = @import("zig.zig");
|
pub const zig = @import("zig.zig");
|
||||||
pub const zip = @import("zip.zig");
|
pub const zip = @import("zip.zig");
|
||||||
|
pub const zon = @import("zon.zig");
|
||||||
pub const start = @import("start.zig");
|
pub const start = @import("start.zig");
|
||||||
|
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
|||||||
@ -9448,7 +9448,18 @@ fn builtinCall(
|
|||||||
} else if (str.len == 0) {
|
} else if (str.len == 0) {
|
||||||
return astgen.failTok(str_lit_token, "import path cannot be empty", .{});
|
return astgen.failTok(str_lit_token, "import path cannot be empty", .{});
|
||||||
}
|
}
|
||||||
const result = try gz.addStrTok(.import, str.index, str_lit_token);
|
const res_ty = try ri.rl.resultType(gz, node) orelse .none;
|
||||||
|
const payload_index = try addExtra(gz.astgen, Zir.Inst.Import{
|
||||||
|
.res_ty = res_ty,
|
||||||
|
.path = str.index,
|
||||||
|
});
|
||||||
|
const result = try gz.add(.{
|
||||||
|
.tag = .import,
|
||||||
|
.data = .{ .pl_tok = .{
|
||||||
|
.src_tok = gz.tokenIndexToRelative(str_lit_token),
|
||||||
|
.payload_index = payload_index,
|
||||||
|
} },
|
||||||
|
});
|
||||||
const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
|
const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
|
||||||
if (!gop.found_existing) {
|
if (!gop.found_existing) {
|
||||||
gop.value_ptr.* = str_lit_token;
|
gop.value_ptr.* = str_lit_token;
|
||||||
@ -11551,9 +11562,21 @@ fn parseStrLit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn failWithStrLitError(astgen: *AstGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, bytes: []const u8, offset: u32) InnerError {
|
fn failWithStrLitError(
|
||||||
|
astgen: *AstGen,
|
||||||
|
err: std.zig.string_literal.Error,
|
||||||
|
token: Ast.TokenIndex,
|
||||||
|
bytes: []const u8,
|
||||||
|
offset: u32,
|
||||||
|
) InnerError {
|
||||||
const raw_string = bytes[offset..];
|
const raw_string = bytes[offset..];
|
||||||
return err.lower(raw_string, offset, AstGen.failOff, .{ astgen, token });
|
return failOff(
|
||||||
|
astgen,
|
||||||
|
token,
|
||||||
|
@intCast(offset + err.offset()),
|
||||||
|
"{}",
|
||||||
|
.{err.fmt(raw_string)},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn failNode(
|
fn failNode(
|
||||||
|
|||||||
@ -483,7 +483,7 @@ pub const Inst = struct {
|
|||||||
/// Uses the `pl_node` union field. `payload_index` points to a `FuncFancy`.
|
/// Uses the `pl_node` union field. `payload_index` points to a `FuncFancy`.
|
||||||
func_fancy,
|
func_fancy,
|
||||||
/// Implements the `@import` builtin.
|
/// Implements the `@import` builtin.
|
||||||
/// Uses the `str_tok` field.
|
/// Uses the `pl_tok` field.
|
||||||
import,
|
import,
|
||||||
/// Integer literal that fits in a u64. Uses the `int` union field.
|
/// Integer literal that fits in a u64. Uses the `int` union field.
|
||||||
int,
|
int,
|
||||||
@ -1673,7 +1673,7 @@ pub const Inst = struct {
|
|||||||
.func = .pl_node,
|
.func = .pl_node,
|
||||||
.func_inferred = .pl_node,
|
.func_inferred = .pl_node,
|
||||||
.func_fancy = .pl_node,
|
.func_fancy = .pl_node,
|
||||||
.import = .str_tok,
|
.import = .pl_tok,
|
||||||
.int = .int,
|
.int = .int,
|
||||||
.int_big = .str,
|
.int_big = .str,
|
||||||
.float = .float,
|
.float = .float,
|
||||||
@ -3841,6 +3841,13 @@ pub const Inst = struct {
|
|||||||
/// If `.none`, restore unconditionally.
|
/// If `.none`, restore unconditionally.
|
||||||
operand: Ref,
|
operand: Ref,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Import = struct {
|
||||||
|
/// The result type of the import, or `.none` if none was available.
|
||||||
|
res_ty: Ref,
|
||||||
|
/// The import path.
|
||||||
|
path: NullTerminatedString,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SpecialProng = enum { none, @"else", under };
|
pub const SpecialProng = enum { none, @"else", under };
|
||||||
|
|||||||
@ -54,7 +54,7 @@ pub const Node = union(enum) {
|
|||||||
/// A floating-point literal.
|
/// A floating-point literal.
|
||||||
float_literal: f128,
|
float_literal: f128,
|
||||||
/// A Unicode codepoint literal.
|
/// A Unicode codepoint literal.
|
||||||
char_literal: u32,
|
char_literal: u21,
|
||||||
/// An enum literal. The string is the literal, i.e. `foo` for `.foo`.
|
/// An enum literal. The string is the literal, i.e. `foo` for `.foo`.
|
||||||
enum_literal: NullTerminatedString,
|
enum_literal: NullTerminatedString,
|
||||||
/// A string literal.
|
/// A string literal.
|
||||||
@ -96,7 +96,7 @@ pub const Node = union(enum) {
|
|||||||
} } },
|
} } },
|
||||||
.float_literal_small => .{ .float_literal = @as(f32, @bitCast(repr.data)) },
|
.float_literal_small => .{ .float_literal = @as(f32, @bitCast(repr.data)) },
|
||||||
.float_literal => .{ .float_literal = @bitCast(zoir.extra[repr.data..][0..4].*) },
|
.float_literal => .{ .float_literal = @bitCast(zoir.extra[repr.data..][0..4].*) },
|
||||||
.char_literal => .{ .char_literal = repr.data },
|
.char_literal => .{ .char_literal = @intCast(repr.data) },
|
||||||
.enum_literal => .{ .enum_literal = @enumFromInt(repr.data) },
|
.enum_literal => .{ .enum_literal = @enumFromInt(repr.data) },
|
||||||
.string_literal => .{ .string_literal = s: {
|
.string_literal => .{ .string_literal = s: {
|
||||||
const start, const len = zoir.extra[repr.data..][0..2].*;
|
const start, const len = zoir.extra[repr.data..][0..2].*;
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
tree: Ast,
|
tree: Ast,
|
||||||
|
|
||||||
|
options: Options,
|
||||||
|
|
||||||
nodes: std.MultiArrayList(Zoir.Node.Repr),
|
nodes: std.MultiArrayList(Zoir.Node.Repr),
|
||||||
extra: std.ArrayListUnmanaged(u32),
|
extra: std.ArrayListUnmanaged(u32),
|
||||||
limbs: std.ArrayListUnmanaged(std.math.big.Limb),
|
limbs: std.ArrayListUnmanaged(std.math.big.Limb),
|
||||||
@ -12,12 +14,21 @@ string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.d
|
|||||||
compile_errors: std.ArrayListUnmanaged(Zoir.CompileError),
|
compile_errors: std.ArrayListUnmanaged(Zoir.CompileError),
|
||||||
error_notes: std.ArrayListUnmanaged(Zoir.CompileError.Note),
|
error_notes: std.ArrayListUnmanaged(Zoir.CompileError.Note),
|
||||||
|
|
||||||
pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zoir {
|
pub const Options = struct {
|
||||||
|
/// When false, string literals are not parsed. `string_literal` nodes will contain empty
|
||||||
|
/// strings, and errors that normally occur during string parsing will not be raised.
|
||||||
|
///
|
||||||
|
/// `parseStrLit` and `strLitSizeHint` may be used to parse string literals after the fact.
|
||||||
|
parse_str_lits: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn generate(gpa: Allocator, tree: Ast, options: Options) Allocator.Error!Zoir {
|
||||||
assert(tree.mode == .zon);
|
assert(tree.mode == .zon);
|
||||||
|
|
||||||
var zg: ZonGen = .{
|
var zg: ZonGen = .{
|
||||||
.gpa = gpa,
|
.gpa = gpa,
|
||||||
.tree = tree,
|
.tree = tree,
|
||||||
|
.options = options,
|
||||||
.nodes = .empty,
|
.nodes = .empty,
|
||||||
.extra = .empty,
|
.extra = .empty,
|
||||||
.limbs = .empty,
|
.limbs = .empty,
|
||||||
@ -250,7 +261,20 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
|
|||||||
.block_two_semicolon,
|
.block_two_semicolon,
|
||||||
.block,
|
.block,
|
||||||
.block_semicolon,
|
.block_semicolon,
|
||||||
=> try zg.addErrorNode(node, "blocks are not allowed in ZON", .{}),
|
=> {
|
||||||
|
const size = switch (node_tags[node]) {
|
||||||
|
.block_two, .block_two_semicolon => @intFromBool(node_datas[node].lhs != 0) + @intFromBool(node_datas[node].rhs != 0),
|
||||||
|
.block, .block_semicolon => node_datas[node].rhs - node_datas[node].lhs,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
if (size == 0) {
|
||||||
|
try zg.addErrorNodeNotes(node, "void literals are not available in ZON", .{}, &.{
|
||||||
|
try zg.errNoteNode(node, "void union payloads can be represented by enum literals", .{}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
try zg.addErrorNode(node, "blocks are not allowed in ZON", .{});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
.array_init_one,
|
.array_init_one,
|
||||||
.array_init_one_comma,
|
.array_init_one_comma,
|
||||||
@ -403,58 +427,37 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
|
|||||||
.ast_node = node,
|
.ast_node = node,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// For short initializers, track the names on the stack rather than going through gpa.
|
||||||
|
var sfba_state = std.heap.stackFallback(256, gpa);
|
||||||
|
const sfba = sfba_state.get();
|
||||||
|
var field_names: std.AutoHashMapUnmanaged(Zoir.NullTerminatedString, Ast.TokenIndex) = .empty;
|
||||||
|
defer field_names.deinit(sfba);
|
||||||
|
|
||||||
|
var reported_any_duplicate = false;
|
||||||
|
|
||||||
for (full.ast.fields, names_start.., first_elem..) |elem_node, extra_name_idx, elem_dest_node| {
|
for (full.ast.fields, names_start.., first_elem..) |elem_node, extra_name_idx, elem_dest_node| {
|
||||||
const name_token = tree.firstToken(elem_node) - 2;
|
const name_token = tree.firstToken(elem_node) - 2;
|
||||||
zg.extra.items[extra_name_idx] = @intFromEnum(zg.identAsString(name_token) catch |err| switch (err) {
|
if (zg.identAsString(name_token)) |name_str| {
|
||||||
error.BadString => undefined, // doesn't matter, there's an error
|
zg.extra.items[extra_name_idx] = @intFromEnum(name_str);
|
||||||
error.OutOfMemory => |e| return e,
|
const gop = try field_names.getOrPut(sfba, name_str);
|
||||||
|
if (gop.found_existing and !reported_any_duplicate) {
|
||||||
|
reported_any_duplicate = true;
|
||||||
|
const earlier_token = gop.value_ptr.*;
|
||||||
|
try zg.addErrorTokNotes(earlier_token, "duplicate struct field name", .{}, &.{
|
||||||
|
try zg.errNoteTok(name_token, "duplicate name here", .{}),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
gop.value_ptr.* = name_token;
|
||||||
|
} else |err| switch (err) {
|
||||||
|
error.BadString => {}, // there's an error, so it's fine to not populate `zg.extra`
|
||||||
|
error.OutOfMemory => |e| return e,
|
||||||
|
}
|
||||||
try zg.expr(elem_node, @enumFromInt(elem_dest_node));
|
try zg.expr(elem_node, @enumFromInt(elem_dest_node));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseStrLit(zg: *ZonGen, token: Ast.TokenIndex, offset: u32) !u32 {
|
|
||||||
const raw_string = zg.tree.tokenSlice(token)[offset..];
|
|
||||||
const start = zg.string_bytes.items.len;
|
|
||||||
switch (try std.zig.string_literal.parseWrite(zg.string_bytes.writer(zg.gpa), raw_string)) {
|
|
||||||
.success => return @intCast(start),
|
|
||||||
.failure => |err| {
|
|
||||||
try zg.lowerStrLitError(err, token, raw_string, offset);
|
|
||||||
return error.BadString;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parseMultilineStrLit(zg: *ZonGen, node: Ast.Node.Index) !u32 {
|
|
||||||
const gpa = zg.gpa;
|
|
||||||
const tree = zg.tree;
|
|
||||||
const string_bytes = &zg.string_bytes;
|
|
||||||
|
|
||||||
const first_tok, const last_tok = bounds: {
|
|
||||||
const node_data = tree.nodes.items(.data)[node];
|
|
||||||
break :bounds .{ node_data.lhs, node_data.rhs };
|
|
||||||
};
|
|
||||||
|
|
||||||
const str_index: u32 = @intCast(string_bytes.items.len);
|
|
||||||
|
|
||||||
// First line: do not append a newline.
|
|
||||||
{
|
|
||||||
const line_bytes = tree.tokenSlice(first_tok)[2..];
|
|
||||||
try string_bytes.appendSlice(gpa, line_bytes);
|
|
||||||
}
|
|
||||||
// Following lines: each line prepends a newline.
|
|
||||||
for (first_tok + 1..last_tok + 1) |tok_idx| {
|
|
||||||
const line_bytes = tree.tokenSlice(@intCast(tok_idx))[2..];
|
|
||||||
try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
|
|
||||||
string_bytes.appendAssumeCapacity('\n');
|
|
||||||
string_bytes.appendSliceAssumeCapacity(line_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return @intCast(str_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
||||||
const tree = zg.tree;
|
const tree = zg.tree;
|
||||||
assert(tree.tokens.items(.tag)[ident_token] == .identifier);
|
assert(tree.tokens.items(.tag)[ident_token] == .identifier);
|
||||||
@ -464,7 +467,18 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
|||||||
try zg.string_bytes.appendSlice(zg.gpa, ident_name);
|
try zg.string_bytes.appendSlice(zg.gpa, ident_name);
|
||||||
return @intCast(start);
|
return @intCast(start);
|
||||||
} else {
|
} else {
|
||||||
const start = try zg.parseStrLit(ident_token, 1);
|
const offset = 1;
|
||||||
|
const start: u32 = @intCast(zg.string_bytes.items.len);
|
||||||
|
const raw_string = zg.tree.tokenSlice(ident_token)[offset..];
|
||||||
|
try zg.string_bytes.ensureUnusedCapacity(zg.gpa, raw_string.len);
|
||||||
|
switch (try std.zig.string_literal.parseWrite(zg.string_bytes.writer(zg.gpa), raw_string)) {
|
||||||
|
.success => {},
|
||||||
|
.failure => |err| {
|
||||||
|
try zg.lowerStrLitError(err, ident_token, raw_string, offset);
|
||||||
|
return error.BadString;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const slice = zg.string_bytes.items[start..];
|
const slice = zg.string_bytes.items[start..];
|
||||||
if (mem.indexOfScalar(u8, slice, 0) != null) {
|
if (mem.indexOfScalar(u8, slice, 0) != null) {
|
||||||
try zg.addErrorTok(ident_token, "identifier cannot contain null bytes", .{});
|
try zg.addErrorTok(ident_token, "identifier cannot contain null bytes", .{});
|
||||||
@ -477,19 +491,93 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Estimates the size of a string node without parsing it.
|
||||||
|
pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize {
|
||||||
|
switch (tree.nodes.items(.tag)[node]) {
|
||||||
|
// Parsed string literals are typically around the size of the raw strings.
|
||||||
|
.string_literal => {
|
||||||
|
const token = tree.nodes.items(.main_token)[node];
|
||||||
|
const raw_string = tree.tokenSlice(token);
|
||||||
|
return raw_string.len;
|
||||||
|
},
|
||||||
|
// Multiline string literal lengths can be computed exactly.
|
||||||
|
.multiline_string_literal => {
|
||||||
|
const first_tok, const last_tok = bounds: {
|
||||||
|
const node_data = tree.nodes.items(.data)[node];
|
||||||
|
break :bounds .{ node_data.lhs, node_data.rhs };
|
||||||
|
};
|
||||||
|
|
||||||
|
var size = tree.tokenSlice(first_tok)[2..].len;
|
||||||
|
for (first_tok + 1..last_tok + 1) |tok_idx| {
|
||||||
|
size += 1; // Newline
|
||||||
|
size += tree.tokenSlice(@intCast(tok_idx))[2..].len;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the given node as a string literal.
|
||||||
|
pub fn parseStrLit(
|
||||||
|
tree: Ast,
|
||||||
|
node: Ast.Node.Index,
|
||||||
|
writer: anytype,
|
||||||
|
) error{OutOfMemory}!std.zig.string_literal.Result {
|
||||||
|
switch (tree.nodes.items(.tag)[node]) {
|
||||||
|
.string_literal => {
|
||||||
|
const token = tree.nodes.items(.main_token)[node];
|
||||||
|
const raw_string = tree.tokenSlice(token);
|
||||||
|
return std.zig.string_literal.parseWrite(writer, raw_string);
|
||||||
|
},
|
||||||
|
.multiline_string_literal => {
|
||||||
|
const first_tok, const last_tok = bounds: {
|
||||||
|
const node_data = tree.nodes.items(.data)[node];
|
||||||
|
break :bounds .{ node_data.lhs, node_data.rhs };
|
||||||
|
};
|
||||||
|
|
||||||
|
// First line: do not append a newline.
|
||||||
|
{
|
||||||
|
const line_bytes = tree.tokenSlice(first_tok)[2..];
|
||||||
|
try writer.writeAll(line_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following lines: each line prepends a newline.
|
||||||
|
for (first_tok + 1..last_tok + 1) |tok_idx| {
|
||||||
|
const line_bytes = tree.tokenSlice(@intCast(tok_idx))[2..];
|
||||||
|
try writer.writeByte('\n');
|
||||||
|
try writer.writeAll(line_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .success;
|
||||||
|
},
|
||||||
|
// Node must represent a string
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const StringLiteralResult = union(enum) {
|
const StringLiteralResult = union(enum) {
|
||||||
nts: Zoir.NullTerminatedString,
|
nts: Zoir.NullTerminatedString,
|
||||||
slice: struct { start: u32, len: u32 },
|
slice: struct { start: u32, len: u32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
fn strLitAsString(zg: *ZonGen, str_node: Ast.Node.Index) !StringLiteralResult {
|
fn strLitAsString(zg: *ZonGen, str_node: Ast.Node.Index) !StringLiteralResult {
|
||||||
|
if (!zg.options.parse_str_lits) return .{ .slice = .{ .start = 0, .len = 0 } };
|
||||||
|
|
||||||
const gpa = zg.gpa;
|
const gpa = zg.gpa;
|
||||||
const string_bytes = &zg.string_bytes;
|
const string_bytes = &zg.string_bytes;
|
||||||
const str_index = switch (zg.tree.nodes.items(.tag)[str_node]) {
|
const str_index: u32 = @intCast(zg.string_bytes.items.len);
|
||||||
.string_literal => try zg.parseStrLit(zg.tree.nodes.items(.main_token)[str_node], 0),
|
const size_hint = strLitSizeHint(zg.tree, str_node);
|
||||||
.multiline_string_literal => try zg.parseMultilineStrLit(str_node),
|
try string_bytes.ensureUnusedCapacity(zg.gpa, size_hint);
|
||||||
else => unreachable,
|
switch (try parseStrLit(zg.tree, str_node, zg.string_bytes.writer(zg.gpa))) {
|
||||||
};
|
.success => {},
|
||||||
|
.failure => |err| {
|
||||||
|
const token = zg.tree.nodes.items(.main_token)[str_node];
|
||||||
|
const raw_string = zg.tree.tokenSlice(token);
|
||||||
|
try zg.lowerStrLitError(err, token, raw_string, 0);
|
||||||
|
return error.BadString;
|
||||||
|
},
|
||||||
|
}
|
||||||
const key: []const u8 = string_bytes.items[str_index..];
|
const key: []const u8 = string_bytes.items[str_index..];
|
||||||
if (std.mem.indexOfScalar(u8, key, 0) != null) return .{ .slice = .{
|
if (std.mem.indexOfScalar(u8, key, 0) != null) return .{ .slice = .{
|
||||||
.start = str_index,
|
.start = str_index,
|
||||||
@ -540,7 +628,7 @@ fn numberLiteral(zg: *ZonGen, num_node: Ast.Node.Index, src_node: Ast.Node.Index
|
|||||||
if (unsigned_num == 0 and sign == .negative) {
|
if (unsigned_num == 0 and sign == .negative) {
|
||||||
try zg.addErrorTokNotes(num_token, "integer literal '-0' is ambiguous", .{}, &.{
|
try zg.addErrorTokNotes(num_token, "integer literal '-0' is ambiguous", .{}, &.{
|
||||||
try zg.errNoteTok(num_token, "use '0' for an integer zero", .{}),
|
try zg.errNoteTok(num_token, "use '0' for an integer zero", .{}),
|
||||||
try zg.errNoteTok(num_token, "use '-0.0' for a flaoting-point signed zero", .{}),
|
try zg.errNoteTok(num_token, "use '-0.0' for a floating-point signed zero", .{}),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -679,8 +767,20 @@ fn setNode(zg: *ZonGen, dest: Zoir.Node.Index, repr: Zoir.Node.Repr) void {
|
|||||||
zg.nodes.set(@intFromEnum(dest), repr);
|
zg.nodes.set(@intFromEnum(dest), repr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerStrLitError(zg: *ZonGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, raw_string: []const u8, offset: u32) Allocator.Error!void {
|
fn lowerStrLitError(
|
||||||
return err.lower(raw_string, offset, ZonGen.addErrorTokOff, .{ zg, token });
|
zg: *ZonGen,
|
||||||
|
err: std.zig.string_literal.Error,
|
||||||
|
token: Ast.TokenIndex,
|
||||||
|
raw_string: []const u8,
|
||||||
|
offset: u32,
|
||||||
|
) Allocator.Error!void {
|
||||||
|
return ZonGen.addErrorTokOff(
|
||||||
|
zg,
|
||||||
|
token,
|
||||||
|
@intCast(offset + err.offset()),
|
||||||
|
"{}",
|
||||||
|
.{err.fmt(raw_string)},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerNumberError(zg: *ZonGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) Allocator.Error!void {
|
fn lowerNumberError(zg: *ZonGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) Allocator.Error!void {
|
||||||
|
|||||||
@ -39,40 +39,82 @@ pub const Error = union(enum) {
|
|||||||
/// `''`. Not returned for string literals.
|
/// `''`. Not returned for string literals.
|
||||||
empty_char_literal,
|
empty_char_literal,
|
||||||
|
|
||||||
/// Returns `func(first_args[0], ..., first_args[n], offset + bad_idx, format, args)`.
|
const FormatMessage = struct {
|
||||||
pub fn lower(
|
|
||||||
err: Error,
|
err: Error,
|
||||||
raw_string: []const u8,
|
raw_string: []const u8,
|
||||||
offset: u32,
|
|
||||||
comptime func: anytype,
|
|
||||||
first_args: anytype,
|
|
||||||
) @typeInfo(@TypeOf(func)).@"fn".return_type.? {
|
|
||||||
switch (err) {
|
|
||||||
inline else => |bad_index_or_void, tag| {
|
|
||||||
const bad_index: u32 = switch (@TypeOf(bad_index_or_void)) {
|
|
||||||
void => 0,
|
|
||||||
else => @intCast(bad_index_or_void),
|
|
||||||
};
|
};
|
||||||
const fmt_str: []const u8, const args = switch (tag) {
|
|
||||||
.invalid_escape_character => .{ "invalid escape character: '{c}'", .{raw_string[bad_index]} },
|
fn formatMessage(
|
||||||
.expected_hex_digit => .{ "expected hex digit, found '{c}'", .{raw_string[bad_index]} },
|
self: FormatMessage,
|
||||||
.empty_unicode_escape_sequence => .{ "empty unicode escape sequence", .{} },
|
comptime f: []const u8,
|
||||||
.expected_hex_digit_or_rbrace => .{ "expected hex digit or '}}', found '{c}'", .{raw_string[bad_index]} },
|
options: std.fmt.FormatOptions,
|
||||||
.invalid_unicode_codepoint => .{ "unicode escape does not correspond to a valid unicode scalar value", .{} },
|
writer: anytype,
|
||||||
.expected_lbrace => .{ "expected '{{', found '{c}'", .{raw_string[bad_index]} },
|
) !void {
|
||||||
.expected_rbrace => .{ "expected '}}', found '{c}'", .{raw_string[bad_index]} },
|
_ = f;
|
||||||
.expected_single_quote => .{ "expected singel quote ('), found '{c}'", .{raw_string[bad_index]} },
|
_ = options;
|
||||||
.invalid_character => .{ "invalid byte in string or character literal: '{c}'", .{raw_string[bad_index]} },
|
switch (self.err) {
|
||||||
.empty_char_literal => .{ "empty character literal", .{} },
|
.invalid_escape_character => |bad_index| try writer.print(
|
||||||
};
|
"invalid escape character: '{c}'",
|
||||||
return @call(.auto, func, first_args ++ .{
|
.{self.raw_string[bad_index]},
|
||||||
offset + bad_index,
|
),
|
||||||
fmt_str,
|
.expected_hex_digit => |bad_index| try writer.print(
|
||||||
args,
|
"expected hex digit, found '{c}'",
|
||||||
});
|
.{self.raw_string[bad_index]},
|
||||||
},
|
),
|
||||||
|
.empty_unicode_escape_sequence => try writer.writeAll(
|
||||||
|
"empty unicode escape sequence",
|
||||||
|
),
|
||||||
|
.expected_hex_digit_or_rbrace => |bad_index| try writer.print(
|
||||||
|
"expected hex digit or '}}', found '{c}'",
|
||||||
|
.{self.raw_string[bad_index]},
|
||||||
|
),
|
||||||
|
.invalid_unicode_codepoint => try writer.writeAll(
|
||||||
|
"unicode escape does not correspond to a valid unicode scalar value",
|
||||||
|
),
|
||||||
|
.expected_lbrace => |bad_index| try writer.print(
|
||||||
|
"expected '{{', found '{c}'",
|
||||||
|
.{self.raw_string[bad_index]},
|
||||||
|
),
|
||||||
|
.expected_rbrace => |bad_index| try writer.print(
|
||||||
|
"expected '}}', found '{c}'",
|
||||||
|
.{self.raw_string[bad_index]},
|
||||||
|
),
|
||||||
|
.expected_single_quote => |bad_index| try writer.print(
|
||||||
|
"expected single quote ('), found '{c}'",
|
||||||
|
.{self.raw_string[bad_index]},
|
||||||
|
),
|
||||||
|
.invalid_character => |bad_index| try writer.print(
|
||||||
|
"invalid byte in string or character literal: '{c}'",
|
||||||
|
.{self.raw_string[bad_index]},
|
||||||
|
),
|
||||||
|
.empty_char_literal => try writer.writeAll(
|
||||||
|
"empty character literal",
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fmt(self: @This(), raw_string: []const u8) std.fmt.Formatter(formatMessage) {
|
||||||
|
return .{ .data = .{
|
||||||
|
.err = self,
|
||||||
|
.raw_string = raw_string,
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(err: Error) usize {
|
||||||
|
return switch (err) {
|
||||||
|
inline .invalid_escape_character,
|
||||||
|
.expected_hex_digit,
|
||||||
|
.empty_unicode_escape_sequence,
|
||||||
|
.expected_hex_digit_or_rbrace,
|
||||||
|
.invalid_unicode_codepoint,
|
||||||
|
.expected_lbrace,
|
||||||
|
.expected_rbrace,
|
||||||
|
.expected_single_quote,
|
||||||
|
.invalid_character,
|
||||||
|
=> |n| n,
|
||||||
|
.empty_char_literal => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Asserts the slice starts and ends with single-quotes.
|
/// Asserts the slice starts and ends with single-quotes.
|
||||||
|
|||||||
45
lib/std/zon.zig
Normal file
45
lib/std/zon.zig
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//! ZON parsing and stringification.
|
||||||
|
//!
|
||||||
|
//! ZON ("Zig Object Notation") is a textual file format. Outside of `nan` and `inf` literals, ZON's
|
||||||
|
//! grammar is a subset of Zig's.
|
||||||
|
//!
|
||||||
|
//! Supported Zig primitives:
|
||||||
|
//! * boolean literals
|
||||||
|
//! * number literals (including `nan` and `inf`)
|
||||||
|
//! * character literals
|
||||||
|
//! * enum literals
|
||||||
|
//! * `null` literals
|
||||||
|
//! * string literals
|
||||||
|
//! * multiline string literals
|
||||||
|
//!
|
||||||
|
//! Supported Zig container types:
|
||||||
|
//! * anonymous struct literals
|
||||||
|
//! * anonymous tuple literals
|
||||||
|
//!
|
||||||
|
//! Here is an example ZON object:
|
||||||
|
//! ```
|
||||||
|
//! .{
|
||||||
|
//! .a = 1.5,
|
||||||
|
//! .b = "hello, world!",
|
||||||
|
//! .c = .{ true, false },
|
||||||
|
//! .d = .{ 1, 2, 3 },
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Individual primitives are also valid ZON, for example:
|
||||||
|
//! ```
|
||||||
|
//! "This string is a valid ZON object."
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ZON may not contain type names.
|
||||||
|
//!
|
||||||
|
//! ZON does not have syntax for pointers, but the parsers will allocate as needed to match the
|
||||||
|
//! given Zig types. Similarly, the serializer will traverse pointers.
|
||||||
|
|
||||||
|
pub const parse = @import("zon/parse.zig");
|
||||||
|
pub const stringify = @import("zon/stringify.zig");
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = parse;
|
||||||
|
_ = stringify;
|
||||||
|
}
|
||||||
3449
lib/std/zon/parse.zig
Normal file
3449
lib/std/zon/parse.zig
Normal file
File diff suppressed because it is too large
Load Diff
2306
lib/std/zon/stringify.zig
Normal file
2306
lib/std/zon/stringify.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -2220,8 +2220,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
|
|||||||
try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
|
try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
|
||||||
for (zcu.import_table.values()) |file_index| {
|
for (zcu.import_table.values()) |file_index| {
|
||||||
if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
|
if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
|
||||||
|
const file = zcu.fileByIndex(file_index);
|
||||||
|
if (file.getMode() == .zig) {
|
||||||
comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
|
comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (comp.file_system_inputs) |fsi| {
|
if (comp.file_system_inputs) |fsi| {
|
||||||
for (zcu.import_table.values()) |file_index| {
|
for (zcu.import_table.values()) |file_index| {
|
||||||
const file = zcu.fileByIndex(file_index);
|
const file = zcu.fileByIndex(file_index);
|
||||||
@ -3206,10 +3209,16 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
|||||||
if (error_msg) |msg| {
|
if (error_msg) |msg| {
|
||||||
try addModuleErrorMsg(zcu, &bundle, msg.*);
|
try addModuleErrorMsg(zcu, &bundle, msg.*);
|
||||||
} else {
|
} else {
|
||||||
// Must be ZIR errors. Note that this may include AST errors.
|
// Must be ZIR or Zoir errors. Note that this may include AST errors.
|
||||||
// addZirErrorMessages asserts that the tree is loaded.
|
_ = try file.getTree(gpa); // Tree must be loaded.
|
||||||
_ = try file.getTree(gpa);
|
if (file.zir_loaded) {
|
||||||
try addZirErrorMessages(&bundle, file);
|
try addZirErrorMessages(&bundle, file);
|
||||||
|
} else if (file.zoir != null) {
|
||||||
|
try addZoirErrorMessages(&bundle, file);
|
||||||
|
} else {
|
||||||
|
// Either Zir or Zoir must have been loaded.
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sorted_failed_analysis: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: {
|
var sorted_failed_analysis: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: {
|
||||||
@ -3623,6 +3632,15 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
|
|||||||
return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);
|
return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addZoirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
|
||||||
|
assert(file.source_loaded);
|
||||||
|
assert(file.tree_loaded);
|
||||||
|
const gpa = eb.gpa;
|
||||||
|
const src_path = try file.fullPath(gpa);
|
||||||
|
defer gpa.free(src_path);
|
||||||
|
return eb.addZoirErrorMessages(file.zoir.?, file.tree, file.source, src_path);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn performAllTheWork(
|
pub fn performAllTheWork(
|
||||||
comp: *Compilation,
|
comp: *Compilation,
|
||||||
main_progress_node: std.Progress.Node,
|
main_progress_node: std.Progress.Node,
|
||||||
@ -4272,6 +4290,7 @@ fn workerAstGenFile(
|
|||||||
wg: *WaitGroup,
|
wg: *WaitGroup,
|
||||||
src: Zcu.AstGenSrc,
|
src: Zcu.AstGenSrc,
|
||||||
) void {
|
) void {
|
||||||
|
assert(file.getMode() == .zig);
|
||||||
const child_prog_node = prog_node.start(file.sub_file_path, 0);
|
const child_prog_node = prog_node.start(file.sub_file_path, 0);
|
||||||
defer child_prog_node.end();
|
defer child_prog_node.end();
|
||||||
|
|
||||||
@ -4325,7 +4344,7 @@ fn workerAstGenFile(
|
|||||||
const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
|
const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
|
||||||
break :blk .{ res, imported_path_digest };
|
break :blk .{ res, imported_path_digest };
|
||||||
};
|
};
|
||||||
if (import_result.is_new) {
|
if (import_result.is_new and import_result.file.getMode() == .zig) {
|
||||||
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
||||||
file.sub_file_path, import_path, import_result.file.sub_file_path,
|
file.sub_file_path, import_path, import_result.file.sub_file_path,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4389,7 +4389,7 @@ pub const LoadedEnumType = struct {
|
|||||||
// Auto-numbered enum. Convert `int_tag_val` to field index.
|
// Auto-numbered enum. Convert `int_tag_val` to field index.
|
||||||
const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
|
const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
|
||||||
inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
|
inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
|
||||||
.big_int => |x| x.to(u32) catch return null,
|
.big_int => |x| x.toInt(u32) catch return null,
|
||||||
.lazy_align, .lazy_size => unreachable,
|
.lazy_align, .lazy_size => unreachable,
|
||||||
};
|
};
|
||||||
return if (field_index < self.names.len) field_index else null;
|
return if (field_index < self.names.len) field_index else null;
|
||||||
@ -7957,7 +7957,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_u8,
|
.tag = .int_u8,
|
||||||
.data = big_int.to(u8) catch unreachable,
|
.data = big_int.toInt(u8) catch unreachable,
|
||||||
});
|
});
|
||||||
break :b;
|
break :b;
|
||||||
},
|
},
|
||||||
@ -7974,7 +7974,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_u16,
|
.tag = .int_u16,
|
||||||
.data = big_int.to(u16) catch unreachable,
|
.data = big_int.toInt(u16) catch unreachable,
|
||||||
});
|
});
|
||||||
break :b;
|
break :b;
|
||||||
},
|
},
|
||||||
@ -7991,7 +7991,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_u32,
|
.tag = .int_u32,
|
||||||
.data = big_int.to(u32) catch unreachable,
|
.data = big_int.toInt(u32) catch unreachable,
|
||||||
});
|
});
|
||||||
break :b;
|
break :b;
|
||||||
},
|
},
|
||||||
@ -8006,7 +8006,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
},
|
},
|
||||||
.i32_type => switch (int.storage) {
|
.i32_type => switch (int.storage) {
|
||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
const casted = big_int.to(i32) catch unreachable;
|
const casted = big_int.toInt(i32) catch unreachable;
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_i32,
|
.tag = .int_i32,
|
||||||
.data = @as(u32, @bitCast(casted)),
|
.data = @as(u32, @bitCast(casted)),
|
||||||
@ -8024,7 +8024,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
},
|
},
|
||||||
.usize_type => switch (int.storage) {
|
.usize_type => switch (int.storage) {
|
||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
if (big_int.to(u32)) |casted| {
|
if (big_int.toInt(u32)) |casted| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_usize,
|
.tag = .int_usize,
|
||||||
.data = casted,
|
.data = casted,
|
||||||
@ -8045,14 +8045,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
},
|
},
|
||||||
.comptime_int_type => switch (int.storage) {
|
.comptime_int_type => switch (int.storage) {
|
||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
if (big_int.to(u32)) |casted| {
|
if (big_int.toInt(u32)) |casted| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_comptime_int_u32,
|
.tag = .int_comptime_int_u32,
|
||||||
.data = casted,
|
.data = casted,
|
||||||
});
|
});
|
||||||
break :b;
|
break :b;
|
||||||
} else |_| {}
|
} else |_| {}
|
||||||
if (big_int.to(i32)) |casted| {
|
if (big_int.toInt(i32)) |casted| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_comptime_int_i32,
|
.tag = .int_comptime_int_i32,
|
||||||
.data = @as(u32, @bitCast(casted)),
|
.data = @as(u32, @bitCast(casted)),
|
||||||
@ -8082,7 +8082,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
}
|
}
|
||||||
switch (int.storage) {
|
switch (int.storage) {
|
||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
if (big_int.to(u32)) |casted| {
|
if (big_int.toInt(u32)) |casted| {
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .int_small,
|
.tag = .int_small,
|
||||||
.data = try addExtra(extra, IntSmall{
|
.data = try addExtra(extra, IntSmall{
|
||||||
|
|||||||
38
src/Sema.zig
38
src/Sema.zig
@ -187,6 +187,7 @@ const Alignment = InternPool.Alignment;
|
|||||||
const AnalUnit = InternPool.AnalUnit;
|
const AnalUnit = InternPool.AnalUnit;
|
||||||
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
|
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
|
||||||
const Cache = std.Build.Cache;
|
const Cache = std.Build.Cache;
|
||||||
|
const LowerZon = @import("Sema/LowerZon.zig");
|
||||||
|
|
||||||
pub const default_branch_quota = 1000;
|
pub const default_branch_quota = 1000;
|
||||||
pub const default_reference_trace_len = 2;
|
pub const default_reference_trace_len = 2;
|
||||||
@ -5790,7 +5791,7 @@ fn addNullTerminatedStrLit(sema: *Sema, string: InternPool.NullTerminatedString)
|
|||||||
return sema.addStrLit(string.toString(), string.length(&sema.pt.zcu.intern_pool));
|
return sema.addStrLit(string.toString(), string.length(&sema.pt.zcu.intern_pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.Inst.Ref {
|
pub fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.Inst.Ref {
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const array_ty = try pt.arrayType(.{
|
const array_ty = try pt.arrayType(.{
|
||||||
.len = len,
|
.len = len,
|
||||||
@ -13964,9 +13965,10 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
|||||||
|
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
|
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
|
||||||
|
const extra = sema.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
|
||||||
const operand_src = block.tokenOffset(inst_data.src_tok);
|
const operand_src = block.tokenOffset(inst_data.src_tok);
|
||||||
const operand = inst_data.get(sema.code);
|
const operand = sema.code.nullTerminatedString(extra.path);
|
||||||
|
|
||||||
const result = pt.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
|
const result = pt.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
|
||||||
error.ImportOutsideModulePath => {
|
error.ImportOutsideModulePath => {
|
||||||
@ -13983,12 +13985,42 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
|||||||
return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
|
return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
switch (result.file.getMode()) {
|
||||||
|
.zig => {
|
||||||
try sema.declareDependency(.{ .file = result.file_index });
|
try sema.declareDependency(.{ .file = result.file_index });
|
||||||
try pt.ensureFileAnalyzed(result.file_index);
|
try pt.ensureFileAnalyzed(result.file_index);
|
||||||
const ty = zcu.fileRootType(result.file_index);
|
const ty = zcu.fileRootType(result.file_index);
|
||||||
try sema.declareDependency(.{ .interned = ty });
|
try sema.declareDependency(.{ .interned = ty });
|
||||||
try sema.addTypeReferenceEntry(operand_src, ty);
|
try sema.addTypeReferenceEntry(operand_src, ty);
|
||||||
return Air.internedToRef(ty);
|
return Air.internedToRef(ty);
|
||||||
|
},
|
||||||
|
.zon => {
|
||||||
|
_ = result.file.getTree(zcu.gpa) catch |err| {
|
||||||
|
// TODO: these errors are file system errors; make sure an update() will
|
||||||
|
// retry this and not cache the file system error, which may be transient.
|
||||||
|
return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ result.file.sub_file_path, @errorName(err) });
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extra.res_ty == .none) {
|
||||||
|
return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});
|
||||||
|
}
|
||||||
|
const res_ty_inst = try sema.resolveInst(extra.res_ty);
|
||||||
|
const res_ty = try sema.analyzeAsType(block, operand_src, res_ty_inst);
|
||||||
|
if (res_ty.isGenericPoison()) {
|
||||||
|
return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
const interned = try LowerZon.run(
|
||||||
|
sema,
|
||||||
|
result.file,
|
||||||
|
result.file_index,
|
||||||
|
res_ty,
|
||||||
|
operand_src,
|
||||||
|
block,
|
||||||
|
);
|
||||||
|
return Air.internedToRef(interned);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
|
|||||||
858
src/Sema/LowerZon.zig
Normal file
858
src/Sema/LowerZon.zig
Normal file
@ -0,0 +1,858 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Zcu = @import("../Zcu.zig");
|
||||||
|
const Sema = @import("../Sema.zig");
|
||||||
|
const Air = @import("../Air.zig");
|
||||||
|
const InternPool = @import("../InternPool.zig");
|
||||||
|
const Type = @import("../Type.zig");
|
||||||
|
const Value = @import("../Value.zig");
|
||||||
|
const Zir = std.zig.Zir;
|
||||||
|
const AstGen = std.zig.AstGen;
|
||||||
|
const CompileError = Zcu.CompileError;
|
||||||
|
const Ast = std.zig.Ast;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const File = Zcu.File;
|
||||||
|
const LazySrcLoc = Zcu.LazySrcLoc;
|
||||||
|
const Ref = std.zig.Zir.Inst.Ref;
|
||||||
|
const NullTerminatedString = InternPool.NullTerminatedString;
|
||||||
|
const NumberLiteralError = std.zig.number_literal.Error;
|
||||||
|
const NodeIndex = std.zig.Ast.Node.Index;
|
||||||
|
const Zoir = std.zig.Zoir;
|
||||||
|
|
||||||
|
const LowerZon = @This();
|
||||||
|
|
||||||
|
sema: *Sema,
|
||||||
|
file: *File,
|
||||||
|
file_index: Zcu.File.Index,
|
||||||
|
import_loc: LazySrcLoc,
|
||||||
|
block: *Sema.Block,
|
||||||
|
base_node_inst: InternPool.TrackedInst.Index,
|
||||||
|
|
||||||
|
/// Lowers the given file as ZON.
|
||||||
|
pub fn run(
|
||||||
|
sema: *Sema,
|
||||||
|
file: *File,
|
||||||
|
file_index: Zcu.File.Index,
|
||||||
|
res_ty: Type,
|
||||||
|
import_loc: LazySrcLoc,
|
||||||
|
block: *Sema.Block,
|
||||||
|
) CompileError!InternPool.Index {
|
||||||
|
const pt = sema.pt;
|
||||||
|
|
||||||
|
_ = try file.getZoir(pt.zcu);
|
||||||
|
|
||||||
|
const tracked_inst = try pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
|
||||||
|
.file = file_index,
|
||||||
|
.inst = .main_struct_inst, // this is the only trackable instruction in a ZON file
|
||||||
|
});
|
||||||
|
|
||||||
|
var lower_zon: LowerZon = .{
|
||||||
|
.sema = sema,
|
||||||
|
.file = file,
|
||||||
|
.file_index = file_index,
|
||||||
|
.import_loc = import_loc,
|
||||||
|
.block = block,
|
||||||
|
.base_node_inst = tracked_inst,
|
||||||
|
};
|
||||||
|
|
||||||
|
try lower_zon.checkType(res_ty);
|
||||||
|
|
||||||
|
return lower_zon.lowerExpr(.root, res_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate that `ty` is a valid ZON type. If not, emit a compile error.
|
||||||
|
/// i.e. no nested optionals, no error sets, etc.
|
||||||
|
fn checkType(self: *LowerZon, ty: Type) !void {
|
||||||
|
var visited: std.AutoHashMapUnmanaged(InternPool.Index, void) = .empty;
|
||||||
|
try self.checkTypeInner(ty, null, &visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checkTypeInner(
|
||||||
|
self: *LowerZon,
|
||||||
|
ty: Type,
|
||||||
|
parent_opt_ty: ?Type,
|
||||||
|
/// Visited structs and unions (not tuples). These are tracked because they are the only way in
|
||||||
|
/// which a type can be self-referential, so must be tracked to avoid loops. Tracking more types
|
||||||
|
/// consumes memory unnecessarily, and would be complicated by optionals.
|
||||||
|
/// Allocated into `self.sema.arena`.
|
||||||
|
visited: *std.AutoHashMapUnmanaged(InternPool.Index, void),
|
||||||
|
) !void {
|
||||||
|
const sema = self.sema;
|
||||||
|
const pt = sema.pt;
|
||||||
|
const zcu = pt.zcu;
|
||||||
|
const ip = &zcu.intern_pool;
|
||||||
|
|
||||||
|
switch (ty.zigTypeTag(zcu)) {
|
||||||
|
.bool,
|
||||||
|
.int,
|
||||||
|
.float,
|
||||||
|
.null,
|
||||||
|
.@"enum",
|
||||||
|
.comptime_float,
|
||||||
|
.comptime_int,
|
||||||
|
.enum_literal,
|
||||||
|
=> {},
|
||||||
|
|
||||||
|
.noreturn,
|
||||||
|
.void,
|
||||||
|
.type,
|
||||||
|
.undefined,
|
||||||
|
.error_union,
|
||||||
|
.error_set,
|
||||||
|
.@"fn",
|
||||||
|
.frame,
|
||||||
|
.@"anyframe",
|
||||||
|
.@"opaque",
|
||||||
|
=> return self.failUnsupportedResultType(ty, null),
|
||||||
|
|
||||||
|
.pointer => {
|
||||||
|
const ptr_info = ty.ptrInfo(zcu);
|
||||||
|
if (!ptr_info.flags.is_const) {
|
||||||
|
return self.failUnsupportedResultType(
|
||||||
|
ty,
|
||||||
|
"ZON does not allow mutable pointers",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
switch (ptr_info.flags.size) {
|
||||||
|
.one => try self.checkTypeInner(
|
||||||
|
.fromInterned(ptr_info.child),
|
||||||
|
parent_opt_ty, // preserved
|
||||||
|
visited,
|
||||||
|
),
|
||||||
|
.slice => try self.checkTypeInner(
|
||||||
|
.fromInterned(ptr_info.child),
|
||||||
|
null,
|
||||||
|
visited,
|
||||||
|
),
|
||||||
|
.many => return self.failUnsupportedResultType(ty, "ZON does not allow many-pointers"),
|
||||||
|
.c => return self.failUnsupportedResultType(ty, "ZON does not allow C pointers"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.optional => if (parent_opt_ty) |p| {
|
||||||
|
return self.failUnsupportedResultType(p, "ZON does not allow nested optionals");
|
||||||
|
} else try self.checkTypeInner(
|
||||||
|
ty.optionalChild(zcu),
|
||||||
|
ty,
|
||||||
|
visited,
|
||||||
|
),
|
||||||
|
.array, .vector => {
|
||||||
|
try self.checkTypeInner(ty.childType(zcu), null, visited);
|
||||||
|
},
|
||||||
|
.@"struct" => if (ty.isTuple(zcu)) {
|
||||||
|
const tuple_info = ip.indexToKey(ty.toIntern()).tuple_type;
|
||||||
|
const field_types = tuple_info.types.get(ip);
|
||||||
|
for (field_types) |field_type| {
|
||||||
|
try self.checkTypeInner(.fromInterned(field_type), null, visited);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const gop = try visited.getOrPut(sema.arena, ty.toIntern());
|
||||||
|
if (gop.found_existing) return;
|
||||||
|
try ty.resolveFields(pt);
|
||||||
|
const struct_info = zcu.typeToStruct(ty).?;
|
||||||
|
for (struct_info.field_types.get(ip)) |field_type| {
|
||||||
|
try self.checkTypeInner(.fromInterned(field_type), null, visited);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.@"union" => {
|
||||||
|
const gop = try visited.getOrPut(sema.arena, ty.toIntern());
|
||||||
|
if (gop.found_existing) return;
|
||||||
|
try ty.resolveFields(pt);
|
||||||
|
const union_info = zcu.typeToUnion(ty).?;
|
||||||
|
for (union_info.field_types.get(ip)) |field_type| {
|
||||||
|
if (field_type != .void_type) {
|
||||||
|
try self.checkTypeInner(.fromInterned(field_type), null, visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodeSrc(self: *LowerZon, node: Zoir.Node.Index) LazySrcLoc {
|
||||||
|
return .{
|
||||||
|
.base_node_inst = self.base_node_inst,
|
||||||
|
.offset = .{ .node_abs = node.getAstNode(self.file.zoir.?) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn failUnsupportedResultType(
|
||||||
|
self: *LowerZon,
|
||||||
|
ty: Type,
|
||||||
|
opt_note: ?[]const u8,
|
||||||
|
) error{ AnalysisFail, OutOfMemory } {
|
||||||
|
@branchHint(.cold);
|
||||||
|
const sema = self.sema;
|
||||||
|
const gpa = sema.gpa;
|
||||||
|
const pt = sema.pt;
|
||||||
|
return sema.failWithOwnedErrorMsg(self.block, msg: {
|
||||||
|
const msg = try sema.errMsg(self.import_loc, "type '{}' is not available in ZON", .{ty.fmt(pt)});
|
||||||
|
errdefer msg.destroy(gpa);
|
||||||
|
if (opt_note) |n| try sema.errNote(self.import_loc, msg, "{s}", .{n});
|
||||||
|
break :msg msg;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fail(
|
||||||
|
self: *LowerZon,
|
||||||
|
node: Zoir.Node.Index,
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) error{ AnalysisFail, OutOfMemory } {
|
||||||
|
@branchHint(.cold);
|
||||||
|
const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args);
|
||||||
|
try self.sema.pt.zcu.errNote(self.import_loc, err_msg, "imported here", .{});
|
||||||
|
return self.sema.failWithOwnedErrorMsg(self.block, err_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerExpr(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError!InternPool.Index {
|
||||||
|
const pt = self.sema.pt;
|
||||||
|
return self.lowerExprInner(node, res_ty) catch |err| switch (err) {
|
||||||
|
error.WrongType => return self.fail(
|
||||||
|
node,
|
||||||
|
"expected type '{}'",
|
||||||
|
.{res_ty.fmt(pt)},
|
||||||
|
),
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerExprInner(
|
||||||
|
self: *LowerZon,
|
||||||
|
node: Zoir.Node.Index,
|
||||||
|
res_ty: Type,
|
||||||
|
) (CompileError || error{WrongType})!InternPool.Index {
|
||||||
|
const pt = self.sema.pt;
|
||||||
|
switch (res_ty.zigTypeTag(pt.zcu)) {
|
||||||
|
.optional => return pt.intern(.{
|
||||||
|
.opt = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.val = if (node.get(self.file.zoir.?) == .null) b: {
|
||||||
|
break :b .none;
|
||||||
|
} else b: {
|
||||||
|
const child_type = res_ty.optionalChild(pt.zcu);
|
||||||
|
break :b try self.lowerExprInner(node, child_type);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.pointer => {
|
||||||
|
const ptr_info = res_ty.ptrInfo(pt.zcu);
|
||||||
|
switch (ptr_info.flags.size) {
|
||||||
|
.one => return pt.intern(.{ .ptr = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.base_addr = .{
|
||||||
|
.uav = .{
|
||||||
|
.orig_ty = res_ty.toIntern(),
|
||||||
|
.val = try self.lowerExprInner(node, .fromInterned(ptr_info.child)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.byte_offset = 0,
|
||||||
|
} }),
|
||||||
|
.slice => return self.lowerSlice(node, res_ty),
|
||||||
|
else => {
|
||||||
|
// Unsupported pointer type, checked in `lower`
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.bool => return self.lowerBool(node),
|
||||||
|
.int, .comptime_int => return self.lowerInt(node, res_ty),
|
||||||
|
.float, .comptime_float => return self.lowerFloat(node, res_ty),
|
||||||
|
.null => return self.lowerNull(node),
|
||||||
|
.@"enum" => return self.lowerEnum(node, res_ty),
|
||||||
|
.enum_literal => return self.lowerEnumLiteral(node),
|
||||||
|
.array => return self.lowerArray(node, res_ty),
|
||||||
|
.@"struct" => return self.lowerStructOrTuple(node, res_ty),
|
||||||
|
.@"union" => return self.lowerUnion(node, res_ty),
|
||||||
|
.vector => return self.lowerVector(node, res_ty),
|
||||||
|
|
||||||
|
.type,
|
||||||
|
.noreturn,
|
||||||
|
.undefined,
|
||||||
|
.error_union,
|
||||||
|
.error_set,
|
||||||
|
.@"fn",
|
||||||
|
.@"opaque",
|
||||||
|
.frame,
|
||||||
|
.@"anyframe",
|
||||||
|
.void,
|
||||||
|
=> return self.fail(node, "type '{}' not available in ZON", .{res_ty.fmt(pt)}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerBool(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
|
||||||
|
return switch (node.get(self.file.zoir.?)) {
|
||||||
|
.true => .bool_true,
|
||||||
|
.false => .bool_false,
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerInt(
|
||||||
|
self: *LowerZon,
|
||||||
|
node: Zoir.Node.Index,
|
||||||
|
res_ty: Type,
|
||||||
|
) !InternPool.Index {
|
||||||
|
@setFloatMode(.strict);
|
||||||
|
return switch (node.get(self.file.zoir.?)) {
|
||||||
|
.int_literal => |int| switch (int) {
|
||||||
|
.small => |val| {
|
||||||
|
const rhs: i32 = val;
|
||||||
|
|
||||||
|
// If our result is a fixed size integer, check that our value is not out of bounds
|
||||||
|
if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
|
||||||
|
const lhs_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||||
|
|
||||||
|
// If lhs is unsigned and rhs is less than 0, we're out of bounds
|
||||||
|
if (lhs_info.signedness == .unsigned and rhs < 0) return self.fail(
|
||||||
|
node,
|
||||||
|
"type '{}' cannot represent integer value '{}'",
|
||||||
|
.{ res_ty.fmt(self.sema.pt), rhs },
|
||||||
|
);
|
||||||
|
|
||||||
|
// If lhs has less than the 32 bits rhs can hold, we need to check the max and
|
||||||
|
// min values
|
||||||
|
if (std.math.cast(u5, lhs_info.bits)) |bits| {
|
||||||
|
const min_int: i32 = if (lhs_info.signedness == .unsigned or bits == 0) b: {
|
||||||
|
break :b 0;
|
||||||
|
} else b: {
|
||||||
|
break :b -(@as(i32, 1) << (bits - 1));
|
||||||
|
};
|
||||||
|
const max_int: i32 = if (bits == 0) b: {
|
||||||
|
break :b 0;
|
||||||
|
} else b: {
|
||||||
|
break :b (@as(i32, 1) << (bits - @intFromBool(lhs_info.signedness == .signed))) - 1;
|
||||||
|
};
|
||||||
|
if (rhs < min_int or rhs > max_int) {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"type '{}' cannot represent integer value '{}'",
|
||||||
|
.{ res_ty.fmt(self.sema.pt), rhs },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .int = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .i64 = rhs },
|
||||||
|
} });
|
||||||
|
},
|
||||||
|
.big => |val| {
|
||||||
|
if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
|
||||||
|
const int_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||||
|
if (!val.fitsInTwosComp(int_info.signedness, int_info.bits)) {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"type '{}' cannot represent integer value '{}'",
|
||||||
|
.{ res_ty.fmt(self.sema.pt), val },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .int = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .big_int = val },
|
||||||
|
} });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.float_literal => |val| {
|
||||||
|
// Check for fractional components
|
||||||
|
if (@rem(val, 1) != 0) {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"fractional component prevents float value '{}' from coercion to type '{}'",
|
||||||
|
.{ val, res_ty.fmt(self.sema.pt) },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a rational representation of the float
|
||||||
|
var rational = try std.math.big.Rational.init(self.sema.arena);
|
||||||
|
rational.setFloat(f128, val) catch |err| switch (err) {
|
||||||
|
error.NonFiniteFloat => unreachable,
|
||||||
|
error.OutOfMemory => return error.OutOfMemory,
|
||||||
|
};
|
||||||
|
|
||||||
|
// The float is reduced in rational.setFloat, so we assert that denominator is equal to
|
||||||
|
// one
|
||||||
|
const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
|
||||||
|
assert(rational.q.toConst().eqlAbs(big_one));
|
||||||
|
|
||||||
|
// Check that the result is in range of the result type
|
||||||
|
const int_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||||
|
if (!rational.p.fitsInTwosComp(int_info.signedness, int_info.bits)) {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"type '{}' cannot represent integer value '{}'",
|
||||||
|
.{ val, res_ty.fmt(self.sema.pt) },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{
|
||||||
|
.int = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .big_int = rational.p.toConst() },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.char_literal => |val| {
|
||||||
|
// If our result is a fixed size integer, check that our value is not out of bounds
|
||||||
|
if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
|
||||||
|
const dest_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||||
|
const unsigned_bits = dest_info.bits - @intFromBool(dest_info.signedness == .signed);
|
||||||
|
if (unsigned_bits < 21) {
|
||||||
|
const out_of_range: u21 = @as(u21, 1) << @intCast(unsigned_bits);
|
||||||
|
if (val >= out_of_range) {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"type '{}' cannot represent integer value '{}'",
|
||||||
|
.{ res_ty.fmt(self.sema.pt), val },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.sema.pt.intern(.{
|
||||||
|
.int = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .i64 = val },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerFloat(
|
||||||
|
self: *LowerZon,
|
||||||
|
node: Zoir.Node.Index,
|
||||||
|
res_ty: Type,
|
||||||
|
) !InternPool.Index {
|
||||||
|
@setFloatMode(.strict);
|
||||||
|
const value = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.int_literal => |int| switch (int) {
|
||||||
|
.small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
|
||||||
|
.big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128)),
|
||||||
|
},
|
||||||
|
.float_literal => |val| try self.sema.pt.floatValue(res_ty, val),
|
||||||
|
.char_literal => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
|
||||||
|
.pos_inf => b: {
|
||||||
|
if (res_ty.toIntern() == .comptime_float_type) return self.fail(
|
||||||
|
node,
|
||||||
|
"expected type '{}'",
|
||||||
|
.{res_ty.fmt(self.sema.pt)},
|
||||||
|
);
|
||||||
|
break :b try self.sema.pt.floatValue(res_ty, std.math.inf(f128));
|
||||||
|
},
|
||||||
|
.neg_inf => b: {
|
||||||
|
if (res_ty.toIntern() == .comptime_float_type) return self.fail(
|
||||||
|
node,
|
||||||
|
"expected type '{}'",
|
||||||
|
.{res_ty.fmt(self.sema.pt)},
|
||||||
|
);
|
||||||
|
break :b try self.sema.pt.floatValue(res_ty, -std.math.inf(f128));
|
||||||
|
},
|
||||||
|
.nan => b: {
|
||||||
|
if (res_ty.toIntern() == .comptime_float_type) return self.fail(
|
||||||
|
node,
|
||||||
|
"expected type '{}'",
|
||||||
|
.{res_ty.fmt(self.sema.pt)},
|
||||||
|
);
|
||||||
|
break :b try self.sema.pt.floatValue(res_ty, std.math.nan(f128));
|
||||||
|
},
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
return value.toIntern();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
|
||||||
|
switch (node.get(self.file.zoir.?)) {
|
||||||
|
.null => return .null_value,
|
||||||
|
else => return error.WrongType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const array_info = res_ty.arrayInfo(self.sema.pt.zcu);
|
||||||
|
const nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.array_literal => |nodes| nodes,
|
||||||
|
.empty_literal => .{ .start = node, .len = 0 },
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (nodes.len != array_info.len) {
|
||||||
|
return error.WrongType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elems = try self.sema.arena.alloc(
|
||||||
|
InternPool.Index,
|
||||||
|
nodes.len + @intFromBool(array_info.sentinel != null),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (0..nodes.len) |i| {
|
||||||
|
elems[i] = try self.lowerExpr(nodes.at(@intCast(i)), array_info.elem_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_info.sentinel) |sentinel| {
|
||||||
|
elems[elems.len - 1] = sentinel.toIntern();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .aggregate = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .elems = elems },
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
switch (node.get(self.file.zoir.?)) {
|
||||||
|
.enum_literal => |field_name| {
|
||||||
|
const field_name_interned = try ip.getOrPutString(
|
||||||
|
self.sema.gpa,
|
||||||
|
self.sema.pt.tid,
|
||||||
|
field_name.get(self.file.zoir.?),
|
||||||
|
.no_embedded_nulls,
|
||||||
|
);
|
||||||
|
const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"enum {} has no member named '{}'",
|
||||||
|
.{
|
||||||
|
res_ty.fmt(self.sema.pt),
|
||||||
|
std.zig.fmtId(field_name.get(self.file.zoir.?)),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = try self.sema.pt.enumValueFieldIndex(res_ty, field_index);
|
||||||
|
|
||||||
|
return value.toIntern();
|
||||||
|
},
|
||||||
|
else => return error.WrongType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
switch (node.get(self.file.zoir.?)) {
|
||||||
|
.enum_literal => |field_name| {
|
||||||
|
const field_name_interned = try ip.getOrPutString(
|
||||||
|
self.sema.gpa,
|
||||||
|
self.sema.pt.tid,
|
||||||
|
field_name.get(self.file.zoir.?),
|
||||||
|
.no_embedded_nulls,
|
||||||
|
);
|
||||||
|
return self.sema.pt.intern(.{ .enum_literal = field_name_interned });
|
||||||
|
},
|
||||||
|
else => return error.WrongType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerStructOrTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
return switch (ip.indexToKey(res_ty.toIntern())) {
|
||||||
|
.tuple_type => self.lowerTuple(node, res_ty),
|
||||||
|
.struct_type => self.lowerStruct(node, res_ty),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
|
||||||
|
const tuple_info = ip.indexToKey(res_ty.toIntern()).tuple_type;
|
||||||
|
|
||||||
|
const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.array_literal => |nodes| nodes,
|
||||||
|
.empty_literal => .{ .start = node, .len = 0 },
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const field_types = tuple_info.types.get(ip);
|
||||||
|
const elems = try self.sema.arena.alloc(InternPool.Index, field_types.len);
|
||||||
|
|
||||||
|
const field_comptime_vals = tuple_info.values.get(ip);
|
||||||
|
if (field_comptime_vals.len > 0) {
|
||||||
|
@memcpy(elems, field_comptime_vals);
|
||||||
|
} else {
|
||||||
|
@memset(elems, .none);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (0..elem_nodes.len) |i| {
|
||||||
|
if (i >= elems.len) {
|
||||||
|
const elem_node = elem_nodes.at(@intCast(i));
|
||||||
|
return self.fail(
|
||||||
|
elem_node,
|
||||||
|
"index {} outside tuple of length {}",
|
||||||
|
.{
|
||||||
|
elems.len,
|
||||||
|
elem_nodes.at(@intCast(i)).getAstNode(self.file.zoir.?),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const val = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(field_types[i]));
|
||||||
|
|
||||||
|
if (elems[i] != .none and val != elems[i]) {
|
||||||
|
const elem_node = elem_nodes.at(@intCast(i));
|
||||||
|
return self.fail(
|
||||||
|
elem_node,
|
||||||
|
"value stored in comptime field does not match the default value of the field",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
elems[i] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (elems, 0..) |val, i| {
|
||||||
|
if (val == .none) {
|
||||||
|
return self.fail(node, "missing tuple field with index {}", .{i});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .aggregate = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .elems = elems },
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
const gpa = self.sema.gpa;
|
||||||
|
|
||||||
|
try res_ty.resolveFields(self.sema.pt);
|
||||||
|
try res_ty.resolveStructFieldInits(self.sema.pt);
|
||||||
|
const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
|
||||||
|
|
||||||
|
const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.struct_literal => |fields| fields,
|
||||||
|
.empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len);
|
||||||
|
|
||||||
|
const field_defaults = struct_info.field_inits.get(ip);
|
||||||
|
if (field_defaults.len > 0) {
|
||||||
|
@memcpy(field_values, field_defaults);
|
||||||
|
} else {
|
||||||
|
@memset(field_values, .none);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (0..fields.names.len) |i| {
|
||||||
|
const field_name = try ip.getOrPutString(
|
||||||
|
gpa,
|
||||||
|
self.sema.pt.tid,
|
||||||
|
fields.names[i].get(self.file.zoir.?),
|
||||||
|
.no_embedded_nulls,
|
||||||
|
);
|
||||||
|
const field_node = fields.vals.at(@intCast(i));
|
||||||
|
|
||||||
|
const name_index = struct_info.nameIndex(ip, field_name) orelse {
|
||||||
|
return self.fail(field_node, "unexpected field '{}'", .{field_name.fmt(ip)});
|
||||||
|
};
|
||||||
|
|
||||||
|
const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);
|
||||||
|
field_values[name_index] = try self.lowerExpr(field_node, field_type);
|
||||||
|
|
||||||
|
if (struct_info.comptime_bits.getBit(ip, name_index)) {
|
||||||
|
const val = ip.indexToKey(field_values[name_index]);
|
||||||
|
const default = ip.indexToKey(field_defaults[name_index]);
|
||||||
|
if (!val.eql(default, ip)) {
|
||||||
|
return self.fail(
|
||||||
|
field_node,
|
||||||
|
"value stored in comptime field does not match the default value of the field",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const field_names = struct_info.field_names.get(ip);
|
||||||
|
for (field_values, field_names) |*value, name| {
|
||||||
|
if (value.* == .none) return self.fail(node, "missing field '{}'", .{name.fmt(ip)});
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .aggregate = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{
|
||||||
|
.elems = field_values,
|
||||||
|
},
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
const gpa = self.sema.gpa;
|
||||||
|
|
||||||
|
const ptr_info = res_ty.ptrInfo(self.sema.pt.zcu);
|
||||||
|
|
||||||
|
assert(ptr_info.flags.size == .slice);
|
||||||
|
|
||||||
|
// String literals
|
||||||
|
const string_alignment = ptr_info.flags.alignment == .none or ptr_info.flags.alignment == .@"1";
|
||||||
|
const string_sentinel = ptr_info.sentinel == .none or ptr_info.sentinel == .zero_u8;
|
||||||
|
if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {
|
||||||
|
switch (node.get(self.file.zoir.?)) {
|
||||||
|
.string_literal => |val| {
|
||||||
|
const ip_str = try ip.getOrPutString(gpa, self.sema.pt.tid, val, .maybe_embedded_nulls);
|
||||||
|
const str_ref = try self.sema.addStrLit(ip_str, val.len);
|
||||||
|
return (try self.sema.coerce(
|
||||||
|
self.block,
|
||||||
|
res_ty,
|
||||||
|
str_ref,
|
||||||
|
self.nodeSrc(node),
|
||||||
|
)).toInterned().?;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice literals
|
||||||
|
const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.array_literal => |nodes| nodes,
|
||||||
|
.empty_literal => .{ .start = node, .len = 0 },
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const elems = try self.sema.arena.alloc(InternPool.Index, elem_nodes.len + @intFromBool(ptr_info.sentinel != .none));
|
||||||
|
|
||||||
|
for (elems, 0..) |*elem, i| {
|
||||||
|
elem.* = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(ptr_info.child));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr_info.sentinel != .none) {
|
||||||
|
elems[elems.len - 1] = ptr_info.sentinel;
|
||||||
|
}
|
||||||
|
|
||||||
|
const array_ty = try self.sema.pt.intern(.{ .array_type = .{
|
||||||
|
.len = elems.len,
|
||||||
|
.sentinel = ptr_info.sentinel,
|
||||||
|
.child = ptr_info.child,
|
||||||
|
} });
|
||||||
|
|
||||||
|
const array = try self.sema.pt.intern(.{ .aggregate = .{
|
||||||
|
.ty = array_ty,
|
||||||
|
.storage = .{ .elems = elems },
|
||||||
|
} });
|
||||||
|
|
||||||
|
const many_item_ptr_type = try self.sema.pt.intern(.{ .ptr_type = .{
|
||||||
|
.child = ptr_info.child,
|
||||||
|
.sentinel = ptr_info.sentinel,
|
||||||
|
.flags = b: {
|
||||||
|
var flags = ptr_info.flags;
|
||||||
|
flags.size = .many;
|
||||||
|
break :b flags;
|
||||||
|
},
|
||||||
|
.packed_offset = ptr_info.packed_offset,
|
||||||
|
} });
|
||||||
|
|
||||||
|
const many_item_ptr = try self.sema.pt.intern(.{
|
||||||
|
.ptr = .{
|
||||||
|
.ty = many_item_ptr_type,
|
||||||
|
.base_addr = .{
|
||||||
|
.uav = .{
|
||||||
|
.orig_ty = (try self.sema.pt.singleConstPtrType(.fromInterned(array_ty))).toIntern(),
|
||||||
|
.val = array,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.byte_offset = 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const len = (try self.sema.pt.intValue(.usize, elems.len)).toIntern();
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .slice = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.ptr = many_item_ptr,
|
||||||
|
.len = len,
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
try res_ty.resolveFields(self.sema.pt);
|
||||||
|
const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;
|
||||||
|
const enum_tag_info = union_info.loadTagType(ip);
|
||||||
|
|
||||||
|
const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.enum_literal => |name| b: {
|
||||||
|
const field_name = try ip.getOrPutString(
|
||||||
|
self.sema.gpa,
|
||||||
|
self.sema.pt.tid,
|
||||||
|
name.get(self.file.zoir.?),
|
||||||
|
.no_embedded_nulls,
|
||||||
|
);
|
||||||
|
break :b .{ field_name, null };
|
||||||
|
},
|
||||||
|
.struct_literal => b: {
|
||||||
|
const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.struct_literal => |fields| fields,
|
||||||
|
else => return self.fail(node, "expected type '{}'", .{res_ty.fmt(self.sema.pt)}),
|
||||||
|
};
|
||||||
|
if (fields.names.len != 1) {
|
||||||
|
return error.WrongType;
|
||||||
|
}
|
||||||
|
const field_name = try ip.getOrPutString(
|
||||||
|
self.sema.gpa,
|
||||||
|
self.sema.pt.tid,
|
||||||
|
fields.names[0].get(self.file.zoir.?),
|
||||||
|
.no_embedded_nulls,
|
||||||
|
);
|
||||||
|
break :b .{ field_name, fields.vals.at(0) };
|
||||||
|
},
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const name_index = enum_tag_info.nameIndex(ip, field_name) orelse {
|
||||||
|
return error.WrongType;
|
||||||
|
};
|
||||||
|
const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_ty), name_index);
|
||||||
|
const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]);
|
||||||
|
const val = if (maybe_field_node) |field_node| b: {
|
||||||
|
if (field_type.toIntern() == .void_type) {
|
||||||
|
return self.fail(field_node, "expected type 'void'", .{});
|
||||||
|
}
|
||||||
|
break :b try self.lowerExpr(field_node, field_type);
|
||||||
|
} else b: {
|
||||||
|
if (field_type.toIntern() != .void_type) {
|
||||||
|
return error.WrongType;
|
||||||
|
}
|
||||||
|
break :b .void_value;
|
||||||
|
};
|
||||||
|
return ip.getUnion(self.sema.pt.zcu.gpa, self.sema.pt.tid, .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.tag = tag.toIntern(),
|
||||||
|
.val = val,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||||
|
const ip = &self.sema.pt.zcu.intern_pool;
|
||||||
|
|
||||||
|
const vector_info = ip.indexToKey(res_ty.toIntern()).vector_type;
|
||||||
|
|
||||||
|
const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||||
|
.array_literal => |nodes| nodes,
|
||||||
|
.empty_literal => .{ .start = node, .len = 0 },
|
||||||
|
else => return error.WrongType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const elems = try self.sema.arena.alloc(InternPool.Index, vector_info.len);
|
||||||
|
|
||||||
|
if (elem_nodes.len != vector_info.len) {
|
||||||
|
return self.fail(
|
||||||
|
node,
|
||||||
|
"expected {} vector elements; found {}",
|
||||||
|
.{ vector_info.len, elem_nodes.len },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (elems, 0..) |*elem, i| {
|
||||||
|
elem.* = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(vector_info.child));
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.sema.pt.intern(.{ .aggregate = .{
|
||||||
|
.ty = res_ty.toIntern(),
|
||||||
|
.storage = .{ .elems = elems },
|
||||||
|
} });
|
||||||
|
}
|
||||||
@ -270,7 +270,7 @@ pub fn getUnsignedIntInner(
|
|||||||
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||||
.undef => unreachable,
|
.undef => unreachable,
|
||||||
.int => |int| switch (int.storage) {
|
.int => |int| switch (int.storage) {
|
||||||
.big_int => |big_int| big_int.to(u64) catch null,
|
.big_int => |big_int| big_int.toInt(u64) catch null,
|
||||||
.u64 => |x| x,
|
.u64 => |x| x,
|
||||||
.i64 => |x| std.math.cast(u64, x),
|
.i64 => |x| std.math.cast(u64, x),
|
||||||
.lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar.toByteUnits() orelse 0,
|
.lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar.toByteUnits() orelse 0,
|
||||||
@ -311,7 +311,7 @@ pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {
|
|||||||
.bool_true => 1,
|
.bool_true => 1,
|
||||||
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||||
.int => |int| switch (int.storage) {
|
.int => |int| switch (int.storage) {
|
||||||
.big_int => |big_int| big_int.to(i64) catch unreachable,
|
.big_int => |big_int| big_int.toInt(i64) catch unreachable,
|
||||||
.i64 => |x| x,
|
.i64 => |x| x,
|
||||||
.u64 => |x| @intCast(x),
|
.u64 => |x| @intCast(x),
|
||||||
.lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
|
.lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
|
||||||
@ -898,7 +898,7 @@ pub fn readFromPackedMemory(
|
|||||||
pub fn toFloat(val: Value, comptime T: type, zcu: *Zcu) T {
|
pub fn toFloat(val: Value, comptime T: type, zcu: *Zcu) T {
|
||||||
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||||
.int => |int| switch (int.storage) {
|
.int => |int| switch (int.storage) {
|
||||||
.big_int => |big_int| @floatCast(bigIntToFloat(big_int.limbs, big_int.positive)),
|
.big_int => |big_int| big_int.toFloat(T),
|
||||||
inline .u64, .i64 => |x| {
|
inline .u64, .i64 => |x| {
|
||||||
if (T == f80) {
|
if (T == f80) {
|
||||||
@panic("TODO we can't lower this properly on non-x86 llvm backend yet");
|
@panic("TODO we can't lower this properly on non-x86 llvm backend yet");
|
||||||
@ -915,25 +915,6 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *Zcu) T {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO move this to std lib big int code
|
|
||||||
fn bigIntToFloat(limbs: []const std.math.big.Limb, positive: bool) f128 {
|
|
||||||
if (limbs.len == 0) return 0;
|
|
||||||
|
|
||||||
const base = std.math.maxInt(std.math.big.Limb) + 1;
|
|
||||||
var result: f128 = 0;
|
|
||||||
var i: usize = limbs.len;
|
|
||||||
while (i != 0) {
|
|
||||||
i -= 1;
|
|
||||||
const limb: f128 = @floatFromInt(limbs[i]);
|
|
||||||
result = @mulAdd(f128, base, result, limb);
|
|
||||||
}
|
|
||||||
if (positive) {
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return -result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clz(val: Value, ty: Type, zcu: *Zcu) u64 {
|
pub fn clz(val: Value, ty: Type, zcu: *Zcu) u64 {
|
||||||
var bigint_buf: BigIntSpace = undefined;
|
var bigint_buf: BigIntSpace = undefined;
|
||||||
const bigint = val.toBigInt(&bigint_buf, zcu);
|
const bigint = val.toBigInt(&bigint_buf, zcu);
|
||||||
@ -1548,7 +1529,7 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, pt: Zcu.PerThread, comptim
|
|||||||
.undef => try pt.undefValue(float_ty),
|
.undef => try pt.undefValue(float_ty),
|
||||||
.int => |int| switch (int.storage) {
|
.int => |int| switch (int.storage) {
|
||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
const float = bigIntToFloat(big_int.limbs, big_int.positive);
|
const float = big_int.toFloat(f128);
|
||||||
return pt.floatValue(float_ty, float);
|
return pt.floatValue(float_ty, float);
|
||||||
},
|
},
|
||||||
inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, pt),
|
inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, pt),
|
||||||
@ -4583,7 +4564,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
|
|||||||
.int => switch (ip.indexToKey(val.toIntern()).int.storage) {
|
.int => switch (ip.indexToKey(val.toIntern()).int.storage) {
|
||||||
.lazy_align, .lazy_size => unreachable, // `val` is fully resolved
|
.lazy_align, .lazy_size => unreachable, // `val` is fully resolved
|
||||||
inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,
|
inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,
|
||||||
.big_int => |big| big.to(T) catch return error.TypeMismatch,
|
.big_int => |big| big.toInt(T) catch return error.TypeMismatch,
|
||||||
},
|
},
|
||||||
|
|
||||||
.float => val.toFloat(T, zcu),
|
.float => val.toFloat(T, zcu),
|
||||||
|
|||||||
40
src/Zcu.zig
40
src/Zcu.zig
@ -39,6 +39,8 @@ const AnalUnit = InternPool.AnalUnit;
|
|||||||
const BuiltinFn = std.zig.BuiltinFn;
|
const BuiltinFn = std.zig.BuiltinFn;
|
||||||
const LlvmObject = @import("codegen/llvm.zig").Object;
|
const LlvmObject = @import("codegen/llvm.zig").Object;
|
||||||
const dev = @import("dev.zig");
|
const dev = @import("dev.zig");
|
||||||
|
const Zoir = std.zig.Zoir;
|
||||||
|
const ZonGen = std.zig.ZonGen;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
@setEvalBranchQuota(4000);
|
@setEvalBranchQuota(4000);
|
||||||
@ -672,6 +674,8 @@ pub const File = struct {
|
|||||||
tree: Ast,
|
tree: Ast,
|
||||||
/// Whether this is populated or not depends on `zir_loaded`.
|
/// Whether this is populated or not depends on `zir_loaded`.
|
||||||
zir: Zir,
|
zir: Zir,
|
||||||
|
/// Cached Zoir, generated lazily.
|
||||||
|
zoir: ?Zoir = null,
|
||||||
/// Module that this file is a part of, managed externally.
|
/// Module that this file is a part of, managed externally.
|
||||||
mod: *Package.Module,
|
mod: *Package.Module,
|
||||||
/// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
|
/// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
|
||||||
@ -704,7 +708,19 @@ pub const File = struct {
|
|||||||
root: *Package.Module,
|
root: *Package.Module,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn getMode(self: File) Ast.Mode {
|
||||||
|
if (std.mem.endsWith(u8, self.sub_file_path, ".zon")) {
|
||||||
|
return .zon;
|
||||||
|
} else if (std.mem.endsWith(u8, self.sub_file_path, ".zig")) {
|
||||||
|
return .zig;
|
||||||
|
} else {
|
||||||
|
// `Module.importFile` rejects all other extensions
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unload(file: *File, gpa: Allocator) void {
|
pub fn unload(file: *File, gpa: Allocator) void {
|
||||||
|
if (file.zoir) |zoir| zoir.deinit(gpa);
|
||||||
file.unloadTree(gpa);
|
file.unloadTree(gpa);
|
||||||
file.unloadSource(gpa);
|
file.unloadSource(gpa);
|
||||||
file.unloadZir(gpa);
|
file.unloadZir(gpa);
|
||||||
@ -778,11 +794,24 @@ pub const File = struct {
|
|||||||
if (file.tree_loaded) return &file.tree;
|
if (file.tree_loaded) return &file.tree;
|
||||||
|
|
||||||
const source = try file.getSource(gpa);
|
const source = try file.getSource(gpa);
|
||||||
file.tree = try Ast.parse(gpa, source.bytes, .zig);
|
file.tree = try Ast.parse(gpa, source.bytes, file.getMode());
|
||||||
file.tree_loaded = true;
|
file.tree_loaded = true;
|
||||||
return &file.tree;
|
return &file.tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getZoir(file: *File, zcu: *Zcu) !*const Zoir {
|
||||||
|
if (file.zoir) |*zoir| return zoir;
|
||||||
|
|
||||||
|
assert(file.tree_loaded);
|
||||||
|
assert(file.tree.mode == .zon);
|
||||||
|
file.zoir = try ZonGen.generate(zcu.gpa, file.tree, .{});
|
||||||
|
if (file.zoir.?.hasCompileErrors()) {
|
||||||
|
try zcu.failed_files.putNoClobber(zcu.gpa, file, null);
|
||||||
|
return error.AnalysisFail;
|
||||||
|
}
|
||||||
|
return &file.zoir.?;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fullyQualifiedNameLen(file: File) usize {
|
pub fn fullyQualifiedNameLen(file: File) usize {
|
||||||
const ext = std.fs.path.extension(file.sub_file_path);
|
const ext = std.fs.path.extension(file.sub_file_path);
|
||||||
return file.sub_file_path.len - ext.len;
|
return file.sub_file_path.len - ext.len;
|
||||||
@ -895,6 +924,7 @@ pub const File = struct {
|
|||||||
pub const Index = InternPool.FileIndex;
|
pub const Index = InternPool.FileIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents the contents of a file loaded with `@embedFile`.
|
||||||
pub const EmbedFile = struct {
|
pub const EmbedFile = struct {
|
||||||
/// Module that this file is a part of, managed externally.
|
/// Module that this file is a part of, managed externally.
|
||||||
owner: *Package.Module,
|
owner: *Package.Module,
|
||||||
@ -2372,6 +2402,12 @@ pub const LazySrcLoc = struct {
|
|||||||
break :inst .{ info.file, info.inst };
|
break :inst .{ info.file, info.inst };
|
||||||
};
|
};
|
||||||
const file = zcu.fileByIndex(file_index);
|
const file = zcu.fileByIndex(file_index);
|
||||||
|
|
||||||
|
// If we're relative to .main_struct_inst, we know the ast node is the root and don't need to resolve the ZIR,
|
||||||
|
// which may not exist e.g. in the case of errors in ZON files.
|
||||||
|
if (zir_inst == .main_struct_inst) return .{ file, 0 };
|
||||||
|
|
||||||
|
// Otherwise, make sure ZIR is loaded.
|
||||||
assert(file.zir_loaded);
|
assert(file.zir_loaded);
|
||||||
|
|
||||||
const zir = file.zir;
|
const zir = file.zir;
|
||||||
@ -3461,8 +3497,6 @@ pub fn atomicPtrAlignment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns null in the following cases:
|
/// Returns null in the following cases:
|
||||||
/// * `@TypeOf(.{})`
|
|
||||||
/// * A struct which has no fields (`struct {}`).
|
|
||||||
/// * Not a struct.
|
/// * Not a struct.
|
||||||
pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType {
|
pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType {
|
||||||
if (ty.ip_index == .none) return null;
|
if (ty.ip_index == .none) return null;
|
||||||
|
|||||||
@ -1867,6 +1867,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
|||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const gpa = zcu.gpa;
|
const gpa = zcu.gpa;
|
||||||
const file = zcu.fileByIndex(file_index);
|
const file = zcu.fileByIndex(file_index);
|
||||||
|
assert(file.getMode() == .zig);
|
||||||
assert(zcu.fileRootType(file_index) == .none);
|
assert(zcu.fileRootType(file_index) == .none);
|
||||||
|
|
||||||
if (file.status != .success_zir) {
|
if (file.status != .success_zir) {
|
||||||
@ -2022,7 +2023,9 @@ pub fn importFile(
|
|||||||
if (mod.deps.get(import_string)) |pkg| {
|
if (mod.deps.get(import_string)) |pkg| {
|
||||||
return pt.importPkg(pkg);
|
return pt.importPkg(pkg);
|
||||||
}
|
}
|
||||||
if (!std.mem.endsWith(u8, import_string, ".zig")) {
|
if (!std.mem.endsWith(u8, import_string, ".zig") and
|
||||||
|
!std.mem.endsWith(u8, import_string, ".zon"))
|
||||||
|
{
|
||||||
return error.ModuleNotFound;
|
return error.ModuleNotFound;
|
||||||
}
|
}
|
||||||
const gpa = zcu.gpa;
|
const gpa = zcu.gpa;
|
||||||
|
|||||||
@ -13776,8 +13776,8 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
|
|||||||
};
|
};
|
||||||
const bit_count = extra.type.scalarBits(self);
|
const bit_count = extra.type.scalarBits(self);
|
||||||
const val: i64 = if (bit_count <= 64)
|
const val: i64 = if (bit_count <= 64)
|
||||||
bigint.to(i64) catch unreachable
|
bigint.toInt(i64) catch unreachable
|
||||||
else if (bigint.to(u64)) |val|
|
else if (bigint.toInt(u64)) |val|
|
||||||
@bitCast(val)
|
@bitCast(val)
|
||||||
else |_| {
|
else |_| {
|
||||||
const limbs = try record.addManyAsSlice(
|
const limbs = try record.addManyAsSlice(
|
||||||
@ -14276,9 +14276,9 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const val: i64 = if (bigint.to(i64)) |val|
|
const val: i64 = if (bigint.toInt(i64)) |val|
|
||||||
val
|
val
|
||||||
else |_| if (bigint.to(u64)) |val|
|
else |_| if (bigint.toInt(u64)) |val|
|
||||||
@bitCast(val)
|
@bitCast(val)
|
||||||
else |_| {
|
else |_| {
|
||||||
const limbs_len = std.math.divCeil(u32, extra.bit_width, 64) catch unreachable;
|
const limbs_len = std.math.divCeil(u32, extra.bit_width, 64) catch unreachable;
|
||||||
|
|||||||
@ -120,7 +120,7 @@ pub fn run(
|
|||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const zoir = try std.zig.ZonGen.generate(gpa, tree);
|
const zoir = try std.zig.ZonGen.generate(gpa, tree, .{});
|
||||||
defer zoir.deinit(gpa);
|
defer zoir.deinit(gpa);
|
||||||
|
|
||||||
if (zoir.hasCompileErrors()) {
|
if (zoir.hasCompileErrors()) {
|
||||||
@ -335,7 +335,7 @@ fn fmtPathFile(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.zon => {
|
.zon => {
|
||||||
var zoir = try std.zig.ZonGen.generate(gpa, tree);
|
var zoir = try std.zig.ZonGen.generate(gpa, tree, .{});
|
||||||
defer zoir.deinit(gpa);
|
defer zoir.deinit(gpa);
|
||||||
|
|
||||||
if (zoir.hasCompileErrors()) {
|
if (zoir.hasCompileErrors()) {
|
||||||
|
|||||||
@ -6278,7 +6278,7 @@ fn cmdAstCheck(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.zon => {
|
.zon => {
|
||||||
const zoir = try ZonGen.generate(gpa, file.tree);
|
const zoir = try ZonGen.generate(gpa, file.tree, .{});
|
||||||
defer zoir.deinit(gpa);
|
defer zoir.deinit(gpa);
|
||||||
|
|
||||||
if (zoir.hasCompileErrors()) {
|
if (zoir.hasCompileErrors()) {
|
||||||
|
|||||||
@ -488,7 +488,6 @@ const Writer = struct {
|
|||||||
.enum_literal,
|
.enum_literal,
|
||||||
.decl_ref,
|
.decl_ref,
|
||||||
.decl_val,
|
.decl_val,
|
||||||
.import,
|
|
||||||
.ret_err_value,
|
.ret_err_value,
|
||||||
.ret_err_value_code,
|
.ret_err_value_code,
|
||||||
.param_anytype,
|
.param_anytype,
|
||||||
@ -515,6 +514,8 @@ const Writer = struct {
|
|||||||
.declaration => try self.writeDeclaration(stream, inst),
|
.declaration => try self.writeDeclaration(stream, inst),
|
||||||
|
|
||||||
.extended => try self.writeExtended(stream, inst),
|
.extended => try self.writeExtended(stream, inst),
|
||||||
|
|
||||||
|
.import => try self.writeImport(stream, inst),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2842,4 +2843,13 @@ const Writer = struct {
|
|||||||
try stream.writeByte('\n');
|
try stream.writeByte('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn writeImport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||||
|
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
|
||||||
|
const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
|
||||||
|
try self.writeInstRef(stream, extra.res_ty);
|
||||||
|
const import_path = self.code.nullTerminatedString(extra.path);
|
||||||
|
try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(import_path)});
|
||||||
|
try self.writeSrcTok(stream, inst_data.src_tok);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
519
test/behavior/zon.zig
Normal file
519
test/behavior/zon.zig
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const expectEqualDeep = std.testing.expectEqualDeep;
|
||||||
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||||
|
const expectEqualStrings = std.testing.expectEqualStrings;
|
||||||
|
|
||||||
|
test "bool" {
|
||||||
|
try expectEqual(true, @as(bool, @import("zon/true.zon")));
|
||||||
|
try expectEqual(false, @as(bool, @import("zon/false.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "optional" {
|
||||||
|
const some: ?u32 = @import("zon/some.zon");
|
||||||
|
const none: ?u32 = @import("zon/none.zon");
|
||||||
|
const @"null": @TypeOf(null) = @import("zon/none.zon");
|
||||||
|
try expectEqual(@as(u32, 10), some);
|
||||||
|
try expectEqual(@as(?u32, null), none);
|
||||||
|
try expectEqual(null, @"null");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "union" {
|
||||||
|
// No tag
|
||||||
|
{
|
||||||
|
const Union = union {
|
||||||
|
x: f32,
|
||||||
|
y: bool,
|
||||||
|
z: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const union1: Union = @import("zon/union1.zon");
|
||||||
|
const union2: Union = @import("zon/union2.zon");
|
||||||
|
const union3: Union = @import("zon/union3.zon");
|
||||||
|
|
||||||
|
try expectEqual(1.5, union1.x);
|
||||||
|
try expectEqual(true, union2.y);
|
||||||
|
try expectEqual({}, union3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inferred tag
|
||||||
|
{
|
||||||
|
const Union = union(enum) {
|
||||||
|
x: f32,
|
||||||
|
y: bool,
|
||||||
|
z: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const union1: Union = comptime @import("zon/union1.zon");
|
||||||
|
const union2: Union = @import("zon/union2.zon");
|
||||||
|
const union3: Union = @import("zon/union3.zon");
|
||||||
|
|
||||||
|
try expectEqual(1.5, union1.x);
|
||||||
|
try expectEqual(true, union2.y);
|
||||||
|
try expectEqual({}, union3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit tag
|
||||||
|
{
|
||||||
|
const Tag = enum(i128) {
|
||||||
|
x = -1,
|
||||||
|
y = 2,
|
||||||
|
z = 1,
|
||||||
|
};
|
||||||
|
const Union = union(Tag) {
|
||||||
|
x: f32,
|
||||||
|
y: bool,
|
||||||
|
z: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const union1: Union = @import("zon/union1.zon");
|
||||||
|
const union2: Union = @import("zon/union2.zon");
|
||||||
|
const union3: Union = @import("zon/union3.zon");
|
||||||
|
|
||||||
|
try expectEqual(1.5, union1.x);
|
||||||
|
try expectEqual(true, union2.y);
|
||||||
|
try expectEqual({}, union3.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "struct" {
|
||||||
|
const Vec0 = struct {};
|
||||||
|
const Vec1 = struct { x: f32 };
|
||||||
|
const Vec2 = struct { x: f32, y: f32 };
|
||||||
|
const Escaped = struct { @"0": f32, foo: f32 };
|
||||||
|
try expectEqual(Vec0{}, @as(Vec0, @import("zon/vec0.zon")));
|
||||||
|
try expectEqual(Vec1{ .x = 1.5 }, @as(Vec1, @import("zon/vec1.zon")));
|
||||||
|
try expectEqual(Vec2{ .x = 1.5, .y = 2 }, @as(Vec2, @import("zon/vec2.zon")));
|
||||||
|
try expectEqual(Escaped{ .@"0" = 1.5, .foo = 2 }, @as(Escaped, @import("zon/escaped_struct.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "struct default fields" {
|
||||||
|
const Vec3 = struct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
z: f32 = 123.4,
|
||||||
|
};
|
||||||
|
try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, @as(Vec3, @import("zon/vec2.zon")));
|
||||||
|
const ascribed: Vec3 = @import("zon/vec2.zon");
|
||||||
|
try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, ascribed);
|
||||||
|
|
||||||
|
const Vec2 = struct {
|
||||||
|
x: f32 = 20.0,
|
||||||
|
y: f32 = 10.0,
|
||||||
|
};
|
||||||
|
try expectEqual(Vec2{ .x = 1.5, .y = 2.0 }, @as(Vec2, @import("zon/vec2.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "struct enum field" {
|
||||||
|
const Struct = struct {
|
||||||
|
x: enum { x, y, z },
|
||||||
|
};
|
||||||
|
try expectEqual(Struct{ .x = .z }, @as(Struct, @import("zon/enum_field.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "tuple" {
|
||||||
|
const Tuple = struct { f32, bool, []const u8, u16 };
|
||||||
|
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "comptime fields" {
|
||||||
|
// Test setting comptime tuple fields to the correct value
|
||||||
|
{
|
||||||
|
const Tuple = struct {
|
||||||
|
comptime f32 = 1.2,
|
||||||
|
comptime bool = true,
|
||||||
|
comptime []const u8 = "hello",
|
||||||
|
comptime u16 = 3,
|
||||||
|
};
|
||||||
|
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test setting comptime struct fields to the correct value
|
||||||
|
{
|
||||||
|
const Vec2 = struct {
|
||||||
|
comptime x: f32 = 1.5,
|
||||||
|
comptime y: f32 = 2.0,
|
||||||
|
};
|
||||||
|
try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/vec2.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test allowing comptime tuple fields to be set to their defaults
|
||||||
|
{
|
||||||
|
const Tuple = struct {
|
||||||
|
f32,
|
||||||
|
bool,
|
||||||
|
[]const u8,
|
||||||
|
u16,
|
||||||
|
comptime u8 = 255,
|
||||||
|
};
|
||||||
|
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test allowing comptime struct fields to be set to their defaults
|
||||||
|
{
|
||||||
|
const Vec2 = struct {
|
||||||
|
comptime x: f32 = 1.5,
|
||||||
|
comptime y: f32 = 2.0,
|
||||||
|
};
|
||||||
|
try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/slice-empty.zon")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "char" {
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(u8, @import("zon/a.zon")));
|
||||||
|
try expectEqual(@as(u8, 'z'), @as(u8, @import("zon/z.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "arrays" {
|
||||||
|
try expectEqual([0]u8{}, @as([0]u8, @import("zon/vec0.zon")));
|
||||||
|
try expectEqual([0:1]u8{}, @as([0:1]u8, @import("zon/vec0.zon")));
|
||||||
|
try expectEqual(1, @as([0:1]u8, @import("zon/vec0.zon"))[0]);
|
||||||
|
try expectEqual([4]u8{ 'a', 'b', 'c', 'd' }, @as([4]u8, @import("zon/array.zon")));
|
||||||
|
try expectEqual([4:2]u8{ 'a', 'b', 'c', 'd' }, @as([4:2]u8, @import("zon/array.zon")));
|
||||||
|
try expectEqual(2, @as([4:2]u8, @import("zon/array.zon"))[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "slices, arrays, tuples" {
|
||||||
|
{
|
||||||
|
const expected_slice: []const u8 = &.{};
|
||||||
|
const found_slice: []const u8 = @import("zon/slice-empty.zon");
|
||||||
|
try expectEqualSlices(u8, expected_slice, found_slice);
|
||||||
|
|
||||||
|
const expected_array: [0]u8 = .{};
|
||||||
|
const found_array: [0]u8 = @import("zon/slice-empty.zon");
|
||||||
|
try expectEqual(expected_array, found_array);
|
||||||
|
|
||||||
|
const T = struct {};
|
||||||
|
const expected_tuple: T = .{};
|
||||||
|
const found_tuple: T = @import("zon/slice-empty.zon");
|
||||||
|
try expectEqual(expected_tuple, found_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const expected_slice: []const u8 = &.{1};
|
||||||
|
const found_slice: []const u8 = @import("zon/slice1_no_newline.zon");
|
||||||
|
try expectEqualSlices(u8, expected_slice, found_slice);
|
||||||
|
|
||||||
|
const expected_array: [1]u8 = .{1};
|
||||||
|
const found_array: [1]u8 = @import("zon/slice1_no_newline.zon");
|
||||||
|
try expectEqual(expected_array, found_array);
|
||||||
|
|
||||||
|
const T = struct { u8 };
|
||||||
|
const expected_tuple: T = .{1};
|
||||||
|
const found_tuple: T = @import("zon/slice1_no_newline.zon");
|
||||||
|
try expectEqual(expected_tuple, found_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const expected_slice: []const u8 = &.{ 'a', 'b', 'c' };
|
||||||
|
const found_slice: []const u8 = @import("zon/slice-abc.zon");
|
||||||
|
try expectEqualSlices(u8, expected_slice, found_slice);
|
||||||
|
|
||||||
|
const expected_array: [3]u8 = .{ 'a', 'b', 'c' };
|
||||||
|
const found_array: [3]u8 = @import("zon/slice-abc.zon");
|
||||||
|
try expectEqual(expected_array, found_array);
|
||||||
|
|
||||||
|
const T = struct { u8, u8, u8 };
|
||||||
|
const expected_tuple: T = .{ 'a', 'b', 'c' };
|
||||||
|
const found_tuple: T = @import("zon/slice-abc.zon");
|
||||||
|
try expectEqual(expected_tuple, found_tuple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "string literals" {
|
||||||
|
try expectEqualSlices(u8, "abc", @import("zon/abc.zon"));
|
||||||
|
try expectEqualSlices(u8, "ab\\c", @import("zon/abc-escaped.zon"));
|
||||||
|
const zero_terminated: [:0]const u8 = @import("zon/abc.zon");
|
||||||
|
try expectEqualDeep(zero_terminated, "abc");
|
||||||
|
try expectEqual(0, zero_terminated[zero_terminated.len]);
|
||||||
|
try expectEqualStrings(
|
||||||
|
\\Hello, world!
|
||||||
|
\\This is a multiline string!
|
||||||
|
\\ There are no escapes, we can, for example, include \n in the string
|
||||||
|
, @import("zon/multiline_string.zon"));
|
||||||
|
try expectEqualStrings("a\nb\x00c", @import("zon/string_embedded_null.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "enum literals" {
|
||||||
|
const Enum = enum {
|
||||||
|
foo,
|
||||||
|
bar,
|
||||||
|
baz,
|
||||||
|
@"0\na",
|
||||||
|
};
|
||||||
|
try expectEqual(Enum.foo, @as(Enum, @import("zon/foo.zon")));
|
||||||
|
try expectEqual(.foo, @as(@TypeOf(.foo), @import("zon/foo.zon")));
|
||||||
|
try expectEqual(Enum.@"0\na", @as(Enum, @import("zon/escaped_enum.zon")));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "int" {
|
||||||
|
const T = struct {
|
||||||
|
u8,
|
||||||
|
i16,
|
||||||
|
i14,
|
||||||
|
i32,
|
||||||
|
i8,
|
||||||
|
i8,
|
||||||
|
u8,
|
||||||
|
u8,
|
||||||
|
u65,
|
||||||
|
u65,
|
||||||
|
i128,
|
||||||
|
i128,
|
||||||
|
i66,
|
||||||
|
i66,
|
||||||
|
i8,
|
||||||
|
i8,
|
||||||
|
i16,
|
||||||
|
i16,
|
||||||
|
i16,
|
||||||
|
i16,
|
||||||
|
i16,
|
||||||
|
i16,
|
||||||
|
u65,
|
||||||
|
i66,
|
||||||
|
i66,
|
||||||
|
u65,
|
||||||
|
i66,
|
||||||
|
i66,
|
||||||
|
u65,
|
||||||
|
i66,
|
||||||
|
i66,
|
||||||
|
};
|
||||||
|
const expected: T = .{
|
||||||
|
// Test various numbers and types
|
||||||
|
10,
|
||||||
|
24,
|
||||||
|
-4,
|
||||||
|
-123,
|
||||||
|
|
||||||
|
// Test limits
|
||||||
|
127,
|
||||||
|
-128,
|
||||||
|
|
||||||
|
// Test characters
|
||||||
|
'a',
|
||||||
|
'z',
|
||||||
|
|
||||||
|
// Test big integers
|
||||||
|
36893488147419103231,
|
||||||
|
36893488147419103231,
|
||||||
|
-18446744073709551615, // Only a big int due to negation
|
||||||
|
-9223372036854775809, // Only a big int due to negation
|
||||||
|
|
||||||
|
// Test big integer limits
|
||||||
|
36893488147419103231,
|
||||||
|
-36893488147419103232,
|
||||||
|
|
||||||
|
// Test parsing whole number floats as integers
|
||||||
|
-1,
|
||||||
|
123,
|
||||||
|
|
||||||
|
// Test non-decimal integers
|
||||||
|
0xff,
|
||||||
|
-0xff,
|
||||||
|
0o77,
|
||||||
|
-0o77,
|
||||||
|
0b11,
|
||||||
|
-0b11,
|
||||||
|
|
||||||
|
// Test non-decimal big integers
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
-0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
-0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
-0x1ffffffffffffffff,
|
||||||
|
};
|
||||||
|
const actual: T = @import("zon/ints.zon");
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "floats" {
|
||||||
|
const T = struct {
|
||||||
|
f16,
|
||||||
|
f32,
|
||||||
|
f64,
|
||||||
|
f128,
|
||||||
|
f16,
|
||||||
|
f16,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f128,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
f32,
|
||||||
|
};
|
||||||
|
const expected: T = .{
|
||||||
|
// Test decimals
|
||||||
|
0.5,
|
||||||
|
123.456,
|
||||||
|
-123.456,
|
||||||
|
42.5,
|
||||||
|
|
||||||
|
// Test whole numbers with and without decimals
|
||||||
|
5.0,
|
||||||
|
5.0,
|
||||||
|
-102,
|
||||||
|
-102,
|
||||||
|
|
||||||
|
// Test characters and negated characters
|
||||||
|
'a',
|
||||||
|
'z',
|
||||||
|
|
||||||
|
// Test big integers
|
||||||
|
36893488147419103231,
|
||||||
|
-36893488147419103231,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
|
||||||
|
// Exponents, underscores
|
||||||
|
123.0E+77,
|
||||||
|
|
||||||
|
// Hexadecimal
|
||||||
|
0x103.70p-5,
|
||||||
|
-0x103.70,
|
||||||
|
0x1234_5678.9ABC_CDEFp-10,
|
||||||
|
};
|
||||||
|
const actual: T = @import("zon/floats.zon");
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "inf and nan" {
|
||||||
|
// f32
|
||||||
|
{
|
||||||
|
const actual: struct { f32, f32, f32 } = @import("zon/inf_and_nan.zon");
|
||||||
|
try expect(std.math.isNan(actual[0]));
|
||||||
|
try expect(std.math.isPositiveInf(actual[1]));
|
||||||
|
try expect(std.math.isNegativeInf(actual[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// f128
|
||||||
|
{
|
||||||
|
const actual: struct { f128, f128, f128 } = @import("zon/inf_and_nan.zon");
|
||||||
|
try expect(std.math.isNan(actual[0]));
|
||||||
|
try expect(std.math.isPositiveInf(actual[1]));
|
||||||
|
try expect(std.math.isNegativeInf(actual[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "vector" {
|
||||||
|
{
|
||||||
|
const actual: @Vector(0, bool) = @import("zon/vec0.zon");
|
||||||
|
const expected: @Vector(0, bool) = .{};
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual: @Vector(3, bool) = @import("zon/vec3_bool.zon");
|
||||||
|
const expected: @Vector(3, bool) = .{ false, false, true };
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const actual: @Vector(0, f32) = @import("zon/vec0.zon");
|
||||||
|
const expected: @Vector(0, f32) = .{};
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual: @Vector(3, f32) = @import("zon/vec3_float.zon");
|
||||||
|
const expected: @Vector(3, f32) = .{ 1.5, 2.5, 3.5 };
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const actual: @Vector(0, u8) = @import("zon/vec0.zon");
|
||||||
|
const expected: @Vector(0, u8) = .{};
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual: @Vector(3, u8) = @import("zon/vec3_int.zon");
|
||||||
|
const expected: @Vector(3, u8) = .{ 2, 4, 6 };
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const actual: @Vector(0, *const u8) = @import("zon/vec0.zon");
|
||||||
|
const expected: @Vector(0, *const u8) = .{};
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual: @Vector(3, *const u8) = @import("zon/vec3_int.zon");
|
||||||
|
const expected: @Vector(3, *const u8) = .{ &2, &4, &6 };
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const actual: @Vector(0, ?*const u8) = @import("zon/vec0.zon");
|
||||||
|
const expected: @Vector(0, ?*const u8) = .{};
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual: @Vector(3, ?*const u8) = @import("zon/vec3_int_opt.zon");
|
||||||
|
const expected: @Vector(3, ?*const u8) = .{ &2, null, &6 };
|
||||||
|
try expectEqual(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "pointers" {
|
||||||
|
// Primitive with varying levels of pointers
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(*const u8, @import("zon/a.zon")).*);
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(*const *const u8, @import("zon/a.zon")).*.*);
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(*const *const *const u8, @import("zon/a.zon")).*.*.*);
|
||||||
|
|
||||||
|
// Primitive optional with varying levels of pointers
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(?*const u8, @import("zon/a.zon")).?.*);
|
||||||
|
try expectEqual(null, @as(?*const u8, @import("zon/none.zon")));
|
||||||
|
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(*const ?u8, @import("zon/a.zon")).*.?);
|
||||||
|
try expectEqual(null, @as(*const ?u8, @import("zon/none.zon")).*);
|
||||||
|
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(?*const *const u8, @import("zon/a.zon")).?.*.*);
|
||||||
|
try expectEqual(null, @as(?*const *const u8, @import("zon/none.zon")));
|
||||||
|
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(*const ?*const u8, @import("zon/a.zon")).*.?.*);
|
||||||
|
try expectEqual(null, @as(*const ?*const u8, @import("zon/none.zon")).*);
|
||||||
|
|
||||||
|
try expectEqual(@as(u8, 'a'), @as(*const *const ?u8, @import("zon/a.zon")).*.*.?);
|
||||||
|
try expectEqual(null, @as(*const *const ?u8, @import("zon/none.zon")).*.*);
|
||||||
|
|
||||||
|
try expectEqual([3]u8{ 2, 4, 6 }, @as(*const [3]u8, @import("zon/vec3_int.zon")).*);
|
||||||
|
|
||||||
|
// A complicated type with nested internal pointers and string allocations
|
||||||
|
{
|
||||||
|
const Inner = struct {
|
||||||
|
f1: *const ?*const []const u8,
|
||||||
|
f2: *const ?*const []const u8,
|
||||||
|
};
|
||||||
|
const Outer = struct {
|
||||||
|
f1: *const ?*const Inner,
|
||||||
|
f2: *const ?*const Inner,
|
||||||
|
};
|
||||||
|
const expected: Outer = .{
|
||||||
|
.f1 = &&.{
|
||||||
|
.f1 = &null,
|
||||||
|
.f2 = &&"foo",
|
||||||
|
},
|
||||||
|
.f2 = &null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const found: ?*const Outer = @import("zon/complex.zon");
|
||||||
|
try std.testing.expectEqualDeep(expected, found.?.*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "recursive" {
|
||||||
|
const Recursive = struct { foo: ?*const @This() };
|
||||||
|
const expected: Recursive = .{ .foo = &.{ .foo = null } };
|
||||||
|
try expectEqualDeep(expected, @as(Recursive, @import("zon/recursive.zon")));
|
||||||
|
}
|
||||||
1
test/behavior/zon/a.zon
Normal file
1
test/behavior/zon/a.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
'a'
|
||||||
1
test/behavior/zon/abc-escaped.zon
Normal file
1
test/behavior/zon/abc-escaped.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
"ab\\c"
|
||||||
1
test/behavior/zon/abc.zon
Normal file
1
test/behavior/zon/abc.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
"abc"
|
||||||
1
test/behavior/zon/array.zon
Normal file
1
test/behavior/zon/array.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ 'a', 'b', 'c', 'd' }
|
||||||
7
test/behavior/zon/complex.zon
Normal file
7
test/behavior/zon/complex.zon
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.{
|
||||||
|
.f1 = .{
|
||||||
|
.f1 = null,
|
||||||
|
.f2 = "foo",
|
||||||
|
},
|
||||||
|
.f2 = null,
|
||||||
|
}
|
||||||
1
test/behavior/zon/enum_field.zon
Normal file
1
test/behavior/zon/enum_field.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ .x = .z }
|
||||||
1
test/behavior/zon/escaped_enum.zon
Normal file
1
test/behavior/zon/escaped_enum.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.@"0\na"
|
||||||
2
test/behavior/zon/escaped_struct.zon
Normal file
2
test/behavior/zon/escaped_struct.zon
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
.{ .@"0" = 1.5, .@"foo" = 2 }
|
||||||
4
test/behavior/zon/false.zon
Normal file
4
test/behavior/zon/false.zon
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Comment
|
||||||
|
false // Another comment
|
||||||
|
// Yet another comment
|
||||||
|
|
||||||
25
test/behavior/zon/floats.zon
Normal file
25
test/behavior/zon/floats.zon
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.{
|
||||||
|
0.5,
|
||||||
|
123.456,
|
||||||
|
-123.456,
|
||||||
|
42.5,
|
||||||
|
|
||||||
|
5.0,
|
||||||
|
5,
|
||||||
|
-102.0,
|
||||||
|
-102,
|
||||||
|
|
||||||
|
'a',
|
||||||
|
'z',
|
||||||
|
|
||||||
|
36893488147419103231,
|
||||||
|
-36893488147419103231,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
|
||||||
|
12_3.0E+77,
|
||||||
|
|
||||||
|
0x103.70p-5,
|
||||||
|
-0x103.70,
|
||||||
|
0x1234_5678.9ABC_CDEFp-10,
|
||||||
|
}
|
||||||
1
test/behavior/zon/foo.zon
Normal file
1
test/behavior/zon/foo.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.foo
|
||||||
5
test/behavior/zon/inf_and_nan.zon
Normal file
5
test/behavior/zon/inf_and_nan.zon
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.{
|
||||||
|
nan,
|
||||||
|
inf,
|
||||||
|
-inf,
|
||||||
|
}
|
||||||
40
test/behavior/zon/ints.zon
Normal file
40
test/behavior/zon/ints.zon
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
.{
|
||||||
|
10,
|
||||||
|
24,
|
||||||
|
-4,
|
||||||
|
-123,
|
||||||
|
|
||||||
|
127,
|
||||||
|
-128,
|
||||||
|
|
||||||
|
'a',
|
||||||
|
'z',
|
||||||
|
|
||||||
|
36893488147419103231,
|
||||||
|
368934_881_474191032_31,
|
||||||
|
-18446744073709551615,
|
||||||
|
-9223372036854775809,
|
||||||
|
|
||||||
|
36893488147419103231,
|
||||||
|
-36893488147419103232,
|
||||||
|
|
||||||
|
-1.0,
|
||||||
|
123.0,
|
||||||
|
|
||||||
|
0xff,
|
||||||
|
-0xff,
|
||||||
|
0o77,
|
||||||
|
-0o77,
|
||||||
|
0b11,
|
||||||
|
-0b11,
|
||||||
|
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
0x1ffffffffffffffff,
|
||||||
|
-0x1ffffffffffffffff,
|
||||||
|
0o3777777777777777777777,
|
||||||
|
0o3777777777777777777777,
|
||||||
|
-0o3777777777777777777777,
|
||||||
|
0b11111111111111111111111111111111111111111111111111111111111111111,
|
||||||
|
0b11111111111111111111111111111111111111111111111111111111111111111,
|
||||||
|
-0b11111111111111111111111111111111111111111111111111111111111111111,
|
||||||
|
}
|
||||||
4
test/behavior/zon/multiline_string.zon
Normal file
4
test/behavior/zon/multiline_string.zon
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// zig fmt: off
|
||||||
|
\\Hello, world!
|
||||||
|
\\This is a multiline string!
|
||||||
|
\\ There are no escapes, we can, for example, include \n in the string
|
||||||
1
test/behavior/zon/none.zon
Normal file
1
test/behavior/zon/none.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
null
|
||||||
1
test/behavior/zon/recursive.zon
Normal file
1
test/behavior/zon/recursive.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ .foo = .{ .foo = null } }
|
||||||
1
test/behavior/zon/slice-abc.zon
Normal file
1
test/behavior/zon/slice-abc.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{'a', 'b', 'c'}
|
||||||
1
test/behavior/zon/slice-empty.zon
Normal file
1
test/behavior/zon/slice-empty.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{}
|
||||||
1
test/behavior/zon/slice1_no_newline.zon
Normal file
1
test/behavior/zon/slice1_no_newline.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ 1 }
|
||||||
1
test/behavior/zon/some.zon
Normal file
1
test/behavior/zon/some.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
10
|
||||||
1
test/behavior/zon/string_embedded_null.zon
Normal file
1
test/behavior/zon/string_embedded_null.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
"a\nb\x00c"
|
||||||
1
test/behavior/zon/true.zon
Normal file
1
test/behavior/zon/true.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
true
|
||||||
1
test/behavior/zon/tuple.zon
Normal file
1
test/behavior/zon/tuple.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ 1.2, true, "hello", 3 }
|
||||||
1
test/behavior/zon/union1.zon
Normal file
1
test/behavior/zon/union1.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ .x = 1.5 }
|
||||||
1
test/behavior/zon/union2.zon
Normal file
1
test/behavior/zon/union2.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ .y = true }
|
||||||
1
test/behavior/zon/union3.zon
Normal file
1
test/behavior/zon/union3.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.z
|
||||||
1
test/behavior/zon/vec0.zon
Normal file
1
test/behavior/zon/vec0.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{}
|
||||||
1
test/behavior/zon/vec1.zon
Normal file
1
test/behavior/zon/vec1.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ .x = 1.5 }
|
||||||
1
test/behavior/zon/vec2.zon
Normal file
1
test/behavior/zon/vec2.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ .x = 1.5, .y = 2 }
|
||||||
1
test/behavior/zon/vec3_bool.zon
Normal file
1
test/behavior/zon/vec3_bool.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ false, false, true }
|
||||||
1
test/behavior/zon/vec3_float.zon
Normal file
1
test/behavior/zon/vec3_float.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ 1.5, 2.5, 3.5 }
|
||||||
1
test/behavior/zon/vec3_int.zon
Normal file
1
test/behavior/zon/vec3_int.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ 2, 4, 6 }
|
||||||
1
test/behavior/zon/vec3_int_opt.zon
Normal file
1
test/behavior/zon/vec3_int_opt.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
.{ 2, null, 6 }
|
||||||
1
test/behavior/zon/z.zon
Normal file
1
test/behavior/zon/z.zon
Normal file
@ -0,0 +1 @@
|
|||||||
|
'z'
|
||||||
9
test/cases/compile_errors/@import_zon_addr_slice.zig
Normal file
9
test/cases/compile_errors/@import_zon_addr_slice.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub fn main() void {
|
||||||
|
const f: struct { value: []const i32 } = @import("zon/addr_slice.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/addr_slice.zon
|
||||||
|
//
|
||||||
|
// addr_slice.zon:2:14: error: pointers are not available in ZON
|
||||||
10
test/cases/compile_errors/@import_zon_array_len.zig
Normal file
10
test/cases/compile_errors/@import_zon_array_len.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: [4]u8 = @import("zon/array.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/array.zon
|
||||||
|
//
|
||||||
|
// array.zon:1:2: error: expected type '[4]u8'
|
||||||
|
// tmp.zig:2:30: note: imported here
|
||||||
9
test/cases/compile_errors/@import_zon_bad_import.zig
Normal file
9
test/cases/compile_errors/@import_zon_bad_import.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
_ = @import(
|
||||||
|
"bogus-does-not-exist.zon",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
//
|
||||||
|
// :3:9: error: unable to open 'bogus-does-not-exist.zon': FileNotFound
|
||||||
125
test/cases/compile_errors/@import_zon_bad_type.zig
Normal file
125
test/cases/compile_errors/@import_zon_bad_type.zig
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
export fn testVoid() void {
|
||||||
|
const f: void = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testInStruct() void {
|
||||||
|
const f: struct { f: [*]const u8 } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testError() void {
|
||||||
|
const f: struct { error{foo} } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testInUnion() void {
|
||||||
|
const f: union(enum) { a: void, b: [*c]const u8 } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testInVector() void {
|
||||||
|
const f: @Vector(0, [*c]const u8) = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testInOpt() void {
|
||||||
|
const f: *const ?[*c]const u8 = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testComptimeField() void {
|
||||||
|
const f: struct { comptime foo: ??u8 = null } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testEnumLiteral() void {
|
||||||
|
const f: @TypeOf(.foo) = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testNestedOpt1() void {
|
||||||
|
const f: ??u8 = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testNestedOpt2() void {
|
||||||
|
const f: ?*const ?u8 = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testNestedOpt3() void {
|
||||||
|
const f: *const ?*const ?*const u8 = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testOpt() void {
|
||||||
|
const f: ?u8 = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testNonExhaustiveEnum() void {
|
||||||
|
const f: enum(u8) { _ } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testUntaggedUnion() void {
|
||||||
|
const f: union { foo: void } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testTaggedUnionVoid() void {
|
||||||
|
const f: union(enum) { foo: void } = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testVisited() void {
|
||||||
|
const V = struct {
|
||||||
|
?f32, // Adds `?f32` to the visited list
|
||||||
|
??f32, // `?f32` is already visited, we need to detect the nested opt anyway
|
||||||
|
f32,
|
||||||
|
};
|
||||||
|
const f: V = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testMutablePointer() void {
|
||||||
|
const f: *i32 = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/neg_inf.zon
|
||||||
|
//
|
||||||
|
// tmp.zig:2:29: error: type 'void' is not available in ZON
|
||||||
|
// tmp.zig:7:50: error: type '[*]const u8' is not available in ZON
|
||||||
|
// tmp.zig:7:50: note: ZON does not allow many-pointers
|
||||||
|
// tmp.zig:12:46: error: type 'error{foo}' is not available in ZON
|
||||||
|
// tmp.zig:17:65: error: type '[*c]const u8' is not available in ZON
|
||||||
|
// tmp.zig:17:65: note: ZON does not allow C pointers
|
||||||
|
// tmp.zig:22:49: error: type '[*c]const u8' is not available in ZON
|
||||||
|
// tmp.zig:22:49: note: ZON does not allow C pointers
|
||||||
|
// tmp.zig:27:45: error: type '[*c]const u8' is not available in ZON
|
||||||
|
// tmp.zig:27:45: note: ZON does not allow C pointers
|
||||||
|
// tmp.zig:32:61: error: type '??u8' is not available in ZON
|
||||||
|
// tmp.zig:32:61: note: ZON does not allow nested optionals
|
||||||
|
// tmp.zig:42:29: error: type '??u8' is not available in ZON
|
||||||
|
// tmp.zig:42:29: note: ZON does not allow nested optionals
|
||||||
|
// tmp.zig:47:36: error: type '?*const ?u8' is not available in ZON
|
||||||
|
// tmp.zig:47:36: note: ZON does not allow nested optionals
|
||||||
|
// tmp.zig:52:50: error: type '?*const ?*const u8' is not available in ZON
|
||||||
|
// tmp.zig:52:50: note: ZON does not allow nested optionals
|
||||||
|
// tmp.zig:82:26: error: type '??f32' is not available in ZON
|
||||||
|
// tmp.zig:82:26: note: ZON does not allow nested optionals
|
||||||
|
// tmp.zig:87:29: error: type '*i32' is not available in ZON
|
||||||
|
// tmp.zig:87:29: note: ZON does not allow mutable pointers
|
||||||
|
// neg_inf.zon:1:1: error: expected type '@Type(.enum_literal)'
|
||||||
|
// tmp.zig:37:38: note: imported here
|
||||||
|
// neg_inf.zon:1:1: error: expected type '?u8'
|
||||||
|
// tmp.zig:57:28: note: imported here
|
||||||
|
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_490'
|
||||||
|
// tmp.zig:62:39: note: imported here
|
||||||
|
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_492'
|
||||||
|
// tmp.zig:67:44: note: imported here
|
||||||
|
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_495'
|
||||||
|
// tmp.zig:72:50: note: imported here
|
||||||
10
test/cases/compile_errors/@import_zon_comptime_inf.zig
Normal file
10
test/cases/compile_errors/@import_zon_comptime_inf.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: comptime_float = @import("zon/inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/inf.zon
|
||||||
|
//
|
||||||
|
// inf.zon:1:1: error: expected type 'comptime_float'
|
||||||
|
// tmp.zig:2:39: note: imported here
|
||||||
10
test/cases/compile_errors/@import_zon_comptime_nan.zig
Normal file
10
test/cases/compile_errors/@import_zon_comptime_nan.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: comptime_float = @import("zon/nan.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/nan.zon
|
||||||
|
//
|
||||||
|
// nan.zon:1:1: error: expected type 'comptime_float'
|
||||||
|
// tmp.zig:2:39: note: imported here
|
||||||
10
test/cases/compile_errors/@import_zon_comptime_neg_inf.zig
Normal file
10
test/cases/compile_errors/@import_zon_comptime_neg_inf.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: comptime_float = @import("zon/neg_inf.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/neg_inf.zon
|
||||||
|
//
|
||||||
|
// neg_inf.zon:1:1: error: expected type 'comptime_float'
|
||||||
|
// tmp.zig:2:39: note: imported here
|
||||||
9
test/cases/compile_errors/@import_zon_doc_comment.zig
Normal file
9
test/cases/compile_errors/@import_zon_doc_comment.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: struct { foo: type } = @import("zon/doc_comment.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/doc_comment.zon
|
||||||
|
//
|
||||||
|
// doc_comment.zon:1:1: error: expected expression, found 'a document comment'
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: f32 = @import("zon/double_negation_float.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/double_negation_float.zon
|
||||||
|
//
|
||||||
|
// double_negation_float.zon:1:1: error: expected number or 'inf' after '-'
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: i32 = @import("zon/double_negation_int.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/double_negation_int.zon
|
||||||
|
//
|
||||||
|
// double_negation_int.zon:1:1: error: expected number or 'inf' after '-'
|
||||||
11
test/cases/compile_errors/@import_zon_enum_embedded_null.zig
Normal file
11
test/cases/compile_errors/@import_zon_enum_embedded_null.zig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
export fn entry() void {
|
||||||
|
const E = enum { foo };
|
||||||
|
const f: struct { E, E } = @import("zon/enum_embedded_null.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/enum_embedded_null.zon
|
||||||
|
//
|
||||||
|
// enum_embedded_null.zon:2:6: error: identifier cannot contain null bytes
|
||||||
11
test/cases/compile_errors/@import_zon_expected_void.zig
Normal file
11
test/cases/compile_errors/@import_zon_expected_void.zig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const U = union(enum) { a: void };
|
||||||
|
const f: U = @import("zon/simple_union.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/simple_union.zon
|
||||||
|
//
|
||||||
|
// simple_union.zon:1:9: error: expected type 'void'
|
||||||
|
// tmp.zig:3:26: note: imported here
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: u8 = @import("zon/invalid_character.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/invalid_character.zon
|
||||||
|
//
|
||||||
|
// invalid_character.zon:1:3: error: invalid escape character: 'a'
|
||||||
9
test/cases/compile_errors/@import_zon_invalid_number.zig
Normal file
9
test/cases/compile_errors/@import_zon_invalid_number.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: u128 = @import("zon/invalid_number.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/invalid_number.zon
|
||||||
|
//
|
||||||
|
// invalid_number.zon:1:19: error: invalid digit 'a' for decimal base
|
||||||
9
test/cases/compile_errors/@import_zon_invalid_string.zig
Normal file
9
test/cases/compile_errors/@import_zon_invalid_string.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: []const u8 = @import("zon/invalid_string.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/invalid_string.zon
|
||||||
|
//
|
||||||
|
// invalid_string.zon:1:5: error: invalid escape character: 'a'
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: u128 = @import("zon/leading_zero_in_integer.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/leading_zero_in_integer.zon
|
||||||
|
//
|
||||||
|
// leading_zero_in_integer.zon:1:1: error: number '0012' has leading zero
|
||||||
|
// leading_zero_in_integer.zon:1:1: note: use '0o' prefix for octal literals
|
||||||
9
test/cases/compile_errors/@import_zon_neg_char.zig
Normal file
9
test/cases/compile_errors/@import_zon_neg_char.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: u8 = @import("zon/neg_char.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/neg_char.zon
|
||||||
|
//
|
||||||
|
// neg_char.zon:1:1: error: expected number or 'inf' after '-'
|
||||||
9
test/cases/compile_errors/@import_zon_neg_nan.zig
Normal file
9
test/cases/compile_errors/@import_zon_neg_nan.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: u8 = @import("zon/neg_nan.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/neg_nan.zon
|
||||||
|
//
|
||||||
|
// neg_nan.zon:1:1: error: expected number or 'inf' after '-'
|
||||||
11
test/cases/compile_errors/@import_zon_negative_zero.zig
Normal file
11
test/cases/compile_errors/@import_zon_negative_zero.zig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: i8 = @import("zon/negative_zero.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/negative_zero.zon
|
||||||
|
//
|
||||||
|
// negative_zero.zon:1:2: error: integer literal '-0' is ambiguous
|
||||||
|
// negative_zero.zon:1:2: note: use '0' for an integer zero
|
||||||
|
// negative_zero.zon:1:2: note: use '-0.0' for a floating-point signed zero
|
||||||
9
test/cases/compile_errors/@import_zon_no_rt.zig
Normal file
9
test/cases/compile_errors/@import_zon_no_rt.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f = @import("zon/simple_union.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/simple_union.zon
|
||||||
|
//
|
||||||
|
// tmp.zig:2:23: error: '@import' of ZON must have a known result type
|
||||||
10
test/cases/compile_errors/@import_zon_number_fail_limits.zig
Normal file
10
test/cases/compile_errors/@import_zon_number_fail_limits.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: i66 = @import("zon/large_number.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/large_number.zon
|
||||||
|
//
|
||||||
|
// large_number.zon:1:1: error: type 'i66' cannot represent integer value '36893488147419103232'
|
||||||
|
// tmp.zig:2:28: note: imported here
|
||||||
16
test/cases/compile_errors/@import_zon_oob_char_0.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_char_0.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
{
|
||||||
|
const f: u6 = @import("zon/char_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const f: u5 = @import("zon/char_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/char_32.zon
|
||||||
|
//
|
||||||
|
// char_32.zon:1:1: error: type 'u5' cannot represent integer value '32'
|
||||||
|
// tmp.zig:7:31: note: imported here
|
||||||
16
test/cases/compile_errors/@import_zon_oob_char_1.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_char_1.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
{
|
||||||
|
const f: i7 = @import("zon/char_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const f: i6 = @import("zon/char_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/char_32.zon
|
||||||
|
//
|
||||||
|
// char_32.zon:1:1: error: type 'i6' cannot represent integer value '32'
|
||||||
|
// tmp.zig:7:31: note: imported here
|
||||||
16
test/cases/compile_errors/@import_zon_oob_int_0.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_int_0.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
{
|
||||||
|
const f: u6 = @import("zon/int_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const f: u5 = @import("zon/int_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/int_32.zon
|
||||||
|
//
|
||||||
|
// int_32.zon:1:1: error: type 'u5' cannot represent integer value '32'
|
||||||
|
// tmp.zig:7:31: note: imported here
|
||||||
16
test/cases/compile_errors/@import_zon_oob_int_1.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_int_1.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
{
|
||||||
|
const f: i7 = @import("zon/int_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const f: i6 = @import("zon/int_32.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/int_32.zon
|
||||||
|
//
|
||||||
|
// int_32.zon:1:1: error: type 'i6' cannot represent integer value '32'
|
||||||
|
// tmp.zig:7:31: note: imported here
|
||||||
16
test/cases/compile_errors/@import_zon_oob_int_2.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_int_2.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
{
|
||||||
|
const f: i7 = @import("zon/int_neg_33.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const f: i6 = @import("zon/int_neg_33.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/int_neg_33.zon
|
||||||
|
//
|
||||||
|
// int_neg_33.zon:1:1: error: type 'i6' cannot represent integer value '-33'
|
||||||
|
// tmp.zig:7:31: note: imported here
|
||||||
10
test/cases/compile_errors/@import_zon_oob_int_3.zig
Normal file
10
test/cases/compile_errors/@import_zon_oob_int_3.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: u64 = @import("zon/int_neg_33.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/int_neg_33.zon
|
||||||
|
//
|
||||||
|
// int_neg_33.zon:1:1: error: type 'u64' cannot represent integer value '-33'
|
||||||
|
// tmp.zig:2:28: note: imported here
|
||||||
82
test/cases/compile_errors/@import_zon_opt_in_err.zig
Normal file
82
test/cases/compile_errors/@import_zon_opt_in_err.zig
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
export fn testFloatA() void {
|
||||||
|
const f: ?f32 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testFloatB() void {
|
||||||
|
const f: *const ?f32 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testFloatC() void {
|
||||||
|
const f: ?*const f32 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testBool() void {
|
||||||
|
const f: ?bool = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testInt() void {
|
||||||
|
const f: ?i32 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Enum = enum { foo };
|
||||||
|
export fn testEnum() void {
|
||||||
|
const f: ?Enum = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testEnumLit() void {
|
||||||
|
const f: ?@TypeOf(.foo) = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testArray() void {
|
||||||
|
const f: ?[1]u8 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Union = union {};
|
||||||
|
export fn testUnion() void {
|
||||||
|
const f: ?Union = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testSlice() void {
|
||||||
|
const f: ?[]const u8 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn testVector() void {
|
||||||
|
const f: ?@Vector(3, f32) = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/vec2.zon
|
||||||
|
//
|
||||||
|
// vec2.zon:1:2: error: expected type '?f32'
|
||||||
|
// tmp.zig:2:29: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '*const ?f32'
|
||||||
|
// tmp.zig:7:36: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?*const f32'
|
||||||
|
// tmp.zig:12:36: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?bool'
|
||||||
|
// tmp.zig:17:30: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?i32'
|
||||||
|
// tmp.zig:22:29: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?tmp.Enum'
|
||||||
|
// tmp.zig:28:30: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?@Type(.enum_literal)'
|
||||||
|
// tmp.zig:33:39: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?[1]u8'
|
||||||
|
// tmp.zig:38:31: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?tmp.Union'
|
||||||
|
// tmp.zig:44:31: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?[]const u8'
|
||||||
|
// tmp.zig:49:36: note: imported here
|
||||||
|
// vec2.zon:1:2: error: expected type '?@Vector(3, f32)'
|
||||||
|
// tmp.zig:54:41: note: imported here
|
||||||
19
test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
Normal file
19
test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const Struct = struct { f: bool };
|
||||||
|
export fn testStruct() void {
|
||||||
|
const f: ?Struct = @import("zon/nan.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tuple = struct { bool };
|
||||||
|
export fn testTuple() void {
|
||||||
|
const f: ?Tuple = @import("zon/nan.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/nan.zon
|
||||||
|
//
|
||||||
|
//nan.zon:1:1: error: expected type '?tmp.Struct'
|
||||||
|
//tmp.zig:3:32: note: imported here
|
||||||
|
//nan.zon:1:1: error: expected type '?struct { bool }'
|
||||||
|
//tmp.zig:9:31: note: imported here
|
||||||
10
test/cases/compile_errors/@import_zon_string_as_array.zig
Normal file
10
test/cases/compile_errors/@import_zon_string_as_array.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: [5]u8 = @import("zon/hello.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/hello.zon
|
||||||
|
//
|
||||||
|
// hello.zon:1:1: error: expected type '[5]u8'
|
||||||
|
// tmp.zig:2:30: note: imported here
|
||||||
11
test/cases/compile_errors/@import_zon_struct_dup_field.zig
Normal file
11
test/cases/compile_errors/@import_zon_struct_dup_field.zig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
export fn entry() void {
|
||||||
|
const f: struct { name: u8 } = @import("zon/struct_dup_field.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/struct_dup_field.zon
|
||||||
|
//
|
||||||
|
// struct_dup_field.zon:2:6: error: duplicate struct field name
|
||||||
|
// struct_dup_field.zon:3:6: note: duplicate name here
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const Vec2 = struct {
|
||||||
|
comptime x: f32 = 1.5,
|
||||||
|
comptime y: f32 = 2.5,
|
||||||
|
};
|
||||||
|
const f: Vec2 = @import("zon/vec2.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/vec2.zon
|
||||||
|
//
|
||||||
|
// vec2.zon:1:19: error: value stored in comptime field does not match the default value of the field
|
||||||
|
// tmp.zig:6:29: note: imported here
|
||||||
9
test/cases/compile_errors/@import_zon_syntax_error.zig
Normal file
9
test/cases/compile_errors/@import_zon_syntax_error.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: bool = @import("zon/syntax_error.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/syntax_error.zon
|
||||||
|
//
|
||||||
|
// syntax_error.zon:3:13: error: expected ',' after initializer
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const T = struct {
|
||||||
|
comptime f32 = 1.5,
|
||||||
|
comptime f32 = 2.5,
|
||||||
|
};
|
||||||
|
const f: T = @import("zon/tuple.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/tuple.zon
|
||||||
|
//
|
||||||
|
// tuple.zon:1:9: error: value stored in comptime field does not match the default value of the field
|
||||||
|
// tmp.zig:6:26: note: imported here
|
||||||
9
test/cases/compile_errors/@import_zon_type_decl.zig
Normal file
9
test/cases/compile_errors/@import_zon_type_decl.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: struct { foo: type } = @import("zon/type_decl.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/type_decl.zon
|
||||||
|
//
|
||||||
|
// type_decl.zon:2:12: error: types are not available in ZON
|
||||||
10
test/cases/compile_errors/@import_zon_type_expr_array.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_array.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: [3]i32 = @import("zon/type_expr_array.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/type_expr_array.zon
|
||||||
|
//
|
||||||
|
// type_expr_array.zon:1:1: error: types are not available in ZON
|
||||||
|
// type_expr_array.zon:1:1: note: replace the type with '.'
|
||||||
10
test/cases/compile_errors/@import_zon_type_expr_fn.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_fn.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: i32 = @import("zon/type_expr_fn.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/type_expr_fn.zon
|
||||||
|
//
|
||||||
|
// type_expr_fn.zon:1:1: error: types are not available in ZON
|
||||||
|
// type_expr_fn.zon:1:1: note: replace the type with '.'
|
||||||
10
test/cases/compile_errors/@import_zon_type_expr_struct.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_struct.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: struct { x: f32, y: f32 } = @import("zon/type_expr_struct.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/type_expr_struct.zon
|
||||||
|
//
|
||||||
|
// type_expr_struct.zon:1:1: error: types are not available in ZON
|
||||||
|
// type_expr_struct.zon:1:1: note: replace the type with '.'
|
||||||
10
test/cases/compile_errors/@import_zon_type_expr_tuple.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_tuple.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export fn entry() void {
|
||||||
|
const f: struct { f32, f32 } = @import("zon/type_expr_tuple.zon");
|
||||||
|
_ = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// imports=zon/type_expr_tuple.zon
|
||||||
|
//
|
||||||
|
// type_expr_tuple.zon:1:1: error: types are not available in ZON
|
||||||
|
// type_expr_tuple.zon:1:1: note: replace the type with '.'
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user