diff options
| -rw-r--r-- | build.zig | 1 | ||||
| -rw-r--r-- | doc/langref.html.in | 4 | ||||
| -rw-r--r-- | lib/std/build.zig | 11 | ||||
| -rw-r--r-- | lib/std/debug.zig | 5 | ||||
| -rw-r--r-- | lib/std/os.zig | 152 | ||||
| -rw-r--r-- | lib/std/special/compiler_rt.zig | 9 | ||||
| -rw-r--r-- | lib/std/special/compiler_rt/aulldiv.zig | 121 | ||||
| -rw-r--r-- | lib/std/special/compiler_rt/aullrem.zig | 123 | ||||
| -rw-r--r-- | lib/std/special/compiler_rt/extendXfYf2_test.zig | 6 | ||||
| -rw-r--r-- | lib/std/special/doc/index.html | 85 | ||||
| -rw-r--r-- | lib/std/special/doc/main.js | 382 | ||||
| -rw-r--r-- | lib/std/special/docs/index.html | 356 | ||||
| -rw-r--r-- | lib/std/special/docs/main.js | 1194 | ||||
| -rw-r--r-- | lib/std/special/start_windows_tls.zig | 12 | ||||
| -rw-r--r-- | lib/std/std.zig | 120 | ||||
| -rw-r--r-- | src/all_types.hpp | 47 | ||||
| -rw-r--r-- | src/analyze.cpp | 47 | ||||
| -rw-r--r-- | src/ast_render.cpp | 3 | ||||
| -rw-r--r-- | src/buffer.hpp | 6 | ||||
| -rw-r--r-- | src/codegen.cpp | 9 | ||||
| -rw-r--r-- | src/dump_analysis.cpp | 393 | ||||
| -rw-r--r-- | src/ir.cpp | 54 | ||||
| -rw-r--r-- | src/main.cpp | 4 | ||||
| -rw-r--r-- | src/parser.cpp | 49 | ||||
| -rw-r--r-- | src/tokenizer.cpp | 53 | ||||
| -rw-r--r-- | src/tokenizer.hpp | 1 |
26 files changed, 2459 insertions, 788 deletions
@@ -373,6 +373,7 @@ fn addLibUserlandStep(b: *Builder, mode: builtin.Mode) void { artifact.bundle_compiler_rt = true; artifact.setTarget(builtin.arch, builtin.os, builtin.abi); artifact.setBuildMode(mode); + artifact.force_pic = true; if (mode != .Debug) { artifact.strip = true; } diff --git a/doc/langref.html.in b/doc/langref.html.in index 844314c144..a30670b0c7 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -10062,7 +10062,7 @@ fn readU32Be() u32 {} <li>Ascii control characters, except for U+000a (LF): U+0000 - U+0009, U+000b - U+0001f, U+007f. (Note that Windows line endings (CRLF) are not allowed, and hard tabs are not allowed.)</li> <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li> </ul> - <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p> + <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possibly the last line of the file).</p> <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/ziglang/zig/issues/663">issue #663</a></p> {#header_close#} @@ -10097,7 +10097,7 @@ TopLevelComptime <- KEYWORD_comptime BlockExpr TopLevelDecl <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl - / KEYWORD_use Expr SEMICOLON + / KEYWORD_usingnamespace Expr SEMICOLON FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) diff --git a/lib/std/build.zig b/lib/std/build.zig index c640f6e8f3..cc062f3af8 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1488,6 +1488,9 @@ pub const LibExeObjStep = struct { dynamic_linker: ?[]const u8 = null, + /// Position Independent Code + force_pic: ?bool = null, + const LinkObject = union(enum) { StaticPath: []const u8, OtherStep: *LibExeObjStep, @@ -2314,6 +2317,14 @@ pub const LibExeObjStep = struct { try zig_args.append(builder.pathFromRoot(dir)); } + if (self.force_pic) |pic| { + if (pic) { + try zig_args.append("-fPIC"); + } else { + try zig_args.append("-fno-PIC"); + } + } + if (self.kind == Kind.Test) { try builder.spawnChild(zig_args.toSliceConst()); } else { diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 25868d67a1..a6bc0fedf3 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2439,3 +2439,8 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void { ); std.debug.warn("{} sp = 0x{x}\n", prefix, sp); } + +// Reference everything so it gets tested. +test "" { + _ = leb; +} diff --git a/lib/std/os.zig b/lib/std/os.zig index c520e1d635..c05c911148 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -183,7 +183,7 @@ pub fn abort() noreturn { exit(127); } -pub const RaiseError = error{Unexpected}; +pub const RaiseError = UnexpectedError; pub fn raise(sig: u8) RaiseError!void { if (builtin.link_libc) { @@ -215,10 +215,7 @@ pub fn raise(sig: u8) RaiseError!void { @compileError("std.os.raise unimplemented for this target"); } -pub const KillError = error{ - PermissionDenied, - Unexpected, -}; +pub const KillError = error{PermissionDenied} || UnexpectedError; pub fn kill(pid: pid_t, sig: u8) KillError!void { switch (errno(system.kill(pid, sig))) { @@ -266,9 +263,7 @@ pub const ReadError = error{ /// This error occurs when no global event loop is configured, /// and reading from the file descriptor would block. WouldBlock, - - Unexpected, -}; +} || UnexpectedError; /// Returns the number of bytes that were read, which can be less than /// buf.len. If 0 bytes were read, that means EOF. @@ -385,8 +380,7 @@ pub const WriteError = error{ BrokenPipe, SystemResources, OperationAborted, - Unexpected, -}; +} || UnexpectedError; /// Write to a file descriptor. Keeps trying if it gets interrupted. /// This function is for blocking file descriptors only. @@ -548,8 +542,7 @@ pub const OpenError = error{ NotDir, PathAlreadyExists, DeviceBusy, - Unexpected, -}; +} || UnexpectedError; /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `openC`. @@ -748,9 +741,7 @@ pub const ExecveError = error{ ProcessFdQuotaExceeded, SystemFdQuotaExceeded, NameTooLong, - - Unexpected, -}; +} || UnexpectedError; fn execveErrnoToErr(err: usize) ExecveError { assert(err > 0); @@ -808,8 +799,7 @@ pub fn getenvC(key: [*]const u8) ?[]const u8 { pub const GetCwdError = error{ NameTooLong, CurrentWorkingDirectoryUnlinked, - Unexpected, -}; +} || UnexpectedError; /// The result is a slice of out_buffer, indexed from 0. pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { @@ -846,8 +836,7 @@ pub const SymLinkError = error{ NameTooLong, InvalidUtf8, BadPathName, - Unexpected, -}; +} || UnexpectedError; /// Creates a symbolic link named `sym_link_path` which contains the string `target_path`. /// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent @@ -932,7 +921,6 @@ pub const UnlinkError = error{ NotDir, SystemResources, ReadOnlyFileSystem, - Unexpected, /// On Windows, file paths must be valid Unicode. InvalidUtf8, @@ -940,7 +928,7 @@ pub const UnlinkError = error{ /// On Windows, file paths cannot contain these characters: /// '/', '*', '?', '"', '<', '>', '|' BadPathName, -}; +} || UnexpectedError; /// Delete a name and possibly the file it refers to. /// See also `unlinkC`. @@ -996,8 +984,7 @@ const RenameError = error{ RenameAcrossMountPoints, InvalidUtf8, BadPathName, - Unexpected, -}; +} || UnexpectedError; /// Change the name or location of a file. pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { @@ -1064,8 +1051,7 @@ pub const MakeDirError = error{ ReadOnlyFileSystem, InvalidUtf8, BadPathName, - Unexpected, -}; +} || UnexpectedError; /// Create a directory. /// `mode` is ignored on Windows. @@ -1116,8 +1102,7 @@ pub const DeleteDirError = error{ ReadOnlyFileSystem, InvalidUtf8, BadPathName, - Unexpected, -}; +} || UnexpectedError; /// Deletes an empty directory. pub fn rmdir(dir_path: []const u8) DeleteDirError!void { @@ -1163,8 +1148,7 @@ pub const ChangeCurDirError = error{ FileNotFound, SystemResources, NotDir, - Unexpected, -}; +} || UnexpectedError; /// Changes the current working directory of the calling process. /// `dir_path` is recommended to be a UTF-8 encoded string. @@ -1206,8 +1190,7 @@ pub const ReadLinkError = error{ FileNotFound, SystemResources, NotDir, - Unexpected, -}; +} || UnexpectedError; /// Read value of a symbolic link. /// The return value is a slice of `out_buffer` from index 0. @@ -1247,8 +1230,7 @@ pub const SetIdError = error{ ResourceLimitReached, InvalidUserId, PermissionDenied, - Unexpected, -}; +} || UnexpectedError; pub fn setuid(uid: u32) SetIdError!void { switch (errno(system.setuid(uid))) { @@ -1357,9 +1339,7 @@ pub const SocketError = error{ /// The protocol type or the specified protocol is not supported within this domain. ProtocolNotSupported, - - Unexpected, -}; +} || UnexpectedError; pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!i32 { const rc = system.socket(domain, socket_type, protocol); @@ -1409,9 +1389,7 @@ pub const BindError = error{ /// The socket inode would reside on a read-only filesystem. ReadOnlyFileSystem, - - Unexpected, -}; +} || UnexpectedError; /// addr is `*const T` where T is one of the sockaddr pub fn bind(fd: i32, addr: *const sockaddr) BindError!void { @@ -1448,9 +1426,7 @@ const ListenError = error{ /// The socket is not of a type that supports the listen() operation. OperationNotSupported, - - Unexpected, -}; +} || UnexpectedError; pub fn listen(sockfd: i32, backlog: u32) ListenError!void { const rc = system.listen(sockfd, backlog); @@ -1487,9 +1463,7 @@ pub const AcceptError = error{ /// Firewall rules forbid connection. BlockedByFirewall, - - Unexpected, -}; +} || UnexpectedError; /// Accept a connection on a socket. `fd` must be opened in blocking mode. /// See also `accept4_async`. @@ -1559,9 +1533,7 @@ pub const EpollCreateError = error{ /// There was insufficient memory to create the kernel object. SystemResources, - - Unexpected, -}; +} || UnexpectedError; pub fn epoll_create1(flags: u32) EpollCreateError!i32 { const rc = system.epoll_create1(flags); @@ -1600,9 +1572,7 @@ pub const EpollCtlError = error{ /// The target file fd does not support epoll. This error can occur if fd refers to, /// for example, a regular file or a directory. FileDescriptorIncompatibleWithEpoll, - - Unexpected, -}; +} || UnexpectedError; pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: ?*epoll_event) EpollCtlError!void { const rc = system.epoll_ctl(epfd, op, fd, event); @@ -1643,8 +1613,7 @@ pub const EventFdError = error{ SystemResources, ProcessFdQuotaExceeded, SystemFdQuotaExceeded, - Unexpected, -}; +} || UnexpectedError; pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 { const rc = system.eventfd(initval, flags); @@ -1663,9 +1632,7 @@ pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 { pub const GetSockNameError = error{ /// Insufficient resources were available in the system to perform the operation. SystemResources, - - Unexpected, -}; +} || UnexpectedError; pub fn getsockname(sockfd: i32) GetSockNameError!sockaddr { var addr: sockaddr = undefined; @@ -1714,9 +1681,7 @@ pub const ConnectError = error{ /// Timeout while attempting connection. The server may be too busy to accept new connections. Note /// that for IP sockets the timeout may be very long when syncookies are enabled on the server. ConnectionTimedOut, - - Unexpected, -}; +} || UnexpectedError; /// Initiate a connection on a socket. /// This is for blocking file descriptors only. @@ -1747,7 +1712,7 @@ pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!v } } -/// Same as `connect` except it is for blocking socket file descriptors. +/// Same as `connect` except it is for non-blocking socket file descriptors. /// It expects to receive EINPROGRESS`. pub fn connect_async(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void { while (true) { @@ -1824,10 +1789,7 @@ pub fn waitpid(pid: i32, flags: u32) u32 { } } -pub const FStatError = error{ - SystemResources, - Unexpected, -}; +pub const FStatError = error{SystemResources} || UnexpectedError; pub fn fstat(fd: fd_t) FStatError!Stat { var stat: Stat = undefined; @@ -1856,9 +1818,7 @@ pub const KQueueError = error{ /// The system-wide limit on the total number of open files has been reached. SystemFdQuotaExceeded, - - Unexpected, -}; +} || UnexpectedError; pub fn kqueue() KQueueError!i32 { const rc = system.kqueue(); @@ -1922,8 +1882,7 @@ pub const INotifyInitError = error{ ProcessFdQuotaExceeded, SystemFdQuotaExceeded, SystemResources, - Unexpected, -}; +} || UnexpectedError; /// initialize an inotify instance pub fn inotify_init1(flags: u32) INotifyInitError!i32 { @@ -1944,8 +1903,7 @@ pub const INotifyAddWatchError = error{ FileNotFound, SystemResources, UserResourceLimitReached, - Unexpected, -}; +} || UnexpectedError; /// add a watch to an initialized inotify instance pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INotifyAddWatchError!i32 { @@ -1992,8 +1950,7 @@ pub const MProtectError = error{ /// dle of a region currently protected as PROT_READ|PROT_WRITE would result in three map‐ /// pings: two read/write mappings at each end and a read-only mapping in the middle.) OutOfMemory, - Unexpected, -}; +} || UnexpectedError; /// `memory.len` must be page-aligned. pub fn mprotect(memory: []align(mem.page_size) u8, protection: u32) MProtectError!void { @@ -2007,10 +1964,7 @@ pub fn mprotect(memory: []align(mem.page_size) u8, protection: u32) MProtectErro } } -pub const ForkError = error{ - SystemResources, - Unexpected, -}; +pub const ForkError = error{SystemResources} || UnexpectedError; pub fn fork() ForkError!pid_t { const rc = system.fork(); @@ -2037,8 +1991,7 @@ pub const MMapError = error{ PermissionDenied, LockedMemoryLimitExceeded, OutOfMemory, - Unexpected, -}; +} || UnexpectedError; /// Map files or devices into memory. /// Use of a mapped region can result in these signals: @@ -2101,9 +2054,7 @@ pub const AccessError = error{ /// On Windows, file paths must be valid Unicode. InvalidUtf8, - - Unexpected, -}; +} || UnexpectedError; /// check user's permissions for a file /// TODO currently this assumes `mode` is `F_OK` on Windows. @@ -2161,8 +2112,7 @@ pub fn accessW(path: [*]const u16, mode: u32) windows.GetFileAttributesError!voi pub const PipeError = error{ SystemFdQuotaExceeded, ProcessFdQuotaExceeded, - Unexpected, -}; +} || UnexpectedError; /// Creates a unidirectional data channel that can be used for interprocess communication. pub fn pipe() PipeError![2]fd_t { @@ -2193,8 +2143,7 @@ pub const SysCtlError = error{ PermissionDenied, SystemResources, NameTooLong, - Unexpected, -}; +} || UnexpectedError; pub fn sysctl( name: []const c_int, @@ -2237,10 +2186,7 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void { } } -pub const SeekError = error{ - Unseekable, - Unexpected, -}; +pub const SeekError = error{Unseekable} || UnexpectedError; /// Repositions read/write file offset relative to the beginning. pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { @@ -2382,9 +2328,7 @@ pub const RealPathError = error{ InvalidUtf8, PathAlreadyExists, - - Unexpected, -}; +} || UnexpectedError; /// Return the canonicalized absolute pathname. /// Expands all symbolic links and resolves references to `.`, `..`, and @@ -2548,10 +2492,7 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf return last_r; } -pub const ClockGetTimeError = error{ - UnsupportedClock, - Unexpected, -}; +pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { switch (errno(system.clock_gettime(clk_id, tp))) { @@ -2571,10 +2512,7 @@ pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { } } -pub const SchedGetAffinityError = error{ - PermissionDenied, - Unexpected, -}; +pub const SchedGetAffinityError = error{PermissionDenied} || UnexpectedError; pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t { var set: cpu_set_t = undefined; @@ -2628,8 +2566,7 @@ pub const SigaltstackError = error{ /// Attempted to change the signal stack while it was active. PermissionDenied, - Unexpected, -}; +} || UnexpectedError; pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { if (windows.is_the_target or uefi.is_the_target or wasi.is_the_target) @@ -2677,9 +2614,7 @@ pub const FutimensError = error{ PermissionDenied, ReadOnlyFileSystem, - - Unexpected, -}; +} || UnexpectedError; pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void { switch (errno(system.futimens(fd, times))) { @@ -2694,10 +2629,7 @@ pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void { } } -pub const GetHostNameError = error{ - PermissionDenied, - Unexpected, -}; +pub const GetHostNameError = error{PermissionDenied} || UnexpectedError; pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { if (builtin.link_libc) { diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 638a9bb60c..902f2da2ff 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -248,8 +248,17 @@ comptime { switch (builtin.arch) { .i386 => { + @export("_alldiv", @import("compiler_rt/aulldiv.zig")._alldiv, strong_linkage); @export("_aulldiv", @import("compiler_rt/aulldiv.zig")._aulldiv, strong_linkage); + @export("_allrem", @import("compiler_rt/aullrem.zig")._allrem, strong_linkage); @export("_aullrem", @import("compiler_rt/aullrem.zig")._aullrem, strong_linkage); + + @export("__divti3", @import("compiler_rt/divti3.zig").__divti3, linkage); + @export("__modti3", @import("compiler_rt/modti3.zig").__modti3, linkage); + @export("__multi3", @import("compiler_rt/multi3.zig").__multi3, linkage); + @export("__udivti3", @import("compiler_rt/udivti3.zig").__udivti3, linkage); + @export("__udivmodti4", @import("compiler_rt/udivmodti4.zig").__udivmodti4, linkage); + @export("__umodti3", @import("compiler_rt/umodti3.zig").__umodti3, linkage); }, .x86_64 => { // The "ti" functions must use @Vector(2, u64) parameter types to adhere to the ABI diff --git a/lib/std/special/compiler_rt/aulldiv.zig b/lib/std/special/compiler_rt/aulldiv.zig index d99bc94ff5..dfca4f4c43 100644 --- a/lib/std/special/compiler_rt/aulldiv.zig +++ b/lib/std/special/compiler_rt/aulldiv.zig @@ -1,55 +1,76 @@ +const builtin = @import("builtin"); + +pub extern stdcallcc fn _alldiv(a: i64, b: i64) i64 { + @setRuntimeSafety(builtin.is_test); + const s_a = a >> (i64.bit_count - 1); + const s_b = b >> (i64.bit_count - 1); + + const an = (a ^ s_a) -% s_a; + const bn = (b ^ s_b) -% s_b; + + const r = @bitCast(u64, an) / @bitCast(u64, bn); + const s = s_a ^ s_b; + return (@bitCast(i64, r) ^ s) -% s; +} + pub nakedcc fn _aulldiv() void { @setRuntimeSafety(false); + + // The stack layout is: + // ESP+16 divisor (hi) + // ESP+12 divisor (low) + // ESP+8 dividend (hi) + // ESP+4 dividend (low) + // ESP return address + asm volatile ( - \\.intel_syntax noprefix - \\ - \\ push ebx - \\ push esi - \\ mov eax,dword ptr [esp+18h] - \\ or eax,eax - \\ jne L1 - \\ mov ecx,dword ptr [esp+14h] - \\ mov eax,dword ptr [esp+10h] - \\ xor edx,edx - \\ div ecx - \\ mov ebx,eax - \\ mov eax,dword ptr [esp+0Ch] - \\ div ecx - \\ mov edx,ebx - \\ jmp L2 - \\ L1: - \\ mov ecx,eax - \\ mov ebx,dword ptr [esp+14h] - \\ mov edx,dword ptr [esp+10h] - \\ mov eax,dword ptr [esp+0Ch] - \\ L3: - \\ shr ecx,1 - \\ rcr ebx,1 - \\ shr edx,1 - \\ rcr eax,1 - \\ or ecx,ecx - \\ jne L3 - \\ div ebx - \\ mov esi,eax - \\ mul dword ptr [esp+18h] - \\ mov ecx,eax - \\ mov eax,dword ptr [esp+14h] - \\ mul esi - \\ add edx,ecx - \\ jb L4 - \\ cmp edx,dword ptr [esp+10h] - \\ ja L4 - \\ jb L5 - \\ cmp eax,dword ptr [esp+0Ch] - \\ jbe L5 - \\ L4: - \\ dec esi - \\ L5: - \\ xor edx,edx - \\ mov eax,esi - \\ L2: - \\ pop esi - \\ pop ebx - \\ ret 10h + \\ push %%ebx + \\ push %%esi + \\ mov 0x18(%%esp),%%eax + \\ or %%eax,%%eax + \\ jne 1f + \\ mov 0x14(%%esp),%%ecx + \\ mov 0x10(%%esp),%%eax + \\ xor %%edx,%%edx + \\ div %%ecx + \\ mov %%eax,%%ebx + \\ mov 0xc(%%esp),%%eax + \\ div %%ecx + \\ mov %%ebx,%%edx + \\ jmp 5f + \\ 1: + \\ mov %%eax,%%ecx + \\ mov 0x14(%%esp),%%ebx + \\ mov 0x10(%%esp),%%edx + \\ mov 0xc(%%esp),%%eax + \\ 2: + \\ shr %%ecx + \\ rcr %%ebx + \\ shr %%edx + \\ rcr %%eax + \\ or %%ecx,%%ecx + \\ jne 2b + \\ div %%ebx + \\ mov %%eax,%%esi + \\ mull 0x18(%%esp) + \\ mov %%eax,%%ecx + \\ mov 0x14(%%esp),%%eax + \\ mul %%esi + \\ add %%ecx,%%edx + \\ jb 3f + \\ cmp 0x10(%%esp),%%edx + \\ ja 3f + \\ jb 4f + \\ cmp 0xc(%%esp),%%eax + \\ jbe 4f + \\ 3: + \\ dec %%esi + \\ 4: + \\ xor %%edx,%%edx + \\ mov %%esi,%%eax + \\ 5: + \\ pop %%esi + \\ pop %%ebx + \\ ret $0x10 ); } diff --git a/lib/std/special/compiler_rt/aullrem.zig b/lib/std/special/compiler_rt/aullrem.zig index 51c4eebe3e..c1fee72032 100644 --- a/lib/std/special/compiler_rt/aullrem.zig +++ b/lib/std/special/compiler_rt/aullrem.zig @@ -1,56 +1,77 @@ +const builtin = @import("builtin"); + +pub extern stdcallcc fn _allrem(a: i64, b: i64) i64 { + @setRuntimeSafety(builtin.is_test); + const s_a = a >> (i64.bit_count - 1); + const s_b = b >> (i64.bit_count - 1); + + const an = (a ^ s_a) -% s_a; + const bn = (b ^ s_b) -% s_b; + + const r = @bitCast(u64, an) % @bitCast(u64, bn); + const s = s_a ^ s_b; + return (@bitCast(i64, r) ^ s) -% s; +} + pub nakedcc fn _aullrem() void { @setRuntimeSafety(false); + + // The stack layout is: + // ESP+16 divisor (hi) + // ESP+12 divisor (low) + // ESP+8 dividend (hi) + // ESP+4 dividend (low) + // ESP return address + asm volatile ( - \\.intel_syntax noprefix - \\ - \\ push ebx - \\ mov eax,dword ptr [esp+14h] - \\ or eax,eax - \\ jne L1a - \\ mov ecx,dword ptr [esp+10h] - \\ mov eax,dword ptr [esp+0Ch] - \\ xor edx,edx - \\ div ecx - \\ mov eax,dword ptr [esp+8] - \\ div ecx - \\ mov eax,edx - \\ xor edx,edx - \\ jmp L2a - \\ L1a: - \\ mov ecx,eax - \\ mov ebx,dword ptr [esp+10h] - \\ mov edx,dword ptr [esp+0Ch] - \\ mov eax,dword ptr [esp+8] - \\ L3a: - \\ shr ecx,1 - \\ rcr ebx,1 - \\ shr edx,1 - \\ rcr eax,1 - \\ or ecx,ecx - \\ jne L3a - \\ div ebx - \\ mov ecx,eax - \\ mul dword ptr [esp+14h] - \\ xchg eax,ecx - \\ mul dword ptr [esp+10h] - \\ add edx,ecx - \\ jb L4a - \\ cmp edx,dword ptr [esp+0Ch] - \\ ja L4a - \\ jb L5a - \\ cmp eax,dword ptr [esp+8] - \\ jbe L5a - \\ L4a: - \\ sub eax,dword ptr [esp+10h] - \\ sbb edx,dword ptr [esp+14h] - \\ L5a: - \\ sub eax,dword ptr [esp+8] - \\ sbb edx,dword ptr [esp+0Ch] - \\ neg edx - \\ neg eax - \\ sbb edx,0 - \\ L2a: - \\ pop ebx - \\ ret 10h + \\ push %%ebx + \\ mov 0x14(%%esp),%%eax + \\ or %%eax,%%eax + \\ jne 1f + \\ mov 0x10(%%esp),%%ecx + \\ mov 0xc(%%esp),%%eax + \\ xor %%edx,%%edx + \\ div %%ecx + \\ mov 0x8(%%esp),%%eax + \\ div %%ecx + \\ mov %%edx,%%eax + \\ xor %%edx,%%edx + \\ jmp 6f + \\ 1: + \\ mov %%eax,%%ecx + \\ mov 0x10(%%esp),%%ebx + \\ mov 0xc(%%esp),%%edx + \\ mov 0x8(%%esp),%%eax + \\ 2: + \\ shr %%ecx + \\ rcr %%ebx + \\ shr %%edx + \\ rcr %%eax + \\ or %%ecx,%%ecx + \\ jne 2b + \\ div %%ebx + \\ mov %%eax,%%ecx + \\ mull 0x14(%%esp) + \\ xchg %%eax,%%ecx + \\ mull 0x10(%%esp) + \\ add %%ecx,%%edx + \\ jb 3f + \\ cmp 0xc(%%esp),%%edx + \\ ja 3f + \\ jb 4f + \\ cmp 0x8(%%esp),%%eax + \\ jbe 4f + \\ 3: + \\ sub 0x10(%%esp),%%eax + \\ sbb 0x14(%%esp),%%edx + \\ 4: + \\ sub 0x8(%%esp),%%eax + \\ sbb 0xc(%%esp),%%edx + \\ neg %%edx + \\ neg %%eax + \\ sbb $0x0,%%edx + \\ 6: + \\ pop %%ebx + \\ ret $0x10 ); } diff --git a/lib/std/special/compiler_rt/extendXfYf2_test.zig b/lib/std/special/compiler_rt/extendXfYf2_test.zig index 050a799823..6f8111c8fb 100644 --- a/lib/std/special/compiler_rt/extendXfYf2_test.zig +++ b/lib/std/special/compiler_rt/extendXfYf2_test.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2; @@ -87,7 +88,10 @@ test "extenddftf2" { test "extendhfsf2" { test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN - test__extendhfsf2(0x7c01, 0x7f802000); // sNaN + // On x86 the NaN becomes quiet because the return is pushed on the x87 + // stack due to ABI requirements + if (builtin.arch != .i386 and builtin.os == .windows) + test__extendhfsf2(0x7c01, 0x7f802000); // sNaN test__extendhfsf2(0, 0); // 0 test__extendhfsf2(0x8000, 0x80000000); // -0 diff --git a/lib/std/special/doc/index.html b/lib/std/special/doc/index.html deleted file mode 100644 index db80ec9550..0000000000 --- a/lib/std/special/doc/index.html +++ /dev/null @@ -1,85 +0,0 @@ -<!doctype html> -<html> - <head> - <meta charset="utf-8"> - <title>Documentation - Zig</title> - <link rel="icon" href="favicon.png"> - <style type="text/css"> - body { - font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; - } - .hidden { - display: none; - } - a { - color: #2A6286; - } - pre{ - font-family:"Source Code Pro",monospace; - font-size:1em; - background-color:#F5F5F5; - padding:1em; - } - #listNav { - list-style-type: none; - margin: 0; - padding: 0; - overflow: hidden; - background-color: #333; - } - #listNav li { - float:left; - } - #listNav li a { - display: block; - color: #fff; - text-align: center; - padding: .8em .8em; - text-decoration: none; - } - #listNav li a:hover { - background-color: #111; - } - #listNav li a.active { - background-color: #4CAF50; - } - - @media (prefers-color-scheme: dark) { - body{ - background-color: #111; - color: #bbb; - } - a { - color: #88f; - } - pre{ - background-color:#2A2A2A; - } - } - </style> - </head> - <body> - <p id="status">Loading...</p> - <div id="sectNav" class="hidden"><ul id="listNav"></ul></div> - <div id="fnProto" class="hidden"> - <pre id="fnProtoCode"></pre> - </div> - <div id="sectPkgs" class="hidden"> - <h2>Packages</h2> - <ul id="listPkgs"> - </ul> - </div> - <div id="sectTypes" class="hidden"> - <h2>Types</h2> - <ul id="listTypes"> - </ul> - </div> - <div id="sectFns" class="hidden"> - <h2>Functions</h2> - <ul id="listFns"> - </ul> - </div> - <script src="data.js"></script> - <script src="main.js"></script> - </body> -</html> diff --git a/lib/std/special/doc/main.js b/lib/std/special/doc/main.js deleted file mode 100644 index 50002f6841..0000000000 --- a/lib/std/special/doc/main.js +++ /dev/null @@ -1,382 +0,0 @@ -(function() { - var domStatus = document.getElementById("status"); - var domSectNav = document.getElementById("sectNav"); - var domListNav = document.getElementById("listNav"); - var domSectPkgs = document.getElementById("sectPkgs"); - var domListPkgs = document.getElementById("listPkgs"); - var domSectTypes = document.getElementById("sectTypes"); - var domListTypes = document.getElementById("listTypes"); - var domSectFns = document.getElementById("sectFns"); - var domListFns = document.getElementById("listFns"); - var domFnProto = document.getElementById("fnProto"); - var domFnProtoCode = document.getElementById("fnProtoCode"); - - var typeKindTypeId; - var typeKindFnId; - findTypeKinds(); - - // for each package, is an array with packages to get to this one - var canonPkgPaths = computeCanonicalPackagePaths(); - - var curNav = { - // each element is a package name, e.g. @import("a") then within there @import("b") - // starting implicitly from root package - pkgNames: [], - // same as above except actual packages, not names - pkgObjs: [], - // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc. - // empty array means refers to the package itself - declNames: [], - // these will be all types, except the last one may be a type or a decl - declObjs: [], - }; - - var rootIsStd = detectRootIsStd(); - var typeTypeId = findTypeTypeId(); - window.addEventListener('hashchange', onHashChange, false); - onHashChange(); - - function renderTitle() { - var list = curNav.pkgNames.concat(curNav.declNames); - var suffix = " - Zig"; - if (list.length === 0) { - if (rootIsStd) { - document.title = "std" + suffix; - } else { - document.title = zigAnalysis.params.rootName + suffix; - } - } else { - document.title = list.join('.') + suffix; - } - } - - function render() { - domStatus.classList.add("hidden"); - domFnProto.classList.add("hidden"); - - renderTitle(); - - var pkg = zigAnalysis.packages[zigAnalysis.rootPkg]; - curNav.pkgObjs = [pkg]; - for (var i = 0; i < curNav.pkgNames.length; i += 1) { - var childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]]; - if (childPkg == null) { - return render404(); - } - pkg = childPkg; - curNav.pkgObjs.push(pkg); - } - - var decl = zigAnalysis.types[pkg.main]; - curNav.declObjs = [decl]; - for (var i = 0; i < curNav.declNames.length; i += 1) { - var childDecl = findSubDecl(decl, curNav.declNames[i]); - if (childDecl == null) { - return render404(); - } - var container = getDeclContainerType(childDecl); - if (container == null) { - if (i + 1 === curNav.declNames.length) { - curNav.declObjs.push(childDecl); - break; - } else { - return render404(); - } - } - decl = container; - curNav.declObjs.push(decl); - } - - renderNav(); - - var lastPkg = curNav.pkgObjs[curNav.pkgObjs.length - 1]; - renderPkgList(lastPkg); - - var lastDecl = curNav.declObjs[curNav.declObjs.length - 1]; - if (lastDecl.pubDecls != null) { - return renderContainer(lastDecl); - } else if (lastDecl.type != null) { - var typeObj = zigAnalysis.types[lastDecl.type]; - if (typeObj.kind === typeKindFnId) { - return renderFn(lastDecl); - } - throw new Error("docs for this decl which is not a container"); - } else { - throw new Error("docs for this decl which is a type"); - } - } - - function renderFn(fnDecl) { - domSectPkgs.classList.add("hidden"); - domSectTypes.classList.add("hidden"); - domSectFns.classList.add("hidden"); - - var typeObj = zigAnalysis.types[fnDecl.type]; - domFnProtoCode.textContent = "fn " + fnDecl.name + typeObj.name.substring(2); - - domFnProto.classList.remove("hidden"); - } - - function renderNav() { - var len = curNav.pkgNames.length + curNav.declNames.length; - resizeDomList(domListNav, len, '<li><a href="#"></a></li>'); - var list = []; - var hrefPkgNames = []; - var hrefDeclNames = []; - for (var i = 0; i < curNav.pkgNames.length; i += 1) { - hrefPkgNames.push(curNav.pkgNames[i]); - list.push({ - name: curNav.pkgNames[i], - link: navLink(hrefPkgNames, hrefDeclNames), - }); - } - for (var i = 0; i < curNav.declNames.length; i += 1) { - hrefDeclNames.push(curNav.declNames[i]); - list.push({ - name: curNav.declNames[i], - link: navLink(hrefPkgNames, hrefDeclNames), - }); - } - - for (var i = 0; i < list.length; i += 1) { - var liDom = domListNav.children[i]; - var aDom = liDom.children[0]; - aDom.textContent = list[i].name; - aDom.setAttribute('href', list[i].link); - if (i + 1 == list.length) { - aDom.classList.add("active"); - } else { - aDom.classList.remove("active"); - } - } - - domSectNav.classList.remove("hidden"); - } - - function render404() { - domStatus.textContent = "404 Not Found"; - domStatus.classList.remove("hidden"); - domSectPkgs.classList.add("hidden"); - domSectTypes.classList.add("hidden"); - domSectFns.classList.add("hidden"); - domFnProto.classList.add("hidden"); - } - - function renderPkgList(pkg) { - var list = []; - for (var key in pkg.table) { - if (key === "root" && rootIsStd) continue; - list.push({ - name: key, - pkg: pkg.table[key], - }); - } - list.sort(function(a, b) { - return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase()); - }); - - if (list.length === 0) { - domSectPkgs.classList.add("hidden"); - } else { - resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>'); - for (var i = 0; i < list.length; i += 1) { - var liDom = domListPkgs.children[i]; - var aDom = liDom.children[0]; - aDom.textContent = list[i].name; - aDom.setAttribute('href', navLinkPkg(list[i].pkg)); - } - - domSectPkgs.classList.remove("hidden"); - } - } - - function navLink(pkgNames, declNames) { - if (pkgNames.length === 0 && declNames.length === 0) { - return '#'; - } else if (declNames.length === 0) { - return '#' + pkgNames.join('.'); - } else { - return '#' + pkgNames.join('.') + ';' + declNames.join('.'); - } - } - - function navLinkPkg(pkgIndex) { - return navLink(canonPkgPaths[pkgIndex], []); - } - - function navLinkDecl(childName) { - return navLink(curNav.pkgNames, curNav.declNames.concat([childName])); - } - - function resizeDomList(listDom, desiredLen, templateHtml) { - // add the missing dom entries - var i, ev; - for (i = listDom.childElementCount; i < desiredLen; i += 1) { - listDom.insertAdjacentHTML('beforeend', templateHtml); - } - // remove extra dom entries - while (desiredLen < listDom.childElementCount) { - listDom.removeChild(listDom.lastChild); - } - } - - function renderContainer(container) { - var typesList = []; - var fnsList = []; - for (var i = 0; i < container.pubDecls.length; i += 1) { - var decl = zigAnalysis.decls[container.pubDecls[i]]; - if (decl.type != null) { - if (decl.type == typeTypeId) { - typesList.push(decl); - } else { - var typeKind = zigAnalysis.types[decl.type].kind; - if (typeKind === typeKindFnId) { - fnsList.push(decl); - } - } - } - } - typesList.sort(function(a, b) { - return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase()); - }); - fnsList.sort(function(a, b) { - return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase()); - }); - - if (typesList.length === 0) { - domSectTypes.classList.add("hidden"); - } else { - resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>'); - for (var i = 0; i < typesList.length; i += 1) { - var liDom = domListTypes.children[i]; - var aDom = liDom.children[0]; - var decl = typesList[i]; - aDom.textContent = decl.name; - aDom.setAttribute('href', navLinkDecl(decl.name)); - } - domSectTypes.classList.remove("hidden"); - } - - if (fnsList.length === 0) { - domSectFns.classList.add("hidden"); - } else { - resizeDomList(domListFns, fnsList.length, '<li><a href="#"></a></li>'); - for (var i = 0; i < fnsList.length; i += 1) { - var liDom = domListFns.children[i]; - var aDom = liDom.children[0]; - var decl = fnsList[i]; - aDom.textContent = decl.name; - aDom.setAttribute('href', navLinkDecl(decl.name)); - } - domSectFns.classList.remove("hidden"); - } - } - - function operatorCompare(a, b) { - if (a === b) { - return 0; - } else if (a < b) { - return -1; - } else { - return 1; - } - } - - function detectRootIsStd() { - var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg]; - if (rootPkg.table["std"] == null) { - // no std mapped into the root package - return false; - } - var stdPkg = zigAnalysis.packages[rootPkg.table["std"]]; - return rootPkg.file === stdPkg.file; - } - - function findTypeKinds() { - for (var i = 0; i < zigAnalysis.typeKinds.length; i += 1) { - if (zigAnalysis.typeKinds[i] === "Type") { - typeKindTypeId = i; - } else if (zigAnalysis.typeKinds[i] === "Fn") { - typeKindFnId = i; - } - } - if (typeKindTypeId == null) { - throw new Error("No type kind 'Type' found"); - } - if (typeKindFnId == null) { - throw new Error("No type kind 'Fn' found"); - } - } - - function findTypeTypeId() { - for (var i = 0; i < zigAnalysis.types.length; i += 1) { - if (zigAnalysis.types[i].kind == typeKindTypeId) { - return i; - } - } - throw new Error("No type 'type' found"); - } - - function onHashChange() { - curNav = { - pkgNames: [], - pkgObjs: [], - declNames: [], - declObjs: [], - }; - if (location.hash[0] === '#' && location.hash.length > 1) { - var parts = location.hash.substring(1).split(";"); - curNav.pkgNames = parts[0].split("."); - if (parts[1] != null) { - curNav.declNames = parts[1].split("."); - } - } - render(); - } - - function findSubDecl(parentType, childName) { - if (parentType.pubDecls == null) throw new Error("parent object has no public decls"); - for (var i = 0; i < parentType.pubDecls.length; i += 1) { - var declIndex = parentType.pubDecls[i]; - var childDecl = zigAnalysis.decls[declIndex]; - if (childDecl.name === childName) { - return childDecl; - } - } - return null; - } - - function getDeclContainerType(decl) { - if (decl.type === typeTypeId) { - return zigAnalysis.types[decl.value]; - } - return null; - } - - function computeCanonicalPackagePaths() { - var list = new Array(zigAnalysis.packages.length); - // Now we try to find all the packages from root. - var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg]; - // Breadth-first to keep the path shortest possible. - var stack = [{ - path: [], - pkg: rootPkg, - }]; - while (stack.length !== 0) { - var item = stack.pop(); - for (var key in item.pkg.table) { - var childPkgIndex = item.pkg.table[key]; - if (list[childPkgIndex] != null) continue; - - var newPath = item.path.concat([key]) - list[childPkgIndex] = newPath; - var childPkg = zigAnalysis.packages[childPkgIndex]; - stack.push({ - path: newPath, - pkg: childPkg, - }); - } - } - return list; - } -})(); diff --git a/lib/std/special/docs/index.html b/lib/std/special/docs/index.html new file mode 100644 index 0000000000..2508308ced --- /dev/null +++ b/lib/std/special/docs/index.html @@ -0,0 +1,356 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Documentation - Zig</title> + <link rel="icon" href="favicon.png"> + <style type="text/css"> + body { + font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif; + max-width: 60em; + } + .hidden { + display: none; + } + a { + color: #2A6286; + } + pre{ + font-family:"Source Code Pro",monospace; + font-size:1em; + background-color:#F5F5F5; + padding:1em; + overflow-x: auto; + } + code { + font-family:"Source Code Pro",monospace; + font-size:1em; + } + nav { + width: 10em; + position: fixed; + left: 0; + top: 0; + height: 100vh; + overflow: auto; + } + nav h2 { + font-size: 1.2em; + text-decoration: underline; + margin: 0; + padding: 0.5em 0; + text-align: center; + } + nav p { + margin: 0; + padding: 0; + text-align: center; + } + section { + margin-left: 10em; + } + section h1 { + border-bottom: 1px dashed; + } + section h2 { + font-size: 1.3em; + margin: 0.5em 0; + padding: 0; + border-bottom: 1px solid; + } + #listNav { + list-style-type: none; + margin: 0.5em 0 0 0; + padding: 0; + overflow: hidden; + background-color: #f1f1f1; + } + #listNav li { + float:left; + } + #listNav li a { + display: block; + color: #000; + text-align: center; + padding: .5em .8em; + text-decoration: none; + } + #listNav li a:hover { + background-color: #555; + color: #fff; + } + #listNav li a.active { + background-color: #FFBB4D; + color: #000; + } + + #listPkgs { + list-style-type: none; + margin: 0; + padding: 0; + background-color: #f1f1f1; + } + #listPkgs li a { + display: block; + color: #000; + padding: 0.5em 1em; + text-decoration: none; + } + #listPkgs li a:hover { + background-color: #555; + color: #fff; + } + #listPkgs li a.active { + background-color: #FFBB4D; + color: #000; + } + #logo { + width: 8em; + padding: 0.5em 1em; + } + + #search { + width: 100%; + } + + #helpDialog { + width: 21em; + height: 19em; + position: fixed; + top: 0; + left: 0; + background-color: #333; + color: #fff; + border: 1px solid #fff; + } + #helpDialog h1 { + text-align: center; + font-size: 1.5em; + } + dt, dd { + display: inline; + margin: 0 0.2em; + } + kbd { + color: #000; + background-color: #fafbfc; + border-color: #d1d5da; + border-bottom-color: #c6cbd1; + box-shadow-color: #c6cbd1; + display: inline-block; + padding: 0.3em 0.2em; + font: 1.2em monospace; + line-height: 0.8em; + vertical-align: middle; + border: solid 1px; + border-radius: 3px; + box-shadow: inset 0 -1px 0; + cursor: default; + } + + #listSearchResults li.selected { + background-color: #93e196; + } + + #tableFnErrors tr td:first-child{ + text-align: right; + font-weight: bold; + vertical-align: top; + } + + #sectGlobalVars td, #sectFns td { + vertical-align: top; + margin: 0; + padding: 0.5em; + max-width: 20em; + text-overflow: ellipsis; + overflow-x: hidden; + } + + .tok-kw { + color: #333; + font-weight: bold; + } + .tok-str { + color: #d14; + } + .tok-builtin { + color: #0086b3; + } + .tok-comment { + color: #777; + font-style: italic; + } + .tok-fn { + color: #900; + font-weight: bold; + } + .tok-null { + color: #008080; + } + .tok-number { + color: #008080; + } + .tok-type { + color: #458; + font-weight: bold; + } + + @media (prefers-color-scheme: dark) { + body{ + background-color: #111; + color: #bbb; + } + a { + color: #88f; + } + pre{ + background-color:#2A2A2A; + } + #listNav { + background-color: #333; + } + #listNav li a { + color: #fff; + } + #listNav li a:hover { + background-color: #555; + color: #fff; + } + #listNav li a.active { + background-color: #FFBB4D; + color: #000; + } + #listPkgs { + background-color: #333; + } + #listPkgs li a { + color: #fff; + } + #listPkgs li a:hover { + background-color: #555; + color: #fff; + } + #listPkgs li a.active { + background-color: #FFBB4D; + color: #000; + } + #listSearchResults li.selected { + background-color: #000; + } + #listSearchResults li.selected a { + color: #fff; + } + .tok-kw { + color: #eee; + } + .tok-str { + color: #2e5; + } + .tok-builtin { + color: #ff894c; + } + .tok-comment { + color: #aa7; + } + .tok-fn { + color: #e33; + } + .tok-null { + color: #ff8080; + } + .tok-number { + color: #ff8080; + } + .tok-type { + color: #68f; + } + } + </style> + </head> + <body> + <nav> + <img alt="ZIG" id="logo" src="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAxNTAgMTAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxnIGZpbGw9IiNmN2E0MWQiPjxwYXRoIGQ9Im0wIDEwdjgwaDE5bDYtMTAgMTItMTBoLTE3di00MGgxNXYtMjB6bTQwIDB2MjBoNjJ2LTIwem05MSAwLTYgMTAtMTIgMTBoMTd2NDBoLTE1djIwaDM1di04MHptLTgzIDYwdjIwaDYydi0yMHoiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwYXRoIGQ9Im0zNyA3MC0xOCAyMHYtMTV6Ii8+PHBhdGggZD0ibTExMyAzMCAxOC0yMHYxNXoiLz48cGF0aCBkPSJtOTYuOTggMTAuNjMgMzYuMjgtMTAuNC04MC4yOSA4OS4xNy0zNi4yOCAxMC40eiIvPjwvZz48L3N2Zz4K"></img> + <div id="sectPkgs" class="hidden"> + <h2>Packages</h2> + <ul id="listPkgs"> + </ul> + </div> + <div id="sectInfo" class="hidden"> + <h2>Zig Version</h2> + <p id="tdZigVer"></p> + <h2>Target</h2> + <p id="tdTarget"></p> + </div> + </nav> + <section> + <input type="search" id="search" autocomplete="off" spellcheck="false" placeholder="`s` to search, `?` to see more options"> + <p id="status">Loading...</p> + <div id="sectNav" class="hidden"><ul id="listNav"></ul></div> + <div id="fnProto" class="hidden"> + <pre id="fnProtoCode"></pre> + </div> + <h1 id="hdrName" class="hidden"></h1> + <div id="fnDocs" class="hidden"></div> + <div id="sectFnErrors" class="hidden"> + <h2>Errors</h2> + <div id="fnErrorsAnyError"> + <p><span class="tok-type">anyerror</span> means the error set is known only at runtime.</p> + </div> + <table id="tableFnErrors"><tbody id="listFnErrors"></tbody></table> + </div> + <div id="fnExamples" class="hidden"></div> + <div id="fnNoExamples" class="hidden"> + <p>This function is not tested or referenced.</p> + </div> + <div id="sectSearchResults" class="hidden"> + <h2>Search Results</h2> + <ul id="listSearchResults"></ul> + </div> + <div id="sectSearchNoResults" class="hidden"> + <h2>No Results Found</h2> + <p>Press escape to exit search and then '?' to see more options.</p> + </div> + <div id="sectFields" class="hidden"> + <h2>Fields</h2> + <ul id="listFields"> + </ul> + </div> + <div id="sectTypes" class="hidden"> + <h2>Types</h2> + <ul id="listTypes"> + </ul> + </div> + <div id="sectGlobalVars" class="hidden"> + <h2>Global Variables</h2> + <table> + <tbody id="listGlobalVars"> + </tbody> + </table> + </div> + <div id="sectFns" class="hidden"> + <h2>Functions</h2> + <table> + <tbody id="listFns"> + </tbody> + </table> + </div> + <div id="sectErrSets" class="hidden"> + <h2>Error Sets</h2> + <ul id="listErrSets"> + </ul> + </div> + </section> + <div id="helpDialog" class="hidden"> + <h1>Keyboard Shortcuts</h1> + <dl><dt><kbd>?</kbd></dt><dd>Show this help dialog</dd></dl> + <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this dialog</dd></dl> + <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl> + <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl> + <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl> + <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl> + </div> + <script src="data.js"></script> + <script src="main.js"></script> + </body> +</html> diff --git a/lib/std/special/docs/main.js b/lib/std/special/docs/main.js new file mode 100644 index 0000000000..5d6e006748 --- /dev/null +++ b/lib/std/special/docs/main.js @@ -0,0 +1,1194 @@ +(function() { + var domStatus = document.getElementById("status"); + var domSectNav = document.getElementById("sectNav"); + var domListNav = document.getElementById("listNav"); + var domSectPkgs = document.getElementById("sectPkgs"); + var domListPkgs = document.getElementById("listPkgs"); + var domSectTypes = document.getElementById("sectTypes"); + var domListTypes = document.getElementById("listTypes"); + var domSectErrSets = document.getElementById("sectErrSets"); + var domListErrSets = document.getElementById("listErrSets"); + var domSectFns = document.getElementById("sectFns"); + var domListFns = document.getElementById("listFns"); + var domSectFields = document.getElementById("sectFields"); + var domListFields = document.getElementById("listFields"); + var domSectGlobalVars = document.getElementById("sectGlobalVars"); + var domListGlobalVars = document.getElementById("listGlobalVars"); + var domFnProto = document.getElementById("fnProto"); + var domFnProtoCode = document.getElementById("fnProtoCode"); + var domFnDocs = document.getElementById("fnDocs"); + var domSectFnErrors = document.getElementById("sectFnErrors"); + var domListFnErrors = document.getElementById("listFnErrors"); + var domTableFnErrors = document.getElementById("tableFnErrors"); + var domFnErrorsAnyError = document.getElementById("fnErrorsAnyError"); + var domFnExamples = document.getElementById("fnExamples"); + var domFnNoExamples = document.getElementById("fnNoExamples"); + var domSearch = document.getElementById("search"); + var domSectSearchResults = document.getElementById("sectSearchResults"); + var domListSearchResults = document.getElementById("listSearchResults"); + var domSectSearchNoResults = document.getElementById("sectSearchNoResults"); + var domSectInfo = document.getElementById("sectInfo"); + var domListInfo = document.getElementById("listInfo"); + var domTdTarget = document.getElementById("tdTarget"); + var domTdZigVer = document.getElementById("tdZigVer"); + var domHdrName = document.getElementById("hdrName"); + var domHelpModal = document.getElementById("helpDialog"); + + var searchTimer = null; + var escapeHtmlReplacements = { "&": "&", '"': """, "<": "<", ">": ">" }; + + var typeKindTypeId; + var typeKindFnId; + var typeKindPtrId; + var typeKindFloatId; + var typeKindIntId; + var typeKindBoolId; + var typeKindVoidId; + var typeKindErrSetId; + var typeKindErrUnionId; + findTypeKinds(); + + // for each package, is an array with packages to get to this one + var canonPkgPaths = computeCanonicalPackagePaths(); + // for each decl, is an array with {declNames, pkgNames} to get to this one + var canonDeclPaths = null; // lazy; use getCanonDeclPath + // for each type, is an array with {declNames, pkgNames} to get to this one + var canonTypeDecls = null; // lazy; use getCanonTypeDecl + + var curNav = { + // each element is a package name, e.g. @import("a") then within there @import("b") + // starting implicitly from root package + pkgNames: [], + // same as above except actual packages, not names + pkgObjs: [], + // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc. + // empty array means refers to the package itself + declNames: [], + // these will be all types, except the last one may be a type or a decl + declObjs: [], + }; + var curNavSearch = ""; + var curSearchIndex = -1; + + var rootIsStd = detectRootIsStd(); + var typeTypeId = findTypeTypeId(); + + // map of decl index to list of non-generic fn indexes + var nodesToFnsMap = indexNodesToFns(); + // map of decl index to list of comptime fn calls + var nodesToCallsMap = indexNodesToCalls(); + + domSearch.addEventListener('keydown', onSearchKeyDown, false); + window.addEventListener('hashchange', onHashChange, false); + window.addEventListener('keydown', onWindowKeyDown, false); + onHashChange(); + + function renderTitle() { + var list = curNav.pkgNames.concat(curNav.declNames); + var suffix = " - Zig"; + if (list.length === 0) { + if (rootIsStd) { + document.title = "std" + suffix; + } else { + document.title = zigAnalysis.params.rootName + suffix; + } + } else { + document.title = list.join('.') + suffix; + } + } + + function render() { + domStatus.classList.add("hidden"); + domFnProto.classList.add("hidden"); + domFnDocs.classList.add("hidden"); + domSectPkgs.classList.add("hidden"); + domSectTypes.classList.add("hidden"); + domSectErrSets.classList.add("hidden"); + domSectFns.classList.add("hidden"); + domSectFields.classList.add("hidden"); + domSectSearchResults.classList.add("hidden"); + domSectSearchNoResults.classList.add("hidden"); + domSectInfo.classList.add("hidden"); + domHdrName.classList.add("hidden"); + domSectNav.classList.add("hidden"); + domSectFnErrors.classList.add("hidden"); + domFnExamples.classList.add("hidden"); + domFnNoExamples.classList.add("hidden"); + domFnErrorsAnyError.classList.add("hidden"); + domTableFnErrors.classList.add("hidden"); + domSectGlobalVars.classList.add("hidden"); + + renderTitle(); + renderInfo(); + renderPkgList(); + + if (curNavSearch !== "") { + return renderSearch(); + } + + var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg]; + var pkg = rootPkg; + curNav.pkgObjs = [pkg]; + for (var i = 0; i < curNav.pkgNames.length; i += 1) { + var childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]]; + if (childPkg == null) { + return render404(); + } + pkg = childPkg; + curNav.pkgObjs.push(pkg); + } + + var decl = zigAnalysis.types[pkg.main]; + curNav.declObjs = [decl]; + for (var i = 0; i < curNav.declNames.length; i += 1) { + var childDecl = findSubDecl(decl, curNav.declNames[i]); + if (childDecl == null) { + return render404(); + } + var container = getDeclContainerType(childDecl); + if (container == null) { + if (i + 1 === curNav.declNames.length) { + curNav.declObjs.push(childDecl); + break; + } else { + return render404(); + } + } + decl = container; + curNav.declObjs.push(decl); + } + + renderNav(); + + var lastDecl = curNav.declObjs[curNav.declObjs.length - 1]; + if (lastDecl.kind === 'var') { + return renderVar(lastDecl); + } + if (lastDecl.type != null) { + var typeObj = zigAnalysis.types[lastDecl.type]; + if (typeObj.kind === typeKindFnId) { + return renderFn(lastDecl); + } + throw new Error("docs for this decl which is not a container"); + } + renderType(lastDecl); + if (lastDecl.pubDecls != null) { + renderContainer(lastDecl); + } + } + + function typeIsErrSet(typeIndex) { + var typeObj = zigAnalysis.types[typeIndex]; + return typeObj.kind === typeKindErrSetId; + } + + function typeIsGenericFn(typeIndex) { + var typeObj = zigAnalysis.types[typeIndex]; + if (typeObj.kind !== typeKindFnId) { + return false; + } + return typeObj.generic; + } + + function renderFn(fnDecl) { + domFnProtoCode.innerHTML = typeIndexName(fnDecl.type, true, true, fnDecl); + + var docsSource = null; + var srcNode = zigAnalysis.astNodes[fnDecl.src]; + if (srcNode.docs != null) { + docsSource = srcNode.docs; + } + + var typeObj = zigAnalysis.types[fnDecl.type]; + var errSetTypeIndex = null; + if (typeObj.ret != null) { + var retType = zigAnalysis.types[typeObj.ret]; + if (retType.kind === typeKindErrSetId) { + errSetTypeIndex = typeObj.ret; + } else if (retType.kind === typeKindErrUnionId) { + errSetTypeIndex = retType.err; + } + } + if (errSetTypeIndex != null) { + var errSetType = zigAnalysis.types[errSetTypeIndex]; + if (errSetType.errors == null) { + domFnErrorsAnyError.classList.remove("hidden"); + } else { + var errorList = []; + for (var i = 0; i < errSetType.errors.length; i += 1) { + var errObj = zigAnalysis.errors[errSetType.errors[i]]; + var srcObj = zigAnalysis.astNodes[errObj.src]; + errorList.push({ + err: errObj, + docs: srcObj.docs, + }); + } + errorList.sort(function(a, b) { + return operatorCompare(a.err.name.toLowerCase(), b.err.name.toLowerCase()); + }); + + resizeDomList(domListFnErrors, errorList.length, '<tr><td></td><td></td></tr>'); + for (var i = 0; i < errorList.length; i += 1) { + var trDom = domListFnErrors.children[i]; + var nameTdDom = trDom.children[0]; + var descTdDom = trDom.children[1]; + nameTdDom.textContent = errorList[i].err.name; + var docs = errorList[i].docs; + if (docs != null) { + descTdDom.innerHTML = markdown(docs); + } else { + descTdDom.textContent = ""; + } + } + domTableFnErrors.classList.remove("hidden"); + } + domSectFnErrors.classList.remove("hidden"); + } + + var protoSrcIndex; + if (typeIsGenericFn(fnDecl.type)) { + protoSrcIndex = fnDecl.value; + + var instantiations = nodesToFnsMap[protoSrcIndex]; + var calls = nodesToCallsMap[protoSrcIndex]; + if (instantiations == null && calls == null) { + domFnNoExamples.classList.remove("hidden"); + } else { + // TODO show examples + domFnExamples.classList.remove("hidden"); + } + } else { + protoSrcIndex = zigAnalysis.fns[fnDecl.value].src; + + domFnExamples.classList.add("hidden"); + domFnNoExamples.classList.add("hidden"); + } + + var protoSrcNode = zigAnalysis.astNodes[protoSrcIndex]; + if (docsSource == null && protoSrcNode != null && protoSrcNode.docs != null) { + docsSource = protoSrcNode.docs; + } + if (docsSource != null) { + domFnDocs.innerHTML = markdown(docsSource); + domFnDocs.classList.remove("hidden"); + } + domFnProto.classList.remove("hidden"); + } + + function renderNav() { + var len = curNav.pkgNames.length + curNav.declNames.length; + resizeDomList(domListNav, len, '<li><a href="#"></a></li>'); + var list = []; + var hrefPkgNames = []; + var hrefDeclNames = []; + for (var i = 0; i < curNav.pkgNames.length; i += 1) { + hrefPkgNames.push(curNav.pkgNames[i]); + list.push({ + name: curNav.pkgNames[i], + link: navLink(hrefPkgNames, hrefDeclNames), + }); + } + for (var i = 0; i < curNav.declNames.length; i += 1) { + hrefDeclNames.push(curNav.declNames[i]); + list.push({ + name: curNav.declNames[i], + link: navLink(hrefPkgNames, hrefDeclNames), + }); + } + + for (var i = 0; i < list.length; i += 1) { + var liDom = domListNav.children[i]; + var aDom = liDom.children[0]; + aDom.textContent = list[i].name; + aDom.setAttribute('href', list[i].link); + if (i + 1 == list.length) { + aDom.classList.add("active"); + } else { + aDom.classList.remove("active"); + } + } + + domSectNav.classList.remove("hidden"); + } + + function renderInfo() { + domTdZigVer.textContent = zigAnalysis.params.zigVersion; + domTdTarget.textContent = zigAnalysis.params.target; + + domSectInfo.classList.remove("hidden"); + } + + function render404() { + domStatus.textContent = "404 Not Found"; + domStatus.classList.remove("hidden"); + } + + function renderPkgList() { + var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg]; + var list = []; + for (var key in rootPkg.table) { + if (key === "root" && rootIsStd) continue; + var pkgIndex = rootPkg.table[key]; + if (zigAnalysis.packages[pkgIndex] == null) continue; + list.push({ + name: key, + pkg: pkgIndex, + }); + } + list.sort(function(a, b) { + return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase()); + }); + + if (list.length !== 0) { + resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>'); + for (var i = 0; i < list.length; i += 1) { + var liDom = domListPkgs.children[i]; + var aDom = liDom.children[0]; + aDom.textContent = list[i].name; + aDom.setAttribute('href', navLinkPkg(list[i].pkg)); + if (list[i].name === curNav.pkgNames[0]) { + aDom.classList.add("active"); + } else { + aDom.classList.remove("active"); + } + } + + domSectPkgs.classList.remove("hidden"); + } + } + + function navLink(pkgNames, declNames) { + if (pkgNames.length === 0 && declNames.length === 0) { + return '#'; + } else if (declNames.length === 0) { + return '#' + pkgNames.join('.'); + } else { + return '#' + pkgNames.join('.') + ';' + declNames.join('.'); + } + } + + function navLinkPkg(pkgIndex) { + return navLink(canonPkgPaths[pkgIndex], []); + } + + function navLinkDecl(childName) { + return navLink(curNav.pkgNames, curNav.declNames.concat([childName])); + } + + function resizeDomList(listDom, desiredLen, templateHtml) { + // add the missing dom entries + var i, ev; + for (i = listDom.childElementCount; i < desiredLen; i += 1) { + listDom.insertAdjacentHTML('beforeend', templateHtml); + } + // remove extra dom entries + while (desiredLen < listDom.childElementCount) { + listDom.removeChild(listDom.lastChild); + } + } + + function typeIndexName(typeIndex, wantHtml, wantLink, fnDecl, skipFnName) { + var typeObj = zigAnalysis.types[typeIndex]; + if (wantLink) { + var declIndex = getCanonTypeDecl(typeIndex); + var declPath = getCanonDeclPath(declIndex); + var haveLink = declPath != null; + var typeNameHtml = typeName(typeObj, true, !haveLink, fnDecl, skipFnName); + if (haveLink) { + return '<a href="' + navLink(declPath.pkgNames, declPath.declNames) + '">' + typeNameHtml + '</a>'; + } else { + return typeNameHtml; + } + } else { + return typeName(typeObj, wantHtml, false, fnDecl, skipFnName); + } + } + + function typeName(typeObj, wantHtml, wantSubLink, fnDecl, skipFnName) { + switch (typeObj.kind) { + case typeKindPtrId: + var name = ""; + switch (typeObj.len) { + case 0: + default: + name += "*"; + break; + case 1: + name += "[*]"; + break; + case 2: + name += "[]"; + break; + case 3: + name += "[*c]"; + break; + } + if (typeObj['const']) { + if (wantHtml) { + name += '<span class="tok-kw">const</span> '; + } else { + name += "const "; + } + } + if (typeObj['volatile']) { + if (wantHtml) { + name += '<span class="tok-kw">volatile</span> '; + } else { + name += "volatile "; + } + } + if (typeObj.align != null) { + if (wantHtml) { + name += '<span class="tok-kw">align</span>('; + } else { + name += "align("; + } + if (wantHtml) { + name += '<span class="tok-number">' + typeObj.align + '</span>'; + } else { + name += typeObj.align; + } + if (typeObj.hostIntBytes != null) { + name += ":"; + if (wantHtml) { + name += '<span class="tok-number">' + typeObj.bitOffsetInHost + '</span>'; + } else { + name += typeObj.bitOffsetInHost; + } + name += ":"; + if (wantHtml) { + name += '<span class="tok-number">' + typeObj.hostIntBytes + '</span>'; + } else { + name += typeObj.hostIntBytes; + } + } + name += ") "; + } + name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null); + return name; + case typeKindFloatId: + if (wantHtml) { + return '<span class="tok-type">f' + typeObj.bits + '</span>'; + } else { + return "f" + typeObj.bits; + } + case typeKindIntId: + var signed = (typeObj.i != null) ? 'i' : 'u'; + var bits = typeObj[signed]; + if (wantHtml) { + return '<span class="tok-type">' + signed + bits + '</span>'; + } else { + return signed + bits; + } + case typeKindTypeId: + if (wantHtml) { + return '<span class="tok-type">type</span>'; + } else { + return "type"; + } + case typeKindBoolId: + if (wantHtml) { + return '<span class="tok-type">bool</span>'; + } else { + return "bool"; + } + case typeKindVoidId: + if (wantHtml) { + return '<span class="tok-type">void</span>'; + } else { + return "void"; + } + case typeKindErrSetId: + if (typeObj.errors == null) { + if (wantHtml) { + return '<span class="tok-type">anyerror</span>'; + } else { + return "anyerror"; + } + } else { + if (wantHtml) { + return escapeHtml(typeObj.name); + } else { + return typeObj.name; + } + } + case typeKindErrUnionId: + var errSetTypeObj = zigAnalysis.types[typeObj.err]; + var payloadHtml = typeIndexName(typeObj.payload, wantHtml, wantSubLink, null); + if (fnDecl != null && errSetTypeObj.fn === fnDecl.value) { + // function index parameter supplied and this is the inferred error set of it + return "!" + payloadHtml; + } else { + return typeIndexName(typeObj.err, wantHtml, wantSubLink, null) + "!" + payloadHtml; + } + case typeKindFnId: + var payloadHtml = ""; + if (wantHtml) { + payloadHtml += '<span class="tok-kw">fn</span>'; + if (fnDecl != null && !skipFnName) { + payloadHtml += ' <span class="tok-fn">' + escapeHtml(fnDecl.name) + '</span>'; + } + } else { + payloadHtml += 'fn' + } + payloadHtml += '('; + if (typeObj.args != null) { + for (var i = 0; i < typeObj.args.length; i += 1) { + if (i != 0) { + payloadHtml += ', '; + } + var argTypeIndex = typeObj.args[i]; + if (argTypeIndex != null) { + payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink); + } else if (wantHtml) { + payloadHtml += '<span class="tok-kw">var</span>'; + } else { + payloadHtml += 'var'; + } + } + } + + payloadHtml += ') '; + if (typeObj.ret != null) { + payloadHtml += typeIndexName(typeObj.ret, wantHtml, wantSubLink, fnDecl); + } else if (wantHtml) { + payloadHtml += '<span class="tok-kw">var</span>'; + } else { + payloadHtml += 'var'; + } + return payloadHtml; + default: + if (wantHtml) { + return escapeHtml(typeObj.name); + } else { + return typeObj.name; + } + } + } + + function renderType(typeObj) { + var name = typeName(typeObj, false, false); + if (name != null && name != "") { + domHdrName.innerText = zigAnalysis.typeKinds[typeObj.kind] + " " + name; + domHdrName.classList.remove("hidden"); + } + } + + function allCompTimeFnCallsHaveTypeResult(typeIndex, value) { + var srcIndex = typeIsGenericFn(typeIndex) ? value : zigAnalysis.fns[value].src; + var calls = nodesToCallsMap[srcIndex]; + if (calls == null) return false; + for (var i = 0; i < calls.length; i += 1) { + var call = zigAnalysis.calls[calls[i]]; + if (call.result.type !== typeTypeId) return false; + } + return true; + } + + function renderVar(decl) { + domFnProtoCode.innerHTML = '<span class="tok-kw">pub</span> <span class="tok-kw">var</span> ' + + escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true); + + var docs = zigAnalysis.astNodes[decl.src].docs; + if (docs != null) { + domFnDocs.innerHTML = markdown(docs); + domFnDocs.classList.remove("hidden"); + } + + domFnProto.classList.remove("hidden"); + } + + function renderContainer(container) { + var typesList = []; + var errSetsList = []; + var fnsList = []; + var varsList = []; + for (var i = 0; i < container.pubDecls.length; i += 1) { + var decl = zigAnalysis.decls[container.pubDecls[i]]; + if (decl.kind === 'var') { + varsList.push(decl); + continue; + } + if (decl.type != null) { + if (decl.type == typeTypeId) { + if (typeIsErrSet(decl.value)) { + errSetsList.push(decl); + } else { + typesList.push(decl); + } + } else { + var typeKind = zigAnalysis.types[decl.type].kind; + if (typeKind === typeKindFnId) { + if (allCompTimeFnCallsHaveTypeResult(decl.type, decl.value)) { + typesList.push(decl); + } else { + fnsList.push(decl); + } + } + } + } + } + typesList.sort(function(a, b) { + return operatorCompare(a.name, b.name); + }); + errSetsList.sort(function(a, b) { + return operatorCompare(a.name, b.name); + }); + fnsList.sort(function(a, b) { + return operatorCompare(a.name, b.name); + }); + varsList.sort(function(a, b) { + return operatorCompare(a.name, b.name); + }); + + if (typesList.length !== 0) { + resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>'); + for (var i = 0; i < typesList.length; i += 1) { + var liDom = domListTypes.children[i]; + var aDom = liDom.children[0]; + var decl = typesList[i]; + aDom.textContent = decl.name; + aDom.setAttribute('href', navLinkDecl(decl.name)); + } + domSectTypes.classList.remove("hidden"); + } + + if (errSetsList.length !== 0) { + resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>'); + for (var i = 0; i < errSetsList.length; i += 1) { + var liDom = domListErrSets.children[i]; + var aDom = liDom.children[0]; + var decl = errSetsList[i]; + aDom.textContent = decl.name; + aDom.setAttribute('href', navLinkDecl(decl.name)); + } + domSectErrSets.classList.remove("hidden"); + } + + if (fnsList.length !== 0) { + resizeDomList(domListFns, fnsList.length, + '<tr><td><a href="#"></a></td><td></td><td></td></tr>'); + for (var i = 0; i < fnsList.length; i += 1) { + var decl = fnsList[i]; + var trDom = domListFns.children[i]; + + var tdName = trDom.children[0]; + var tdNameA = tdName.children[0]; + var tdType = trDom.children[1]; + var tdDesc = trDom.children[2]; + + tdNameA.setAttribute('href', navLinkDecl(decl.name)); + tdNameA.textContent = decl.name; + + tdType.innerHTML = typeIndexName(decl.type, true, true, decl, true); + + var docs = zigAnalysis.astNodes[decl.src].docs; + if (docs != null) { + tdDesc.innerHTML = shortDescMarkdown(docs); + } else { + tdDesc.textContent = ""; + } + } + domSectFns.classList.remove("hidden"); + } + + if (container.fields.length !== 0) { + resizeDomList(domListFields, container.fields.length, '<li></li>'); + for (var i = 0; i < container.fields.length; i += 1) { + var liDom = domListFields.children[i]; + var field = container.fields[i]; + + var protoHtml = escapeHtml(field.name) + ": "; + protoHtml += typeIndexName(field.type, true, true); + liDom.innerHTML = protoHtml; + } + domSectFields.classList.remove("hidden"); + } + + if (varsList.length !== 0) { + resizeDomList(domListGlobalVars, varsList.length, + '<tr><td><a href="#"></a></td><td></td><td></td></tr>'); + for (var i = 0; i < varsList.length; i += 1) { + var decl = varsList[i]; + var trDom = domListGlobalVars.children[i]; + + var tdName = trDom.children[0]; + var tdNameA = tdName.children[0]; + var tdType = trDom.children[1]; + var tdDesc = trDom.children[2]; + + tdNameA.setAttribute('href', navLinkDecl(decl.name)); + tdNameA.textContent = decl.name; + + tdType.innerHTML = typeIndexName(decl.type, true, true); + + var docs = zigAnalysis.astNodes[decl.src].docs; + if (docs != null) { + tdDesc.innerHTML = shortDescMarkdown(docs); + } else { + tdDesc.textContent = ""; + } + } + domSectGlobalVars.classList.remove("hidden"); + } + } + + function operatorCompare(a, b) { + if (a === b) { + return 0; + } else if (a < b) { + return -1; + } else { + return 1; + } + } + + function detectRootIsStd() { + var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg]; + if (rootPkg.table["std"] == null) { + // no std mapped into the root package + return false; + } + var stdPkg = zigAnalysis.packages[rootPkg.table["std"]]; + if (stdPkg == null) return false; + return rootPkg.file === stdPkg.file; + } + + function findTypeKinds() { + for (var i = 0; i < zigAnalysis.typeKinds.length; i += 1) { + if (zigAnalysis.typeKinds[i] === "Type") { + typeKindTypeId = i; + } else if (zigAnalysis.typeKinds[i] === "Fn") { + typeKindFnId = i; + } else if (zigAnalysis.typeKinds[i] === "Pointer") { + typeKindPtrId = i; + } else if (zigAnalysis.typeKinds[i] === "Float") { + typeKindFloatId = i; + } else if (zigAnalysis.typeKinds[i] === "Int") { + typeKindIntId = i; + } else if (zigAnalysis.typeKinds[i] === "Bool") { + typeKindBoolId = i; + } else if (zigAnalysis.typeKinds[i] === "Void") { + typeKindVoidId = i; + } else if (zigAnalysis.typeKinds[i] === "ErrorSet") { + typeKindErrSetId = i; + } else if (zigAnalysis.typeKinds[i] === "ErrorUnion") { + typeKindErrUnionId = i; + } + } + if (typeKindTypeId == null) { + throw new Error("No type kind 'Type' found"); + } + if (typeKindFnId == null) { + throw new Error("No type kind 'Fn' found"); + } + if (typeKindPtrId == null) { + throw new Error("No type kind 'Pointer' found"); + } + if (typeKindFloatId == null) { + throw new Error("No type kind 'Float' found"); + } + if (typeKindIntId == null) { + throw new Error("No type kind 'Int' found"); + } + if (typeKindBoolId == null) { + throw new Error("No type kind 'Bool' found"); + } + if (typeKindVoidId == null) { + throw new Error("No type kind 'Void' found"); + } + if (typeKindErrSetId == null) { + throw new Error("No type kind 'ErrorSet' found"); + } + if (typeKindErrUnionId == null) { + throw new Error("No type kind 'ErrorUnion' found"); + } + } + + function findTypeTypeId() { + for (var i = 0; i < zigAnalysis.types.length; i += 1) { + if (zigAnalysis.types[i].kind == typeKindTypeId) { + return i; + } + } + throw new Error("No type 'type' found"); + } + + function onHashChange() { + curNav = { + pkgNames: [], + pkgObjs: [], + declNames: [], + declObjs: [], + }; + curNavSearch = ""; + + if (location.hash[0] === '#' && location.hash.length > 1) { + var query = location.hash.substring(1); + var qpos = query.indexOf("?"); + if (qpos === -1) { + nonSearchPart = query; + } else { + nonSearchPart = query.substring(0, qpos); + curNavSearch = decodeURIComponent(query.substring(qpos + 1)); + } + + var parts = nonSearchPart.split(";"); + curNav.pkgNames = decodeURIComponent(parts[0]).split("."); + if (parts[1] != null) { + curNav.declNames = decodeURIComponent(parts[1]).split("."); + } + } + if (domSearch.value !== curNavSearch) { + domSearch.value = curNavSearch; + } + render(); + } + + function findSubDecl(parentType, childName) { + if (parentType.pubDecls == null) throw new Error("parent object has no public decls"); + for (var i = 0; i < parentType.pubDecls.length; i += 1) { + var declIndex = parentType.pubDecls[i]; + var childDecl = zigAnalysis.decls[declIndex]; + if (childDecl.name === childName) { + return childDecl; + } + } + return null; + } + + function getDeclContainerType(decl) { + if (decl.type === typeTypeId) { + return zigAnalysis.types[decl.value]; + } + return null; + } + + function computeCanonicalPackagePaths() { + var list = new Array(zigAnalysis.packages.length); + // Now we try to find all the packages from root. + var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg]; + // Breadth-first to keep the path shortest possible. + var stack = [{ + path: [], + pkg: rootPkg, + }]; + while (stack.length !== 0) { + var item = stack.shift(); + for (var key in item.pkg.table) { + var childPkgIndex = item.pkg.table[key]; + if (list[childPkgIndex] != null) continue; + var childPkg = zigAnalysis.packages[childPkgIndex]; + if (childPkg == null) continue; + + var newPath = item.path.concat([key]) + list[childPkgIndex] = newPath; + stack.push({ + path: newPath, + pkg: childPkg, + }); + } + } + return list; + } + + function computeCanonDeclPaths() { + var list = new Array(zigAnalysis.decls.length); + canonTypeDecls = new Array(zigAnalysis.types.length); + + for (var pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) { + if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue; + var pkg = zigAnalysis.packages[pkgI]; + var pkgNames = canonPkgPaths[pkgI]; + var stack = [{ + declNames: [], + type: zigAnalysis.types[pkg.main], + }]; + while (stack.length !== 0) { + var item = stack.shift(); + + if (item.type.pubDecls != null) { + for (var declI = 0; declI < item.type.pubDecls.length; declI += 1) { + var mainDeclIndex = item.type.pubDecls[declI]; + if (list[mainDeclIndex] != null) continue; + + var decl = zigAnalysis.decls[mainDeclIndex]; + if (decl.type === typeTypeId) { + canonTypeDecls[decl.value] = mainDeclIndex; + } + var declNames = item.declNames.concat([decl.name]); + list[mainDeclIndex] = { + pkgNames: pkgNames, + declNames: declNames, + }; + var containerType = getDeclContainerType(decl); + if (containerType != null) { + stack.push({ + declNames: declNames, + type: containerType, + }); + } + } + } + } + } + return list; + } + + function getCanonDeclPath(index) { + if (canonDeclPaths == null) { + canonDeclPaths = computeCanonDeclPaths(); + } + return canonDeclPaths[index]; + } + + function getCanonTypeDecl(index) { + getCanonDeclPath(0); + return canonTypeDecls[index]; + } + + function escapeHtml(text) { + return text.replace(/[&"<>]/g, function (m) { + return escapeHtmlReplacements[m]; + }); + } + + function shortDescMarkdown(docs) { + var parts = docs.trim().split("\n"); + var firstLine = parts[0]; + return markdown(firstLine); + } + + function markdown(mdText) { + // TODO implement more + return escapeHtml(mdText); + } + + function onSearchKeyDown(ev) { + switch (ev.which) { + case 13: + var liDom = domListSearchResults.children[curSearchIndex]; + if (liDom == null && domListSearchResults.children.length !== 0) { + liDom = domListSearchResults.children[0]; + } + if (liDom != null) { + var aDom = liDom.children[0]; + location.href = aDom.getAttribute("href"); + curSearchIndex = -1; + ev.preventDefault(); + ev.stopPropagation(); + return; + } + case 27: + domSearch.value = ""; + domSearch.blur(); + curSearchIndex = -1; + ev.preventDefault(); + ev.stopPropagation(); + startSearch(); + return; + case 38: + moveSearchCursor(-1); + ev.preventDefault(); + ev.stopPropagation(); + return; + case 40: + moveSearchCursor(1); + ev.preventDefault(); + ev.stopPropagation(); + return; + default: + curSearchIndex = -1; + ev.stopPropagation(); + startAsyncSearch(); + } + } + + function moveSearchCursor(dir) { + if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) { + if (dir > 0) { + curSearchIndex = -1 + dir; + } else if (dir < 0) { + curSearchIndex = domListSearchResults.children.length + dir; + } + } else { + curSearchIndex += dir; + } + if (curSearchIndex < 0) { + curSearchIndex = 0; + } + if (curSearchIndex >= domListSearchResults.children.length) { + curSearchIndex = domListSearchResults.children.length - 1; + } + renderSearchCursor(); + } + + function onWindowKeyDown(ev) { + switch (ev.which) { + case 27: + if (!domHelpModal.classList.contains("hidden")) { + domHelpModal.classList.add("hidden"); + ev.preventDefault(); + ev.stopPropagation(); + } + break; + case 83: + domSearch.focus(); + domSearch.select(); + ev.preventDefault(); + ev.stopPropagation(); + startAsyncSearch(); + break; + case 191: + ev.preventDefault(); + ev.stopPropagation(); + showHelpModal(); + break; + } + } + + function showHelpModal() { + domHelpModal.classList.remove("hidden"); + domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px"; + domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px"; + domHelpModal.focus(); + } + + function clearAsyncSearch() { + if (searchTimer != null) clearTimeout(searchTimer); + } + + function startAsyncSearch() { + clearAsyncSearch(); + searchTimer = setTimeout(startSearch, 100); + } + function startSearch() { + var parts = location.hash.split("?"); + var newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value); + if (parts.length === 1) { + location.hash = location.hash + newPart2; + } else { + location.hash = parts[0] + newPart2; + } + } + function renderSearch() { + var matchedItems = []; + var ignoreCase = (curNavSearch.toLowerCase() === curNavSearch); + var terms = curNavSearch.split(/[ \r\n\t]+/); + + decl_loop: for (var declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) { + var canonPath = getCanonDeclPath(declIndex); + if (canonPath == null) continue; + + var decl = zigAnalysis.decls[declIndex]; + var lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1]; + var fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.'); + var astNode = zigAnalysis.astNodes[decl.src]; + var fileAndDocs = zigAnalysis.files[astNode.file]; + if (astNode.docs != null) { + fileAndDocs += "\n" + astNode.docs; + } + var fullPathSearchTextLower = fullPathSearchText; + if (ignoreCase) { + fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase(); + fileAndDocs = fileAndDocs.toLowerCase(); + } + + var points = 0; + for (var termIndex = 0; termIndex < terms.length; termIndex += 1) { + var term = terms[termIndex]; + + // exact, case sensitive match of full decl path + if (fullPathSearchText === term) { + points += 4; + continue; + } + // exact, case sensitive match of just decl name + if (decl.name == term) { + points += 3; + continue; + } + // substring, case insensitive match of full decl path + if (fullPathSearchTextLower.indexOf(term) >= 0) { + points += 2; + continue; + } + if (fileAndDocs.indexOf(term) >= 0) { + points += 1; + continue; + } + + continue decl_loop; + } + + matchedItems.push({ + decl: decl, + path: canonPath, + points: points, + }); + } + + if (matchedItems.length !== 0) { + resizeDomList(domListSearchResults, matchedItems.length, '<li><a href="#"></a></li>'); + + matchedItems.sort(function(a, b) { + var cmp = operatorCompare(b.points, a.points); + if (cmp != 0) return cmp; + return operatorCompare(a.decl.name, b.decl.name); + }); + + for (var i = 0; i < matchedItems.length; i += 1) { + var liDom = domListSearchResults.children[i]; + var aDom = liDom.children[0]; + var match = matchedItems[i]; + var lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1]; + aDom.textContent = lastPkgName + "." + match.path.declNames.join('.'); + aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames)); + } + renderSearchCursor(); + + domSectSearchResults.classList.remove("hidden"); + } else { + domSectSearchNoResults.classList.remove("hidden"); + } + } + + function renderSearchCursor() { + for (var i = 0; i < domListSearchResults.children.length; i += 1) { + var liDom = domListSearchResults.children[i]; + if (curSearchIndex === i) { + liDom.classList.add("selected"); + } else { + liDom.classList.remove("selected"); + } + } + } + + function indexNodesToFns() { + var map = {}; + for (var i = 0; i < zigAnalysis.fns.length; i += 1) { + var fn = zigAnalysis.fns[i]; + if (typeIsGenericFn(fn.type)) continue; + if (map[fn.src] == null) { + map[fn.src] = [i]; + } else { + map[fn.src].push(i); + } + } + return map; + } + + function indexNodesToCalls() { + var map = {}; + for (var i = 0; i < zigAnalysis.calls.length; i += 1) { + var call = zigAnalysis.calls[i]; + var fn = zigAnalysis.fns[call.fn]; + if (map[fn.src] == null) { + map[fn.src] = [i]; + } else { + map[fn.src].push(i); + } + } + return map; + } +})(); diff --git a/lib/std/special/start_windows_tls.zig b/lib/std/special/start_windows_tls.zig index 71165d355b..bfd0e44122 100644 --- a/lib/std/special/start_windows_tls.zig +++ b/lib/std/special/start_windows_tls.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; export var _tls_start: u8 linksection(".tls") = 0; @@ -6,6 +7,17 @@ export var _tls_end: u8 linksection(".tls$ZZZ") = 0; export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; +comptime { + if (builtin.arch == .i386) { + // The __tls_array is the offset of the ThreadLocalStoragePointer field + // in the TEB block whose base address held in the %fs segment. + asm ( + \\ .global __tls_array + \\ __tls_array = 0x2C + ); + } +} + // TODO this is how I would like it to be expressed // TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate // why they do that. diff --git a/lib/std/std.zig b/lib/std/std.zig index 1c64242c4b..3c5655e8f3 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -62,61 +62,69 @@ pub const unicode = @import("unicode.zig"); pub const valgrind = @import("valgrind.zig"); pub const zig = @import("zig.zig"); -test "std" { - // run tests from these - _ = @import("array_list.zig"); - _ = @import("atomic.zig"); - _ = @import("bloom_filter.zig"); - _ = @import("buf_map.zig"); - _ = @import("buf_set.zig"); - _ = @import("buffer.zig"); - _ = @import("hash_map.zig"); - _ = @import("linked_list.zig"); - _ = @import("mutex.zig"); - _ = @import("statically_initialized_mutex.zig"); - _ = @import("segmented_list.zig"); - _ = @import("spinlock.zig"); - _ = @import("child_process.zig"); +// Reference everything so it gets tested. +test "" { + _ = AlignedArrayList; + _ = ArrayList; + _ = AutoHashMap; + _ = BloomFilter; + _ = BufMap; + _ = BufSet; + _ = Buffer; + _ = BufferOutStream; + _ = DynLib; + _ = HashMap; + _ = Mutex; + _ = PackedIntArrayEndian; + _ = PackedIntArray; + _ = PackedIntSliceEndian; + _ = PackedIntSlice; + _ = PriorityQueue; + _ = SinglyLinkedList; + _ = StaticallyInitializedMutex; + _ = SegmentedList; + _ = SpinLock; + _ = StringHashMap; + _ = ChildProcess; + _ = TailQueue; + _ = Thread; - _ = @import("ascii.zig"); - _ = @import("base64.zig"); - _ = @import("build.zig"); - _ = @import("c.zig"); - _ = @import("coff.zig"); - _ = @import("crypto.zig"); - _ = @import("cstr.zig"); - _ = @import("debug.zig"); - _ = @import("dwarf.zig"); - _ = @import("dynamic_library.zig"); - _ = @import("elf.zig"); - _ = @import("event.zig"); - _ = @import("fmt.zig"); - _ = @import("fs.zig"); - _ = @import("hash.zig"); - _ = @import("heap.zig"); - _ = @import("http.zig"); - _ = @import("io.zig"); - _ = @import("json.zig"); - _ = @import("lazy_init.zig"); - _ = @import("macho.zig"); - _ = @import("math.zig"); - _ = @import("mem.zig"); - _ = @import("meta.zig"); - _ = @import("net.zig"); - _ = @import("os.zig"); - _ = @import("pdb.zig"); - _ = @import("process.zig"); - _ = @import("packed_int_array.zig"); - _ = @import("priority_queue.zig"); - _ = @import("rand.zig"); - _ = @import("rb.zig"); - _ = @import("sort.zig"); - _ = @import("testing.zig"); - _ = @import("thread.zig"); - _ = @import("time.zig"); - _ = @import("unicode.zig"); - _ = @import("valgrind.zig"); - _ = @import("zig.zig"); - - _ = @import("debug/leb128.zig"); + _ = atomic; + _ = base64; + _ = build; + _ = c; + _ = coff; + _ = crypto; + _ = cstr; + _ = debug; + _ = dwarf; + _ = elf; + _ = event; + _ = fmt; + _ = fs; + _ = hash; + _ = hash_map; + _ = heap; + _ = http; + _ = io; + _ = json; + _ = lazyInit; + _ = macho; + _ = math; + _ = mem; + _ = meta; + _ = net; + _ = os; + _ = packed_int_array; + _ = pdb; + _ = process; + _ = rand; + _ = rb; + _ = sort; + _ = ascii; + _ = testing; + _ = time; + _ = unicode; + _ = valgrind; + _ = zig; } diff --git a/src/all_types.hpp b/src/all_types.hpp index 1119d2bf4e..c9f905118f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -589,6 +589,7 @@ enum NodeType { NodeTypeIfErrorExpr, NodeTypeIfOptional, NodeTypeErrorSetDecl, + NodeTypeErrorSetField, NodeTypeResume, NodeTypeAwaitExpr, NodeTypeSuspend, @@ -612,16 +613,10 @@ enum FnInline { }; struct AstNodeFnProto { - VisibMod visib_mod; Buf *name; ZigList<AstNode *> params; AstNode *return_type; Token *return_var_token; - bool is_var_args; - bool is_extern; - bool is_export; - FnInline fn_inline; - CallingConvention cc; AstNode *fn_def_node; // populated if this is an extern declaration Buf *lib_name; @@ -629,8 +624,16 @@ struct AstNodeFnProto { AstNode *align_expr; // populated if the "section(S)" is present AstNode *section_expr; + Buf doc_comments; + FnInline fn_inline; + CallingConvention cc; + + VisibMod visib_mod; bool auto_err_set; + bool is_var_args; + bool is_extern; + bool is_export; }; struct AstNodeFnDef { @@ -642,6 +645,7 @@ struct AstNodeParamDecl { Buf *name; AstNode *type; Token *var_token; + Buf doc_comments; bool is_noalias; bool is_comptime; bool is_var_args; @@ -684,6 +688,7 @@ struct AstNodeVariableDeclaration { // populated if the "section(S)" is present AstNode *section_expr; Token *threadlocal_tok; + Buf doc_comments; VisibMod visib_mod; bool is_const; @@ -957,25 +962,35 @@ enum ContainerLayout { }; struct AstNodeContainerDecl { - ContainerKind kind; + AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) ZigList<AstNode *> fields; ZigList<AstNode *> decls; + + ContainerKind kind; ContainerLayout layout; - AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) + bool auto_enum, is_root; // union(enum) }; +struct AstNodeErrorSetField { + Buf doc_comments; + AstNode *field_name; +}; + struct AstNodeErrorSetDecl { + // Each AstNode could be AstNodeErrorSetField or just AstNodeSymbolExpr to save memory ZigList<AstNode *> decls; }; struct AstNodeStructField { - VisibMod visib_mod; Buf *name; AstNode *type; AstNode *value; // populated if the "align(A)" is present AstNode *align_expr; + Buf doc_comments; + + VisibMod visib_mod; }; struct AstNodeStringLiteral { @@ -1126,6 +1141,7 @@ struct AstNode { AstNodeInferredArrayType inferred_array_type; AstNodeErrorType error_type; AstNodeErrorSetDecl err_set_decl; + AstNodeErrorSetField err_set_field; AstNodeResumeExpr resume_expr; AstNodeAwaitExpr await_expr; AstNodeSuspend suspend; @@ -1274,9 +1290,10 @@ struct ZigTypeErrorUnion { }; struct ZigTypeErrorSet { - uint32_t err_count; ErrorTableEntry **errors; ZigFn *infer_fn; + uint32_t err_count; + bool incomplete; }; struct ZigTypeEnum { @@ -1306,6 +1323,15 @@ bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b); uint32_t tld_ptr_hash(const Tld *ptr); bool tld_ptr_eql(const Tld *a, const Tld *b); +uint32_t node_ptr_hash(const AstNode *ptr); +bool node_ptr_eql(const AstNode *a, const AstNode *b); + +uint32_t fn_ptr_hash(const ZigFn *ptr); +bool fn_ptr_eql(const ZigFn *a, const ZigFn *b); + +uint32_t err_ptr_hash(const ErrorTableEntry *ptr); +bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b); + struct ZigTypeUnion { AstNode *decl_node; TypeUnionField *fields; @@ -2120,6 +2146,7 @@ struct ErrorTableEntry { Buf name; uint32_t value; AstNode *decl_node; + ErrorTableEntry *other; // null, or another error decl that was merged into this ZigType *set_with_only_this_in_it; // If we generate a constant error name value for this error, we memoize it here. // The type of this is array diff --git a/src/analyze.cpp b/src/analyze.cpp index cca239c275..82b09175d3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -913,7 +913,10 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { if (type_is_c_abi_int(g, fn_type_id->return_type)) { return false; } - if (g->zig_target->arch == ZigLLVM_x86_64) { + if (g->zig_target->arch == ZigLLVM_x86) { + X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); + return abi_class == X64CABIClass_MEMORY; + } else if (g->zig_target->arch == ZigLLVM_x86_64) { X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); return abi_class == X64CABIClass_MEMORY; } else if (target_is_arm(g->zig_target) || target_is_riscv(g->zig_target)) { @@ -1633,6 +1636,7 @@ ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) { err_set_type->data.error_set.err_count = 0; err_set_type->data.error_set.errors = nullptr; err_set_type->data.error_set.infer_fn = fn_entry; + err_set_type->data.error_set.incomplete = true; err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; @@ -3572,6 +3576,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeSuspend: case NodeTypeEnumLiteral: case NodeTypeAnyFrameType: + case NodeTypeErrorSetField: zig_unreachable(); } } @@ -4276,12 +4281,12 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node) { assert(err_set_type->id == ZigTypeIdErrorSet); ZigFn *infer_fn = err_set_type->data.error_set.infer_fn; - if (infer_fn != nullptr) { + if (infer_fn != nullptr && err_set_type->data.error_set.incomplete) { if (infer_fn->anal_state == FnAnalStateInvalid) { return false; } else if (infer_fn->anal_state == FnAnalStateReady) { analyze_fn_body(g, infer_fn); - if (err_set_type->data.error_set.infer_fn != nullptr) { + if (err_set_type->data.error_set.incomplete) { assert(g->errors.length != 0); return false; } @@ -4508,7 +4513,9 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) { ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; - if (return_err_set_type->data.error_set.infer_fn != nullptr) { + if (return_err_set_type->data.error_set.infer_fn != nullptr && + return_err_set_type->data.error_set.incomplete) + { ZigType *inferred_err_set_type; if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) { inferred_err_set_type = fn->src_implicit_return_type; @@ -4521,14 +4528,16 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { return; } - if (inferred_err_set_type->data.error_set.infer_fn != nullptr) { + if (inferred_err_set_type->data.error_set.infer_fn != nullptr && + inferred_err_set_type->data.error_set.incomplete) + { if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) { fn->anal_state = FnAnalStateInvalid; return; } } - return_err_set_type->data.error_set.infer_fn = nullptr; + return_err_set_type->data.error_set.incomplete = false; if (type_is_global_error_set(inferred_err_set_type)) { return_err_set_type->data.error_set.err_count = UINT32_MAX; } else { @@ -7319,6 +7328,30 @@ bool tld_ptr_eql(const Tld *a, const Tld *b) { return a == b; } +uint32_t node_ptr_hash(const AstNode *ptr) { + return hash_ptr((void*)ptr); +} + +bool node_ptr_eql(const AstNode *a, const AstNode *b) { + return a == b; +} + +uint32_t fn_ptr_hash(const ZigFn *ptr) { + return hash_ptr((void*)ptr); +} + +bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) { + return a == b; +} + +uint32_t err_ptr_hash(const ErrorTableEntry *ptr) { + return hash_ptr((void*)ptr); +} + +bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b) { + return a == b; +} + ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name)); resolve_top_level_decl(codegen, tld, nullptr, false); @@ -7331,7 +7364,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { bool type_is_global_error_set(ZigType *err_set_type) { assert(err_set_type->id == ZigTypeIdErrorSet); - assert(err_set_type->data.error_set.infer_fn == nullptr); + assert(!err_set_type->data.error_set.incomplete); return err_set_type->data.error_set.err_count == UINT32_MAX; } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 537a74d7b1..18940c4b80 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -266,6 +266,8 @@ static const char *node_type_str(NodeType node_type) { return "AnyFrameType"; case NodeTypeEnumLiteral: return "EnumLiteral"; + case NodeTypeErrorSetField: + return "ErrorSetField"; } zig_unreachable(); } @@ -1177,6 +1179,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeTestDecl: case NodeTypeStructField: case NodeTypeUsingNamespace: + case NodeTypeErrorSetField: zig_panic("TODO more ast rendering"); } } diff --git a/src/buffer.hpp b/src/buffer.hpp index 251b5c2f27..6442e4f123 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -38,6 +38,12 @@ static inline char *buf_ptr(Buf *buf) { return buf->list.items; } +static inline const char *buf_ptr(const Buf *buf) { + assert(buf); + assert(buf->list.length); + return buf->list.items; +} + static inline void buf_resize(Buf *buf, size_t new_len) { buf->list.resize(new_len + 1); buf->list.at(buf_len(buf)) = 0; diff --git a/src/codegen.cpp b/src/codegen.cpp index 88ff179ca7..3dbd0b8538 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8727,6 +8727,9 @@ static void init(CodeGen *g) { // Be aware of https://github.com/ziglang/zig/issues/3275 target_specific_cpu_args = ""; target_specific_features = riscv_default_features; + } else if (g->zig_target->arch == ZigLLVM_x86) { + target_specific_cpu_args = "pentium4"; + target_specific_features = ""; } else { target_specific_cpu_args = ""; target_specific_features = ""; @@ -10355,15 +10358,15 @@ void codegen_build_and_link(CodeGen *g) { } } if (g->enable_doc_generation) { - Buf *doc_dir_path = buf_sprintf("%s" OS_SEP "doc", buf_ptr(g->output_dir)); + Buf *doc_dir_path = buf_sprintf("%s" OS_SEP "docs", buf_ptr(g->output_dir)); if ((err = os_make_path(doc_dir_path))) { fprintf(stderr, "Unable to create directory %s: %s\n", buf_ptr(doc_dir_path), err_str(err)); exit(1); } - Buf *index_html_src_path = buf_sprintf("%s" OS_SEP "special" OS_SEP "doc" OS_SEP "index.html", + Buf *index_html_src_path = buf_sprintf("%s" OS_SEP "special" OS_SEP "docs" OS_SEP "index.html", buf_ptr(g->zig_std_dir)); Buf *index_html_dest_path = buf_sprintf("%s" OS_SEP "index.html", buf_ptr(doc_dir_path)); - Buf *main_js_src_path = buf_sprintf("%s" OS_SEP "special" OS_SEP "doc" OS_SEP "main.js", + Buf *main_js_src_path = buf_sprintf("%s" OS_SEP "special" OS_SEP "docs" OS_SEP "main.js", buf_ptr(g->zig_std_dir)); Buf *main_js_dest_path = buf_sprintf("%s" OS_SEP "main.js", buf_ptr(doc_dir_path)); diff --git a/src/dump_analysis.cpp b/src/dump_analysis.cpp index 220019c184..168d86a21f 100644 --- a/src/dump_analysis.cpp +++ b/src/dump_analysis.cpp @@ -351,6 +351,15 @@ struct AnalDumpCtx { ZigList<Tld *> decl_list; HashMap<const Tld *, uint32_t, tld_ptr_hash, tld_ptr_eql> decl_map; + + ZigList<ZigFn *> fn_list; + HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_map; + + ZigList<AstNode *> node_list; + HashMap<const AstNode *, uint32_t, node_ptr_hash, node_ptr_eql> node_map; + + ZigList<ErrorTableEntry *> err_list; + HashMap<const ErrorTableEntry *, uint32_t, err_ptr_hash, err_ptr_eql> err_map; }; static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty); @@ -416,6 +425,39 @@ static uint32_t anal_dump_get_file_id(AnalDumpCtx *ctx, Buf *file) { return file_id; } +static uint32_t anal_dump_get_node_id(AnalDumpCtx *ctx, AstNode *node) { + uint32_t node_id = ctx->node_list.length; + auto existing_entry = ctx->node_map.put_unique(node, node_id); + if (existing_entry == nullptr) { + ctx->node_list.append(node); + } else { + node_id = existing_entry->value; + } + return node_id; +} + +static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) { + uint32_t fn_id = ctx->fn_list.length; + auto existing_entry = ctx->fn_map.put_unique(fn, fn_id); + if (existing_entry == nullptr) { + ctx->fn_list.append(fn); + } else { + fn_id = existing_entry->value; + } + return fn_id; +} + +static uint32_t anal_dump_get_err_id(AnalDumpCtx *ctx, ErrorTableEntry *err) { + uint32_t err_id = ctx->err_list.length; + auto existing_entry = ctx->err_map.put_unique(err, err_id); + if (existing_entry == nullptr) { + ctx->err_list.append(err); + } else { + err_id = existing_entry->value; + } + return err_id; +} + static uint32_t anal_dump_get_decl_id(AnalDumpCtx *ctx, Tld *tld) { uint32_t decl_id = ctx->decl_list.length; auto existing_entry = ctx->decl_map.put_unique(tld, decl_id); @@ -475,6 +517,21 @@ static void anal_dump_file_ref(AnalDumpCtx *ctx, Buf *file) { jw_int(&ctx->jw, file_id); } +static void anal_dump_node_ref(AnalDumpCtx *ctx, AstNode *node) { + uint32_t node_id = anal_dump_get_node_id(ctx, node); + jw_int(&ctx->jw, node_id); +} + +static void anal_dump_fn_ref(AnalDumpCtx *ctx, ZigFn *fn) { + uint32_t fn_id = anal_dump_get_fn_id(ctx, fn); + jw_int(&ctx->jw, fn_id); +} + +static void anal_dump_err_ref(AnalDumpCtx *ctx, ErrorTableEntry *err) { + uint32_t err_id = anal_dump_get_err_id(ctx, err); + jw_int(&ctx->jw, err_id); +} + static void anal_dump_decl_ref(AnalDumpCtx *ctx, Tld *tld) { uint32_t decl_id = anal_dump_get_decl_id(ctx, tld); jw_int(&ctx->jw, decl_id); @@ -536,11 +593,8 @@ static void anal_dump_decl(AnalDumpCtx *ctx, Tld *tld) { jw_object_field(jw, "import"); anal_dump_type_ref(ctx, tld->import); - jw_object_field(jw, "line"); - jw_int(jw, tld->source_node->line); - - jw_object_field(jw, "col"); - jw_int(jw, tld->source_node->column); + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, tld->source_node); jw_object_field(jw, "name"); jw_string(jw, buf_ptr(tld->name)); @@ -584,8 +638,10 @@ static void anal_dump_decl(AnalDumpCtx *ctx, Tld *tld) { jw_object_field(jw, "type"); anal_dump_type_ref(ctx, fn->type_entry); - } + jw_object_field(jw, "value"); + anal_dump_fn_ref(ctx, fn); + } break; } default: @@ -626,6 +682,19 @@ static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, anal_dump_type_ref(ctx, val_ty); return; } + case ZigTypeIdFn: { + if (value->data.x_ptr.special == ConstPtrSpecialFunction) { + ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry; + if (val_fn->type_entry->data.fn.is_generic) { + anal_dump_node_ref(ctx, val_fn->proto_node); + } else { + anal_dump_fn_ref(ctx, val_fn); + } + } else { + jw_null(&ctx->jw); + } + return; + } default: jw_null(&ctx->jw); return; @@ -633,24 +702,75 @@ static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, zig_unreachable(); } -static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { +static void anal_dump_pointer_attrs(AnalDumpCtx *ctx, ZigType *ty) { JsonWriter *jw = &ctx->jw; - jw_array_elem(jw); + if (ty->data.pointer.explicit_alignment != 0) { + jw_object_field(jw, "align"); + jw_int(jw, ty->data.pointer.explicit_alignment); + } + if (ty->data.pointer.is_const) { + jw_object_field(jw, "const"); + jw_bool(jw, true); + } + if (ty->data.pointer.is_volatile) { + jw_object_field(jw, "volatile"); + jw_bool(jw, true); + } + if (ty->data.pointer.allow_zero) { + jw_object_field(jw, "allowZero"); + jw_bool(jw, true); + } + if (ty->data.pointer.host_int_bytes != 0) { + jw_object_field(jw, "hostIntBytes"); + jw_int(jw, ty->data.pointer.host_int_bytes); + + jw_object_field(jw, "bitOffsetInHost"); + jw_int(jw, ty->data.pointer.bit_offset_in_host); + } + + jw_object_field(jw, "elem"); + anal_dump_type_ref(ctx, ty->data.pointer.child_type); +} + +static void anal_dump_struct_field(AnalDumpCtx *ctx, const TypeStructField *struct_field) { + JsonWriter *jw = &ctx->jw; + jw_begin_object(jw); jw_object_field(jw, "name"); - jw_string(jw, buf_ptr(&ty->name)); + jw_string(jw, buf_ptr(struct_field->name)); + + jw_object_field(jw, "type"); + anal_dump_type_ref(ctx, struct_field->type_entry); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, struct_field->decl_node); + + jw_end_object(jw); +} + +static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { + JsonWriter *jw = &ctx->jw; + jw_array_elem(jw); + jw_begin_object(jw); jw_object_field(jw, "kind"); jw_int(jw, type_id_index(ty)); switch (ty->id) { + case ZigTypeIdMetaType: + case ZigTypeIdBool: + break; case ZigTypeIdStruct: { if (ty->data.structure.is_slice) { - // TODO + jw_object_field(jw, "len"); + jw_int(jw, 2); + anal_dump_pointer_attrs(ctx, ty->data.structure.fields[slice_ptr_index].type_entry); break; } + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); { jw_object_field(jw, "pubDecls"); jw_begin_array(jw); @@ -691,6 +811,17 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { jw_end_array(jw); } + { + jw_object_field(jw, "fields"); + jw_begin_array(jw); + + for(size_t i = 0; i < ty->data.structure.src_field_count; i += 1) { + jw_array_elem(jw); + anal_dump_struct_field(ctx, &ty->data.structure.fields[i]); + } + jw_end_array(jw); + } + if (ty->data.structure.root_struct != nullptr) { Buf *path_buf = ty->data.structure.root_struct->path; @@ -705,13 +836,167 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { jw_int(jw, ty->data.floating.bit_count); break; } + case ZigTypeIdInt: { + if (ty->data.integral.is_signed) { + jw_object_field(jw, "i"); + } else { + jw_object_field(jw, "u"); + } + jw_int(jw, ty->data.integral.bit_count); + break; + } + case ZigTypeIdFn: { + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + jw_object_field(jw, "generic"); + jw_bool(jw, ty->data.fn.is_generic); + + if (ty->data.fn.fn_type_id.return_type != nullptr) { + jw_object_field(jw, "ret"); + anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.return_type); + } + + if (ty->data.fn.fn_type_id.param_count != 0) { + jw_object_field(jw, "args"); + jw_begin_array(jw); + for (size_t i = 0; i < ty->data.fn.fn_type_id.param_count; i += 1) { + jw_array_elem(jw); + if (ty->data.fn.fn_type_id.param_info[i].type != nullptr) { + anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.param_info[i].type); + } else { + jw_null(jw); + } + } + jw_end_array(jw); + } + break; + } + case ZigTypeIdPointer: { + switch (ty->data.pointer.ptr_len) { + case PtrLenSingle: + break; + case PtrLenUnknown: + jw_object_field(jw, "len"); + jw_int(jw, 1); + break; + case PtrLenC: + jw_object_field(jw, "len"); + jw_int(jw, 3); + break; + } + anal_dump_pointer_attrs(ctx, ty); + break; + } + case ZigTypeIdErrorSet: { + if (type_is_global_error_set(ty)) { + break; + } + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + if (ty->data.error_set.infer_fn != nullptr) { + jw_object_field(jw, "fn"); + anal_dump_fn_ref(ctx, ty->data.error_set.infer_fn); + } + jw_object_field(jw, "errors"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ty->data.error_set.err_count; i += 1) { + jw_array_elem(jw); + ErrorTableEntry *err = ty->data.error_set.errors[i]; + anal_dump_err_ref(ctx, err); + } + jw_end_array(jw); + break; + } + case ZigTypeIdErrorUnion: { + jw_object_field(jw, "err"); + anal_dump_type_ref(ctx, ty->data.error_union.err_set_type); + + jw_object_field(jw, "payload"); + anal_dump_type_ref(ctx, ty->data.error_union.payload_type); + + break; + } default: - // TODO + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); break; } jw_end_object(jw); } +static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { + JsonWriter *jw = &ctx->jw; + + jw_begin_object(jw); + + jw_object_field(jw, "file"); + anal_dump_file_ref(ctx, node->owner->data.structure.root_struct->path); + + jw_object_field(jw, "line"); + jw_int(jw, node->line); + + jw_object_field(jw, "col"); + jw_int(jw, node->column); + + const Buf *doc_comments_buf; + switch (node->type) { + case NodeTypeParamDecl: + doc_comments_buf = &node->data.param_decl.doc_comments; + break; + case NodeTypeFnProto: + doc_comments_buf = &node->data.fn_proto.doc_comments; + break; + case NodeTypeVariableDeclaration: + doc_comments_buf = &node->data.variable_declaration.doc_comments; + break; + case NodeTypeErrorSetField: + doc_comments_buf = &node->data.err_set_field.doc_comments; + break; + case NodeTypeStructField: + doc_comments_buf = &node->data.struct_field.doc_comments; + break; + default: + doc_comments_buf = nullptr; + break; + } + if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) { + jw_object_field(jw, "docs"); + jw_string(jw, buf_ptr(doc_comments_buf)); + } + + jw_end_object(jw); +} + +static void anal_dump_err(AnalDumpCtx *ctx, const ErrorTableEntry *err) { + JsonWriter *jw = &ctx->jw; + + jw_begin_object(jw); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, err->decl_node); + + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&err->name)); + + jw_end_object(jw); +} + +static void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) { + JsonWriter *jw = &ctx->jw; + + jw_begin_object(jw); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, fn->proto_node); + + jw_object_field(jw, "type"); + anal_dump_type_ref(ctx, fn->type_entry); + + jw_end_object(jw); +} + void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl) { Error err; AnalDumpCtx ctx = {}; @@ -722,6 +1007,9 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const ctx.pkg_map.init(16); ctx.file_map.init(16); ctx.decl_map.init(16); + ctx.node_map.init(16); + ctx.fn_map.init(16); + ctx.err_map.init(16); jw_begin_object(jw); @@ -761,6 +1049,71 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const jw_object_field(jw, "rootPkg"); anal_dump_pkg_ref(&ctx, g->root_package); + // Poke the functions + for (size_t i = 0; i < g->fn_defs.length; i += 1) { + ZigFn *fn = g->fn_defs.at(i); + (void)anal_dump_get_fn_id(&ctx, fn); + } + + jw_object_field(jw, "calls"); + jw_begin_array(jw); + { + auto it = g->memoized_fn_eval_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + jw_array_elem(jw); + jw_begin_object(jw); + + jw_object_field(jw, "args"); + jw_begin_object(jw); + + Scope *scope = entry->key; + while (scope != nullptr) { + if (scope->id == ScopeIdVarDecl) { + ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var; + jw_object_field(jw, var->name); + jw_begin_object(jw); + jw_object_field(jw, "type"); + anal_dump_type_ref(&ctx, var->var_type); + jw_object_field(jw, "value"); + anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value); + jw_end_object(jw); + } else if (scope->id == ScopeIdFnDef) { + jw_end_object(jw); + + jw_object_field(jw, "fn"); + ZigFn *fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry; + anal_dump_fn_ref(&ctx, fn); + + ConstExprValue *result = entry->value; + jw_object_field(jw, "result"); + jw_begin_object(jw); + jw_object_field(jw, "type"); + anal_dump_type_ref(&ctx, result->type); + jw_object_field(jw, "value"); + anal_dump_value(&ctx, scope->source_node, result->type, result); + jw_end_object(jw); + break; + } + scope = scope->parent; + } + jw_end_object(jw); + } + } + jw_end_array(jw); + + jw_object_field(jw, "fns"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) { + ZigFn *fn = ctx.fn_list.at(i); + jw_array_elem(jw); + anal_dump_fn(&ctx, fn); + } + jw_end_array(jw); + jw_object_field(jw, "packages"); jw_begin_array(jw); for (uint32_t i = 0; i < ctx.pkg_list.length; i += 1) { @@ -794,5 +1147,23 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const } jw_end_array(jw); + jw_object_field(jw, "errors"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.err_list.length; i += 1) { + const ErrorTableEntry *err = ctx.err_list.at(i); + jw_array_elem(jw); + anal_dump_err(&ctx, err); + } + jw_end_array(jw); + + jw_object_field(jw, "astNodes"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.node_list.length; i += 1) { + const AstNode *node = ctx.node_list.at(i); + jw_array_elem(jw); + anal_dump_node(&ctx, node); + } + jw_end_array(jw); + jw_end_object(jw); } diff --git a/src/ir.cpp b/src/ir.cpp index 52b59ddcad..f29870e039 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7892,11 +7892,14 @@ static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigTyp } uint32_t index = set1->data.error_set.err_count; + bool need_comma = false; for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; if (errors[error_entry->value] == nullptr) { errors[error_entry->value] = error_entry; - buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name)); + const char *comma = need_comma ? "," : ""; + need_comma = true; + buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&error_entry->name)); err_set_type->data.error_set.errors[index] = error_entry; index += 1; } @@ -7927,6 +7930,17 @@ static ZigType *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstN return err_set_type; } +static AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node) { + if (err_set_field_node->type == NodeTypeSymbol) { + return err_set_field_node; + } else if (err_set_field_node->type == NodeTypeErrorSetField) { + assert(err_set_field_node->data.err_set_field.field_name->type == NodeTypeSymbol); + return err_set_field_node->data.err_set_field.field_name; + } else { + return err_set_field_node; + } +} + static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeErrorSetDecl); @@ -7945,11 +7959,11 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count); for (uint32_t i = 0; i < err_count; i += 1) { - AstNode *symbol_node = node->data.err_set_decl.decls.at(i); - assert(symbol_node->type == NodeTypeSymbol); + AstNode *field_node = node->data.err_set_decl.decls.at(i); + AstNode *symbol_node = ast_field_to_symbol_node(field_node); Buf *err_name = symbol_node->data.symbol_expr.symbol; ErrorTableEntry *err = allocate<ErrorTableEntry>(1); - err->decl_node = symbol_node; + err->decl_node = field_node; buf_init_from_buf(&err->name, err_name); auto existing_entry = irb->codegen->error_table.put_unique(err_name, err); @@ -7965,8 +7979,10 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A ErrorTableEntry *prev_err = errors[err->value]; if (prev_err != nullptr) { - ErrorMsg *msg = add_node_error(irb->codegen, err->decl_node, buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name))); - add_error_note(irb->codegen, msg, prev_err->decl_node, buf_sprintf("other error here")); + ErrorMsg *msg = add_node_error(irb->codegen, ast_field_to_symbol_node(err->decl_node), + buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name))); + add_error_note(irb->codegen, msg, ast_field_to_symbol_node(prev_err->decl_node), + buf_sprintf("other error here")); return irb->codegen->invalid_instruction; } errors[err->value] = err; @@ -8116,6 +8132,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSwitchProng: case NodeTypeSwitchRange: case NodeTypeStructField: + case NodeTypeErrorSetField: case NodeTypeFnDef: case NodeTypeTestDecl: zig_unreachable(); @@ -9470,6 +9487,14 @@ static void populate_error_set_table(ErrorTableEntry **errors, ZigType *set) { } } +static ErrorTableEntry *better_documented_error(ErrorTableEntry *preferred, ErrorTableEntry *other) { + if (preferred->decl_node->type == NodeTypeErrorSetField) + return preferred; + if (other->decl_node->type == NodeTypeErrorSetField) + return other; + return preferred; +} + static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigType *set2, AstNode *source_node) { @@ -9496,12 +9521,17 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp buf_resize(&err_set_type->name, 0); buf_appendf(&err_set_type->name, "error{"); + bool need_comma = false; for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; ErrorTableEntry *existing_entry = errors[error_entry->value]; if (existing_entry != nullptr) { - intersection_list.append(existing_entry); - buf_appendf(&err_set_type->name, "%s,", buf_ptr(&existing_entry->name)); + // prefer the one with docs + const char *comma = need_comma ? "," : ""; + need_comma = true; + ErrorTableEntry *existing_entry_with_docs = better_documented_error(existing_entry, error_entry); + intersection_list.append(existing_entry_with_docs); + buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name)); } } free(errors); @@ -9683,7 +9713,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted ZigType *container_set = wanted_type; // if the container set is inferred, then this will always work. - if (container_set->data.error_set.infer_fn != nullptr) { + if (container_set->data.error_set.infer_fn != nullptr && container_set->data.error_set.incomplete) { return result; } // if the container set is the global one, it will always work. @@ -12049,7 +12079,7 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa ZigList<ErrorTableEntry *> *missing_errors = &cast_result->data.error_set_mismatch->missing_errors; for (size_t i = 0; i < missing_errors->length; i += 1) { ErrorTableEntry *error_entry = missing_errors->at(i); - add_error_note(ira->codegen, parent_msg, error_entry->decl_node, + add_error_note(ira->codegen, parent_msg, ast_field_to_symbol_node(error_entry->decl_node), buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name))); } break; @@ -16148,7 +16178,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c UndefOk); if (inferred_err_set_type != nullptr) { - inferred_err_set_type->data.error_set.infer_fn = nullptr; + inferred_err_set_type->data.error_set.incomplete = false; if (result->type->id == ZigTypeIdErrorUnion) { ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; if (err != nullptr) { @@ -23608,7 +23638,7 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct if (!type_is_global_error_set(err_set_type) && err_set_type->data.error_set.err_count == 0) { - assert(err_set_type->data.error_set.infer_fn == nullptr); + assert(!err_set_type->data.error_set.incomplete); return ir_const_bool(ira, &instruction->base, false); } } diff --git a/src/main.cpp b/src/main.cpp index 9b8bddabd7..fb2881f3a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " build-exe [source] create executable from source or object files\n" " build-lib [source] create library from source or object files\n" " build-obj [source] create object from source or assembly\n" - " builtin show the source code of that @import(\"builtin\")\n" + " builtin show the source code of @import(\"builtin\")\n" " cc C compiler\n" " fmt parse files and render in canonical zig format\n" " id print the base64-encoded compiler id\n" @@ -65,7 +65,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -ftime-report print timing diagnostics\n" " -fstack-report print stack size diagnostics\n" " -fdump-analysis write analysis.json file with type information\n" - " -fgenerate-docs create a doc/ dir with html documentation\n" + " -fgenerate-docs create a docs/ dir with html documentation\n" " --libc [file] Provide a file which specifies libc paths\n" " --name [name] override output name\n" " --output-dir [dir] override output directory (defaults to cwd)\n" diff --git a/src/parser.cpp b/src/parser.cpp index 96071daa07..9fcf233e2d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -37,7 +37,7 @@ static AstNode *ast_parse_root(ParseContext *pc); static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc); static AstNode *ast_parse_test_decl(ParseContext *pc); static AstNode *ast_parse_top_level_comptime(ParseContext *pc); -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod); +static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, Buf *doc_comments); static AstNode *ast_parse_fn_proto(ParseContext *pc); static AstNode *ast_parse_var_decl(ParseContext *pc); static AstNode *ast_parse_container_field(ParseContext *pc); @@ -497,6 +497,23 @@ static AstNode *ast_parse_root(ParseContext *pc) { return node; } +static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) { + Token *first_doc_token = nullptr; + Token *doc_token = nullptr; + while ((doc_token = eat_token_if(pc, TokenIdDocComment))) { + if (first_doc_token == nullptr) { + first_doc_token = doc_token; + } + if (buf->list.length == 0) { + buf_resize(buf, 0); + } + // chops off '///' but leaves '\n' + buf_append_mem(buf, buf_ptr(pc->buf) + doc_token->start_pos + 3, + doc_token->end_pos - doc_token->start_pos - 3); + } + return first_doc_token; +} + // ContainerMembers // <- TestDecl ContainerMembers // / TopLevelComptime ContainerMembers @@ -519,10 +536,13 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { continue; } + Buf doc_comment_buf = BUF_INIT; + ast_parse_doc_comments(pc, &doc_comment_buf); + Token *visib_token = eat_token_if(pc, TokenIdKeywordPub); VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate; - AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod); + AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf); if (top_level_decl != nullptr) { res.decls.append(top_level_decl); continue; @@ -532,6 +552,7 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { if (container_field != nullptr) { assert(container_field->type == NodeTypeStructField); container_field->data.struct_field.visib_mod = visib_mod; + container_field->data.struct_field.doc_comments = doc_comment_buf; res.fields.append(container_field); if (eat_token_if(pc, TokenIdComma) != nullptr) { continue; @@ -581,7 +602,7 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { // <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) // / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl // / KEYWORD_use Expr SEMICOLON -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { +static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, Buf *doc_comments) { Token *first = eat_token_if(pc, TokenIdKeywordExport); if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordExtern); @@ -603,6 +624,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { var_decl->column = first->start_column; var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; var_decl->data.variable_declaration.visib_mod = visib_mod; + var_decl->data.variable_declaration.doc_comments = *doc_comments; var_decl->data.variable_declaration.is_extern = first->id == TokenIdKeywordExtern; var_decl->data.variable_declaration.is_export = first->id == TokenIdKeywordExport; var_decl->data.variable_declaration.lib_name = token_buf(lib_name); @@ -623,6 +645,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { fn_proto->line = first->start_line; fn_proto->column = first->start_column; fn_proto->data.fn_proto.visib_mod = visib_mod; + fn_proto->data.fn_proto.doc_comments = *doc_comments; fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport; switch (first->id) { @@ -657,6 +680,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); var_decl->data.variable_declaration.visib_mod = visib_mod; + var_decl->data.variable_declaration.doc_comments = *doc_comments; var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; return var_decl; } @@ -672,6 +696,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { assert(fn_proto->type == NodeTypeFnProto); fn_proto->data.fn_proto.visib_mod = visib_mod; + fn_proto->data.fn_proto.doc_comments = *doc_comments; AstNode *res = fn_proto; if (body != nullptr) { res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); @@ -1719,11 +1744,20 @@ static AstNode *ast_parse_error_set_decl(ParseContext *pc) { } ZigList<AstNode *> decls = ast_parse_list<AstNode>(pc, TokenIdComma, [](ParseContext *context) { + Buf doc_comment_buf = BUF_INIT; + Token *doc_token = ast_parse_doc_comments(context, &doc_comment_buf); Token *ident = eat_token_if(context, TokenIdSymbol); if (ident == nullptr) return (AstNode*)nullptr; - return token_symbol(context, ident); + AstNode *symbol_node = token_symbol(context, ident); + if (doc_token == nullptr) + return symbol_node; + + AstNode *field_node = ast_create_node(context, NodeTypeErrorSetField, doc_token); + field_node->data.err_set_field.field_name = symbol_node; + field_node->data.err_set_field.doc_comments = doc_comment_buf; + return field_node; }); expect_token(pc, TokenIdRBrace); @@ -2057,6 +2091,9 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) { // ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType static AstNode *ast_parse_param_decl(ParseContext *pc) { + Buf doc_comments = BUF_INIT; + ast_parse_doc_comments(pc, &doc_comments); + Token *first = eat_token_if(pc, TokenIdKeywordNoAlias); if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordCompTime); @@ -2089,6 +2126,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { res->line = first->start_line; res->column = first->start_column; res->data.param_decl.name = token_buf(name); + res->data.param_decl.doc_comments = doc_comments; res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias; res->data.param_decl.is_comptime = first->id == TokenIdKeywordCompTime; return res; @@ -3029,6 +3067,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeErrorSetDecl: visit_node_list(&node->data.err_set_decl.decls, visit, context); break; + case NodeTypeErrorSetField: + visit_field(&node->data.err_set_field.field_name, visit, context); + break; case NodeTypeResume: visit_field(&node->data.resume_expr.expr, visit, context); break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 11824bd871..475c284d27 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -197,6 +197,8 @@ enum TokenizeState { TokenizeStateSawStar, TokenizeStateSawStarPercent, TokenizeStateSawSlash, + TokenizeStateSawSlash2, + TokenizeStateSawSlash3, TokenizeStateSawBackslash, TokenizeStateSawPercent, TokenizeStateSawPlus, @@ -207,6 +209,7 @@ enum TokenizeState { TokenizeStateSawCaret, TokenizeStateSawBar, TokenizeStateSawBarBar, + TokenizeStateDocComment, TokenizeStateLineComment, TokenizeStateLineString, TokenizeStateLineStringEnd, @@ -912,8 +915,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawSlash: switch (c) { case '/': - cancel_token(&t); - t.state = TokenizeStateLineComment; + t.state = TokenizeStateSawSlash2; break; case '=': set_token_id(&t, t.cur_tok, TokenIdDivEq); @@ -927,6 +929,38 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; + case TokenizeStateSawSlash2: + switch (c) { + case '/': + t.state = TokenizeStateSawSlash3; + break; + case '\n': + cancel_token(&t); + t.state = TokenizeStateStart; + break; + default: + cancel_token(&t); + t.state = TokenizeStateLineComment; + break; + } + break; + case TokenizeStateSawSlash3: + switch (c) { + case '/': + cancel_token(&t); + t.state = TokenizeStateLineComment; + break; + case '\n': + set_token_id(&t, t.cur_tok, TokenIdDocComment); + end_token(&t); + t.state = TokenizeStateStart; + break; + default: + set_token_id(&t, t.cur_tok, TokenIdDocComment); + t.state = TokenizeStateDocComment; + break; + } + break; case TokenizeStateSawBackslash: switch (c) { case '\\': @@ -1006,6 +1040,17 @@ void tokenize(Buf *buf, Tokenization *out) { break; } break; + case TokenizeStateDocComment: + switch (c) { + case '\n': + end_token(&t); + t.state = TokenizeStateStart; + break; + default: + // do nothing + break; + } + break; case TokenizeStateSymbolFirstC: switch (c) { case '"': @@ -1495,6 +1540,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateLineStringEnd: case TokenizeStateSawBarBar: case TokenizeStateLBracket: + case TokenizeStateDocComment: end_token(&t); break; case TokenizeStateSawDotDot: @@ -1507,6 +1553,8 @@ void tokenize(Buf *buf, Tokenization *out) { tokenize_error(&t, "unexpected EOF"); break; case TokenizeStateLineComment: + case TokenizeStateSawSlash2: + case TokenizeStateSawSlash3: break; } if (t.state != TokenizeStateError) { @@ -1553,6 +1601,7 @@ const char * token_name(TokenId id) { case TokenIdComma: return ","; case TokenIdDash: return "-"; case TokenIdDivEq: return "/="; + case TokenIdDocComment: return "DocComment"; case TokenIdDot: return "."; case TokenIdEllipsis2: return ".."; case TokenIdEllipsis3: return "..."; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index a3d1a60008..e33a82f31d 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -42,6 +42,7 @@ enum TokenId { TokenIdComma, TokenIdDash, TokenIdDivEq, + TokenIdDocComment, TokenIdDot, TokenIdEllipsis2, TokenIdEllipsis3, |
