Merge remote-tracking branch 'origin/master' into self-hosted-incremental-compilation
This commit is contained in:
commit
69a5f0d797
@ -800,10 +800,9 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
.Keyword_for,
|
||||
.Keyword_if,
|
||||
.Keyword_inline,
|
||||
.Keyword_nakedcc,
|
||||
.Keyword_noalias,
|
||||
.Keyword_noasync,
|
||||
.Keyword_noinline,
|
||||
.Keyword_nosuspend,
|
||||
.Keyword_or,
|
||||
.Keyword_orelse,
|
||||
.Keyword_packed,
|
||||
@ -813,7 +812,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
.Keyword_return,
|
||||
.Keyword_linksection,
|
||||
.Keyword_callconv,
|
||||
.Keyword_stdcallcc,
|
||||
.Keyword_struct,
|
||||
.Keyword_suspend,
|
||||
.Keyword_switch,
|
||||
|
@ -1565,7 +1565,7 @@ value == null{#endsyntax#}</pre>
|
||||
const array1 = [_]u32{1,2};
|
||||
const array2 = [_]u32{3,4};
|
||||
const together = array1 ++ array2;
|
||||
mem.eql(u32, together, &[_]u32{1,2,3,4}){#endsyntax#}</pre>
|
||||
mem.eql(u32, &together, &[_]u32{1,2,3,4}){#endsyntax#}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -6713,7 +6713,7 @@ const assert = std.debug.assert;
|
||||
test "async fn pointer in a struct field" {
|
||||
var data: i32 = 1;
|
||||
const Foo = struct {
|
||||
bar: async fn (*i32) void,
|
||||
bar: fn (*i32) callconv(.Async) void,
|
||||
};
|
||||
var foo = Foo{ .bar = func };
|
||||
var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined;
|
||||
@ -6723,7 +6723,7 @@ test "async fn pointer in a struct field" {
|
||||
assert(data == 4);
|
||||
}
|
||||
|
||||
async fn func(y: *i32) void {
|
||||
fn func(y: *i32) void {
|
||||
defer y.* += 2;
|
||||
y.* += 1;
|
||||
suspend;
|
||||
@ -8189,9 +8189,7 @@ fn List(comptime T: type) type {
|
||||
{#code_end#}
|
||||
<p>
|
||||
When {#syntax#}@This(){#endsyntax#} is used at global scope, it returns a reference to the
|
||||
current import. There is a proposal to remove the import type and use an empty struct
|
||||
type instead. See
|
||||
<a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details.
|
||||
struct that corresponds to the current file.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
@ -9990,6 +9988,13 @@ coding style.
|
||||
conventions.
|
||||
</p>
|
||||
<p>
|
||||
File names fall into two categories: types and namespaces. If the file
|
||||
(implicity a struct) has top level fields, it should be named like any
|
||||
other struct with fields using {#syntax#}TitleCase{#endsyntax#}. Otherwise,
|
||||
it should use {#syntax#}snake_case{#endsyntax#}. Directory names should be
|
||||
{#syntax#}snake_case{#endsyntax#}.
|
||||
</p>
|
||||
<p>
|
||||
These are general rules of thumb; if it makes sense to do something different,
|
||||
do what makes sense. For example, if there is an established convention such as
|
||||
{#syntax#}ENOENT{#endsyntax#}, follow the established convention.
|
||||
@ -9998,6 +10003,7 @@ coding style.
|
||||
{#header_open|Examples#}
|
||||
{#code_begin|syntax#}
|
||||
const namespace_name = @import("dir_name/file_name.zig");
|
||||
const TypeName = @import("dir_name/TypeName.zig");
|
||||
var global_var: i32 = undefined;
|
||||
const const_name = 42;
|
||||
const primitive_type_alias = f32;
|
||||
@ -10088,7 +10094,7 @@ TopLevelDecl
|
||||
/ (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
|
||||
/ KEYWORD_usingnamespace Expr SEMICOLON
|
||||
|
||||
FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
|
||||
VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
|
||||
|
||||
@ -10098,6 +10104,7 @@ ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
|
||||
Statement
|
||||
<- KEYWORD_comptime? VarDecl
|
||||
/ KEYWORD_comptime BlockExprStatement
|
||||
/ KEYWORD_nosuspend BlockExprStatement
|
||||
/ KEYWORD_suspend (SEMICOLON / BlockExprStatement)
|
||||
/ KEYWORD_defer BlockExprStatement
|
||||
/ KEYWORD_errdefer BlockExprStatement
|
||||
@ -10154,6 +10161,7 @@ PrimaryExpr
|
||||
/ IfExpr
|
||||
/ KEYWORD_break BreakLabel? Expr?
|
||||
/ KEYWORD_comptime Expr
|
||||
/ KEYWORD_nosuspend Expr
|
||||
/ KEYWORD_continue BreakLabel?
|
||||
/ KEYWORD_resume Expr
|
||||
/ KEYWORD_return Expr?
|
||||
@ -10255,11 +10263,6 @@ WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
|
||||
|
||||
LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
|
||||
|
||||
# Fn specific
|
||||
FnCC
|
||||
<- KEYWORD_extern
|
||||
/ KEYWORD_async
|
||||
|
||||
ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
||||
|
||||
ParamType
|
||||
@ -10521,6 +10524,7 @@ KEYWORD_for <- 'for' end_of_word
|
||||
KEYWORD_if <- 'if' end_of_word
|
||||
KEYWORD_inline <- 'inline' end_of_word
|
||||
KEYWORD_noalias <- 'noalias' end_of_word
|
||||
KEYWORD_nosuspend <- 'nosuspend' end_of_word
|
||||
KEYWORD_null <- 'null' end_of_word
|
||||
KEYWORD_or <- 'or' end_of_word
|
||||
KEYWORD_orelse <- 'orelse' end_of_word
|
||||
|
@ -227,6 +227,8 @@ test "ascii character classes" {
|
||||
testing.expect(isSpace(' '));
|
||||
}
|
||||
|
||||
/// Allocates a lower case copy of `ascii_string`.
|
||||
/// Caller owns returned string and must free with `allocator`.
|
||||
pub fn allocLowerString(allocator: *std.mem.Allocator, ascii_string: []const u8) ![]u8 {
|
||||
const result = try allocator.alloc(u8, ascii_string.len);
|
||||
for (result) |*c, i| {
|
||||
@ -241,6 +243,23 @@ test "allocLowerString" {
|
||||
std.testing.expect(std.mem.eql(u8, "abcdefghijklmnopqrst0234+💩!", result));
|
||||
}
|
||||
|
||||
/// Allocates an upper case copy of `ascii_string`.
|
||||
/// Caller owns returned string and must free with `allocator`.
|
||||
pub fn allocUpperString(allocator: *std.mem.Allocator, ascii_string: []const u8) ![]u8 {
|
||||
const result = try allocator.alloc(u8, ascii_string.len);
|
||||
for (result) |*c, i| {
|
||||
c.* = toUpper(ascii_string[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
test "allocUpperString" {
|
||||
const result = try allocUpperString(std.testing.allocator, "aBcDeFgHiJkLmNOPqrst0234+💩!");
|
||||
defer std.testing.allocator.free(result);
|
||||
std.testing.expect(std.mem.eql(u8, "ABCDEFGHIJKLMNOPQRST0234+💩!", result));
|
||||
}
|
||||
|
||||
/// Compares strings `a` and `b` case insensitively and returns whether they are equal.
|
||||
pub fn eqlIgnoreCase(a: []const u8, b: []const u8) bool {
|
||||
if (a.len != b.len) return false;
|
||||
for (a) |a_c, i| {
|
||||
@ -255,7 +274,7 @@ test "eqlIgnoreCase" {
|
||||
std.testing.expect(!eqlIgnoreCase("hElLo!", "helro!"));
|
||||
}
|
||||
|
||||
/// Finds `substr` in `container`, starting at `start_index`.
|
||||
/// Finds `substr` in `container`, ignoring case, starting at `start_index`.
|
||||
/// TODO boyer-moore algorithm
|
||||
pub fn indexOfIgnoreCasePos(container: []const u8, start_index: usize, substr: []const u8) ?usize {
|
||||
if (substr.len > container.len) return null;
|
||||
@ -268,7 +287,7 @@ pub fn indexOfIgnoreCasePos(container: []const u8, start_index: usize, substr: [
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Finds `substr` in `container`, starting at `start_index`.
|
||||
/// Finds `substr` in `container`, ignoring case, starting at index 0.
|
||||
pub fn indexOfIgnoreCase(container: []const u8, substr: []const u8) ?usize {
|
||||
return indexOfIgnoreCasePos(container, 0, substr);
|
||||
}
|
||||
|
@ -284,11 +284,11 @@ pub const Builder = struct {
|
||||
return run_step;
|
||||
}
|
||||
|
||||
fn dupe(self: *Builder, bytes: []const u8) []u8 {
|
||||
pub fn dupe(self: *Builder, bytes: []const u8) []u8 {
|
||||
return mem.dupe(self.allocator, u8, bytes) catch unreachable;
|
||||
}
|
||||
|
||||
fn dupePath(self: *Builder, bytes: []const u8) []u8 {
|
||||
pub fn dupePath(self: *Builder, bytes: []const u8) []u8 {
|
||||
const the_copy = self.dupe(bytes);
|
||||
for (the_copy) |*byte| {
|
||||
switch (byte.*) {
|
||||
@ -717,7 +717,7 @@ pub const Builder = struct {
|
||||
return self.invalid_user_input;
|
||||
}
|
||||
|
||||
fn spawnChild(self: *Builder, argv: []const []const u8) !void {
|
||||
pub fn spawnChild(self: *Builder, argv: []const []const u8) !void {
|
||||
return self.spawnChildEnvMap(null, self.env_map, argv);
|
||||
}
|
||||
|
||||
@ -843,7 +843,7 @@ pub const Builder = struct {
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
|
||||
pub fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
|
||||
if (self.verbose) {
|
||||
warn("cp {} {} ", .{ source_path, dest_path });
|
||||
}
|
||||
@ -855,7 +855,7 @@ pub const Builder = struct {
|
||||
};
|
||||
}
|
||||
|
||||
fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
|
||||
pub fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
|
||||
return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable;
|
||||
}
|
||||
|
||||
@ -985,7 +985,7 @@ pub const Builder = struct {
|
||||
self.search_prefixes.append(search_prefix) catch unreachable;
|
||||
}
|
||||
|
||||
fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
|
||||
pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
|
||||
const base_dir = switch (dir) {
|
||||
.Prefix => self.install_path,
|
||||
.Bin => self.exe_dir,
|
||||
@ -1132,6 +1132,7 @@ pub const LibExeObjStep = struct {
|
||||
name_prefix: []const u8,
|
||||
filter: ?[]const u8,
|
||||
single_threaded: bool,
|
||||
test_evented_io: bool = false,
|
||||
code_model: builtin.CodeModel = .default,
|
||||
|
||||
root_src: ?FileSource,
|
||||
@ -1864,6 +1865,10 @@ pub const LibExeObjStep = struct {
|
||||
try zig_args.append(filter);
|
||||
}
|
||||
|
||||
if (self.test_evented_io) {
|
||||
try zig_args.append("--test-evented-io");
|
||||
}
|
||||
|
||||
if (self.name_prefix.len != 0) {
|
||||
try zig_args.append("--test-name-prefix");
|
||||
try zig_args.append(self.name_prefix);
|
||||
|
@ -217,7 +217,7 @@ pub extern "c" fn utimes(path: [*:0]const u8, times: *[2]timeval) c_int;
|
||||
pub extern "c" fn utimensat(dirfd: fd_t, pathname: [*:0]const u8, times: *[2]timespec, flags: u32) c_int;
|
||||
pub extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int;
|
||||
|
||||
pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
|
||||
pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: fn (?*c_void) callconv(.C) ?*c_void, noalias arg: ?*c_void) c_int;
|
||||
pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
|
||||
pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
|
||||
pub extern "c" fn pthread_attr_setguardsize(attr: *pthread_attr_t, guardsize: usize) c_int;
|
||||
|
@ -9,7 +9,7 @@ pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
|
||||
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||
pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
|
||||
|
||||
pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
|
||||
pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int;
|
||||
pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
|
@ -24,7 +24,7 @@ pub extern "c" fn sendfile(
|
||||
flags: u32,
|
||||
) c_int;
|
||||
|
||||
pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
|
||||
pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int;
|
||||
pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
|
@ -75,7 +75,7 @@ pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*]const u8, mask: u32)
|
||||
/// See std.elf for constants for this
|
||||
pub extern "c" fn getauxval(__type: c_ulong) c_ulong;
|
||||
|
||||
pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
|
||||
pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int;
|
||||
pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
|
||||
|
||||
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||
|
@ -6,7 +6,7 @@ usingnamespace std.c;
|
||||
extern "c" fn __errno() *c_int;
|
||||
pub const _errno = __errno;
|
||||
|
||||
pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
|
||||
pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int;
|
||||
pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
|
||||
|
||||
pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
|
||||
|
@ -338,7 +338,7 @@ pub const Blake3 = struct {
|
||||
}
|
||||
|
||||
// Section 5.1.2 of the BLAKE3 spec explains this algorithm in more detail.
|
||||
fn add_chunk_chaining_value(self: *Blake3, new_cv: [8]u32, total_chunks: u64) void {
|
||||
fn add_chunk_chaining_value(self: *Blake3, first_cv: [8]u32, total_chunks: u64) void {
|
||||
// This chunk might complete some subtrees. For each completed subtree,
|
||||
// its left child will be the current top entry in the CV stack, and
|
||||
// its right child will be the current value of `new_cv`. Pop each left
|
||||
@ -346,6 +346,7 @@ pub const Blake3 = struct {
|
||||
// with the result. After all these merges, push the final value of
|
||||
// `new_cv` onto the stack. The number of completed subtrees is given
|
||||
// by the number of trailing 0-bits in the new total number of chunks.
|
||||
var new_cv = first_cv;
|
||||
var chunk_counter = total_chunks;
|
||||
while (chunk_counter & 1 == 0) {
|
||||
new_cv = parent_cv(self.pop_cv(), new_cv, self.key, self.flags);
|
||||
|
@ -62,7 +62,7 @@ pub fn warn(comptime fmt: []const u8, args: var) void {
|
||||
const held = stderr_mutex.acquire();
|
||||
defer held.release();
|
||||
const stderr = getStderrStream();
|
||||
noasync stderr.print(fmt, args) catch return;
|
||||
nosuspend stderr.print(fmt, args) catch return;
|
||||
}
|
||||
|
||||
pub fn getStderrStream() *File.OutStream {
|
||||
@ -112,7 +112,7 @@ pub fn detectTTYConfig() TTY.Config {
|
||||
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const stderr = getStderrStream();
|
||||
if (builtin.strip_debug_info) {
|
||||
stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
|
||||
@ -133,7 +133,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||
/// unbuffered, and ignores any error returned.
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const stderr = getStderrStream();
|
||||
if (builtin.strip_debug_info) {
|
||||
stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
|
||||
@ -203,7 +203,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
|
||||
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const stderr = getStderrStream();
|
||||
if (builtin.strip_debug_info) {
|
||||
stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
|
||||
@ -261,7 +261,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
|
||||
resetSegfaultHandler();
|
||||
}
|
||||
|
||||
noasync switch (panic_stage) {
|
||||
nosuspend switch (panic_stage) {
|
||||
0 => {
|
||||
panic_stage = 1;
|
||||
|
||||
@ -357,7 +357,7 @@ pub const StackIterator = struct {
|
||||
else
|
||||
0;
|
||||
|
||||
fn next(self: *StackIterator) ?usize {
|
||||
pub fn next(self: *StackIterator) ?usize {
|
||||
var address = self.next_internal() orelse return null;
|
||||
|
||||
if (self.first_address) |first_address| {
|
||||
@ -447,7 +447,7 @@ pub const TTY = struct {
|
||||
windows_api,
|
||||
|
||||
fn setColor(conf: Config, out_stream: var, color: Color) void {
|
||||
noasync switch (conf) {
|
||||
nosuspend switch (conf) {
|
||||
.no_color => return,
|
||||
.escape_codes => switch (color) {
|
||||
.Red => out_stream.writeAll(RED) catch return,
|
||||
@ -604,7 +604,7 @@ fn printLineInfo(
|
||||
tty_config: TTY.Config,
|
||||
comptime printLineFromFile: var,
|
||||
) !void {
|
||||
noasync {
|
||||
nosuspend {
|
||||
tty_config.setColor(out_stream, .White);
|
||||
|
||||
if (line_info) |*li| {
|
||||
@ -651,7 +651,7 @@ pub const OpenSelfDebugInfoError = error{
|
||||
|
||||
/// TODO resources https://github.com/ziglang/zig/issues/4353
|
||||
pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
|
||||
noasync {
|
||||
nosuspend {
|
||||
if (builtin.strip_debug_info)
|
||||
return error.MissingDebugInfo;
|
||||
if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
|
||||
@ -672,7 +672,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
|
||||
|
||||
/// TODO resources https://github.com/ziglang/zig/issues/4353
|
||||
fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const coff_file = try std.fs.openFileAbsoluteW(coff_file_path, .{ .intended_io_mode = .blocking });
|
||||
errdefer coff_file.close();
|
||||
|
||||
@ -853,7 +853,7 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
|
||||
|
||||
/// TODO resources https://github.com/ziglang/zig/issues/4353
|
||||
pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const mapped_mem = try mapWholeFile(elf_file_path);
|
||||
const hdr = @ptrCast(*const elf.Ehdr, &mapped_mem[0]);
|
||||
if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
@ -1056,7 +1056,7 @@ const MachoSymbol = struct {
|
||||
};
|
||||
|
||||
fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const file = try fs.cwd().openFile(path, .{ .intended_io_mode = .blocking });
|
||||
defer file.close();
|
||||
|
||||
@ -1418,7 +1418,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) {
|
||||
}
|
||||
|
||||
fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
|
||||
noasync {
|
||||
nosuspend {
|
||||
// Translate the VA into an address into this object
|
||||
const relocated_address = address - self.base_address;
|
||||
assert(relocated_address >= 0x100000000);
|
||||
@ -1643,14 +1643,14 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) {
|
||||
// Translate the VA into an address into this object
|
||||
const relocated_address = address - self.base_address;
|
||||
|
||||
if (noasync self.dwarf.findCompileUnit(relocated_address)) |compile_unit| {
|
||||
if (nosuspend self.dwarf.findCompileUnit(relocated_address)) |compile_unit| {
|
||||
return SymbolInfo{
|
||||
.symbol_name = noasync self.dwarf.getSymbolName(relocated_address) orelse "???",
|
||||
.symbol_name = nosuspend self.dwarf.getSymbolName(relocated_address) orelse "???",
|
||||
.compile_unit_name = compile_unit.die.getAttrString(&self.dwarf, DW.AT_name) catch |err| switch (err) {
|
||||
error.MissingDebugInfo, error.InvalidDebugInfo => "???",
|
||||
else => return err,
|
||||
},
|
||||
.line_info = noasync self.dwarf.getLineNumberInfo(compile_unit.*, relocated_address) catch |err| switch (err) {
|
||||
.line_info = nosuspend self.dwarf.getLineNumberInfo(compile_unit.*, relocated_address) catch |err| switch (err) {
|
||||
error.MissingDebugInfo, error.InvalidDebugInfo => null,
|
||||
else => return err,
|
||||
},
|
||||
|
@ -121,7 +121,7 @@ const Die = struct {
|
||||
};
|
||||
}
|
||||
|
||||
fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]const u8 {
|
||||
pub fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]const u8 {
|
||||
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||
return switch (form_value.*) {
|
||||
FormValue.String => |value| value,
|
||||
@ -248,17 +248,17 @@ fn readUnitLength(in_stream: var, endian: builtin.Endian, is_64: *bool) !u64 {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO the noasyncs here are workarounds
|
||||
// TODO the nosuspends here are workarounds
|
||||
fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
|
||||
const buf = try allocator.alloc(u8, size);
|
||||
errdefer allocator.free(buf);
|
||||
if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;
|
||||
if ((try nosuspend in_stream.read(buf)) < size) return error.EndOfFile;
|
||||
return buf;
|
||||
}
|
||||
|
||||
// TODO the noasyncs here are workarounds
|
||||
// TODO the nosuspends here are workarounds
|
||||
fn readAddress(in_stream: var, endian: builtin.Endian, is_64: bool) !u64 {
|
||||
return noasync if (is_64)
|
||||
return nosuspend if (is_64)
|
||||
try in_stream.readInt(u64, endian)
|
||||
else
|
||||
@as(u64, try in_stream.readInt(u32, endian));
|
||||
@ -269,29 +269,29 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize
|
||||
return FormValue{ .Block = buf };
|
||||
}
|
||||
|
||||
// TODO the noasyncs here are workarounds
|
||||
// TODO the nosuspends here are workarounds
|
||||
fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, endian: builtin.Endian, size: usize) !FormValue {
|
||||
const block_len = try noasync in_stream.readVarInt(usize, endian, size);
|
||||
const block_len = try nosuspend in_stream.readVarInt(usize, endian, size);
|
||||
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
||||
}
|
||||
|
||||
fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, endian: builtin.Endian, comptime size: i32) !FormValue {
|
||||
// TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
|
||||
// `noasync` should be removed from all the function calls once it is fixed.
|
||||
// `nosuspend` should be removed from all the function calls once it is fixed.
|
||||
return FormValue{
|
||||
.Const = Constant{
|
||||
.signed = signed,
|
||||
.payload = switch (size) {
|
||||
1 => try noasync in_stream.readInt(u8, endian),
|
||||
2 => try noasync in_stream.readInt(u16, endian),
|
||||
4 => try noasync in_stream.readInt(u32, endian),
|
||||
8 => try noasync in_stream.readInt(u64, endian),
|
||||
1 => try nosuspend in_stream.readInt(u8, endian),
|
||||
2 => try nosuspend in_stream.readInt(u16, endian),
|
||||
4 => try nosuspend in_stream.readInt(u32, endian),
|
||||
8 => try nosuspend in_stream.readInt(u64, endian),
|
||||
-1 => blk: {
|
||||
if (signed) {
|
||||
const x = try noasync leb.readILEB128(i64, in_stream);
|
||||
const x = try nosuspend leb.readILEB128(i64, in_stream);
|
||||
break :blk @bitCast(u64, x);
|
||||
} else {
|
||||
const x = try noasync leb.readULEB128(u64, in_stream);
|
||||
const x = try nosuspend leb.readULEB128(u64, in_stream);
|
||||
break :blk x;
|
||||
}
|
||||
},
|
||||
@ -301,21 +301,21 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
|
||||
};
|
||||
}
|
||||
|
||||
// TODO the noasyncs here are workarounds
|
||||
// TODO the nosuspends here are workarounds
|
||||
fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, endian: builtin.Endian, size: i32) !FormValue {
|
||||
return FormValue{
|
||||
.Ref = switch (size) {
|
||||
1 => try noasync in_stream.readInt(u8, endian),
|
||||
2 => try noasync in_stream.readInt(u16, endian),
|
||||
4 => try noasync in_stream.readInt(u32, endian),
|
||||
8 => try noasync in_stream.readInt(u64, endian),
|
||||
-1 => try noasync leb.readULEB128(u64, in_stream),
|
||||
1 => try nosuspend in_stream.readInt(u8, endian),
|
||||
2 => try nosuspend in_stream.readInt(u16, endian),
|
||||
4 => try nosuspend in_stream.readInt(u32, endian),
|
||||
8 => try nosuspend in_stream.readInt(u64, endian),
|
||||
-1 => try nosuspend leb.readULEB128(u64, in_stream),
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// TODO the noasyncs here are workarounds
|
||||
// TODO the nosuspends here are workarounds
|
||||
fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endian: builtin.Endian, is_64: bool) anyerror!FormValue {
|
||||
return switch (form_id) {
|
||||
FORM_addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) },
|
||||
@ -323,7 +323,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia
|
||||
FORM_block2 => parseFormValueBlock(allocator, in_stream, endian, 2),
|
||||
FORM_block4 => parseFormValueBlock(allocator, in_stream, endian, 4),
|
||||
FORM_block => x: {
|
||||
const block_len = try noasync leb.readULEB128(usize, in_stream);
|
||||
const block_len = try nosuspend leb.readULEB128(usize, in_stream);
|
||||
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
||||
},
|
||||
FORM_data1 => parseFormValueConstant(allocator, in_stream, false, endian, 1),
|
||||
@ -335,11 +335,11 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia
|
||||
return parseFormValueConstant(allocator, in_stream, signed, endian, -1);
|
||||
},
|
||||
FORM_exprloc => {
|
||||
const size = try noasync leb.readULEB128(usize, in_stream);
|
||||
const size = try nosuspend leb.readULEB128(usize, in_stream);
|
||||
const buf = try readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue{ .ExprLoc = buf };
|
||||
},
|
||||
FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
|
||||
FORM_flag => FormValue{ .Flag = (try nosuspend in_stream.readByte()) != 0 },
|
||||
FORM_flag_present => FormValue{ .Flag = true },
|
||||
FORM_sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) },
|
||||
|
||||
@ -350,12 +350,12 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia
|
||||
FORM_ref_udata => parseFormValueRef(allocator, in_stream, endian, -1),
|
||||
|
||||
FORM_ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) },
|
||||
FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readInt(u64, endian) },
|
||||
FORM_ref_sig8 => FormValue{ .Ref = try nosuspend in_stream.readInt(u64, endian) },
|
||||
|
||||
FORM_string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
|
||||
FORM_strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) },
|
||||
FORM_indirect => {
|
||||
const child_form_id = try noasync leb.readULEB128(u64, in_stream);
|
||||
const child_form_id = try nosuspend leb.readULEB128(u64, in_stream);
|
||||
const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64));
|
||||
var frame = try allocator.create(F);
|
||||
defer allocator.destroy(frame);
|
||||
@ -389,7 +389,7 @@ pub const DwarfInfo = struct {
|
||||
return self.abbrev_table_list.allocator;
|
||||
}
|
||||
|
||||
fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
|
||||
pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
|
||||
for (di.func_list.span()) |*func| {
|
||||
if (func.pc_range) |range| {
|
||||
if (address >= range.start and address < range.end) {
|
||||
@ -578,7 +578,7 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
|
||||
pub fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
|
||||
for (di.compile_unit_list.span()) |*compile_unit| {
|
||||
if (compile_unit.pc_range) |range| {
|
||||
if (target_address >= range.start and target_address < range.end) return compile_unit;
|
||||
@ -690,7 +690,7 @@ pub const DwarfInfo = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
|
||||
pub fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
|
||||
var stream = io.fixedBufferStream(di.debug_line);
|
||||
const in = &stream.inStream();
|
||||
const seekable = &stream.seekableStream();
|
||||
|
@ -33,11 +33,11 @@ const LinkMap = extern struct {
|
||||
pub const Iterator = struct {
|
||||
current: ?*LinkMap,
|
||||
|
||||
fn end(self: *Iterator) bool {
|
||||
pub fn end(self: *Iterator) bool {
|
||||
return self.current == null;
|
||||
}
|
||||
|
||||
fn next(self: *Iterator) ?*LinkMap {
|
||||
pub fn next(self: *Iterator) ?*LinkMap {
|
||||
if (self.current) |it| {
|
||||
self.current = it.l_next;
|
||||
return it;
|
||||
|
@ -548,6 +548,7 @@ fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
|
||||
error.BrokenPipe => return error.UnableToReadElfFile,
|
||||
error.Unseekable => return error.UnableToReadElfFile,
|
||||
error.ConnectionResetByPeer => return error.UnableToReadElfFile,
|
||||
error.ConnectionTimedOut => return error.UnableToReadElfFile,
|
||||
error.InputOutput => return error.FileSystem,
|
||||
error.Unexpected => return error.Unexpected,
|
||||
error.WouldBlock => return error.Unexpected,
|
||||
|
@ -21,7 +21,7 @@ pub fn Batch(
|
||||
/// usual recommended option for this parameter.
|
||||
auto_async,
|
||||
|
||||
/// Always uses the `noasync` keyword when using `await` on the jobs,
|
||||
/// Always uses the `nosuspend` keyword when using `await` on the jobs,
|
||||
/// making `add` and `wait` non-async functions. Asserts that the jobs do not suspend.
|
||||
never_async,
|
||||
|
||||
@ -75,7 +75,7 @@ pub fn Batch(
|
||||
const job = &self.jobs[self.next_job_index];
|
||||
self.next_job_index = (self.next_job_index + 1) % max_jobs;
|
||||
if (job.frame) |existing| {
|
||||
job.result = if (async_ok) await existing else noasync await existing;
|
||||
job.result = if (async_ok) await existing else nosuspend await existing;
|
||||
if (CollectedResult != void) {
|
||||
job.result catch |err| {
|
||||
self.collected_result = err;
|
||||
@ -94,7 +94,7 @@ pub fn Batch(
|
||||
/// a time, however, it need not be the same thread.
|
||||
pub fn wait(self: *Self) CollectedResult {
|
||||
for (self.jobs) |*job| if (job.frame) |f| {
|
||||
job.result = if (async_ok) await f else noasync await f;
|
||||
job.result = if (async_ok) await f else nosuspend await f;
|
||||
if (CollectedResult != void) {
|
||||
job.result catch |err| {
|
||||
self.collected_result = err;
|
||||
|
@ -105,7 +105,7 @@ pub fn Channel(comptime T: type) type {
|
||||
|
||||
/// await this function to get an item from the channel. If the buffer is empty, the frame will
|
||||
/// complete when the next item is put in the channel.
|
||||
pub async fn get(self: *SelfChannel) T {
|
||||
pub fn get(self: *SelfChannel) callconv(.Async) T {
|
||||
// TODO https://github.com/ziglang/zig/issues/2765
|
||||
var result: T = undefined;
|
||||
var my_tick_node = Loop.NextTickNode.init(@frame());
|
||||
@ -305,8 +305,7 @@ test "std.event.Channel wraparound" {
|
||||
channel.put(7);
|
||||
testing.expectEqual(@as(i32, 7), channel.get());
|
||||
}
|
||||
|
||||
async fn testChannelGetter(channel: *Channel(i32)) void {
|
||||
fn testChannelGetter(channel: *Channel(i32)) callconv(.Async) void {
|
||||
const value1 = channel.get();
|
||||
testing.expect(value1 == 1234);
|
||||
|
||||
@ -321,12 +320,10 @@ async fn testChannelGetter(channel: *Channel(i32)) void {
|
||||
testing.expect(value4.? == 4444);
|
||||
await last_put;
|
||||
}
|
||||
|
||||
async fn testChannelPutter(channel: *Channel(i32)) void {
|
||||
fn testChannelPutter(channel: *Channel(i32)) callconv(.Async) void {
|
||||
channel.put(1234);
|
||||
channel.put(4567);
|
||||
}
|
||||
|
||||
async fn testPut(channel: *Channel(i32), value: i32) void {
|
||||
fn testPut(channel: *Channel(i32), value: i32) callconv(.Async) void {
|
||||
channel.put(value);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ pub fn Future(comptime T: type) type {
|
||||
/// Obtain the value. If it's not available, wait until it becomes
|
||||
/// available.
|
||||
/// Thread-safe.
|
||||
pub async fn get(self: *Self) *T {
|
||||
pub fn get(self: *Self) callconv(.Async) *T {
|
||||
if (@atomicLoad(Available, &self.available, .SeqCst) == .Finished) {
|
||||
return &self.data;
|
||||
}
|
||||
@ -59,7 +59,7 @@ pub fn Future(comptime T: type) type {
|
||||
/// should start working on the data.
|
||||
/// It's not required to call start() before resolve() but it can be useful since
|
||||
/// this method is thread-safe.
|
||||
pub async fn start(self: *Self) ?*T {
|
||||
pub fn start(self: *Self) callconv(.Async) ?*T {
|
||||
const state = @cmpxchgStrong(Available, &self.available, .NotStarted, .Started, .SeqCst, .SeqCst) orelse return null;
|
||||
switch (state) {
|
||||
.Started => {
|
||||
|
@ -84,7 +84,7 @@ pub fn Group(comptime ReturnType: type) type {
|
||||
/// Wait for all the calls and promises of the group to complete.
|
||||
/// Thread-safe.
|
||||
/// Safe to call any number of times.
|
||||
pub async fn wait(self: *Self) ReturnType {
|
||||
pub fn wait(self: *Self) callconv(.Async) ReturnType {
|
||||
const held = self.lock.acquire();
|
||||
defer held.release();
|
||||
|
||||
@ -127,8 +127,7 @@ test "std.event.Group" {
|
||||
|
||||
const handle = async testGroup(std.heap.page_allocator);
|
||||
}
|
||||
|
||||
async fn testGroup(allocator: *Allocator) void {
|
||||
fn testGroup(allocator: *Allocator) callconv(.Async) void {
|
||||
var count: usize = 0;
|
||||
var group = Group(void).init(allocator);
|
||||
var sleep_a_little_frame = async sleepALittle(&count);
|
||||
@ -145,20 +144,17 @@ async fn testGroup(allocator: *Allocator) void {
|
||||
another.add(&something_that_fails_frame) catch @panic("memory");
|
||||
testing.expectError(error.ItBroke, another.wait());
|
||||
}
|
||||
|
||||
async fn sleepALittle(count: *usize) void {
|
||||
fn sleepALittle(count: *usize) callconv(.Async) void {
|
||||
std.time.sleep(1 * std.time.millisecond);
|
||||
_ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
|
||||
}
|
||||
|
||||
async fn increaseByTen(count: *usize) void {
|
||||
fn increaseByTen(count: *usize) callconv(.Async) void {
|
||||
var i: usize = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
_ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
async fn doSomethingThatFails() anyerror!void {}
|
||||
async fn somethingElse() anyerror!void {
|
||||
fn doSomethingThatFails() callconv(.Async) anyerror!void {}
|
||||
fn somethingElse() callconv(.Async) anyerror!void {
|
||||
return error.ItBroke;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ pub const Lock = struct {
|
||||
while (self.queue.get()) |node| resume node.data;
|
||||
}
|
||||
|
||||
pub async fn acquire(self: *Lock) Held {
|
||||
pub fn acquire(self: *Lock) callconv(.Async) Held {
|
||||
var my_tick_node = Loop.NextTickNode.init(@frame());
|
||||
|
||||
errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire
|
||||
@ -134,8 +134,7 @@ test "std.event.Lock" {
|
||||
const expected_result = [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
|
||||
testing.expectEqualSlices(i32, &expected_result, &shared_test_data);
|
||||
}
|
||||
|
||||
async fn testLock(lock: *Lock) void {
|
||||
fn testLock(lock: *Lock) callconv(.Async) void {
|
||||
var handle1 = async lockRunner(lock);
|
||||
var tick_node1 = Loop.NextTickNode{
|
||||
.prev = undefined,
|
||||
@ -167,8 +166,7 @@ async fn testLock(lock: *Lock) void {
|
||||
|
||||
var shared_test_data = [1]i32{0} ** 10;
|
||||
var shared_test_index: usize = 0;
|
||||
|
||||
async fn lockRunner(lock: *Lock) void {
|
||||
fn lockRunner(lock: *Lock) callconv(.Async) void {
|
||||
suspend; // resumed by onNextTick
|
||||
|
||||
var i: usize = 0;
|
||||
|
@ -31,7 +31,7 @@ pub fn Locked(comptime T: type) type {
|
||||
self.lock.deinit();
|
||||
}
|
||||
|
||||
pub async fn acquire(self: *Self) HeldLock {
|
||||
pub fn acquire(self: *Self) callconv(.Async) HeldLock {
|
||||
return HeldLock{
|
||||
// TODO guaranteed allocation elision
|
||||
.held = self.lock.acquire(),
|
||||
|
@ -195,7 +195,7 @@ pub const Loop = struct {
|
||||
const wakeup_bytes = [_]u8{0x1} ** 8;
|
||||
|
||||
fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
|
||||
noasync switch (builtin.os.tag) {
|
||||
nosuspend switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
errdefer {
|
||||
while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
|
||||
@ -371,7 +371,7 @@ pub const Loop = struct {
|
||||
}
|
||||
|
||||
fn deinitOsData(self: *Loop) void {
|
||||
noasync switch (builtin.os.tag) {
|
||||
nosuspend switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
os.close(self.os_data.final_eventfd);
|
||||
while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
|
||||
@ -493,7 +493,7 @@ pub const Loop = struct {
|
||||
pub fn waitUntilFdWritableOrReadable(self: *Loop, fd: os.fd_t) void {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
self.linuxWaitFd(@intCast(usize, fd), os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN);
|
||||
self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN);
|
||||
},
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => {
|
||||
self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT);
|
||||
@ -503,7 +503,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) void {
|
||||
pub fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, flags: u16) void {
|
||||
var resume_node = ResumeNode.Basic{
|
||||
.base = ResumeNode{
|
||||
.id = ResumeNode.Id.Basic,
|
||||
@ -512,21 +512,28 @@ pub const Loop = struct {
|
||||
},
|
||||
.kev = undefined,
|
||||
};
|
||||
defer self.bsdRemoveKev(ident, filter);
|
||||
|
||||
defer {
|
||||
// If the kevent was set to be ONESHOT, it doesn't need to be deleted manually.
|
||||
if (flags & os.EV_ONESHOT != 0) {
|
||||
self.bsdRemoveKev(ident, filter);
|
||||
}
|
||||
}
|
||||
|
||||
suspend {
|
||||
self.bsdAddKev(&resume_node, ident, filter, fflags) catch unreachable;
|
||||
self.bsdAddKev(&resume_node, ident, filter, flags) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
/// resume_node must live longer than the anyframe that it holds a reference to.
|
||||
pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
|
||||
pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, flags: u16) !void {
|
||||
self.beginOneEvent();
|
||||
errdefer self.finishOneEvent();
|
||||
var kev = [1]os.Kevent{os.Kevent{
|
||||
.ident = ident,
|
||||
.filter = filter,
|
||||
.flags = os.EV_ADD | os.EV_ENABLE | os.EV_CLEAR,
|
||||
.fflags = fflags,
|
||||
.flags = os.EV_ADD | os.EV_ENABLE | os.EV_CLEAR | flags,
|
||||
.fflags = 0,
|
||||
.data = 0,
|
||||
.udata = @ptrToInt(&resume_node.base),
|
||||
}};
|
||||
@ -616,14 +623,16 @@ pub const Loop = struct {
|
||||
|
||||
self.workerRun();
|
||||
|
||||
switch (builtin.os.tag) {
|
||||
.linux,
|
||||
.macosx,
|
||||
.freebsd,
|
||||
.netbsd,
|
||||
.dragonfly,
|
||||
=> self.fs_thread.wait(),
|
||||
else => {},
|
||||
if (!builtin.single_threaded) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux,
|
||||
.macosx,
|
||||
.freebsd,
|
||||
.netbsd,
|
||||
.dragonfly,
|
||||
=> self.fs_thread.wait(),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
for (self.extra_threads) |extra_thread| {
|
||||
@ -663,7 +672,7 @@ pub const Loop = struct {
|
||||
}
|
||||
|
||||
pub fn finishOneEvent(self: *Loop) void {
|
||||
noasync {
|
||||
nosuspend {
|
||||
const prev = @atomicRmw(usize, &self.pending_event_count, .Sub, 1, .SeqCst);
|
||||
if (prev != 1) return;
|
||||
|
||||
@ -1041,7 +1050,7 @@ pub const Loop = struct {
|
||||
}
|
||||
|
||||
fn posixFsRun(self: *Loop) void {
|
||||
noasync while (true) {
|
||||
nosuspend while (true) {
|
||||
self.fs_thread_wakeup.reset();
|
||||
while (self.fs_queue.get()) |node| {
|
||||
switch (node.data.msg) {
|
||||
|
@ -97,7 +97,7 @@ pub const RwLock = struct {
|
||||
while (self.reader_queue.get()) |node| resume node.data;
|
||||
}
|
||||
|
||||
pub async fn acquireRead(self: *RwLock) HeldRead {
|
||||
pub fn acquireRead(self: *RwLock) callconv(.Async) HeldRead {
|
||||
_ = @atomicRmw(usize, &self.reader_lock_count, .Add, 1, .SeqCst);
|
||||
|
||||
suspend {
|
||||
@ -130,7 +130,7 @@ pub const RwLock = struct {
|
||||
return HeldRead{ .lock = self };
|
||||
}
|
||||
|
||||
pub async fn acquireWrite(self: *RwLock) HeldWrite {
|
||||
pub fn acquireWrite(self: *RwLock) callconv(.Async) HeldWrite {
|
||||
suspend {
|
||||
var my_tick_node = Loop.NextTickNode{
|
||||
.data = @frame(),
|
||||
@ -225,8 +225,7 @@ test "std.event.RwLock" {
|
||||
const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
|
||||
testing.expectEqualSlices(i32, expected_result, shared_test_data);
|
||||
}
|
||||
|
||||
async fn testLock(allocator: *Allocator, lock: *RwLock) void {
|
||||
fn testLock(allocator: *Allocator, lock: *RwLock) callconv(.Async) void {
|
||||
var read_nodes: [100]Loop.NextTickNode = undefined;
|
||||
for (read_nodes) |*read_node| {
|
||||
const frame = allocator.create(@Frame(readRunner)) catch @panic("memory");
|
||||
@ -259,8 +258,7 @@ const shared_it_count = 10;
|
||||
var shared_test_data = [1]i32{0} ** 10;
|
||||
var shared_test_index: usize = 0;
|
||||
var shared_count: usize = 0;
|
||||
|
||||
async fn writeRunner(lock: *RwLock) void {
|
||||
fn writeRunner(lock: *RwLock) callconv(.Async) void {
|
||||
suspend; // resumed by onNextTick
|
||||
|
||||
var i: usize = 0;
|
||||
@ -277,8 +275,7 @@ async fn writeRunner(lock: *RwLock) void {
|
||||
shared_test_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
async fn readRunner(lock: *RwLock) void {
|
||||
fn readRunner(lock: *RwLock) callconv(.Async) void {
|
||||
suspend; // resumed by onNextTick
|
||||
std.time.sleep(1);
|
||||
|
||||
|
@ -40,14 +40,14 @@ pub fn RwLocked(comptime T: type) type {
|
||||
self.lock.deinit();
|
||||
}
|
||||
|
||||
pub async fn acquireRead(self: *Self) HeldReadLock {
|
||||
pub fn acquireRead(self: *Self) callconv(.Async) HeldReadLock {
|
||||
return HeldReadLock{
|
||||
.held = self.lock.acquireRead(),
|
||||
.value = &self.locked_data,
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn acquireWrite(self: *Self) HeldWriteLock {
|
||||
pub fn acquireWrite(self: *Self) callconv(.Async) HeldWriteLock {
|
||||
return HeldWriteLock{
|
||||
.held = self.lock.acquireWrite(),
|
||||
.value = &self.locked_data,
|
||||
|
@ -66,7 +66,7 @@ pub const File = struct {
|
||||
lock_nonblocking: bool = false,
|
||||
|
||||
/// Setting this to `.blocking` prevents `O_NONBLOCK` from being passed even
|
||||
/// if `std.io.is_async`. It allows the use of `noasync` when calling functions
|
||||
/// if `std.io.is_async`. It allows the use of `nosuspend` when calling functions
|
||||
/// related to opening the file, reading, writing, and locking.
|
||||
intended_io_mode: io.ModeOverride = io.default_mode,
|
||||
};
|
||||
@ -112,7 +112,7 @@ pub const File = struct {
|
||||
mode: Mode = default_mode,
|
||||
|
||||
/// Setting this to `.blocking` prevents `O_NONBLOCK` from being passed even
|
||||
/// if `std.io.is_async`. It allows the use of `noasync` when calling functions
|
||||
/// if `std.io.is_async`. It allows the use of `nosuspend` when calling functions
|
||||
/// related to opening the file, reading, writing, and locking.
|
||||
intended_io_mode: io.ModeOverride = io.default_mode,
|
||||
};
|
||||
|
@ -113,11 +113,9 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void {
|
||||
hasher.update(mem.asBytes(&key));
|
||||
} else {
|
||||
// Otherwise, hash every element.
|
||||
// TODO remove the copy to an array once field access is done.
|
||||
const array: [info.len]info.child = key;
|
||||
comptime var i = 0;
|
||||
inline while (i < info.len) : (i += 1) {
|
||||
hash(hasher, array[i], strat);
|
||||
hash(hasher, key[i], strat);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -136,7 +136,7 @@ pub const Token = union(enum) {
|
||||
/// they are encountered. No copies or allocations are performed during parsing and the entire
|
||||
/// parsing state requires ~40-50 bytes of stack space.
|
||||
///
|
||||
/// Conforms strictly to RFC8529.
|
||||
/// Conforms strictly to RFC8259.
|
||||
///
|
||||
/// For a non-byte based wrapper, consider using TokenStream instead.
|
||||
pub const StreamingParser = struct {
|
||||
@ -2194,7 +2194,7 @@ test "write json then parse it" {
|
||||
try jw.emitBool(true);
|
||||
|
||||
try jw.objectField("int");
|
||||
try jw.emitNumber(@as(i32, 1234));
|
||||
try jw.emitNumber(1234);
|
||||
|
||||
try jw.objectField("array");
|
||||
try jw.beginArray();
|
||||
@ -2203,7 +2203,7 @@ test "write json then parse it" {
|
||||
try jw.emitNull();
|
||||
|
||||
try jw.arrayElem();
|
||||
try jw.emitNumber(@as(f64, 12.34));
|
||||
try jw.emitNumber(12.34);
|
||||
|
||||
try jw.endArray();
|
||||
|
||||
@ -2336,7 +2336,7 @@ pub const StringifyOptions = struct {
|
||||
/// After a colon, should whitespace be inserted?
|
||||
separator: bool = true,
|
||||
|
||||
fn outputIndent(
|
||||
pub fn outputIndent(
|
||||
whitespace: @This(),
|
||||
out_stream: var,
|
||||
) @TypeOf(out_stream).Error!void {
|
||||
|
@ -168,8 +168,11 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
|
||||
return;
|
||||
}
|
||||
},
|
||||
.Float => if (@floatCast(f64, value) == value) {
|
||||
try self.stream.print("{}", .{value});
|
||||
.ComptimeInt => {
|
||||
return self.emitNumber(@as(std.math.IntFittingRange(value, value), value));
|
||||
},
|
||||
.Float, .ComptimeFloat => if (@floatCast(f64, value) == value) {
|
||||
try self.stream.print("{}", .{@floatCast(f64, value)});
|
||||
self.popState();
|
||||
return;
|
||||
},
|
||||
@ -180,6 +183,7 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
|
||||
}
|
||||
|
||||
pub fn emitString(self: *Self, string: []const u8) !void {
|
||||
assert(self.state[self.state_index] == State.Value);
|
||||
try self.writeEscapedString(string);
|
||||
self.popState();
|
||||
}
|
||||
@ -191,7 +195,9 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
|
||||
|
||||
/// Writes the complete json into the output stream
|
||||
pub fn emitJson(self: *Self, json: std.json.Value) Stream.Error!void {
|
||||
assert(self.state[self.state_index] == State.Value);
|
||||
try self.stringify(json);
|
||||
self.popState();
|
||||
}
|
||||
|
||||
fn indent(self: *Self) !void {
|
||||
@ -233,7 +239,32 @@ test "json write stream" {
|
||||
defer arena_allocator.deinit();
|
||||
|
||||
var w = std.json.writeStream(out, 10);
|
||||
try w.emitJson(try getJson(&arena_allocator.allocator));
|
||||
|
||||
try w.beginObject();
|
||||
|
||||
try w.objectField("object");
|
||||
try w.emitJson(try getJsonObject(&arena_allocator.allocator));
|
||||
|
||||
try w.objectField("string");
|
||||
try w.emitString("This is a string");
|
||||
|
||||
try w.objectField("array");
|
||||
try w.beginArray();
|
||||
try w.arrayElem();
|
||||
try w.emitString("Another string");
|
||||
try w.arrayElem();
|
||||
try w.emitNumber(@as(i32, 1));
|
||||
try w.arrayElem();
|
||||
try w.emitNumber(@as(f32, 3.5));
|
||||
try w.endArray();
|
||||
|
||||
try w.objectField("int");
|
||||
try w.emitNumber(@as(i32, 10));
|
||||
|
||||
try w.objectField("float");
|
||||
try w.emitNumber(@as(f32, 3.5));
|
||||
|
||||
try w.endObject();
|
||||
|
||||
const result = slice_stream.getWritten();
|
||||
const expected =
|
||||
@ -246,38 +277,18 @@ test "json write stream" {
|
||||
\\ "array": [
|
||||
\\ "Another string",
|
||||
\\ 1,
|
||||
\\ 3.14e+00
|
||||
\\ 3.5e+00
|
||||
\\ ],
|
||||
\\ "int": 10,
|
||||
\\ "float": 3.14e+00
|
||||
\\ "float": 3.5e+00
|
||||
\\}
|
||||
;
|
||||
std.testing.expect(std.mem.eql(u8, expected, result));
|
||||
}
|
||||
|
||||
fn getJson(allocator: *std.mem.Allocator) !std.json.Value {
|
||||
var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) };
|
||||
_ = try value.Object.put("string", std.json.Value{ .String = "This is a string" });
|
||||
_ = try value.Object.put("int", std.json.Value{ .Integer = @intCast(i64, 10) });
|
||||
_ = try value.Object.put("float", std.json.Value{ .Float = 3.14 });
|
||||
_ = try value.Object.put("array", try getJsonArray(allocator));
|
||||
_ = try value.Object.put("object", try getJsonObject(allocator));
|
||||
return value;
|
||||
}
|
||||
|
||||
fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value {
|
||||
var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) };
|
||||
_ = try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) });
|
||||
_ = try value.Object.put("two", std.json.Value{ .Float = 2.0 });
|
||||
return value;
|
||||
}
|
||||
|
||||
fn getJsonArray(allocator: *std.mem.Allocator) !std.json.Value {
|
||||
var value = std.json.Value{ .Array = std.json.Array.init(allocator) };
|
||||
var array = &value.Array;
|
||||
_ = try array.append(std.json.Value{ .String = "Another string" });
|
||||
_ = try array.append(std.json.Value{ .Integer = @intCast(i64, 1) });
|
||||
_ = try array.append(std.json.Value{ .Float = 3.14 });
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -124,9 +124,9 @@ pub const Allocator = struct {
|
||||
|
||||
fn AllocWithOptionsPayload(comptime Elem: type, comptime alignment: ?u29, comptime sentinel: ?Elem) type {
|
||||
if (sentinel) |s| {
|
||||
return [:s]align(alignment orelse @alignOf(T)) Elem;
|
||||
return [:s]align(alignment orelse @alignOf(Elem)) Elem;
|
||||
} else {
|
||||
return []align(alignment orelse @alignOf(T)) Elem;
|
||||
return []align(alignment orelse @alignOf(Elem)) Elem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,6 +296,22 @@ pub const Allocator = struct {
|
||||
}
|
||||
};
|
||||
|
||||
var failAllocator = Allocator {
|
||||
.reallocFn = failAllocatorRealloc,
|
||||
.shrinkFn = failAllocatorShrink,
|
||||
};
|
||||
fn failAllocatorRealloc(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
fn failAllocatorShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
|
||||
@panic("failAllocatorShrink should never be called because it cannot allocate");
|
||||
}
|
||||
|
||||
test "mem.Allocator basics" {
|
||||
testing.expectError(error.OutOfMemory, failAllocator.alloc(u8, 1));
|
||||
testing.expectError(error.OutOfMemory, failAllocator.allocSentinel(u8, 1, 0));
|
||||
}
|
||||
|
||||
/// Copy all of source into dest at position 0.
|
||||
/// dest.len must be >= source.len.
|
||||
/// dest.ptr must be <= src.ptr.
|
||||
@ -381,6 +397,9 @@ pub fn zeroes(comptime T: type) T {
|
||||
}
|
||||
},
|
||||
.Array => |info| {
|
||||
if (info.sentinel) |sentinel| {
|
||||
return [_:sentinel]info.child{zeroes(info.child)} ** info.len;
|
||||
}
|
||||
return [_]info.child{zeroes(info.child)} ** info.len;
|
||||
},
|
||||
.Vector,
|
||||
@ -441,6 +460,7 @@ test "mem.zeroes" {
|
||||
array: [2]u32,
|
||||
optional_int: ?u8,
|
||||
empty: void,
|
||||
sentinel: [3:0]u8,
|
||||
};
|
||||
|
||||
const b = zeroes(ZigStruct);
|
||||
@ -465,6 +485,9 @@ test "mem.zeroes" {
|
||||
testing.expectEqual(@as(u32, 0), e);
|
||||
}
|
||||
testing.expectEqual(@as(?u8, null), b.optional_int);
|
||||
for (b.sentinel) |e| {
|
||||
testing.expectEqual(@as(u8, 0), e);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn secureZero(comptime T: type, s: []T) void {
|
||||
|
@ -341,7 +341,7 @@ pub const Address = extern union {
|
||||
return mem.eql(u8, a_bytes, b_bytes);
|
||||
}
|
||||
|
||||
fn getOsSockLen(self: Address) os.socklen_t {
|
||||
pub fn getOsSockLen(self: Address) os.socklen_t {
|
||||
switch (self.any.family) {
|
||||
os.AF_INET => return @sizeOf(os.sockaddr_in),
|
||||
os.AF_INET6 => return @sizeOf(os.sockaddr_in6),
|
||||
@ -377,7 +377,6 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
|
||||
|
||||
return fs.File{
|
||||
.handle = sockfd,
|
||||
.io_mode = std.io.mode,
|
||||
};
|
||||
}
|
||||
|
||||
@ -386,7 +385,7 @@ pub const AddressList = struct {
|
||||
addrs: []Address,
|
||||
canon_name: ?[]u8,
|
||||
|
||||
fn deinit(self: *AddressList) void {
|
||||
pub fn deinit(self: *AddressList) void {
|
||||
// Here we copy the arena allocator into stack memory, because
|
||||
// otherwise it would destroy itself while it was still working.
|
||||
var arena = self.arena;
|
||||
@ -1366,6 +1365,10 @@ pub const StreamServer = struct {
|
||||
|
||||
/// Firewall rules forbid connection.
|
||||
BlockedByFirewall,
|
||||
|
||||
/// Permission to create a socket of the specified type and/or
|
||||
/// protocol is denied.
|
||||
PermissionDenied,
|
||||
} || os.UnexpectedError;
|
||||
|
||||
pub const Connection = struct {
|
||||
|
@ -81,7 +81,7 @@ test "resolve DNS" {
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
if (!std.io.is_async) return error.SkipZigTest;
|
||||
|
||||
if (std.builtin.os.tag != .linux) {
|
||||
if (std.builtin.os.tag != .linux and !std.builtin.os.tag.isDarwin()) {
|
||||
// TODO build abstractions for other operating systems
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
@ -292,6 +292,7 @@ pub const ReadError = error{
|
||||
OperationAborted,
|
||||
BrokenPipe,
|
||||
ConnectionResetByPeer,
|
||||
ConnectionTimedOut,
|
||||
|
||||
/// This error occurs when no global event loop is configured,
|
||||
/// and reading from the file descriptor would block.
|
||||
@ -351,6 +352,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ECONNRESET => return error.ConnectionResetByPeer,
|
||||
ETIMEDOUT => return error.ConnectionTimedOut,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
@ -2156,6 +2158,9 @@ pub const SocketError = error{
|
||||
|
||||
/// The protocol type or the specified protocol is not supported within this domain.
|
||||
ProtocolNotSupported,
|
||||
|
||||
/// The socket type is not supported by the protocol.
|
||||
SocketTypeNotSupported,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t {
|
||||
@ -2164,11 +2169,11 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t {
|
||||
socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC)
|
||||
else
|
||||
socket_type;
|
||||
const rc = system.socket(domain, socket_type, protocol);
|
||||
const rc = system.socket(domain, filtered_sock_type, protocol);
|
||||
switch (errno(rc)) {
|
||||
0 => {
|
||||
const fd = @intCast(fd_t, rc);
|
||||
if (!have_sock_flags and filtered_sock_type != socket_type) {
|
||||
if (!have_sock_flags) {
|
||||
try setSockFlags(fd, socket_type);
|
||||
}
|
||||
return fd;
|
||||
@ -2181,6 +2186,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t {
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
EPROTONOSUPPORT => return error.ProtocolNotSupported,
|
||||
EPROTOTYPE => return error.SocketTypeNotSupported,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
@ -2290,6 +2296,10 @@ pub const AcceptError = error{
|
||||
/// This error occurs when no global event loop is configured,
|
||||
/// and accepting from the socket would block.
|
||||
WouldBlock,
|
||||
|
||||
/// Permission to create a socket of the specified type and/or
|
||||
/// protocol is denied.
|
||||
PermissionDenied,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Accept a connection on a socket.
|
||||
@ -2331,7 +2341,7 @@ pub fn accept(
|
||||
switch (errno(rc)) {
|
||||
0 => {
|
||||
const fd = @intCast(fd_t, rc);
|
||||
if (!have_accept4 and flags != 0) {
|
||||
if (!have_accept4) {
|
||||
try setSockFlags(fd, flags);
|
||||
}
|
||||
return fd;
|
||||
@ -2539,7 +2549,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect
|
||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
EAGAIN, EINPROGRESS => {
|
||||
const loop = std.event.Loop.instance orelse return error.WouldBlock;
|
||||
loop.waitUntilFdWritableOrReadable(sockfd);
|
||||
loop.waitUntilFdWritable(sockfd);
|
||||
return getsockoptError(sockfd);
|
||||
},
|
||||
EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
|
||||
@ -3267,26 +3277,26 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
|
||||
}
|
||||
|
||||
fn setSockFlags(fd: fd_t, flags: u32) !void {
|
||||
{
|
||||
if ((flags & SOCK_CLOEXEC) != 0) {
|
||||
var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
if ((flags & SOCK_NONBLOCK) != 0) fd_flags |= FD_CLOEXEC;
|
||||
fd_flags |= FD_CLOEXEC;
|
||||
_ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
{
|
||||
if ((flags & SOCK_NONBLOCK) != 0) {
|
||||
var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
if ((flags & SOCK_CLOEXEC) != 0) fl_flags |= O_NONBLOCK;
|
||||
fl_flags |= O_NONBLOCK;
|
||||
_ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
|
@ -125,7 +125,7 @@ pub const empty_sigset = sigset_t(0);
|
||||
|
||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
|
||||
pub const Sigaction = extern struct {
|
||||
handler: extern fn (c_int) void,
|
||||
handler: fn (c_int) callconv(.C) void,
|
||||
sa_mask: sigset_t,
|
||||
sa_flags: c_int,
|
||||
};
|
||||
@ -1263,10 +1263,10 @@ pub const RTLD_NOLOAD = 0x10;
|
||||
pub const RTLD_NODELETE = 0x80;
|
||||
pub const RTLD_FIRST = 0x100;
|
||||
|
||||
pub const RTLD_NEXT = @intToPtr(*c_void, ~maxInt(usize));
|
||||
pub const RTLD_DEFAULT = @intToPtr(*c_void, ~maxInt(usize) - 1);
|
||||
pub const RTLD_SELF = @intToPtr(*c_void, ~maxInt(usize) - 2);
|
||||
pub const RTLD_MAIN_ONLY = @intToPtr(*c_void, ~maxInt(usize) - 4);
|
||||
pub const RTLD_NEXT = @intToPtr(*c_void, @bitCast(usize, @as(isize, -1)));
|
||||
pub const RTLD_DEFAULT = @intToPtr(*c_void, @bitCast(usize, @as(isize, -2)));
|
||||
pub const RTLD_SELF = @intToPtr(*c_void, @bitCast(usize, @as(isize, -3)));
|
||||
pub const RTLD_MAIN_ONLY = @intToPtr(*c_void, @bitCast(usize, @as(isize, -5)));
|
||||
|
||||
/// duplicate file descriptor
|
||||
pub const F_DUPFD = 0;
|
||||
|
@ -458,9 +458,9 @@ pub const S_IFSOCK = 49152;
|
||||
pub const S_IFWHT = 57344;
|
||||
pub const S_IFMT = 61440;
|
||||
|
||||
pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
|
||||
pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
|
||||
pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
|
||||
pub const SIG_ERR = @intToPtr(fn (i32) callconv(.C) void, maxInt(usize));
|
||||
pub const SIG_DFL = @intToPtr(fn (i32) callconv(.C) void, 0);
|
||||
pub const SIG_IGN = @intToPtr(fn (i32) callconv(.C) void, 1);
|
||||
pub const BADSIG = SIG_ERR;
|
||||
pub const SIG_BLOCK = 1;
|
||||
pub const SIG_UNBLOCK = 2;
|
||||
@ -519,13 +519,13 @@ pub const sigset_t = extern struct {
|
||||
pub const sig_atomic_t = c_int;
|
||||
pub const Sigaction = extern struct {
|
||||
__sigaction_u: extern union {
|
||||
__sa_handler: ?extern fn (c_int) void,
|
||||
__sa_sigaction: ?extern fn (c_int, [*c]siginfo_t, ?*c_void) void,
|
||||
__sa_handler: ?fn (c_int) callconv(.C) void,
|
||||
__sa_sigaction: ?fn (c_int, [*c]siginfo_t, ?*c_void) callconv(.C) void,
|
||||
},
|
||||
sa_flags: c_int,
|
||||
sa_mask: sigset_t,
|
||||
};
|
||||
pub const sig_t = [*c]extern fn (c_int) void;
|
||||
pub const sig_t = [*c]fn (c_int) callconv(.C) void;
|
||||
|
||||
pub const sigvec = extern struct {
|
||||
sv_handler: [*c]__sighandler_t,
|
||||
|
@ -725,16 +725,16 @@ pub const winsize = extern struct {
|
||||
|
||||
const NSIG = 32;
|
||||
|
||||
pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
|
||||
pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
|
||||
pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
|
||||
pub const SIG_ERR = @intToPtr(fn (i32) callconv(.C) void, maxInt(usize));
|
||||
pub const SIG_DFL = @intToPtr(fn (i32) callconv(.C) void, 0);
|
||||
pub const SIG_IGN = @intToPtr(fn (i32) callconv(.C) void, 1);
|
||||
|
||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
|
||||
pub const Sigaction = extern struct {
|
||||
/// signal handler
|
||||
__sigaction_u: extern union {
|
||||
__sa_handler: extern fn (i32) void,
|
||||
__sa_sigaction: extern fn (i32, *__siginfo, usize) void,
|
||||
__sa_handler: fn (i32) callconv(.C) void,
|
||||
__sa_sigaction: fn (i32, *__siginfo, usize) callconv(.C) void,
|
||||
},
|
||||
|
||||
/// see signal options
|
||||
|
@ -813,15 +813,15 @@ pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffff
|
||||
pub const k_sigaction = if (is_mips)
|
||||
extern struct {
|
||||
flags: usize,
|
||||
sigaction: ?extern fn (i32, *siginfo_t, ?*c_void) void,
|
||||
sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void,
|
||||
mask: [4]u32,
|
||||
restorer: extern fn () void,
|
||||
restorer: fn () callconv(.C) void,
|
||||
}
|
||||
else
|
||||
extern struct {
|
||||
sigaction: ?extern fn (i32, *siginfo_t, ?*c_void) void,
|
||||
sigaction: ?fn (i32, *siginfo_t, ?*c_void) callconv(.C) void,
|
||||
flags: usize,
|
||||
restorer: extern fn () void,
|
||||
restorer: fn () callconv(.C) void,
|
||||
mask: [2]u32,
|
||||
};
|
||||
|
||||
@ -831,7 +831,7 @@ pub const Sigaction = extern struct {
|
||||
sigaction: ?sigaction_fn,
|
||||
mask: sigset_t,
|
||||
flags: u32,
|
||||
restorer: ?extern fn () void = null,
|
||||
restorer: ?fn () callconv(.C) void = null,
|
||||
};
|
||||
|
||||
pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
|
||||
|
@ -599,7 +599,7 @@ pub fn flock(fd: fd_t, operation: i32) usize {
|
||||
var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);
|
||||
|
||||
// We must follow the C calling convention when we call into the VDSO
|
||||
const vdso_clock_gettime_ty = extern fn (i32, *timespec) usize;
|
||||
const vdso_clock_gettime_ty = fn (i32, *timespec) callconv(.C) usize;
|
||||
|
||||
pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
|
||||
if (@hasDecl(@This(), "VDSO_CGT_SYM")) {
|
||||
@ -791,7 +791,7 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
|
||||
.sigaction = act.sigaction,
|
||||
.flags = act.flags | SA_RESTORER,
|
||||
.mask = undefined,
|
||||
.restorer = @ptrCast(extern fn () void, restorer_fn),
|
||||
.restorer = @ptrCast(fn () callconv(.C) void, restorer_fn),
|
||||
};
|
||||
var ksa_old: k_sigaction = undefined;
|
||||
const ksa_mask_size = @sizeOf(@TypeOf(ksa_old.mask));
|
||||
|
@ -86,7 +86,7 @@ pub fn syscall6(
|
||||
}
|
||||
|
||||
/// This matches the libc clone function.
|
||||
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
|
||||
pub fn restore() callconv(.Naked) void {
|
||||
return asm volatile ("svc #0"
|
||||
|
@ -86,7 +86,7 @@ pub fn syscall6(
|
||||
}
|
||||
|
||||
/// This matches the libc clone function.
|
||||
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
|
||||
pub const restore = restore_rt;
|
||||
|
||||
|
@ -106,7 +106,7 @@ pub fn socketcall(call: usize, args: [*]usize) usize {
|
||||
}
|
||||
|
||||
/// This matches the libc clone function.
|
||||
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
|
||||
pub fn restore() callconv(.Naked) void {
|
||||
return asm volatile ("int $0x80"
|
||||
|
@ -142,7 +142,7 @@ pub fn syscall6(
|
||||
}
|
||||
|
||||
/// This matches the libc clone function.
|
||||
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
|
||||
pub fn restore() callconv(.Naked) void {
|
||||
return asm volatile ("syscall"
|
||||
|
@ -85,7 +85,7 @@ pub fn syscall6(
|
||||
);
|
||||
}
|
||||
|
||||
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
|
||||
pub const restore = restore_rt;
|
||||
|
||||
|
@ -86,7 +86,7 @@ pub fn syscall6(
|
||||
}
|
||||
|
||||
/// This matches the libc clone function.
|
||||
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
|
||||
|
||||
pub const restore = restore_rt;
|
||||
|
||||
|
@ -5,8 +5,8 @@ const Status = uefi.Status;
|
||||
|
||||
/// Protocol for touchscreens
|
||||
pub const AbsolutePointerProtocol = extern struct {
|
||||
_reset: extern fn (*const AbsolutePointerProtocol, bool) Status,
|
||||
_get_state: extern fn (*const AbsolutePointerProtocol, *AbsolutePointerState) Status,
|
||||
_reset: fn (*const AbsolutePointerProtocol, bool) callconv(.C) Status,
|
||||
_get_state: fn (*const AbsolutePointerProtocol, *AbsolutePointerState) callconv(.C) Status,
|
||||
wait_for_input: Event,
|
||||
mode: *AbsolutePointerMode,
|
||||
|
||||
|
@ -5,7 +5,7 @@ const Status = uefi.Status;
|
||||
|
||||
/// Override EDID information
|
||||
pub const EdidOverrideProtocol = extern struct {
|
||||
_get_edid: extern fn (*const EdidOverrideProtocol, Handle, *u32, *usize, *?[*]u8) Status,
|
||||
_get_edid: fn (*const EdidOverrideProtocol, Handle, *u32, *usize, *?[*]u8) callconv(.C) Status,
|
||||
|
||||
/// Returns policy information and potentially a replacement EDID for the specified video output device.
|
||||
/// attributes must be align(4)
|
||||
|
@ -5,16 +5,16 @@ const Status = uefi.Status;
|
||||
|
||||
pub const FileProtocol = extern struct {
|
||||
revision: u64,
|
||||
_open: extern fn (*const FileProtocol, **const FileProtocol, [*:0]const u16, u64, u64) Status,
|
||||
_close: extern fn (*const FileProtocol) Status,
|
||||
_delete: extern fn (*const FileProtocol) Status,
|
||||
_read: extern fn (*const FileProtocol, *usize, [*]u8) Status,
|
||||
_write: extern fn (*const FileProtocol, *usize, [*]const u8) Status,
|
||||
_get_position: extern fn (*const FileProtocol, *u64) Status,
|
||||
_set_position: extern fn (*const FileProtocol, *const u64) Status,
|
||||
_get_info: extern fn (*const FileProtocol, *align(8) const Guid, *const usize, [*]u8) Status,
|
||||
_set_info: extern fn (*const FileProtocol, *align(8) const Guid, usize, [*]const u8) Status,
|
||||
_flush: extern fn (*const FileProtocol) Status,
|
||||
_open: fn (*const FileProtocol, **const FileProtocol, [*:0]const u16, u64, u64) callconv(.C) Status,
|
||||
_close: fn (*const FileProtocol) callconv(.C) Status,
|
||||
_delete: fn (*const FileProtocol) callconv(.C) Status,
|
||||
_read: fn (*const FileProtocol, *usize, [*]u8) callconv(.C) Status,
|
||||
_write: fn (*const FileProtocol, *usize, [*]const u8) callconv(.C) Status,
|
||||
_get_position: fn (*const FileProtocol, *u64) callconv(.C) Status,
|
||||
_set_position: fn (*const FileProtocol, *const u64) callconv(.C) Status,
|
||||
_get_info: fn (*const FileProtocol, *align(8) const Guid, *const usize, [*]u8) callconv(.C) Status,
|
||||
_set_info: fn (*const FileProtocol, *align(8) const Guid, usize, [*]const u8) callconv(.C) Status,
|
||||
_flush: fn (*const FileProtocol) callconv(.C) Status,
|
||||
|
||||
pub fn open(self: *const FileProtocol, new_handle: **const FileProtocol, file_name: [*:0]const u16, open_mode: u64, attributes: u64) Status {
|
||||
return self._open(self, new_handle, file_name, open_mode, attributes);
|
||||
|
@ -4,9 +4,9 @@ const Status = uefi.Status;
|
||||
|
||||
/// Graphics output
|
||||
pub const GraphicsOutputProtocol = extern struct {
|
||||
_query_mode: extern fn (*const GraphicsOutputProtocol, u32, *usize, **GraphicsOutputModeInformation) Status,
|
||||
_set_mode: extern fn (*const GraphicsOutputProtocol, u32) Status,
|
||||
_blt: extern fn (*const GraphicsOutputProtocol, ?[*]GraphicsOutputBltPixel, GraphicsOutputBltOperation, usize, usize, usize, usize, usize, usize, usize) Status,
|
||||
_query_mode: fn (*const GraphicsOutputProtocol, u32, *usize, **GraphicsOutputModeInformation) callconv(.C) Status,
|
||||
_set_mode: fn (*const GraphicsOutputProtocol, u32) callconv(.C) Status,
|
||||
_blt: fn (*const GraphicsOutputProtocol, ?[*]GraphicsOutputBltPixel, GraphicsOutputBltOperation, usize, usize, usize, usize, usize, usize, usize) callconv(.C) Status,
|
||||
mode: *GraphicsOutputProtocolMode,
|
||||
|
||||
/// Returns information for an available graphics mode that the graphics device and the set of active video output devices supports.
|
||||
|
@ -6,10 +6,10 @@ const hii = uefi.protocols.hii;
|
||||
/// Database manager for HII-related data structures.
|
||||
pub const HIIDatabaseProtocol = extern struct {
|
||||
_new_package_list: Status, // TODO
|
||||
_remove_package_list: extern fn (*const HIIDatabaseProtocol, hii.HIIHandle) Status,
|
||||
_update_package_list: extern fn (*const HIIDatabaseProtocol, hii.HIIHandle, *const hii.HIIPackageList) Status,
|
||||
_list_package_lists: extern fn (*const HIIDatabaseProtocol, u8, ?*const Guid, *usize, [*]hii.HIIHandle) Status,
|
||||
_export_package_lists: extern fn (*const HIIDatabaseProtocol, ?hii.HIIHandle, *usize, *hii.HIIPackageList) Status,
|
||||
_remove_package_list: fn (*const HIIDatabaseProtocol, hii.HIIHandle) callconv(.C) Status,
|
||||
_update_package_list: fn (*const HIIDatabaseProtocol, hii.HIIHandle, *const hii.HIIPackageList) callconv(.C) Status,
|
||||
_list_package_lists: fn (*const HIIDatabaseProtocol, u8, ?*const Guid, *usize, [*]hii.HIIHandle) callconv(.C) Status,
|
||||
_export_package_lists: fn (*const HIIDatabaseProtocol, ?hii.HIIHandle, *usize, *hii.HIIPackageList) callconv(.C) Status,
|
||||
_register_package_notify: Status, // TODO
|
||||
_unregister_package_notify: Status, // TODO
|
||||
_find_keyboard_layouts: Status, // TODO
|
||||
|
@ -6,7 +6,7 @@ const hii = uefi.protocols.hii;
|
||||
/// Display a popup window
|
||||
pub const HIIPopupProtocol = extern struct {
|
||||
revision: u64,
|
||||
_create_popup: extern fn (*const HIIPopupProtocol, HIIPopupStyle, HIIPopupType, hii.HIIHandle, u16, ?*HIIPopupSelection) Status,
|
||||
_create_popup: fn (*const HIIPopupProtocol, HIIPopupStyle, HIIPopupType, hii.HIIHandle, u16, ?*HIIPopupSelection) callconv(.C) Status,
|
||||
|
||||
/// Displays a popup window.
|
||||
pub fn createPopup(self: *const HIIPopupProtocol, style: HIIPopupStyle, popup_type: HIIPopupType, handle: hii.HIIHandle, msg: u16, user_selection: ?*HIIPopupSelection) Status {
|
||||
|
@ -4,10 +4,10 @@ const Event = uefi.Event;
|
||||
const Status = uefi.Status;
|
||||
|
||||
pub const Ip6ConfigProtocol = extern struct {
|
||||
_set_data: extern fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, usize, *const c_void) Status,
|
||||
_get_data: extern fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, *usize, ?*const c_void) Status,
|
||||
_register_data_notify: extern fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, Event) Status,
|
||||
_unregister_data_notify: extern fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, Event) Status,
|
||||
_set_data: fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, usize, *const c_void) callconv(.C) Status,
|
||||
_get_data: fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, *usize, ?*const c_void) callconv(.C) Status,
|
||||
_register_data_notify: fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, Event) callconv(.C) Status,
|
||||
_unregister_data_notify: fn (*const Ip6ConfigProtocol, Ip6ConfigDataType, Event) callconv(.C) Status,
|
||||
|
||||
pub fn setData(self: *const Ip6ConfigProtocol, data_type: Ip6ConfigDataType, data_size: usize, data: *const c_void) Status {
|
||||
return self._set_data(self, data_type, data_size, data);
|
||||
|
@ -7,15 +7,15 @@ const ManagedNetworkConfigData = uefi.protocols.ManagedNetworkConfigData;
|
||||
const SimpleNetworkMode = uefi.protocols.SimpleNetworkMode;
|
||||
|
||||
pub const Ip6Protocol = extern struct {
|
||||
_get_mode_data: extern fn (*const Ip6Protocol, ?*Ip6ModeData, ?*ManagedNetworkConfigData, ?*SimpleNetworkMode) Status,
|
||||
_configure: extern fn (*const Ip6Protocol, ?*const Ip6ConfigData) Status,
|
||||
_groups: extern fn (*const Ip6Protocol, bool, ?*const Ip6Address) Status,
|
||||
_routes: extern fn (*const Ip6Protocol, bool, ?*const Ip6Address, u8, ?*const Ip6Address) Status,
|
||||
_neighbors: extern fn (*const Ip6Protocol, bool, *const Ip6Address, ?*const MacAddress, u32, bool) Status,
|
||||
_transmit: extern fn (*const Ip6Protocol, *Ip6CompletionToken) Status,
|
||||
_receive: extern fn (*const Ip6Protocol, *Ip6CompletionToken) Status,
|
||||
_cancel: extern fn (*const Ip6Protocol, ?*Ip6CompletionToken) Status,
|
||||
_poll: extern fn (*const Ip6Protocol) Status,
|
||||
_get_mode_data: fn (*const Ip6Protocol, ?*Ip6ModeData, ?*ManagedNetworkConfigData, ?*SimpleNetworkMode) callconv(.C) Status,
|
||||
_configure: fn (*const Ip6Protocol, ?*const Ip6ConfigData) callconv(.C) Status,
|
||||
_groups: fn (*const Ip6Protocol, bool, ?*const Ip6Address) callconv(.C) Status,
|
||||
_routes: fn (*const Ip6Protocol, bool, ?*const Ip6Address, u8, ?*const Ip6Address) callconv(.C) Status,
|
||||
_neighbors: fn (*const Ip6Protocol, bool, *const Ip6Address, ?*const MacAddress, u32, bool) callconv(.C) Status,
|
||||
_transmit: fn (*const Ip6Protocol, *Ip6CompletionToken) callconv(.C) Status,
|
||||
_receive: fn (*const Ip6Protocol, *Ip6CompletionToken) callconv(.C) Status,
|
||||
_cancel: fn (*const Ip6Protocol, ?*Ip6CompletionToken) callconv(.C) Status,
|
||||
_poll: fn (*const Ip6Protocol) callconv(.C) Status,
|
||||
|
||||
/// Gets the current operational settings for this instance of the EFI IPv6 Protocol driver.
|
||||
pub fn getModeData(self: *const Ip6Protocol, ip6_mode_data: ?*Ip6ModeData, mnp_config_data: ?*ManagedNetworkConfigData, snp_mode_data: ?*SimpleNetworkMode) Status {
|
||||
|
@ -4,8 +4,8 @@ const Guid = uefi.Guid;
|
||||
const Status = uefi.Status;
|
||||
|
||||
pub const Ip6ServiceBindingProtocol = extern struct {
|
||||
_create_child: extern fn (*const Ip6ServiceBindingProtocol, *?Handle) Status,
|
||||
_destroy_child: extern fn (*const Ip6ServiceBindingProtocol, Handle) Status,
|
||||
_create_child: fn (*const Ip6ServiceBindingProtocol, *?Handle) callconv(.C) Status,
|
||||
_destroy_child: fn (*const Ip6ServiceBindingProtocol, Handle) callconv(.C) Status,
|
||||
|
||||
pub fn createChild(self: *const Ip6ServiceBindingProtocol, handle: *?Handle) Status {
|
||||
return self._create_child(self, handle);
|
||||
|
@ -19,7 +19,7 @@ pub const LoadedImageProtocol = extern struct {
|
||||
image_size: u64,
|
||||
image_code_type: MemoryType,
|
||||
image_data_type: MemoryType,
|
||||
_unload: extern fn (*const LoadedImageProtocol, Handle) Status,
|
||||
_unload: fn (*const LoadedImageProtocol, Handle) callconv(.C) Status,
|
||||
|
||||
/// Unloads an image from memory.
|
||||
pub fn unload(self: *const LoadedImageProtocol, handle: Handle) Status {
|
||||
|
@ -7,14 +7,14 @@ const SimpleNetworkMode = uefi.protocols.SimpleNetworkMode;
|
||||
const MacAddress = uefi.protocols.MacAddress;
|
||||
|
||||
pub const ManagedNetworkProtocol = extern struct {
|
||||
_get_mode_data: extern fn (*const ManagedNetworkProtocol, ?*ManagedNetworkConfigData, ?*SimpleNetworkMode) Status,
|
||||
_configure: extern fn (*const ManagedNetworkProtocol, ?*const ManagedNetworkConfigData) Status,
|
||||
_mcast_ip_to_mac: extern fn (*const ManagedNetworkProtocol, bool, *const c_void, *MacAddress) Status,
|
||||
_groups: extern fn (*const ManagedNetworkProtocol, bool, ?*const MacAddress) Status,
|
||||
_transmit: extern fn (*const ManagedNetworkProtocol, *const ManagedNetworkCompletionToken) Status,
|
||||
_receive: extern fn (*const ManagedNetworkProtocol, *const ManagedNetworkCompletionToken) Status,
|
||||
_cancel: extern fn (*const ManagedNetworkProtocol, ?*const ManagedNetworkCompletionToken) Status,
|
||||
_poll: extern fn (*const ManagedNetworkProtocol) usize,
|
||||
_get_mode_data: fn (*const ManagedNetworkProtocol, ?*ManagedNetworkConfigData, ?*SimpleNetworkMode) callconv(.C) Status,
|
||||
_configure: fn (*const ManagedNetworkProtocol, ?*const ManagedNetworkConfigData) callconv(.C) Status,
|
||||
_mcast_ip_to_mac: fn (*const ManagedNetworkProtocol, bool, *const c_void, *MacAddress) callconv(.C) Status,
|
||||
_groups: fn (*const ManagedNetworkProtocol, bool, ?*const MacAddress) callconv(.C) Status,
|
||||
_transmit: fn (*const ManagedNetworkProtocol, *const ManagedNetworkCompletionToken) callconv(.C) Status,
|
||||
_receive: fn (*const ManagedNetworkProtocol, *const ManagedNetworkCompletionToken) callconv(.C) Status,
|
||||
_cancel: fn (*const ManagedNetworkProtocol, ?*const ManagedNetworkCompletionToken) callconv(.C) Status,
|
||||
_poll: fn (*const ManagedNetworkProtocol) callconv(.C) usize,
|
||||
|
||||
/// Returns the operational parameters for the current MNP child driver.
|
||||
/// May also support returning the underlying SNP driver mode data.
|
||||
|
@ -4,8 +4,8 @@ const Guid = uefi.Guid;
|
||||
const Status = uefi.Status;
|
||||
|
||||
pub const ManagedNetworkServiceBindingProtocol = extern struct {
|
||||
_create_child: extern fn (*const ManagedNetworkServiceBindingProtocol, *?Handle) Status,
|
||||
_destroy_child: extern fn (*const ManagedNetworkServiceBindingProtocol, Handle) Status,
|
||||
_create_child: fn (*const ManagedNetworkServiceBindingProtocol, *?Handle) callconv(.C) Status,
|
||||
_destroy_child: fn (*const ManagedNetworkServiceBindingProtocol, Handle) callconv(.C) Status,
|
||||
|
||||
pub fn createChild(self: *const ManagedNetworkServiceBindingProtocol, handle: *?Handle) Status {
|
||||
return self._create_child(self, handle);
|
||||
|
@ -4,8 +4,8 @@ const Status = uefi.Status;
|
||||
|
||||
/// Random Number Generator protocol
|
||||
pub const RNGProtocol = extern struct {
|
||||
_get_info: extern fn (*const RNGProtocol, *usize, [*]align(8) Guid) Status,
|
||||
_get_rng: extern fn (*const RNGProtocol, ?*align(8) const Guid, usize, [*]u8) Status,
|
||||
_get_info: fn (*const RNGProtocol, *usize, [*]align(8) Guid) callconv(.C) Status,
|
||||
_get_rng: fn (*const RNGProtocol, ?*align(8) const Guid, usize, [*]u8) callconv(.C) Status,
|
||||
|
||||
/// Returns information about the random number generation implementation.
|
||||
pub fn getInfo(self: *const RNGProtocol, list_size: *usize, list: [*]align(8) Guid) Status {
|
||||
|
@ -5,7 +5,7 @@ const Status = uefi.Status;
|
||||
|
||||
pub const SimpleFileSystemProtocol = extern struct {
|
||||
revision: u64,
|
||||
_open_volume: extern fn (*const SimpleFileSystemProtocol, **const FileProtocol) Status,
|
||||
_open_volume: fn (*const SimpleFileSystemProtocol, **const FileProtocol) callconv(.C) Status,
|
||||
|
||||
pub fn openVolume(self: *const SimpleFileSystemProtocol, root: **const FileProtocol) Status {
|
||||
return self._open_volume(self, root);
|
||||
|
@ -5,19 +5,19 @@ const Status = uefi.Status;
|
||||
|
||||
pub const SimpleNetworkProtocol = extern struct {
|
||||
revision: u64,
|
||||
_start: extern fn (*const SimpleNetworkProtocol) Status,
|
||||
_stop: extern fn (*const SimpleNetworkProtocol) Status,
|
||||
_initialize: extern fn (*const SimpleNetworkProtocol, usize, usize) Status,
|
||||
_reset: extern fn (*const SimpleNetworkProtocol, bool) Status,
|
||||
_shutdown: extern fn (*const SimpleNetworkProtocol) Status,
|
||||
_receive_filters: extern fn (*const SimpleNetworkProtocol, SimpleNetworkReceiveFilter, SimpleNetworkReceiveFilter, bool, usize, ?[*]const MacAddress) Status,
|
||||
_station_address: extern fn (*const SimpleNetworkProtocol, bool, ?*const MacAddress) Status,
|
||||
_statistics: extern fn (*const SimpleNetworkProtocol, bool, ?*usize, ?*NetworkStatistics) Status,
|
||||
_mcast_ip_to_mac: extern fn (*const SimpleNetworkProtocol, bool, *const c_void, *MacAddress) Status,
|
||||
_nvdata: extern fn (*const SimpleNetworkProtocol, bool, usize, usize, [*]u8) Status,
|
||||
_get_status: extern fn (*const SimpleNetworkProtocol, *SimpleNetworkInterruptStatus, ?*?[*]u8) Status,
|
||||
_transmit: extern fn (*const SimpleNetworkProtocol, usize, usize, [*]const u8, ?*const MacAddress, ?*const MacAddress, ?*const u16) Status,
|
||||
_receive: extern fn (*const SimpleNetworkProtocol, ?*usize, *usize, [*]u8, ?*MacAddress, ?*MacAddress, ?*u16) Status,
|
||||
_start: fn (*const SimpleNetworkProtocol) callconv(.C) Status,
|
||||
_stop: fn (*const SimpleNetworkProtocol) callconv(.C) Status,
|
||||
_initialize: fn (*const SimpleNetworkProtocol, usize, usize) callconv(.C) Status,
|
||||
_reset: fn (*const SimpleNetworkProtocol, bool) callconv(.C) Status,
|
||||
_shutdown: fn (*const SimpleNetworkProtocol) callconv(.C) Status,
|
||||
_receive_filters: fn (*const SimpleNetworkProtocol, SimpleNetworkReceiveFilter, SimpleNetworkReceiveFilter, bool, usize, ?[*]const MacAddress) callconv(.C) Status,
|
||||
_station_address: fn (*const SimpleNetworkProtocol, bool, ?*const MacAddress) callconv(.C) Status,
|
||||
_statistics: fn (*const SimpleNetworkProtocol, bool, ?*usize, ?*NetworkStatistics) callconv(.C) Status,
|
||||
_mcast_ip_to_mac: fn (*const SimpleNetworkProtocol, bool, *const c_void, *MacAddress) callconv(.C) Status,
|
||||
_nvdata: fn (*const SimpleNetworkProtocol, bool, usize, usize, [*]u8) callconv(.C) Status,
|
||||
_get_status: fn (*const SimpleNetworkProtocol, *SimpleNetworkInterruptStatus, ?*?[*]u8) callconv(.C) Status,
|
||||
_transmit: fn (*const SimpleNetworkProtocol, usize, usize, [*]const u8, ?*const MacAddress, ?*const MacAddress, ?*const u16) callconv(.C) Status,
|
||||
_receive: fn (*const SimpleNetworkProtocol, ?*usize, *usize, [*]u8, ?*MacAddress, ?*MacAddress, ?*u16) callconv(.C) Status,
|
||||
wait_for_packet: Event,
|
||||
mode: *SimpleNetworkMode,
|
||||
|
||||
|
@ -5,8 +5,8 @@ const Status = uefi.Status;
|
||||
|
||||
/// Protocol for mice
|
||||
pub const SimplePointerProtocol = struct {
|
||||
_reset: extern fn (*const SimplePointerProtocol, bool) Status,
|
||||
_get_state: extern fn (*const SimplePointerProtocol, *SimplePointerState) Status,
|
||||
_reset: fn (*const SimplePointerProtocol, bool) callconv(.C) Status,
|
||||
_get_state: fn (*const SimplePointerProtocol, *SimplePointerState) callconv(.C) Status,
|
||||
wait_for_input: Event,
|
||||
mode: *SimplePointerMode,
|
||||
|
||||
|
@ -5,12 +5,12 @@ const Status = uefi.Status;
|
||||
|
||||
/// Character input devices, e.g. Keyboard
|
||||
pub const SimpleTextInputExProtocol = extern struct {
|
||||
_reset: extern fn (*const SimpleTextInputExProtocol, bool) Status,
|
||||
_read_key_stroke_ex: extern fn (*const SimpleTextInputExProtocol, *KeyData) Status,
|
||||
_reset: fn (*const SimpleTextInputExProtocol, bool) callconv(.C) Status,
|
||||
_read_key_stroke_ex: fn (*const SimpleTextInputExProtocol, *KeyData) callconv(.C) Status,
|
||||
wait_for_key_ex: Event,
|
||||
_set_state: extern fn (*const SimpleTextInputExProtocol, *const u8) Status,
|
||||
_register_key_notify: extern fn (*const SimpleTextInputExProtocol, *const KeyData, extern fn (*const KeyData) usize, **c_void) Status,
|
||||
_unregister_key_notify: extern fn (*const SimpleTextInputExProtocol, *const c_void) Status,
|
||||
_set_state: fn (*const SimpleTextInputExProtocol, *const u8) callconv(.C) Status,
|
||||
_register_key_notify: fn (*const SimpleTextInputExProtocol, *const KeyData, fn (*const KeyData) callconv(.C) usize, **c_void) callconv(.C) Status,
|
||||
_unregister_key_notify: fn (*const SimpleTextInputExProtocol, *const c_void) callconv(.C) Status,
|
||||
|
||||
/// Resets the input device hardware.
|
||||
pub fn reset(self: *const SimpleTextInputExProtocol, verify: bool) Status {
|
||||
@ -28,7 +28,7 @@ pub const SimpleTextInputExProtocol = extern struct {
|
||||
}
|
||||
|
||||
/// Register a notification function for a particular keystroke for the input device.
|
||||
pub fn registerKeyNotify(self: *const SimpleTextInputExProtocol, key_data: *const KeyData, notify: extern fn (*const KeyData) usize, handle: **c_void) Status {
|
||||
pub fn registerKeyNotify(self: *const SimpleTextInputExProtocol, key_data: *const KeyData, notify: fn (*const KeyData) callconv(.C) usize, handle: **c_void) Status {
|
||||
return self._register_key_notify(self, key_data, notify, handle);
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@ const Status = uefi.Status;
|
||||
|
||||
/// Character input devices, e.g. Keyboard
|
||||
pub const SimpleTextInputProtocol = extern struct {
|
||||
_reset: extern fn (*const SimpleTextInputProtocol, bool) usize,
|
||||
_read_key_stroke: extern fn (*const SimpleTextInputProtocol, *InputKey) Status,
|
||||
_reset: fn (*const SimpleTextInputProtocol, bool) callconv(.C) usize,
|
||||
_read_key_stroke: fn (*const SimpleTextInputProtocol, *InputKey) callconv(.C) Status,
|
||||
wait_for_key: Event,
|
||||
|
||||
/// Resets the input device hardware.
|
||||
|
@ -4,15 +4,15 @@ const Status = uefi.Status;
|
||||
|
||||
/// Character output devices
|
||||
pub const SimpleTextOutputProtocol = extern struct {
|
||||
_reset: extern fn (*const SimpleTextOutputProtocol, bool) Status,
|
||||
_output_string: extern fn (*const SimpleTextOutputProtocol, [*:0]const u16) Status,
|
||||
_test_string: extern fn (*const SimpleTextOutputProtocol, [*:0]const u16) Status,
|
||||
_query_mode: extern fn (*const SimpleTextOutputProtocol, usize, *usize, *usize) Status,
|
||||
_set_mode: extern fn (*const SimpleTextOutputProtocol, usize) Status,
|
||||
_set_attribute: extern fn (*const SimpleTextOutputProtocol, usize) Status,
|
||||
_clear_screen: extern fn (*const SimpleTextOutputProtocol) Status,
|
||||
_set_cursor_position: extern fn (*const SimpleTextOutputProtocol, usize, usize) Status,
|
||||
_enable_cursor: extern fn (*const SimpleTextOutputProtocol, bool) Status,
|
||||
_reset: fn (*const SimpleTextOutputProtocol, bool) callconv(.C) Status,
|
||||
_output_string: fn (*const SimpleTextOutputProtocol, [*:0]const u16) callconv(.C) Status,
|
||||
_test_string: fn (*const SimpleTextOutputProtocol, [*:0]const u16) callconv(.C) Status,
|
||||
_query_mode: fn (*const SimpleTextOutputProtocol, usize, *usize, *usize) callconv(.C) Status,
|
||||
_set_mode: fn (*const SimpleTextOutputProtocol, usize) callconv(.C) Status,
|
||||
_set_attribute: fn (*const SimpleTextOutputProtocol, usize) callconv(.C) Status,
|
||||
_clear_screen: fn (*const SimpleTextOutputProtocol) callconv(.C) Status,
|
||||
_set_cursor_position: fn (*const SimpleTextOutputProtocol, usize, usize) callconv(.C) Status,
|
||||
_enable_cursor: fn (*const SimpleTextOutputProtocol, bool) callconv(.C) Status,
|
||||
mode: *SimpleTextOutputMode,
|
||||
|
||||
/// Resets the text output device hardware.
|
||||
|
@ -9,13 +9,13 @@ const ManagedNetworkConfigData = uefi.protocols.ManagedNetworkConfigData;
|
||||
const SimpleNetworkMode = uefi.protocols.SimpleNetworkMode;
|
||||
|
||||
pub const Udp6Protocol = extern struct {
|
||||
_get_mode_data: extern fn (*const Udp6Protocol, ?*Udp6ConfigData, ?*Ip6ModeData, ?*ManagedNetworkConfigData, ?*SimpleNetworkMode) Status,
|
||||
_configure: extern fn (*const Udp6Protocol, ?*const Udp6ConfigData) Status,
|
||||
_groups: extern fn (*const Udp6Protocol, bool, ?*const Ip6Address) Status,
|
||||
_transmit: extern fn (*const Udp6Protocol, *Udp6CompletionToken) Status,
|
||||
_receive: extern fn (*const Udp6Protocol, *Udp6CompletionToken) Status,
|
||||
_cancel: extern fn (*const Udp6Protocol, ?*Udp6CompletionToken) Status,
|
||||
_poll: extern fn (*const Udp6Protocol) Status,
|
||||
_get_mode_data: fn (*const Udp6Protocol, ?*Udp6ConfigData, ?*Ip6ModeData, ?*ManagedNetworkConfigData, ?*SimpleNetworkMode) callconv(.C) Status,
|
||||
_configure: fn (*const Udp6Protocol, ?*const Udp6ConfigData) callconv(.C) Status,
|
||||
_groups: fn (*const Udp6Protocol, bool, ?*const Ip6Address) callconv(.C) Status,
|
||||
_transmit: fn (*const Udp6Protocol, *Udp6CompletionToken) callconv(.C) Status,
|
||||
_receive: fn (*const Udp6Protocol, *Udp6CompletionToken) callconv(.C) Status,
|
||||
_cancel: fn (*const Udp6Protocol, ?*Udp6CompletionToken) callconv(.C) Status,
|
||||
_poll: fn (*const Udp6Protocol) callconv(.C) Status,
|
||||
|
||||
pub fn getModeData(self: *const Udp6Protocol, udp6_config_data: ?*Udp6ConfigData, ip6_mode_data: ?*Ip6ModeData, mnp_config_data: ?*ManagedNetworkConfigData, snp_mode_data: ?*SimpleNetworkMode) Status {
|
||||
return self._get_mode_data(self, udp6_config_data, ip6_mode_data, mnp_config_data, snp_mode_data);
|
||||
|
@ -4,8 +4,8 @@ const Guid = uefi.Guid;
|
||||
const Status = uefi.Status;
|
||||
|
||||
pub const Udp6ServiceBindingProtocol = extern struct {
|
||||
_create_child: extern fn (*const Udp6ServiceBindingProtocol, *?Handle) Status,
|
||||
_destroy_child: extern fn (*const Udp6ServiceBindingProtocol, Handle) Status,
|
||||
_create_child: fn (*const Udp6ServiceBindingProtocol, *?Handle) callconv(.C) Status,
|
||||
_destroy_child: fn (*const Udp6ServiceBindingProtocol, Handle) callconv(.C) Status,
|
||||
|
||||
pub fn createChild(self: *const Udp6ServiceBindingProtocol, handle: *?Handle) Status {
|
||||
return self._create_child(self, handle);
|
||||
|
@ -21,117 +21,117 @@ pub const BootServices = extern struct {
|
||||
hdr: TableHeader,
|
||||
|
||||
/// Raises a task's priority level and returns its previous level.
|
||||
raiseTpl: extern fn (usize) usize,
|
||||
raiseTpl: fn (usize) callconv(.C) usize,
|
||||
|
||||
/// Restores a task's priority level to its previous value.
|
||||
restoreTpl: extern fn (usize) void,
|
||||
restoreTpl: fn (usize) callconv(.C) void,
|
||||
|
||||
/// Allocates memory pages from the system.
|
||||
allocatePages: extern fn (AllocateType, MemoryType, usize, *[*]align(4096) u8) Status,
|
||||
allocatePages: fn (AllocateType, MemoryType, usize, *[*]align(4096) u8) callconv(.C) Status,
|
||||
|
||||
/// Frees memory pages.
|
||||
freePages: extern fn ([*]align(4096) u8, usize) Status,
|
||||
freePages: fn ([*]align(4096) u8, usize) callconv(.C) Status,
|
||||
|
||||
/// Returns the current memory map.
|
||||
getMemoryMap: extern fn (*usize, [*]MemoryDescriptor, *usize, *usize, *u32) Status,
|
||||
getMemoryMap: fn (*usize, [*]MemoryDescriptor, *usize, *usize, *u32) callconv(.C) Status,
|
||||
|
||||
/// Allocates pool memory.
|
||||
allocatePool: extern fn (MemoryType, usize, *[*]align(8) u8) Status,
|
||||
allocatePool: fn (MemoryType, usize, *[*]align(8) u8) callconv(.C) Status,
|
||||
|
||||
/// Returns pool memory to the system.
|
||||
freePool: extern fn ([*]align(8) u8) Status,
|
||||
freePool: fn ([*]align(8) u8) callconv(.C) Status,
|
||||
|
||||
/// Creates an event.
|
||||
createEvent: extern fn (u32, usize, ?extern fn (Event, ?*c_void) void, ?*const c_void, *Event) Status,
|
||||
createEvent: fn (u32, usize, ?fn (Event, ?*c_void) callconv(.C) void, ?*const c_void, *Event) callconv(.C) Status,
|
||||
|
||||
/// Sets the type of timer and the trigger time for a timer event.
|
||||
setTimer: extern fn (Event, TimerDelay, u64) Status,
|
||||
setTimer: fn (Event, TimerDelay, u64) callconv(.C) Status,
|
||||
|
||||
/// Stops execution until an event is signaled.
|
||||
waitForEvent: extern fn (usize, [*]const Event, *usize) Status,
|
||||
waitForEvent: fn (usize, [*]const Event, *usize) callconv(.C) Status,
|
||||
|
||||
/// Signals an event.
|
||||
signalEvent: extern fn (Event) Status,
|
||||
signalEvent: fn (Event) callconv(.C) Status,
|
||||
|
||||
/// Closes an event.
|
||||
closeEvent: extern fn (Event) Status,
|
||||
closeEvent: fn (Event) callconv(.C) Status,
|
||||
|
||||
/// Checks whether an event is in the signaled state.
|
||||
checkEvent: extern fn (Event) Status,
|
||||
checkEvent: fn (Event) callconv(.C) Status,
|
||||
|
||||
installProtocolInterface: Status, // TODO
|
||||
reinstallProtocolInterface: Status, // TODO
|
||||
uninstallProtocolInterface: Status, // TODO
|
||||
|
||||
/// Queries a handle to determine if it supports a specified protocol.
|
||||
handleProtocol: extern fn (Handle, *align(8) const Guid, *?*c_void) Status,
|
||||
handleProtocol: fn (Handle, *align(8) const Guid, *?*c_void) callconv(.C) Status,
|
||||
|
||||
reserved: *c_void,
|
||||
|
||||
registerProtocolNotify: Status, // TODO
|
||||
|
||||
/// Returns an array of handles that support a specified protocol.
|
||||
locateHandle: extern fn (LocateSearchType, ?*align(8) const Guid, ?*const c_void, *usize, [*]Handle) Status,
|
||||
locateHandle: fn (LocateSearchType, ?*align(8) const Guid, ?*const c_void, *usize, [*]Handle) callconv(.C) Status,
|
||||
|
||||
locateDevicePath: Status, // TODO
|
||||
installConfigurationTable: Status, // TODO
|
||||
|
||||
/// Loads an EFI image into memory.
|
||||
loadImage: extern fn (bool, Handle, ?*const DevicePathProtocol, ?[*]const u8, usize, *?Handle) Status,
|
||||
loadImage: fn (bool, Handle, ?*const DevicePathProtocol, ?[*]const u8, usize, *?Handle) callconv(.C) Status,
|
||||
|
||||
/// Transfers control to a loaded image's entry point.
|
||||
startImage: extern fn (Handle, ?*usize, ?*[*]u16) Status,
|
||||
startImage: fn (Handle, ?*usize, ?*[*]u16) callconv(.C) Status,
|
||||
|
||||
/// Terminates a loaded EFI image and returns control to boot services.
|
||||
exit: extern fn (Handle, Status, usize, ?*const c_void) Status,
|
||||
exit: fn (Handle, Status, usize, ?*const c_void) callconv(.C) Status,
|
||||
|
||||
/// Unloads an image.
|
||||
unloadImage: extern fn (Handle) Status,
|
||||
unloadImage: fn (Handle) callconv(.C) Status,
|
||||
|
||||
/// Terminates all boot services.
|
||||
exitBootServices: extern fn (Handle, usize) Status,
|
||||
exitBootServices: fn (Handle, usize) callconv(.C) Status,
|
||||
|
||||
/// Returns a monotonically increasing count for the platform.
|
||||
getNextMonotonicCount: extern fn (*u64) Status,
|
||||
getNextMonotonicCount: fn (*u64) callconv(.C) Status,
|
||||
|
||||
/// Induces a fine-grained stall.
|
||||
stall: extern fn (usize) Status,
|
||||
stall: fn (usize) callconv(.C) Status,
|
||||
|
||||
/// Sets the system's watchdog timer.
|
||||
setWatchdogTimer: extern fn (usize, u64, usize, ?[*]const u16) Status,
|
||||
setWatchdogTimer: fn (usize, u64, usize, ?[*]const u16) callconv(.C) Status,
|
||||
|
||||
connectController: Status, // TODO
|
||||
disconnectController: Status, // TODO
|
||||
|
||||
/// Queries a handle to determine if it supports a specified protocol.
|
||||
openProtocol: extern fn (Handle, *align(8) const Guid, *?*c_void, ?Handle, ?Handle, OpenProtocolAttributes) Status,
|
||||
openProtocol: fn (Handle, *align(8) const Guid, *?*c_void, ?Handle, ?Handle, OpenProtocolAttributes) callconv(.C) Status,
|
||||
|
||||
/// Closes a protocol on a handle that was opened using openProtocol().
|
||||
closeProtocol: extern fn (Handle, *align(8) const Guid, Handle, ?Handle) Status,
|
||||
closeProtocol: fn (Handle, *align(8) const Guid, Handle, ?Handle) callconv(.C) Status,
|
||||
|
||||
/// Retrieves the list of agents that currently have a protocol interface opened.
|
||||
openProtocolInformation: extern fn (Handle, *align(8) const Guid, *[*]ProtocolInformationEntry, *usize) Status,
|
||||
openProtocolInformation: fn (Handle, *align(8) const Guid, *[*]ProtocolInformationEntry, *usize) callconv(.C) Status,
|
||||
|
||||
/// Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool.
|
||||
protocolsPerHandle: extern fn (Handle, *[*]*align(8) const Guid, *usize) Status,
|
||||
protocolsPerHandle: fn (Handle, *[*]*align(8) const Guid, *usize) callconv(.C) Status,
|
||||
|
||||
/// Returns an array of handles that support the requested protocol in a buffer allocated from pool.
|
||||
locateHandleBuffer: extern fn (LocateSearchType, ?*align(8) const Guid, ?*const c_void, *usize, *[*]Handle) Status,
|
||||
locateHandleBuffer: fn (LocateSearchType, ?*align(8) const Guid, ?*const c_void, *usize, *[*]Handle) callconv(.C) Status,
|
||||
|
||||
/// Returns the first protocol instance that matches the given protocol.
|
||||
locateProtocol: extern fn (*align(8) const Guid, ?*const c_void, *?*c_void) Status,
|
||||
locateProtocol: fn (*align(8) const Guid, ?*const c_void, *?*c_void) callconv(.C) Status,
|
||||
|
||||
installMultipleProtocolInterfaces: Status, // TODO
|
||||
uninstallMultipleProtocolInterfaces: Status, // TODO
|
||||
|
||||
/// Computes and returns a 32-bit CRC for a data buffer.
|
||||
calculateCrc32: extern fn ([*]const u8, usize, *u32) Status,
|
||||
calculateCrc32: fn ([*]const u8, usize, *u32) callconv(.C) Status,
|
||||
|
||||
/// Copies the contents of one buffer to another buffer
|
||||
copyMem: extern fn ([*]u8, [*]const u8, usize) void,
|
||||
copyMem: fn ([*]u8, [*]const u8, usize) callconv(.C) void,
|
||||
|
||||
/// Fills a buffer with a specified value
|
||||
setMem: extern fn ([*]u8, usize, u8) void,
|
||||
setMem: fn ([*]u8, usize, u8) callconv(.C) void,
|
||||
|
||||
createEventEx: Status, // TODO
|
||||
|
||||
|
@ -17,7 +17,7 @@ pub const RuntimeServices = extern struct {
|
||||
hdr: TableHeader,
|
||||
|
||||
/// Returns the current time and date information, and the time-keeping capabilities of the hardware platform.
|
||||
getTime: extern fn (*uefi.Time, ?*TimeCapabilities) Status,
|
||||
getTime: fn (*uefi.Time, ?*TimeCapabilities) callconv(.C) Status,
|
||||
|
||||
setTime: Status, // TODO
|
||||
getWakeupTime: Status, // TODO
|
||||
@ -26,18 +26,18 @@ pub const RuntimeServices = extern struct {
|
||||
convertPointer: Status, // TODO
|
||||
|
||||
/// Returns the value of a variable.
|
||||
getVariable: extern fn ([*:0]const u16, *align(8) const Guid, ?*u32, *usize, ?*c_void) Status,
|
||||
getVariable: fn ([*:0]const u16, *align(8) const Guid, ?*u32, *usize, ?*c_void) callconv(.C) Status,
|
||||
|
||||
/// Enumerates the current variable names.
|
||||
getNextVariableName: extern fn (*usize, [*:0]u16, *align(8) Guid) Status,
|
||||
getNextVariableName: fn (*usize, [*:0]u16, *align(8) Guid) callconv(.C) Status,
|
||||
|
||||
/// Sets the value of a variable.
|
||||
setVariable: extern fn ([*:0]const u16, *align(8) const Guid, u32, usize, *c_void) Status,
|
||||
setVariable: fn ([*:0]const u16, *align(8) const Guid, u32, usize, *c_void) callconv(.C) Status,
|
||||
|
||||
getNextHighMonotonicCount: Status, // TODO
|
||||
|
||||
/// Resets the entire platform.
|
||||
resetSystem: extern fn (ResetType, Status, usize, ?*const c_void) noreturn,
|
||||
resetSystem: fn (ResetType, Status, usize, ?*const c_void) callconv(.C) noreturn,
|
||||
|
||||
updateCapsule: Status, // TODO
|
||||
queryCapsuleCapabilities: Status, // TODO
|
||||
|
@ -627,7 +627,7 @@ pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
|
||||
pub const MEM_DECOMMIT = 0x4000;
|
||||
pub const MEM_RELEASE = 0x8000;
|
||||
|
||||
pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
|
||||
pub const PTHREAD_START_ROUTINE = fn (LPVOID) callconv(.C) DWORD;
|
||||
pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
|
||||
|
||||
pub const WIN32_FIND_DATAW = extern struct {
|
||||
@ -784,7 +784,7 @@ pub const IMAGE_TLS_DIRECTORY = extern struct {
|
||||
pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
|
||||
pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
|
||||
|
||||
pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;
|
||||
pub const PIMAGE_TLS_CALLBACK = ?fn (PVOID, DWORD, PVOID) callconv(.C) void;
|
||||
|
||||
pub const PROV_RSA_FULL = 1;
|
||||
|
||||
@ -810,7 +810,7 @@ pub const FILE_ACTION_MODIFIED = 0x00000003;
|
||||
pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
|
||||
pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
|
||||
|
||||
pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;
|
||||
pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?fn (DWORD, DWORD, *OVERLAPPED) callconv(.C) void;
|
||||
|
||||
pub const FILE_NOTIFY_CHANGE_CREATION = 64;
|
||||
pub const FILE_NOTIFY_CHANGE_SIZE = 8;
|
||||
@ -863,7 +863,7 @@ pub const RTL_CRITICAL_SECTION = extern struct {
|
||||
pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
|
||||
pub const INIT_ONCE = RTL_RUN_ONCE;
|
||||
pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
|
||||
pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
|
||||
pub const INIT_ONCE_FN = fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) callconv(.C) BOOL;
|
||||
|
||||
pub const RTL_RUN_ONCE = extern struct {
|
||||
Ptr: ?*c_void,
|
||||
@ -1418,7 +1418,7 @@ pub const RTL_DRIVE_LETTER_CURDIR = extern struct {
|
||||
DosPath: UNICODE_STRING,
|
||||
};
|
||||
|
||||
pub const PPS_POST_PROCESS_INIT_ROUTINE = ?extern fn () void;
|
||||
pub const PPS_POST_PROCESS_INIT_ROUTINE = ?fn () callconv(.C) void;
|
||||
|
||||
pub const FILE_BOTH_DIR_INFORMATION = extern struct {
|
||||
NextEntryOffset: ULONG,
|
||||
@ -1438,7 +1438,7 @@ pub const FILE_BOTH_DIR_INFORMATION = extern struct {
|
||||
};
|
||||
pub const FILE_BOTH_DIRECTORY_INFORMATION = FILE_BOTH_DIR_INFORMATION;
|
||||
|
||||
pub const IO_APC_ROUTINE = extern fn (PVOID, *IO_STATUS_BLOCK, ULONG) void;
|
||||
pub const IO_APC_ROUTINE = fn (PVOID, *IO_STATUS_BLOCK, ULONG) callconv(.C) void;
|
||||
|
||||
pub const CURDIR = extern struct {
|
||||
DosPath: UNICODE_STRING,
|
||||
|
@ -73,7 +73,6 @@ pub const WM_XBUTTONDBLCLK = 0x020D;
|
||||
// WA
|
||||
pub const WA_INACTIVE = 0;
|
||||
pub const WA_ACTIVE = 0x0006;
|
||||
pub const WM_ACTIVATE = 0x0006;
|
||||
|
||||
// WS
|
||||
pub const WS_OVERLAPPED = 0x00000000;
|
||||
@ -147,7 +146,6 @@ pub extern "user32" fn CreateWindowExA(
|
||||
|
||||
pub extern "user32" fn RegisterClassExA(*const WNDCLASSEXA) callconv(.Stdcall) c_ushort;
|
||||
pub extern "user32" fn DefWindowProcA(HWND, Msg: UINT, WPARAM, LPARAM) callconv(.Stdcall) LRESULT;
|
||||
pub extern "user32" fn GetModuleHandleA(lpModuleName: ?LPCSTR) callconv(.Stdcall) HMODULE;
|
||||
pub extern "user32" fn ShowWindow(hWnd: ?HWND, nCmdShow: i32) callconv(.Stdcall) bool;
|
||||
pub extern "user32" fn UpdateWindow(hWnd: ?HWND) callconv(.Stdcall) bool;
|
||||
pub extern "user32" fn GetDC(hWnd: ?HWND) callconv(.Stdcall) ?HDC;
|
||||
|
@ -106,7 +106,7 @@ pub const WSAOVERLAPPED = extern struct {
|
||||
hEvent: ?WSAEVENT,
|
||||
};
|
||||
|
||||
pub const WSAOVERLAPPED_COMPLETION_ROUTINE = extern fn (dwError: DWORD, cbTransferred: DWORD, lpOverlapped: *WSAOVERLAPPED, dwFlags: DWORD) void;
|
||||
pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred: DWORD, lpOverlapped: *WSAOVERLAPPED, dwFlags: DWORD) callconv(.C) void;
|
||||
|
||||
pub const ADDRESS_FAMILY = u16;
|
||||
|
||||
|
@ -644,7 +644,7 @@ const MsfStream = struct {
|
||||
return stream;
|
||||
}
|
||||
|
||||
fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
|
||||
pub fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
|
||||
var list = ArrayList(u8).init(allocator);
|
||||
while (true) {
|
||||
const byte = try self.inStream().readByte();
|
||||
@ -684,13 +684,13 @@ const MsfStream = struct {
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
fn seekBy(self: *MsfStream, len: i64) !void {
|
||||
pub fn seekBy(self: *MsfStream, len: i64) !void {
|
||||
self.pos = @intCast(u64, @intCast(i64, self.pos) + len);
|
||||
if (self.pos >= self.blocks.len * self.block_size)
|
||||
return error.EOF;
|
||||
}
|
||||
|
||||
fn seekTo(self: *MsfStream, len: u64) !void {
|
||||
pub fn seekTo(self: *MsfStream, len: u64) !void {
|
||||
self.pos = len;
|
||||
if (self.pos >= self.blocks.len * self.block_size)
|
||||
return error.EOF;
|
||||
@ -708,7 +708,7 @@ const MsfStream = struct {
|
||||
return block * self.block_size + offset;
|
||||
}
|
||||
|
||||
fn inStream(self: *MsfStream) std.io.InStream(*MsfStream, Error, read) {
|
||||
pub fn inStream(self: *MsfStream) std.io.InStream(*MsfStream, Error, read) {
|
||||
return .{ .context = self };
|
||||
}
|
||||
};
|
||||
|
@ -185,18 +185,18 @@ pub fn PriorityQueue(comptime T: type) type {
|
||||
self.len = new_len;
|
||||
}
|
||||
|
||||
const Iterator = struct {
|
||||
pub const Iterator = struct {
|
||||
queue: *PriorityQueue(T),
|
||||
count: usize,
|
||||
|
||||
fn next(it: *Iterator) ?T {
|
||||
pub fn next(it: *Iterator) ?T {
|
||||
if (it.count > it.queue.len - 1) return null;
|
||||
const out = it.count;
|
||||
it.count += 1;
|
||||
return it.queue.items[out];
|
||||
}
|
||||
|
||||
fn reset(it: *Iterator) void {
|
||||
pub fn reset(it: *Iterator) void {
|
||||
it.count = 0;
|
||||
}
|
||||
};
|
||||
|
@ -1498,6 +1498,22 @@
|
||||
}
|
||||
];
|
||||
|
||||
// Links, images and inner links don't use the same marker to wrap their content.
|
||||
const linksFormat = [
|
||||
{
|
||||
prefix: "[",
|
||||
regex: /\[([^\]]*)\]\(([^\)]*)\)/,
|
||||
urlIndex: 2, // Index in the match that contains the link URL
|
||||
textIndex: 1 // Index in the match that contains the link text
|
||||
},
|
||||
{
|
||||
prefix: "h",
|
||||
regex: /http[s]?:\/\/[^\s]+/,
|
||||
urlIndex: 0,
|
||||
textIndex: 0
|
||||
}
|
||||
];
|
||||
|
||||
const stack = [];
|
||||
|
||||
var innerHTML = "";
|
||||
@ -1548,6 +1564,29 @@
|
||||
currentRun += innerText[i];
|
||||
in_code = true;
|
||||
} else {
|
||||
var foundMatches = false;
|
||||
|
||||
for (var j = 0; j < linksFormat.length; j++) {
|
||||
const linkFmt = linksFormat[j];
|
||||
|
||||
if (linkFmt.prefix == innerText[i]) {
|
||||
var remaining = innerText.substring(i);
|
||||
var matches = remaining.match(linkFmt.regex);
|
||||
|
||||
if (matches) {
|
||||
flushRun();
|
||||
innerHTML += ' <a href="' + matches[linkFmt.urlIndex] + '">' + matches[linkFmt.textIndex] + '</a> ';
|
||||
i += matches[0].length; // Skip the fragment we just consumed
|
||||
foundMatches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundMatches) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var any = false;
|
||||
for (var idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {
|
||||
const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1];
|
||||
|
@ -34,7 +34,7 @@ pub fn main() anyerror!void {
|
||||
std.heap.page_allocator.free(async_frame_buffer);
|
||||
async_frame_buffer = try std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size);
|
||||
}
|
||||
const casted_fn = @ptrCast(async fn () anyerror!void, test_fn.func);
|
||||
const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func);
|
||||
break :blk await @asyncCall(async_frame_buffer, {}, casted_fn);
|
||||
},
|
||||
.blocking => {
|
||||
|
@ -224,8 +224,7 @@ inline fn initEventLoopAndCallMain() u8 {
|
||||
// and we want fewer call frames in stack traces.
|
||||
return @call(.{ .modifier = .always_inline }, callMain, .{});
|
||||
}
|
||||
|
||||
async fn callMainAsync(loop: *std.event.Loop) u8 {
|
||||
fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 {
|
||||
// This prevents the event loop from terminating at least until main() has returned.
|
||||
loop.beginOneEvent();
|
||||
defer loop.finishOneEvent();
|
||||
|
@ -280,7 +280,7 @@ pub const Thread = struct {
|
||||
std.debug.dumpStackTrace(trace.*);
|
||||
}
|
||||
};
|
||||
return 0;
|
||||
return null;
|
||||
},
|
||||
else => @compileError(bad_startfn_ret),
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ pub const Error = union(enum) {
|
||||
ExpectedStatement: ExpectedStatement,
|
||||
ExpectedVarDeclOrFn: ExpectedVarDeclOrFn,
|
||||
ExpectedVarDecl: ExpectedVarDecl,
|
||||
ExpectedFn: ExpectedFn,
|
||||
ExpectedReturnType: ExpectedReturnType,
|
||||
ExpectedAggregateKw: ExpectedAggregateKw,
|
||||
UnattachedDocComment: UnattachedDocComment,
|
||||
@ -165,6 +166,7 @@ pub const Error = union(enum) {
|
||||
ExpectedDerefOrUnwrap: ExpectedDerefOrUnwrap,
|
||||
ExpectedSuffixOp: ExpectedSuffixOp,
|
||||
DeclBetweenFields: DeclBetweenFields,
|
||||
InvalidAnd: InvalidAnd,
|
||||
|
||||
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
|
||||
switch (self.*) {
|
||||
@ -177,6 +179,7 @@ pub const Error = union(enum) {
|
||||
.ExpectedStatement => |*x| return x.render(tokens, stream),
|
||||
.ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
|
||||
.ExpectedVarDecl => |*x| return x.render(tokens, stream),
|
||||
.ExpectedFn => |*x| return x.render(tokens, stream),
|
||||
.ExpectedReturnType => |*x| return x.render(tokens, stream),
|
||||
.ExpectedAggregateKw => |*x| return x.render(tokens, stream),
|
||||
.UnattachedDocComment => |*x| return x.render(tokens, stream),
|
||||
@ -213,6 +216,7 @@ pub const Error = union(enum) {
|
||||
.ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
|
||||
.ExpectedSuffixOp => |*x| return x.render(tokens, stream),
|
||||
.DeclBetweenFields => |*x| return x.render(tokens, stream),
|
||||
.InvalidAnd => |*x| return x.render(tokens, stream),
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,6 +231,7 @@ pub const Error = union(enum) {
|
||||
.ExpectedStatement => |x| return x.token,
|
||||
.ExpectedVarDeclOrFn => |x| return x.token,
|
||||
.ExpectedVarDecl => |x| return x.token,
|
||||
.ExpectedFn => |x| return x.token,
|
||||
.ExpectedReturnType => |x| return x.token,
|
||||
.ExpectedAggregateKw => |x| return x.token,
|
||||
.UnattachedDocComment => |x| return x.token,
|
||||
@ -263,6 +268,7 @@ pub const Error = union(enum) {
|
||||
.ExpectedDerefOrUnwrap => |x| return x.token,
|
||||
.ExpectedSuffixOp => |x| return x.token,
|
||||
.DeclBetweenFields => |x| return x.token,
|
||||
.InvalidAnd => |x| return x.token,
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,6 +280,7 @@ pub const Error = union(enum) {
|
||||
pub const ExpectedStatement = SingleTokenError("Expected statement, found '{}'");
|
||||
pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found '{}'");
|
||||
pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
|
||||
pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");
|
||||
pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
|
||||
pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'");
|
||||
pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
|
||||
@ -308,6 +315,7 @@ pub const Error = union(enum) {
|
||||
pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
|
||||
pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
|
||||
pub const DeclBetweenFields = SimpleError("Declarations are not allowed between container fields");
|
||||
pub const InvalidAnd = SimpleError("`&&` is invalid. Note that `and` is boolean AND.");
|
||||
|
||||
pub const ExpectedCall = struct {
|
||||
node: *Node,
|
||||
@ -335,9 +343,6 @@ pub const Error = union(enum) {
|
||||
pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
|
||||
const found_token = tokens.at(self.token);
|
||||
switch (found_token.id) {
|
||||
.Invalid_ampersands => {
|
||||
return stream.print("`&&` is invalid. Note that `and` is boolean AND.", .{});
|
||||
},
|
||||
.Invalid => {
|
||||
return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
|
||||
},
|
||||
@ -438,7 +443,7 @@ pub const Node = struct {
|
||||
ContainerDecl,
|
||||
Asm,
|
||||
Comptime,
|
||||
Noasync,
|
||||
Nosuspend,
|
||||
Block,
|
||||
|
||||
// Misc
|
||||
@ -569,9 +574,9 @@ pub const Node = struct {
|
||||
|
||||
return true;
|
||||
},
|
||||
.Noasync => {
|
||||
const noasync_node = @fieldParentPtr(Noasync, "base", n);
|
||||
return noasync_node.expr.id != .Block;
|
||||
.Nosuspend => {
|
||||
const nosuspend_node = @fieldParentPtr(Nosuspend, "base", n);
|
||||
return nosuspend_node.expr.id != .Block;
|
||||
},
|
||||
else => return true,
|
||||
}
|
||||
@ -875,18 +880,20 @@ pub const Node = struct {
|
||||
return_type: ReturnType,
|
||||
var_args_token: ?TokenIndex,
|
||||
extern_export_inline_token: ?TokenIndex,
|
||||
cc_token: ?TokenIndex,
|
||||
body_node: ?*Node,
|
||||
lib_name: ?*Node, // populated if this is an extern declaration
|
||||
align_expr: ?*Node, // populated if align(A) is present
|
||||
section_expr: ?*Node, // populated if linksection(A) is present
|
||||
callconv_expr: ?*Node, // populated if callconv(A) is present
|
||||
is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
|
||||
is_async: bool = false, // TODO: remove once async fn rewriting is
|
||||
|
||||
pub const ParamList = SegmentedList(*Node, 2);
|
||||
|
||||
pub const ReturnType = union(enum) {
|
||||
Explicit: *Node,
|
||||
InferErrorSet: *Node,
|
||||
Invalid: TokenIndex,
|
||||
};
|
||||
|
||||
pub fn iterate(self: *FnProto, index: usize) ?*Node {
|
||||
@ -915,6 +922,7 @@ pub const Node = struct {
|
||||
if (i < 1) return node;
|
||||
i -= 1;
|
||||
},
|
||||
.Invalid => {},
|
||||
}
|
||||
|
||||
if (self.body_node) |body_node| {
|
||||
@ -929,7 +937,6 @@ pub const Node = struct {
|
||||
if (self.visib_token) |visib_token| return visib_token;
|
||||
if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
|
||||
assert(self.lib_name == null);
|
||||
if (self.cc_token) |cc_token| return cc_token;
|
||||
return self.fn_token;
|
||||
}
|
||||
|
||||
@ -937,6 +944,7 @@ pub const Node = struct {
|
||||
if (self.body_node) |body_node| return body_node.lastToken();
|
||||
switch (self.return_type) {
|
||||
.Explicit, .InferErrorSet => |node| return node.lastToken(),
|
||||
.Invalid => |tok| return tok,
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1084,12 +1092,12 @@ pub const Node = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Noasync = struct {
|
||||
base: Node = Node{ .id = .Noasync },
|
||||
noasync_token: TokenIndex,
|
||||
pub const Nosuspend = struct {
|
||||
base: Node = Node{ .id = .Nosuspend },
|
||||
nosuspend_token: TokenIndex,
|
||||
expr: *Node,
|
||||
|
||||
pub fn iterate(self: *Noasync, index: usize) ?*Node {
|
||||
pub fn iterate(self: *Nosuspend, index: usize) ?*Node {
|
||||
var i = index;
|
||||
|
||||
if (i < 1) return self.expr;
|
||||
@ -1098,11 +1106,11 @@ pub const Node = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn firstToken(self: *const Noasync) TokenIndex {
|
||||
return self.noasync_token;
|
||||
pub fn firstToken(self: *const Nosuspend) TokenIndex {
|
||||
return self.nosuspend_token;
|
||||
}
|
||||
|
||||
pub fn lastToken(self: *const Noasync) TokenIndex {
|
||||
pub fn lastToken(self: *const Nosuspend) TokenIndex {
|
||||
return self.expr.lastToken();
|
||||
}
|
||||
};
|
||||
|
@ -660,7 +660,7 @@ pub const CrossTarget = struct {
|
||||
return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch());
|
||||
}
|
||||
|
||||
fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
|
||||
pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
|
||||
set.removeFeatureSet(self.cpu_features_sub);
|
||||
set.addFeatureSet(self.cpu_features_add);
|
||||
set.populateDependencies(self.getCpuArch().allFeaturesList());
|
||||
|
@ -48,31 +48,24 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {
|
||||
|
||||
while (it.peek().?.id == .LineComment) _ = it.next();
|
||||
|
||||
tree.root_node = parseRoot(arena, &it, tree) catch |err| blk: {
|
||||
switch (err) {
|
||||
error.ParseError => {
|
||||
assert(tree.errors.len != 0);
|
||||
break :blk undefined;
|
||||
},
|
||||
error.OutOfMemory => {
|
||||
return error.OutOfMemory;
|
||||
},
|
||||
}
|
||||
};
|
||||
tree.root_node = try parseRoot(arena, &it, tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
/// Root <- skip ContainerMembers eof
|
||||
fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root {
|
||||
fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {
|
||||
const node = try arena.create(Node.Root);
|
||||
node.* = .{
|
||||
.decls = try parseContainerMembers(arena, it, tree),
|
||||
.eof_token = eatToken(it, .Eof) orelse {
|
||||
.eof_token = eatToken(it, .Eof) orelse blk: {
|
||||
// parseContainerMembers will try to skip as much
|
||||
// invalid tokens as it can so this can only be a '}'
|
||||
const tok = eatToken(it, .RBrace).?;
|
||||
try tree.errors.push(.{
|
||||
.ExpectedContainerMembers = .{ .token = it.index },
|
||||
.ExpectedContainerMembers = .{ .token = tok },
|
||||
});
|
||||
return error.ParseError;
|
||||
break :blk tok;
|
||||
},
|
||||
};
|
||||
return node;
|
||||
@ -108,7 +101,13 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
|
||||
|
||||
const doc_comments = try parseDocComment(arena, it, tree);
|
||||
|
||||
if (try parseTestDecl(arena, it, tree)) |node| {
|
||||
if (parseTestDecl(arena, it, tree) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.ParseError => {
|
||||
findNextContainerMember(it);
|
||||
continue;
|
||||
},
|
||||
}) |node| {
|
||||
if (field_state == .seen) {
|
||||
field_state = .{ .end = node.firstToken() };
|
||||
}
|
||||
@ -117,7 +116,13 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try parseTopLevelComptime(arena, it, tree)) |node| {
|
||||
if (parseTopLevelComptime(arena, it, tree) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.ParseError => {
|
||||
findNextContainerMember(it);
|
||||
continue;
|
||||
},
|
||||
}) |node| {
|
||||
if (field_state == .seen) {
|
||||
field_state = .{ .end = node.firstToken() };
|
||||
}
|
||||
@ -128,7 +133,13 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
|
||||
|
||||
const visib_token = eatToken(it, .Keyword_pub);
|
||||
|
||||
if (try parseTopLevelDecl(arena, it, tree)) |node| {
|
||||
if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.ParseError => {
|
||||
findNextContainerMember(it);
|
||||
continue;
|
||||
},
|
||||
}) |node| {
|
||||
if (field_state == .seen) {
|
||||
field_state = .{ .end = visib_token orelse node.firstToken() };
|
||||
}
|
||||
@ -163,10 +174,18 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
|
||||
try tree.errors.push(.{
|
||||
.ExpectedPubItem = .{ .token = it.index },
|
||||
});
|
||||
return error.ParseError;
|
||||
// ignore this pub
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try parseContainerField(arena, it, tree)) |node| {
|
||||
if (parseContainerField(arena, it, tree) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.ParseError => {
|
||||
// attempt to recover
|
||||
findNextContainerMember(it);
|
||||
continue;
|
||||
},
|
||||
}) |node| {
|
||||
switch (field_state) {
|
||||
.none => field_state = .seen,
|
||||
.err, .seen => {},
|
||||
@ -182,7 +201,21 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
|
||||
const field = node.cast(Node.ContainerField).?;
|
||||
field.doc_comments = doc_comments;
|
||||
try list.push(node);
|
||||
const comma = eatToken(it, .Comma) orelse break;
|
||||
const comma = eatToken(it, .Comma) orelse {
|
||||
// try to continue parsing
|
||||
const index = it.index;
|
||||
findNextContainerMember(it);
|
||||
switch (it.peek().?.id) {
|
||||
.Eof, .RBrace => break,
|
||||
else => {
|
||||
// add error and continue
|
||||
try tree.errors.push(.{
|
||||
.ExpectedToken = .{ .token = index, .expected_id = .Comma },
|
||||
});
|
||||
continue;
|
||||
},
|
||||
}
|
||||
};
|
||||
if (try parseAppendedDocComment(arena, it, tree, comma)) |appended_comment|
|
||||
field.doc_comments = appended_comment;
|
||||
continue;
|
||||
@ -194,12 +227,102 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
|
||||
.UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
switch (it.peek().?.id) {
|
||||
.Eof, .RBrace => break,
|
||||
else => {
|
||||
// this was likely not supposed to end yet,
|
||||
// try to find the next declaration
|
||||
const index = it.index;
|
||||
findNextContainerMember(it);
|
||||
try tree.errors.push(.{
|
||||
.ExpectedContainerMembers = .{ .token = index },
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// Attempts to find next container member by searching for certain tokens
|
||||
fn findNextContainerMember(it: *TokenIterator) void {
|
||||
var level: u32 = 0;
|
||||
while (true) {
|
||||
const tok = nextToken(it);
|
||||
switch (tok.ptr.id) {
|
||||
// any of these can start a new top level declaration
|
||||
.Keyword_test,
|
||||
.Keyword_comptime,
|
||||
.Keyword_pub,
|
||||
.Keyword_export,
|
||||
.Keyword_extern,
|
||||
.Keyword_inline,
|
||||
.Keyword_noinline,
|
||||
.Keyword_usingnamespace,
|
||||
.Keyword_threadlocal,
|
||||
.Keyword_const,
|
||||
.Keyword_var,
|
||||
.Keyword_fn,
|
||||
.Identifier,
|
||||
=> {
|
||||
if (level == 0) {
|
||||
putBackToken(it, tok.index);
|
||||
return;
|
||||
}
|
||||
},
|
||||
.Comma, .Semicolon => {
|
||||
// this decl was likely meant to end here
|
||||
if (level == 0) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
.LParen, .LBracket, .LBrace => level += 1,
|
||||
.RParen, .RBracket, .RBrace => {
|
||||
if (level == 0) {
|
||||
// end of container, exit
|
||||
putBackToken(it, tok.index);
|
||||
return;
|
||||
}
|
||||
level -= 1;
|
||||
},
|
||||
.Eof => {
|
||||
putBackToken(it, tok.index);
|
||||
return;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to find the next statement by searching for a semicolon
|
||||
fn findNextStmt(it: *TokenIterator) void {
|
||||
var level: u32 = 0;
|
||||
while (true) {
|
||||
const tok = nextToken(it);
|
||||
switch (tok.ptr.id) {
|
||||
.LBrace => level += 1,
|
||||
.RBrace => {
|
||||
if (level == 0) {
|
||||
putBackToken(it, tok.index);
|
||||
return;
|
||||
}
|
||||
level -= 1;
|
||||
},
|
||||
.Semicolon => {
|
||||
if (level == 0) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
.Eof => {
|
||||
putBackToken(it, tok.index);
|
||||
return;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Eat a multiline container doc comment
|
||||
fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
var lines = Node.DocComment.LineList.init(arena);
|
||||
@ -279,22 +402,30 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
fn_node.*.extern_export_inline_token = extern_export_inline_token;
|
||||
fn_node.*.lib_name = lib_name;
|
||||
if (eatToken(it, .Semicolon)) |_| return node;
|
||||
if (try parseBlock(arena, it, tree)) |body_node| {
|
||||
if (parseBlock(arena, it, tree) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
// since parseBlock only return error.ParseError on
|
||||
// a missing '}' we can assume this function was
|
||||
// supposed to end here.
|
||||
error.ParseError => return node,
|
||||
}) |body_node| {
|
||||
fn_node.body_node = body_node;
|
||||
return node;
|
||||
}
|
||||
try tree.errors.push(.{
|
||||
.ExpectedSemiOrLBrace = .{ .token = it.index },
|
||||
});
|
||||
return null;
|
||||
return error.ParseError;
|
||||
}
|
||||
|
||||
if (extern_export_inline_token) |token| {
|
||||
if (tree.tokens.at(token).id == .Keyword_inline or
|
||||
tree.tokens.at(token).id == .Keyword_noinline)
|
||||
{
|
||||
putBackToken(it, token);
|
||||
return null;
|
||||
try tree.errors.push(.{
|
||||
.ExpectedFn = .{ .token = it.index },
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,42 +444,40 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
try tree.errors.push(.{
|
||||
.ExpectedVarDecl = .{ .token = it.index },
|
||||
});
|
||||
// ignore this and try again;
|
||||
return error.ParseError;
|
||||
}
|
||||
|
||||
if (extern_export_inline_token) |token| {
|
||||
if (lib_name) |string_literal_node|
|
||||
putBackToken(it, string_literal_node.cast(Node.StringLiteral).?.token);
|
||||
putBackToken(it, token);
|
||||
return null;
|
||||
try tree.errors.push(.{
|
||||
.ExpectedVarDeclOrFn = .{ .token = it.index },
|
||||
});
|
||||
// ignore this and try again;
|
||||
return error.ParseError;
|
||||
}
|
||||
|
||||
const use_node = (try parseUse(arena, it, tree)) orelse return null;
|
||||
const expr_node = try expectNode(arena, it, tree, parseExpr, .{
|
||||
.ExpectedExpr = .{ .token = it.index },
|
||||
});
|
||||
const semicolon_token = try expectToken(it, tree, .Semicolon);
|
||||
const use_node_raw = use_node.cast(Node.Use).?;
|
||||
use_node_raw.*.expr = expr_node;
|
||||
use_node_raw.*.semicolon_token = semicolon_token;
|
||||
|
||||
return use_node;
|
||||
return try parseUse(arena, it, tree);
|
||||
}
|
||||
|
||||
/// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const cc = parseFnCC(arena, it, tree);
|
||||
const fn_token = eatToken(it, .Keyword_fn) orelse {
|
||||
if (cc) |fnCC| {
|
||||
if (fnCC == .Extern) {
|
||||
putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl
|
||||
} else {
|
||||
try tree.errors.push(.{
|
||||
.ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn },
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
// TODO: Remove once extern/async fn rewriting is
|
||||
var is_async = false;
|
||||
var is_extern = false;
|
||||
const cc_token: ?usize = blk: {
|
||||
if (eatToken(it, .Keyword_extern)) |token| {
|
||||
is_extern = true;
|
||||
break :blk token;
|
||||
}
|
||||
if (eatToken(it, .Keyword_async)) |token| {
|
||||
is_async = true;
|
||||
break :blk token;
|
||||
}
|
||||
break :blk null;
|
||||
};
|
||||
const fn_token = eatToken(it, .Keyword_fn) orelse {
|
||||
if (cc_token) |token|
|
||||
putBackToken(it, token);
|
||||
return null;
|
||||
};
|
||||
const name_token = eatToken(it, .Identifier);
|
||||
@ -361,18 +490,23 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const exclamation_token = eatToken(it, .Bang);
|
||||
|
||||
const return_type_expr = (try parseVarType(arena, it, tree)) orelse
|
||||
try expectNode(arena, it, tree, parseTypeExpr, .{
|
||||
.ExpectedReturnType = .{ .token = it.index },
|
||||
});
|
||||
(try parseTypeExpr(arena, it, tree)) orelse blk: {
|
||||
try tree.errors.push(.{
|
||||
.ExpectedReturnType = .{ .token = it.index },
|
||||
});
|
||||
// most likely the user forgot to specify the return type.
|
||||
// Mark return type as invalid and try to continue.
|
||||
break :blk null;
|
||||
};
|
||||
|
||||
const return_type: Node.FnProto.ReturnType = if (exclamation_token != null)
|
||||
.{
|
||||
.InferErrorSet = return_type_expr,
|
||||
}
|
||||
// TODO https://github.com/ziglang/zig/issues/3750
|
||||
const R = Node.FnProto.ReturnType;
|
||||
const return_type = if (return_type_expr == null)
|
||||
R{ .Invalid = rparen }
|
||||
else if (exclamation_token != null)
|
||||
R{ .InferErrorSet = return_type_expr.? }
|
||||
else
|
||||
.{
|
||||
.Explicit = return_type_expr,
|
||||
};
|
||||
R{ .Explicit = return_type_expr.? };
|
||||
|
||||
const var_args_token = if (params.len > 0)
|
||||
params.at(params.len - 1).*.cast(Node.ParamDecl).?.var_args_token
|
||||
@ -389,21 +523,15 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
.return_type = return_type,
|
||||
.var_args_token = var_args_token,
|
||||
.extern_export_inline_token = null,
|
||||
.cc_token = null,
|
||||
.body_node = null,
|
||||
.lib_name = null,
|
||||
.align_expr = align_expr,
|
||||
.section_expr = section_expr,
|
||||
.callconv_expr = callconv_expr,
|
||||
.is_extern_prototype = is_extern,
|
||||
.is_async = is_async,
|
||||
};
|
||||
|
||||
if (cc) |kind| {
|
||||
switch (kind) {
|
||||
.CC => |token| fn_proto_node.cc_token = token,
|
||||
.Extern => |token| fn_proto_node.extern_export_inline_token = token,
|
||||
}
|
||||
}
|
||||
|
||||
return &fn_proto_node.base;
|
||||
}
|
||||
|
||||
@ -495,7 +623,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
|
||||
/// Statement
|
||||
/// <- KEYWORD_comptime? VarDecl
|
||||
/// / KEYWORD_comptime BlockExprStatement
|
||||
/// / KEYWORD_noasync BlockExprStatement
|
||||
/// / KEYWORD_nosuspend BlockExprStatement
|
||||
/// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
|
||||
/// / KEYWORD_defer BlockExprStatement
|
||||
/// / KEYWORD_errdefer Payload? BlockExprStatement
|
||||
@ -527,14 +655,14 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
if (eatToken(it, .Keyword_noasync)) |noasync_token| {
|
||||
if (eatToken(it, .Keyword_nosuspend)) |nosuspend_token| {
|
||||
const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
|
||||
.ExpectedBlockOrAssignment = .{ .token = it.index },
|
||||
});
|
||||
|
||||
const node = try arena.create(Node.Noasync);
|
||||
const node = try arena.create(Node.Nosuspend);
|
||||
node.* = .{
|
||||
.noasync_token = noasync_token,
|
||||
.nosuspend_token = nosuspend_token,
|
||||
.expr = block_expr,
|
||||
};
|
||||
return &node.base;
|
||||
@ -579,7 +707,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
|
||||
if (try parseLabeledStatement(arena, it, tree)) |node| return node;
|
||||
if (try parseSwitchExpr(arena, it, tree)) |node| return node;
|
||||
if (try parseAssignExpr(arena, it, tree)) |node| {
|
||||
_ = try expectToken(it, tree, .Semicolon);
|
||||
_ = eatToken(it, .Semicolon) orelse {
|
||||
try tree.errors.push(.{
|
||||
.ExpectedToken = .{ .token = it.index, .expected_id = .Semicolon },
|
||||
});
|
||||
// pretend we saw a semicolon and continue parsing
|
||||
};
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -688,8 +821,13 @@ fn parseLoopStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
|
||||
node.cast(Node.While).?.inline_token = inline_token;
|
||||
return node;
|
||||
}
|
||||
if (inline_token == null) return null;
|
||||
|
||||
return null;
|
||||
// If we've seen "inline", there should have been a "for" or "while"
|
||||
try tree.errors.push(.{
|
||||
.ExpectedInlinable = .{ .token = it.index },
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
|
||||
/// ForStatement
|
||||
@ -818,7 +956,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
|
||||
fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
if (try parseBlockExpr(arena, it, tree)) |node| return node;
|
||||
if (try parseAssignExpr(arena, it, tree)) |node| {
|
||||
_ = try expectToken(it, tree, .Semicolon);
|
||||
_ = eatToken(it, .Semicolon) orelse {
|
||||
try tree.errors.push(.{
|
||||
.ExpectedToken = .{ .token = it.index, .expected_id = .Semicolon },
|
||||
});
|
||||
// pretend we saw a semicolon and continue parsing
|
||||
};
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
@ -908,7 +1051,7 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
/// / IfExpr
|
||||
/// / KEYWORD_break BreakLabel? Expr?
|
||||
/// / KEYWORD_comptime Expr
|
||||
/// / KEYWORD_noasync Expr
|
||||
/// / KEYWORD_nosuspend Expr
|
||||
/// / KEYWORD_continue BreakLabel?
|
||||
/// / KEYWORD_resume Expr
|
||||
/// / KEYWORD_return Expr?
|
||||
@ -925,7 +1068,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
const node = try arena.create(Node.ControlFlowExpression);
|
||||
node.* = .{
|
||||
.ltoken = token,
|
||||
.kind = Node.ControlFlowExpression.Kind{ .Break = label },
|
||||
.kind = .{ .Break = label },
|
||||
.rhs = expr_node,
|
||||
};
|
||||
return &node.base;
|
||||
@ -944,13 +1087,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
if (eatToken(it, .Keyword_noasync)) |token| {
|
||||
if (eatToken(it, .Keyword_nosuspend)) |token| {
|
||||
const expr_node = try expectNode(arena, it, tree, parseExpr, .{
|
||||
.ExpectedExpr = .{ .token = it.index },
|
||||
});
|
||||
const node = try arena.create(Node.Noasync);
|
||||
const node = try arena.create(Node.Nosuspend);
|
||||
node.* = .{
|
||||
.noasync_token = token,
|
||||
.nosuspend_token = token,
|
||||
.expr = expr_node,
|
||||
};
|
||||
return &node.base;
|
||||
@ -961,7 +1104,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
const node = try arena.create(Node.ControlFlowExpression);
|
||||
node.* = .{
|
||||
.ltoken = token,
|
||||
.kind = Node.ControlFlowExpression.Kind{ .Continue = label },
|
||||
.kind = .{ .Continue = label },
|
||||
.rhs = null,
|
||||
};
|
||||
return &node.base;
|
||||
@ -985,7 +1128,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
const node = try arena.create(Node.ControlFlowExpression);
|
||||
node.* = .{
|
||||
.ltoken = token,
|
||||
.kind = Node.ControlFlowExpression.Kind.Return,
|
||||
.kind = .Return,
|
||||
.rhs = expr_node,
|
||||
};
|
||||
return &node.base;
|
||||
@ -1023,7 +1166,14 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
|
||||
var statements = Node.Block.StatementList.init(arena);
|
||||
while (true) {
|
||||
const statement = (try parseStatement(arena, it, tree)) orelse break;
|
||||
const statement = (parseStatement(arena, it, tree) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.ParseError => {
|
||||
// try to skip to the next statement
|
||||
findNextStmt(it);
|
||||
continue;
|
||||
},
|
||||
}) orelse break;
|
||||
try statements.push(statement);
|
||||
}
|
||||
|
||||
@ -1197,6 +1347,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
if (maybe_async) |async_token| {
|
||||
const token_fn = eatToken(it, .Keyword_fn);
|
||||
if (token_fn != null) {
|
||||
// TODO: remove this hack when async fn rewriting is
|
||||
// HACK: If we see the keyword `fn`, then we assume that
|
||||
// we are parsing an async fn proto, and not a call.
|
||||
// We therefore put back all tokens consumed by the async
|
||||
@ -1205,7 +1356,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
putBackToken(it, async_token);
|
||||
return parsePrimaryTypeExpr(arena, it, tree);
|
||||
}
|
||||
// TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
|
||||
var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{
|
||||
.ExpectedPrimaryTypeExpr = .{ .token = it.index },
|
||||
});
|
||||
@ -1223,7 +1373,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
try tree.errors.push(.{
|
||||
.ExpectedParamList = .{ .token = it.index },
|
||||
});
|
||||
return null;
|
||||
// ignore this, continue parsing
|
||||
return res;
|
||||
};
|
||||
const node = try arena.create(Node.SuffixOp);
|
||||
node.* = .{
|
||||
@ -1288,7 +1439,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
/// / IfTypeExpr
|
||||
/// / INTEGER
|
||||
/// / KEYWORD_comptime TypeExpr
|
||||
/// / KEYWORD_noasync TypeExpr
|
||||
/// / KEYWORD_error DOT IDENTIFIER
|
||||
/// / KEYWORD_false
|
||||
/// / KEYWORD_null
|
||||
@ -1327,15 +1477,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (eatToken(it, .Keyword_noasync)) |token| {
|
||||
const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
|
||||
const node = try arena.create(Node.Noasync);
|
||||
node.* = .{
|
||||
.noasync_token = token,
|
||||
.expr = expr,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
if (eatToken(it, .Keyword_error)) |token| {
|
||||
const period = try expectToken(it, tree, .Period);
|
||||
const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
|
||||
@ -1778,24 +1919,6 @@ fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
return expr_node;
|
||||
}
|
||||
|
||||
/// FnCC
|
||||
/// <- KEYWORD_nakedcc
|
||||
/// / KEYWORD_stdcallcc
|
||||
/// / KEYWORD_extern
|
||||
/// / KEYWORD_async
|
||||
fn parseFnCC(arena: *Allocator, it: *TokenIterator, tree: *Tree) ?FnCC {
|
||||
if (eatToken(it, .Keyword_nakedcc)) |token| return FnCC{ .CC = token };
|
||||
if (eatToken(it, .Keyword_stdcallcc)) |token| return FnCC{ .CC = token };
|
||||
if (eatToken(it, .Keyword_extern)) |token| return FnCC{ .Extern = token };
|
||||
if (eatToken(it, .Keyword_async)) |token| return FnCC{ .CC = token };
|
||||
return null;
|
||||
}
|
||||
|
||||
const FnCC = union(enum) {
|
||||
CC: TokenIndex,
|
||||
Extern: TokenIndex,
|
||||
};
|
||||
|
||||
/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
||||
fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const doc_comments = try parseDocComment(arena, it, tree);
|
||||
@ -2290,7 +2413,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
const node = try arena.create(Node.AnyFrameType);
|
||||
node.* = .{
|
||||
.anyframe_token = token,
|
||||
.result = Node.AnyFrameType.Result{
|
||||
.result = .{
|
||||
.arrow_token = arrow,
|
||||
.return_type = undefined, // set by caller
|
||||
},
|
||||
@ -2331,6 +2454,13 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
} else null;
|
||||
_ = try expectToken(it, tree, .RParen);
|
||||
|
||||
if (ptr_info.align_info != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraAlignQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{
|
||||
.node = expr_node,
|
||||
.bit_range = bit_range,
|
||||
@ -2339,14 +2469,32 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
continue;
|
||||
}
|
||||
if (eatToken(it, .Keyword_const)) |const_token| {
|
||||
if (ptr_info.const_token != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraConstQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
ptr_info.const_token = const_token;
|
||||
continue;
|
||||
}
|
||||
if (eatToken(it, .Keyword_volatile)) |volatile_token| {
|
||||
if (ptr_info.volatile_token != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraVolatileQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
ptr_info.volatile_token = volatile_token;
|
||||
continue;
|
||||
}
|
||||
if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
|
||||
if (ptr_info.allowzero_token != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraAllowZeroQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
ptr_info.allowzero_token = allowzero_token;
|
||||
continue;
|
||||
}
|
||||
@ -2365,9 +2513,9 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
if (try parseByteAlign(arena, it, tree)) |align_expr| {
|
||||
if (slice_type.align_info != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraAlignQualifier = .{ .token = it.index },
|
||||
.ExtraAlignQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
return error.ParseError;
|
||||
continue;
|
||||
}
|
||||
slice_type.align_info = Node.PrefixOp.PtrInfo.Align{
|
||||
.node = align_expr,
|
||||
@ -2378,9 +2526,9 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
if (eatToken(it, .Keyword_const)) |const_token| {
|
||||
if (slice_type.const_token != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraConstQualifier = .{ .token = it.index },
|
||||
.ExtraConstQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
return error.ParseError;
|
||||
continue;
|
||||
}
|
||||
slice_type.const_token = const_token;
|
||||
continue;
|
||||
@ -2388,9 +2536,9 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
if (eatToken(it, .Keyword_volatile)) |volatile_token| {
|
||||
if (slice_type.volatile_token != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraVolatileQualifier = .{ .token = it.index },
|
||||
.ExtraVolatileQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
return error.ParseError;
|
||||
continue;
|
||||
}
|
||||
slice_type.volatile_token = volatile_token;
|
||||
continue;
|
||||
@ -2398,9 +2546,9 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
|
||||
if (slice_type.allowzero_token != null) {
|
||||
try tree.errors.push(.{
|
||||
.ExtraAllowZeroQualifier = .{ .token = it.index },
|
||||
.ExtraAllowZeroQualifier = .{ .token = it.index - 1 },
|
||||
});
|
||||
return error.ParseError;
|
||||
continue;
|
||||
}
|
||||
slice_type.allowzero_token = allowzero_token;
|
||||
continue;
|
||||
@ -2749,7 +2897,19 @@ fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
|
||||
var list = L.init(arena);
|
||||
while (try nodeParseFn(arena, it, tree)) |node| {
|
||||
try list.push(node);
|
||||
if (eatToken(it, .Comma) == null) break;
|
||||
|
||||
switch (it.peek().?.id) {
|
||||
.Comma => _ = nextToken(it),
|
||||
// all possible delimiters
|
||||
.Colon, .RParen, .RBrace, .RBracket => break,
|
||||
else => {
|
||||
// this is likely just a missing comma,
|
||||
// continue parsing this list and give an error
|
||||
try tree.errors.push(.{
|
||||
.ExpectedToken = .{ .token = it.index, .expected_id = .Comma },
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@ -2759,7 +2919,17 @@ fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) {
|
||||
fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
|
||||
return struct {
|
||||
pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
|
||||
const op_token = eatToken(it, token) orelse return null;
|
||||
const op_token = if (token == .Keyword_and) switch (it.peek().?.id) {
|
||||
.Keyword_and => nextToken(it).index,
|
||||
.Invalid_ampersands => blk: {
|
||||
try tree.errors.push(.{
|
||||
.InvalidAnd = .{ .token = it.index },
|
||||
});
|
||||
break :blk nextToken(it).index;
|
||||
},
|
||||
else => return null,
|
||||
} else eatToken(it, token) orelse return null;
|
||||
|
||||
const node = try arena.create(Node.InfixOp);
|
||||
node.* = .{
|
||||
.op_token = op_token,
|
||||
@ -2780,7 +2950,13 @@ fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
|
||||
try tree.errors.push(.{
|
||||
.ExpectedParamList = .{ .token = it.index },
|
||||
});
|
||||
return error.ParseError;
|
||||
|
||||
// lets pretend this was an identifier so we can continue parsing
|
||||
const node = try arena.create(Node.Identifier);
|
||||
node.* = .{
|
||||
.token = token,
|
||||
};
|
||||
return &node.base;
|
||||
};
|
||||
const node = try arena.create(Node.BuiltinCall);
|
||||
node.* = .{
|
||||
@ -2896,8 +3072,10 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
.doc_comments = null,
|
||||
.visib_token = null,
|
||||
.use_token = token,
|
||||
.expr = undefined, // set by caller
|
||||
.semicolon_token = undefined, // set by caller
|
||||
.expr = try expectNode(arena, it, tree, parseExpr, .{
|
||||
.ExpectedExpr = .{ .token = it.index },
|
||||
}),
|
||||
.semicolon_token = try expectToken(it, tree, .Semicolon),
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
@ -3077,6 +3255,8 @@ fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {
|
||||
try tree.errors.push(.{
|
||||
.ExpectedToken = .{ .token = token.index, .expected_id = id },
|
||||
});
|
||||
// go back so that we can recover properly
|
||||
putBackToken(it, token.index);
|
||||
return error.ParseError;
|
||||
}
|
||||
return token.index;
|
||||
|
@ -1,3 +1,153 @@
|
||||
test "recovery: top level" {
|
||||
try testError(
|
||||
\\test "" {inline}
|
||||
\\test "" {inline}
|
||||
, &[_]Error{
|
||||
.ExpectedInlinable,
|
||||
.ExpectedInlinable,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: block statements" {
|
||||
try testError(
|
||||
\\test "" {
|
||||
\\ foo + +;
|
||||
\\ inline;
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.InvalidToken,
|
||||
.ExpectedInlinable,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: missing comma" {
|
||||
try testError(
|
||||
\\test "" {
|
||||
\\ switch (foo) {
|
||||
\\ 2 => {}
|
||||
\\ 3 => {}
|
||||
\\ else => {
|
||||
\\ foo && bar +;
|
||||
\\ }
|
||||
\\ }
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.ExpectedToken,
|
||||
.ExpectedToken,
|
||||
.InvalidAnd,
|
||||
.InvalidToken,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: extra qualifier" {
|
||||
try testError(
|
||||
\\const a: *const const u8;
|
||||
\\test ""
|
||||
, &[_]Error{
|
||||
.ExtraConstQualifier,
|
||||
.ExpectedLBrace,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: missing return type" {
|
||||
try testError(
|
||||
\\fn foo() {
|
||||
\\ a && b;
|
||||
\\}
|
||||
\\test ""
|
||||
, &[_]Error{
|
||||
.ExpectedReturnType,
|
||||
.InvalidAnd,
|
||||
.ExpectedLBrace,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: continue after invalid decl" {
|
||||
try testError(
|
||||
\\fn foo {
|
||||
\\ inline;
|
||||
\\}
|
||||
\\pub test "" {
|
||||
\\ async a && b;
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.ExpectedToken,
|
||||
.ExpectedPubItem,
|
||||
.ExpectedParamList,
|
||||
.InvalidAnd,
|
||||
});
|
||||
try testError(
|
||||
\\threadlocal test "" {
|
||||
\\ @a && b;
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.ExpectedVarDecl,
|
||||
.ExpectedParamList,
|
||||
.InvalidAnd,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: invalid extern/inline" {
|
||||
try testError(
|
||||
\\inline test "" { a && b; }
|
||||
, &[_]Error{
|
||||
.ExpectedFn,
|
||||
.InvalidAnd,
|
||||
});
|
||||
try testError(
|
||||
\\extern "" test "" { a && b; }
|
||||
, &[_]Error{
|
||||
.ExpectedVarDeclOrFn,
|
||||
.InvalidAnd,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: missing semicolon" {
|
||||
try testError(
|
||||
\\test "" {
|
||||
\\ comptime a && b
|
||||
\\ c && d
|
||||
\\ @foo
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.InvalidAnd,
|
||||
.ExpectedToken,
|
||||
.InvalidAnd,
|
||||
.ExpectedToken,
|
||||
.ExpectedParamList,
|
||||
.ExpectedToken,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: invalid container members" {
|
||||
try testError(
|
||||
\\usingnamespace;
|
||||
\\foo+
|
||||
\\bar@,
|
||||
\\while (a == 2) { test "" {}}
|
||||
\\test "" {
|
||||
\\ a && b
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.ExpectedExpr,
|
||||
.ExpectedToken,
|
||||
.ExpectedToken,
|
||||
.ExpectedContainerMembers,
|
||||
.InvalidAnd,
|
||||
.ExpectedToken,
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: invalid parameter" {
|
||||
try testError(
|
||||
\\fn main() void {
|
||||
\\ a(comptime T: type)
|
||||
\\}
|
||||
, &[_]Error{
|
||||
.ExpectedToken,
|
||||
});
|
||||
}
|
||||
|
||||
test "zig fmt: top-level fields" {
|
||||
try testCanonical(
|
||||
\\a: did_you_know,
|
||||
@ -19,7 +169,9 @@ test "zig fmt: decl between fields" {
|
||||
\\ const baz1 = 2;
|
||||
\\ b: usize,
|
||||
\\};
|
||||
);
|
||||
, &[_]Error{
|
||||
.DeclBetweenFields,
|
||||
});
|
||||
}
|
||||
|
||||
test "zig fmt: errdefer with payload" {
|
||||
@ -35,10 +187,10 @@ test "zig fmt: errdefer with payload" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: noasync block" {
|
||||
test "zig fmt: nosuspend block" {
|
||||
try testCanonical(
|
||||
\\pub fn main() anyerror!void {
|
||||
\\ noasync {
|
||||
\\ nosuspend {
|
||||
\\ var foo: Foo = .{ .bar = 42 };
|
||||
\\ }
|
||||
\\}
|
||||
@ -46,10 +198,10 @@ test "zig fmt: noasync block" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: noasync await" {
|
||||
test "zig fmt: nosuspend await" {
|
||||
try testCanonical(
|
||||
\\fn foo() void {
|
||||
\\ x = noasync await y;
|
||||
\\ x = nosuspend await y;
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
@ -123,22 +275,6 @@ test "zig fmt: trailing comma in fn parameter list" {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Remove nakedcc/stdcallcc once zig 0.6.0 is released. See https://github.com/ziglang/zig/pull/3977
|
||||
test "zig fmt: convert extern/nakedcc/stdcallcc into callconv(...)" {
|
||||
try testTransform(
|
||||
\\nakedcc fn foo1() void {}
|
||||
\\stdcallcc fn foo2() void {}
|
||||
\\extern fn foo3() void {}
|
||||
\\extern "mylib" fn foo4() void {}
|
||||
,
|
||||
\\fn foo1() callconv(.Naked) void {}
|
||||
\\fn foo2() callconv(.Stdcall) void {}
|
||||
\\fn foo3() callconv(.C) void {}
|
||||
\\fn foo4() callconv(.C) void {}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comptime struct field" {
|
||||
try testCanonical(
|
||||
\\const Foo = struct {
|
||||
@ -252,10 +388,10 @@ test "zig fmt: anon list literal syntax" {
|
||||
test "zig fmt: async function" {
|
||||
try testCanonical(
|
||||
\\pub const Server = struct {
|
||||
\\ handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
|
||||
\\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void,
|
||||
\\};
|
||||
\\test "hi" {
|
||||
\\ var ptr = @ptrCast(async fn (i32) void, other);
|
||||
\\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other);
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
@ -451,15 +587,6 @@ test "zig fmt: aligned struct field" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: preserve space between async fn definitions" {
|
||||
try testCanonical(
|
||||
\\async fn a() void {}
|
||||
\\
|
||||
\\async fn b() void {}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comment to disable/enable zig fmt first" {
|
||||
try testCanonical(
|
||||
\\// Test trailing comma syntax
|
||||
@ -1515,7 +1642,7 @@ test "zig fmt: line comments in struct initializer" {
|
||||
|
||||
test "zig fmt: first line comment in struct initializer" {
|
||||
try testCanonical(
|
||||
\\pub async fn acquire(self: *Self) HeldLock {
|
||||
\\pub fn acquire(self: *Self) HeldLock {
|
||||
\\ return HeldLock{
|
||||
\\ // guaranteed allocation elision
|
||||
\\ .held = self.lock.acquire(),
|
||||
@ -2477,8 +2604,7 @@ test "zig fmt: fn type" {
|
||||
\\}
|
||||
\\
|
||||
\\const a: fn (u8) u8 = undefined;
|
||||
\\const b: extern fn (u8) u8 = undefined;
|
||||
\\const c: fn (u8) callconv(.Naked) u8 = undefined;
|
||||
\\const b: fn (u8) callconv(.Naked) u8 = undefined;
|
||||
\\const ap: fn (u8) u8 = a;
|
||||
\\
|
||||
);
|
||||
@ -2500,7 +2626,7 @@ test "zig fmt: inline asm" {
|
||||
|
||||
test "zig fmt: async functions" {
|
||||
try testCanonical(
|
||||
\\async fn simpleAsyncFn() void {
|
||||
\\fn simpleAsyncFn() void {
|
||||
\\ const a = async a.b();
|
||||
\\ x += 1;
|
||||
\\ suspend;
|
||||
@ -2519,9 +2645,9 @@ test "zig fmt: async functions" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: noasync" {
|
||||
test "zig fmt: nosuspend" {
|
||||
try testCanonical(
|
||||
\\const a = noasync foo();
|
||||
\\const a = nosuspend foo();
|
||||
\\
|
||||
);
|
||||
}
|
||||
@ -2854,7 +2980,10 @@ test "zig fmt: extern without container keyword returns error" {
|
||||
try testError(
|
||||
\\const container = extern {};
|
||||
\\
|
||||
);
|
||||
, &[_]Error{
|
||||
.ExpectedExpr,
|
||||
.ExpectedVarDeclOrFn,
|
||||
});
|
||||
}
|
||||
|
||||
test "zig fmt: integer literals with underscore separators" {
|
||||
@ -2926,6 +3055,40 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: noasync to nosuspend" {
|
||||
// TODO: remove this
|
||||
try testTransform(
|
||||
\\pub fn main() void {
|
||||
\\ noasync call();
|
||||
\\}
|
||||
,
|
||||
\\pub fn main() void {
|
||||
\\ nosuspend call();
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: convert async fn into callconv(.Async)" {
|
||||
try testTransform(
|
||||
\\async fn foo() void {}
|
||||
,
|
||||
\\fn foo() callconv(.Async) void {}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: convert extern fn proto into callconv(.C)" {
|
||||
try testTransform(
|
||||
\\extern fn foo0() void {}
|
||||
\\const foo1 = extern fn () void;
|
||||
,
|
||||
\\extern fn foo0() void {}
|
||||
\\const foo1 = fn () callconv(.C) void;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const warn = std.debug.warn;
|
||||
@ -2972,7 +3135,6 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
|
||||
anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree);
|
||||
return buffer.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn testTransform(source: []const u8, expected_source: []const u8) !void {
|
||||
const needed_alloc_count = x: {
|
||||
// Try it once with unlimited memory, make sure it works
|
||||
@ -3020,14 +3182,20 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn testCanonical(source: []const u8) !void {
|
||||
return testTransform(source, source);
|
||||
}
|
||||
|
||||
fn testError(source: []const u8) !void {
|
||||
const Error = @TagType(std.zig.ast.Error);
|
||||
|
||||
fn testError(source: []const u8, expected_errors: []const Error) !void {
|
||||
const tree = try std.zig.parse(std.testing.allocator, source);
|
||||
defer tree.deinit();
|
||||
|
||||
std.testing.expect(tree.errors.len != 0);
|
||||
std.testing.expect(tree.errors.len == expected_errors.len);
|
||||
for (expected_errors) |expected, i| {
|
||||
const err = tree.errors.at(i);
|
||||
|
||||
std.testing.expect(expected == err.*);
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ pub const Error = error{
|
||||
|
||||
/// Returns whether anything changed
|
||||
pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {
|
||||
// cannot render an invalid tree
|
||||
std.debug.assert(tree.errors.len == 0);
|
||||
|
||||
// make a passthrough stream that checks whether something changed
|
||||
const MyStream = struct {
|
||||
const MyStream = @This();
|
||||
@ -391,11 +394,15 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space);
|
||||
return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
|
||||
},
|
||||
.Noasync => {
|
||||
const noasync_node = @fieldParentPtr(ast.Node.Noasync, "base", base);
|
||||
|
||||
try renderToken(tree, stream, noasync_node.noasync_token, indent, start_col, Space.Space);
|
||||
return renderExpression(allocator, stream, tree, indent, start_col, noasync_node.expr, space);
|
||||
.Nosuspend => {
|
||||
const nosuspend_node = @fieldParentPtr(ast.Node.Nosuspend, "base", base);
|
||||
if (mem.eql(u8, tree.tokenSlice(nosuspend_node.nosuspend_token), "noasync")) {
|
||||
// TODO: remove this
|
||||
try stream.writeAll("nosuspend ");
|
||||
} else {
|
||||
try renderToken(tree, stream, nosuspend_node.nosuspend_token, indent, start_col, Space.Space);
|
||||
}
|
||||
return renderExpression(allocator, stream, tree, indent, start_col, nosuspend_node.expr, space);
|
||||
},
|
||||
|
||||
.Suspend => {
|
||||
@ -1409,32 +1416,15 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
|
||||
}
|
||||
|
||||
// Some extra machinery is needed to rewrite the old-style cc
|
||||
// notation to the new callconv one
|
||||
var cc_rewrite_str: ?[*:0]const u8 = null;
|
||||
if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
|
||||
const tok = tree.tokens.at(extern_export_inline_token);
|
||||
if (tok.id != .Keyword_extern or fn_proto.body_node == null) {
|
||||
try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export
|
||||
} else {
|
||||
cc_rewrite_str = ".C";
|
||||
fn_proto.lib_name = null;
|
||||
}
|
||||
if (!fn_proto.is_extern_prototype)
|
||||
try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
|
||||
}
|
||||
|
||||
if (fn_proto.lib_name) |lib_name| {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
|
||||
}
|
||||
|
||||
if (fn_proto.cc_token) |cc_token| {
|
||||
var str = tree.tokenSlicePtr(tree.tokens.at(cc_token));
|
||||
if (mem.eql(u8, str, "stdcallcc")) {
|
||||
cc_rewrite_str = ".Stdcall";
|
||||
} else if (mem.eql(u8, str, "nakedcc")) {
|
||||
cc_rewrite_str = ".Naked";
|
||||
} else try renderToken(tree, stream, cc_token, indent, start_col, Space.Space); // stdcallcc
|
||||
}
|
||||
|
||||
const lparen = if (fn_proto.name_token) |name_token| blk: {
|
||||
try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
|
||||
try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
|
||||
@ -1457,6 +1447,7 @@ fn renderExpression(
|
||||
else switch (fn_proto.return_type) {
|
||||
.Explicit => |node| node.firstToken(),
|
||||
.InferErrorSet => |node| tree.prevToken(node.firstToken()),
|
||||
.Invalid => unreachable,
|
||||
});
|
||||
assert(tree.tokens.at(rparen).id == .RParen);
|
||||
|
||||
@ -1524,20 +1515,21 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
|
||||
try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
|
||||
} else if (cc_rewrite_str) |str| {
|
||||
try stream.writeAll("callconv(");
|
||||
try stream.writeAll(mem.spanZ(str));
|
||||
try stream.writeAll(") ");
|
||||
} else if (fn_proto.is_extern_prototype) {
|
||||
try stream.writeAll("callconv(.C) ");
|
||||
} else if (fn_proto.is_async) {
|
||||
try stream.writeAll("callconv(.Async) ");
|
||||
}
|
||||
|
||||
switch (fn_proto.return_type) {
|
||||
ast.Node.FnProto.ReturnType.Explicit => |node| {
|
||||
.Explicit => |node| {
|
||||
return renderExpression(allocator, stream, tree, indent, start_col, node, space);
|
||||
},
|
||||
ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
|
||||
.InferErrorSet => |node| {
|
||||
try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, start_col, Space.None); // !
|
||||
return renderExpression(allocator, stream, tree, indent, start_col, node, space);
|
||||
},
|
||||
.Invalid => unreachable,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -837,6 +837,7 @@ pub const NativeTargetInfo = struct {
|
||||
error.BrokenPipe => return error.UnableToReadElfFile,
|
||||
error.Unseekable => return error.UnableToReadElfFile,
|
||||
error.ConnectionResetByPeer => return error.UnableToReadElfFile,
|
||||
error.ConnectionTimedOut => return error.UnableToReadElfFile,
|
||||
error.Unexpected => return error.Unexpected,
|
||||
error.InputOutput => return error.FileSystem,
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ pub fn version_from_build(build: []const u8) !std.builtin.Version {
|
||||
zend += 1;
|
||||
}
|
||||
if (zend == yindex + 1) return error.InvalidVersion;
|
||||
const z = std.fmt.parseUnsigned(u16, build[yindex + 1..zend], 10) catch return error.InvalidVersion;
|
||||
const z = std.fmt.parseUnsigned(u16, build[yindex + 1 .. zend], 10) catch return error.InvalidVersion;
|
||||
|
||||
result.patch = switch (result.minor) {
|
||||
// TODO: compiler complains without explicit @as() coercion
|
||||
@ -97,7 +97,9 @@ pub fn version_from_build(build: []const u8) !std.builtin.Version {
|
||||
4 => @as(u32, switch (y) { // Tiger: 10.4
|
||||
'A' => 0,
|
||||
'B' => 1,
|
||||
'C', 'E', => 2,
|
||||
'C',
|
||||
'E',
|
||||
=> 2,
|
||||
'F' => 3,
|
||||
'G' => @as(u32, block: {
|
||||
if (z >= 1454) break :block 5;
|
||||
@ -105,7 +107,10 @@ pub fn version_from_build(build: []const u8) !std.builtin.Version {
|
||||
}),
|
||||
'H' => 5,
|
||||
'I' => 6,
|
||||
'J', 'K', 'N', => 7,
|
||||
'J',
|
||||
'K',
|
||||
'N',
|
||||
=> 7,
|
||||
'L' => 8,
|
||||
'P' => 9,
|
||||
'R' => 10,
|
||||
@ -438,7 +443,7 @@ test "version_from_build" {
|
||||
for (known) |pair| {
|
||||
var buf: [32]u8 = undefined;
|
||||
const ver = try version_from_build(pair[0]);
|
||||
const sver = try std.fmt.bufPrint(buf[0..], "{}.{}.{}", .{ver.major, ver.minor, ver.patch});
|
||||
const sver = try std.fmt.bufPrint(buf[0..], "{}.{}.{}", .{ ver.major, ver.minor, ver.patch });
|
||||
std.testing.expect(std.mem.eql(u8, sver, pair[1]));
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -781,7 +781,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigCla
|
||||
pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;
|
||||
pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
|
||||
pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;
|
||||
pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool;
|
||||
pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?fn (?*c_void, *const struct_ZigClangDecl) callconv(.C) bool) bool;
|
||||
pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;
|
||||
pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClangTagDecl) bool;
|
||||
pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl;
|
||||
|
@ -589,6 +589,7 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [
|
||||
error.EndOfStream => return .EndOfFile,
|
||||
error.IsDir => return .IsDir,
|
||||
error.ConnectionResetByPeer => unreachable,
|
||||
error.ConnectionTimedOut => unreachable,
|
||||
error.OutOfMemory => return .OutOfMemory,
|
||||
error.Unseekable => unreachable,
|
||||
error.SharingViolation => return .SharingViolation,
|
||||
|
@ -668,6 +668,31 @@ fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const ZigClangTypedefNameDe
|
||||
return transCreateNodeIdentifier(c, builtin_name);
|
||||
}
|
||||
|
||||
fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {
|
||||
const table = [_][2][]const u8{
|
||||
.{ "uint8_t", "u8" },
|
||||
.{ "int8_t", "i8" },
|
||||
.{ "uint16_t", "u16" },
|
||||
.{ "int16_t", "i16" },
|
||||
.{ "uint32_t", "u32" },
|
||||
.{ "int32_t", "i32" },
|
||||
.{ "uint64_t", "u64" },
|
||||
.{ "int64_t", "i64" },
|
||||
.{ "intptr_t", "isize" },
|
||||
.{ "uintptr_t", "usize" },
|
||||
.{ "ssize_t", "isize" },
|
||||
.{ "size_t", "usize" },
|
||||
};
|
||||
|
||||
for (table) |entry| {
|
||||
if (mem.eql(u8, checked_name, entry[0])) {
|
||||
return entry[1];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_level_visit: bool) Error!?*ast.Node {
|
||||
if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv|
|
||||
return transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
|
||||
@ -678,54 +703,36 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
|
||||
// TODO https://github.com/ziglang/zig/issues/3756
|
||||
// TODO https://github.com/ziglang/zig/issues/1802
|
||||
const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name;
|
||||
|
||||
if (mem.eql(u8, checked_name, "uint8_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "u8")
|
||||
else if (mem.eql(u8, checked_name, "int8_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "i8")
|
||||
else if (mem.eql(u8, checked_name, "uint16_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "u16")
|
||||
else if (mem.eql(u8, checked_name, "int16_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "i16")
|
||||
else if (mem.eql(u8, checked_name, "uint32_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "u32")
|
||||
else if (mem.eql(u8, checked_name, "int32_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "i32")
|
||||
else if (mem.eql(u8, checked_name, "uint64_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "u64")
|
||||
else if (mem.eql(u8, checked_name, "int64_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "i64")
|
||||
else if (mem.eql(u8, checked_name, "intptr_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "isize")
|
||||
else if (mem.eql(u8, checked_name, "uintptr_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "usize")
|
||||
else if (mem.eql(u8, checked_name, "ssize_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "isize")
|
||||
else if (mem.eql(u8, checked_name, "size_t"))
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, "usize");
|
||||
if (checkForBuiltinTypedef(checked_name)) |builtin| {
|
||||
return transTypeDefAsBuiltin(c, typedef_decl, builtin);
|
||||
}
|
||||
|
||||
if (!top_level_visit) {
|
||||
return transCreateNodeIdentifier(c, checked_name);
|
||||
}
|
||||
|
||||
_ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);
|
||||
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
|
||||
const const_tok = try appendToken(c, .Keyword_const, "const");
|
||||
const node = try transCreateNodeVarDecl(c, true, true, checked_name);
|
||||
node.eq_token = try appendToken(c, .Equal, "=");
|
||||
const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
|
||||
try addTopLevelDecl(c, checked_name, &node.base);
|
||||
return transCreateNodeIdentifier(c, checked_name);
|
||||
}
|
||||
|
||||
fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedefNameDecl, toplevel: bool, checked_name: []const u8) Error!?*ast.Node.VarDecl {
|
||||
const node = try transCreateNodeVarDecl(rp.c, toplevel, true, checked_name);
|
||||
node.eq_token = try appendToken(rp.c, .Equal, "=");
|
||||
|
||||
const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
|
||||
const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
|
||||
node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try failDecl(c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
|
||||
try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
|
||||
return null;
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
};
|
||||
node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
||||
try addTopLevelDecl(c, checked_name, &node.base);
|
||||
return transCreateNodeIdentifier(c, checked_name);
|
||||
|
||||
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
|
||||
return node;
|
||||
}
|
||||
|
||||
fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
|
||||
@ -1394,6 +1401,26 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
|
||||
node.semicolon_token = try appendToken(c, .Semicolon, ";");
|
||||
try block_scope.block_node.statements.push(&node.base);
|
||||
},
|
||||
.Typedef => {
|
||||
const typedef_decl = @ptrCast(*const ZigClangTypedefNameDecl, it[0]);
|
||||
const name = try c.str(ZigClangNamedDecl_getName_bytes_begin(
|
||||
@ptrCast(*const ZigClangNamedDecl, typedef_decl),
|
||||
));
|
||||
|
||||
const underlying_qual = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
|
||||
const underlying_type = ZigClangQualType_getTypePtr(underlying_qual);
|
||||
|
||||
const mangled_name = try block_scope.makeMangledName(c, name);
|
||||
if (checkForBuiltinTypedef(name)) |builtin| {
|
||||
try block_scope.variables.push(.{
|
||||
.alias = builtin,
|
||||
.name = mangled_name,
|
||||
});
|
||||
} else {
|
||||
const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse return error.UnsupportedTranslation;
|
||||
try block_scope.block_node.statements.push(&node.base);
|
||||
}
|
||||
},
|
||||
else => |kind| return revertAndWarn(
|
||||
rp,
|
||||
error.UnsupportedTranslation,
|
||||
@ -4094,7 +4121,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
|
||||
.return_type = proto_alias.return_type,
|
||||
.var_args_token = null,
|
||||
.extern_export_inline_token = inline_tok,
|
||||
.cc_token = null,
|
||||
.body_node = null,
|
||||
.lib_name = null,
|
||||
.align_expr = null,
|
||||
@ -4753,7 +4779,6 @@ fn finishTransFnProto(
|
||||
.return_type = .{ .Explicit = return_type_node },
|
||||
.var_args_token = null, // TODO this field is broken in the AST data model
|
||||
.extern_export_inline_token = extern_export_inline_tok,
|
||||
.cc_token = null,
|
||||
.body_node = null,
|
||||
.lib_name = null,
|
||||
.align_expr = align_expr,
|
||||
@ -5119,7 +5144,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
.return_type = .{ .Explicit = &type_of.base },
|
||||
.doc_comments = null,
|
||||
.var_args_token = null,
|
||||
.cc_token = null,
|
||||
.body_node = null,
|
||||
.lib_name = null,
|
||||
.align_expr = null,
|
||||
|
@ -283,7 +283,7 @@ pub const Inst = struct {
|
||||
comptime_int,
|
||||
comptime_float,
|
||||
|
||||
fn toType(self: BuiltinType) Type {
|
||||
pub fn toType(self: BuiltinType) Type {
|
||||
return switch (self) {
|
||||
.isize => Type.initTag(.isize),
|
||||
.usize => Type.initTag(.usize),
|
||||
|
@ -672,7 +672,7 @@ enum NodeType {
|
||||
NodeTypeSwitchProng,
|
||||
NodeTypeSwitchRange,
|
||||
NodeTypeCompTime,
|
||||
NodeTypeNoAsync,
|
||||
NodeTypeNoSuspend,
|
||||
NodeTypeBreak,
|
||||
NodeTypeContinue,
|
||||
NodeTypeAsmExpr,
|
||||
@ -718,7 +718,6 @@ struct AstNodeFnProto {
|
||||
Buf doc_comments;
|
||||
|
||||
FnInline fn_inline;
|
||||
bool is_async;
|
||||
|
||||
VisibMod visib_mod;
|
||||
bool auto_err_set;
|
||||
@ -862,7 +861,7 @@ enum CallModifier {
|
||||
CallModifierAsync,
|
||||
CallModifierNeverTail,
|
||||
CallModifierNeverInline,
|
||||
CallModifierNoAsync,
|
||||
CallModifierNoSuspend,
|
||||
CallModifierAlwaysTail,
|
||||
CallModifierAlwaysInline,
|
||||
CallModifierCompileTime,
|
||||
@ -1014,7 +1013,7 @@ struct AstNodeCompTime {
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct AstNodeNoAsync {
|
||||
struct AstNodeNoSuspend {
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
@ -1225,7 +1224,7 @@ struct AstNode {
|
||||
AstNodeSwitchProng switch_prong;
|
||||
AstNodeSwitchRange switch_range;
|
||||
AstNodeCompTime comptime_expr;
|
||||
AstNodeNoAsync noasync_expr;
|
||||
AstNodeNoSuspend nosuspend_expr;
|
||||
AstNodeAsmExpr asm_expr;
|
||||
AstNodeFieldAccessExpr field_access_expr;
|
||||
AstNodePtrDerefExpr ptr_deref_expr;
|
||||
@ -1858,7 +1857,7 @@ enum PanicMsgId {
|
||||
PanicMsgIdResumedAnAwaitingFn,
|
||||
PanicMsgIdFrameTooSmall,
|
||||
PanicMsgIdResumedFnPendingAwait,
|
||||
PanicMsgIdBadNoAsyncCall,
|
||||
PanicMsgIdBadNoSuspendCall,
|
||||
PanicMsgIdResumeNotSuspendedFn,
|
||||
PanicMsgIdBadSentinel,
|
||||
PanicMsgIdShxTooBigRhs,
|
||||
@ -2376,7 +2375,7 @@ enum ScopeId {
|
||||
ScopeIdRuntime,
|
||||
ScopeIdTypeOf,
|
||||
ScopeIdExpr,
|
||||
ScopeIdNoAsync,
|
||||
ScopeIdNoSuspend,
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
@ -2510,9 +2509,9 @@ struct ScopeCompTime {
|
||||
Scope base;
|
||||
};
|
||||
|
||||
// This scope is created for a noasync expression.
|
||||
// NodeTypeNoAsync
|
||||
struct ScopeNoAsync {
|
||||
// This scope is created for a nosuspend expression.
|
||||
// NodeTypeNoSuspend
|
||||
struct ScopeNoSuspend {
|
||||
Scope base;
|
||||
};
|
||||
|
||||
@ -4488,7 +4487,7 @@ struct IrInstSrcAwait {
|
||||
|
||||
IrInstSrc *frame;
|
||||
ResultLoc *result_loc;
|
||||
bool is_noasync;
|
||||
bool is_nosuspend;
|
||||
};
|
||||
|
||||
struct IrInstGenAwait {
|
||||
@ -4497,7 +4496,7 @@ struct IrInstGenAwait {
|
||||
IrInstGen *frame;
|
||||
IrInstGen *result_loc;
|
||||
ZigFn *target_fn;
|
||||
bool is_noasync;
|
||||
bool is_nosuspend;
|
||||
};
|
||||
|
||||
struct IrInstSrcResume {
|
||||
|
@ -106,7 +106,7 @@ static ScopeExpr *find_expr_scope(Scope *scope) {
|
||||
case ScopeIdDecls:
|
||||
case ScopeIdFnDef:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdNoAsync:
|
||||
case ScopeIdNoSuspend:
|
||||
case ScopeIdVarDecl:
|
||||
case ScopeIdCImport:
|
||||
case ScopeIdSuspend:
|
||||
@ -227,9 +227,9 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
|
||||
return &scope->base;
|
||||
}
|
||||
|
||||
Scope *create_noasync_scope(CodeGen *g, AstNode *node, Scope *parent) {
|
||||
ScopeNoAsync *scope = heap::c_allocator.create<ScopeNoAsync>();
|
||||
init_scope(g, &scope->base, ScopeIdNoAsync, node, parent);
|
||||
Scope *create_nosuspend_scope(CodeGen *g, AstNode *node, Scope *parent) {
|
||||
ScopeNoSuspend *scope = heap::c_allocator.create<ScopeNoSuspend>();
|
||||
init_scope(g, &scope->base, ScopeIdNoSuspend, node, parent);
|
||||
return &scope->base;
|
||||
}
|
||||
|
||||
@ -1528,8 +1528,6 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
}
|
||||
|
||||
CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) {
|
||||
if (fn_proto->is_async)
|
||||
return CallingConventionAsync;
|
||||
// Compatible with the C ABI
|
||||
if (fn_proto->is_extern || fn_proto->is_export)
|
||||
return CallingConventionC;
|
||||
@ -3771,7 +3769,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeCompTime:
|
||||
preview_comptime_decl(g, node, decls_scope);
|
||||
break;
|
||||
case NodeTypeNoAsync:
|
||||
case NodeTypeNoSuspend:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeDefer:
|
||||
@ -4689,7 +4687,7 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
|
||||
static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node,
|
||||
bool must_not_be_async, CallModifier modifier)
|
||||
{
|
||||
if (modifier == CallModifierNoAsync)
|
||||
if (modifier == CallModifierNoSuspend)
|
||||
return ErrorNone;
|
||||
bool callee_is_async = false;
|
||||
switch (callee->type_entry->data.fn.fn_type_id.cc) {
|
||||
@ -4812,7 +4810,7 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
|
||||
}
|
||||
for (size_t i = 0; i < fn->await_list.length; i += 1) {
|
||||
IrInstGenAwait *await = fn->await_list.at(i);
|
||||
if (await->is_noasync) continue;
|
||||
if (await->is_nosuspend) continue;
|
||||
switch (analyze_callee_async(g, fn, await->target_fn, await->base.base.source_node, must_not_be_async,
|
||||
CallModifierNone))
|
||||
{
|
||||
@ -6239,7 +6237,7 @@ static void mark_suspension_point(Scope *scope) {
|
||||
case ScopeIdDecls:
|
||||
case ScopeIdFnDef:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdNoAsync:
|
||||
case ScopeIdNoSuspend:
|
||||
case ScopeIdCImport:
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdTypeOf:
|
||||
@ -6472,7 +6470,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
||||
// The funtion call result of foo() must be spilled.
|
||||
for (size_t i = 0; i < fn->await_list.length; i += 1) {
|
||||
IrInstGenAwait *await = fn->await_list.at(i);
|
||||
if (await->is_noasync) {
|
||||
if (await->is_nosuspend) {
|
||||
continue;
|
||||
}
|
||||
if (await->base.value->special != ConstValSpecialRuntime) {
|
||||
|
@ -125,7 +125,7 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
|
||||
Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
Scope *create_noasync_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
Scope *create_nosuspend_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstSrc *is_comptime);
|
||||
Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
|
@ -220,8 +220,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "SwitchRange";
|
||||
case NodeTypeCompTime:
|
||||
return "CompTime";
|
||||
case NodeTypeNoAsync:
|
||||
return "NoAsync";
|
||||
case NodeTypeNoSuspend:
|
||||
return "NoSuspend";
|
||||
case NodeTypeBreak:
|
||||
return "Break";
|
||||
case NodeTypeContinue:
|
||||
@ -709,8 +709,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
switch (node->data.fn_call_expr.modifier) {
|
||||
case CallModifierNone:
|
||||
break;
|
||||
case CallModifierNoAsync:
|
||||
fprintf(ar->f, "noasync ");
|
||||
case CallModifierNoSuspend:
|
||||
fprintf(ar->f, "nosuspend ");
|
||||
break;
|
||||
case CallModifierAsync:
|
||||
fprintf(ar->f, "async ");
|
||||
@ -1093,10 +1093,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
render_node_grouped(ar, node->data.comptime_expr.expr);
|
||||
break;
|
||||
}
|
||||
case NodeTypeNoAsync:
|
||||
case NodeTypeNoSuspend:
|
||||
{
|
||||
fprintf(ar->f, "noasync ");
|
||||
render_node_grouped(ar, node->data.noasync_expr.expr);
|
||||
fprintf(ar->f, "nosuspend ");
|
||||
render_node_grouped(ar, node->data.nosuspend_expr.expr);
|
||||
break;
|
||||
}
|
||||
case NodeTypeForExpr:
|
||||
|
@ -243,6 +243,7 @@ bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed) {
|
||||
}
|
||||
|
||||
if (!is_signed) {
|
||||
if(bn->is_negative) return false;
|
||||
size_t full_bits = bn->digit_count * 64;
|
||||
size_t leading_zero_count = bigint_clz(bn, full_bits);
|
||||
return bit_count >= full_bits - leading_zero_count;
|
||||
|
@ -685,7 +685,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
|
||||
case ScopeIdLoop:
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdNoAsync:
|
||||
case ScopeIdNoSuspend:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
case ScopeIdExpr:
|
||||
@ -966,8 +966,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
|
||||
return buf_create_from_str("frame too small");
|
||||
case PanicMsgIdResumedFnPendingAwait:
|
||||
return buf_create_from_str("resumed an async function which can only be awaited");
|
||||
case PanicMsgIdBadNoAsyncCall:
|
||||
return buf_create_from_str("async function called in noasync scope suspended");
|
||||
case PanicMsgIdBadNoSuspendCall:
|
||||
return buf_create_from_str("async function called in nosuspend scope suspended");
|
||||
case PanicMsgIdResumeNotSuspendedFn:
|
||||
return buf_create_from_str("resumed a non-suspended function");
|
||||
case PanicMsgIdBadSentinel:
|
||||
@ -4071,7 +4071,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
|
||||
case ScopeIdLoop:
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdNoAsync:
|
||||
case ScopeIdNoSuspend:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
case ScopeIdExpr:
|
||||
@ -4222,9 +4222,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
|
||||
// even if prefix_arg_err_ret_stack is true, let the async function do its own
|
||||
// initialization.
|
||||
} else {
|
||||
if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) {
|
||||
if (instruction->modifier == CallModifierNoSuspend && !fn_is_async(g->cur_fn)) {
|
||||
// Async function called as a normal function, and calling function is not async.
|
||||
// This is allowed because it was called with `noasync` which asserts that it will
|
||||
// This is allowed because it was called with `nosuspend` which asserts that it will
|
||||
// never suspend.
|
||||
awaiter_init_val = zero;
|
||||
} else {
|
||||
@ -4335,7 +4335,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
|
||||
case CallModifierCompileTime:
|
||||
zig_unreachable();
|
||||
case CallModifierNone:
|
||||
case CallModifierNoAsync:
|
||||
case CallModifierNoSuspend:
|
||||
case CallModifierAsync:
|
||||
call_attr = ZigLLVM_CallAttrAuto;
|
||||
break;
|
||||
@ -4411,7 +4411,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
|
||||
get_llvm_type(g, instruction->base.value->type), "");
|
||||
}
|
||||
return nullptr;
|
||||
} else if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) {
|
||||
} else if (instruction->modifier == CallModifierNoSuspend && !fn_is_async(g->cur_fn)) {
|
||||
gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
|
||||
|
||||
if (ir_want_runtime_safety(g, &instruction->base)) {
|
||||
@ -4422,13 +4422,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
|
||||
all_ones, LLVMAtomicOrderingRelease);
|
||||
LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, prev_val, all_ones, "");
|
||||
|
||||
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoAsyncPanic");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoAsyncOk");
|
||||
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoSuspendPanic");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoSuspendOk");
|
||||
LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block);
|
||||
|
||||
// The async function suspended, but this noasync call asserted it wouldn't.
|
||||
// The async function suspended, but this nosuspend call asserted it wouldn't.
|
||||
LLVMPositionBuilderAtEnd(g->builder, bad_block);
|
||||
gen_safety_crash(g, PanicMsgIdBadNoAsyncCall);
|
||||
gen_safety_crash(g, PanicMsgIdBadNoSuspendCall);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
}
|
||||
@ -6401,7 +6401,7 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutableGen *executable, IrI
|
||||
LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
|
||||
nullptr : ir_llvm_value(g, instruction->result_loc);
|
||||
|
||||
if (instruction->is_noasync ||
|
||||
if (instruction->is_nosuspend ||
|
||||
(instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn)))
|
||||
{
|
||||
return gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type,
|
||||
@ -7928,7 +7928,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
}
|
||||
|
||||
if (!is_async) {
|
||||
// allocate async frames for noasync calls & awaits to async functions
|
||||
// allocate async frames for nosuspend calls & awaits to async functions
|
||||
ZigType *largest_call_frame_type = nullptr;
|
||||
IrInstGen *all_calls_alloca = ir_create_alloca(g, &fn_table_entry->fndef_scope->base,
|
||||
fn_table_entry->body_node, fn_table_entry, g->builtin_types.entry_void, "@async_call_frame");
|
||||
@ -7938,7 +7938,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
continue;
|
||||
if (!fn_is_async(call->fn_entry))
|
||||
continue;
|
||||
if (call->modifier != CallModifierNoAsync)
|
||||
if (call->modifier != CallModifierNoSuspend)
|
||||
continue;
|
||||
if (call->frame_result_loc != nullptr)
|
||||
continue;
|
||||
|
97
src/ir.cpp
97
src/ir.cpp
@ -4846,12 +4846,12 @@ static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_ins
|
||||
}
|
||||
|
||||
static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstSrc *frame, ResultLoc *result_loc, bool is_noasync)
|
||||
IrInstSrc *frame, ResultLoc *result_loc, bool is_nosuspend)
|
||||
{
|
||||
IrInstSrcAwait *instruction = ir_build_instruction<IrInstSrcAwait>(irb, scope, source_node);
|
||||
instruction->frame = frame;
|
||||
instruction->result_loc = result_loc;
|
||||
instruction->is_noasync = is_noasync;
|
||||
instruction->is_nosuspend = is_nosuspend;
|
||||
|
||||
ir_ref_instruction(frame, irb->current_basic_block);
|
||||
|
||||
@ -4859,14 +4859,14 @@ static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *s
|
||||
}
|
||||
|
||||
static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruction,
|
||||
IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc, bool is_noasync)
|
||||
IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc, bool is_nosuspend)
|
||||
{
|
||||
IrInstGenAwait *instruction = ir_build_inst_gen<IrInstGenAwait>(&ira->new_irb,
|
||||
source_instruction->scope, source_instruction->source_node);
|
||||
instruction->base.value->type = result_type;
|
||||
instruction->frame = frame;
|
||||
instruction->result_loc = result_loc;
|
||||
instruction->is_noasync = is_noasync;
|
||||
instruction->is_nosuspend = is_nosuspend;
|
||||
|
||||
ir_ref_inst_gen(frame);
|
||||
if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
|
||||
@ -4982,7 +4982,7 @@ static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_
|
||||
case ScopeIdLoop:
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdNoAsync:
|
||||
case ScopeIdNoSuspend:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
case ScopeIdExpr:
|
||||
@ -5072,7 +5072,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope
|
||||
case ScopeIdLoop:
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdNoAsync:
|
||||
case ScopeIdNoSuspend:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
case ScopeIdExpr:
|
||||
@ -7335,10 +7335,10 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static ScopeNoAsync *get_scope_noasync(Scope *scope) {
|
||||
static ScopeNoSuspend *get_scope_nosuspend(Scope *scope) {
|
||||
while (scope) {
|
||||
if (scope->id == ScopeIdNoAsync)
|
||||
return (ScopeNoAsync *)scope;
|
||||
if (scope->id == ScopeIdNoSuspend)
|
||||
return (ScopeNoSuspend *)scope;
|
||||
if (scope->id == ScopeIdFnDef)
|
||||
return nullptr;
|
||||
|
||||
@ -7355,15 +7355,15 @@ static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node,
|
||||
if (node->data.fn_call_expr.modifier == CallModifierBuiltin)
|
||||
return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc);
|
||||
|
||||
bool is_noasync = get_scope_noasync(scope) != nullptr;
|
||||
bool is_nosuspend = get_scope_nosuspend(scope) != nullptr;
|
||||
CallModifier modifier = node->data.fn_call_expr.modifier;
|
||||
if (is_noasync) {
|
||||
if (is_nosuspend) {
|
||||
if (modifier == CallModifierAsync) {
|
||||
add_node_error(irb->codegen, node,
|
||||
buf_sprintf("async call in noasync scope"));
|
||||
buf_sprintf("async call in nosuspend scope"));
|
||||
return irb->codegen->invalid_inst_src;
|
||||
}
|
||||
modifier = CallModifierNoAsync;
|
||||
modifier = CallModifierNoSuspend;
|
||||
}
|
||||
|
||||
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
|
||||
@ -9222,10 +9222,10 @@ static IrInstSrc *ir_gen_comptime(IrBuilderSrc *irb, Scope *parent_scope, AstNod
|
||||
return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr);
|
||||
}
|
||||
|
||||
static IrInstSrc *ir_gen_noasync(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) {
|
||||
assert(node->type == NodeTypeNoAsync);
|
||||
static IrInstSrc *ir_gen_nosuspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) {
|
||||
assert(node->type == NodeTypeNoSuspend);
|
||||
|
||||
Scope *child_scope = create_noasync_scope(irb->codegen, node, parent_scope);
|
||||
Scope *child_scope = create_nosuspend_scope(irb->codegen, node, parent_scope);
|
||||
// purposefully pass null for result_loc and let EndExpr handle it
|
||||
return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr);
|
||||
}
|
||||
@ -9813,8 +9813,8 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod
|
||||
|
||||
static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeResume);
|
||||
if (get_scope_noasync(scope) != nullptr) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("resume in noasync scope"));
|
||||
if (get_scope_nosuspend(scope) != nullptr) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("resume in nosuspend scope"));
|
||||
return irb->codegen->invalid_inst_src;
|
||||
}
|
||||
|
||||
@ -9830,7 +9830,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
{
|
||||
assert(node->type == NodeTypeAwaitExpr);
|
||||
|
||||
bool is_noasync = get_scope_noasync(scope) != nullptr;
|
||||
bool is_nosuspend = get_scope_nosuspend(scope) != nullptr;
|
||||
|
||||
AstNode *expr_node = node->data.await_expr.expr;
|
||||
if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) {
|
||||
@ -9864,7 +9864,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
|
||||
if (target_inst == irb->codegen->invalid_inst_src)
|
||||
return irb->codegen->invalid_inst_src;
|
||||
|
||||
IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc, is_noasync);
|
||||
IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc, is_nosuspend);
|
||||
return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);
|
||||
}
|
||||
|
||||
@ -9876,8 +9876,8 @@ static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode
|
||||
add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
|
||||
return irb->codegen->invalid_inst_src;
|
||||
}
|
||||
if (get_scope_noasync(parent_scope) != nullptr) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("suspend in noasync scope"));
|
||||
if (get_scope_nosuspend(parent_scope) != nullptr) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("suspend in nosuspend scope"));
|
||||
return irb->codegen->invalid_inst_src;
|
||||
}
|
||||
|
||||
@ -10017,8 +10017,8 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope
|
||||
return ir_gen_switch_expr(irb, scope, node, lval, result_loc);
|
||||
case NodeTypeCompTime:
|
||||
return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc);
|
||||
case NodeTypeNoAsync:
|
||||
return ir_expr_wrap(irb, scope, ir_gen_noasync(irb, scope, node, lval), result_loc);
|
||||
case NodeTypeNoSuspend:
|
||||
return ir_expr_wrap(irb, scope, ir_gen_nosuspend(irb, scope, node, lval), result_loc);
|
||||
case NodeTypeErrorType:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc);
|
||||
case NodeTypeBreak:
|
||||
@ -10105,7 +10105,7 @@ static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *sco
|
||||
case NodeTypeIfOptional:
|
||||
case NodeTypeSwitchExpr:
|
||||
case NodeTypeCompTime:
|
||||
case NodeTypeNoAsync:
|
||||
case NodeTypeNoSuspend:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeBreak:
|
||||
case NodeTypeContinue:
|
||||
@ -12760,9 +12760,7 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInst *source_instr,
|
||||
const_val->type = new_type;
|
||||
break;
|
||||
case CastOpIntToFloat:
|
||||
{
|
||||
assert(new_type->id == ZigTypeIdFloat);
|
||||
|
||||
if (new_type->id == ZigTypeIdFloat) {
|
||||
BigFloat bigfloat;
|
||||
bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint);
|
||||
switch (new_type->data.floating.bit_count) {
|
||||
@ -12783,9 +12781,13 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInst *source_instr,
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
break;
|
||||
} else if (new_type->id == ZigTypeIdComptimeFloat) {
|
||||
bigfloat_init_bigint(&const_val->data.x_bigfloat, &other_val->data.x_bigint);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
break;
|
||||
case CastOpFloatToInt:
|
||||
float_init_bigint(&const_val->data.x_bigint, other_val);
|
||||
if (new_type->id == ZigTypeIdInt) {
|
||||
@ -19999,6 +20001,11 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
|
||||
if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
|
||||
return result_loc;
|
||||
}
|
||||
if (result_loc->value->type->data.pointer.is_const) {
|
||||
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
IrInstGen *dummy_value = ir_const(ira, source_instr, impl_fn_type_id->return_type);
|
||||
dummy_value->value->special = ConstValSpecialRuntime;
|
||||
IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr,
|
||||
@ -20025,7 +20032,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
|
||||
|
||||
if (impl_fn_type_id->cc == CallingConventionAsync &&
|
||||
parent_fn_entry->inferred_async_node == nullptr &&
|
||||
modifier != CallModifierNoAsync)
|
||||
modifier != CallModifierNoSuspend)
|
||||
{
|
||||
parent_fn_entry->inferred_async_node = fn_ref->base.source_node;
|
||||
parent_fn_entry->inferred_async_fn = impl_fn;
|
||||
@ -20123,7 +20130,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
|
||||
|
||||
if (fn_type_id->cc == CallingConventionAsync &&
|
||||
parent_fn_entry->inferred_async_node == nullptr &&
|
||||
modifier != CallModifierNoAsync)
|
||||
modifier != CallModifierNoSuspend)
|
||||
{
|
||||
parent_fn_entry->inferred_async_node = fn_ref->base.source_node;
|
||||
parent_fn_entry->inferred_async_fn = fn_entry;
|
||||
@ -20137,6 +20144,11 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
|
||||
if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
|
||||
return result_loc;
|
||||
}
|
||||
if (result_loc->value->type->data.pointer.is_const) {
|
||||
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
IrInstGen *dummy_value = ir_const(ira, source_instr, return_type);
|
||||
dummy_value->value->special = ConstValSpecialRuntime;
|
||||
IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr,
|
||||
@ -20233,7 +20245,7 @@ static IrInstGen *ir_analyze_call_extra(IrAnalyze *ira, IrInst* source_instr,
|
||||
case CallModifierNone:
|
||||
case CallModifierAlwaysInline:
|
||||
case CallModifierAlwaysTail:
|
||||
case CallModifierNoAsync:
|
||||
case CallModifierNoSuspend:
|
||||
modifier = CallModifierCompileTime;
|
||||
break;
|
||||
case CallModifierNeverInline:
|
||||
@ -21614,6 +21626,15 @@ static IrInstGen *ir_analyze_container_member_access_inner(IrAnalyze *ira,
|
||||
if (tld->resolution == TldResolutionResolving)
|
||||
return ir_error_dependency_loop(ira, source_instr);
|
||||
|
||||
if (tld->visib_mod == VisibModPrivate &&
|
||||
tld->import != get_scope_import(source_instr->scope))
|
||||
{
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr,
|
||||
buf_sprintf("'%s' is private", buf_ptr(field_name)));
|
||||
add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
TldFn *tld_fn = (TldFn *)tld;
|
||||
ZigFn *fn_entry = tld_fn->fn_entry;
|
||||
assert(fn_entry != nullptr);
|
||||
@ -21687,6 +21708,9 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_ins
|
||||
if (field->is_comptime) {
|
||||
IrInstGen *elem = ir_const(ira, source_instr, field_type);
|
||||
memoize_field_init_val(ira->codegen, struct_type, field);
|
||||
if(field->init_val != nullptr && type_is_invalid(field->init_val->type)){
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
copy_const_val(ira->codegen, elem->value, field->init_val);
|
||||
return ir_get_ref2(ira, source_instr, elem, field_type, true, false);
|
||||
}
|
||||
@ -25043,6 +25067,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
|
||||
inner_fields[3]->type = get_optional_type2(ira->codegen, struct_field->type_entry);
|
||||
if (inner_fields[3]->type == nullptr) return ErrorSemanticAnalyzeFail;
|
||||
memoize_field_init_val(ira->codegen, type_entry, struct_field);
|
||||
if(struct_field->init_val != nullptr && type_is_invalid(struct_field->init_val->type)){
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
set_optional_payload(inner_fields[3], struct_field->init_val);
|
||||
|
||||
ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
|
||||
@ -30277,7 +30304,7 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i
|
||||
ir_assert(fn_entry != nullptr, &instruction->base.base);
|
||||
|
||||
// If it's not @Frame(func) then it's definitely a suspend point
|
||||
if (target_fn == nullptr && !instruction->is_noasync) {
|
||||
if (target_fn == nullptr && !instruction->is_nosuspend) {
|
||||
if (fn_entry->inferred_async_node == nullptr) {
|
||||
fn_entry->inferred_async_node = instruction->base.base.source_node;
|
||||
}
|
||||
@ -30301,7 +30328,7 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i
|
||||
}
|
||||
|
||||
IrInstGenAwait *result = ir_build_await_gen(ira, &instruction->base.base, frame, result_type, result_loc,
|
||||
instruction->is_noasync);
|
||||
instruction->is_nosuspend);
|
||||
result->target_fn = target_fn;
|
||||
fn_entry->await_list.append(result);
|
||||
return ir_finish_anal(ira, &result->base);
|
||||
|
@ -861,8 +861,8 @@ static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction)
|
||||
switch (call_instruction->modifier) {
|
||||
case CallModifierNone:
|
||||
break;
|
||||
case CallModifierNoAsync:
|
||||
fprintf(irp->f, "noasync ");
|
||||
case CallModifierNoSuspend:
|
||||
fprintf(irp->f, "nosuspend ");
|
||||
break;
|
||||
case CallModifierAsync:
|
||||
fprintf(irp->f, "async ");
|
||||
@ -906,8 +906,8 @@ static void ir_print_call_gen(IrPrintGen *irp, IrInstGenCall *call_instruction)
|
||||
switch (call_instruction->modifier) {
|
||||
case CallModifierNone:
|
||||
break;
|
||||
case CallModifierNoAsync:
|
||||
fprintf(irp->f, "noasync ");
|
||||
case CallModifierNoSuspend:
|
||||
fprintf(irp->f, "nosuspend ");
|
||||
break;
|
||||
case CallModifierAsync:
|
||||
fprintf(irp->f, "async ");
|
||||
|
@ -93,7 +93,6 @@ static AstNode *ast_parse_field_init(ParseContext *pc);
|
||||
static AstNode *ast_parse_while_continue_expr(ParseContext *pc);
|
||||
static AstNode *ast_parse_link_section(ParseContext *pc);
|
||||
static AstNode *ast_parse_callconv(ParseContext *pc);
|
||||
static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc);
|
||||
static AstNode *ast_parse_param_decl(ParseContext *pc);
|
||||
static AstNode *ast_parse_param_type(ParseContext *pc);
|
||||
static AstNode *ast_parse_if_prefix(ParseContext *pc);
|
||||
@ -707,7 +706,6 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
|
||||
fn_proto->column = first->start_column;
|
||||
fn_proto->data.fn_proto.visib_mod = visib_mod;
|
||||
fn_proto->data.fn_proto.doc_comments = *doc_comments;
|
||||
// ast_parse_fn_cc may set it
|
||||
if (!fn_proto->data.fn_proto.is_extern)
|
||||
fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern;
|
||||
fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport;
|
||||
@ -788,29 +786,11 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
|
||||
static AstNode *ast_parse_fn_proto(ParseContext *pc) {
|
||||
Token *first = peek_token(pc);
|
||||
AstNodeFnProto fn_cc;
|
||||
Token *fn;
|
||||
if (ast_parse_fn_cc(pc).unwrap(&fn_cc)) {
|
||||
// The extern keyword for fn CC is also used for container decls.
|
||||
// We therefore put it back, as allow container decl to consume it
|
||||
// later.
|
||||
if (fn_cc.is_extern) {
|
||||
fn = eat_token_if(pc, TokenIdKeywordFn);
|
||||
if (fn == nullptr) {
|
||||
put_back_token(pc);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
fn = expect_token(pc, TokenIdKeywordFn);
|
||||
}
|
||||
} else {
|
||||
fn_cc = {};
|
||||
fn = eat_token_if(pc, TokenIdKeywordFn);
|
||||
if (fn == nullptr)
|
||||
return nullptr;
|
||||
Token *first = eat_token_if(pc, TokenIdKeywordFn);
|
||||
if (first == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Token *identifier = eat_token_if(pc, TokenIdSymbol);
|
||||
@ -830,7 +810,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
|
||||
}
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeFnProto, first);
|
||||
res->data.fn_proto = fn_cc;
|
||||
res->data.fn_proto = {};
|
||||
res->data.fn_proto.name = token_buf(identifier);
|
||||
res->data.fn_proto.params = params;
|
||||
res->data.fn_proto.align_expr = align_expr;
|
||||
@ -913,7 +893,7 @@ static AstNode *ast_parse_container_field(ParseContext *pc) {
|
||||
// Statement
|
||||
// <- KEYWORD_comptime? VarDecl
|
||||
// / KEYWORD_comptime BlockExprStatement
|
||||
// / KEYWORD_noasync BlockExprStatement
|
||||
// / KEYWORD_nosuspend BlockExprStatement
|
||||
// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
|
||||
// / KEYWORD_defer BlockExprStatement
|
||||
// / KEYWORD_errdefer Payload? BlockExprStatement
|
||||
@ -937,11 +917,11 @@ static AstNode *ast_parse_statement(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
|
||||
if (noasync != nullptr) {
|
||||
Token *nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend);
|
||||
if (nosuspend != nullptr) {
|
||||
AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
|
||||
res->data.noasync_expr.expr = statement;
|
||||
AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend);
|
||||
res->data.nosuspend_expr.expr = statement;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1289,7 +1269,7 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
|
||||
// / IfExpr
|
||||
// / KEYWORD_break BreakLabel? Expr?
|
||||
// / KEYWORD_comptime Expr
|
||||
// / KEYWORD_noasync Expr
|
||||
// / KEYWORD_nosuspend Expr
|
||||
// / KEYWORD_continue BreakLabel?
|
||||
// / KEYWORD_resume Expr
|
||||
// / KEYWORD_return Expr?
|
||||
@ -1324,11 +1304,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
|
||||
if (noasync != nullptr) {
|
||||
Token *nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend);
|
||||
if (nosuspend != nullptr) {
|
||||
AstNode *expr = ast_expect(pc, ast_parse_expr);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
|
||||
res->data.noasync_expr.expr = expr;
|
||||
AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend);
|
||||
res->data.nosuspend_expr.expr = expr;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1524,17 +1504,6 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {
|
||||
static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
|
||||
Token *async_token = eat_token_if(pc, TokenIdKeywordAsync);
|
||||
if (async_token) {
|
||||
if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
|
||||
// HACK: If we see the keyword `fn`, then we assume that
|
||||
// we are parsing an async fn proto, and not a call.
|
||||
// We therefore put back all tokens consumed by the async
|
||||
// prefix...
|
||||
put_back_token(pc);
|
||||
put_back_token(pc);
|
||||
|
||||
return ast_parse_primary_type_expr(pc);
|
||||
}
|
||||
|
||||
AstNode *child = ast_expect(pc, ast_parse_primary_type_expr);
|
||||
while (true) {
|
||||
AstNode *suffix = ast_parse_suffix_op(pc);
|
||||
@ -1640,7 +1609,6 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
|
||||
// / IfTypeExpr
|
||||
// / INTEGER
|
||||
// / KEYWORD_comptime TypeExpr
|
||||
// / KEYWORD_noasync TypeExpr
|
||||
// / KEYWORD_error DOT IDENTIFIER
|
||||
// / KEYWORD_false
|
||||
// / KEYWORD_null
|
||||
@ -1742,14 +1710,6 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
|
||||
if (noasync != nullptr) {
|
||||
AstNode *expr = ast_expect(pc, ast_parse_type_expr);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
|
||||
res->data.noasync_expr.expr = expr;
|
||||
return res;
|
||||
}
|
||||
|
||||
Token *error = eat_token_if(pc, TokenIdKeywordError);
|
||||
if (error != nullptr) {
|
||||
Token *dot = expect_token(pc, TokenIdDot);
|
||||
@ -2187,23 +2147,6 @@ static AstNode *ast_parse_callconv(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// FnCC
|
||||
// <- KEYWORD_extern
|
||||
// / KEYWORD_async
|
||||
static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
|
||||
AstNodeFnProto res = {};
|
||||
if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {
|
||||
res.is_async = true;
|
||||
return Optional<AstNodeFnProto>::some(res);
|
||||
}
|
||||
if (eat_token_if(pc, TokenIdKeywordExtern) != nullptr) {
|
||||
res.is_extern = true;
|
||||
return Optional<AstNodeFnProto>::some(res);
|
||||
}
|
||||
|
||||
return Optional<AstNodeFnProto>::none();
|
||||
}
|
||||
|
||||
// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
||||
static AstNode *ast_parse_param_decl(ParseContext *pc) {
|
||||
Buf doc_comments = BUF_INIT;
|
||||
@ -3189,7 +3132,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeCompTime:
|
||||
visit_field(&node->data.comptime_expr.expr, visit, context);
|
||||
break;
|
||||
case NodeTypeNoAsync:
|
||||
case NodeTypeNoSuspend:
|
||||
visit_field(&node->data.comptime_expr.expr, visit, context);
|
||||
break;
|
||||
case NodeTypeBreak:
|
||||
|
@ -128,8 +128,8 @@ static const struct ZigKeyword zig_keywords[] = {
|
||||
{"if", TokenIdKeywordIf},
|
||||
{"inline", TokenIdKeywordInline},
|
||||
{"noalias", TokenIdKeywordNoAlias},
|
||||
{"noasync", TokenIdKeywordNoAsync},
|
||||
{"noinline", TokenIdKeywordNoInline},
|
||||
{"nosuspend", TokenIdKeywordNoSuspend},
|
||||
{"null", TokenIdKeywordNull},
|
||||
{"or", TokenIdKeywordOr},
|
||||
{"orelse", TokenIdKeywordOrElse},
|
||||
@ -1589,8 +1589,8 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdKeywordIf: return "if";
|
||||
case TokenIdKeywordInline: return "inline";
|
||||
case TokenIdKeywordNoAlias: return "noalias";
|
||||
case TokenIdKeywordNoAsync: return "noasync";
|
||||
case TokenIdKeywordNoInline: return "noinline";
|
||||
case TokenIdKeywordNoSuspend: return "nosuspend";
|
||||
case TokenIdKeywordNull: return "null";
|
||||
case TokenIdKeywordOr: return "or";
|
||||
case TokenIdKeywordOrElse: return "orelse";
|
||||
|
@ -78,7 +78,7 @@ enum TokenId {
|
||||
TokenIdKeywordNoInline,
|
||||
TokenIdKeywordLinkSection,
|
||||
TokenIdKeywordNoAlias,
|
||||
TokenIdKeywordNoAsync,
|
||||
TokenIdKeywordNoSuspend,
|
||||
TokenIdKeywordNull,
|
||||
TokenIdKeywordOr,
|
||||
TokenIdKeywordOrElse,
|
||||
|
@ -2,6 +2,29 @@ const tests = @import("tests.zig");
|
||||
const std = @import("std");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add("call assigned to constant",
|
||||
\\const Foo = struct {
|
||||
\\ x: i32,
|
||||
\\};
|
||||
\\fn foo() Foo {
|
||||
\\ return .{ .x = 42 };
|
||||
\\}
|
||||
\\fn bar(val: var) Foo {
|
||||
\\ return .{ .x = val };
|
||||
\\}
|
||||
\\export fn entry() void {
|
||||
\\ const baz: Foo = undefined;
|
||||
\\ baz = foo();
|
||||
\\}
|
||||
\\export fn entry1() void {
|
||||
\\ const baz: Foo = undefined;
|
||||
\\ baz = bar(42);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:12:14: error: cannot assign to constant",
|
||||
"tmp.zig:16:14: error: cannot assign to constant",
|
||||
});
|
||||
|
||||
cases.add("invalid pointer syntax",
|
||||
\\export fn foo() void {
|
||||
\\ var guid: *:0 const u8 = undefined;
|
||||
@ -243,9 +266,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
"tmp.zig:17:17: error: RHS of shift is too large for LHS type",
|
||||
});
|
||||
|
||||
cases.addTest("combination of noasync and async",
|
||||
cases.addTest("combination of nosuspend and async",
|
||||
\\export fn entry() void {
|
||||
\\ noasync {
|
||||
\\ nosuspend {
|
||||
\\ const bar = async foo();
|
||||
\\ suspend;
|
||||
\\ resume bar;
|
||||
@ -253,9 +276,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\}
|
||||
\\fn foo() void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:21: error: async call in noasync scope",
|
||||
"tmp.zig:4:9: error: suspend in noasync scope",
|
||||
"tmp.zig:5:9: error: resume in noasync scope",
|
||||
"tmp.zig:3:21: error: async call in nosuspend scope",
|
||||
"tmp.zig:4:9: error: suspend in nosuspend scope",
|
||||
"tmp.zig:5:9: error: resume in nosuspend scope",
|
||||
});
|
||||
|
||||
cases.add("atomicrmw with bool op not .Xchg",
|
||||
@ -779,7 +802,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
});
|
||||
|
||||
cases.add("exported async function",
|
||||
\\export async fn foo() void {}
|
||||
\\export fn foo() callconv(.Async) void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:1:1: error: exported function cannot be async",
|
||||
});
|
||||
@ -1258,11 +1281,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
|
||||
cases.add("bad alignment in @asyncCall",
|
||||
\\export fn entry() void {
|
||||
\\ var ptr: async fn () void = func;
|
||||
\\ var ptr: fn () callconv(.Async) void = func;
|
||||
\\ var bytes: [64]u8 = undefined;
|
||||
\\ _ = @asyncCall(&bytes, {}, ptr);
|
||||
\\}
|
||||
\\async fn func() void {}
|
||||
\\fn func() callconv(.Async) void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:4:21: error: expected type '[]align(16) u8', found '*[64]u8'",
|
||||
});
|
||||
@ -1408,7 +1431,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\export fn entry() void {
|
||||
\\ _ = async amain();
|
||||
\\}
|
||||
\\async fn amain() void {
|
||||
\\fn amain() callconv(.Async) void {
|
||||
\\ other();
|
||||
\\}
|
||||
\\fn other() void {
|
||||
@ -1424,7 +1447,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\export fn entry() void {
|
||||
\\ _ = async amain();
|
||||
\\}
|
||||
\\async fn amain() void {
|
||||
\\fn amain() callconv(.Async) void {
|
||||
\\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
@ -1451,7 +1474,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ var ptr = afunc;
|
||||
\\ _ = ptr();
|
||||
\\}
|
||||
\\async fn afunc() void {}
|
||||
\\fn afunc() callconv(.Async) void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:6:12: error: function is not comptime-known; @asyncCall required",
|
||||
});
|
||||
@ -1462,7 +1485,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = async ptr();
|
||||
\\}
|
||||
\\
|
||||
\\async fn afunc() void { }
|
||||
\\fn afunc() callconv(.Async) void { }
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:15: error: function is not comptime-known; @asyncCall required",
|
||||
});
|
||||
@ -3051,7 +3074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\export fn entry() void {
|
||||
\\ _ = async foo();
|
||||
\\}
|
||||
\\async fn foo() void {
|
||||
\\fn foo() void {
|
||||
\\ suspend {
|
||||
\\ suspend {
|
||||
\\ }
|
||||
@ -3099,7 +3122,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\export fn entry() void {
|
||||
\\ _ = async amain();
|
||||
\\}
|
||||
\\async fn amain() void {
|
||||
\\fn amain() callconv(.Async) void {
|
||||
\\ return error.ShouldBeCompileError;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
@ -3569,7 +3592,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
});
|
||||
|
||||
cases.add("attempt to use 0 bit type in extern fn",
|
||||
\\extern fn foo(ptr: extern fn(*void) void) void;
|
||||
\\extern fn foo(ptr: fn(*void) callconv(.C) void) void;
|
||||
\\
|
||||
\\export fn entry() void {
|
||||
\\ foo(bar);
|
||||
@ -3580,7 +3603,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ bar(&{});
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'",
|
||||
"tmp.zig:1:23: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'",
|
||||
"tmp.zig:7:11: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'",
|
||||
});
|
||||
|
||||
@ -5352,6 +5375,50 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
break :x tc;
|
||||
});
|
||||
|
||||
cases.addCase(x: {
|
||||
const tc = cases.create("multiple files with private member instance function (canonical invocation) error",
|
||||
\\const Foo = @import("foo.zig",).Foo;
|
||||
\\
|
||||
\\export fn callPrivFunction() void {
|
||||
\\ var foo = Foo{};
|
||||
\\ Foo.privateFunction(foo);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:5:8: error: 'privateFunction' is private",
|
||||
"foo.zig:2:5: note: declared here",
|
||||
});
|
||||
|
||||
tc.addSourceFile("foo.zig",
|
||||
\\pub const Foo = struct {
|
||||
\\ fn privateFunction(self: *Foo) void { }
|
||||
\\};
|
||||
);
|
||||
|
||||
break :x tc;
|
||||
});
|
||||
|
||||
cases.addCase(x: {
|
||||
const tc = cases.create("multiple files with private member instance function error",
|
||||
\\const Foo = @import("foo.zig",).Foo;
|
||||
\\
|
||||
\\export fn callPrivFunction() void {
|
||||
\\ var foo = Foo{};
|
||||
\\ foo.privateFunction();
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:5:8: error: 'privateFunction' is private",
|
||||
"foo.zig:2:5: note: declared here",
|
||||
});
|
||||
|
||||
tc.addSourceFile("foo.zig",
|
||||
\\pub const Foo = struct {
|
||||
\\ fn privateFunction(self: *Foo) void { }
|
||||
\\};
|
||||
);
|
||||
|
||||
break :x tc;
|
||||
});
|
||||
|
||||
cases.add("container init with non-type",
|
||||
\\const zero: i32 = 0;
|
||||
\\const a = zero{1};
|
||||
@ -7330,4 +7397,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
":3:18: error: expected type '[*:0]const u8', found '*[64]u8'",
|
||||
":3:18: note: destination pointer requires a terminating '0' sentinel",
|
||||
});
|
||||
|
||||
cases.add("issue #5221: invalid struct init type referenced by @typeInfo and passed into function",
|
||||
\\fn ignore(comptime param: var) void {}
|
||||
\\
|
||||
\\export fn foo() void {
|
||||
\\ const MyStruct = struct {
|
||||
\\ wrong_type: []u8 = "foo",
|
||||
\\ };
|
||||
\\
|
||||
\\ comptime ignore(@typeInfo(MyStruct).Struct.fields[0]);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
":5:28: error: expected type '[]u8', found '*const [3:0]u8'",
|
||||
});
|
||||
|
||||
cases.add("integer underflow error",
|
||||
\\export fn entry() void {
|
||||
\\ _ = @intToPtr(*c_void, ~@as(usize, @import("std").math.maxInt(usize)) - 1);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
":2:75: error: operation caused overflow",
|
||||
});
|
||||
}
|
||||
|
@ -243,4 +243,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("scoped typedef",
|
||||
\\int main(int argc, char **argv) {
|
||||
\\ typedef int Foo;
|
||||
\\ typedef Foo Bar;
|
||||
\\ typedef void (*func)(int);
|
||||
\\ typedef int uint32_t;
|
||||
\\ uint32_t a;
|
||||
\\ Foo i;
|
||||
\\ Bar j;
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
@ -234,12 +234,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addRuntimeSafety("noasync function call, callee suspends",
|
||||
cases.addRuntimeSafety("nosuspend function call, callee suspends",
|
||||
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
|
||||
\\ @import("std").os.exit(126);
|
||||
\\}
|
||||
\\pub fn main() void {
|
||||
\\ _ = noasync add(101, 100);
|
||||
\\ _ = nosuspend add(101, 100);
|
||||
\\}
|
||||
\\fn add(a: i32, b: i32) i32 {
|
||||
\\ if (a > 100) {
|
||||
@ -282,7 +282,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
||||
\\ var ptr = other;
|
||||
\\ var frame = @asyncCall(&bytes, {}, ptr);
|
||||
\\}
|
||||
\\async fn other() void {
|
||||
\\fn other() callconv(.Async) void {
|
||||
\\ suspend;
|
||||
\\}
|
||||
);
|
||||
@ -874,16 +874,16 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
||||
\\ return &failing_frame;
|
||||
\\}
|
||||
\\
|
||||
\\async fn failing() anyerror!void {
|
||||
\\fn failing() anyerror!void {
|
||||
\\ suspend;
|
||||
\\ return second();
|
||||
\\}
|
||||
\\
|
||||
\\async fn second() anyerror!void {
|
||||
\\fn second() callconv(.Async) anyerror!void {
|
||||
\\ return error.Fail;
|
||||
\\}
|
||||
\\
|
||||
\\async fn printTrace(p: anyframe->anyerror!void) void {
|
||||
\\fn printTrace(p: anyframe->anyerror!void) void {
|
||||
\\ (await p) catch unreachable;
|
||||
\\}
|
||||
);
|
||||
|
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