mirror of
https://github.com/ziglang/zig.git
synced 2024-11-21 19:42:56 +00:00
Compare commits
20 Commits
7870a8435b
...
c4ae53b6ec
Author | SHA1 | Date | |
---|---|---|---|
|
c4ae53b6ec | ||
|
f845fa04a0 | ||
|
54950c9c4b | ||
|
0f2fde90af | ||
|
d7ba90b8d6 | ||
|
78735d83a0 | ||
|
ea92351baa | ||
|
30d6f24581 | ||
|
d3f1bb9ab1 | ||
|
978a693666 | ||
|
24dc5c5126 | ||
|
7da51184d2 | ||
|
a59ccc08c1 | ||
|
77f6422740 | ||
|
0451d38064 | ||
|
b30045c900 | ||
|
e99d07a9ad | ||
|
3bff320d08 | ||
|
d2bbcf9e71 | ||
|
0cbc043644 |
@ -426,7 +426,7 @@ pub fn build(b: *std.Build) !void {
|
||||
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_exclude_paths = &.{"test/cases"};
|
||||
const fmt_exclude_paths = &.{ "test/cases", "test/behavior/zon" };
|
||||
const do_fmt = b.addFmt(.{
|
||||
.paths = fmt_include_paths,
|
||||
.exclude_paths = fmt_exclude_paths,
|
||||
|
@ -48,7 +48,8 @@ fn read(ma: *MemoryAccessor, address: usize, buf: []u8) bool {
|
||||
switch (linux.E.init(bytes_read)) {
|
||||
.SUCCESS => return bytes_read == buf.len,
|
||||
.FAULT => return false,
|
||||
.INVAL, .PERM, .SRCH => unreachable, // own pid is always valid
|
||||
.INVAL, .SRCH => unreachable, // own pid is always valid
|
||||
.PERM => {}, // Known to happen in containers.
|
||||
.NOMEM => {},
|
||||
.NOSYS => {}, // QEMU is known not to implement this syscall.
|
||||
else => unreachable, // unexpected
|
||||
|
@ -1579,7 +1579,8 @@ test parseInt {
|
||||
try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16));
|
||||
}
|
||||
|
||||
fn parseIntWithSign(
|
||||
/// Like `parseIntWithGenericCharacter`, but with a sign argument.
|
||||
pub fn parseIntWithSign(
|
||||
comptime Result: type,
|
||||
comptime Character: type,
|
||||
buf: []const Character,
|
||||
|
@ -44,6 +44,7 @@ pub const Thread = @import("Thread.zig");
|
||||
pub const Treap = @import("treap.zig").Treap;
|
||||
pub const Tz = tz.Tz;
|
||||
pub const Uri = @import("Uri.zig");
|
||||
pub const zon = @import("zon.zig");
|
||||
|
||||
pub const array_hash_map = @import("array_hash_map.zig");
|
||||
pub const atomic = @import("atomic.zig");
|
||||
|
@ -7,12 +7,13 @@
|
||||
/// Reference to externally-owned data.
|
||||
source: [:0]const u8,
|
||||
|
||||
mode: Mode,
|
||||
|
||||
tokens: TokenList.Slice,
|
||||
/// The root AST node is assumed to be index 0. Since there can be no
|
||||
/// references to the root node, this means 0 is available to indicate null.
|
||||
nodes: NodeList.Slice,
|
||||
extra_data: []Node.Index,
|
||||
mode: Mode = .zig,
|
||||
|
||||
errors: []const Error,
|
||||
|
||||
|
@ -130,6 +130,8 @@ fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void {
|
||||
}
|
||||
|
||||
pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
|
||||
assert(tree.mode == .zig);
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena.deinit();
|
||||
|
||||
@ -8789,36 +8791,22 @@ fn numberLiteral(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index, source_node:
|
||||
}
|
||||
}
|
||||
|
||||
fn failWithNumberError(astgen: *AstGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) InnerError {
|
||||
const is_float = std.mem.indexOfScalar(u8, bytes, '.') != null;
|
||||
switch (err) {
|
||||
.leading_zero => if (is_float) {
|
||||
return astgen.failTok(token, "number '{s}' has leading zero", .{bytes});
|
||||
} else {
|
||||
return astgen.failTokNotes(token, "number '{s}' has leading zero", .{bytes}, &.{
|
||||
try astgen.errNoteTok(token, "use '0o' prefix for octal literals", .{}),
|
||||
});
|
||||
},
|
||||
.digit_after_base => return astgen.failTok(token, "expected a digit after base prefix", .{}),
|
||||
.upper_case_base => |i| return astgen.failOff(token, @intCast(i), "base prefix must be lowercase", .{}),
|
||||
.invalid_float_base => |i| return astgen.failOff(token, @intCast(i), "invalid base for float literal", .{}),
|
||||
.repeated_underscore => |i| return astgen.failOff(token, @intCast(i), "repeated digit separator", .{}),
|
||||
.invalid_underscore_after_special => |i| return astgen.failOff(token, @intCast(i), "expected digit before digit separator", .{}),
|
||||
.invalid_digit => |info| return astgen.failOff(token, @intCast(info.i), "invalid digit '{c}' for {s} base", .{ bytes[info.i], @tagName(info.base) }),
|
||||
.invalid_digit_exponent => |i| return astgen.failOff(token, @intCast(i), "invalid digit '{c}' in exponent", .{bytes[i]}),
|
||||
.duplicate_exponent => |i| return astgen.failOff(token, @intCast(i), "duplicate exponent", .{}),
|
||||
.exponent_after_underscore => |i| return astgen.failOff(token, @intCast(i), "expected digit before exponent", .{}),
|
||||
.special_after_underscore => |i| return astgen.failOff(token, @intCast(i), "expected digit before '{c}'", .{bytes[i]}),
|
||||
.trailing_special => |i| return astgen.failOff(token, @intCast(i), "expected digit after '{c}'", .{bytes[i - 1]}),
|
||||
.trailing_underscore => |i| return astgen.failOff(token, @intCast(i), "trailing digit separator", .{}),
|
||||
.duplicate_period => unreachable, // Validated by tokenizer
|
||||
.invalid_character => unreachable, // Validated by tokenizer
|
||||
.invalid_exponent_sign => |i| {
|
||||
assert(bytes.len >= 2 and bytes[0] == '0' and bytes[1] == 'x'); // Validated by tokenizer
|
||||
return astgen.failOff(token, @intCast(i), "sign '{c}' cannot follow digit '{c}' in hex base", .{ bytes[i], bytes[i - 1] });
|
||||
},
|
||||
.period_after_exponent => |i| return astgen.failOff(token, @intCast(i), "unexpected period after exponent", .{}),
|
||||
}
|
||||
fn failWithNumberError(
|
||||
astgen: *AstGen,
|
||||
err: std.zig.number_literal.Error,
|
||||
token: Ast.TokenIndex,
|
||||
bytes: []const u8,
|
||||
) InnerError {
|
||||
const note = err.noteWithSource(bytes);
|
||||
const notes: []const u32 = if (note) |n| &.{try astgen.errNoteTok(token, "{s}", .{n})} else &.{};
|
||||
try astgen.appendErrorTokNotesOff(
|
||||
token,
|
||||
@as(u32, @intCast(err.offset())),
|
||||
"{}",
|
||||
.{err.fmtWithSource(bytes)},
|
||||
notes,
|
||||
);
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
fn asmExpr(
|
||||
@ -9313,7 +9301,18 @@ fn builtinCall(
|
||||
} else if (str.len == 0) {
|
||||
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);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = str_lit_token;
|
||||
@ -11399,85 +11398,20 @@ 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..];
|
||||
switch (err) {
|
||||
.invalid_escape_character => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"invalid escape character: '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.expected_hex_digit => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected hex digit, found '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.empty_unicode_escape_sequence => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"empty unicode escape sequence",
|
||||
.{},
|
||||
);
|
||||
},
|
||||
.expected_hex_digit_or_rbrace => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected hex digit or '}}', found '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.invalid_unicode_codepoint => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"unicode escape does not correspond to a valid unicode scalar value",
|
||||
.{},
|
||||
);
|
||||
},
|
||||
.expected_lbrace => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected '{{', found '{c}",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.expected_rbrace => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected '}}', found '{c}",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.expected_single_quote => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected single quote ('), found '{c}",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.invalid_character => |bad_index| {
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"invalid byte in string or character literal: '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.empty_char_literal => {
|
||||
return astgen.failOff(token, offset, "empty character literal", .{});
|
||||
},
|
||||
}
|
||||
return astgen.failOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(err.offset())),
|
||||
"{}",
|
||||
.{err.fmtWithSource(raw_string)},
|
||||
);
|
||||
}
|
||||
|
||||
fn failNode(
|
||||
@ -11595,7 +11529,7 @@ fn appendErrorTokNotesOff(
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
notes: []const u32,
|
||||
) !void {
|
||||
) Allocator.Error!void {
|
||||
@branchHint(.cold);
|
||||
const gpa = astgen.gpa;
|
||||
const string_bytes = &astgen.string_bytes;
|
||||
@ -11791,32 +11725,17 @@ fn strLitAsString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !IndexSlice {
|
||||
}
|
||||
|
||||
fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice {
|
||||
const tree = astgen.tree;
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
|
||||
const start = node_datas[node].lhs;
|
||||
const end = node_datas[node].rhs;
|
||||
|
||||
const gpa = astgen.gpa;
|
||||
const data = astgen.tree.nodes.items(.data);
|
||||
const string_bytes = &astgen.string_bytes;
|
||||
const str_index = string_bytes.items.len;
|
||||
|
||||
// First line: do not append a newline.
|
||||
var tok_i = start;
|
||||
{
|
||||
const slice = tree.tokenSlice(tok_i);
|
||||
const line_bytes = slice[2..];
|
||||
try string_bytes.appendSlice(gpa, line_bytes);
|
||||
tok_i += 1;
|
||||
}
|
||||
// Following lines: each line prepends a newline.
|
||||
while (tok_i <= end) : (tok_i += 1) {
|
||||
const slice = tree.tokenSlice(tok_i);
|
||||
const line_bytes = slice[2..];
|
||||
try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
|
||||
string_bytes.appendAssumeCapacity('\n');
|
||||
string_bytes.appendSliceAssumeCapacity(line_bytes);
|
||||
var parser = std.zig.string_literal.multilineParser(string_bytes.writer(gpa));
|
||||
var tok_i = data[node].lhs;
|
||||
while (tok_i <= data[node].rhs) : (tok_i += 1) {
|
||||
try parser.line(astgen.tree.tokenSlice(tok_i));
|
||||
}
|
||||
|
||||
const len = string_bytes.items.len - str_index;
|
||||
try string_bytes.append(gpa, 0);
|
||||
return IndexSlice{
|
||||
|
@ -1667,7 +1667,7 @@ pub const Inst = struct {
|
||||
.func = .pl_node,
|
||||
.func_inferred = .pl_node,
|
||||
.func_fancy = .pl_node,
|
||||
.import = .str_tok,
|
||||
.import = .pl_tok,
|
||||
.int = .int,
|
||||
.int_big = .str,
|
||||
.float = .float,
|
||||
@ -3572,6 +3572,13 @@ pub const Inst = struct {
|
||||
/// If `.none`, restore unconditionally.
|
||||
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 };
|
||||
|
@ -58,8 +58,83 @@ pub const Error = union(enum) {
|
||||
invalid_exponent_sign: usize,
|
||||
/// Period comes directly after exponent.
|
||||
period_after_exponent: usize,
|
||||
|
||||
pub fn fmtWithSource(self: Error, bytes: []const u8) std.fmt.Formatter(formatErrorWithSource) {
|
||||
return .{ .data = .{ .err = self, .bytes = bytes } };
|
||||
}
|
||||
|
||||
pub fn noteWithSource(self: Error, bytes: []const u8) ?[]const u8 {
|
||||
if (self == .leading_zero) {
|
||||
const is_float = std.mem.indexOfScalar(u8, bytes, '.') != null;
|
||||
if (!is_float) return "use '0o' prefix for octal literals";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn offset(self: Error) usize {
|
||||
return switch (self) {
|
||||
.leading_zero => 0,
|
||||
.digit_after_base => 0,
|
||||
.upper_case_base => |i| i,
|
||||
.invalid_float_base => |i| i,
|
||||
.repeated_underscore => |i| i,
|
||||
.invalid_underscore_after_special => |i| i,
|
||||
.invalid_digit => |e| e.i,
|
||||
.invalid_digit_exponent => |i| i,
|
||||
.duplicate_period => 0,
|
||||
.duplicate_exponent => |i| i,
|
||||
.exponent_after_underscore => |i| i,
|
||||
.special_after_underscore => |i| i,
|
||||
.trailing_special => |i| i,
|
||||
.trailing_underscore => |i| i,
|
||||
.invalid_character => |i| i,
|
||||
.invalid_exponent_sign => |i| i,
|
||||
.period_after_exponent => |i| i,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const FormatWithSource = struct {
|
||||
bytes: []const u8,
|
||||
err: Error,
|
||||
};
|
||||
|
||||
fn formatErrorWithSource(
|
||||
self: FormatWithSource,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = options;
|
||||
_ = fmt;
|
||||
switch (self.err) {
|
||||
.leading_zero => try writer.print("number '{s}' has leading zero", .{self.bytes}),
|
||||
.digit_after_base => try writer.writeAll("expected a digit after base prefix"),
|
||||
.upper_case_base => try writer.writeAll("base prefix must be lowercase"),
|
||||
.invalid_float_base => try writer.writeAll("invalid base for float literal"),
|
||||
.repeated_underscore => try writer.writeAll("repeated digit separator"),
|
||||
.invalid_underscore_after_special => try writer.writeAll("expected digit before digit separator"),
|
||||
.invalid_digit => |info| try writer.print("invalid digit '{c}' for {s} base", .{ self.bytes[info.i], @tagName(info.base) }),
|
||||
.invalid_digit_exponent => |i| try writer.print("invalid digit '{c}' in exponent", .{self.bytes[i]}),
|
||||
.duplicate_exponent => try writer.writeAll("duplicate exponent"),
|
||||
.exponent_after_underscore => try writer.writeAll("expected digit before exponent"),
|
||||
.special_after_underscore => |i| try writer.print("expected digit before '{c}'", .{self.bytes[i]}),
|
||||
.trailing_special => |i| try writer.print("expected digit after '{c}'", .{self.bytes[i - 1]}),
|
||||
.trailing_underscore => try writer.writeAll("trailing digit separator"),
|
||||
.duplicate_period => try writer.writeAll("duplicate period"),
|
||||
.invalid_character => try writer.writeAll("invalid character"),
|
||||
.invalid_exponent_sign => |i| {
|
||||
const hex = self.bytes.len >= 2 and self.bytes[0] == '0' and self.bytes[1] == 'x';
|
||||
if (hex) {
|
||||
try writer.print("sign '{c}' cannot follow digit '{c}' in hex base", .{ self.bytes[i], self.bytes[i - 1] });
|
||||
} else {
|
||||
try writer.print("sign '{c}' cannot follow digit '{c}' in current base", .{ self.bytes[i], self.bytes[i - 1] });
|
||||
}
|
||||
},
|
||||
.period_after_exponent => try writer.writeAll("unexpected period after exponent"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse Zig number literal accepted by fmt.parseInt, fmt.parseFloat and big_int.setString.
|
||||
/// Valid for any input.
|
||||
pub fn parseNumberLiteral(bytes: []const u8) Result {
|
||||
|
@ -38,8 +38,74 @@ pub const Error = union(enum) {
|
||||
invalid_character: usize,
|
||||
/// `''`. Not returned for string literals.
|
||||
empty_char_literal,
|
||||
|
||||
pub fn fmtWithSource(self: Error, raw_string: []const u8) std.fmt.Formatter(formatErrorWithSource) {
|
||||
return .{ .data = .{ .err = self, .raw_string = raw_string } };
|
||||
}
|
||||
|
||||
pub fn offset(self: Error) usize {
|
||||
return switch (self) {
|
||||
.invalid_escape_character => |i| i,
|
||||
.expected_hex_digit => |i| i,
|
||||
.empty_unicode_escape_sequence => |i| i,
|
||||
.expected_hex_digit_or_rbrace => |i| i,
|
||||
.invalid_unicode_codepoint => |i| i,
|
||||
.expected_lbrace => |i| i,
|
||||
.expected_rbrace => |i| i,
|
||||
.expected_single_quote => |i| i,
|
||||
.invalid_character => |i| i,
|
||||
.empty_char_literal => 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const FormatWithSource = struct {
|
||||
raw_string: []const u8,
|
||||
err: Error,
|
||||
};
|
||||
|
||||
fn formatErrorWithSource(
|
||||
self: FormatWithSource,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = options;
|
||||
_ = fmt;
|
||||
switch (self.err) {
|
||||
.invalid_escape_character => |bad_index| {
|
||||
try writer.print("invalid escape character: '{c}'", .{self.raw_string[bad_index]});
|
||||
},
|
||||
.expected_hex_digit => |bad_index| {
|
||||
try writer.print("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.print("empty character literal", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts the slice starts and ends with single-quotes.
|
||||
/// Returns an error if there is not exactly one UTF-8 codepoint in between.
|
||||
pub fn parseCharLiteral(slice: []const u8) ParsedCharLiteral {
|
||||
@ -247,7 +313,7 @@ test parseCharLiteral {
|
||||
|
||||
/// Parses `bytes` as a Zig string literal and writes the result to the std.io.Writer type.
|
||||
/// Asserts `bytes` has '"' at beginning and end.
|
||||
pub fn parseWrite(writer: anytype, bytes: []const u8) error{OutOfMemory}!Result {
|
||||
pub fn parseWrite(writer: anytype, bytes: []const u8) !Result {
|
||||
assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"');
|
||||
|
||||
var index: usize = 1;
|
||||
@ -312,3 +378,141 @@ test parseAlloc {
|
||||
try expect(eql(u8, "foo", try parseAlloc(alloc, "\"f\x6f\x6f\"")));
|
||||
try expect(eql(u8, "f💯", try parseAlloc(alloc, "\"f\u{1f4af}\"")));
|
||||
}
|
||||
|
||||
/// Parses one line at a time of a multiline Zig string literal to a std.io.Writer type. Does not append a null terminator.
|
||||
pub fn MultilineParser(comptime Writer: type) type {
|
||||
return struct {
|
||||
writer: Writer,
|
||||
first_line: bool,
|
||||
|
||||
pub fn init(writer: Writer) @This() {
|
||||
return .{
|
||||
.writer = writer,
|
||||
.first_line = true,
|
||||
};
|
||||
}
|
||||
|
||||
/// Parse one line of a multiline string, writing the result to the writer prepending a newline if necessary.
|
||||
///
|
||||
/// Asserts bytes begins with "\\". The line may be terminated with '\n' or "\r\n", but may not contain any interior newlines.
|
||||
/// contain any interior newlines.
|
||||
pub fn line(self: *@This(), bytes: []const u8) Writer.Error!void {
|
||||
assert(bytes.len >= 2 and bytes[0] == '\\' and bytes[1] == '\\');
|
||||
if (self.first_line) {
|
||||
self.first_line = false;
|
||||
} else {
|
||||
try self.writer.writeByte('\n');
|
||||
}
|
||||
try self.writer.writeAll(bytes[2..]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn multilineParser(writer: anytype) MultilineParser(@TypeOf(writer)) {
|
||||
return MultilineParser(@TypeOf(writer)).init(writer);
|
||||
}
|
||||
|
||||
test "parse multiline" {
|
||||
// Varying newlines
|
||||
{
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\foo");
|
||||
try std.testing.expectEqualStrings("foo", parsed.items);
|
||||
try parser.line("\\\\bar");
|
||||
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
|
||||
}
|
||||
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\foo");
|
||||
try std.testing.expectEqualStrings("foo", parsed.items);
|
||||
try parser.line("\\\\bar\n");
|
||||
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
|
||||
}
|
||||
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\foo");
|
||||
try std.testing.expectEqualStrings("foo", parsed.items);
|
||||
try parser.line("\\\\bar\r\n");
|
||||
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
|
||||
}
|
||||
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\foo\n");
|
||||
try std.testing.expectEqualStrings("foo", parsed.items);
|
||||
try parser.line("\\\\bar");
|
||||
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
|
||||
}
|
||||
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\foo\r\n");
|
||||
try std.testing.expectEqualStrings("foo", parsed.items);
|
||||
try parser.line("\\\\bar");
|
||||
try std.testing.expectEqualStrings("foo\nbar", parsed.items);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty lines
|
||||
{
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\");
|
||||
try std.testing.expectEqualStrings("", parsed.items);
|
||||
try parser.line("\\\\");
|
||||
try std.testing.expectEqualStrings("\n", parsed.items);
|
||||
try parser.line("\\\\foo");
|
||||
try std.testing.expectEqualStrings("\n\nfoo", parsed.items);
|
||||
try parser.line("\\\\bar");
|
||||
try std.testing.expectEqualStrings("\n\nfoo\nbar", parsed.items);
|
||||
}
|
||||
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\foo");
|
||||
try std.testing.expectEqualStrings("foo", parsed.items);
|
||||
try parser.line("\\\\");
|
||||
try std.testing.expectEqualStrings("foo\n", parsed.items);
|
||||
try parser.line("\\\\bar");
|
||||
try std.testing.expectEqualStrings("foo\n\nbar", parsed.items);
|
||||
try parser.line("\\\\");
|
||||
try std.testing.expectEqualStrings("foo\n\nbar\n", parsed.items);
|
||||
}
|
||||
}
|
||||
|
||||
// No escapes
|
||||
{
|
||||
var parsed = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer parsed.deinit();
|
||||
const writer = parsed.writer();
|
||||
var parser = multilineParser(writer);
|
||||
try parser.line("\\\\no \\n escape");
|
||||
try std.testing.expectEqualStrings("no \\n escape", parsed.items);
|
||||
try parser.line("\\\\still no \\n escape");
|
||||
try std.testing.expectEqualStrings("no \\n escape\nstill no \\n escape", parsed.items);
|
||||
}
|
||||
}
|
||||
|
97
lib/std/zon.zig
Normal file
97
lib/std/zon.zig
Normal file
@ -0,0 +1,97 @@
|
||||
//! ZON serialization and deserialization.
|
||||
//!
|
||||
//! # ZON
|
||||
//! ZON, or Zig Object Notation, is a subset* of Zig used for data storage. ZON contains no type
|
||||
//! names.
|
||||
//!
|
||||
//! Supported Zig primitives:
|
||||
//! * boolean literals
|
||||
//! * number literals (including `nan` and `inf`)
|
||||
//! * character literals
|
||||
//! * enum literals
|
||||
//! * `null` and `void` literals
|
||||
//! * string literals
|
||||
//! * multiline string literals
|
||||
//!
|
||||
//! Supported Zig containers:
|
||||
//! * anonymous struct literals
|
||||
//! * anonymous tuple literals
|
||||
//! * slices
|
||||
//! * notated as a reference to a tuple literal
|
||||
//! * this syntax will likely be removed in the future, at which point ZON will not distinguish
|
||||
//! between slices and tuples
|
||||
//!
|
||||
//! Here is an example ZON object:
|
||||
//! ```zon
|
||||
//! .{
|
||||
//! .a = 1.5,
|
||||
//! .b = "hello, world!",
|
||||
//! .c = .{ true, false },
|
||||
//! .d = &.{ 1, 2, 3 },
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Individual primitives are also valid ZON, for example:
|
||||
//! ```zon
|
||||
//! "This string is a valid ZON object."
|
||||
//! ```
|
||||
//!
|
||||
//! \* ZON is not currently a true subset of Zig, because it supports `nan` and
|
||||
//! `inf` literals, which Zig does not.
|
||||
//!
|
||||
//! # Deserialization
|
||||
//!
|
||||
//! The simplest way to deserialize ZON at runtime is `parseFromSlice`. (For reading ZON at
|
||||
//! comptime, you can use `@import`.)
|
||||
//!
|
||||
//! If you need lower level control, or more detailed diagnostics, you can generate the AST yourself
|
||||
//! with `std.zig.Ast.parse` and then deserialize it with:
|
||||
//! * `parseFromAst`
|
||||
//! * `parseFromAstNoAlloc`
|
||||
//!
|
||||
//! If you'd like to deserialize just part of an AST, you can use:
|
||||
//! * `parseFromAstNode`
|
||||
//! * `parseFromAstNodeNoAlloc`
|
||||
//!
|
||||
//! If you need lower level control than provided by this module, you can operate directly on the
|
||||
//! results of `std.zig.Ast.parse`.
|
||||
//!
|
||||
//!
|
||||
//! # Serialization
|
||||
//!
|
||||
//! The simplest way to serialize to ZON is to call `stringify`.
|
||||
//!
|
||||
//! If you need to serialize recursive types, the following functions are also provided:
|
||||
//! * `stringifyMaxDepth`
|
||||
//! * `stringifyArbitraryDepth`
|
||||
//!
|
||||
//! If you need more control over the serialization process, for example to control which fields are
|
||||
//! serialized, configure fields individually, or to stringify ZON values that do not exist in
|
||||
//! memory, you can use `Stringifier`.
|
||||
//!
|
||||
//! Note that serializing floats with more than 64 bits may result in a loss of precision
|
||||
//! (see https://github.com/ziglang/zig/issues/1181).
|
||||
|
||||
pub const ParseOptions = @import("zon/parse.zig").ParseOptions;
|
||||
pub const ParseStatus = @import("zon/parse.zig").ParseStatus;
|
||||
pub const parseFromSlice = @import("zon/parse.zig").parseFromSlice;
|
||||
pub const parseFromAst = @import("zon/parse.zig").parseFromAst;
|
||||
pub const parseFromAstNoAlloc = @import("zon/parse.zig").parseFromAstNoAlloc;
|
||||
pub const parseFromAstNode = @import("zon/parse.zig").parseFromAstNode;
|
||||
pub const parseFromAstNodeNoAlloc = @import("zon/parse.zig").parseFromAstNodeNoAlloc;
|
||||
pub const parseFree = @import("zon/parse.zig").parseFree;
|
||||
|
||||
pub const StringifierOptions = @import("zon/stringify.zig").StringifierOptions;
|
||||
pub const StringifyValueOptions = @import("zon/stringify.zig").StringifyValueOptions;
|
||||
pub const StringifyOptions = @import("zon/stringify.zig").StringifyOptions;
|
||||
pub const StringifyContainerOptions = @import("zon/stringify.zig").StringifyContainerOptions;
|
||||
pub const Stringifier = @import("zon/stringify.zig").Stringifier;
|
||||
pub const stringify = @import("zon/stringify.zig").stringify;
|
||||
pub const stringifyMaxDepth = @import("zon/stringify.zig").stringifyMaxDepth;
|
||||
pub const stringifyArbitraryDepth = @import("zon/stringify.zig").stringifyArbitraryDepth;
|
||||
pub const stringifier = @import("zon/stringify.zig").stringifier;
|
||||
|
||||
test {
|
||||
_ = @import("zon/parse.zig");
|
||||
_ = @import("zon/stringify.zig");
|
||||
}
|
2843
lib/std/zon/parse.zig
Normal file
2843
lib/std/zon/parse.zig
Normal file
File diff suppressed because it is too large
Load Diff
1920
lib/std/zon/stringify.zig
Normal file
1920
lib/std/zon/stringify.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -1018,6 +1018,11 @@ pub const Inst = struct {
|
||||
pub fn toType(ref: Ref) Type {
|
||||
return Type.fromInterned(ref.toInterned().?);
|
||||
}
|
||||
|
||||
pub fn toTypeAllowNone(ref: Ref) ?Type {
|
||||
if (ref == .none) return null;
|
||||
return ref.toType();
|
||||
}
|
||||
};
|
||||
|
||||
/// All instructions have an 8-byte payload, which is contained within
|
||||
|
@ -2192,7 +2192,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
|
||||
try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
|
||||
for (zcu.import_table.values()) |file_index| {
|
||||
if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
|
||||
comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
if (file.mode == .zig) {
|
||||
comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
|
||||
}
|
||||
}
|
||||
if (comp.file_system_inputs) |fsi| {
|
||||
for (zcu.import_table.values()) |file_index| {
|
||||
@ -4150,6 +4153,7 @@ fn workerAstGenFile(
|
||||
wg: *WaitGroup,
|
||||
src: Zcu.AstGenSrc,
|
||||
) void {
|
||||
assert(file.mode == .zig);
|
||||
const child_prog_node = prog_node.start(file.sub_file_path, 0);
|
||||
defer child_prog_node.end();
|
||||
|
||||
@ -4202,7 +4206,7 @@ fn workerAstGenFile(
|
||||
const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
|
||||
break :blk .{ res, imported_path_digest };
|
||||
};
|
||||
if (import_result.is_new) {
|
||||
if (import_result.is_new and import_result.file.mode == .zig) {
|
||||
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
||||
file.sub_file_path, import_path, import_result.file.sub_file_path,
|
||||
});
|
||||
|
@ -14,6 +14,7 @@ pub const Digest = [Hash.digest_length]u8;
|
||||
pub const multihash_len = 1 + 1 + Hash.digest_length;
|
||||
pub const multihash_hex_digest_len = 2 * multihash_len;
|
||||
pub const MultiHashHexDigest = [multihash_hex_digest_len]u8;
|
||||
const AstGen = std.zig.AstGen;
|
||||
|
||||
pub const Dependency = struct {
|
||||
location: Location,
|
||||
@ -456,7 +457,6 @@ const Parse = struct {
|
||||
return duped;
|
||||
}
|
||||
|
||||
/// TODO: try to DRY this with AstGen.parseStrLit
|
||||
fn parseStrLit(
|
||||
p: *Parse,
|
||||
token: Ast.TokenIndex,
|
||||
@ -470,95 +470,13 @@ const Parse = struct {
|
||||
buf.* = buf_managed.moveToUnmanaged();
|
||||
switch (try result) {
|
||||
.success => {},
|
||||
.failure => |err| try p.appendStrLitError(err, token, bytes, offset),
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: try to DRY this with AstGen.failWithStrLitError
|
||||
fn appendStrLitError(
|
||||
p: *Parse,
|
||||
err: std.zig.string_literal.Error,
|
||||
token: Ast.TokenIndex,
|
||||
bytes: []const u8,
|
||||
offset: u32,
|
||||
) Allocator.Error!void {
|
||||
const raw_string = bytes[offset..];
|
||||
switch (err) {
|
||||
.invalid_escape_character => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"invalid escape character: '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.expected_hex_digit => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected hex digit, found '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.empty_unicode_escape_sequence => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"empty unicode escape sequence",
|
||||
.{},
|
||||
);
|
||||
},
|
||||
.expected_hex_digit_or_rbrace => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected hex digit or '}}', found '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.invalid_unicode_codepoint => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"unicode escape does not correspond to a valid unicode scalar value",
|
||||
.{},
|
||||
);
|
||||
},
|
||||
.expected_lbrace => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected '{{', found '{c}",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.expected_rbrace => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected '}}', found '{c}",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.expected_single_quote => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"expected single quote ('), found '{c}",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.invalid_character => |bad_index| {
|
||||
try p.appendErrorOff(
|
||||
token,
|
||||
offset + @as(u32, @intCast(bad_index)),
|
||||
"invalid byte in string or character literal: '{c}'",
|
||||
.{raw_string[bad_index]},
|
||||
);
|
||||
},
|
||||
.empty_char_literal => {
|
||||
try p.appendErrorOff(token, offset, "empty character literal", .{});
|
||||
},
|
||||
.failure => |err| try appendErrorOff(
|
||||
p,
|
||||
token,
|
||||
offset + @as(u32, @intCast(err.offset())),
|
||||
"{}",
|
||||
err.fmtWithSource(raw_string),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,6 +478,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
|
||||
.status = .never_loaded,
|
||||
.prev_status = .never_loaded,
|
||||
.mod = new,
|
||||
.mode = .zig,
|
||||
};
|
||||
break :b new;
|
||||
};
|
||||
|
46
src/Sema.zig
46
src/Sema.zig
@ -192,6 +192,7 @@ const Alignment = InternPool.Alignment;
|
||||
const AnalUnit = InternPool.AnalUnit;
|
||||
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
|
||||
const Cache = std.Build.Cache;
|
||||
const zon = @import("zon.zig");
|
||||
|
||||
pub const default_branch_quota = 1000;
|
||||
pub const default_reference_trace_len = 2;
|
||||
@ -14475,9 +14476,10 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
||||
|
||||
const pt = sema.pt;
|
||||
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 = inst_data.get(sema.code);
|
||||
const operand = sema.code.nullTerminatedString(extra.path);
|
||||
|
||||
const result = pt.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
|
||||
error.ImportOutsideModulePath => {
|
||||
@ -14494,12 +14496,40 @@ 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) });
|
||||
},
|
||||
};
|
||||
try sema.declareDependency(.{ .file = result.file_index });
|
||||
try pt.ensureFileAnalyzed(result.file_index);
|
||||
const ty = zcu.fileRootType(result.file_index);
|
||||
try sema.declareDependency(.{ .interned = ty });
|
||||
try sema.addTypeReferenceEntry(operand_src, ty);
|
||||
return Air.internedToRef(ty);
|
||||
switch (result.file.mode) {
|
||||
.zig => {
|
||||
try sema.declareDependency(.{ .file = result.file_index });
|
||||
try pt.ensureFileAnalyzed(result.file_index);
|
||||
const ty = zcu.fileRootType(result.file_index);
|
||||
try sema.declareDependency(.{ .interned = ty });
|
||||
try sema.addTypeReferenceEntry(operand_src, 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 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 ZON must have a known result type", .{});
|
||||
}
|
||||
|
||||
const interned = try zon.lower(
|
||||
sema,
|
||||
result.file,
|
||||
result.file_index,
|
||||
res_ty,
|
||||
);
|
||||
return Air.internedToRef(interned);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
|
23
src/Zcu.zig
23
src/Zcu.zig
@ -453,6 +453,9 @@ pub const File = struct {
|
||||
/// successful, this field is unloaded.
|
||||
prev_zir: ?*Zir = null,
|
||||
|
||||
/// Whether the file is Zig or ZON. This filed is always populated.
|
||||
mode: Ast.Mode,
|
||||
|
||||
pub const Status = enum {
|
||||
never_loaded,
|
||||
retryable_failure,
|
||||
@ -472,6 +475,17 @@ pub const File = struct {
|
||||
root: *Package.Module,
|
||||
};
|
||||
|
||||
pub fn modeFromPath(path: []const u8) Ast.Mode {
|
||||
if (std.mem.endsWith(u8, path, ".zon")) {
|
||||
return .zon;
|
||||
} else if (std.mem.endsWith(u8, path, ".zig")) {
|
||||
return .zig;
|
||||
} else {
|
||||
// `Module.importFile` rejects all other extensions
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unload(file: *File, gpa: Allocator) void {
|
||||
file.unloadTree(gpa);
|
||||
file.unloadSource(gpa);
|
||||
@ -546,7 +560,7 @@ pub const File = struct {
|
||||
if (file.tree_loaded) return &file.tree;
|
||||
|
||||
const source = try file.getSource(gpa);
|
||||
file.tree = try Ast.parse(gpa, source.bytes, .zig);
|
||||
file.tree = try Ast.parse(gpa, source.bytes, file.mode);
|
||||
file.tree_loaded = true;
|
||||
return &file.tree;
|
||||
}
|
||||
@ -663,6 +677,7 @@ pub const File = struct {
|
||||
pub const Index = InternPool.FileIndex;
|
||||
};
|
||||
|
||||
/// Represents the contents of a file loaded with `@embedFile`.
|
||||
pub const EmbedFile = struct {
|
||||
/// Relative to the owning module's root directory.
|
||||
sub_file_path: InternPool.NullTerminatedString,
|
||||
@ -2087,6 +2102,12 @@ pub const LazySrcLoc = struct {
|
||||
break :inst .{ info.file, info.inst };
|
||||
};
|
||||
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);
|
||||
|
||||
const zir = file.zir;
|
||||
|
@ -1066,6 +1066,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
assert(file.mode == .zig);
|
||||
assert(zcu.fileRootType(file_index) == .none);
|
||||
|
||||
if (file.status != .success_zir) {
|
||||
@ -1463,6 +1464,7 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
|
||||
.status = .never_loaded,
|
||||
.prev_status = .never_loaded,
|
||||
.mod = mod,
|
||||
.mode = Zcu.File.modeFromPath(sub_file_path),
|
||||
};
|
||||
|
||||
try new_file.addReference(zcu, .{ .root = mod });
|
||||
@ -1493,7 +1495,9 @@ pub fn importFile(
|
||||
if (mod.deps.get(import_string)) |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;
|
||||
}
|
||||
const gpa = zcu.gpa;
|
||||
@ -1574,6 +1578,7 @@ pub fn importFile(
|
||||
.status = .never_loaded,
|
||||
.prev_status = .never_loaded,
|
||||
.mod = mod,
|
||||
.mode = Zcu.File.modeFromPath(sub_file_path),
|
||||
};
|
||||
|
||||
return .{
|
||||
|
@ -6037,6 +6037,7 @@ fn cmdAstCheck(
|
||||
.tree = undefined,
|
||||
.zir = undefined,
|
||||
.mod = undefined,
|
||||
.mode = .zig,
|
||||
};
|
||||
if (zig_source_file) |file_name| {
|
||||
var f = fs.cwd().openFile(file_name, .{}) catch |err| {
|
||||
@ -6361,6 +6362,7 @@ fn cmdDumpZir(
|
||||
.tree = undefined,
|
||||
.zir = try Zcu.loadZirCache(gpa, f),
|
||||
.mod = undefined,
|
||||
.mode = .zig,
|
||||
};
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
@ -6433,6 +6435,7 @@ fn cmdChangelist(
|
||||
.tree = undefined,
|
||||
.zir = undefined,
|
||||
.mod = undefined,
|
||||
.mode = Zcu.File.modeFromPath(old_source_file),
|
||||
};
|
||||
|
||||
file.mod = try Package.Module.createLimited(arena, .{
|
||||
|
@ -488,7 +488,6 @@ const Writer = struct {
|
||||
.enum_literal,
|
||||
.decl_ref,
|
||||
.decl_val,
|
||||
.import,
|
||||
.ret_err_value,
|
||||
.ret_err_value_code,
|
||||
.param_anytype,
|
||||
@ -515,6 +514,8 @@ const Writer = struct {
|
||||
.declaration => try self.writeDeclaration(stream, inst),
|
||||
|
||||
.extended => try self.writeExtended(stream, inst),
|
||||
|
||||
.import => try self.writeImport(stream, inst),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2979,4 +2980,13 @@ const Writer = struct {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
1292
src/zon.zig
Normal file
1292
src/zon.zig
Normal file
File diff suppressed because it is too large
Load Diff
322
test/behavior/zon.zig
Normal file
322
test/behavior/zon.zig
Normal file
@ -0,0 +1,322 @@
|
||||
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 "void" {
|
||||
try expectEqual({}, @as(void, @import("zon/void.zon")));
|
||||
}
|
||||
|
||||
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");
|
||||
const union4: Union = @import("zon/union4.zon");
|
||||
|
||||
try expectEqual(union1.x, 1.5);
|
||||
try expectEqual(union2.y, true);
|
||||
try expectEqual(union3.z, {});
|
||||
try expectEqual(union4.z, {});
|
||||
}
|
||||
|
||||
// Inferred tag
|
||||
{
|
||||
const Union = union(enum) {
|
||||
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");
|
||||
const union4: Union = @import("zon/union4.zon");
|
||||
|
||||
try expectEqual(union1.x, 1.5);
|
||||
try expectEqual(union2.y, true);
|
||||
try expectEqual(union3.z, {});
|
||||
try expectEqual(union4.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");
|
||||
const union4: Union = @import("zon/union4.zon");
|
||||
|
||||
try expectEqual(union1.x, 1.5);
|
||||
try expectEqual(union2.y, true);
|
||||
try expectEqual(union3.z, {});
|
||||
try expectEqual(union4.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);
|
||||
}
|
||||
|
||||
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 "char" {
|
||||
try expectEqual(@as(u8, 'a'), @as(u8, @import("zon/a.zon")));
|
||||
try expectEqual(@as(u8, 'z'), @as(u8, @import("zon/z.zon")));
|
||||
try expectEqual(@as(i8, -'a'), @as(i8, @import("zon/a_neg.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" {
|
||||
return error.SkipZigTest;
|
||||
// {
|
||||
// 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/slice-1.zon");
|
||||
// try expectEqualSlices(u8, expected_slice, found_slice);
|
||||
|
||||
// const expected_array: [1]u8 = .{1};
|
||||
// const found_array: [1]u8 = @import("zon/slice-1.zon");
|
||||
// try expectEqual(expected_array, found_array);
|
||||
|
||||
// const T = struct { u8 };
|
||||
// const expected_tuple: T = .{1};
|
||||
// const found_tuple: T = @import("zon/slice-1.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 expected = .{
|
||||
// Test various numbers and types
|
||||
@as(u8, 10),
|
||||
@as(i16, 24),
|
||||
@as(i14, -4),
|
||||
@as(i32, -123),
|
||||
|
||||
// Test limits
|
||||
@as(i8, 127),
|
||||
@as(i8, -128),
|
||||
|
||||
// Test characters
|
||||
@as(u8, 'a'),
|
||||
@as(u8, 'z'),
|
||||
|
||||
// Test big integers
|
||||
@as(u65, 36893488147419103231),
|
||||
@as(u65, 36893488147419103231),
|
||||
@as(i128, -18446744073709551615), // Only a big int due to negation
|
||||
@as(i128, -9223372036854775809), // Only a big int due to negation
|
||||
|
||||
// Test big integer limits
|
||||
@as(i66, 36893488147419103231),
|
||||
@as(i66, -36893488147419103232),
|
||||
|
||||
// Test parsing whole number floats as integers
|
||||
@as(i8, -1),
|
||||
@as(i8, 123),
|
||||
|
||||
// Test non-decimal integers
|
||||
@as(i16, 0xff),
|
||||
@as(i16, -0xff),
|
||||
@as(i16, 0o77),
|
||||
@as(i16, -0o77),
|
||||
@as(i16, 0b11),
|
||||
@as(i16, -0b11),
|
||||
|
||||
// Test non-decimal big integers
|
||||
@as(u65, 0x1ffffffffffffffff),
|
||||
@as(i66, 0x1ffffffffffffffff),
|
||||
@as(i66, -0x1ffffffffffffffff),
|
||||
@as(u65, 0x1ffffffffffffffff),
|
||||
@as(i66, 0x1ffffffffffffffff),
|
||||
@as(i66, -0x1ffffffffffffffff),
|
||||
@as(u65, 0x1ffffffffffffffff),
|
||||
@as(i66, 0x1ffffffffffffffff),
|
||||
@as(i66, -0x1ffffffffffffffff),
|
||||
};
|
||||
const actual: @TypeOf(expected) = @import("zon/ints.zon");
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "floats" {
|
||||
const expected = .{
|
||||
// Test decimals
|
||||
@as(f16, 0.5),
|
||||
@as(f32, 123.456),
|
||||
@as(f64, -123.456),
|
||||
@as(f128, 42.5),
|
||||
|
||||
// Test whole numbers with and without decimals
|
||||
@as(f16, 5.0),
|
||||
@as(f16, 5.0),
|
||||
@as(f32, -102),
|
||||
@as(f32, -102),
|
||||
|
||||
// Test characters and negated characters
|
||||
@as(f32, 'a'),
|
||||
@as(f32, 'z'),
|
||||
@as(f32, -'z'),
|
||||
|
||||
// Test big integers
|
||||
@as(f32, 36893488147419103231),
|
||||
@as(f32, -36893488147419103231),
|
||||
@as(f128, 0x1ffffffffffffffff),
|
||||
@as(f32, 0x1ffffffffffffffff),
|
||||
|
||||
// Exponents, underscores
|
||||
@as(f32, 123.0E+77),
|
||||
|
||||
// Hexadecimal
|
||||
@as(f32, 0x103.70p-5),
|
||||
@as(f32, -0x103.70),
|
||||
@as(f32, 0x1234_5678.9ABC_CDEFp-10),
|
||||
};
|
||||
const actual: @TypeOf(expected) = @import("zon/floats.zon");
|
||||
try expectEqual(actual, expected);
|
||||
}
|
||||
|
||||
test "inf and nan" {
|
||||
// comptime float
|
||||
{
|
||||
const actual: struct { comptime_float, comptime_float, comptime_float, comptime_float } = @import("zon/inf_and_nan.zon");
|
||||
try expect(std.math.isNan(actual[0]));
|
||||
try expect(std.math.isNan(actual[1]));
|
||||
try expect(std.math.isPositiveInf(@as(f128, @floatCast(actual[2]))));
|
||||
try expect(std.math.isNegativeInf(@as(f128, @floatCast(actual[3]))));
|
||||
}
|
||||
|
||||
// f32
|
||||
{
|
||||
const actual: struct { f32, f32, f32, f32 } = @import("zon/inf_and_nan.zon");
|
||||
try expect(std.math.isNan(actual[0]));
|
||||
try expect(std.math.isNan(actual[1]));
|
||||
try expect(std.math.isPositiveInf(actual[2]));
|
||||
try expect(std.math.isNegativeInf(actual[3]));
|
||||
}
|
||||
}
|
1
test/behavior/zon/a.zon
Normal file
1
test/behavior/zon/a.zon
Normal file
@ -0,0 +1 @@
|
||||
'a'
|
1
test/behavior/zon/a_neg.zon
Normal file
1
test/behavior/zon/a_neg.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' }
|
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 @@
|
||||
// zig fmt: off
|
||||
.{ .@"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
|
||||
|
26
test/behavior/zon/floats.zon
Normal file
26
test/behavior/zon/floats.zon
Normal file
@ -0,0 +1,26 @@
|
||||
.{
|
||||
0.5,
|
||||
123.456,
|
||||
-123.456,
|
||||
42.5,
|
||||
|
||||
5.0,
|
||||
5,
|
||||
-102.0,
|
||||
-102,
|
||||
|
||||
'a',
|
||||
'z',
|
||||
-'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
|
6
test/behavior/zon/inf_and_nan.zon
Normal file
6
test/behavior/zon/inf_and_nan.zon
Normal file
@ -0,0 +1,6 @@
|
||||
.{
|
||||
nan,
|
||||
-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/slice-1.zon
Normal file
1
test/behavior/zon/slice-1.zon
Normal file
@ -0,0 +1 @@
|
||||
.{ 1 }
|
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/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/union4.zon
Normal file
1
test/behavior/zon/union4.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/void.zon
Normal file
1
test/behavior/zon/void.zon
Normal file
@ -0,0 +1 @@
|
||||
{}
|
1
test/behavior/zon/z.zon
Normal file
1
test/behavior/zon/z.zon
Normal file
@ -0,0 +1 @@
|
||||
'z'
|
11
test/cases/compile_errors/@import_zon_addr_slice.zig
Normal file
11
test/cases/compile_errors/@import_zon_addr_slice.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/addr_slice.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/addr_slice.zon
|
||||
//
|
||||
// addr_slice.zon:2:14: error: invalid ZON value
|
13
test/cases/compile_errors/@import_zon_array_len.zig
Normal file
13
test/cases/compile_errors/@import_zon_array_len.zig
Normal file
@ -0,0 +1,13 @@
|
||||
pub fn main() void {
|
||||
const f: [4]u8 = @import("zon/array.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/array.zon
|
||||
//
|
||||
// 2:22: error: expected type '[4]u8', found 'struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}'
|
||||
// note: destination has length 4
|
||||
// note: source has length 3
|
12
test/cases/compile_errors/@import_zon_bad_import.zig
Normal file
12
test/cases/compile_errors/@import_zon_bad_import.zig
Normal file
@ -0,0 +1,12 @@
|
||||
pub fn main() void {
|
||||
_ = @import(
|
||||
"bogus-does-not-exist.zon",
|
||||
);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
// output_mode=Exe
|
||||
//
|
||||
// :3:9: error: unable to open 'bogus-does-not-exist.zon': FileNotFound
|
11
test/cases/compile_errors/@import_zon_coerce_pointer.zig
Normal file
11
test/cases/compile_errors/@import_zon_coerce_pointer.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: *struct { u8, u8, u8 } = @import("zon/array.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/array.zon
|
||||
//
|
||||
// found 'struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}'
|
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/double_negation_float.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/double_negation_float.zon
|
||||
//
|
||||
// double_negation_float.zon:1:2: error: invalid ZON value
|
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/double_negation_int.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/double_negation_int.zon
|
||||
//
|
||||
// double_negation_int.zon:1:2: error: invalid ZON value
|
12
test/cases/compile_errors/@import_zon_enum_embedded_null.zig
Normal file
12
test/cases/compile_errors/@import_zon_enum_embedded_null.zig
Normal file
@ -0,0 +1,12 @@
|
||||
const std = @import("std");
|
||||
pub fn main() void {
|
||||
const f = @import("zon/enum_embedded_null.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// 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_invalid_character.zig
Normal file
11
test/cases/compile_errors/@import_zon_invalid_character.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f = @import("zon/invalid_character.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/invalid_character.zon
|
||||
//
|
||||
// invalid_character.zon:1:3: error: invalid escape character: 'a'
|
11
test/cases/compile_errors/@import_zon_invalid_number.zig
Normal file
11
test/cases/compile_errors/@import_zon_invalid_number.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f = @import("zon/invalid_number.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/invalid_number.zon
|
||||
//
|
||||
// invalid_number.zon:1:19: error: invalid digit 'a' for decimal base
|
11
test/cases/compile_errors/@import_zon_invalid_string.zig
Normal file
11
test/cases/compile_errors/@import_zon_invalid_string.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f = @import("zon/invalid_string.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/invalid_string.zon
|
||||
//
|
||||
// invalid_string.zon:1:5: error: invalid escape character: 'a'
|
@ -0,0 +1,12 @@
|
||||
pub fn main() void {
|
||||
const f = @import("zon/leading_zero_in_integer.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// 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
|
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 @@
|
||||
pub fn main() void {
|
||||
const f: i8 = @import("zon/negative_zero.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/negative_zero.zon
|
||||
//
|
||||
// negative_zero.zon:1:1: error: integer literal '-0' is ambiguous
|
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: f32 = @import("zon/negative_zero.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/negative_zero.zon
|
||||
//
|
||||
// negative_zero.zon:1:1: error: integer literal '-0' is ambiguous
|
11
test/cases/compile_errors/@import_zon_number_fail_limits.zig
Normal file
11
test/cases/compile_errors/@import_zon_number_fail_limits.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i66 = @import("zon/large_number.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/large_number.zon
|
||||
//
|
||||
// 2:20: error: type 'i66' cannot represent integer value '36893488147419103232'
|
12
test/cases/compile_errors/@import_zon_struct_dup_field.zig
Normal file
12
test/cases/compile_errors/@import_zon_struct_dup_field.zig
Normal file
@ -0,0 +1,12 @@
|
||||
const std = @import("std");
|
||||
pub fn main() void {
|
||||
const f = @import("zon/struct_dup_field.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/struct_dup_field.zon
|
||||
//
|
||||
// struct_dup_field.zon:3:6: error: duplicate field
|
11
test/cases/compile_errors/@import_zon_syntax_error.zig
Normal file
11
test/cases/compile_errors/@import_zon_syntax_error.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: bool = @import("zon/syntax_error.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/syntax_error.zon
|
||||
//
|
||||
// syntax_error.zon:3:13: error: expected ',' after initializer
|
11
test/cases/compile_errors/@import_zon_type_decl.zig
Normal file
11
test/cases/compile_errors/@import_zon_type_decl.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/type_decl.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/type_decl.zon
|
||||
//
|
||||
// type_decl.zon:2:12: error: invalid ZON value
|
11
test/cases/compile_errors/@import_zon_type_expr_array.zig
Normal file
11
test/cases/compile_errors/@import_zon_type_expr_array.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/type_expr_array.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/type_expr_array.zon
|
||||
//
|
||||
// type_expr_array.zon:1:1: error: type expressions not allowed in ZON
|
11
test/cases/compile_errors/@import_zon_type_expr_fn.zig
Normal file
11
test/cases/compile_errors/@import_zon_type_expr_fn.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/type_expr_fn.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/type_expr_fn.zon
|
||||
//
|
||||
// type_expr_fn.zon:1:1: error: type expressions not allowed in ZON
|
11
test/cases/compile_errors/@import_zon_type_expr_struct.zig
Normal file
11
test/cases/compile_errors/@import_zon_type_expr_struct.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/type_expr_struct.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/type_expr_struct.zon
|
||||
//
|
||||
// type_expr_struct.zon:1:1: error: type expressions not allowed in ZON
|
11
test/cases/compile_errors/@import_zon_type_expr_tuple.zig
Normal file
11
test/cases/compile_errors/@import_zon_type_expr_tuple.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/type_expr_tuple.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/type_expr_tuple.zon
|
||||
//
|
||||
// type_expr_tuple.zon:1:1: error: type expressions not allowed in ZON
|
11
test/cases/compile_errors/@import_zon_type_mismatch.zig
Normal file
11
test/cases/compile_errors/@import_zon_type_mismatch.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: bool = @import("zon/struct.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/struct.zon
|
||||
//
|
||||
// 2:21: error: expected type 'bool', found 'struct{comptime boolean: bool = true, comptime number: comptime_int = 123}'
|
12
test/cases/compile_errors/@import_zon_unescaped_newline.zig
Normal file
12
test/cases/compile_errors/@import_zon_unescaped_newline.zig
Normal file
@ -0,0 +1,12 @@
|
||||
pub fn main() void {
|
||||
const f: i8 = @import("zon/unescaped_newline.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/unescaped_newline.zon
|
||||
//
|
||||
// unescaped_newline.zon:1:1: error: expected expression, found 'invalid bytes'
|
||||
// unescaped_newline.zon:1:3: note: invalid byte: '\n'
|
11
test/cases/compile_errors/@import_zon_unknown_ident.zig
Normal file
11
test/cases/compile_errors/@import_zon_unknown_ident.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn main() void {
|
||||
const f: i32 = @import("zon/unknown_ident.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// output_mode=Exe
|
||||
// imports=zon/unknown_ident.zon
|
||||
//
|
||||
// unknown_ident.zon:2:14: error: use of unknown identifier 'truefalse'
|
3
test/cases/compile_errors/zon/addr_slice.zon
Normal file
3
test/cases/compile_errors/zon/addr_slice.zon
Normal file
@ -0,0 +1,3 @@
|
||||
.{
|
||||
.value = &.{ 1, 2, 3 },
|
||||
}
|
1
test/cases/compile_errors/zon/array.zon
Normal file
1
test/cases/compile_errors/zon/array.zon
Normal file
@ -0,0 +1 @@
|
||||
.{ 'a', 'b', 'c' }
|
3
test/cases/compile_errors/zon/desktop.ini
Normal file
3
test/cases/compile_errors/zon/desktop.ini
Normal file
@ -0,0 +1,3 @@
|
||||
[LocalizedFileNames]
|
||||
invalid_zon_2.zig=@invalid_zon_2.zig,0
|
||||
invalid_zon_1.zig=@invalid_zon_1.zig,0
|
1
test/cases/compile_errors/zon/double_negation_float.zon
Normal file
1
test/cases/compile_errors/zon/double_negation_float.zon
Normal file
@ -0,0 +1 @@
|
||||
--1.0
|
1
test/cases/compile_errors/zon/double_negation_int.zon
Normal file
1
test/cases/compile_errors/zon/double_negation_int.zon
Normal file
@ -0,0 +1 @@
|
||||
--1
|
4
test/cases/compile_errors/zon/enum_embedded_null.zon
Normal file
4
test/cases/compile_errors/zon/enum_embedded_null.zon
Normal file
@ -0,0 +1,4 @@
|
||||
.{
|
||||
.@"\x00",
|
||||
10,
|
||||
}
|
1
test/cases/compile_errors/zon/invalid_character.zon
Normal file
1
test/cases/compile_errors/zon/invalid_character.zon
Normal file
@ -0,0 +1 @@
|
||||
'\a'
|
1
test/cases/compile_errors/zon/invalid_number.zon
Normal file
1
test/cases/compile_errors/zon/invalid_number.zon
Normal file
@ -0,0 +1 @@
|
||||
368934881474191032a32
|
1
test/cases/compile_errors/zon/invalid_string.zon
Normal file
1
test/cases/compile_errors/zon/invalid_string.zon
Normal file
@ -0,0 +1 @@
|
||||
"\"\a\""
|
1
test/cases/compile_errors/zon/large_number.zon
Normal file
1
test/cases/compile_errors/zon/large_number.zon
Normal file
@ -0,0 +1 @@
|
||||
36893488147419103232
|
@ -0,0 +1 @@
|
||||
0012
|
1
test/cases/compile_errors/zon/negative_zero.zon
Normal file
1
test/cases/compile_errors/zon/negative_zero.zon
Normal file
@ -0,0 +1 @@
|
||||
-0
|
4
test/cases/compile_errors/zon/struct.zon
Normal file
4
test/cases/compile_errors/zon/struct.zon
Normal file
@ -0,0 +1,4 @@
|
||||
.{
|
||||
.boolean = true,
|
||||
.number = 123,
|
||||
}
|
4
test/cases/compile_errors/zon/struct_dup_field.zon
Normal file
4
test/cases/compile_errors/zon/struct_dup_field.zon
Normal file
@ -0,0 +1,4 @@
|
||||
.{
|
||||
.name = 10,
|
||||
.name = 20,
|
||||
}
|
4
test/cases/compile_errors/zon/syntax_error.zon
Normal file
4
test/cases/compile_errors/zon/syntax_error.zon
Normal file
@ -0,0 +1,4 @@
|
||||
.{
|
||||
.boolean = true
|
||||
.number = 123,
|
||||
}
|
3
test/cases/compile_errors/zon/type_decl.zon
Normal file
3
test/cases/compile_errors/zon/type_decl.zon
Normal file
@ -0,0 +1,3 @@
|
||||
.{
|
||||
.foo = struct {},
|
||||
}
|
1
test/cases/compile_errors/zon/type_expr_array.zon
Normal file
1
test/cases/compile_errors/zon/type_expr_array.zon
Normal file
@ -0,0 +1 @@
|
||||
[3]i32{1, 2, 3}
|
1
test/cases/compile_errors/zon/type_expr_fn.zon
Normal file
1
test/cases/compile_errors/zon/type_expr_fn.zon
Normal file
@ -0,0 +1 @@
|
||||
fn foo() void {}
|
1
test/cases/compile_errors/zon/type_expr_struct.zon
Normal file
1
test/cases/compile_errors/zon/type_expr_struct.zon
Normal file
@ -0,0 +1 @@
|
||||
Vec2{ .x = 1.0, .y = 2.0 }
|
1
test/cases/compile_errors/zon/type_expr_tuple.zon
Normal file
1
test/cases/compile_errors/zon/type_expr_tuple.zon
Normal file
@ -0,0 +1 @@
|
||||
Vec2{1.0, 2.0}
|
2
test/cases/compile_errors/zon/unescaped_newline.zon
Normal file
2
test/cases/compile_errors/zon/unescaped_newline.zon
Normal file
@ -0,0 +1,2 @@
|
||||
"a
|
||||
b"
|
3
test/cases/compile_errors/zon/unknown_ident.zon
Normal file
3
test/cases/compile_errors/zon/unknown_ident.zon
Normal file
@ -0,0 +1,3 @@
|
||||
.{
|
||||
.value = truefalse,
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user