authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-11 01:37:50-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-11 01:37:50-07:00
logd0c06ca7127110a8afeb0ef524a197049892db21
treecfd3e55c36eec1ae396907d254c907e542e05407
parenteaca8626b270b5c17d686c77220e2aacb5fd908f
parent139734154070b0e229df4c6c0e3297badd1d4fdc
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19208 from ziglang/rework-autodoc

Redesign How Autodoc Works

36 files changed, 7392 insertions(+), 25207 deletions(-)

.github/CODEOWNERS-5
......@@ -1,8 +1,3 @@
1# Autodoc
2/src/Autodoc.zig @kristoff-it
3/src/autodoc/* @kristoff-it
4/lib/docs/* @kristoff-it
5
61# std.json
72/lib/std/json* @thejoshwolfe
83
.github/ISSUE_TEMPLATE/autodoc-issue.md deleted-12
......@@ -1,12 +0,0 @@
1---
2name: Autodoc Issue
3about: Issues with automatically generated docs, including stdlib docs.
4title: 'Autodoc: {your issue}'
5labels: autodoc
6assignees: kristoff-it
7
8---
9
10Autodoc is still work in progress and as such many bugs and missing features are already known.
11
12# Please report only <ins>regressions</ins>, i.e. things that worked in a previous build of new Autodoc (orange banner) that now don't work any more.
CMakeLists.txt-3
......@@ -907,8 +907,6 @@ else()
907907endif()
908908
909909# -Dno-langref is currently hardcoded because building the langref takes too damn long
910# -Dno-autodocs is currently hardcoded because the C backend generates a miscompilation
911# that prevents it from working.
912910# To obtain these two forms of documentation, run zig build against stage3 rather than stage2.
913911set(ZIG_BUILD_ARGS
914912 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
......@@ -918,7 +916,6 @@ set(ZIG_BUILD_ARGS
918916 ${ZIG_STATIC_ARG}
919917 ${ZIG_NO_LIB_ARG}
920918 "-Dno-langref"
921 "-Dno-autodocs"
922919 ${ZIG_SINGLE_THREADED_ARG}
923920 ${ZIG_PIE_ARG}
924921 "-Dtarget=${ZIG_TARGET_TRIPLE}"
build.zig+5-3
......@@ -31,7 +31,7 @@ pub fn build(b: *std.Build) !void {
3131 const test_step = b.step("test", "Run all the tests");
3232 const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files and langref to installation prefix. Useful for development") orelse false;
3333 const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files;
34 const skip_install_autodocs = b.option(bool, "no-autodocs", "skip copying of standard library autodocs to the installation prefix") orelse skip_install_lib_files;
34 const std_docs = b.option(bool, "std-docs", "include standard library autodocs") orelse false;
3535 const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;
3636
3737 const docgen_exe = b.addExecutable(.{
......@@ -55,17 +55,19 @@ pub fn build(b: *std.Build) !void {
5555 b.getInstallStep().dependOn(&install_langref.step);
5656 }
5757
58 const autodoc_test = b.addTest(.{
58 const autodoc_test = b.addObject(.{
59 .name = "std",
5960 .root_source_file = .{ .path = "lib/std/std.zig" },
6061 .target = target,
6162 .zig_lib_dir = .{ .path = "lib" },
63 .optimize = .Debug,
6264 });
6365 const install_std_docs = b.addInstallDirectory(.{
6466 .source_dir = autodoc_test.getEmittedDocs(),
6567 .install_dir = .prefix,
6668 .install_subdir = "doc/std",
6769 });
68 if (!skip_install_autodocs) {
70 if (std_docs) {
6971 b.getInstallStep().dependOn(&install_std_docs.step);
7072 }
7173
lib/compiler/std-docs.zig created+384
......@@ -0,0 +1,384 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;
5
6pub fn main() !void {
7 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
8 defer arena_instance.deinit();
9 const arena = arena_instance.allocator();
10
11 var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
12 const gpa = general_purpose_allocator.allocator();
13
14 const args = try std.process.argsAlloc(arena);
15 const zig_lib_directory = args[1];
16 const zig_exe_path = args[2];
17 const global_cache_path = args[3];
18
19 var lib_dir = try std.fs.cwd().openDir(zig_lib_directory, .{});
20 defer lib_dir.close();
21
22 const listen_port: u16 = 0;
23 const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable;
24 var http_server = try address.listen(.{});
25 const port = http_server.listen_address.in.getPort();
26 const url = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
27 std.io.getStdOut().writeAll(url) catch {};
28 openBrowserTab(gpa, url[0 .. url.len - 1 :'\n']) catch |err| {
29 std.log.err("unable to open browser: {s}", .{@errorName(err)});
30 };
31
32 var context: Context = .{
33 .gpa = gpa,
34 .zig_exe_path = zig_exe_path,
35 .global_cache_path = global_cache_path,
36 .lib_dir = lib_dir,
37 .zig_lib_directory = zig_lib_directory,
38 };
39
40 while (true) {
41 const connection = try http_server.accept();
42 _ = std.Thread.spawn(.{}, accept, .{ &context, connection }) catch |err| {
43 std.log.err("unable to accept connection: {s}", .{@errorName(err)});
44 connection.stream.close();
45 continue;
46 };
47 }
48}
49
50fn accept(context: *Context, connection: std.net.Server.Connection) void {
51 defer connection.stream.close();
52
53 var read_buffer: [8000]u8 = undefined;
54 var server = std.http.Server.init(connection, &read_buffer);
55 while (server.state == .ready) {
56 var request = server.receiveHead() catch |err| switch (err) {
57 error.HttpConnectionClosing => return,
58 else => {
59 std.log.err("closing http connection: {s}", .{@errorName(err)});
60 return;
61 },
62 };
63 serveRequest(&request, context) catch |err| {
64 std.log.err("unable to serve {s}: {s}", .{ request.head.target, @errorName(err) });
65 return;
66 };
67 }
68}
69
70const Context = struct {
71 gpa: Allocator,
72 lib_dir: std.fs.Dir,
73 zig_lib_directory: []const u8,
74 zig_exe_path: []const u8,
75 global_cache_path: []const u8,
76};
77
78fn serveRequest(request: *std.http.Server.Request, context: *Context) !void {
79 if (std.mem.eql(u8, request.head.target, "/") or
80 std.mem.eql(u8, request.head.target, "/debug/"))
81 {
82 try serveDocsFile(request, context, "docs/index.html", "text/html");
83 } else if (std.mem.eql(u8, request.head.target, "/main.js") or
84 std.mem.eql(u8, request.head.target, "/debug/main.js"))
85 {
86 try serveDocsFile(request, context, "docs/main.js", "application/javascript");
87 } else if (std.mem.eql(u8, request.head.target, "/main.wasm")) {
88 try serveWasm(request, context, .ReleaseFast);
89 } else if (std.mem.eql(u8, request.head.target, "/debug/main.wasm")) {
90 try serveWasm(request, context, .Debug);
91 } else if (std.mem.eql(u8, request.head.target, "/sources.tar") or
92 std.mem.eql(u8, request.head.target, "/debug/sources.tar"))
93 {
94 try serveSourcesTar(request, context);
95 } else {
96 try request.respond("not found", .{
97 .status = .not_found,
98 .extra_headers = &.{
99 .{ .name = "content-type", .value = "text/plain" },
100 },
101 });
102 }
103}
104
105const cache_control_header: std.http.Header = .{
106 .name = "cache-control",
107 .value = "max-age=0, must-revalidate",
108};
109
110fn serveDocsFile(
111 request: *std.http.Server.Request,
112 context: *Context,
113 name: []const u8,
114 content_type: []const u8,
115) !void {
116 const gpa = context.gpa;
117 // The desired API is actually sendfile, which will require enhancing std.http.Server.
118 // We load the file with every request so that the user can make changes to the file
119 // and refresh the HTML page without restarting this server.
120 const file_contents = try context.lib_dir.readFileAlloc(gpa, name, 10 * 1024 * 1024);
121 defer gpa.free(file_contents);
122 try request.respond(file_contents, .{
123 .extra_headers = &.{
124 .{ .name = "content-type", .value = content_type },
125 cache_control_header,
126 },
127 });
128}
129
130fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
131 const gpa = context.gpa;
132
133 var send_buffer: [0x4000]u8 = undefined;
134 var response = request.respondStreaming(.{
135 .send_buffer = &send_buffer,
136 .respond_options = .{
137 .extra_headers = &.{
138 .{ .name = "content-type", .value = "application/x-tar" },
139 cache_control_header,
140 },
141 },
142 });
143 const w = response.writer();
144
145 var std_dir = try context.lib_dir.openDir("std", .{ .iterate = true });
146 defer std_dir.close();
147
148 var walker = try std_dir.walk(gpa);
149 defer walker.deinit();
150
151 while (try walker.next()) |entry| {
152 switch (entry.kind) {
153 .file => {
154 if (!std.mem.endsWith(u8, entry.basename, ".zig"))
155 continue;
156 if (std.mem.endsWith(u8, entry.basename, "test.zig"))
157 continue;
158 },
159 else => continue,
160 }
161
162 var file = try std_dir.openFile(entry.path, .{});
163 defer file.close();
164
165 const stat = try file.stat();
166 const padding = p: {
167 const remainder = stat.size % 512;
168 break :p if (remainder > 0) 512 - remainder else 0;
169 };
170
171 var file_header = std.tar.output.Header.init();
172 file_header.typeflag = .regular;
173 try file_header.setPath("std", entry.path);
174 try file_header.setSize(stat.size);
175 try file_header.updateChecksum();
176 try w.writeAll(std.mem.asBytes(&file_header));
177 try w.writeFile(file);
178 try w.writeByteNTimes(0, padding);
179 }
180 // intentionally omitting the pointless trailer
181 //try w.writeByteNTimes(0, 512 * 2);
182 try response.end();
183}
184
185fn serveWasm(
186 request: *std.http.Server.Request,
187 context: *Context,
188 optimize_mode: std.builtin.OptimizeMode,
189) !void {
190 const gpa = context.gpa;
191
192 var arena_instance = std.heap.ArenaAllocator.init(gpa);
193 defer arena_instance.deinit();
194 const arena = arena_instance.allocator();
195
196 // Do the compilation every request, so that the user can edit the files
197 // and see the changes without restarting the server.
198 const wasm_binary_path = try buildWasmBinary(arena, context, optimize_mode);
199 // std.http.Server does not have a sendfile API yet.
200 const file_contents = try std.fs.cwd().readFileAlloc(gpa, wasm_binary_path, 10 * 1024 * 1024);
201 defer gpa.free(file_contents);
202 try request.respond(file_contents, .{
203 .extra_headers = &.{
204 .{ .name = "content-type", .value = "application/wasm" },
205 cache_control_header,
206 },
207 });
208}
209
210fn buildWasmBinary(
211 arena: Allocator,
212 context: *Context,
213 optimize_mode: std.builtin.OptimizeMode,
214) ![]const u8 {
215 const gpa = context.gpa;
216
217 const main_src_path = try std.fs.path.join(arena, &.{
218 context.zig_lib_directory, "docs", "wasm", "main.zig",
219 });
220
221 var argv: std.ArrayListUnmanaged([]const u8) = .{};
222
223 try argv.appendSlice(arena, &.{
224 context.zig_exe_path,
225 "build-exe",
226 "-fno-entry",
227 "-O",
228 @tagName(optimize_mode),
229 "-target",
230 "wasm32-freestanding",
231 "-mcpu",
232 "baseline+atomics+bulk_memory+multivalue+mutable_globals+nontrapping_fptoint+reference_types+sign_ext",
233 "--cache-dir",
234 context.global_cache_path,
235 "--global-cache-dir",
236 context.global_cache_path,
237 "--name",
238 "autodoc",
239 "-rdynamic",
240 main_src_path,
241 "--listen=-",
242 });
243
244 var child = std.ChildProcess.init(argv.items, gpa);
245 child.stdin_behavior = .Pipe;
246 child.stdout_behavior = .Pipe;
247 child.stderr_behavior = .Pipe;
248 try child.spawn();
249
250 var poller = std.io.poll(gpa, enum { stdout, stderr }, .{
251 .stdout = child.stdout.?,
252 .stderr = child.stderr.?,
253 });
254 defer poller.deinit();
255
256 try sendMessage(child.stdin.?, .update);
257 try sendMessage(child.stdin.?, .exit);
258
259 const Header = std.zig.Server.Message.Header;
260 var result: ?[]const u8 = null;
261 var result_error_bundle = std.zig.ErrorBundle.empty;
262
263 const stdout = poller.fifo(.stdout);
264
265 poll: while (true) {
266 while (stdout.readableLength() < @sizeOf(Header)) {
267 if (!(try poller.poll())) break :poll;
268 }
269 const header = stdout.reader().readStruct(Header) catch unreachable;
270 while (stdout.readableLength() < header.bytes_len) {
271 if (!(try poller.poll())) break :poll;
272 }
273 const body = stdout.readableSliceOfLen(header.bytes_len);
274
275 switch (header.tag) {
276 .zig_version => {
277 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
278 return error.ZigProtocolVersionMismatch;
279 }
280 },
281 .error_bundle => {
282 const EbHdr = std.zig.Server.Message.ErrorBundle;
283 const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body));
284 const extra_bytes =
285 body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
286 const string_bytes =
287 body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
288 // TODO: use @ptrCast when the compiler supports it
289 const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
290 const extra_array = try arena.alloc(u32, unaligned_extra.len);
291 @memcpy(extra_array, unaligned_extra);
292 result_error_bundle = .{
293 .string_bytes = try arena.dupe(u8, string_bytes),
294 .extra = extra_array,
295 };
296 },
297 .emit_bin_path => {
298 const EbpHdr = std.zig.Server.Message.EmitBinPath;
299 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
300 if (!ebp_hdr.flags.cache_hit) {
301 std.log.info("source changes detected; rebuilt wasm component", .{});
302 }
303 result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]);
304 },
305 else => {}, // ignore other messages
306 }
307
308 stdout.discard(body.len);
309 }
310
311 const stderr = poller.fifo(.stderr);
312 if (stderr.readableLength() > 0) {
313 const owned_stderr = try stderr.toOwnedSlice();
314 defer gpa.free(owned_stderr);
315 std.debug.print("{s}", .{owned_stderr});
316 }
317
318 // Send EOF to stdin.
319 child.stdin.?.close();
320 child.stdin = null;
321
322 switch (try child.wait()) {
323 .Exited => |code| {
324 if (code != 0) {
325 std.log.err(
326 "the following command exited with error code {d}:\n{s}",
327 .{ code, try std.Build.Step.allocPrintCmd(arena, null, argv.items) },
328 );
329 return error.WasmCompilationFailed;
330 }
331 },
332 .Signal, .Stopped, .Unknown => {
333 std.log.err(
334 "the following command terminated unexpectedly:\n{s}",
335 .{try std.Build.Step.allocPrintCmd(arena, null, argv.items)},
336 );
337 return error.WasmCompilationFailed;
338 },
339 }
340
341 if (result_error_bundle.errorMessageCount() > 0) {
342 const color = std.zig.Color.auto;
343 result_error_bundle.renderToStdErr(color.renderOptions());
344 std.log.err("the following command failed with {d} compilation errors:\n{s}", .{
345 result_error_bundle.errorMessageCount(),
346 try std.Build.Step.allocPrintCmd(arena, null, argv.items),
347 });
348 return error.WasmCompilationFailed;
349 }
350
351 return result orelse {
352 std.log.err("child process failed to report result\n{s}", .{
353 try std.Build.Step.allocPrintCmd(arena, null, argv.items),
354 });
355 return error.WasmCompilationFailed;
356 };
357}
358
359fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
360 const header: std.zig.Client.Message.Header = .{
361 .tag = tag,
362 .bytes_len = 0,
363 };
364 try file.writeAll(std.mem.asBytes(&header));
365}
366
367fn openBrowserTab(gpa: Allocator, url: []const u8) !void {
368 // Until https://github.com/ziglang/zig/issues/19205 is implemented, we
369 // spawn a thread for this child process.
370 _ = try std.Thread.spawn(.{}, openBrowserTabThread, .{ gpa, url });
371}
372
373fn openBrowserTabThread(gpa: Allocator, url: []const u8) !void {
374 const main_exe = switch (builtin.os.tag) {
375 .windows => "explorer",
376 else => "xdg-open",
377 };
378 var child = std.ChildProcess.init(&.{ main_exe, url }, gpa);
379 child.stdin_behavior = .Ignore;
380 child.stdout_behavior = .Ignore;
381 child.stderr_behavior = .Ignore;
382 try child.spawn();
383 _ = try child.wait();
384}
lib/docs/commonmark.js deleted-10270
......@@ -1,10270 +0,0 @@
1/* commonmark 0.30.0 https://github.com/commonmark/commonmark.js @license BSD3 */
2(function (global, factory) {
3 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4 typeof define === 'function' && define.amd ? define(['exports'], factory) :
5 (global = global || self, factory(global.commonmark = {}));
6}(this, (function (exports) { 'use strict';
7
8 function isContainer(node) {
9 switch (node._type) {
10 case "document":
11 case "block_quote":
12 case "list":
13 case "item":
14 case "paragraph":
15 case "heading":
16 case "emph":
17 case "strong":
18 case "link":
19 case "image":
20 case "custom_inline":
21 case "custom_block":
22 return true;
23 default:
24 return false;
25 }
26 }
27
28 var resumeAt = function(node, entering) {
29 this.current = node;
30 this.entering = entering === true;
31 };
32
33 var next = function() {
34 var cur = this.current;
35 var entering = this.entering;
36
37 if (cur === null) {
38 return null;
39 }
40
41 var container = isContainer(cur);
42
43 if (entering && container) {
44 if (cur._firstChild) {
45 this.current = cur._firstChild;
46 this.entering = true;
47 } else {
48 // stay on node but exit
49 this.entering = false;
50 }
51 } else if (cur === this.root) {
52 this.current = null;
53 } else if (cur._next === null) {
54 this.current = cur._parent;
55 this.entering = false;
56 } else {
57 this.current = cur._next;
58 this.entering = true;
59 }
60
61 return { entering: entering, node: cur };
62 };
63
64 var NodeWalker = function(root) {
65 return {
66 current: root,
67 root: root,
68 entering: true,
69 next: next,
70 resumeAt: resumeAt
71 };
72 };
73
74 var Node = function(nodeType, sourcepos) {
75 this._type = nodeType;
76 this._parent = null;
77 this._firstChild = null;
78 this._lastChild = null;
79 this._prev = null;
80 this._next = null;
81 this._sourcepos = sourcepos;
82 this._lastLineBlank = false;
83 this._lastLineChecked = false;
84 this._open = true;
85 this._string_content = null;
86 this._literal = null;
87 this._listData = {};
88 this._info = null;
89 this._destination = null;
90 this._title = null;
91 this._isFenced = false;
92 this._fenceChar = null;
93 this._fenceLength = 0;
94 this._fenceOffset = null;
95 this._level = null;
96 this._onEnter = null;
97 this._onExit = null;
98 };
99
100 var proto = Node.prototype;
101
102 Object.defineProperty(proto, "isContainer", {
103 get: function() {
104 return isContainer(this);
105 }
106 });
107
108 Object.defineProperty(proto, "type", {
109 get: function() {
110 return this._type;
111 }
112 });
113
114 Object.defineProperty(proto, "firstChild", {
115 get: function() {
116 return this._firstChild;
117 }
118 });
119
120 Object.defineProperty(proto, "lastChild", {
121 get: function() {
122 return this._lastChild;
123 }
124 });
125
126 Object.defineProperty(proto, "next", {
127 get: function() {
128 return this._next;
129 }
130 });
131
132 Object.defineProperty(proto, "prev", {
133 get: function() {
134 return this._prev;
135 }
136 });
137
138 Object.defineProperty(proto, "parent", {
139 get: function() {
140 return this._parent;
141 }
142 });
143
144 Object.defineProperty(proto, "sourcepos", {
145 get: function() {
146 return this._sourcepos;
147 }
148 });
149
150 Object.defineProperty(proto, "literal", {
151 get: function() {
152 return this._literal;
153 },
154 set: function(s) {
155 this._literal = s;
156 }
157 });
158
159 Object.defineProperty(proto, "destination", {
160 get: function() {
161 return this._destination;
162 },
163 set: function(s) {
164 this._destination = s;
165 }
166 });
167
168 Object.defineProperty(proto, "title", {
169 get: function() {
170 return this._title;
171 },
172 set: function(s) {
173 this._title = s;
174 }
175 });
176
177 Object.defineProperty(proto, "info", {
178 get: function() {
179 return this._info;
180 },
181 set: function(s) {
182 this._info = s;
183 }
184 });
185
186 Object.defineProperty(proto, "level", {
187 get: function() {
188 return this._level;
189 },
190 set: function(s) {
191 this._level = s;
192 }
193 });
194
195 Object.defineProperty(proto, "listType", {
196 get: function() {
197 return this._listData.type;
198 },
199 set: function(t) {
200 this._listData.type = t;
201 }
202 });
203
204 Object.defineProperty(proto, "listTight", {
205 get: function() {
206 return this._listData.tight;
207 },
208 set: function(t) {
209 this._listData.tight = t;
210 }
211 });
212
213 Object.defineProperty(proto, "listStart", {
214 get: function() {
215 return this._listData.start;
216 },
217 set: function(n) {
218 this._listData.start = n;
219 }
220 });
221
222 Object.defineProperty(proto, "listDelimiter", {
223 get: function() {
224 return this._listData.delimiter;
225 },
226 set: function(delim) {
227 this._listData.delimiter = delim;
228 }
229 });
230
231 Object.defineProperty(proto, "onEnter", {
232 get: function() {
233 return this._onEnter;
234 },
235 set: function(s) {
236 this._onEnter = s;
237 }
238 });
239
240 Object.defineProperty(proto, "onExit", {
241 get: function() {
242 return this._onExit;
243 },
244 set: function(s) {
245 this._onExit = s;
246 }
247 });
248
249 Node.prototype.appendChild = function(child) {
250 child.unlink();
251 child._parent = this;
252 if (this._lastChild) {
253 this._lastChild._next = child;
254 child._prev = this._lastChild;
255 this._lastChild = child;
256 } else {
257 this._firstChild = child;
258 this._lastChild = child;
259 }
260 };
261
262 Node.prototype.prependChild = function(child) {
263 child.unlink();
264 child._parent = this;
265 if (this._firstChild) {
266 this._firstChild._prev = child;
267 child._next = this._firstChild;
268 this._firstChild = child;
269 } else {
270 this._firstChild = child;
271 this._lastChild = child;
272 }
273 };
274
275 Node.prototype.unlink = function() {
276 if (this._prev) {
277 this._prev._next = this._next;
278 } else if (this._parent) {
279 this._parent._firstChild = this._next;
280 }
281 if (this._next) {
282 this._next._prev = this._prev;
283 } else if (this._parent) {
284 this._parent._lastChild = this._prev;
285 }
286 this._parent = null;
287 this._next = null;
288 this._prev = null;
289 };
290
291 Node.prototype.insertAfter = function(sibling) {
292 sibling.unlink();
293 sibling._next = this._next;
294 if (sibling._next) {
295 sibling._next._prev = sibling;
296 }
297 sibling._prev = this;
298 this._next = sibling;
299 sibling._parent = this._parent;
300 if (!sibling._next) {
301 sibling._parent._lastChild = sibling;
302 }
303 };
304
305 Node.prototype.insertBefore = function(sibling) {
306 sibling.unlink();
307 sibling._prev = this._prev;
308 if (sibling._prev) {
309 sibling._prev._next = sibling;
310 }
311 sibling._next = this;
312 this._prev = sibling;
313 sibling._parent = this._parent;
314 if (!sibling._prev) {
315 sibling._parent._firstChild = sibling;
316 }
317 };
318
319 Node.prototype.walker = function() {
320 var walker = new NodeWalker(this);
321 return walker;
322 };
323
324 /* Example of use of walker:
325
326 var walker = w.walker();
327 var event;
328
329 while (event = walker.next()) {
330 console.log(event.entering, event.node.type);
331 }
332
333 */
334
335 var encodeCache = {};
336
337
338 // Create a lookup array where anything but characters in `chars` string
339 // and alphanumeric chars is percent-encoded.
340 //
341 function getEncodeCache(exclude) {
342 var i, ch, cache = encodeCache[exclude];
343 if (cache) { return cache; }
344
345 cache = encodeCache[exclude] = [];
346
347 for (i = 0; i < 128; i++) {
348 ch = String.fromCharCode(i);
349
350 if (/^[0-9a-z]$/i.test(ch)) {
351 // always allow unencoded alphanumeric characters
352 cache.push(ch);
353 } else {
354 cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));
355 }
356 }
357
358 for (i = 0; i < exclude.length; i++) {
359 cache[exclude.charCodeAt(i)] = exclude[i];
360 }
361
362 return cache;
363 }
364
365
366 // Encode unsafe characters with percent-encoding, skipping already
367 // encoded sequences.
368 //
369 // - string - string to encode
370 // - exclude - list of characters to ignore (in addition to a-zA-Z0-9)
371 // - keepEscaped - don't encode '%' in a correct escape sequence (default: true)
372 //
373 function encode(string, exclude, keepEscaped) {
374 var i, l, code, nextCode, cache,
375 result = '';
376
377 if (typeof exclude !== 'string') {
378 // encode(string, keepEscaped)
379 keepEscaped = exclude;
380 exclude = encode.defaultChars;
381 }
382
383 if (typeof keepEscaped === 'undefined') {
384 keepEscaped = true;
385 }
386
387 cache = getEncodeCache(exclude);
388
389 for (i = 0, l = string.length; i < l; i++) {
390 code = string.charCodeAt(i);
391
392 if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {
393 if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {
394 result += string.slice(i, i + 3);
395 i += 2;
396 continue;
397 }
398 }
399
400 if (code < 128) {
401 result += cache[code];
402 continue;
403 }
404
405 if (code >= 0xD800 && code <= 0xDFFF) {
406 if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {
407 nextCode = string.charCodeAt(i + 1);
408 if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {
409 result += encodeURIComponent(string[i] + string[i + 1]);
410 i++;
411 continue;
412 }
413 }
414 result += '%EF%BF%BD';
415 continue;
416 }
417
418 result += encodeURIComponent(string[i]);
419 }
420
421 return result;
422 }
423
424 encode.defaultChars = ";/?:@&=+$,-_.!~*'()#";
425 encode.componentChars = "-_.!~*'()";
426
427
428 var encode_1 = encode;
429
430 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
431
432 function unwrapExports (x) {
433 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
434 }
435
436 function createCommonjsModule(fn, module) {
437 return module = { exports: {} }, fn(module, module.exports), module.exports;
438 }
439
440 function getCjsExportFromNamespace (n) {
441 return n && n['default'] || n;
442 }
443
444 var Aacute = "Á";
445 var aacute = "á";
446 var Abreve = "Ă";
447 var abreve = "ă";
448 var ac = "∾";
449 var acd = "∿";
450 var acE = "∾̳";
451 var Acirc = "Â";
452 var acirc = "â";
453 var acute = "´";
454 var Acy = "А";
455 var acy = "а";
456 var AElig = "Æ";
457 var aelig = "æ";
458 var af = "⁡";
459 var Afr = "𝔄";
460 var afr = "𝔞";
461 var Agrave = "À";
462 var agrave = "à";
463 var alefsym = "ℵ";
464 var aleph = "ℵ";
465 var Alpha = "Α";
466 var alpha = "α";
467 var Amacr = "Ā";
468 var amacr = "ā";
469 var amalg = "⨿";
470 var amp = "&";
471 var AMP = "&";
472 var andand = "⩕";
473 var And = "⩓";
474 var and = "∧";
475 var andd = "⩜";
476 var andslope = "⩘";
477 var andv = "⩚";
478 var ang = "∠";
479 var ange = "⦤";
480 var angle = "∠";
481 var angmsdaa = "⦨";
482 var angmsdab = "⦩";
483 var angmsdac = "⦪";
484 var angmsdad = "⦫";
485 var angmsdae = "⦬";
486 var angmsdaf = "⦭";
487 var angmsdag = "⦮";
488 var angmsdah = "⦯";
489 var angmsd = "∡";
490 var angrt = "∟";
491 var angrtvb = "⊾";
492 var angrtvbd = "⦝";
493 var angsph = "∢";
494 var angst = "Å";
495 var angzarr = "⍼";
496 var Aogon = "Ą";
497 var aogon = "ą";
498 var Aopf = "𝔸";
499 var aopf = "𝕒";
500 var apacir = "⩯";
501 var ap = "≈";
502 var apE = "⩰";
503 var ape = "≊";
504 var apid = "≋";
505 var apos = "'";
506 var ApplyFunction = "⁡";
507 var approx = "≈";
508 var approxeq = "≊";
509 var Aring = "Å";
510 var aring = "å";
511 var Ascr = "𝒜";
512 var ascr = "𝒶";
513 var Assign = "≔";
514 var ast = "*";
515 var asymp = "≈";
516 var asympeq = "≍";
517 var Atilde = "Ã";
518 var atilde = "ã";
519 var Auml = "Ä";
520 var auml = "ä";
521 var awconint = "∳";
522 var awint = "⨑";
523 var backcong = "≌";
524 var backepsilon = "϶";
525 var backprime = "‵";
526 var backsim = "∽";
527 var backsimeq = "⋍";
528 var Backslash = "∖";
529 var Barv = "⫧";
530 var barvee = "⊽";
531 var barwed = "⌅";
532 var Barwed = "⌆";
533 var barwedge = "⌅";
534 var bbrk = "⎵";
535 var bbrktbrk = "⎶";
536 var bcong = "≌";
537 var Bcy = "Б";
538 var bcy = "б";
539 var bdquo = "„";
540 var becaus = "∵";
541 var because = "∵";
542 var Because = "∵";
543 var bemptyv = "⦰";
544 var bepsi = "϶";
545 var bernou = "ℬ";
546 var Bernoullis = "ℬ";
547 var Beta = "Β";
548 var beta = "β";
549 var beth = "ℶ";
550 var between = "≬";
551 var Bfr = "𝔅";
552 var bfr = "𝔟";
553 var bigcap = "⋂";
554 var bigcirc = "◯";
555 var bigcup = "⋃";
556 var bigodot = "⨀";
557 var bigoplus = "⨁";
558 var bigotimes = "⨂";
559 var bigsqcup = "⨆";
560 var bigstar = "★";
561 var bigtriangledown = "▽";
562 var bigtriangleup = "△";
563 var biguplus = "⨄";
564 var bigvee = "⋁";
565 var bigwedge = "⋀";
566 var bkarow = "⤍";
567 var blacklozenge = "⧫";
568 var blacksquare = "▪";
569 var blacktriangle = "▴";
570 var blacktriangledown = "▾";
571 var blacktriangleleft = "◂";
572 var blacktriangleright = "▸";
573 var blank = "␣";
574 var blk12 = "▒";
575 var blk14 = "░";
576 var blk34 = "▓";
577 var block = "█";
578 var bne = "=⃥";
579 var bnequiv = "≡⃥";
580 var bNot = "⫭";
581 var bnot = "⌐";
582 var Bopf = "𝔹";
583 var bopf = "𝕓";
584 var bot = "⊥";
585 var bottom = "⊥";
586 var bowtie = "⋈";
587 var boxbox = "⧉";
588 var boxdl = "┐";
589 var boxdL = "╕";
590 var boxDl = "╖";
591 var boxDL = "╗";
592 var boxdr = "┌";
593 var boxdR = "╒";
594 var boxDr = "╓";
595 var boxDR = "╔";
596 var boxh = "─";
597 var boxH = "═";
598 var boxhd = "┬";
599 var boxHd = "╤";
600 var boxhD = "╥";
601 var boxHD = "╦";
602 var boxhu = "┴";
603 var boxHu = "╧";
604 var boxhU = "╨";
605 var boxHU = "╩";
606 var boxminus = "⊟";
607 var boxplus = "⊞";
608 var boxtimes = "⊠";
609 var boxul = "┘";
610 var boxuL = "╛";
611 var boxUl = "╜";
612 var boxUL = "╝";
613 var boxur = "└";
614 var boxuR = "╘";
615 var boxUr = "╙";
616 var boxUR = "╚";
617 var boxv = "│";
618 var boxV = "║";
619 var boxvh = "┼";
620 var boxvH = "╪";
621 var boxVh = "╫";
622 var boxVH = "╬";
623 var boxvl = "┤";
624 var boxvL = "╡";
625 var boxVl = "╢";
626 var boxVL = "╣";
627 var boxvr = "├";
628 var boxvR = "╞";
629 var boxVr = "╟";
630 var boxVR = "╠";
631 var bprime = "‵";
632 var breve = "˘";
633 var Breve = "˘";
634 var brvbar = "¦";
635 var bscr = "𝒷";
636 var Bscr = "ℬ";
637 var bsemi = "⁏";
638 var bsim = "∽";
639 var bsime = "⋍";
640 var bsolb = "⧅";
641 var bsol = "\\";
642 var bsolhsub = "⟈";
643 var bull = "•";
644 var bullet = "•";
645 var bump = "≎";
646 var bumpE = "⪮";
647 var bumpe = "≏";
648 var Bumpeq = "≎";
649 var bumpeq = "≏";
650 var Cacute = "Ć";
651 var cacute = "ć";
652 var capand = "⩄";
653 var capbrcup = "⩉";
654 var capcap = "⩋";
655 var cap = "∩";
656 var Cap = "⋒";
657 var capcup = "⩇";
658 var capdot = "⩀";
659 var CapitalDifferentialD = "ⅅ";
660 var caps = "∩︀";
661 var caret = "⁁";
662 var caron = "ˇ";
663 var Cayleys = "ℭ";
664 var ccaps = "⩍";
665 var Ccaron = "Č";
666 var ccaron = "č";
667 var Ccedil = "Ç";
668 var ccedil = "ç";
669 var Ccirc = "Ĉ";
670 var ccirc = "ĉ";
671 var Cconint = "∰";
672 var ccups = "⩌";
673 var ccupssm = "⩐";
674 var Cdot = "Ċ";
675 var cdot = "ċ";
676 var cedil = "¸";
677 var Cedilla = "¸";
678 var cemptyv = "⦲";
679 var cent = "¢";
680 var centerdot = "·";
681 var CenterDot = "·";
682 var cfr = "𝔠";
683 var Cfr = "ℭ";
684 var CHcy = "Ч";
685 var chcy = "ч";
686 var check = "✓";
687 var checkmark = "✓";
688 var Chi = "Χ";
689 var chi = "χ";
690 var circ = "ˆ";
691 var circeq = "≗";
692 var circlearrowleft = "↺";
693 var circlearrowright = "↻";
694 var circledast = "⊛";
695 var circledcirc = "⊚";
696 var circleddash = "⊝";
697 var CircleDot = "⊙";
698 var circledR = "®";
699 var circledS = "Ⓢ";
700 var CircleMinus = "⊖";
701 var CirclePlus = "⊕";
702 var CircleTimes = "⊗";
703 var cir = "○";
704 var cirE = "⧃";
705 var cire = "≗";
706 var cirfnint = "⨐";
707 var cirmid = "⫯";
708 var cirscir = "⧂";
709 var ClockwiseContourIntegral = "∲";
710 var CloseCurlyDoubleQuote = "”";
711 var CloseCurlyQuote = "’";
712 var clubs = "♣";
713 var clubsuit = "♣";
714 var colon = ":";
715 var Colon = "∷";
716 var Colone = "⩴";
717 var colone = "≔";
718 var coloneq = "≔";
719 var comma = ",";
720 var commat = "@";
721 var comp = "∁";
722 var compfn = "∘";
723 var complement = "∁";
724 var complexes = "ℂ";
725 var cong = "≅";
726 var congdot = "⩭";
727 var Congruent = "≡";
728 var conint = "∮";
729 var Conint = "∯";
730 var ContourIntegral = "∮";
731 var copf = "𝕔";
732 var Copf = "ℂ";
733 var coprod = "∐";
734 var Coproduct = "∐";
735 var copy = "©";
736 var COPY = "©";
737 var copysr = "℗";
738 var CounterClockwiseContourIntegral = "∳";
739 var crarr = "↵";
740 var cross = "✗";
741 var Cross = "⨯";
742 var Cscr = "𝒞";
743 var cscr = "𝒸";
744 var csub = "⫏";
745 var csube = "⫑";
746 var csup = "⫐";
747 var csupe = "⫒";
748 var ctdot = "⋯";
749 var cudarrl = "⤸";
750 var cudarrr = "⤵";
751 var cuepr = "⋞";
752 var cuesc = "⋟";
753 var cularr = "↶";
754 var cularrp = "⤽";
755 var cupbrcap = "⩈";
756 var cupcap = "⩆";
757 var CupCap = "≍";
758 var cup = "∪";
759 var Cup = "⋓";
760 var cupcup = "⩊";
761 var cupdot = "⊍";
762 var cupor = "⩅";
763 var cups = "∪︀";
764 var curarr = "↷";
765 var curarrm = "⤼";
766 var curlyeqprec = "⋞";
767 var curlyeqsucc = "⋟";
768 var curlyvee = "⋎";
769 var curlywedge = "⋏";
770 var curren = "¤";
771 var curvearrowleft = "↶";
772 var curvearrowright = "↷";
773 var cuvee = "⋎";
774 var cuwed = "⋏";
775 var cwconint = "∲";
776 var cwint = "∱";
777 var cylcty = "⌭";
778 var dagger = "†";
779 var Dagger = "‡";
780 var daleth = "ℸ";
781 var darr = "↓";
782 var Darr = "↡";
783 var dArr = "⇓";
784 var dash = "‐";
785 var Dashv = "⫤";
786 var dashv = "⊣";
787 var dbkarow = "⤏";
788 var dblac = "˝";
789 var Dcaron = "Ď";
790 var dcaron = "ď";
791 var Dcy = "Д";
792 var dcy = "д";
793 var ddagger = "‡";
794 var ddarr = "⇊";
795 var DD = "ⅅ";
796 var dd = "ⅆ";
797 var DDotrahd = "⤑";
798 var ddotseq = "⩷";
799 var deg = "°";
800 var Del = "∇";
801 var Delta = "Δ";
802 var delta = "δ";
803 var demptyv = "⦱";
804 var dfisht = "⥿";
805 var Dfr = "𝔇";
806 var dfr = "𝔡";
807 var dHar = "⥥";
808 var dharl = "⇃";
809 var dharr = "⇂";
810 var DiacriticalAcute = "´";
811 var DiacriticalDot = "˙";
812 var DiacriticalDoubleAcute = "˝";
813 var DiacriticalGrave = "`";
814 var DiacriticalTilde = "˜";
815 var diam = "⋄";
816 var diamond = "⋄";
817 var Diamond = "⋄";
818 var diamondsuit = "♦";
819 var diams = "♦";
820 var die = "¨";
821 var DifferentialD = "ⅆ";
822 var digamma = "ϝ";
823 var disin = "⋲";
824 var div = "÷";
825 var divide = "÷";
826 var divideontimes = "⋇";
827 var divonx = "⋇";
828 var DJcy = "Ђ";
829 var djcy = "ђ";
830 var dlcorn = "⌞";
831 var dlcrop = "⌍";
832 var dollar = "$";
833 var Dopf = "𝔻";
834 var dopf = "𝕕";
835 var Dot = "¨";
836 var dot = "˙";
837 var DotDot = "⃜";
838 var doteq = "≐";
839 var doteqdot = "≑";
840 var DotEqual = "≐";
841 var dotminus = "∸";
842 var dotplus = "∔";
843 var dotsquare = "⊡";
844 var doublebarwedge = "⌆";
845 var DoubleContourIntegral = "∯";
846 var DoubleDot = "¨";
847 var DoubleDownArrow = "⇓";
848 var DoubleLeftArrow = "⇐";
849 var DoubleLeftRightArrow = "⇔";
850 var DoubleLeftTee = "⫤";
851 var DoubleLongLeftArrow = "⟸";
852 var DoubleLongLeftRightArrow = "⟺";
853 var DoubleLongRightArrow = "⟹";
854 var DoubleRightArrow = "⇒";
855 var DoubleRightTee = "⊨";
856 var DoubleUpArrow = "⇑";
857 var DoubleUpDownArrow = "⇕";
858 var DoubleVerticalBar = "∥";
859 var DownArrowBar = "⤓";
860 var downarrow = "↓";
861 var DownArrow = "↓";
862 var Downarrow = "⇓";
863 var DownArrowUpArrow = "⇵";
864 var DownBreve = "̑";
865 var downdownarrows = "⇊";
866 var downharpoonleft = "⇃";
867 var downharpoonright = "⇂";
868 var DownLeftRightVector = "⥐";
869 var DownLeftTeeVector = "⥞";
870 var DownLeftVectorBar = "⥖";
871 var DownLeftVector = "↽";
872 var DownRightTeeVector = "⥟";
873 var DownRightVectorBar = "⥗";
874 var DownRightVector = "⇁";
875 var DownTeeArrow = "↧";
876 var DownTee = "⊤";
877 var drbkarow = "⤐";
878 var drcorn = "⌟";
879 var drcrop = "⌌";
880 var Dscr = "𝒟";
881 var dscr = "𝒹";
882 var DScy = "Ѕ";
883 var dscy = "ѕ";
884 var dsol = "⧶";
885 var Dstrok = "Đ";
886 var dstrok = "đ";
887 var dtdot = "⋱";
888 var dtri = "▿";
889 var dtrif = "▾";
890 var duarr = "⇵";
891 var duhar = "⥯";
892 var dwangle = "⦦";
893 var DZcy = "Џ";
894 var dzcy = "џ";
895 var dzigrarr = "⟿";
896 var Eacute = "É";
897 var eacute = "é";
898 var easter = "⩮";
899 var Ecaron = "Ě";
900 var ecaron = "ě";
901 var Ecirc = "Ê";
902 var ecirc = "ê";
903 var ecir = "≖";
904 var ecolon = "≕";
905 var Ecy = "Э";
906 var ecy = "э";
907 var eDDot = "⩷";
908 var Edot = "Ė";
909 var edot = "ė";
910 var eDot = "≑";
911 var ee = "ⅇ";
912 var efDot = "≒";
913 var Efr = "𝔈";
914 var efr = "𝔢";
915 var eg = "⪚";
916 var Egrave = "È";
917 var egrave = "è";
918 var egs = "⪖";
919 var egsdot = "⪘";
920 var el = "⪙";
921 var Element = "∈";
922 var elinters = "⏧";
923 var ell = "ℓ";
924 var els = "⪕";
925 var elsdot = "⪗";
926 var Emacr = "Ē";
927 var emacr = "ē";
928 var empty = "∅";
929 var emptyset = "∅";
930 var EmptySmallSquare = "◻";
931 var emptyv = "∅";
932 var EmptyVerySmallSquare = "▫";
933 var emsp13 = " ";
934 var emsp14 = " ";
935 var emsp = " ";
936 var ENG = "Ŋ";
937 var eng = "ŋ";
938 var ensp = " ";
939 var Eogon = "Ę";
940 var eogon = "ę";
941 var Eopf = "𝔼";
942 var eopf = "𝕖";
943 var epar = "⋕";
944 var eparsl = "⧣";
945 var eplus = "⩱";
946 var epsi = "ε";
947 var Epsilon = "Ε";
948 var epsilon = "ε";
949 var epsiv = "ϵ";
950 var eqcirc = "≖";
951 var eqcolon = "≕";
952 var eqsim = "≂";
953 var eqslantgtr = "⪖";
954 var eqslantless = "⪕";
955 var Equal = "⩵";
956 var equals = "=";
957 var EqualTilde = "≂";
958 var equest = "≟";
959 var Equilibrium = "⇌";
960 var equiv = "≡";
961 var equivDD = "⩸";
962 var eqvparsl = "⧥";
963 var erarr = "⥱";
964 var erDot = "≓";
965 var escr = "ℯ";
966 var Escr = "ℰ";
967 var esdot = "≐";
968 var Esim = "⩳";
969 var esim = "≂";
970 var Eta = "Η";
971 var eta = "η";
972 var ETH = "Ð";
973 var eth = "ð";
974 var Euml = "Ë";
975 var euml = "ë";
976 var euro = "€";
977 var excl = "!";
978 var exist = "∃";
979 var Exists = "∃";
980 var expectation = "ℰ";
981 var exponentiale = "ⅇ";
982 var ExponentialE = "ⅇ";
983 var fallingdotseq = "≒";
984 var Fcy = "Ф";
985 var fcy = "ф";
986 var female = "♀";
987 var ffilig = "ffi";
988 var fflig = "ff";
989 var ffllig = "ffl";
990 var Ffr = "𝔉";
991 var ffr = "𝔣";
992 var filig = "fi";
993 var FilledSmallSquare = "◼";
994 var FilledVerySmallSquare = "▪";
995 var fjlig = "fj";
996 var flat = "♭";
997 var fllig = "fl";
998 var fltns = "▱";
999 var fnof = "ƒ";
1000 var Fopf = "𝔽";
1001 var fopf = "𝕗";
1002 var forall = "∀";
1003 var ForAll = "∀";
1004 var fork = "⋔";
1005 var forkv = "⫙";
1006 var Fouriertrf = "ℱ";
1007 var fpartint = "⨍";
1008 var frac12 = "½";
1009 var frac13 = "⅓";
1010 var frac14 = "¼";
1011 var frac15 = "⅕";
1012 var frac16 = "⅙";
1013 var frac18 = "⅛";
1014 var frac23 = "⅔";
1015 var frac25 = "⅖";
1016 var frac34 = "¾";
1017 var frac35 = "⅗";
1018 var frac38 = "⅜";
1019 var frac45 = "⅘";
1020 var frac56 = "⅚";
1021 var frac58 = "⅝";
1022 var frac78 = "⅞";
1023 var frasl = "⁄";
1024 var frown = "⌢";
1025 var fscr = "𝒻";
1026 var Fscr = "ℱ";
1027 var gacute = "ǵ";
1028 var Gamma = "Γ";
1029 var gamma = "γ";
1030 var Gammad = "Ϝ";
1031 var gammad = "ϝ";
1032 var gap = "⪆";
1033 var Gbreve = "Ğ";
1034 var gbreve = "ğ";
1035 var Gcedil = "Ģ";
1036 var Gcirc = "Ĝ";
1037 var gcirc = "ĝ";
1038 var Gcy = "Г";
1039 var gcy = "г";
1040 var Gdot = "Ġ";
1041 var gdot = "ġ";
1042 var ge = "≥";
1043 var gE = "≧";
1044 var gEl = "⪌";
1045 var gel = "⋛";
1046 var geq = "≥";
1047 var geqq = "≧";
1048 var geqslant = "⩾";
1049 var gescc = "⪩";
1050 var ges = "⩾";
1051 var gesdot = "⪀";
1052 var gesdoto = "⪂";
1053 var gesdotol = "⪄";
1054 var gesl = "⋛︀";
1055 var gesles = "⪔";
1056 var Gfr = "𝔊";
1057 var gfr = "𝔤";
1058 var gg = "≫";
1059 var Gg = "⋙";
1060 var ggg = "⋙";
1061 var gimel = "ℷ";
1062 var GJcy = "Ѓ";
1063 var gjcy = "ѓ";
1064 var gla = "⪥";
1065 var gl = "≷";
1066 var glE = "⪒";
1067 var glj = "⪤";
1068 var gnap = "⪊";
1069 var gnapprox = "⪊";
1070 var gne = "⪈";
1071 var gnE = "≩";
1072 var gneq = "⪈";
1073 var gneqq = "≩";
1074 var gnsim = "⋧";
1075 var Gopf = "𝔾";
1076 var gopf = "𝕘";
1077 var grave = "`";
1078 var GreaterEqual = "≥";
1079 var GreaterEqualLess = "⋛";
1080 var GreaterFullEqual = "≧";
1081 var GreaterGreater = "⪢";
1082 var GreaterLess = "≷";
1083 var GreaterSlantEqual = "⩾";
1084 var GreaterTilde = "≳";
1085 var Gscr = "𝒢";
1086 var gscr = "ℊ";
1087 var gsim = "≳";
1088 var gsime = "⪎";
1089 var gsiml = "⪐";
1090 var gtcc = "⪧";
1091 var gtcir = "⩺";
1092 var gt = ">";
1093 var GT = ">";
1094 var Gt = "≫";
1095 var gtdot = "⋗";
1096 var gtlPar = "⦕";
1097 var gtquest = "⩼";
1098 var gtrapprox = "⪆";
1099 var gtrarr = "⥸";
1100 var gtrdot = "⋗";
1101 var gtreqless = "⋛";
1102 var gtreqqless = "⪌";
1103 var gtrless = "≷";
1104 var gtrsim = "≳";
1105 var gvertneqq = "≩︀";
1106 var gvnE = "≩︀";
1107 var Hacek = "ˇ";
1108 var hairsp = " ";
1109 var half = "½";
1110 var hamilt = "ℋ";
1111 var HARDcy = "Ъ";
1112 var hardcy = "ъ";
1113 var harrcir = "⥈";
1114 var harr = "↔";
1115 var hArr = "⇔";
1116 var harrw = "↭";
1117 var Hat = "^";
1118 var hbar = "ℏ";
1119 var Hcirc = "Ĥ";
1120 var hcirc = "ĥ";
1121 var hearts = "♥";
1122 var heartsuit = "♥";
1123 var hellip = "…";
1124 var hercon = "⊹";
1125 var hfr = "𝔥";
1126 var Hfr = "ℌ";
1127 var HilbertSpace = "ℋ";
1128 var hksearow = "⤥";
1129 var hkswarow = "⤦";
1130 var hoarr = "⇿";
1131 var homtht = "∻";
1132 var hookleftarrow = "↩";
1133 var hookrightarrow = "↪";
1134 var hopf = "𝕙";
1135 var Hopf = "ℍ";
1136 var horbar = "―";
1137 var HorizontalLine = "─";
1138 var hscr = "𝒽";
1139 var Hscr = "ℋ";
1140 var hslash = "ℏ";
1141 var Hstrok = "Ħ";
1142 var hstrok = "ħ";
1143 var HumpDownHump = "≎";
1144 var HumpEqual = "≏";
1145 var hybull = "⁃";
1146 var hyphen = "‐";
1147 var Iacute = "Í";
1148 var iacute = "í";
1149 var ic = "⁣";
1150 var Icirc = "Î";
1151 var icirc = "î";
1152 var Icy = "И";
1153 var icy = "и";
1154 var Idot = "İ";
1155 var IEcy = "Е";
1156 var iecy = "е";
1157 var iexcl = "¡";
1158 var iff = "⇔";
1159 var ifr = "𝔦";
1160 var Ifr = "ℑ";
1161 var Igrave = "Ì";
1162 var igrave = "ì";
1163 var ii = "ⅈ";
1164 var iiiint = "⨌";
1165 var iiint = "∭";
1166 var iinfin = "⧜";
1167 var iiota = "℩";
1168 var IJlig = "IJ";
1169 var ijlig = "ij";
1170 var Imacr = "Ī";
1171 var imacr = "ī";
1172 var image = "ℑ";
1173 var ImaginaryI = "ⅈ";
1174 var imagline = "ℐ";
1175 var imagpart = "ℑ";
1176 var imath = "ı";
1177 var Im = "ℑ";
1178 var imof = "⊷";
1179 var imped = "Ƶ";
1180 var Implies = "⇒";
1181 var incare = "℅";
1182 var infin = "∞";
1183 var infintie = "⧝";
1184 var inodot = "ı";
1185 var intcal = "⊺";
1186 var int = "∫";
1187 var Int = "∬";
1188 var integers = "ℤ";
1189 var Integral = "∫";
1190 var intercal = "⊺";
1191 var Intersection = "⋂";
1192 var intlarhk = "⨗";
1193 var intprod = "⨼";
1194 var InvisibleComma = "⁣";
1195 var InvisibleTimes = "⁢";
1196 var IOcy = "Ё";
1197 var iocy = "ё";
1198 var Iogon = "Į";
1199 var iogon = "į";
1200 var Iopf = "𝕀";
1201 var iopf = "𝕚";
1202 var Iota = "Ι";
1203 var iota = "ι";
1204 var iprod = "⨼";
1205 var iquest = "¿";
1206 var iscr = "𝒾";
1207 var Iscr = "ℐ";
1208 var isin = "∈";
1209 var isindot = "⋵";
1210 var isinE = "⋹";
1211 var isins = "⋴";
1212 var isinsv = "⋳";
1213 var isinv = "∈";
1214 var it = "⁢";
1215 var Itilde = "Ĩ";
1216 var itilde = "ĩ";
1217 var Iukcy = "І";
1218 var iukcy = "і";
1219 var Iuml = "Ï";
1220 var iuml = "ï";
1221 var Jcirc = "Ĵ";
1222 var jcirc = "ĵ";
1223 var Jcy = "Й";
1224 var jcy = "й";
1225 var Jfr = "𝔍";
1226 var jfr = "𝔧";
1227 var jmath = "ȷ";
1228 var Jopf = "𝕁";
1229 var jopf = "𝕛";
1230 var Jscr = "𝒥";
1231 var jscr = "𝒿";
1232 var Jsercy = "Ј";
1233 var jsercy = "ј";
1234 var Jukcy = "Є";
1235 var jukcy = "є";
1236 var Kappa = "Κ";
1237 var kappa = "κ";
1238 var kappav = "ϰ";
1239 var Kcedil = "Ķ";
1240 var kcedil = "ķ";
1241 var Kcy = "К";
1242 var kcy = "к";
1243 var Kfr = "𝔎";
1244 var kfr = "𝔨";
1245 var kgreen = "ĸ";
1246 var KHcy = "Х";
1247 var khcy = "х";
1248 var KJcy = "Ќ";
1249 var kjcy = "ќ";
1250 var Kopf = "𝕂";
1251 var kopf = "𝕜";
1252 var Kscr = "𝒦";
1253 var kscr = "𝓀";
1254 var lAarr = "⇚";
1255 var Lacute = "Ĺ";
1256 var lacute = "ĺ";
1257 var laemptyv = "⦴";
1258 var lagran = "ℒ";
1259 var Lambda = "Λ";
1260 var lambda = "λ";
1261 var lang = "⟨";
1262 var Lang = "⟪";
1263 var langd = "⦑";
1264 var langle = "⟨";
1265 var lap = "⪅";
1266 var Laplacetrf = "ℒ";
1267 var laquo = "«";
1268 var larrb = "⇤";
1269 var larrbfs = "⤟";
1270 var larr = "←";
1271 var Larr = "↞";
1272 var lArr = "⇐";
1273 var larrfs = "⤝";
1274 var larrhk = "↩";
1275 var larrlp = "↫";
1276 var larrpl = "⤹";
1277 var larrsim = "⥳";
1278 var larrtl = "↢";
1279 var latail = "⤙";
1280 var lAtail = "⤛";
1281 var lat = "⪫";
1282 var late = "⪭";
1283 var lates = "⪭︀";
1284 var lbarr = "⤌";
1285 var lBarr = "⤎";
1286 var lbbrk = "❲";
1287 var lbrace = "{";
1288 var lbrack = "[";
1289 var lbrke = "⦋";
1290 var lbrksld = "⦏";
1291 var lbrkslu = "⦍";
1292 var Lcaron = "Ľ";
1293 var lcaron = "ľ";
1294 var Lcedil = "Ļ";
1295 var lcedil = "ļ";
1296 var lceil = "⌈";
1297 var lcub = "{";
1298 var Lcy = "Л";
1299 var lcy = "л";
1300 var ldca = "⤶";
1301 var ldquo = "“";
1302 var ldquor = "„";
1303 var ldrdhar = "⥧";
1304 var ldrushar = "⥋";
1305 var ldsh = "↲";
1306 var le = "≤";
1307 var lE = "≦";
1308 var LeftAngleBracket = "⟨";
1309 var LeftArrowBar = "⇤";
1310 var leftarrow = "←";
1311 var LeftArrow = "←";
1312 var Leftarrow = "⇐";
1313 var LeftArrowRightArrow = "⇆";
1314 var leftarrowtail = "↢";
1315 var LeftCeiling = "⌈";
1316 var LeftDoubleBracket = "⟦";
1317 var LeftDownTeeVector = "⥡";
1318 var LeftDownVectorBar = "⥙";
1319 var LeftDownVector = "⇃";
1320 var LeftFloor = "⌊";
1321 var leftharpoondown = "↽";
1322 var leftharpoonup = "↼";
1323 var leftleftarrows = "⇇";
1324 var leftrightarrow = "↔";
1325 var LeftRightArrow = "↔";
1326 var Leftrightarrow = "⇔";
1327 var leftrightarrows = "⇆";
1328 var leftrightharpoons = "⇋";
1329 var leftrightsquigarrow = "↭";
1330 var LeftRightVector = "⥎";
1331 var LeftTeeArrow = "↤";
1332 var LeftTee = "⊣";
1333 var LeftTeeVector = "⥚";
1334 var leftthreetimes = "⋋";
1335 var LeftTriangleBar = "⧏";
1336 var LeftTriangle = "⊲";
1337 var LeftTriangleEqual = "⊴";
1338 var LeftUpDownVector = "⥑";
1339 var LeftUpTeeVector = "⥠";
1340 var LeftUpVectorBar = "⥘";
1341 var LeftUpVector = "↿";
1342 var LeftVectorBar = "⥒";
1343 var LeftVector = "↼";
1344 var lEg = "⪋";
1345 var leg = "⋚";
1346 var leq = "≤";
1347 var leqq = "≦";
1348 var leqslant = "⩽";
1349 var lescc = "⪨";
1350 var les = "⩽";
1351 var lesdot = "⩿";
1352 var lesdoto = "⪁";
1353 var lesdotor = "⪃";
1354 var lesg = "⋚︀";
1355 var lesges = "⪓";
1356 var lessapprox = "⪅";
1357 var lessdot = "⋖";
1358 var lesseqgtr = "⋚";
1359 var lesseqqgtr = "⪋";
1360 var LessEqualGreater = "⋚";
1361 var LessFullEqual = "≦";
1362 var LessGreater = "≶";
1363 var lessgtr = "≶";
1364 var LessLess = "⪡";
1365 var lesssim = "≲";
1366 var LessSlantEqual = "⩽";
1367 var LessTilde = "≲";
1368 var lfisht = "⥼";
1369 var lfloor = "⌊";
1370 var Lfr = "𝔏";
1371 var lfr = "𝔩";
1372 var lg = "≶";
1373 var lgE = "⪑";
1374 var lHar = "⥢";
1375 var lhard = "↽";
1376 var lharu = "↼";
1377 var lharul = "⥪";
1378 var lhblk = "▄";
1379 var LJcy = "Љ";
1380 var ljcy = "љ";
1381 var llarr = "⇇";
1382 var ll = "≪";
1383 var Ll = "⋘";
1384 var llcorner = "⌞";
1385 var Lleftarrow = "⇚";
1386 var llhard = "⥫";
1387 var lltri = "◺";
1388 var Lmidot = "Ŀ";
1389 var lmidot = "ŀ";
1390 var lmoustache = "⎰";
1391 var lmoust = "⎰";
1392 var lnap = "⪉";
1393 var lnapprox = "⪉";
1394 var lne = "⪇";
1395 var lnE = "≨";
1396 var lneq = "⪇";
1397 var lneqq = "≨";
1398 var lnsim = "⋦";
1399 var loang = "⟬";
1400 var loarr = "⇽";
1401 var lobrk = "⟦";
1402 var longleftarrow = "⟵";
1403 var LongLeftArrow = "⟵";
1404 var Longleftarrow = "⟸";
1405 var longleftrightarrow = "⟷";
1406 var LongLeftRightArrow = "⟷";
1407 var Longleftrightarrow = "⟺";
1408 var longmapsto = "⟼";
1409 var longrightarrow = "⟶";
1410 var LongRightArrow = "⟶";
1411 var Longrightarrow = "⟹";
1412 var looparrowleft = "↫";
1413 var looparrowright = "↬";
1414 var lopar = "⦅";
1415 var Lopf = "𝕃";
1416 var lopf = "𝕝";
1417 var loplus = "⨭";
1418 var lotimes = "⨴";
1419 var lowast = "∗";
1420 var lowbar = "_";
1421 var LowerLeftArrow = "↙";
1422 var LowerRightArrow = "↘";
1423 var loz = "◊";
1424 var lozenge = "◊";
1425 var lozf = "⧫";
1426 var lpar = "(";
1427 var lparlt = "⦓";
1428 var lrarr = "⇆";
1429 var lrcorner = "⌟";
1430 var lrhar = "⇋";
1431 var lrhard = "⥭";
1432 var lrm = "‎";
1433 var lrtri = "⊿";
1434 var lsaquo = "‹";
1435 var lscr = "𝓁";
1436 var Lscr = "ℒ";
1437 var lsh = "↰";
1438 var Lsh = "↰";
1439 var lsim = "≲";
1440 var lsime = "⪍";
1441 var lsimg = "⪏";
1442 var lsqb = "[";
1443 var lsquo = "‘";
1444 var lsquor = "‚";
1445 var Lstrok = "Ł";
1446 var lstrok = "ł";
1447 var ltcc = "⪦";
1448 var ltcir = "⩹";
1449 var lt = "<";
1450 var LT = "<";
1451 var Lt = "≪";
1452 var ltdot = "⋖";
1453 var lthree = "⋋";
1454 var ltimes = "⋉";
1455 var ltlarr = "⥶";
1456 var ltquest = "⩻";
1457 var ltri = "◃";
1458 var ltrie = "⊴";
1459 var ltrif = "◂";
1460 var ltrPar = "⦖";
1461 var lurdshar = "⥊";
1462 var luruhar = "⥦";
1463 var lvertneqq = "≨︀";
1464 var lvnE = "≨︀";
1465 var macr = "¯";
1466 var male = "♂";
1467 var malt = "✠";
1468 var maltese = "✠";
1469 var map = "↦";
1470 var mapsto = "↦";
1471 var mapstodown = "↧";
1472 var mapstoleft = "↤";
1473 var mapstoup = "↥";
1474 var marker = "▮";
1475 var mcomma = "⨩";
1476 var Mcy = "М";
1477 var mcy = "м";
1478 var mdash = "—";
1479 var mDDot = "∺";
1480 var measuredangle = "∡";
1481 var MediumSpace = " ";
1482 var Mellintrf = "ℳ";
1483 var Mfr = "𝔐";
1484 var mfr = "𝔪";
1485 var mho = "℧";
1486 var micro = "µ";
1487 var midast = "*";
1488 var midcir = "⫰";
1489 var mid = "∣";
1490 var middot = "·";
1491 var minusb = "⊟";
1492 var minus = "−";
1493 var minusd = "∸";
1494 var minusdu = "⨪";
1495 var MinusPlus = "∓";
1496 var mlcp = "⫛";
1497 var mldr = "…";
1498 var mnplus = "∓";
1499 var models = "⊧";
1500 var Mopf = "𝕄";
1501 var mopf = "𝕞";
1502 var mp = "∓";
1503 var mscr = "𝓂";
1504 var Mscr = "ℳ";
1505 var mstpos = "∾";
1506 var Mu = "Μ";
1507 var mu = "μ";
1508 var multimap = "⊸";
1509 var mumap = "⊸";
1510 var nabla = "∇";
1511 var Nacute = "Ń";
1512 var nacute = "ń";
1513 var nang = "∠⃒";
1514 var nap = "≉";
1515 var napE = "⩰̸";
1516 var napid = "≋̸";
1517 var napos = "ʼn";
1518 var napprox = "≉";
1519 var natural = "♮";
1520 var naturals = "ℕ";
1521 var natur = "♮";
1522 var nbsp = " ";
1523 var nbump = "≎̸";
1524 var nbumpe = "≏̸";
1525 var ncap = "⩃";
1526 var Ncaron = "Ň";
1527 var ncaron = "ň";
1528 var Ncedil = "Ņ";
1529 var ncedil = "ņ";
1530 var ncong = "≇";
1531 var ncongdot = "⩭̸";
1532 var ncup = "⩂";
1533 var Ncy = "Н";
1534 var ncy = "н";
1535 var ndash = "–";
1536 var nearhk = "⤤";
1537 var nearr = "↗";
1538 var neArr = "⇗";
1539 var nearrow = "↗";
1540 var ne = "≠";
1541 var nedot = "≐̸";
1542 var NegativeMediumSpace = "​";
1543 var NegativeThickSpace = "​";
1544 var NegativeThinSpace = "​";
1545 var NegativeVeryThinSpace = "​";
1546 var nequiv = "≢";
1547 var nesear = "⤨";
1548 var nesim = "≂̸";
1549 var NestedGreaterGreater = "≫";
1550 var NestedLessLess = "≪";
1551 var NewLine = "\n";
1552 var nexist = "∄";
1553 var nexists = "∄";
1554 var Nfr = "𝔑";
1555 var nfr = "𝔫";
1556 var ngE = "≧̸";
1557 var nge = "≱";
1558 var ngeq = "≱";
1559 var ngeqq = "≧̸";
1560 var ngeqslant = "⩾̸";
1561 var nges = "⩾̸";
1562 var nGg = "⋙̸";
1563 var ngsim = "≵";
1564 var nGt = "≫⃒";
1565 var ngt = "≯";
1566 var ngtr = "≯";
1567 var nGtv = "≫̸";
1568 var nharr = "↮";
1569 var nhArr = "⇎";
1570 var nhpar = "⫲";
1571 var ni = "∋";
1572 var nis = "⋼";
1573 var nisd = "⋺";
1574 var niv = "∋";
1575 var NJcy = "Њ";
1576 var njcy = "њ";
1577 var nlarr = "↚";
1578 var nlArr = "⇍";
1579 var nldr = "‥";
1580 var nlE = "≦̸";
1581 var nle = "≰";
1582 var nleftarrow = "↚";
1583 var nLeftarrow = "⇍";
1584 var nleftrightarrow = "↮";
1585 var nLeftrightarrow = "⇎";
1586 var nleq = "≰";
1587 var nleqq = "≦̸";
1588 var nleqslant = "⩽̸";
1589 var nles = "⩽̸";
1590 var nless = "≮";
1591 var nLl = "⋘̸";
1592 var nlsim = "≴";
1593 var nLt = "≪⃒";
1594 var nlt = "≮";
1595 var nltri = "⋪";
1596 var nltrie = "⋬";
1597 var nLtv = "≪̸";
1598 var nmid = "∤";
1599 var NoBreak = "⁠";
1600 var NonBreakingSpace = " ";
1601 var nopf = "𝕟";
1602 var Nopf = "ℕ";
1603 var Not = "⫬";
1604 var not = "¬";
1605 var NotCongruent = "≢";
1606 var NotCupCap = "≭";
1607 var NotDoubleVerticalBar = "∦";
1608 var NotElement = "∉";
1609 var NotEqual = "≠";
1610 var NotEqualTilde = "≂̸";
1611 var NotExists = "∄";
1612 var NotGreater = "≯";
1613 var NotGreaterEqual = "≱";
1614 var NotGreaterFullEqual = "≧̸";
1615 var NotGreaterGreater = "≫̸";
1616 var NotGreaterLess = "≹";
1617 var NotGreaterSlantEqual = "⩾̸";
1618 var NotGreaterTilde = "≵";
1619 var NotHumpDownHump = "≎̸";
1620 var NotHumpEqual = "≏̸";
1621 var notin = "∉";
1622 var notindot = "⋵̸";
1623 var notinE = "⋹̸";
1624 var notinva = "∉";
1625 var notinvb = "⋷";
1626 var notinvc = "⋶";
1627 var NotLeftTriangleBar = "⧏̸";
1628 var NotLeftTriangle = "⋪";
1629 var NotLeftTriangleEqual = "⋬";
1630 var NotLess = "≮";
1631 var NotLessEqual = "≰";
1632 var NotLessGreater = "≸";
1633 var NotLessLess = "≪̸";
1634 var NotLessSlantEqual = "⩽̸";
1635 var NotLessTilde = "≴";
1636 var NotNestedGreaterGreater = "⪢̸";
1637 var NotNestedLessLess = "⪡̸";
1638 var notni = "∌";
1639 var notniva = "∌";
1640 var notnivb = "⋾";
1641 var notnivc = "⋽";
1642 var NotPrecedes = "⊀";
1643 var NotPrecedesEqual = "⪯̸";
1644 var NotPrecedesSlantEqual = "⋠";
1645 var NotReverseElement = "∌";
1646 var NotRightTriangleBar = "⧐̸";
1647 var NotRightTriangle = "⋫";
1648 var NotRightTriangleEqual = "⋭";
1649 var NotSquareSubset = "⊏̸";
1650 var NotSquareSubsetEqual = "⋢";
1651 var NotSquareSuperset = "⊐̸";
1652 var NotSquareSupersetEqual = "⋣";
1653 var NotSubset = "⊂⃒";
1654 var NotSubsetEqual = "⊈";
1655 var NotSucceeds = "⊁";
1656 var NotSucceedsEqual = "⪰̸";
1657 var NotSucceedsSlantEqual = "⋡";
1658 var NotSucceedsTilde = "≿̸";
1659 var NotSuperset = "⊃⃒";
1660 var NotSupersetEqual = "⊉";
1661 var NotTilde = "≁";
1662 var NotTildeEqual = "≄";
1663 var NotTildeFullEqual = "≇";
1664 var NotTildeTilde = "≉";
1665 var NotVerticalBar = "∤";
1666 var nparallel = "∦";
1667 var npar = "∦";
1668 var nparsl = "⫽⃥";
1669 var npart = "∂̸";
1670 var npolint = "⨔";
1671 var npr = "⊀";
1672 var nprcue = "⋠";
1673 var nprec = "⊀";
1674 var npreceq = "⪯̸";
1675 var npre = "⪯̸";
1676 var nrarrc = "⤳̸";
1677 var nrarr = "↛";
1678 var nrArr = "⇏";
1679 var nrarrw = "↝̸";
1680 var nrightarrow = "↛";
1681 var nRightarrow = "⇏";
1682 var nrtri = "⋫";
1683 var nrtrie = "⋭";
1684 var nsc = "⊁";
1685 var nsccue = "⋡";
1686 var nsce = "⪰̸";
1687 var Nscr = "𝒩";
1688 var nscr = "𝓃";
1689 var nshortmid = "∤";
1690 var nshortparallel = "∦";
1691 var nsim = "≁";
1692 var nsime = "≄";
1693 var nsimeq = "≄";
1694 var nsmid = "∤";
1695 var nspar = "∦";
1696 var nsqsube = "⋢";
1697 var nsqsupe = "⋣";
1698 var nsub = "⊄";
1699 var nsubE = "⫅̸";
1700 var nsube = "⊈";
1701 var nsubset = "⊂⃒";
1702 var nsubseteq = "⊈";
1703 var nsubseteqq = "⫅̸";
1704 var nsucc = "⊁";
1705 var nsucceq = "⪰̸";
1706 var nsup = "⊅";
1707 var nsupE = "⫆̸";
1708 var nsupe = "⊉";
1709 var nsupset = "⊃⃒";
1710 var nsupseteq = "⊉";
1711 var nsupseteqq = "⫆̸";
1712 var ntgl = "≹";
1713 var Ntilde = "Ñ";
1714 var ntilde = "ñ";
1715 var ntlg = "≸";
1716 var ntriangleleft = "⋪";
1717 var ntrianglelefteq = "⋬";
1718 var ntriangleright = "⋫";
1719 var ntrianglerighteq = "⋭";
1720 var Nu = "Ν";
1721 var nu = "ν";
1722 var num = "#";
1723 var numero = "№";
1724 var numsp = " ";
1725 var nvap = "≍⃒";
1726 var nvdash = "⊬";
1727 var nvDash = "⊭";
1728 var nVdash = "⊮";
1729 var nVDash = "⊯";
1730 var nvge = "≥⃒";
1731 var nvgt = ">⃒";
1732 var nvHarr = "⤄";
1733 var nvinfin = "⧞";
1734 var nvlArr = "⤂";
1735 var nvle = "≤⃒";
1736 var nvlt = "<⃒";
1737 var nvltrie = "⊴⃒";
1738 var nvrArr = "⤃";
1739 var nvrtrie = "⊵⃒";
1740 var nvsim = "∼⃒";
1741 var nwarhk = "⤣";
1742 var nwarr = "↖";
1743 var nwArr = "⇖";
1744 var nwarrow = "↖";
1745 var nwnear = "⤧";
1746 var Oacute = "Ó";
1747 var oacute = "ó";
1748 var oast = "⊛";
1749 var Ocirc = "Ô";
1750 var ocirc = "ô";
1751 var ocir = "⊚";
1752 var Ocy = "О";
1753 var ocy = "о";
1754 var odash = "⊝";
1755 var Odblac = "Ő";
1756 var odblac = "ő";
1757 var odiv = "⨸";
1758 var odot = "⊙";
1759 var odsold = "⦼";
1760 var OElig = "Œ";
1761 var oelig = "œ";
1762 var ofcir = "⦿";
1763 var Ofr = "𝔒";
1764 var ofr = "𝔬";
1765 var ogon = "˛";
1766 var Ograve = "Ò";
1767 var ograve = "ò";
1768 var ogt = "⧁";
1769 var ohbar = "⦵";
1770 var ohm = "Ω";
1771 var oint = "∮";
1772 var olarr = "↺";
1773 var olcir = "⦾";
1774 var olcross = "⦻";
1775 var oline = "‾";
1776 var olt = "⧀";
1777 var Omacr = "Ō";
1778 var omacr = "ō";
1779 var Omega = "Ω";
1780 var omega = "ω";
1781 var Omicron = "Ο";
1782 var omicron = "ο";
1783 var omid = "⦶";
1784 var ominus = "⊖";
1785 var Oopf = "𝕆";
1786 var oopf = "𝕠";
1787 var opar = "⦷";
1788 var OpenCurlyDoubleQuote = "“";
1789 var OpenCurlyQuote = "‘";
1790 var operp = "⦹";
1791 var oplus = "⊕";
1792 var orarr = "↻";
1793 var Or = "⩔";
1794 var or = "∨";
1795 var ord = "⩝";
1796 var order = "ℴ";
1797 var orderof = "ℴ";
1798 var ordf = "ª";
1799 var ordm = "º";
1800 var origof = "⊶";
1801 var oror = "⩖";
1802 var orslope = "⩗";
1803 var orv = "⩛";
1804 var oS = "Ⓢ";
1805 var Oscr = "𝒪";
1806 var oscr = "ℴ";
1807 var Oslash = "Ø";
1808 var oslash = "ø";
1809 var osol = "⊘";
1810 var Otilde = "Õ";
1811 var otilde = "õ";
1812 var otimesas = "⨶";
1813 var Otimes = "⨷";
1814 var otimes = "⊗";
1815 var Ouml = "Ö";
1816 var ouml = "ö";
1817 var ovbar = "⌽";
1818 var OverBar = "‾";
1819 var OverBrace = "⏞";
1820 var OverBracket = "⎴";
1821 var OverParenthesis = "⏜";
1822 var para = "¶";
1823 var parallel = "∥";
1824 var par = "∥";
1825 var parsim = "⫳";
1826 var parsl = "⫽";
1827 var part = "∂";
1828 var PartialD = "∂";
1829 var Pcy = "П";
1830 var pcy = "п";
1831 var percnt = "%";
1832 var period = ".";
1833 var permil = "‰";
1834 var perp = "⊥";
1835 var pertenk = "‱";
1836 var Pfr = "𝔓";
1837 var pfr = "𝔭";
1838 var Phi = "Φ";
1839 var phi = "φ";
1840 var phiv = "ϕ";
1841 var phmmat = "ℳ";
1842 var phone = "☎";
1843 var Pi = "Π";
1844 var pi = "π";
1845 var pitchfork = "⋔";
1846 var piv = "ϖ";
1847 var planck = "ℏ";
1848 var planckh = "ℎ";
1849 var plankv = "ℏ";
1850 var plusacir = "⨣";
1851 var plusb = "⊞";
1852 var pluscir = "⨢";
1853 var plus = "+";
1854 var plusdo = "∔";
1855 var plusdu = "⨥";
1856 var pluse = "⩲";
1857 var PlusMinus = "±";
1858 var plusmn = "±";
1859 var plussim = "⨦";
1860 var plustwo = "⨧";
1861 var pm = "±";
1862 var Poincareplane = "ℌ";
1863 var pointint = "⨕";
1864 var popf = "𝕡";
1865 var Popf = "ℙ";
1866 var pound = "£";
1867 var prap = "⪷";
1868 var Pr = "⪻";
1869 var pr = "≺";
1870 var prcue = "≼";
1871 var precapprox = "⪷";
1872 var prec = "≺";
1873 var preccurlyeq = "≼";
1874 var Precedes = "≺";
1875 var PrecedesEqual = "⪯";
1876 var PrecedesSlantEqual = "≼";
1877 var PrecedesTilde = "≾";
1878 var preceq = "⪯";
1879 var precnapprox = "⪹";
1880 var precneqq = "⪵";
1881 var precnsim = "⋨";
1882 var pre = "⪯";
1883 var prE = "⪳";
1884 var precsim = "≾";
1885 var prime = "′";
1886 var Prime = "″";
1887 var primes = "ℙ";
1888 var prnap = "⪹";
1889 var prnE = "⪵";
1890 var prnsim = "⋨";
1891 var prod = "∏";
1892 var Product = "∏";
1893 var profalar = "⌮";
1894 var profline = "⌒";
1895 var profsurf = "⌓";
1896 var prop = "∝";
1897 var Proportional = "∝";
1898 var Proportion = "∷";
1899 var propto = "∝";
1900 var prsim = "≾";
1901 var prurel = "⊰";
1902 var Pscr = "𝒫";
1903 var pscr = "𝓅";
1904 var Psi = "Ψ";
1905 var psi = "ψ";
1906 var puncsp = " ";
1907 var Qfr = "𝔔";
1908 var qfr = "𝔮";
1909 var qint = "⨌";
1910 var qopf = "𝕢";
1911 var Qopf = "ℚ";
1912 var qprime = "⁗";
1913 var Qscr = "𝒬";
1914 var qscr = "𝓆";
1915 var quaternions = "ℍ";
1916 var quatint = "⨖";
1917 var quest = "?";
1918 var questeq = "≟";
1919 var quot = "\"";
1920 var QUOT = "\"";
1921 var rAarr = "⇛";
1922 var race = "∽̱";
1923 var Racute = "Ŕ";
1924 var racute = "ŕ";
1925 var radic = "√";
1926 var raemptyv = "⦳";
1927 var rang = "⟩";
1928 var Rang = "⟫";
1929 var rangd = "⦒";
1930 var range = "⦥";
1931 var rangle = "⟩";
1932 var raquo = "»";
1933 var rarrap = "⥵";
1934 var rarrb = "⇥";
1935 var rarrbfs = "⤠";
1936 var rarrc = "⤳";
1937 var rarr = "→";
1938 var Rarr = "↠";
1939 var rArr = "⇒";
1940 var rarrfs = "⤞";
1941 var rarrhk = "↪";
1942 var rarrlp = "↬";
1943 var rarrpl = "⥅";
1944 var rarrsim = "⥴";
1945 var Rarrtl = "⤖";
1946 var rarrtl = "↣";
1947 var rarrw = "↝";
1948 var ratail = "⤚";
1949 var rAtail = "⤜";
1950 var ratio = "∶";
1951 var rationals = "ℚ";
1952 var rbarr = "⤍";
1953 var rBarr = "⤏";
1954 var RBarr = "⤐";
1955 var rbbrk = "❳";
1956 var rbrace = "}";
1957 var rbrack = "]";
1958 var rbrke = "⦌";
1959 var rbrksld = "⦎";
1960 var rbrkslu = "⦐";
1961 var Rcaron = "Ř";
1962 var rcaron = "ř";
1963 var Rcedil = "Ŗ";
1964 var rcedil = "ŗ";
1965 var rceil = "⌉";
1966 var rcub = "}";
1967 var Rcy = "Р";
1968 var rcy = "р";
1969 var rdca = "⤷";
1970 var rdldhar = "⥩";
1971 var rdquo = "”";
1972 var rdquor = "”";
1973 var rdsh = "↳";
1974 var real = "ℜ";
1975 var realine = "ℛ";
1976 var realpart = "ℜ";
1977 var reals = "ℝ";
1978 var Re = "ℜ";
1979 var rect = "▭";
1980 var reg = "®";
1981 var REG = "®";
1982 var ReverseElement = "∋";
1983 var ReverseEquilibrium = "⇋";
1984 var ReverseUpEquilibrium = "⥯";
1985 var rfisht = "⥽";
1986 var rfloor = "⌋";
1987 var rfr = "𝔯";
1988 var Rfr = "ℜ";
1989 var rHar = "⥤";
1990 var rhard = "⇁";
1991 var rharu = "⇀";
1992 var rharul = "⥬";
1993 var Rho = "Ρ";
1994 var rho = "ρ";
1995 var rhov = "ϱ";
1996 var RightAngleBracket = "⟩";
1997 var RightArrowBar = "⇥";
1998 var rightarrow = "→";
1999 var RightArrow = "→";
2000 var Rightarrow = "⇒";
2001 var RightArrowLeftArrow = "⇄";
2002 var rightarrowtail = "↣";
2003 var RightCeiling = "⌉";
2004 var RightDoubleBracket = "⟧";
2005 var RightDownTeeVector = "⥝";
2006 var RightDownVectorBar = "⥕";
2007 var RightDownVector = "⇂";
2008 var RightFloor = "⌋";
2009 var rightharpoondown = "⇁";
2010 var rightharpoonup = "⇀";
2011 var rightleftarrows = "⇄";
2012 var rightleftharpoons = "⇌";
2013 var rightrightarrows = "⇉";
2014 var rightsquigarrow = "↝";
2015 var RightTeeArrow = "↦";
2016 var RightTee = "⊢";
2017 var RightTeeVector = "⥛";
2018 var rightthreetimes = "⋌";
2019 var RightTriangleBar = "⧐";
2020 var RightTriangle = "⊳";
2021 var RightTriangleEqual = "⊵";
2022 var RightUpDownVector = "⥏";
2023 var RightUpTeeVector = "⥜";
2024 var RightUpVectorBar = "⥔";
2025 var RightUpVector = "↾";
2026 var RightVectorBar = "⥓";
2027 var RightVector = "⇀";
2028 var ring = "˚";
2029 var risingdotseq = "≓";
2030 var rlarr = "⇄";
2031 var rlhar = "⇌";
2032 var rlm = "‏";
2033 var rmoustache = "⎱";
2034 var rmoust = "⎱";
2035 var rnmid = "⫮";
2036 var roang = "⟭";
2037 var roarr = "⇾";
2038 var robrk = "⟧";
2039 var ropar = "⦆";
2040 var ropf = "𝕣";
2041 var Ropf = "ℝ";
2042 var roplus = "⨮";
2043 var rotimes = "⨵";
2044 var RoundImplies = "⥰";
2045 var rpar = ")";
2046 var rpargt = "⦔";
2047 var rppolint = "⨒";
2048 var rrarr = "⇉";
2049 var Rrightarrow = "⇛";
2050 var rsaquo = "›";
2051 var rscr = "𝓇";
2052 var Rscr = "ℛ";
2053 var rsh = "↱";
2054 var Rsh = "↱";
2055 var rsqb = "]";
2056 var rsquo = "’";
2057 var rsquor = "’";
2058 var rthree = "⋌";
2059 var rtimes = "⋊";
2060 var rtri = "▹";
2061 var rtrie = "⊵";
2062 var rtrif = "▸";
2063 var rtriltri = "⧎";
2064 var RuleDelayed = "⧴";
2065 var ruluhar = "⥨";
2066 var rx = "℞";
2067 var Sacute = "Ś";
2068 var sacute = "ś";
2069 var sbquo = "‚";
2070 var scap = "⪸";
2071 var Scaron = "Š";
2072 var scaron = "š";
2073 var Sc = "⪼";
2074 var sc = "≻";
2075 var sccue = "≽";
2076 var sce = "⪰";
2077 var scE = "⪴";
2078 var Scedil = "Ş";
2079 var scedil = "ş";
2080 var Scirc = "Ŝ";
2081 var scirc = "ŝ";
2082 var scnap = "⪺";
2083 var scnE = "⪶";
2084 var scnsim = "⋩";
2085 var scpolint = "⨓";
2086 var scsim = "≿";
2087 var Scy = "С";
2088 var scy = "с";
2089 var sdotb = "⊡";
2090 var sdot = "⋅";
2091 var sdote = "⩦";
2092 var searhk = "⤥";
2093 var searr = "↘";
2094 var seArr = "⇘";
2095 var searrow = "↘";
2096 var sect = "§";
2097 var semi = ";";
2098 var seswar = "⤩";
2099 var setminus = "∖";
2100 var setmn = "∖";
2101 var sext = "✶";
2102 var Sfr = "𝔖";
2103 var sfr = "𝔰";
2104 var sfrown = "⌢";
2105 var sharp = "♯";
2106 var SHCHcy = "Щ";
2107 var shchcy = "щ";
2108 var SHcy = "Ш";
2109 var shcy = "ш";
2110 var ShortDownArrow = "↓";
2111 var ShortLeftArrow = "←";
2112 var shortmid = "∣";
2113 var shortparallel = "∥";
2114 var ShortRightArrow = "→";
2115 var ShortUpArrow = "↑";
2116 var shy = "­";
2117 var Sigma = "Σ";
2118 var sigma = "σ";
2119 var sigmaf = "ς";
2120 var sigmav = "ς";
2121 var sim = "∼";
2122 var simdot = "⩪";
2123 var sime = "≃";
2124 var simeq = "≃";
2125 var simg = "⪞";
2126 var simgE = "⪠";
2127 var siml = "⪝";
2128 var simlE = "⪟";
2129 var simne = "≆";
2130 var simplus = "⨤";
2131 var simrarr = "⥲";
2132 var slarr = "←";
2133 var SmallCircle = "∘";
2134 var smallsetminus = "∖";
2135 var smashp = "⨳";
2136 var smeparsl = "⧤";
2137 var smid = "∣";
2138 var smile = "⌣";
2139 var smt = "⪪";
2140 var smte = "⪬";
2141 var smtes = "⪬︀";
2142 var SOFTcy = "Ь";
2143 var softcy = "ь";
2144 var solbar = "⌿";
2145 var solb = "⧄";
2146 var sol = "/";
2147 var Sopf = "𝕊";
2148 var sopf = "𝕤";
2149 var spades = "♠";
2150 var spadesuit = "♠";
2151 var spar = "∥";
2152 var sqcap = "⊓";
2153 var sqcaps = "⊓︀";
2154 var sqcup = "⊔";
2155 var sqcups = "⊔︀";
2156 var Sqrt = "√";
2157 var sqsub = "⊏";
2158 var sqsube = "⊑";
2159 var sqsubset = "⊏";
2160 var sqsubseteq = "⊑";
2161 var sqsup = "⊐";
2162 var sqsupe = "⊒";
2163 var sqsupset = "⊐";
2164 var sqsupseteq = "⊒";
2165 var square = "□";
2166 var Square = "□";
2167 var SquareIntersection = "⊓";
2168 var SquareSubset = "⊏";
2169 var SquareSubsetEqual = "⊑";
2170 var SquareSuperset = "⊐";
2171 var SquareSupersetEqual = "⊒";
2172 var SquareUnion = "⊔";
2173 var squarf = "▪";
2174 var squ = "□";
2175 var squf = "▪";
2176 var srarr = "→";
2177 var Sscr = "𝒮";
2178 var sscr = "𝓈";
2179 var ssetmn = "∖";
2180 var ssmile = "⌣";
2181 var sstarf = "⋆";
2182 var Star = "⋆";
2183 var star = "☆";
2184 var starf = "★";
2185 var straightepsilon = "ϵ";
2186 var straightphi = "ϕ";
2187 var strns = "¯";
2188 var sub = "⊂";
2189 var Sub = "⋐";
2190 var subdot = "⪽";
2191 var subE = "⫅";
2192 var sube = "⊆";
2193 var subedot = "⫃";
2194 var submult = "⫁";
2195 var subnE = "⫋";
2196 var subne = "⊊";
2197 var subplus = "⪿";
2198 var subrarr = "⥹";
2199 var subset = "⊂";
2200 var Subset = "⋐";
2201 var subseteq = "⊆";
2202 var subseteqq = "⫅";
2203 var SubsetEqual = "⊆";
2204 var subsetneq = "⊊";
2205 var subsetneqq = "⫋";
2206 var subsim = "⫇";
2207 var subsub = "⫕";
2208 var subsup = "⫓";
2209 var succapprox = "⪸";
2210 var succ = "≻";
2211 var succcurlyeq = "≽";
2212 var Succeeds = "≻";
2213 var SucceedsEqual = "⪰";
2214 var SucceedsSlantEqual = "≽";
2215 var SucceedsTilde = "≿";
2216 var succeq = "⪰";
2217 var succnapprox = "⪺";
2218 var succneqq = "⪶";
2219 var succnsim = "⋩";
2220 var succsim = "≿";
2221 var SuchThat = "∋";
2222 var sum = "∑";
2223 var Sum = "∑";
2224 var sung = "♪";
2225 var sup1 = "¹";
2226 var sup2 = "²";
2227 var sup3 = "³";
2228 var sup = "⊃";
2229 var Sup = "⋑";
2230 var supdot = "⪾";
2231 var supdsub = "⫘";
2232 var supE = "⫆";
2233 var supe = "⊇";
2234 var supedot = "⫄";
2235 var Superset = "⊃";
2236 var SupersetEqual = "⊇";
2237 var suphsol = "⟉";
2238 var suphsub = "⫗";
2239 var suplarr = "⥻";
2240 var supmult = "⫂";
2241 var supnE = "⫌";
2242 var supne = "⊋";
2243 var supplus = "⫀";
2244 var supset = "⊃";
2245 var Supset = "⋑";
2246 var supseteq = "⊇";
2247 var supseteqq = "⫆";
2248 var supsetneq = "⊋";
2249 var supsetneqq = "⫌";
2250 var supsim = "⫈";
2251 var supsub = "⫔";
2252 var supsup = "⫖";
2253 var swarhk = "⤦";
2254 var swarr = "↙";
2255 var swArr = "⇙";
2256 var swarrow = "↙";
2257 var swnwar = "⤪";
2258 var szlig = "ß";
2259 var Tab = "\t";
2260 var target = "⌖";
2261 var Tau = "Τ";
2262 var tau = "τ";
2263 var tbrk = "⎴";
2264 var Tcaron = "Ť";
2265 var tcaron = "ť";
2266 var Tcedil = "Ţ";
2267 var tcedil = "ţ";
2268 var Tcy = "Т";
2269 var tcy = "т";
2270 var tdot = "⃛";
2271 var telrec = "⌕";
2272 var Tfr = "𝔗";
2273 var tfr = "𝔱";
2274 var there4 = "∴";
2275 var therefore = "∴";
2276 var Therefore = "∴";
2277 var Theta = "Θ";
2278 var theta = "θ";
2279 var thetasym = "ϑ";
2280 var thetav = "ϑ";
2281 var thickapprox = "≈";
2282 var thicksim = "∼";
2283 var ThickSpace = "  ";
2284 var ThinSpace = " ";
2285 var thinsp = " ";
2286 var thkap = "≈";
2287 var thksim = "∼";
2288 var THORN = "Þ";
2289 var thorn = "þ";
2290 var tilde = "˜";
2291 var Tilde = "∼";
2292 var TildeEqual = "≃";
2293 var TildeFullEqual = "≅";
2294 var TildeTilde = "≈";
2295 var timesbar = "⨱";
2296 var timesb = "⊠";
2297 var times = "×";
2298 var timesd = "⨰";
2299 var tint = "∭";
2300 var toea = "⤨";
2301 var topbot = "⌶";
2302 var topcir = "⫱";
2303 var top = "⊤";
2304 var Topf = "𝕋";
2305 var topf = "𝕥";
2306 var topfork = "⫚";
2307 var tosa = "⤩";
2308 var tprime = "‴";
2309 var trade = "™";
2310 var TRADE = "™";
2311 var triangle = "▵";
2312 var triangledown = "▿";
2313 var triangleleft = "◃";
2314 var trianglelefteq = "⊴";
2315 var triangleq = "≜";
2316 var triangleright = "▹";
2317 var trianglerighteq = "⊵";
2318 var tridot = "◬";
2319 var trie = "≜";
2320 var triminus = "⨺";
2321 var TripleDot = "⃛";
2322 var triplus = "⨹";
2323 var trisb = "⧍";
2324 var tritime = "⨻";
2325 var trpezium = "⏢";
2326 var Tscr = "𝒯";
2327 var tscr = "𝓉";
2328 var TScy = "Ц";
2329 var tscy = "ц";
2330 var TSHcy = "Ћ";
2331 var tshcy = "ћ";
2332 var Tstrok = "Ŧ";
2333 var tstrok = "ŧ";
2334 var twixt = "≬";
2335 var twoheadleftarrow = "↞";
2336 var twoheadrightarrow = "↠";
2337 var Uacute = "Ú";
2338 var uacute = "ú";
2339 var uarr = "↑";
2340 var Uarr = "↟";
2341 var uArr = "⇑";
2342 var Uarrocir = "⥉";
2343 var Ubrcy = "Ў";
2344 var ubrcy = "ў";
2345 var Ubreve = "Ŭ";
2346 var ubreve = "ŭ";
2347 var Ucirc = "Û";
2348 var ucirc = "û";
2349 var Ucy = "У";
2350 var ucy = "у";
2351 var udarr = "⇅";
2352 var Udblac = "Ű";
2353 var udblac = "ű";
2354 var udhar = "⥮";
2355 var ufisht = "⥾";
2356 var Ufr = "𝔘";
2357 var ufr = "𝔲";
2358 var Ugrave = "Ù";
2359 var ugrave = "ù";
2360 var uHar = "⥣";
2361 var uharl = "↿";
2362 var uharr = "↾";
2363 var uhblk = "▀";
2364 var ulcorn = "⌜";
2365 var ulcorner = "⌜";
2366 var ulcrop = "⌏";
2367 var ultri = "◸";
2368 var Umacr = "Ū";
2369 var umacr = "ū";
2370 var uml = "¨";
2371 var UnderBar = "_";
2372 var UnderBrace = "⏟";
2373 var UnderBracket = "⎵";
2374 var UnderParenthesis = "⏝";
2375 var Union = "⋃";
2376 var UnionPlus = "⊎";
2377 var Uogon = "Ų";
2378 var uogon = "ų";
2379 var Uopf = "𝕌";
2380 var uopf = "𝕦";
2381 var UpArrowBar = "⤒";
2382 var uparrow = "↑";
2383 var UpArrow = "↑";
2384 var Uparrow = "⇑";
2385 var UpArrowDownArrow = "⇅";
2386 var updownarrow = "↕";
2387 var UpDownArrow = "↕";
2388 var Updownarrow = "⇕";
2389 var UpEquilibrium = "⥮";
2390 var upharpoonleft = "↿";
2391 var upharpoonright = "↾";
2392 var uplus = "⊎";
2393 var UpperLeftArrow = "↖";
2394 var UpperRightArrow = "↗";
2395 var upsi = "υ";
2396 var Upsi = "ϒ";
2397 var upsih = "ϒ";
2398 var Upsilon = "Υ";
2399 var upsilon = "υ";
2400 var UpTeeArrow = "↥";
2401 var UpTee = "⊥";
2402 var upuparrows = "⇈";
2403 var urcorn = "⌝";
2404 var urcorner = "⌝";
2405 var urcrop = "⌎";
2406 var Uring = "Ů";
2407 var uring = "ů";
2408 var urtri = "◹";
2409 var Uscr = "𝒰";
2410 var uscr = "𝓊";
2411 var utdot = "⋰";
2412 var Utilde = "Ũ";
2413 var utilde = "ũ";
2414 var utri = "▵";
2415 var utrif = "▴";
2416 var uuarr = "⇈";
2417 var Uuml = "Ü";
2418 var uuml = "ü";
2419 var uwangle = "⦧";
2420 var vangrt = "⦜";
2421 var varepsilon = "ϵ";
2422 var varkappa = "ϰ";
2423 var varnothing = "∅";
2424 var varphi = "ϕ";
2425 var varpi = "ϖ";
2426 var varpropto = "∝";
2427 var varr = "↕";
2428 var vArr = "⇕";
2429 var varrho = "ϱ";
2430 var varsigma = "ς";
2431 var varsubsetneq = "⊊︀";
2432 var varsubsetneqq = "⫋︀";
2433 var varsupsetneq = "⊋︀";
2434 var varsupsetneqq = "⫌︀";
2435 var vartheta = "ϑ";
2436 var vartriangleleft = "⊲";
2437 var vartriangleright = "⊳";
2438 var vBar = "⫨";
2439 var Vbar = "⫫";
2440 var vBarv = "⫩";
2441 var Vcy = "В";
2442 var vcy = "в";
2443 var vdash = "⊢";
2444 var vDash = "⊨";
2445 var Vdash = "⊩";
2446 var VDash = "⊫";
2447 var Vdashl = "⫦";
2448 var veebar = "⊻";
2449 var vee = "∨";
2450 var Vee = "⋁";
2451 var veeeq = "≚";
2452 var vellip = "⋮";
2453 var verbar = "|";
2454 var Verbar = "‖";
2455 var vert = "|";
2456 var Vert = "‖";
2457 var VerticalBar = "∣";
2458 var VerticalLine = "|";
2459 var VerticalSeparator = "❘";
2460 var VerticalTilde = "≀";
2461 var VeryThinSpace = " ";
2462 var Vfr = "𝔙";
2463 var vfr = "𝔳";
2464 var vltri = "⊲";
2465 var vnsub = "⊂⃒";
2466 var vnsup = "⊃⃒";
2467 var Vopf = "𝕍";
2468 var vopf = "𝕧";
2469 var vprop = "∝";
2470 var vrtri = "⊳";
2471 var Vscr = "𝒱";
2472 var vscr = "𝓋";
2473 var vsubnE = "⫋︀";
2474 var vsubne = "⊊︀";
2475 var vsupnE = "⫌︀";
2476 var vsupne = "⊋︀";
2477 var Vvdash = "⊪";
2478 var vzigzag = "⦚";
2479 var Wcirc = "Ŵ";
2480 var wcirc = "ŵ";
2481 var wedbar = "⩟";
2482 var wedge = "∧";
2483 var Wedge = "⋀";
2484 var wedgeq = "≙";
2485 var weierp = "℘";
2486 var Wfr = "𝔚";
2487 var wfr = "𝔴";
2488 var Wopf = "𝕎";
2489 var wopf = "𝕨";
2490 var wp = "℘";
2491 var wr = "≀";
2492 var wreath = "≀";
2493 var Wscr = "𝒲";
2494 var wscr = "𝓌";
2495 var xcap = "⋂";
2496 var xcirc = "◯";
2497 var xcup = "⋃";
2498 var xdtri = "▽";
2499 var Xfr = "𝔛";
2500 var xfr = "𝔵";
2501 var xharr = "⟷";
2502 var xhArr = "⟺";
2503 var Xi = "Ξ";
2504 var xi = "ξ";
2505 var xlarr = "⟵";
2506 var xlArr = "⟸";
2507 var xmap = "⟼";
2508 var xnis = "⋻";
2509 var xodot = "⨀";
2510 var Xopf = "𝕏";
2511 var xopf = "𝕩";
2512 var xoplus = "⨁";
2513 var xotime = "⨂";
2514 var xrarr = "⟶";
2515 var xrArr = "⟹";
2516 var Xscr = "𝒳";
2517 var xscr = "𝓍";
2518 var xsqcup = "⨆";
2519 var xuplus = "⨄";
2520 var xutri = "△";
2521 var xvee = "⋁";
2522 var xwedge = "⋀";
2523 var Yacute = "Ý";
2524 var yacute = "ý";
2525 var YAcy = "Я";
2526 var yacy = "я";
2527 var Ycirc = "Ŷ";
2528 var ycirc = "ŷ";
2529 var Ycy = "Ы";
2530 var ycy = "ы";
2531 var yen = "¥";
2532 var Yfr = "𝔜";
2533 var yfr = "𝔶";
2534 var YIcy = "Ї";
2535 var yicy = "ї";
2536 var Yopf = "𝕐";
2537 var yopf = "𝕪";
2538 var Yscr = "𝒴";
2539 var yscr = "𝓎";
2540 var YUcy = "Ю";
2541 var yucy = "ю";
2542 var yuml = "ÿ";
2543 var Yuml = "Ÿ";
2544 var Zacute = "Ź";
2545 var zacute = "ź";
2546 var Zcaron = "Ž";
2547 var zcaron = "ž";
2548 var Zcy = "З";
2549 var zcy = "з";
2550 var Zdot = "Ż";
2551 var zdot = "ż";
2552 var zeetrf = "ℨ";
2553 var ZeroWidthSpace = "​";
2554 var Zeta = "Ζ";
2555 var zeta = "ζ";
2556 var zfr = "𝔷";
2557 var Zfr = "ℨ";
2558 var ZHcy = "Ж";
2559 var zhcy = "ж";
2560 var zigrarr = "⇝";
2561 var zopf = "𝕫";
2562 var Zopf = "ℤ";
2563 var Zscr = "𝒵";
2564 var zscr = "𝓏";
2565 var zwj = "‍";
2566 var zwnj = "‌";
2567 var entities = {
2568 Aacute: Aacute,
2569 aacute: aacute,
2570 Abreve: Abreve,
2571 abreve: abreve,
2572 ac: ac,
2573 acd: acd,
2574 acE: acE,
2575 Acirc: Acirc,
2576 acirc: acirc,
2577 acute: acute,
2578 Acy: Acy,
2579 acy: acy,
2580 AElig: AElig,
2581 aelig: aelig,
2582 af: af,
2583 Afr: Afr,
2584 afr: afr,
2585 Agrave: Agrave,
2586 agrave: agrave,
2587 alefsym: alefsym,
2588 aleph: aleph,
2589 Alpha: Alpha,
2590 alpha: alpha,
2591 Amacr: Amacr,
2592 amacr: amacr,
2593 amalg: amalg,
2594 amp: amp,
2595 AMP: AMP,
2596 andand: andand,
2597 And: And,
2598 and: and,
2599 andd: andd,
2600 andslope: andslope,
2601 andv: andv,
2602 ang: ang,
2603 ange: ange,
2604 angle: angle,
2605 angmsdaa: angmsdaa,
2606 angmsdab: angmsdab,
2607 angmsdac: angmsdac,
2608 angmsdad: angmsdad,
2609 angmsdae: angmsdae,
2610 angmsdaf: angmsdaf,
2611 angmsdag: angmsdag,
2612 angmsdah: angmsdah,
2613 angmsd: angmsd,
2614 angrt: angrt,
2615 angrtvb: angrtvb,
2616 angrtvbd: angrtvbd,
2617 angsph: angsph,
2618 angst: angst,
2619 angzarr: angzarr,
2620 Aogon: Aogon,
2621 aogon: aogon,
2622 Aopf: Aopf,
2623 aopf: aopf,
2624 apacir: apacir,
2625 ap: ap,
2626 apE: apE,
2627 ape: ape,
2628 apid: apid,
2629 apos: apos,
2630 ApplyFunction: ApplyFunction,
2631 approx: approx,
2632 approxeq: approxeq,
2633 Aring: Aring,
2634 aring: aring,
2635 Ascr: Ascr,
2636 ascr: ascr,
2637 Assign: Assign,
2638 ast: ast,
2639 asymp: asymp,
2640 asympeq: asympeq,
2641 Atilde: Atilde,
2642 atilde: atilde,
2643 Auml: Auml,
2644 auml: auml,
2645 awconint: awconint,
2646 awint: awint,
2647 backcong: backcong,
2648 backepsilon: backepsilon,
2649 backprime: backprime,
2650 backsim: backsim,
2651 backsimeq: backsimeq,
2652 Backslash: Backslash,
2653 Barv: Barv,
2654 barvee: barvee,
2655 barwed: barwed,
2656 Barwed: Barwed,
2657 barwedge: barwedge,
2658 bbrk: bbrk,
2659 bbrktbrk: bbrktbrk,
2660 bcong: bcong,
2661 Bcy: Bcy,
2662 bcy: bcy,
2663 bdquo: bdquo,
2664 becaus: becaus,
2665 because: because,
2666 Because: Because,
2667 bemptyv: bemptyv,
2668 bepsi: bepsi,
2669 bernou: bernou,
2670 Bernoullis: Bernoullis,
2671 Beta: Beta,
2672 beta: beta,
2673 beth: beth,
2674 between: between,
2675 Bfr: Bfr,
2676 bfr: bfr,
2677 bigcap: bigcap,
2678 bigcirc: bigcirc,
2679 bigcup: bigcup,
2680 bigodot: bigodot,
2681 bigoplus: bigoplus,
2682 bigotimes: bigotimes,
2683 bigsqcup: bigsqcup,
2684 bigstar: bigstar,
2685 bigtriangledown: bigtriangledown,
2686 bigtriangleup: bigtriangleup,
2687 biguplus: biguplus,
2688 bigvee: bigvee,
2689 bigwedge: bigwedge,
2690 bkarow: bkarow,
2691 blacklozenge: blacklozenge,
2692 blacksquare: blacksquare,
2693 blacktriangle: blacktriangle,
2694 blacktriangledown: blacktriangledown,
2695 blacktriangleleft: blacktriangleleft,
2696 blacktriangleright: blacktriangleright,
2697 blank: blank,
2698 blk12: blk12,
2699 blk14: blk14,
2700 blk34: blk34,
2701 block: block,
2702 bne: bne,
2703 bnequiv: bnequiv,
2704 bNot: bNot,
2705 bnot: bnot,
2706 Bopf: Bopf,
2707 bopf: bopf,
2708 bot: bot,
2709 bottom: bottom,
2710 bowtie: bowtie,
2711 boxbox: boxbox,
2712 boxdl: boxdl,
2713 boxdL: boxdL,
2714 boxDl: boxDl,
2715 boxDL: boxDL,
2716 boxdr: boxdr,
2717 boxdR: boxdR,
2718 boxDr: boxDr,
2719 boxDR: boxDR,
2720 boxh: boxh,
2721 boxH: boxH,
2722 boxhd: boxhd,
2723 boxHd: boxHd,
2724 boxhD: boxhD,
2725 boxHD: boxHD,
2726 boxhu: boxhu,
2727 boxHu: boxHu,
2728 boxhU: boxhU,
2729 boxHU: boxHU,
2730 boxminus: boxminus,
2731 boxplus: boxplus,
2732 boxtimes: boxtimes,
2733 boxul: boxul,
2734 boxuL: boxuL,
2735 boxUl: boxUl,
2736 boxUL: boxUL,
2737 boxur: boxur,
2738 boxuR: boxuR,
2739 boxUr: boxUr,
2740 boxUR: boxUR,
2741 boxv: boxv,
2742 boxV: boxV,
2743 boxvh: boxvh,
2744 boxvH: boxvH,
2745 boxVh: boxVh,
2746 boxVH: boxVH,
2747 boxvl: boxvl,
2748 boxvL: boxvL,
2749 boxVl: boxVl,
2750 boxVL: boxVL,
2751 boxvr: boxvr,
2752 boxvR: boxvR,
2753 boxVr: boxVr,
2754 boxVR: boxVR,
2755 bprime: bprime,
2756 breve: breve,
2757 Breve: Breve,
2758 brvbar: brvbar,
2759 bscr: bscr,
2760 Bscr: Bscr,
2761 bsemi: bsemi,
2762 bsim: bsim,
2763 bsime: bsime,
2764 bsolb: bsolb,
2765 bsol: bsol,
2766 bsolhsub: bsolhsub,
2767 bull: bull,
2768 bullet: bullet,
2769 bump: bump,
2770 bumpE: bumpE,
2771 bumpe: bumpe,
2772 Bumpeq: Bumpeq,
2773 bumpeq: bumpeq,
2774 Cacute: Cacute,
2775 cacute: cacute,
2776 capand: capand,
2777 capbrcup: capbrcup,
2778 capcap: capcap,
2779 cap: cap,
2780 Cap: Cap,
2781 capcup: capcup,
2782 capdot: capdot,
2783 CapitalDifferentialD: CapitalDifferentialD,
2784 caps: caps,
2785 caret: caret,
2786 caron: caron,
2787 Cayleys: Cayleys,
2788 ccaps: ccaps,
2789 Ccaron: Ccaron,
2790 ccaron: ccaron,
2791 Ccedil: Ccedil,
2792 ccedil: ccedil,
2793 Ccirc: Ccirc,
2794 ccirc: ccirc,
2795 Cconint: Cconint,
2796 ccups: ccups,
2797 ccupssm: ccupssm,
2798 Cdot: Cdot,
2799 cdot: cdot,
2800 cedil: cedil,
2801 Cedilla: Cedilla,
2802 cemptyv: cemptyv,
2803 cent: cent,
2804 centerdot: centerdot,
2805 CenterDot: CenterDot,
2806 cfr: cfr,
2807 Cfr: Cfr,
2808 CHcy: CHcy,
2809 chcy: chcy,
2810 check: check,
2811 checkmark: checkmark,
2812 Chi: Chi,
2813 chi: chi,
2814 circ: circ,
2815 circeq: circeq,
2816 circlearrowleft: circlearrowleft,
2817 circlearrowright: circlearrowright,
2818 circledast: circledast,
2819 circledcirc: circledcirc,
2820 circleddash: circleddash,
2821 CircleDot: CircleDot,
2822 circledR: circledR,
2823 circledS: circledS,
2824 CircleMinus: CircleMinus,
2825 CirclePlus: CirclePlus,
2826 CircleTimes: CircleTimes,
2827 cir: cir,
2828 cirE: cirE,
2829 cire: cire,
2830 cirfnint: cirfnint,
2831 cirmid: cirmid,
2832 cirscir: cirscir,
2833 ClockwiseContourIntegral: ClockwiseContourIntegral,
2834 CloseCurlyDoubleQuote: CloseCurlyDoubleQuote,
2835 CloseCurlyQuote: CloseCurlyQuote,
2836 clubs: clubs,
2837 clubsuit: clubsuit,
2838 colon: colon,
2839 Colon: Colon,
2840 Colone: Colone,
2841 colone: colone,
2842 coloneq: coloneq,
2843 comma: comma,
2844 commat: commat,
2845 comp: comp,
2846 compfn: compfn,
2847 complement: complement,
2848 complexes: complexes,
2849 cong: cong,
2850 congdot: congdot,
2851 Congruent: Congruent,
2852 conint: conint,
2853 Conint: Conint,
2854 ContourIntegral: ContourIntegral,
2855 copf: copf,
2856 Copf: Copf,
2857 coprod: coprod,
2858 Coproduct: Coproduct,
2859 copy: copy,
2860 COPY: COPY,
2861 copysr: copysr,
2862 CounterClockwiseContourIntegral: CounterClockwiseContourIntegral,
2863 crarr: crarr,
2864 cross: cross,
2865 Cross: Cross,
2866 Cscr: Cscr,
2867 cscr: cscr,
2868 csub: csub,
2869 csube: csube,
2870 csup: csup,
2871 csupe: csupe,
2872 ctdot: ctdot,
2873 cudarrl: cudarrl,
2874 cudarrr: cudarrr,
2875 cuepr: cuepr,
2876 cuesc: cuesc,
2877 cularr: cularr,
2878 cularrp: cularrp,
2879 cupbrcap: cupbrcap,
2880 cupcap: cupcap,
2881 CupCap: CupCap,
2882 cup: cup,
2883 Cup: Cup,
2884 cupcup: cupcup,
2885 cupdot: cupdot,
2886 cupor: cupor,
2887 cups: cups,
2888 curarr: curarr,
2889 curarrm: curarrm,
2890 curlyeqprec: curlyeqprec,
2891 curlyeqsucc: curlyeqsucc,
2892 curlyvee: curlyvee,
2893 curlywedge: curlywedge,
2894 curren: curren,
2895 curvearrowleft: curvearrowleft,
2896 curvearrowright: curvearrowright,
2897 cuvee: cuvee,
2898 cuwed: cuwed,
2899 cwconint: cwconint,
2900 cwint: cwint,
2901 cylcty: cylcty,
2902 dagger: dagger,
2903 Dagger: Dagger,
2904 daleth: daleth,
2905 darr: darr,
2906 Darr: Darr,
2907 dArr: dArr,
2908 dash: dash,
2909 Dashv: Dashv,
2910 dashv: dashv,
2911 dbkarow: dbkarow,
2912 dblac: dblac,
2913 Dcaron: Dcaron,
2914 dcaron: dcaron,
2915 Dcy: Dcy,
2916 dcy: dcy,
2917 ddagger: ddagger,
2918 ddarr: ddarr,
2919 DD: DD,
2920 dd: dd,
2921 DDotrahd: DDotrahd,
2922 ddotseq: ddotseq,
2923 deg: deg,
2924 Del: Del,
2925 Delta: Delta,
2926 delta: delta,
2927 demptyv: demptyv,
2928 dfisht: dfisht,
2929 Dfr: Dfr,
2930 dfr: dfr,
2931 dHar: dHar,
2932 dharl: dharl,
2933 dharr: dharr,
2934 DiacriticalAcute: DiacriticalAcute,
2935 DiacriticalDot: DiacriticalDot,
2936 DiacriticalDoubleAcute: DiacriticalDoubleAcute,
2937 DiacriticalGrave: DiacriticalGrave,
2938 DiacriticalTilde: DiacriticalTilde,
2939 diam: diam,
2940 diamond: diamond,
2941 Diamond: Diamond,
2942 diamondsuit: diamondsuit,
2943 diams: diams,
2944 die: die,
2945 DifferentialD: DifferentialD,
2946 digamma: digamma,
2947 disin: disin,
2948 div: div,
2949 divide: divide,
2950 divideontimes: divideontimes,
2951 divonx: divonx,
2952 DJcy: DJcy,
2953 djcy: djcy,
2954 dlcorn: dlcorn,
2955 dlcrop: dlcrop,
2956 dollar: dollar,
2957 Dopf: Dopf,
2958 dopf: dopf,
2959 Dot: Dot,
2960 dot: dot,
2961 DotDot: DotDot,
2962 doteq: doteq,
2963 doteqdot: doteqdot,
2964 DotEqual: DotEqual,
2965 dotminus: dotminus,
2966 dotplus: dotplus,
2967 dotsquare: dotsquare,
2968 doublebarwedge: doublebarwedge,
2969 DoubleContourIntegral: DoubleContourIntegral,
2970 DoubleDot: DoubleDot,
2971 DoubleDownArrow: DoubleDownArrow,
2972 DoubleLeftArrow: DoubleLeftArrow,
2973 DoubleLeftRightArrow: DoubleLeftRightArrow,
2974 DoubleLeftTee: DoubleLeftTee,
2975 DoubleLongLeftArrow: DoubleLongLeftArrow,
2976 DoubleLongLeftRightArrow: DoubleLongLeftRightArrow,
2977 DoubleLongRightArrow: DoubleLongRightArrow,
2978 DoubleRightArrow: DoubleRightArrow,
2979 DoubleRightTee: DoubleRightTee,
2980 DoubleUpArrow: DoubleUpArrow,
2981 DoubleUpDownArrow: DoubleUpDownArrow,
2982 DoubleVerticalBar: DoubleVerticalBar,
2983 DownArrowBar: DownArrowBar,
2984 downarrow: downarrow,
2985 DownArrow: DownArrow,
2986 Downarrow: Downarrow,
2987 DownArrowUpArrow: DownArrowUpArrow,
2988 DownBreve: DownBreve,
2989 downdownarrows: downdownarrows,
2990 downharpoonleft: downharpoonleft,
2991 downharpoonright: downharpoonright,
2992 DownLeftRightVector: DownLeftRightVector,
2993 DownLeftTeeVector: DownLeftTeeVector,
2994 DownLeftVectorBar: DownLeftVectorBar,
2995 DownLeftVector: DownLeftVector,
2996 DownRightTeeVector: DownRightTeeVector,
2997 DownRightVectorBar: DownRightVectorBar,
2998 DownRightVector: DownRightVector,
2999 DownTeeArrow: DownTeeArrow,
3000 DownTee: DownTee,
3001 drbkarow: drbkarow,
3002 drcorn: drcorn,
3003 drcrop: drcrop,
3004 Dscr: Dscr,
3005 dscr: dscr,
3006 DScy: DScy,
3007 dscy: dscy,
3008 dsol: dsol,
3009 Dstrok: Dstrok,
3010 dstrok: dstrok,
3011 dtdot: dtdot,
3012 dtri: dtri,
3013 dtrif: dtrif,
3014 duarr: duarr,
3015 duhar: duhar,
3016 dwangle: dwangle,
3017 DZcy: DZcy,
3018 dzcy: dzcy,
3019 dzigrarr: dzigrarr,
3020 Eacute: Eacute,
3021 eacute: eacute,
3022 easter: easter,
3023 Ecaron: Ecaron,
3024 ecaron: ecaron,
3025 Ecirc: Ecirc,
3026 ecirc: ecirc,
3027 ecir: ecir,
3028 ecolon: ecolon,
3029 Ecy: Ecy,
3030 ecy: ecy,
3031 eDDot: eDDot,
3032 Edot: Edot,
3033 edot: edot,
3034 eDot: eDot,
3035 ee: ee,
3036 efDot: efDot,
3037 Efr: Efr,
3038 efr: efr,
3039 eg: eg,
3040 Egrave: Egrave,
3041 egrave: egrave,
3042 egs: egs,
3043 egsdot: egsdot,
3044 el: el,
3045 Element: Element,
3046 elinters: elinters,
3047 ell: ell,
3048 els: els,
3049 elsdot: elsdot,
3050 Emacr: Emacr,
3051 emacr: emacr,
3052 empty: empty,
3053 emptyset: emptyset,
3054 EmptySmallSquare: EmptySmallSquare,
3055 emptyv: emptyv,
3056 EmptyVerySmallSquare: EmptyVerySmallSquare,
3057 emsp13: emsp13,
3058 emsp14: emsp14,
3059 emsp: emsp,
3060 ENG: ENG,
3061 eng: eng,
3062 ensp: ensp,
3063 Eogon: Eogon,
3064 eogon: eogon,
3065 Eopf: Eopf,
3066 eopf: eopf,
3067 epar: epar,
3068 eparsl: eparsl,
3069 eplus: eplus,
3070 epsi: epsi,
3071 Epsilon: Epsilon,
3072 epsilon: epsilon,
3073 epsiv: epsiv,
3074 eqcirc: eqcirc,
3075 eqcolon: eqcolon,
3076 eqsim: eqsim,
3077 eqslantgtr: eqslantgtr,
3078 eqslantless: eqslantless,
3079 Equal: Equal,
3080 equals: equals,
3081 EqualTilde: EqualTilde,
3082 equest: equest,
3083 Equilibrium: Equilibrium,
3084 equiv: equiv,
3085 equivDD: equivDD,
3086 eqvparsl: eqvparsl,
3087 erarr: erarr,
3088 erDot: erDot,
3089 escr: escr,
3090 Escr: Escr,
3091 esdot: esdot,
3092 Esim: Esim,
3093 esim: esim,
3094 Eta: Eta,
3095 eta: eta,
3096 ETH: ETH,
3097 eth: eth,
3098 Euml: Euml,
3099 euml: euml,
3100 euro: euro,
3101 excl: excl,
3102 exist: exist,
3103 Exists: Exists,
3104 expectation: expectation,
3105 exponentiale: exponentiale,
3106 ExponentialE: ExponentialE,
3107 fallingdotseq: fallingdotseq,
3108 Fcy: Fcy,
3109 fcy: fcy,
3110 female: female,
3111 ffilig: ffilig,
3112 fflig: fflig,
3113 ffllig: ffllig,
3114 Ffr: Ffr,
3115 ffr: ffr,
3116 filig: filig,
3117 FilledSmallSquare: FilledSmallSquare,
3118 FilledVerySmallSquare: FilledVerySmallSquare,
3119 fjlig: fjlig,
3120 flat: flat,
3121 fllig: fllig,
3122 fltns: fltns,
3123 fnof: fnof,
3124 Fopf: Fopf,
3125 fopf: fopf,
3126 forall: forall,
3127 ForAll: ForAll,
3128 fork: fork,
3129 forkv: forkv,
3130 Fouriertrf: Fouriertrf,
3131 fpartint: fpartint,
3132 frac12: frac12,
3133 frac13: frac13,
3134 frac14: frac14,
3135 frac15: frac15,
3136 frac16: frac16,
3137 frac18: frac18,
3138 frac23: frac23,
3139 frac25: frac25,
3140 frac34: frac34,
3141 frac35: frac35,
3142 frac38: frac38,
3143 frac45: frac45,
3144 frac56: frac56,
3145 frac58: frac58,
3146 frac78: frac78,
3147 frasl: frasl,
3148 frown: frown,
3149 fscr: fscr,
3150 Fscr: Fscr,
3151 gacute: gacute,
3152 Gamma: Gamma,
3153 gamma: gamma,
3154 Gammad: Gammad,
3155 gammad: gammad,
3156 gap: gap,
3157 Gbreve: Gbreve,
3158 gbreve: gbreve,
3159 Gcedil: Gcedil,
3160 Gcirc: Gcirc,
3161 gcirc: gcirc,
3162 Gcy: Gcy,
3163 gcy: gcy,
3164 Gdot: Gdot,
3165 gdot: gdot,
3166 ge: ge,
3167 gE: gE,
3168 gEl: gEl,
3169 gel: gel,
3170 geq: geq,
3171 geqq: geqq,
3172 geqslant: geqslant,
3173 gescc: gescc,
3174 ges: ges,
3175 gesdot: gesdot,
3176 gesdoto: gesdoto,
3177 gesdotol: gesdotol,
3178 gesl: gesl,
3179 gesles: gesles,
3180 Gfr: Gfr,
3181 gfr: gfr,
3182 gg: gg,
3183 Gg: Gg,
3184 ggg: ggg,
3185 gimel: gimel,
3186 GJcy: GJcy,
3187 gjcy: gjcy,
3188 gla: gla,
3189 gl: gl,
3190 glE: glE,
3191 glj: glj,
3192 gnap: gnap,
3193 gnapprox: gnapprox,
3194 gne: gne,
3195 gnE: gnE,
3196 gneq: gneq,
3197 gneqq: gneqq,
3198 gnsim: gnsim,
3199 Gopf: Gopf,
3200 gopf: gopf,
3201 grave: grave,
3202 GreaterEqual: GreaterEqual,
3203 GreaterEqualLess: GreaterEqualLess,
3204 GreaterFullEqual: GreaterFullEqual,
3205 GreaterGreater: GreaterGreater,
3206 GreaterLess: GreaterLess,
3207 GreaterSlantEqual: GreaterSlantEqual,
3208 GreaterTilde: GreaterTilde,
3209 Gscr: Gscr,
3210 gscr: gscr,
3211 gsim: gsim,
3212 gsime: gsime,
3213 gsiml: gsiml,
3214 gtcc: gtcc,
3215 gtcir: gtcir,
3216 gt: gt,
3217 GT: GT,
3218 Gt: Gt,
3219 gtdot: gtdot,
3220 gtlPar: gtlPar,
3221 gtquest: gtquest,
3222 gtrapprox: gtrapprox,
3223 gtrarr: gtrarr,
3224 gtrdot: gtrdot,
3225 gtreqless: gtreqless,
3226 gtreqqless: gtreqqless,
3227 gtrless: gtrless,
3228 gtrsim: gtrsim,
3229 gvertneqq: gvertneqq,
3230 gvnE: gvnE,
3231 Hacek: Hacek,
3232 hairsp: hairsp,
3233 half: half,
3234 hamilt: hamilt,
3235 HARDcy: HARDcy,
3236 hardcy: hardcy,
3237 harrcir: harrcir,
3238 harr: harr,
3239 hArr: hArr,
3240 harrw: harrw,
3241 Hat: Hat,
3242 hbar: hbar,
3243 Hcirc: Hcirc,
3244 hcirc: hcirc,
3245 hearts: hearts,
3246 heartsuit: heartsuit,
3247 hellip: hellip,
3248 hercon: hercon,
3249 hfr: hfr,
3250 Hfr: Hfr,
3251 HilbertSpace: HilbertSpace,
3252 hksearow: hksearow,
3253 hkswarow: hkswarow,
3254 hoarr: hoarr,
3255 homtht: homtht,
3256 hookleftarrow: hookleftarrow,
3257 hookrightarrow: hookrightarrow,
3258 hopf: hopf,
3259 Hopf: Hopf,
3260 horbar: horbar,
3261 HorizontalLine: HorizontalLine,
3262 hscr: hscr,
3263 Hscr: Hscr,
3264 hslash: hslash,
3265 Hstrok: Hstrok,
3266 hstrok: hstrok,
3267 HumpDownHump: HumpDownHump,
3268 HumpEqual: HumpEqual,
3269 hybull: hybull,
3270 hyphen: hyphen,
3271 Iacute: Iacute,
3272 iacute: iacute,
3273 ic: ic,
3274 Icirc: Icirc,
3275 icirc: icirc,
3276 Icy: Icy,
3277 icy: icy,
3278 Idot: Idot,
3279 IEcy: IEcy,
3280 iecy: iecy,
3281 iexcl: iexcl,
3282 iff: iff,
3283 ifr: ifr,
3284 Ifr: Ifr,
3285 Igrave: Igrave,
3286 igrave: igrave,
3287 ii: ii,
3288 iiiint: iiiint,
3289 iiint: iiint,
3290 iinfin: iinfin,
3291 iiota: iiota,
3292 IJlig: IJlig,
3293 ijlig: ijlig,
3294 Imacr: Imacr,
3295 imacr: imacr,
3296 image: image,
3297 ImaginaryI: ImaginaryI,
3298 imagline: imagline,
3299 imagpart: imagpart,
3300 imath: imath,
3301 Im: Im,
3302 imof: imof,
3303 imped: imped,
3304 Implies: Implies,
3305 incare: incare,
3306 "in": "∈",
3307 infin: infin,
3308 infintie: infintie,
3309 inodot: inodot,
3310 intcal: intcal,
3311 int: int,
3312 Int: Int,
3313 integers: integers,
3314 Integral: Integral,
3315 intercal: intercal,
3316 Intersection: Intersection,
3317 intlarhk: intlarhk,
3318 intprod: intprod,
3319 InvisibleComma: InvisibleComma,
3320 InvisibleTimes: InvisibleTimes,
3321 IOcy: IOcy,
3322 iocy: iocy,
3323 Iogon: Iogon,
3324 iogon: iogon,
3325 Iopf: Iopf,
3326 iopf: iopf,
3327 Iota: Iota,
3328 iota: iota,
3329 iprod: iprod,
3330 iquest: iquest,
3331 iscr: iscr,
3332 Iscr: Iscr,
3333 isin: isin,
3334 isindot: isindot,
3335 isinE: isinE,
3336 isins: isins,
3337 isinsv: isinsv,
3338 isinv: isinv,
3339 it: it,
3340 Itilde: Itilde,
3341 itilde: itilde,
3342 Iukcy: Iukcy,
3343 iukcy: iukcy,
3344 Iuml: Iuml,
3345 iuml: iuml,
3346 Jcirc: Jcirc,
3347 jcirc: jcirc,
3348 Jcy: Jcy,
3349 jcy: jcy,
3350 Jfr: Jfr,
3351 jfr: jfr,
3352 jmath: jmath,
3353 Jopf: Jopf,
3354 jopf: jopf,
3355 Jscr: Jscr,
3356 jscr: jscr,
3357 Jsercy: Jsercy,
3358 jsercy: jsercy,
3359 Jukcy: Jukcy,
3360 jukcy: jukcy,
3361 Kappa: Kappa,
3362 kappa: kappa,
3363 kappav: kappav,
3364 Kcedil: Kcedil,
3365 kcedil: kcedil,
3366 Kcy: Kcy,
3367 kcy: kcy,
3368 Kfr: Kfr,
3369 kfr: kfr,
3370 kgreen: kgreen,
3371 KHcy: KHcy,
3372 khcy: khcy,
3373 KJcy: KJcy,
3374 kjcy: kjcy,
3375 Kopf: Kopf,
3376 kopf: kopf,
3377 Kscr: Kscr,
3378 kscr: kscr,
3379 lAarr: lAarr,
3380 Lacute: Lacute,
3381 lacute: lacute,
3382 laemptyv: laemptyv,
3383 lagran: lagran,
3384 Lambda: Lambda,
3385 lambda: lambda,
3386 lang: lang,
3387 Lang: Lang,
3388 langd: langd,
3389 langle: langle,
3390 lap: lap,
3391 Laplacetrf: Laplacetrf,
3392 laquo: laquo,
3393 larrb: larrb,
3394 larrbfs: larrbfs,
3395 larr: larr,
3396 Larr: Larr,
3397 lArr: lArr,
3398 larrfs: larrfs,
3399 larrhk: larrhk,
3400 larrlp: larrlp,
3401 larrpl: larrpl,
3402 larrsim: larrsim,
3403 larrtl: larrtl,
3404 latail: latail,
3405 lAtail: lAtail,
3406 lat: lat,
3407 late: late,
3408 lates: lates,
3409 lbarr: lbarr,
3410 lBarr: lBarr,
3411 lbbrk: lbbrk,
3412 lbrace: lbrace,
3413 lbrack: lbrack,
3414 lbrke: lbrke,
3415 lbrksld: lbrksld,
3416 lbrkslu: lbrkslu,
3417 Lcaron: Lcaron,
3418 lcaron: lcaron,
3419 Lcedil: Lcedil,
3420 lcedil: lcedil,
3421 lceil: lceil,
3422 lcub: lcub,
3423 Lcy: Lcy,
3424 lcy: lcy,
3425 ldca: ldca,
3426 ldquo: ldquo,
3427 ldquor: ldquor,
3428 ldrdhar: ldrdhar,
3429 ldrushar: ldrushar,
3430 ldsh: ldsh,
3431 le: le,
3432 lE: lE,
3433 LeftAngleBracket: LeftAngleBracket,
3434 LeftArrowBar: LeftArrowBar,
3435 leftarrow: leftarrow,
3436 LeftArrow: LeftArrow,
3437 Leftarrow: Leftarrow,
3438 LeftArrowRightArrow: LeftArrowRightArrow,
3439 leftarrowtail: leftarrowtail,
3440 LeftCeiling: LeftCeiling,
3441 LeftDoubleBracket: LeftDoubleBracket,
3442 LeftDownTeeVector: LeftDownTeeVector,
3443 LeftDownVectorBar: LeftDownVectorBar,
3444 LeftDownVector: LeftDownVector,
3445 LeftFloor: LeftFloor,
3446 leftharpoondown: leftharpoondown,
3447 leftharpoonup: leftharpoonup,
3448 leftleftarrows: leftleftarrows,
3449 leftrightarrow: leftrightarrow,
3450 LeftRightArrow: LeftRightArrow,
3451 Leftrightarrow: Leftrightarrow,
3452 leftrightarrows: leftrightarrows,
3453 leftrightharpoons: leftrightharpoons,
3454 leftrightsquigarrow: leftrightsquigarrow,
3455 LeftRightVector: LeftRightVector,
3456 LeftTeeArrow: LeftTeeArrow,
3457 LeftTee: LeftTee,
3458 LeftTeeVector: LeftTeeVector,
3459 leftthreetimes: leftthreetimes,
3460 LeftTriangleBar: LeftTriangleBar,
3461 LeftTriangle: LeftTriangle,
3462 LeftTriangleEqual: LeftTriangleEqual,
3463 LeftUpDownVector: LeftUpDownVector,
3464 LeftUpTeeVector: LeftUpTeeVector,
3465 LeftUpVectorBar: LeftUpVectorBar,
3466 LeftUpVector: LeftUpVector,
3467 LeftVectorBar: LeftVectorBar,
3468 LeftVector: LeftVector,
3469 lEg: lEg,
3470 leg: leg,
3471 leq: leq,
3472 leqq: leqq,
3473 leqslant: leqslant,
3474 lescc: lescc,
3475 les: les,
3476 lesdot: lesdot,
3477 lesdoto: lesdoto,
3478 lesdotor: lesdotor,
3479 lesg: lesg,
3480 lesges: lesges,
3481 lessapprox: lessapprox,
3482 lessdot: lessdot,
3483 lesseqgtr: lesseqgtr,
3484 lesseqqgtr: lesseqqgtr,
3485 LessEqualGreater: LessEqualGreater,
3486 LessFullEqual: LessFullEqual,
3487 LessGreater: LessGreater,
3488 lessgtr: lessgtr,
3489 LessLess: LessLess,
3490 lesssim: lesssim,
3491 LessSlantEqual: LessSlantEqual,
3492 LessTilde: LessTilde,
3493 lfisht: lfisht,
3494 lfloor: lfloor,
3495 Lfr: Lfr,
3496 lfr: lfr,
3497 lg: lg,
3498 lgE: lgE,
3499 lHar: lHar,
3500 lhard: lhard,
3501 lharu: lharu,
3502 lharul: lharul,
3503 lhblk: lhblk,
3504 LJcy: LJcy,
3505 ljcy: ljcy,
3506 llarr: llarr,
3507 ll: ll,
3508 Ll: Ll,
3509 llcorner: llcorner,
3510 Lleftarrow: Lleftarrow,
3511 llhard: llhard,
3512 lltri: lltri,
3513 Lmidot: Lmidot,
3514 lmidot: lmidot,
3515 lmoustache: lmoustache,
3516 lmoust: lmoust,
3517 lnap: lnap,
3518 lnapprox: lnapprox,
3519 lne: lne,
3520 lnE: lnE,
3521 lneq: lneq,
3522 lneqq: lneqq,
3523 lnsim: lnsim,
3524 loang: loang,
3525 loarr: loarr,
3526 lobrk: lobrk,
3527 longleftarrow: longleftarrow,
3528 LongLeftArrow: LongLeftArrow,
3529 Longleftarrow: Longleftarrow,
3530 longleftrightarrow: longleftrightarrow,
3531 LongLeftRightArrow: LongLeftRightArrow,
3532 Longleftrightarrow: Longleftrightarrow,
3533 longmapsto: longmapsto,
3534 longrightarrow: longrightarrow,
3535 LongRightArrow: LongRightArrow,
3536 Longrightarrow: Longrightarrow,
3537 looparrowleft: looparrowleft,
3538 looparrowright: looparrowright,
3539 lopar: lopar,
3540 Lopf: Lopf,
3541 lopf: lopf,
3542 loplus: loplus,
3543 lotimes: lotimes,
3544 lowast: lowast,
3545 lowbar: lowbar,
3546 LowerLeftArrow: LowerLeftArrow,
3547 LowerRightArrow: LowerRightArrow,
3548 loz: loz,
3549 lozenge: lozenge,
3550 lozf: lozf,
3551 lpar: lpar,
3552 lparlt: lparlt,
3553 lrarr: lrarr,
3554 lrcorner: lrcorner,
3555 lrhar: lrhar,
3556 lrhard: lrhard,
3557 lrm: lrm,
3558 lrtri: lrtri,
3559 lsaquo: lsaquo,
3560 lscr: lscr,
3561 Lscr: Lscr,
3562 lsh: lsh,
3563 Lsh: Lsh,
3564 lsim: lsim,
3565 lsime: lsime,
3566 lsimg: lsimg,
3567 lsqb: lsqb,
3568 lsquo: lsquo,
3569 lsquor: lsquor,
3570 Lstrok: Lstrok,
3571 lstrok: lstrok,
3572 ltcc: ltcc,
3573 ltcir: ltcir,
3574 lt: lt,
3575 LT: LT,
3576 Lt: Lt,
3577 ltdot: ltdot,
3578 lthree: lthree,
3579 ltimes: ltimes,
3580 ltlarr: ltlarr,
3581 ltquest: ltquest,
3582 ltri: ltri,
3583 ltrie: ltrie,
3584 ltrif: ltrif,
3585 ltrPar: ltrPar,
3586 lurdshar: lurdshar,
3587 luruhar: luruhar,
3588 lvertneqq: lvertneqq,
3589 lvnE: lvnE,
3590 macr: macr,
3591 male: male,
3592 malt: malt,
3593 maltese: maltese,
3594 "Map": "⤅",
3595 map: map,
3596 mapsto: mapsto,
3597 mapstodown: mapstodown,
3598 mapstoleft: mapstoleft,
3599 mapstoup: mapstoup,
3600 marker: marker,
3601 mcomma: mcomma,
3602 Mcy: Mcy,
3603 mcy: mcy,
3604 mdash: mdash,
3605 mDDot: mDDot,
3606 measuredangle: measuredangle,
3607 MediumSpace: MediumSpace,
3608 Mellintrf: Mellintrf,
3609 Mfr: Mfr,
3610 mfr: mfr,
3611 mho: mho,
3612 micro: micro,
3613 midast: midast,
3614 midcir: midcir,
3615 mid: mid,
3616 middot: middot,
3617 minusb: minusb,
3618 minus: minus,
3619 minusd: minusd,
3620 minusdu: minusdu,
3621 MinusPlus: MinusPlus,
3622 mlcp: mlcp,
3623 mldr: mldr,
3624 mnplus: mnplus,
3625 models: models,
3626 Mopf: Mopf,
3627 mopf: mopf,
3628 mp: mp,
3629 mscr: mscr,
3630 Mscr: Mscr,
3631 mstpos: mstpos,
3632 Mu: Mu,
3633 mu: mu,
3634 multimap: multimap,
3635 mumap: mumap,
3636 nabla: nabla,
3637 Nacute: Nacute,
3638 nacute: nacute,
3639 nang: nang,
3640 nap: nap,
3641 napE: napE,
3642 napid: napid,
3643 napos: napos,
3644 napprox: napprox,
3645 natural: natural,
3646 naturals: naturals,
3647 natur: natur,
3648 nbsp: nbsp,
3649 nbump: nbump,
3650 nbumpe: nbumpe,
3651 ncap: ncap,
3652 Ncaron: Ncaron,
3653 ncaron: ncaron,
3654 Ncedil: Ncedil,
3655 ncedil: ncedil,
3656 ncong: ncong,
3657 ncongdot: ncongdot,
3658 ncup: ncup,
3659 Ncy: Ncy,
3660 ncy: ncy,
3661 ndash: ndash,
3662 nearhk: nearhk,
3663 nearr: nearr,
3664 neArr: neArr,
3665 nearrow: nearrow,
3666 ne: ne,
3667 nedot: nedot,
3668 NegativeMediumSpace: NegativeMediumSpace,
3669 NegativeThickSpace: NegativeThickSpace,
3670 NegativeThinSpace: NegativeThinSpace,
3671 NegativeVeryThinSpace: NegativeVeryThinSpace,
3672 nequiv: nequiv,
3673 nesear: nesear,
3674 nesim: nesim,
3675 NestedGreaterGreater: NestedGreaterGreater,
3676 NestedLessLess: NestedLessLess,
3677 NewLine: NewLine,
3678 nexist: nexist,
3679 nexists: nexists,
3680 Nfr: Nfr,
3681 nfr: nfr,
3682 ngE: ngE,
3683 nge: nge,
3684 ngeq: ngeq,
3685 ngeqq: ngeqq,
3686 ngeqslant: ngeqslant,
3687 nges: nges,
3688 nGg: nGg,
3689 ngsim: ngsim,
3690 nGt: nGt,
3691 ngt: ngt,
3692 ngtr: ngtr,
3693 nGtv: nGtv,
3694 nharr: nharr,
3695 nhArr: nhArr,
3696 nhpar: nhpar,
3697 ni: ni,
3698 nis: nis,
3699 nisd: nisd,
3700 niv: niv,
3701 NJcy: NJcy,
3702 njcy: njcy,
3703 nlarr: nlarr,
3704 nlArr: nlArr,
3705 nldr: nldr,
3706 nlE: nlE,
3707 nle: nle,
3708 nleftarrow: nleftarrow,
3709 nLeftarrow: nLeftarrow,
3710 nleftrightarrow: nleftrightarrow,
3711 nLeftrightarrow: nLeftrightarrow,
3712 nleq: nleq,
3713 nleqq: nleqq,
3714 nleqslant: nleqslant,
3715 nles: nles,
3716 nless: nless,
3717 nLl: nLl,
3718 nlsim: nlsim,
3719 nLt: nLt,
3720 nlt: nlt,
3721 nltri: nltri,
3722 nltrie: nltrie,
3723 nLtv: nLtv,
3724 nmid: nmid,
3725 NoBreak: NoBreak,
3726 NonBreakingSpace: NonBreakingSpace,
3727 nopf: nopf,
3728 Nopf: Nopf,
3729 Not: Not,
3730 not: not,
3731 NotCongruent: NotCongruent,
3732 NotCupCap: NotCupCap,
3733 NotDoubleVerticalBar: NotDoubleVerticalBar,
3734 NotElement: NotElement,
3735 NotEqual: NotEqual,
3736 NotEqualTilde: NotEqualTilde,
3737 NotExists: NotExists,
3738 NotGreater: NotGreater,
3739 NotGreaterEqual: NotGreaterEqual,
3740 NotGreaterFullEqual: NotGreaterFullEqual,
3741 NotGreaterGreater: NotGreaterGreater,
3742 NotGreaterLess: NotGreaterLess,
3743 NotGreaterSlantEqual: NotGreaterSlantEqual,
3744 NotGreaterTilde: NotGreaterTilde,
3745 NotHumpDownHump: NotHumpDownHump,
3746 NotHumpEqual: NotHumpEqual,
3747 notin: notin,
3748 notindot: notindot,
3749 notinE: notinE,
3750 notinva: notinva,
3751 notinvb: notinvb,
3752 notinvc: notinvc,
3753 NotLeftTriangleBar: NotLeftTriangleBar,
3754 NotLeftTriangle: NotLeftTriangle,
3755 NotLeftTriangleEqual: NotLeftTriangleEqual,
3756 NotLess: NotLess,
3757 NotLessEqual: NotLessEqual,
3758 NotLessGreater: NotLessGreater,
3759 NotLessLess: NotLessLess,
3760 NotLessSlantEqual: NotLessSlantEqual,
3761 NotLessTilde: NotLessTilde,
3762 NotNestedGreaterGreater: NotNestedGreaterGreater,
3763 NotNestedLessLess: NotNestedLessLess,
3764 notni: notni,
3765 notniva: notniva,
3766 notnivb: notnivb,
3767 notnivc: notnivc,
3768 NotPrecedes: NotPrecedes,
3769 NotPrecedesEqual: NotPrecedesEqual,
3770 NotPrecedesSlantEqual: NotPrecedesSlantEqual,
3771 NotReverseElement: NotReverseElement,
3772 NotRightTriangleBar: NotRightTriangleBar,
3773 NotRightTriangle: NotRightTriangle,
3774 NotRightTriangleEqual: NotRightTriangleEqual,
3775 NotSquareSubset: NotSquareSubset,
3776 NotSquareSubsetEqual: NotSquareSubsetEqual,
3777 NotSquareSuperset: NotSquareSuperset,
3778 NotSquareSupersetEqual: NotSquareSupersetEqual,
3779 NotSubset: NotSubset,
3780 NotSubsetEqual: NotSubsetEqual,
3781 NotSucceeds: NotSucceeds,
3782 NotSucceedsEqual: NotSucceedsEqual,
3783 NotSucceedsSlantEqual: NotSucceedsSlantEqual,
3784 NotSucceedsTilde: NotSucceedsTilde,
3785 NotSuperset: NotSuperset,
3786 NotSupersetEqual: NotSupersetEqual,
3787 NotTilde: NotTilde,
3788 NotTildeEqual: NotTildeEqual,
3789 NotTildeFullEqual: NotTildeFullEqual,
3790 NotTildeTilde: NotTildeTilde,
3791 NotVerticalBar: NotVerticalBar,
3792 nparallel: nparallel,
3793 npar: npar,
3794 nparsl: nparsl,
3795 npart: npart,
3796 npolint: npolint,
3797 npr: npr,
3798 nprcue: nprcue,
3799 nprec: nprec,
3800 npreceq: npreceq,
3801 npre: npre,
3802 nrarrc: nrarrc,
3803 nrarr: nrarr,
3804 nrArr: nrArr,
3805 nrarrw: nrarrw,
3806 nrightarrow: nrightarrow,
3807 nRightarrow: nRightarrow,
3808 nrtri: nrtri,
3809 nrtrie: nrtrie,
3810 nsc: nsc,
3811 nsccue: nsccue,
3812 nsce: nsce,
3813 Nscr: Nscr,
3814 nscr: nscr,
3815 nshortmid: nshortmid,
3816 nshortparallel: nshortparallel,
3817 nsim: nsim,
3818 nsime: nsime,
3819 nsimeq: nsimeq,
3820 nsmid: nsmid,
3821 nspar: nspar,
3822 nsqsube: nsqsube,
3823 nsqsupe: nsqsupe,
3824 nsub: nsub,
3825 nsubE: nsubE,
3826 nsube: nsube,
3827 nsubset: nsubset,
3828 nsubseteq: nsubseteq,
3829 nsubseteqq: nsubseteqq,
3830 nsucc: nsucc,
3831 nsucceq: nsucceq,
3832 nsup: nsup,
3833 nsupE: nsupE,
3834 nsupe: nsupe,
3835 nsupset: nsupset,
3836 nsupseteq: nsupseteq,
3837 nsupseteqq: nsupseteqq,
3838 ntgl: ntgl,
3839 Ntilde: Ntilde,
3840 ntilde: ntilde,
3841 ntlg: ntlg,
3842 ntriangleleft: ntriangleleft,
3843 ntrianglelefteq: ntrianglelefteq,
3844 ntriangleright: ntriangleright,
3845 ntrianglerighteq: ntrianglerighteq,
3846 Nu: Nu,
3847 nu: nu,
3848 num: num,
3849 numero: numero,
3850 numsp: numsp,
3851 nvap: nvap,
3852 nvdash: nvdash,
3853 nvDash: nvDash,
3854 nVdash: nVdash,
3855 nVDash: nVDash,
3856 nvge: nvge,
3857 nvgt: nvgt,
3858 nvHarr: nvHarr,
3859 nvinfin: nvinfin,
3860 nvlArr: nvlArr,
3861 nvle: nvle,
3862 nvlt: nvlt,
3863 nvltrie: nvltrie,
3864 nvrArr: nvrArr,
3865 nvrtrie: nvrtrie,
3866 nvsim: nvsim,
3867 nwarhk: nwarhk,
3868 nwarr: nwarr,
3869 nwArr: nwArr,
3870 nwarrow: nwarrow,
3871 nwnear: nwnear,
3872 Oacute: Oacute,
3873 oacute: oacute,
3874 oast: oast,
3875 Ocirc: Ocirc,
3876 ocirc: ocirc,
3877 ocir: ocir,
3878 Ocy: Ocy,
3879 ocy: ocy,
3880 odash: odash,
3881 Odblac: Odblac,
3882 odblac: odblac,
3883 odiv: odiv,
3884 odot: odot,
3885 odsold: odsold,
3886 OElig: OElig,
3887 oelig: oelig,
3888 ofcir: ofcir,
3889 Ofr: Ofr,
3890 ofr: ofr,
3891 ogon: ogon,
3892 Ograve: Ograve,
3893 ograve: ograve,
3894 ogt: ogt,
3895 ohbar: ohbar,
3896 ohm: ohm,
3897 oint: oint,
3898 olarr: olarr,
3899 olcir: olcir,
3900 olcross: olcross,
3901 oline: oline,
3902 olt: olt,
3903 Omacr: Omacr,
3904 omacr: omacr,
3905 Omega: Omega,
3906 omega: omega,
3907 Omicron: Omicron,
3908 omicron: omicron,
3909 omid: omid,
3910 ominus: ominus,
3911 Oopf: Oopf,
3912 oopf: oopf,
3913 opar: opar,
3914 OpenCurlyDoubleQuote: OpenCurlyDoubleQuote,
3915 OpenCurlyQuote: OpenCurlyQuote,
3916 operp: operp,
3917 oplus: oplus,
3918 orarr: orarr,
3919 Or: Or,
3920 or: or,
3921 ord: ord,
3922 order: order,
3923 orderof: orderof,
3924 ordf: ordf,
3925 ordm: ordm,
3926 origof: origof,
3927 oror: oror,
3928 orslope: orslope,
3929 orv: orv,
3930 oS: oS,
3931 Oscr: Oscr,
3932 oscr: oscr,
3933 Oslash: Oslash,
3934 oslash: oslash,
3935 osol: osol,
3936 Otilde: Otilde,
3937 otilde: otilde,
3938 otimesas: otimesas,
3939 Otimes: Otimes,
3940 otimes: otimes,
3941 Ouml: Ouml,
3942 ouml: ouml,
3943 ovbar: ovbar,
3944 OverBar: OverBar,
3945 OverBrace: OverBrace,
3946 OverBracket: OverBracket,
3947 OverParenthesis: OverParenthesis,
3948 para: para,
3949 parallel: parallel,
3950 par: par,
3951 parsim: parsim,
3952 parsl: parsl,
3953 part: part,
3954 PartialD: PartialD,
3955 Pcy: Pcy,
3956 pcy: pcy,
3957 percnt: percnt,
3958 period: period,
3959 permil: permil,
3960 perp: perp,
3961 pertenk: pertenk,
3962 Pfr: Pfr,
3963 pfr: pfr,
3964 Phi: Phi,
3965 phi: phi,
3966 phiv: phiv,
3967 phmmat: phmmat,
3968 phone: phone,
3969 Pi: Pi,
3970 pi: pi,
3971 pitchfork: pitchfork,
3972 piv: piv,
3973 planck: planck,
3974 planckh: planckh,
3975 plankv: plankv,
3976 plusacir: plusacir,
3977 plusb: plusb,
3978 pluscir: pluscir,
3979 plus: plus,
3980 plusdo: plusdo,
3981 plusdu: plusdu,
3982 pluse: pluse,
3983 PlusMinus: PlusMinus,
3984 plusmn: plusmn,
3985 plussim: plussim,
3986 plustwo: plustwo,
3987 pm: pm,
3988 Poincareplane: Poincareplane,
3989 pointint: pointint,
3990 popf: popf,
3991 Popf: Popf,
3992 pound: pound,
3993 prap: prap,
3994 Pr: Pr,
3995 pr: pr,
3996 prcue: prcue,
3997 precapprox: precapprox,
3998 prec: prec,
3999 preccurlyeq: preccurlyeq,
4000 Precedes: Precedes,
4001 PrecedesEqual: PrecedesEqual,
4002 PrecedesSlantEqual: PrecedesSlantEqual,
4003 PrecedesTilde: PrecedesTilde,
4004 preceq: preceq,
4005 precnapprox: precnapprox,
4006 precneqq: precneqq,
4007 precnsim: precnsim,
4008 pre: pre,
4009 prE: prE,
4010 precsim: precsim,
4011 prime: prime,
4012 Prime: Prime,
4013 primes: primes,
4014 prnap: prnap,
4015 prnE: prnE,
4016 prnsim: prnsim,
4017 prod: prod,
4018 Product: Product,
4019 profalar: profalar,
4020 profline: profline,
4021 profsurf: profsurf,
4022 prop: prop,
4023 Proportional: Proportional,
4024 Proportion: Proportion,
4025 propto: propto,
4026 prsim: prsim,
4027 prurel: prurel,
4028 Pscr: Pscr,
4029 pscr: pscr,
4030 Psi: Psi,
4031 psi: psi,
4032 puncsp: puncsp,
4033 Qfr: Qfr,
4034 qfr: qfr,
4035 qint: qint,
4036 qopf: qopf,
4037 Qopf: Qopf,
4038 qprime: qprime,
4039 Qscr: Qscr,
4040 qscr: qscr,
4041 quaternions: quaternions,
4042 quatint: quatint,
4043 quest: quest,
4044 questeq: questeq,
4045 quot: quot,
4046 QUOT: QUOT,
4047 rAarr: rAarr,
4048 race: race,
4049 Racute: Racute,
4050 racute: racute,
4051 radic: radic,
4052 raemptyv: raemptyv,
4053 rang: rang,
4054 Rang: Rang,
4055 rangd: rangd,
4056 range: range,
4057 rangle: rangle,
4058 raquo: raquo,
4059 rarrap: rarrap,
4060 rarrb: rarrb,
4061 rarrbfs: rarrbfs,
4062 rarrc: rarrc,
4063 rarr: rarr,
4064 Rarr: Rarr,
4065 rArr: rArr,
4066 rarrfs: rarrfs,
4067 rarrhk: rarrhk,
4068 rarrlp: rarrlp,
4069 rarrpl: rarrpl,
4070 rarrsim: rarrsim,
4071 Rarrtl: Rarrtl,
4072 rarrtl: rarrtl,
4073 rarrw: rarrw,
4074 ratail: ratail,
4075 rAtail: rAtail,
4076 ratio: ratio,
4077 rationals: rationals,
4078 rbarr: rbarr,
4079 rBarr: rBarr,
4080 RBarr: RBarr,
4081 rbbrk: rbbrk,
4082 rbrace: rbrace,
4083 rbrack: rbrack,
4084 rbrke: rbrke,
4085 rbrksld: rbrksld,
4086 rbrkslu: rbrkslu,
4087 Rcaron: Rcaron,
4088 rcaron: rcaron,
4089 Rcedil: Rcedil,
4090 rcedil: rcedil,
4091 rceil: rceil,
4092 rcub: rcub,
4093 Rcy: Rcy,
4094 rcy: rcy,
4095 rdca: rdca,
4096 rdldhar: rdldhar,
4097 rdquo: rdquo,
4098 rdquor: rdquor,
4099 rdsh: rdsh,
4100 real: real,
4101 realine: realine,
4102 realpart: realpart,
4103 reals: reals,
4104 Re: Re,
4105 rect: rect,
4106 reg: reg,
4107 REG: REG,
4108 ReverseElement: ReverseElement,
4109 ReverseEquilibrium: ReverseEquilibrium,
4110 ReverseUpEquilibrium: ReverseUpEquilibrium,
4111 rfisht: rfisht,
4112 rfloor: rfloor,
4113 rfr: rfr,
4114 Rfr: Rfr,
4115 rHar: rHar,
4116 rhard: rhard,
4117 rharu: rharu,
4118 rharul: rharul,
4119 Rho: Rho,
4120 rho: rho,
4121 rhov: rhov,
4122 RightAngleBracket: RightAngleBracket,
4123 RightArrowBar: RightArrowBar,
4124 rightarrow: rightarrow,
4125 RightArrow: RightArrow,
4126 Rightarrow: Rightarrow,
4127 RightArrowLeftArrow: RightArrowLeftArrow,
4128 rightarrowtail: rightarrowtail,
4129 RightCeiling: RightCeiling,
4130 RightDoubleBracket: RightDoubleBracket,
4131 RightDownTeeVector: RightDownTeeVector,
4132 RightDownVectorBar: RightDownVectorBar,
4133 RightDownVector: RightDownVector,
4134 RightFloor: RightFloor,
4135 rightharpoondown: rightharpoondown,
4136 rightharpoonup: rightharpoonup,
4137 rightleftarrows: rightleftarrows,
4138 rightleftharpoons: rightleftharpoons,
4139 rightrightarrows: rightrightarrows,
4140 rightsquigarrow: rightsquigarrow,
4141 RightTeeArrow: RightTeeArrow,
4142 RightTee: RightTee,
4143 RightTeeVector: RightTeeVector,
4144 rightthreetimes: rightthreetimes,
4145 RightTriangleBar: RightTriangleBar,
4146 RightTriangle: RightTriangle,
4147 RightTriangleEqual: RightTriangleEqual,
4148 RightUpDownVector: RightUpDownVector,
4149 RightUpTeeVector: RightUpTeeVector,
4150 RightUpVectorBar: RightUpVectorBar,
4151 RightUpVector: RightUpVector,
4152 RightVectorBar: RightVectorBar,
4153 RightVector: RightVector,
4154 ring: ring,
4155 risingdotseq: risingdotseq,
4156 rlarr: rlarr,
4157 rlhar: rlhar,
4158 rlm: rlm,
4159 rmoustache: rmoustache,
4160 rmoust: rmoust,
4161 rnmid: rnmid,
4162 roang: roang,
4163 roarr: roarr,
4164 robrk: robrk,
4165 ropar: ropar,
4166 ropf: ropf,
4167 Ropf: Ropf,
4168 roplus: roplus,
4169 rotimes: rotimes,
4170 RoundImplies: RoundImplies,
4171 rpar: rpar,
4172 rpargt: rpargt,
4173 rppolint: rppolint,
4174 rrarr: rrarr,
4175 Rrightarrow: Rrightarrow,
4176 rsaquo: rsaquo,
4177 rscr: rscr,
4178 Rscr: Rscr,
4179 rsh: rsh,
4180 Rsh: Rsh,
4181 rsqb: rsqb,
4182 rsquo: rsquo,
4183 rsquor: rsquor,
4184 rthree: rthree,
4185 rtimes: rtimes,
4186 rtri: rtri,
4187 rtrie: rtrie,
4188 rtrif: rtrif,
4189 rtriltri: rtriltri,
4190 RuleDelayed: RuleDelayed,
4191 ruluhar: ruluhar,
4192 rx: rx,
4193 Sacute: Sacute,
4194 sacute: sacute,
4195 sbquo: sbquo,
4196 scap: scap,
4197 Scaron: Scaron,
4198 scaron: scaron,
4199 Sc: Sc,
4200 sc: sc,
4201 sccue: sccue,
4202 sce: sce,
4203 scE: scE,
4204 Scedil: Scedil,
4205 scedil: scedil,
4206 Scirc: Scirc,
4207 scirc: scirc,
4208 scnap: scnap,
4209 scnE: scnE,
4210 scnsim: scnsim,
4211 scpolint: scpolint,
4212 scsim: scsim,
4213 Scy: Scy,
4214 scy: scy,
4215 sdotb: sdotb,
4216 sdot: sdot,
4217 sdote: sdote,
4218 searhk: searhk,
4219 searr: searr,
4220 seArr: seArr,
4221 searrow: searrow,
4222 sect: sect,
4223 semi: semi,
4224 seswar: seswar,
4225 setminus: setminus,
4226 setmn: setmn,
4227 sext: sext,
4228 Sfr: Sfr,
4229 sfr: sfr,
4230 sfrown: sfrown,
4231 sharp: sharp,
4232 SHCHcy: SHCHcy,
4233 shchcy: shchcy,
4234 SHcy: SHcy,
4235 shcy: shcy,
4236 ShortDownArrow: ShortDownArrow,
4237 ShortLeftArrow: ShortLeftArrow,
4238 shortmid: shortmid,
4239 shortparallel: shortparallel,
4240 ShortRightArrow: ShortRightArrow,
4241 ShortUpArrow: ShortUpArrow,
4242 shy: shy,
4243 Sigma: Sigma,
4244 sigma: sigma,
4245 sigmaf: sigmaf,
4246 sigmav: sigmav,
4247 sim: sim,
4248 simdot: simdot,
4249 sime: sime,
4250 simeq: simeq,
4251 simg: simg,
4252 simgE: simgE,
4253 siml: siml,
4254 simlE: simlE,
4255 simne: simne,
4256 simplus: simplus,
4257 simrarr: simrarr,
4258 slarr: slarr,
4259 SmallCircle: SmallCircle,
4260 smallsetminus: smallsetminus,
4261 smashp: smashp,
4262 smeparsl: smeparsl,
4263 smid: smid,
4264 smile: smile,
4265 smt: smt,
4266 smte: smte,
4267 smtes: smtes,
4268 SOFTcy: SOFTcy,
4269 softcy: softcy,
4270 solbar: solbar,
4271 solb: solb,
4272 sol: sol,
4273 Sopf: Sopf,
4274 sopf: sopf,
4275 spades: spades,
4276 spadesuit: spadesuit,
4277 spar: spar,
4278 sqcap: sqcap,
4279 sqcaps: sqcaps,
4280 sqcup: sqcup,
4281 sqcups: sqcups,
4282 Sqrt: Sqrt,
4283 sqsub: sqsub,
4284 sqsube: sqsube,
4285 sqsubset: sqsubset,
4286 sqsubseteq: sqsubseteq,
4287 sqsup: sqsup,
4288 sqsupe: sqsupe,
4289 sqsupset: sqsupset,
4290 sqsupseteq: sqsupseteq,
4291 square: square,
4292 Square: Square,
4293 SquareIntersection: SquareIntersection,
4294 SquareSubset: SquareSubset,
4295 SquareSubsetEqual: SquareSubsetEqual,
4296 SquareSuperset: SquareSuperset,
4297 SquareSupersetEqual: SquareSupersetEqual,
4298 SquareUnion: SquareUnion,
4299 squarf: squarf,
4300 squ: squ,
4301 squf: squf,
4302 srarr: srarr,
4303 Sscr: Sscr,
4304 sscr: sscr,
4305 ssetmn: ssetmn,
4306 ssmile: ssmile,
4307 sstarf: sstarf,
4308 Star: Star,
4309 star: star,
4310 starf: starf,
4311 straightepsilon: straightepsilon,
4312 straightphi: straightphi,
4313 strns: strns,
4314 sub: sub,
4315 Sub: Sub,
4316 subdot: subdot,
4317 subE: subE,
4318 sube: sube,
4319 subedot: subedot,
4320 submult: submult,
4321 subnE: subnE,
4322 subne: subne,
4323 subplus: subplus,
4324 subrarr: subrarr,
4325 subset: subset,
4326 Subset: Subset,
4327 subseteq: subseteq,
4328 subseteqq: subseteqq,
4329 SubsetEqual: SubsetEqual,
4330 subsetneq: subsetneq,
4331 subsetneqq: subsetneqq,
4332 subsim: subsim,
4333 subsub: subsub,
4334 subsup: subsup,
4335 succapprox: succapprox,
4336 succ: succ,
4337 succcurlyeq: succcurlyeq,
4338 Succeeds: Succeeds,
4339 SucceedsEqual: SucceedsEqual,
4340 SucceedsSlantEqual: SucceedsSlantEqual,
4341 SucceedsTilde: SucceedsTilde,
4342 succeq: succeq,
4343 succnapprox: succnapprox,
4344 succneqq: succneqq,
4345 succnsim: succnsim,
4346 succsim: succsim,
4347 SuchThat: SuchThat,
4348 sum: sum,
4349 Sum: Sum,
4350 sung: sung,
4351 sup1: sup1,
4352 sup2: sup2,
4353 sup3: sup3,
4354 sup: sup,
4355 Sup: Sup,
4356 supdot: supdot,
4357 supdsub: supdsub,
4358 supE: supE,
4359 supe: supe,
4360 supedot: supedot,
4361 Superset: Superset,
4362 SupersetEqual: SupersetEqual,
4363 suphsol: suphsol,
4364 suphsub: suphsub,
4365 suplarr: suplarr,
4366 supmult: supmult,
4367 supnE: supnE,
4368 supne: supne,
4369 supplus: supplus,
4370 supset: supset,
4371 Supset: Supset,
4372 supseteq: supseteq,
4373 supseteqq: supseteqq,
4374 supsetneq: supsetneq,
4375 supsetneqq: supsetneqq,
4376 supsim: supsim,
4377 supsub: supsub,
4378 supsup: supsup,
4379 swarhk: swarhk,
4380 swarr: swarr,
4381 swArr: swArr,
4382 swarrow: swarrow,
4383 swnwar: swnwar,
4384 szlig: szlig,
4385 Tab: Tab,
4386 target: target,
4387 Tau: Tau,
4388 tau: tau,
4389 tbrk: tbrk,
4390 Tcaron: Tcaron,
4391 tcaron: tcaron,
4392 Tcedil: Tcedil,
4393 tcedil: tcedil,
4394 Tcy: Tcy,
4395 tcy: tcy,
4396 tdot: tdot,
4397 telrec: telrec,
4398 Tfr: Tfr,
4399 tfr: tfr,
4400 there4: there4,
4401 therefore: therefore,
4402 Therefore: Therefore,
4403 Theta: Theta,
4404 theta: theta,
4405 thetasym: thetasym,
4406 thetav: thetav,
4407 thickapprox: thickapprox,
4408 thicksim: thicksim,
4409 ThickSpace: ThickSpace,
4410 ThinSpace: ThinSpace,
4411 thinsp: thinsp,
4412 thkap: thkap,
4413 thksim: thksim,
4414 THORN: THORN,
4415 thorn: thorn,
4416 tilde: tilde,
4417 Tilde: Tilde,
4418 TildeEqual: TildeEqual,
4419 TildeFullEqual: TildeFullEqual,
4420 TildeTilde: TildeTilde,
4421 timesbar: timesbar,
4422 timesb: timesb,
4423 times: times,
4424 timesd: timesd,
4425 tint: tint,
4426 toea: toea,
4427 topbot: topbot,
4428 topcir: topcir,
4429 top: top,
4430 Topf: Topf,
4431 topf: topf,
4432 topfork: topfork,
4433 tosa: tosa,
4434 tprime: tprime,
4435 trade: trade,
4436 TRADE: TRADE,
4437 triangle: triangle,
4438 triangledown: triangledown,
4439 triangleleft: triangleleft,
4440 trianglelefteq: trianglelefteq,
4441 triangleq: triangleq,
4442 triangleright: triangleright,
4443 trianglerighteq: trianglerighteq,
4444 tridot: tridot,
4445 trie: trie,
4446 triminus: triminus,
4447 TripleDot: TripleDot,
4448 triplus: triplus,
4449 trisb: trisb,
4450 tritime: tritime,
4451 trpezium: trpezium,
4452 Tscr: Tscr,
4453 tscr: tscr,
4454 TScy: TScy,
4455 tscy: tscy,
4456 TSHcy: TSHcy,
4457 tshcy: tshcy,
4458 Tstrok: Tstrok,
4459 tstrok: tstrok,
4460 twixt: twixt,
4461 twoheadleftarrow: twoheadleftarrow,
4462 twoheadrightarrow: twoheadrightarrow,
4463 Uacute: Uacute,
4464 uacute: uacute,
4465 uarr: uarr,
4466 Uarr: Uarr,
4467 uArr: uArr,
4468 Uarrocir: Uarrocir,
4469 Ubrcy: Ubrcy,
4470 ubrcy: ubrcy,
4471 Ubreve: Ubreve,
4472 ubreve: ubreve,
4473 Ucirc: Ucirc,
4474 ucirc: ucirc,
4475 Ucy: Ucy,
4476 ucy: ucy,
4477 udarr: udarr,
4478 Udblac: Udblac,
4479 udblac: udblac,
4480 udhar: udhar,
4481 ufisht: ufisht,
4482 Ufr: Ufr,
4483 ufr: ufr,
4484 Ugrave: Ugrave,
4485 ugrave: ugrave,
4486 uHar: uHar,
4487 uharl: uharl,
4488 uharr: uharr,
4489 uhblk: uhblk,
4490 ulcorn: ulcorn,
4491 ulcorner: ulcorner,
4492 ulcrop: ulcrop,
4493 ultri: ultri,
4494 Umacr: Umacr,
4495 umacr: umacr,
4496 uml: uml,
4497 UnderBar: UnderBar,
4498 UnderBrace: UnderBrace,
4499 UnderBracket: UnderBracket,
4500 UnderParenthesis: UnderParenthesis,
4501 Union: Union,
4502 UnionPlus: UnionPlus,
4503 Uogon: Uogon,
4504 uogon: uogon,
4505 Uopf: Uopf,
4506 uopf: uopf,
4507 UpArrowBar: UpArrowBar,
4508 uparrow: uparrow,
4509 UpArrow: UpArrow,
4510 Uparrow: Uparrow,
4511 UpArrowDownArrow: UpArrowDownArrow,
4512 updownarrow: updownarrow,
4513 UpDownArrow: UpDownArrow,
4514 Updownarrow: Updownarrow,
4515 UpEquilibrium: UpEquilibrium,
4516 upharpoonleft: upharpoonleft,
4517 upharpoonright: upharpoonright,
4518 uplus: uplus,
4519 UpperLeftArrow: UpperLeftArrow,
4520 UpperRightArrow: UpperRightArrow,
4521 upsi: upsi,
4522 Upsi: Upsi,
4523 upsih: upsih,
4524 Upsilon: Upsilon,
4525 upsilon: upsilon,
4526 UpTeeArrow: UpTeeArrow,
4527 UpTee: UpTee,
4528 upuparrows: upuparrows,
4529 urcorn: urcorn,
4530 urcorner: urcorner,
4531 urcrop: urcrop,
4532 Uring: Uring,
4533 uring: uring,
4534 urtri: urtri,
4535 Uscr: Uscr,
4536 uscr: uscr,
4537 utdot: utdot,
4538 Utilde: Utilde,
4539 utilde: utilde,
4540 utri: utri,
4541 utrif: utrif,
4542 uuarr: uuarr,
4543 Uuml: Uuml,
4544 uuml: uuml,
4545 uwangle: uwangle,
4546 vangrt: vangrt,
4547 varepsilon: varepsilon,
4548 varkappa: varkappa,
4549 varnothing: varnothing,
4550 varphi: varphi,
4551 varpi: varpi,
4552 varpropto: varpropto,
4553 varr: varr,
4554 vArr: vArr,
4555 varrho: varrho,
4556 varsigma: varsigma,
4557 varsubsetneq: varsubsetneq,
4558 varsubsetneqq: varsubsetneqq,
4559 varsupsetneq: varsupsetneq,
4560 varsupsetneqq: varsupsetneqq,
4561 vartheta: vartheta,
4562 vartriangleleft: vartriangleleft,
4563 vartriangleright: vartriangleright,
4564 vBar: vBar,
4565 Vbar: Vbar,
4566 vBarv: vBarv,
4567 Vcy: Vcy,
4568 vcy: vcy,
4569 vdash: vdash,
4570 vDash: vDash,
4571 Vdash: Vdash,
4572 VDash: VDash,
4573 Vdashl: Vdashl,
4574 veebar: veebar,
4575 vee: vee,
4576 Vee: Vee,
4577 veeeq: veeeq,
4578 vellip: vellip,
4579 verbar: verbar,
4580 Verbar: Verbar,
4581 vert: vert,
4582 Vert: Vert,
4583 VerticalBar: VerticalBar,
4584 VerticalLine: VerticalLine,
4585 VerticalSeparator: VerticalSeparator,
4586 VerticalTilde: VerticalTilde,
4587 VeryThinSpace: VeryThinSpace,
4588 Vfr: Vfr,
4589 vfr: vfr,
4590 vltri: vltri,
4591 vnsub: vnsub,
4592 vnsup: vnsup,
4593 Vopf: Vopf,
4594 vopf: vopf,
4595 vprop: vprop,
4596 vrtri: vrtri,
4597 Vscr: Vscr,
4598 vscr: vscr,
4599 vsubnE: vsubnE,
4600 vsubne: vsubne,
4601 vsupnE: vsupnE,
4602 vsupne: vsupne,
4603 Vvdash: Vvdash,
4604 vzigzag: vzigzag,
4605 Wcirc: Wcirc,
4606 wcirc: wcirc,
4607 wedbar: wedbar,
4608 wedge: wedge,
4609 Wedge: Wedge,
4610 wedgeq: wedgeq,
4611 weierp: weierp,
4612 Wfr: Wfr,
4613 wfr: wfr,
4614 Wopf: Wopf,
4615 wopf: wopf,
4616 wp: wp,
4617 wr: wr,
4618 wreath: wreath,
4619 Wscr: Wscr,
4620 wscr: wscr,
4621 xcap: xcap,
4622 xcirc: xcirc,
4623 xcup: xcup,
4624 xdtri: xdtri,
4625 Xfr: Xfr,
4626 xfr: xfr,
4627 xharr: xharr,
4628 xhArr: xhArr,
4629 Xi: Xi,
4630 xi: xi,
4631 xlarr: xlarr,
4632 xlArr: xlArr,
4633 xmap: xmap,
4634 xnis: xnis,
4635 xodot: xodot,
4636 Xopf: Xopf,
4637 xopf: xopf,
4638 xoplus: xoplus,
4639 xotime: xotime,
4640 xrarr: xrarr,
4641 xrArr: xrArr,
4642 Xscr: Xscr,
4643 xscr: xscr,
4644 xsqcup: xsqcup,
4645 xuplus: xuplus,
4646 xutri: xutri,
4647 xvee: xvee,
4648 xwedge: xwedge,
4649 Yacute: Yacute,
4650 yacute: yacute,
4651 YAcy: YAcy,
4652 yacy: yacy,
4653 Ycirc: Ycirc,
4654 ycirc: ycirc,
4655 Ycy: Ycy,
4656 ycy: ycy,
4657 yen: yen,
4658 Yfr: Yfr,
4659 yfr: yfr,
4660 YIcy: YIcy,
4661 yicy: yicy,
4662 Yopf: Yopf,
4663 yopf: yopf,
4664 Yscr: Yscr,
4665 yscr: yscr,
4666 YUcy: YUcy,
4667 yucy: yucy,
4668 yuml: yuml,
4669 Yuml: Yuml,
4670 Zacute: Zacute,
4671 zacute: zacute,
4672 Zcaron: Zcaron,
4673 zcaron: zcaron,
4674 Zcy: Zcy,
4675 zcy: zcy,
4676 Zdot: Zdot,
4677 zdot: zdot,
4678 zeetrf: zeetrf,
4679 ZeroWidthSpace: ZeroWidthSpace,
4680 Zeta: Zeta,
4681 zeta: zeta,
4682 zfr: zfr,
4683 Zfr: Zfr,
4684 ZHcy: ZHcy,
4685 zhcy: zhcy,
4686 zigrarr: zigrarr,
4687 zopf: zopf,
4688 Zopf: Zopf,
4689 Zscr: Zscr,
4690 zscr: zscr,
4691 zwj: zwj,
4692 zwnj: zwnj
4693 };
4694
4695 var entities$1 = /*#__PURE__*/Object.freeze({
4696 __proto__: null,
4697 Aacute: Aacute,
4698 aacute: aacute,
4699 Abreve: Abreve,
4700 abreve: abreve,
4701 ac: ac,
4702 acd: acd,
4703 acE: acE,
4704 Acirc: Acirc,
4705 acirc: acirc,
4706 acute: acute,
4707 Acy: Acy,
4708 acy: acy,
4709 AElig: AElig,
4710 aelig: aelig,
4711 af: af,
4712 Afr: Afr,
4713 afr: afr,
4714 Agrave: Agrave,
4715 agrave: agrave,
4716 alefsym: alefsym,
4717 aleph: aleph,
4718 Alpha: Alpha,
4719 alpha: alpha,
4720 Amacr: Amacr,
4721 amacr: amacr,
4722 amalg: amalg,
4723 amp: amp,
4724 AMP: AMP,
4725 andand: andand,
4726 And: And,
4727 and: and,
4728 andd: andd,
4729 andslope: andslope,
4730 andv: andv,
4731 ang: ang,
4732 ange: ange,
4733 angle: angle,
4734 angmsdaa: angmsdaa,
4735 angmsdab: angmsdab,
4736 angmsdac: angmsdac,
4737 angmsdad: angmsdad,
4738 angmsdae: angmsdae,
4739 angmsdaf: angmsdaf,
4740 angmsdag: angmsdag,
4741 angmsdah: angmsdah,
4742 angmsd: angmsd,
4743 angrt: angrt,
4744 angrtvb: angrtvb,
4745 angrtvbd: angrtvbd,
4746 angsph: angsph,
4747 angst: angst,
4748 angzarr: angzarr,
4749 Aogon: Aogon,
4750 aogon: aogon,
4751 Aopf: Aopf,
4752 aopf: aopf,
4753 apacir: apacir,
4754 ap: ap,
4755 apE: apE,
4756 ape: ape,
4757 apid: apid,
4758 apos: apos,
4759 ApplyFunction: ApplyFunction,
4760 approx: approx,
4761 approxeq: approxeq,
4762 Aring: Aring,
4763 aring: aring,
4764 Ascr: Ascr,
4765 ascr: ascr,
4766 Assign: Assign,
4767 ast: ast,
4768 asymp: asymp,
4769 asympeq: asympeq,
4770 Atilde: Atilde,
4771 atilde: atilde,
4772 Auml: Auml,
4773 auml: auml,
4774 awconint: awconint,
4775 awint: awint,
4776 backcong: backcong,
4777 backepsilon: backepsilon,
4778 backprime: backprime,
4779 backsim: backsim,
4780 backsimeq: backsimeq,
4781 Backslash: Backslash,
4782 Barv: Barv,
4783 barvee: barvee,
4784 barwed: barwed,
4785 Barwed: Barwed,
4786 barwedge: barwedge,
4787 bbrk: bbrk,
4788 bbrktbrk: bbrktbrk,
4789 bcong: bcong,
4790 Bcy: Bcy,
4791 bcy: bcy,
4792 bdquo: bdquo,
4793 becaus: becaus,
4794 because: because,
4795 Because: Because,
4796 bemptyv: bemptyv,
4797 bepsi: bepsi,
4798 bernou: bernou,
4799 Bernoullis: Bernoullis,
4800 Beta: Beta,
4801 beta: beta,
4802 beth: beth,
4803 between: between,
4804 Bfr: Bfr,
4805 bfr: bfr,
4806 bigcap: bigcap,
4807 bigcirc: bigcirc,
4808 bigcup: bigcup,
4809 bigodot: bigodot,
4810 bigoplus: bigoplus,
4811 bigotimes: bigotimes,
4812 bigsqcup: bigsqcup,
4813 bigstar: bigstar,
4814 bigtriangledown: bigtriangledown,
4815 bigtriangleup: bigtriangleup,
4816 biguplus: biguplus,
4817 bigvee: bigvee,
4818 bigwedge: bigwedge,
4819 bkarow: bkarow,
4820 blacklozenge: blacklozenge,
4821 blacksquare: blacksquare,
4822 blacktriangle: blacktriangle,
4823 blacktriangledown: blacktriangledown,
4824 blacktriangleleft: blacktriangleleft,
4825 blacktriangleright: blacktriangleright,
4826 blank: blank,
4827 blk12: blk12,
4828 blk14: blk14,
4829 blk34: blk34,
4830 block: block,
4831 bne: bne,
4832 bnequiv: bnequiv,
4833 bNot: bNot,
4834 bnot: bnot,
4835 Bopf: Bopf,
4836 bopf: bopf,
4837 bot: bot,
4838 bottom: bottom,
4839 bowtie: bowtie,
4840 boxbox: boxbox,
4841 boxdl: boxdl,
4842 boxdL: boxdL,
4843 boxDl: boxDl,
4844 boxDL: boxDL,
4845 boxdr: boxdr,
4846 boxdR: boxdR,
4847 boxDr: boxDr,
4848 boxDR: boxDR,
4849 boxh: boxh,
4850 boxH: boxH,
4851 boxhd: boxhd,
4852 boxHd: boxHd,
4853 boxhD: boxhD,
4854 boxHD: boxHD,
4855 boxhu: boxhu,
4856 boxHu: boxHu,
4857 boxhU: boxhU,
4858 boxHU: boxHU,
4859 boxminus: boxminus,
4860 boxplus: boxplus,
4861 boxtimes: boxtimes,
4862 boxul: boxul,
4863 boxuL: boxuL,
4864 boxUl: boxUl,
4865 boxUL: boxUL,
4866 boxur: boxur,
4867 boxuR: boxuR,
4868 boxUr: boxUr,
4869 boxUR: boxUR,
4870 boxv: boxv,
4871 boxV: boxV,
4872 boxvh: boxvh,
4873 boxvH: boxvH,
4874 boxVh: boxVh,
4875 boxVH: boxVH,
4876 boxvl: boxvl,
4877 boxvL: boxvL,
4878 boxVl: boxVl,
4879 boxVL: boxVL,
4880 boxvr: boxvr,
4881 boxvR: boxvR,
4882 boxVr: boxVr,
4883 boxVR: boxVR,
4884 bprime: bprime,
4885 breve: breve,
4886 Breve: Breve,
4887 brvbar: brvbar,
4888 bscr: bscr,
4889 Bscr: Bscr,
4890 bsemi: bsemi,
4891 bsim: bsim,
4892 bsime: bsime,
4893 bsolb: bsolb,
4894 bsol: bsol,
4895 bsolhsub: bsolhsub,
4896 bull: bull,
4897 bullet: bullet,
4898 bump: bump,
4899 bumpE: bumpE,
4900 bumpe: bumpe,
4901 Bumpeq: Bumpeq,
4902 bumpeq: bumpeq,
4903 Cacute: Cacute,
4904 cacute: cacute,
4905 capand: capand,
4906 capbrcup: capbrcup,
4907 capcap: capcap,
4908 cap: cap,
4909 Cap: Cap,
4910 capcup: capcup,
4911 capdot: capdot,
4912 CapitalDifferentialD: CapitalDifferentialD,
4913 caps: caps,
4914 caret: caret,
4915 caron: caron,
4916 Cayleys: Cayleys,
4917 ccaps: ccaps,
4918 Ccaron: Ccaron,
4919 ccaron: ccaron,
4920 Ccedil: Ccedil,
4921 ccedil: ccedil,
4922 Ccirc: Ccirc,
4923 ccirc: ccirc,
4924 Cconint: Cconint,
4925 ccups: ccups,
4926 ccupssm: ccupssm,
4927 Cdot: Cdot,
4928 cdot: cdot,
4929 cedil: cedil,
4930 Cedilla: Cedilla,
4931 cemptyv: cemptyv,
4932 cent: cent,
4933 centerdot: centerdot,
4934 CenterDot: CenterDot,
4935 cfr: cfr,
4936 Cfr: Cfr,
4937 CHcy: CHcy,
4938 chcy: chcy,
4939 check: check,
4940 checkmark: checkmark,
4941 Chi: Chi,
4942 chi: chi,
4943 circ: circ,
4944 circeq: circeq,
4945 circlearrowleft: circlearrowleft,
4946 circlearrowright: circlearrowright,
4947 circledast: circledast,
4948 circledcirc: circledcirc,
4949 circleddash: circleddash,
4950 CircleDot: CircleDot,
4951 circledR: circledR,
4952 circledS: circledS,
4953 CircleMinus: CircleMinus,
4954 CirclePlus: CirclePlus,
4955 CircleTimes: CircleTimes,
4956 cir: cir,
4957 cirE: cirE,
4958 cire: cire,
4959 cirfnint: cirfnint,
4960 cirmid: cirmid,
4961 cirscir: cirscir,
4962 ClockwiseContourIntegral: ClockwiseContourIntegral,
4963 CloseCurlyDoubleQuote: CloseCurlyDoubleQuote,
4964 CloseCurlyQuote: CloseCurlyQuote,
4965 clubs: clubs,
4966 clubsuit: clubsuit,
4967 colon: colon,
4968 Colon: Colon,
4969 Colone: Colone,
4970 colone: colone,
4971 coloneq: coloneq,
4972 comma: comma,
4973 commat: commat,
4974 comp: comp,
4975 compfn: compfn,
4976 complement: complement,
4977 complexes: complexes,
4978 cong: cong,
4979 congdot: congdot,
4980 Congruent: Congruent,
4981 conint: conint,
4982 Conint: Conint,
4983 ContourIntegral: ContourIntegral,
4984 copf: copf,
4985 Copf: Copf,
4986 coprod: coprod,
4987 Coproduct: Coproduct,
4988 copy: copy,
4989 COPY: COPY,
4990 copysr: copysr,
4991 CounterClockwiseContourIntegral: CounterClockwiseContourIntegral,
4992 crarr: crarr,
4993 cross: cross,
4994 Cross: Cross,
4995 Cscr: Cscr,
4996 cscr: cscr,
4997 csub: csub,
4998 csube: csube,
4999 csup: csup,
5000 csupe: csupe,
5001 ctdot: ctdot,
5002 cudarrl: cudarrl,
5003 cudarrr: cudarrr,
5004 cuepr: cuepr,
5005 cuesc: cuesc,
5006 cularr: cularr,
5007 cularrp: cularrp,
5008 cupbrcap: cupbrcap,
5009 cupcap: cupcap,
5010 CupCap: CupCap,
5011 cup: cup,
5012 Cup: Cup,
5013 cupcup: cupcup,
5014 cupdot: cupdot,
5015 cupor: cupor,
5016 cups: cups,
5017 curarr: curarr,
5018 curarrm: curarrm,
5019 curlyeqprec: curlyeqprec,
5020 curlyeqsucc: curlyeqsucc,
5021 curlyvee: curlyvee,
5022 curlywedge: curlywedge,
5023 curren: curren,
5024 curvearrowleft: curvearrowleft,
5025 curvearrowright: curvearrowright,
5026 cuvee: cuvee,
5027 cuwed: cuwed,
5028 cwconint: cwconint,
5029 cwint: cwint,
5030 cylcty: cylcty,
5031 dagger: dagger,
5032 Dagger: Dagger,
5033 daleth: daleth,
5034 darr: darr,
5035 Darr: Darr,
5036 dArr: dArr,
5037 dash: dash,
5038 Dashv: Dashv,
5039 dashv: dashv,
5040 dbkarow: dbkarow,
5041 dblac: dblac,
5042 Dcaron: Dcaron,
5043 dcaron: dcaron,
5044 Dcy: Dcy,
5045 dcy: dcy,
5046 ddagger: ddagger,
5047 ddarr: ddarr,
5048 DD: DD,
5049 dd: dd,
5050 DDotrahd: DDotrahd,
5051 ddotseq: ddotseq,
5052 deg: deg,
5053 Del: Del,
5054 Delta: Delta,
5055 delta: delta,
5056 demptyv: demptyv,
5057 dfisht: dfisht,
5058 Dfr: Dfr,
5059 dfr: dfr,
5060 dHar: dHar,
5061 dharl: dharl,
5062 dharr: dharr,
5063 DiacriticalAcute: DiacriticalAcute,
5064 DiacriticalDot: DiacriticalDot,
5065 DiacriticalDoubleAcute: DiacriticalDoubleAcute,
5066 DiacriticalGrave: DiacriticalGrave,
5067 DiacriticalTilde: DiacriticalTilde,
5068 diam: diam,
5069 diamond: diamond,
5070 Diamond: Diamond,
5071 diamondsuit: diamondsuit,
5072 diams: diams,
5073 die: die,
5074 DifferentialD: DifferentialD,
5075 digamma: digamma,
5076 disin: disin,
5077 div: div,
5078 divide: divide,
5079 divideontimes: divideontimes,
5080 divonx: divonx,
5081 DJcy: DJcy,
5082 djcy: djcy,
5083 dlcorn: dlcorn,
5084 dlcrop: dlcrop,
5085 dollar: dollar,
5086 Dopf: Dopf,
5087 dopf: dopf,
5088 Dot: Dot,
5089 dot: dot,
5090 DotDot: DotDot,
5091 doteq: doteq,
5092 doteqdot: doteqdot,
5093 DotEqual: DotEqual,
5094 dotminus: dotminus,
5095 dotplus: dotplus,
5096 dotsquare: dotsquare,
5097 doublebarwedge: doublebarwedge,
5098 DoubleContourIntegral: DoubleContourIntegral,
5099 DoubleDot: DoubleDot,
5100 DoubleDownArrow: DoubleDownArrow,
5101 DoubleLeftArrow: DoubleLeftArrow,
5102 DoubleLeftRightArrow: DoubleLeftRightArrow,
5103 DoubleLeftTee: DoubleLeftTee,
5104 DoubleLongLeftArrow: DoubleLongLeftArrow,
5105 DoubleLongLeftRightArrow: DoubleLongLeftRightArrow,
5106 DoubleLongRightArrow: DoubleLongRightArrow,
5107 DoubleRightArrow: DoubleRightArrow,
5108 DoubleRightTee: DoubleRightTee,
5109 DoubleUpArrow: DoubleUpArrow,
5110 DoubleUpDownArrow: DoubleUpDownArrow,
5111 DoubleVerticalBar: DoubleVerticalBar,
5112 DownArrowBar: DownArrowBar,
5113 downarrow: downarrow,
5114 DownArrow: DownArrow,
5115 Downarrow: Downarrow,
5116 DownArrowUpArrow: DownArrowUpArrow,
5117 DownBreve: DownBreve,
5118 downdownarrows: downdownarrows,
5119 downharpoonleft: downharpoonleft,
5120 downharpoonright: downharpoonright,
5121 DownLeftRightVector: DownLeftRightVector,
5122 DownLeftTeeVector: DownLeftTeeVector,
5123 DownLeftVectorBar: DownLeftVectorBar,
5124 DownLeftVector: DownLeftVector,
5125 DownRightTeeVector: DownRightTeeVector,
5126 DownRightVectorBar: DownRightVectorBar,
5127 DownRightVector: DownRightVector,
5128 DownTeeArrow: DownTeeArrow,
5129 DownTee: DownTee,
5130 drbkarow: drbkarow,
5131 drcorn: drcorn,
5132 drcrop: drcrop,
5133 Dscr: Dscr,
5134 dscr: dscr,
5135 DScy: DScy,
5136 dscy: dscy,
5137 dsol: dsol,
5138 Dstrok: Dstrok,
5139 dstrok: dstrok,
5140 dtdot: dtdot,
5141 dtri: dtri,
5142 dtrif: dtrif,
5143 duarr: duarr,
5144 duhar: duhar,
5145 dwangle: dwangle,
5146 DZcy: DZcy,
5147 dzcy: dzcy,
5148 dzigrarr: dzigrarr,
5149 Eacute: Eacute,
5150 eacute: eacute,
5151 easter: easter,
5152 Ecaron: Ecaron,
5153 ecaron: ecaron,
5154 Ecirc: Ecirc,
5155 ecirc: ecirc,
5156 ecir: ecir,
5157 ecolon: ecolon,
5158 Ecy: Ecy,
5159 ecy: ecy,
5160 eDDot: eDDot,
5161 Edot: Edot,
5162 edot: edot,
5163 eDot: eDot,
5164 ee: ee,
5165 efDot: efDot,
5166 Efr: Efr,
5167 efr: efr,
5168 eg: eg,
5169 Egrave: Egrave,
5170 egrave: egrave,
5171 egs: egs,
5172 egsdot: egsdot,
5173 el: el,
5174 Element: Element,
5175 elinters: elinters,
5176 ell: ell,
5177 els: els,
5178 elsdot: elsdot,
5179 Emacr: Emacr,
5180 emacr: emacr,
5181 empty: empty,
5182 emptyset: emptyset,
5183 EmptySmallSquare: EmptySmallSquare,
5184 emptyv: emptyv,
5185 EmptyVerySmallSquare: EmptyVerySmallSquare,
5186 emsp13: emsp13,
5187 emsp14: emsp14,
5188 emsp: emsp,
5189 ENG: ENG,
5190 eng: eng,
5191 ensp: ensp,
5192 Eogon: Eogon,
5193 eogon: eogon,
5194 Eopf: Eopf,
5195 eopf: eopf,
5196 epar: epar,
5197 eparsl: eparsl,
5198 eplus: eplus,
5199 epsi: epsi,
5200 Epsilon: Epsilon,
5201 epsilon: epsilon,
5202 epsiv: epsiv,
5203 eqcirc: eqcirc,
5204 eqcolon: eqcolon,
5205 eqsim: eqsim,
5206 eqslantgtr: eqslantgtr,
5207 eqslantless: eqslantless,
5208 Equal: Equal,
5209 equals: equals,
5210 EqualTilde: EqualTilde,
5211 equest: equest,
5212 Equilibrium: Equilibrium,
5213 equiv: equiv,
5214 equivDD: equivDD,
5215 eqvparsl: eqvparsl,
5216 erarr: erarr,
5217 erDot: erDot,
5218 escr: escr,
5219 Escr: Escr,
5220 esdot: esdot,
5221 Esim: Esim,
5222 esim: esim,
5223 Eta: Eta,
5224 eta: eta,
5225 ETH: ETH,
5226 eth: eth,
5227 Euml: Euml,
5228 euml: euml,
5229 euro: euro,
5230 excl: excl,
5231 exist: exist,
5232 Exists: Exists,
5233 expectation: expectation,
5234 exponentiale: exponentiale,
5235 ExponentialE: ExponentialE,
5236 fallingdotseq: fallingdotseq,
5237 Fcy: Fcy,
5238 fcy: fcy,
5239 female: female,
5240 ffilig: ffilig,
5241 fflig: fflig,
5242 ffllig: ffllig,
5243 Ffr: Ffr,
5244 ffr: ffr,
5245 filig: filig,
5246 FilledSmallSquare: FilledSmallSquare,
5247 FilledVerySmallSquare: FilledVerySmallSquare,
5248 fjlig: fjlig,
5249 flat: flat,
5250 fllig: fllig,
5251 fltns: fltns,
5252 fnof: fnof,
5253 Fopf: Fopf,
5254 fopf: fopf,
5255 forall: forall,
5256 ForAll: ForAll,
5257 fork: fork,
5258 forkv: forkv,
5259 Fouriertrf: Fouriertrf,
5260 fpartint: fpartint,
5261 frac12: frac12,
5262 frac13: frac13,
5263 frac14: frac14,
5264 frac15: frac15,
5265 frac16: frac16,
5266 frac18: frac18,
5267 frac23: frac23,
5268 frac25: frac25,
5269 frac34: frac34,
5270 frac35: frac35,
5271 frac38: frac38,
5272 frac45: frac45,
5273 frac56: frac56,
5274 frac58: frac58,
5275 frac78: frac78,
5276 frasl: frasl,
5277 frown: frown,
5278 fscr: fscr,
5279 Fscr: Fscr,
5280 gacute: gacute,
5281 Gamma: Gamma,
5282 gamma: gamma,
5283 Gammad: Gammad,
5284 gammad: gammad,
5285 gap: gap,
5286 Gbreve: Gbreve,
5287 gbreve: gbreve,
5288 Gcedil: Gcedil,
5289 Gcirc: Gcirc,
5290 gcirc: gcirc,
5291 Gcy: Gcy,
5292 gcy: gcy,
5293 Gdot: Gdot,
5294 gdot: gdot,
5295 ge: ge,
5296 gE: gE,
5297 gEl: gEl,
5298 gel: gel,
5299 geq: geq,
5300 geqq: geqq,
5301 geqslant: geqslant,
5302 gescc: gescc,
5303 ges: ges,
5304 gesdot: gesdot,
5305 gesdoto: gesdoto,
5306 gesdotol: gesdotol,
5307 gesl: gesl,
5308 gesles: gesles,
5309 Gfr: Gfr,
5310 gfr: gfr,
5311 gg: gg,
5312 Gg: Gg,
5313 ggg: ggg,
5314 gimel: gimel,
5315 GJcy: GJcy,
5316 gjcy: gjcy,
5317 gla: gla,
5318 gl: gl,
5319 glE: glE,
5320 glj: glj,
5321 gnap: gnap,
5322 gnapprox: gnapprox,
5323 gne: gne,
5324 gnE: gnE,
5325 gneq: gneq,
5326 gneqq: gneqq,
5327 gnsim: gnsim,
5328 Gopf: Gopf,
5329 gopf: gopf,
5330 grave: grave,
5331 GreaterEqual: GreaterEqual,
5332 GreaterEqualLess: GreaterEqualLess,
5333 GreaterFullEqual: GreaterFullEqual,
5334 GreaterGreater: GreaterGreater,
5335 GreaterLess: GreaterLess,
5336 GreaterSlantEqual: GreaterSlantEqual,
5337 GreaterTilde: GreaterTilde,
5338 Gscr: Gscr,
5339 gscr: gscr,
5340 gsim: gsim,
5341 gsime: gsime,
5342 gsiml: gsiml,
5343 gtcc: gtcc,
5344 gtcir: gtcir,
5345 gt: gt,
5346 GT: GT,
5347 Gt: Gt,
5348 gtdot: gtdot,
5349 gtlPar: gtlPar,
5350 gtquest: gtquest,
5351 gtrapprox: gtrapprox,
5352 gtrarr: gtrarr,
5353 gtrdot: gtrdot,
5354 gtreqless: gtreqless,
5355 gtreqqless: gtreqqless,
5356 gtrless: gtrless,
5357 gtrsim: gtrsim,
5358 gvertneqq: gvertneqq,
5359 gvnE: gvnE,
5360 Hacek: Hacek,
5361 hairsp: hairsp,
5362 half: half,
5363 hamilt: hamilt,
5364 HARDcy: HARDcy,
5365 hardcy: hardcy,
5366 harrcir: harrcir,
5367 harr: harr,
5368 hArr: hArr,
5369 harrw: harrw,
5370 Hat: Hat,
5371 hbar: hbar,
5372 Hcirc: Hcirc,
5373 hcirc: hcirc,
5374 hearts: hearts,
5375 heartsuit: heartsuit,
5376 hellip: hellip,
5377 hercon: hercon,
5378 hfr: hfr,
5379 Hfr: Hfr,
5380 HilbertSpace: HilbertSpace,
5381 hksearow: hksearow,
5382 hkswarow: hkswarow,
5383 hoarr: hoarr,
5384 homtht: homtht,
5385 hookleftarrow: hookleftarrow,
5386 hookrightarrow: hookrightarrow,
5387 hopf: hopf,
5388 Hopf: Hopf,
5389 horbar: horbar,
5390 HorizontalLine: HorizontalLine,
5391 hscr: hscr,
5392 Hscr: Hscr,
5393 hslash: hslash,
5394 Hstrok: Hstrok,
5395 hstrok: hstrok,
5396 HumpDownHump: HumpDownHump,
5397 HumpEqual: HumpEqual,
5398 hybull: hybull,
5399 hyphen: hyphen,
5400 Iacute: Iacute,
5401 iacute: iacute,
5402 ic: ic,
5403 Icirc: Icirc,
5404 icirc: icirc,
5405 Icy: Icy,
5406 icy: icy,
5407 Idot: Idot,
5408 IEcy: IEcy,
5409 iecy: iecy,
5410 iexcl: iexcl,
5411 iff: iff,
5412 ifr: ifr,
5413 Ifr: Ifr,
5414 Igrave: Igrave,
5415 igrave: igrave,
5416 ii: ii,
5417 iiiint: iiiint,
5418 iiint: iiint,
5419 iinfin: iinfin,
5420 iiota: iiota,
5421 IJlig: IJlig,
5422 ijlig: ijlig,
5423 Imacr: Imacr,
5424 imacr: imacr,
5425 image: image,
5426 ImaginaryI: ImaginaryI,
5427 imagline: imagline,
5428 imagpart: imagpart,
5429 imath: imath,
5430 Im: Im,
5431 imof: imof,
5432 imped: imped,
5433 Implies: Implies,
5434 incare: incare,
5435 infin: infin,
5436 infintie: infintie,
5437 inodot: inodot,
5438 intcal: intcal,
5439 int: int,
5440 Int: Int,
5441 integers: integers,
5442 Integral: Integral,
5443 intercal: intercal,
5444 Intersection: Intersection,
5445 intlarhk: intlarhk,
5446 intprod: intprod,
5447 InvisibleComma: InvisibleComma,
5448 InvisibleTimes: InvisibleTimes,
5449 IOcy: IOcy,
5450 iocy: iocy,
5451 Iogon: Iogon,
5452 iogon: iogon,
5453 Iopf: Iopf,
5454 iopf: iopf,
5455 Iota: Iota,
5456 iota: iota,
5457 iprod: iprod,
5458 iquest: iquest,
5459 iscr: iscr,
5460 Iscr: Iscr,
5461 isin: isin,
5462 isindot: isindot,
5463 isinE: isinE,
5464 isins: isins,
5465 isinsv: isinsv,
5466 isinv: isinv,
5467 it: it,
5468 Itilde: Itilde,
5469 itilde: itilde,
5470 Iukcy: Iukcy,
5471 iukcy: iukcy,
5472 Iuml: Iuml,
5473 iuml: iuml,
5474 Jcirc: Jcirc,
5475 jcirc: jcirc,
5476 Jcy: Jcy,
5477 jcy: jcy,
5478 Jfr: Jfr,
5479 jfr: jfr,
5480 jmath: jmath,
5481 Jopf: Jopf,
5482 jopf: jopf,
5483 Jscr: Jscr,
5484 jscr: jscr,
5485 Jsercy: Jsercy,
5486 jsercy: jsercy,
5487 Jukcy: Jukcy,
5488 jukcy: jukcy,
5489 Kappa: Kappa,
5490 kappa: kappa,
5491 kappav: kappav,
5492 Kcedil: Kcedil,
5493 kcedil: kcedil,
5494 Kcy: Kcy,
5495 kcy: kcy,
5496 Kfr: Kfr,
5497 kfr: kfr,
5498 kgreen: kgreen,
5499 KHcy: KHcy,
5500 khcy: khcy,
5501 KJcy: KJcy,
5502 kjcy: kjcy,
5503 Kopf: Kopf,
5504 kopf: kopf,
5505 Kscr: Kscr,
5506 kscr: kscr,
5507 lAarr: lAarr,
5508 Lacute: Lacute,
5509 lacute: lacute,
5510 laemptyv: laemptyv,
5511 lagran: lagran,
5512 Lambda: Lambda,
5513 lambda: lambda,
5514 lang: lang,
5515 Lang: Lang,
5516 langd: langd,
5517 langle: langle,
5518 lap: lap,
5519 Laplacetrf: Laplacetrf,
5520 laquo: laquo,
5521 larrb: larrb,
5522 larrbfs: larrbfs,
5523 larr: larr,
5524 Larr: Larr,
5525 lArr: lArr,
5526 larrfs: larrfs,
5527 larrhk: larrhk,
5528 larrlp: larrlp,
5529 larrpl: larrpl,
5530 larrsim: larrsim,
5531 larrtl: larrtl,
5532 latail: latail,
5533 lAtail: lAtail,
5534 lat: lat,
5535 late: late,
5536 lates: lates,
5537 lbarr: lbarr,
5538 lBarr: lBarr,
5539 lbbrk: lbbrk,
5540 lbrace: lbrace,
5541 lbrack: lbrack,
5542 lbrke: lbrke,
5543 lbrksld: lbrksld,
5544 lbrkslu: lbrkslu,
5545 Lcaron: Lcaron,
5546 lcaron: lcaron,
5547 Lcedil: Lcedil,
5548 lcedil: lcedil,
5549 lceil: lceil,
5550 lcub: lcub,
5551 Lcy: Lcy,
5552 lcy: lcy,
5553 ldca: ldca,
5554 ldquo: ldquo,
5555 ldquor: ldquor,
5556 ldrdhar: ldrdhar,
5557 ldrushar: ldrushar,
5558 ldsh: ldsh,
5559 le: le,
5560 lE: lE,
5561 LeftAngleBracket: LeftAngleBracket,
5562 LeftArrowBar: LeftArrowBar,
5563 leftarrow: leftarrow,
5564 LeftArrow: LeftArrow,
5565 Leftarrow: Leftarrow,
5566 LeftArrowRightArrow: LeftArrowRightArrow,
5567 leftarrowtail: leftarrowtail,
5568 LeftCeiling: LeftCeiling,
5569 LeftDoubleBracket: LeftDoubleBracket,
5570 LeftDownTeeVector: LeftDownTeeVector,
5571 LeftDownVectorBar: LeftDownVectorBar,
5572 LeftDownVector: LeftDownVector,
5573 LeftFloor: LeftFloor,
5574 leftharpoondown: leftharpoondown,
5575 leftharpoonup: leftharpoonup,
5576 leftleftarrows: leftleftarrows,
5577 leftrightarrow: leftrightarrow,
5578 LeftRightArrow: LeftRightArrow,
5579 Leftrightarrow: Leftrightarrow,
5580 leftrightarrows: leftrightarrows,
5581 leftrightharpoons: leftrightharpoons,
5582 leftrightsquigarrow: leftrightsquigarrow,
5583 LeftRightVector: LeftRightVector,
5584 LeftTeeArrow: LeftTeeArrow,
5585 LeftTee: LeftTee,
5586 LeftTeeVector: LeftTeeVector,
5587 leftthreetimes: leftthreetimes,
5588 LeftTriangleBar: LeftTriangleBar,
5589 LeftTriangle: LeftTriangle,
5590 LeftTriangleEqual: LeftTriangleEqual,
5591 LeftUpDownVector: LeftUpDownVector,
5592 LeftUpTeeVector: LeftUpTeeVector,
5593 LeftUpVectorBar: LeftUpVectorBar,
5594 LeftUpVector: LeftUpVector,
5595 LeftVectorBar: LeftVectorBar,
5596 LeftVector: LeftVector,
5597 lEg: lEg,
5598 leg: leg,
5599 leq: leq,
5600 leqq: leqq,
5601 leqslant: leqslant,
5602 lescc: lescc,
5603 les: les,
5604 lesdot: lesdot,
5605 lesdoto: lesdoto,
5606 lesdotor: lesdotor,
5607 lesg: lesg,
5608 lesges: lesges,
5609 lessapprox: lessapprox,
5610 lessdot: lessdot,
5611 lesseqgtr: lesseqgtr,
5612 lesseqqgtr: lesseqqgtr,
5613 LessEqualGreater: LessEqualGreater,
5614 LessFullEqual: LessFullEqual,
5615 LessGreater: LessGreater,
5616 lessgtr: lessgtr,
5617 LessLess: LessLess,
5618 lesssim: lesssim,
5619 LessSlantEqual: LessSlantEqual,
5620 LessTilde: LessTilde,
5621 lfisht: lfisht,
5622 lfloor: lfloor,
5623 Lfr: Lfr,
5624 lfr: lfr,
5625 lg: lg,
5626 lgE: lgE,
5627 lHar: lHar,
5628 lhard: lhard,
5629 lharu: lharu,
5630 lharul: lharul,
5631 lhblk: lhblk,
5632 LJcy: LJcy,
5633 ljcy: ljcy,
5634 llarr: llarr,
5635 ll: ll,
5636 Ll: Ll,
5637 llcorner: llcorner,
5638 Lleftarrow: Lleftarrow,
5639 llhard: llhard,
5640 lltri: lltri,
5641 Lmidot: Lmidot,
5642 lmidot: lmidot,
5643 lmoustache: lmoustache,
5644 lmoust: lmoust,
5645 lnap: lnap,
5646 lnapprox: lnapprox,
5647 lne: lne,
5648 lnE: lnE,
5649 lneq: lneq,
5650 lneqq: lneqq,
5651 lnsim: lnsim,
5652 loang: loang,
5653 loarr: loarr,
5654 lobrk: lobrk,
5655 longleftarrow: longleftarrow,
5656 LongLeftArrow: LongLeftArrow,
5657 Longleftarrow: Longleftarrow,
5658 longleftrightarrow: longleftrightarrow,
5659 LongLeftRightArrow: LongLeftRightArrow,
5660 Longleftrightarrow: Longleftrightarrow,
5661 longmapsto: longmapsto,
5662 longrightarrow: longrightarrow,
5663 LongRightArrow: LongRightArrow,
5664 Longrightarrow: Longrightarrow,
5665 looparrowleft: looparrowleft,
5666 looparrowright: looparrowright,
5667 lopar: lopar,
5668 Lopf: Lopf,
5669 lopf: lopf,
5670 loplus: loplus,
5671 lotimes: lotimes,
5672 lowast: lowast,
5673 lowbar: lowbar,
5674 LowerLeftArrow: LowerLeftArrow,
5675 LowerRightArrow: LowerRightArrow,
5676 loz: loz,
5677 lozenge: lozenge,
5678 lozf: lozf,
5679 lpar: lpar,
5680 lparlt: lparlt,
5681 lrarr: lrarr,
5682 lrcorner: lrcorner,
5683 lrhar: lrhar,
5684 lrhard: lrhard,
5685 lrm: lrm,
5686 lrtri: lrtri,
5687 lsaquo: lsaquo,
5688 lscr: lscr,
5689 Lscr: Lscr,
5690 lsh: lsh,
5691 Lsh: Lsh,
5692 lsim: lsim,
5693 lsime: lsime,
5694 lsimg: lsimg,
5695 lsqb: lsqb,
5696 lsquo: lsquo,
5697 lsquor: lsquor,
5698 Lstrok: Lstrok,
5699 lstrok: lstrok,
5700 ltcc: ltcc,
5701 ltcir: ltcir,
5702 lt: lt,
5703 LT: LT,
5704 Lt: Lt,
5705 ltdot: ltdot,
5706 lthree: lthree,
5707 ltimes: ltimes,
5708 ltlarr: ltlarr,
5709 ltquest: ltquest,
5710 ltri: ltri,
5711 ltrie: ltrie,
5712 ltrif: ltrif,
5713 ltrPar: ltrPar,
5714 lurdshar: lurdshar,
5715 luruhar: luruhar,
5716 lvertneqq: lvertneqq,
5717 lvnE: lvnE,
5718 macr: macr,
5719 male: male,
5720 malt: malt,
5721 maltese: maltese,
5722 map: map,
5723 mapsto: mapsto,
5724 mapstodown: mapstodown,
5725 mapstoleft: mapstoleft,
5726 mapstoup: mapstoup,
5727 marker: marker,
5728 mcomma: mcomma,
5729 Mcy: Mcy,
5730 mcy: mcy,
5731 mdash: mdash,
5732 mDDot: mDDot,
5733 measuredangle: measuredangle,
5734 MediumSpace: MediumSpace,
5735 Mellintrf: Mellintrf,
5736 Mfr: Mfr,
5737 mfr: mfr,
5738 mho: mho,
5739 micro: micro,
5740 midast: midast,
5741 midcir: midcir,
5742 mid: mid,
5743 middot: middot,
5744 minusb: minusb,
5745 minus: minus,
5746 minusd: minusd,
5747 minusdu: minusdu,
5748 MinusPlus: MinusPlus,
5749 mlcp: mlcp,
5750 mldr: mldr,
5751 mnplus: mnplus,
5752 models: models,
5753 Mopf: Mopf,
5754 mopf: mopf,
5755 mp: mp,
5756 mscr: mscr,
5757 Mscr: Mscr,
5758 mstpos: mstpos,
5759 Mu: Mu,
5760 mu: mu,
5761 multimap: multimap,
5762 mumap: mumap,
5763 nabla: nabla,
5764 Nacute: Nacute,
5765 nacute: nacute,
5766 nang: nang,
5767 nap: nap,
5768 napE: napE,
5769 napid: napid,
5770 napos: napos,
5771 napprox: napprox,
5772 natural: natural,
5773 naturals: naturals,
5774 natur: natur,
5775 nbsp: nbsp,
5776 nbump: nbump,
5777 nbumpe: nbumpe,
5778 ncap: ncap,
5779 Ncaron: Ncaron,
5780 ncaron: ncaron,
5781 Ncedil: Ncedil,
5782 ncedil: ncedil,
5783 ncong: ncong,
5784 ncongdot: ncongdot,
5785 ncup: ncup,
5786 Ncy: Ncy,
5787 ncy: ncy,
5788 ndash: ndash,
5789 nearhk: nearhk,
5790 nearr: nearr,
5791 neArr: neArr,
5792 nearrow: nearrow,
5793 ne: ne,
5794 nedot: nedot,
5795 NegativeMediumSpace: NegativeMediumSpace,
5796 NegativeThickSpace: NegativeThickSpace,
5797 NegativeThinSpace: NegativeThinSpace,
5798 NegativeVeryThinSpace: NegativeVeryThinSpace,
5799 nequiv: nequiv,
5800 nesear: nesear,
5801 nesim: nesim,
5802 NestedGreaterGreater: NestedGreaterGreater,
5803 NestedLessLess: NestedLessLess,
5804 NewLine: NewLine,
5805 nexist: nexist,
5806 nexists: nexists,
5807 Nfr: Nfr,
5808 nfr: nfr,
5809 ngE: ngE,
5810 nge: nge,
5811 ngeq: ngeq,
5812 ngeqq: ngeqq,
5813 ngeqslant: ngeqslant,
5814 nges: nges,
5815 nGg: nGg,
5816 ngsim: ngsim,
5817 nGt: nGt,
5818 ngt: ngt,
5819 ngtr: ngtr,
5820 nGtv: nGtv,
5821 nharr: nharr,
5822 nhArr: nhArr,
5823 nhpar: nhpar,
5824 ni: ni,
5825 nis: nis,
5826 nisd: nisd,
5827 niv: niv,
5828 NJcy: NJcy,
5829 njcy: njcy,
5830 nlarr: nlarr,
5831 nlArr: nlArr,
5832 nldr: nldr,
5833 nlE: nlE,
5834 nle: nle,
5835 nleftarrow: nleftarrow,
5836 nLeftarrow: nLeftarrow,
5837 nleftrightarrow: nleftrightarrow,
5838 nLeftrightarrow: nLeftrightarrow,
5839 nleq: nleq,
5840 nleqq: nleqq,
5841 nleqslant: nleqslant,
5842 nles: nles,
5843 nless: nless,
5844 nLl: nLl,
5845 nlsim: nlsim,
5846 nLt: nLt,
5847 nlt: nlt,
5848 nltri: nltri,
5849 nltrie: nltrie,
5850 nLtv: nLtv,
5851 nmid: nmid,
5852 NoBreak: NoBreak,
5853 NonBreakingSpace: NonBreakingSpace,
5854 nopf: nopf,
5855 Nopf: Nopf,
5856 Not: Not,
5857 not: not,
5858 NotCongruent: NotCongruent,
5859 NotCupCap: NotCupCap,
5860 NotDoubleVerticalBar: NotDoubleVerticalBar,
5861 NotElement: NotElement,
5862 NotEqual: NotEqual,
5863 NotEqualTilde: NotEqualTilde,
5864 NotExists: NotExists,
5865 NotGreater: NotGreater,
5866 NotGreaterEqual: NotGreaterEqual,
5867 NotGreaterFullEqual: NotGreaterFullEqual,
5868 NotGreaterGreater: NotGreaterGreater,
5869 NotGreaterLess: NotGreaterLess,
5870 NotGreaterSlantEqual: NotGreaterSlantEqual,
5871 NotGreaterTilde: NotGreaterTilde,
5872 NotHumpDownHump: NotHumpDownHump,
5873 NotHumpEqual: NotHumpEqual,
5874 notin: notin,
5875 notindot: notindot,
5876 notinE: notinE,
5877 notinva: notinva,
5878 notinvb: notinvb,
5879 notinvc: notinvc,
5880 NotLeftTriangleBar: NotLeftTriangleBar,
5881 NotLeftTriangle: NotLeftTriangle,
5882 NotLeftTriangleEqual: NotLeftTriangleEqual,
5883 NotLess: NotLess,
5884 NotLessEqual: NotLessEqual,
5885 NotLessGreater: NotLessGreater,
5886 NotLessLess: NotLessLess,
5887 NotLessSlantEqual: NotLessSlantEqual,
5888 NotLessTilde: NotLessTilde,
5889 NotNestedGreaterGreater: NotNestedGreaterGreater,
5890 NotNestedLessLess: NotNestedLessLess,
5891 notni: notni,
5892 notniva: notniva,
5893 notnivb: notnivb,
5894 notnivc: notnivc,
5895 NotPrecedes: NotPrecedes,
5896 NotPrecedesEqual: NotPrecedesEqual,
5897 NotPrecedesSlantEqual: NotPrecedesSlantEqual,
5898 NotReverseElement: NotReverseElement,
5899 NotRightTriangleBar: NotRightTriangleBar,
5900 NotRightTriangle: NotRightTriangle,
5901 NotRightTriangleEqual: NotRightTriangleEqual,
5902 NotSquareSubset: NotSquareSubset,
5903 NotSquareSubsetEqual: NotSquareSubsetEqual,
5904 NotSquareSuperset: NotSquareSuperset,
5905 NotSquareSupersetEqual: NotSquareSupersetEqual,
5906 NotSubset: NotSubset,
5907 NotSubsetEqual: NotSubsetEqual,
5908 NotSucceeds: NotSucceeds,
5909 NotSucceedsEqual: NotSucceedsEqual,
5910 NotSucceedsSlantEqual: NotSucceedsSlantEqual,
5911 NotSucceedsTilde: NotSucceedsTilde,
5912 NotSuperset: NotSuperset,
5913 NotSupersetEqual: NotSupersetEqual,
5914 NotTilde: NotTilde,
5915 NotTildeEqual: NotTildeEqual,
5916 NotTildeFullEqual: NotTildeFullEqual,
5917 NotTildeTilde: NotTildeTilde,
5918 NotVerticalBar: NotVerticalBar,
5919 nparallel: nparallel,
5920 npar: npar,
5921 nparsl: nparsl,
5922 npart: npart,
5923 npolint: npolint,
5924 npr: npr,
5925 nprcue: nprcue,
5926 nprec: nprec,
5927 npreceq: npreceq,
5928 npre: npre,
5929 nrarrc: nrarrc,
5930 nrarr: nrarr,
5931 nrArr: nrArr,
5932 nrarrw: nrarrw,
5933 nrightarrow: nrightarrow,
5934 nRightarrow: nRightarrow,
5935 nrtri: nrtri,
5936 nrtrie: nrtrie,
5937 nsc: nsc,
5938 nsccue: nsccue,
5939 nsce: nsce,
5940 Nscr: Nscr,
5941 nscr: nscr,
5942 nshortmid: nshortmid,
5943 nshortparallel: nshortparallel,
5944 nsim: nsim,
5945 nsime: nsime,
5946 nsimeq: nsimeq,
5947 nsmid: nsmid,
5948 nspar: nspar,
5949 nsqsube: nsqsube,
5950 nsqsupe: nsqsupe,
5951 nsub: nsub,
5952 nsubE: nsubE,
5953 nsube: nsube,
5954 nsubset: nsubset,
5955 nsubseteq: nsubseteq,
5956 nsubseteqq: nsubseteqq,
5957 nsucc: nsucc,
5958 nsucceq: nsucceq,
5959 nsup: nsup,
5960 nsupE: nsupE,
5961 nsupe: nsupe,
5962 nsupset: nsupset,
5963 nsupseteq: nsupseteq,
5964 nsupseteqq: nsupseteqq,
5965 ntgl: ntgl,
5966 Ntilde: Ntilde,
5967 ntilde: ntilde,
5968 ntlg: ntlg,
5969 ntriangleleft: ntriangleleft,
5970 ntrianglelefteq: ntrianglelefteq,
5971 ntriangleright: ntriangleright,
5972 ntrianglerighteq: ntrianglerighteq,
5973 Nu: Nu,
5974 nu: nu,
5975 num: num,
5976 numero: numero,
5977 numsp: numsp,
5978 nvap: nvap,
5979 nvdash: nvdash,
5980 nvDash: nvDash,
5981 nVdash: nVdash,
5982 nVDash: nVDash,
5983 nvge: nvge,
5984 nvgt: nvgt,
5985 nvHarr: nvHarr,
5986 nvinfin: nvinfin,
5987 nvlArr: nvlArr,
5988 nvle: nvle,
5989 nvlt: nvlt,
5990 nvltrie: nvltrie,
5991 nvrArr: nvrArr,
5992 nvrtrie: nvrtrie,
5993 nvsim: nvsim,
5994 nwarhk: nwarhk,
5995 nwarr: nwarr,
5996 nwArr: nwArr,
5997 nwarrow: nwarrow,
5998 nwnear: nwnear,
5999 Oacute: Oacute,
6000 oacute: oacute,
6001 oast: oast,
6002 Ocirc: Ocirc,
6003 ocirc: ocirc,
6004 ocir: ocir,
6005 Ocy: Ocy,
6006 ocy: ocy,
6007 odash: odash,
6008 Odblac: Odblac,
6009 odblac: odblac,
6010 odiv: odiv,
6011 odot: odot,
6012 odsold: odsold,
6013 OElig: OElig,
6014 oelig: oelig,
6015 ofcir: ofcir,
6016 Ofr: Ofr,
6017 ofr: ofr,
6018 ogon: ogon,
6019 Ograve: Ograve,
6020 ograve: ograve,
6021 ogt: ogt,
6022 ohbar: ohbar,
6023 ohm: ohm,
6024 oint: oint,
6025 olarr: olarr,
6026 olcir: olcir,
6027 olcross: olcross,
6028 oline: oline,
6029 olt: olt,
6030 Omacr: Omacr,
6031 omacr: omacr,
6032 Omega: Omega,
6033 omega: omega,
6034 Omicron: Omicron,
6035 omicron: omicron,
6036 omid: omid,
6037 ominus: ominus,
6038 Oopf: Oopf,
6039 oopf: oopf,
6040 opar: opar,
6041 OpenCurlyDoubleQuote: OpenCurlyDoubleQuote,
6042 OpenCurlyQuote: OpenCurlyQuote,
6043 operp: operp,
6044 oplus: oplus,
6045 orarr: orarr,
6046 Or: Or,
6047 or: or,
6048 ord: ord,
6049 order: order,
6050 orderof: orderof,
6051 ordf: ordf,
6052 ordm: ordm,
6053 origof: origof,
6054 oror: oror,
6055 orslope: orslope,
6056 orv: orv,
6057 oS: oS,
6058 Oscr: Oscr,
6059 oscr: oscr,
6060 Oslash: Oslash,
6061 oslash: oslash,
6062 osol: osol,
6063 Otilde: Otilde,
6064 otilde: otilde,
6065 otimesas: otimesas,
6066 Otimes: Otimes,
6067 otimes: otimes,
6068 Ouml: Ouml,
6069 ouml: ouml,
6070 ovbar: ovbar,
6071 OverBar: OverBar,
6072 OverBrace: OverBrace,
6073 OverBracket: OverBracket,
6074 OverParenthesis: OverParenthesis,
6075 para: para,
6076 parallel: parallel,
6077 par: par,
6078 parsim: parsim,
6079 parsl: parsl,
6080 part: part,
6081 PartialD: PartialD,
6082 Pcy: Pcy,
6083 pcy: pcy,
6084 percnt: percnt,
6085 period: period,
6086 permil: permil,
6087 perp: perp,
6088 pertenk: pertenk,
6089 Pfr: Pfr,
6090 pfr: pfr,
6091 Phi: Phi,
6092 phi: phi,
6093 phiv: phiv,
6094 phmmat: phmmat,
6095 phone: phone,
6096 Pi: Pi,
6097 pi: pi,
6098 pitchfork: pitchfork,
6099 piv: piv,
6100 planck: planck,
6101 planckh: planckh,
6102 plankv: plankv,
6103 plusacir: plusacir,
6104 plusb: plusb,
6105 pluscir: pluscir,
6106 plus: plus,
6107 plusdo: plusdo,
6108 plusdu: plusdu,
6109 pluse: pluse,
6110 PlusMinus: PlusMinus,
6111 plusmn: plusmn,
6112 plussim: plussim,
6113 plustwo: plustwo,
6114 pm: pm,
6115 Poincareplane: Poincareplane,
6116 pointint: pointint,
6117 popf: popf,
6118 Popf: Popf,
6119 pound: pound,
6120 prap: prap,
6121 Pr: Pr,
6122 pr: pr,
6123 prcue: prcue,
6124 precapprox: precapprox,
6125 prec: prec,
6126 preccurlyeq: preccurlyeq,
6127 Precedes: Precedes,
6128 PrecedesEqual: PrecedesEqual,
6129 PrecedesSlantEqual: PrecedesSlantEqual,
6130 PrecedesTilde: PrecedesTilde,
6131 preceq: preceq,
6132 precnapprox: precnapprox,
6133 precneqq: precneqq,
6134 precnsim: precnsim,
6135 pre: pre,
6136 prE: prE,
6137 precsim: precsim,
6138 prime: prime,
6139 Prime: Prime,
6140 primes: primes,
6141 prnap: prnap,
6142 prnE: prnE,
6143 prnsim: prnsim,
6144 prod: prod,
6145 Product: Product,
6146 profalar: profalar,
6147 profline: profline,
6148 profsurf: profsurf,
6149 prop: prop,
6150 Proportional: Proportional,
6151 Proportion: Proportion,
6152 propto: propto,
6153 prsim: prsim,
6154 prurel: prurel,
6155 Pscr: Pscr,
6156 pscr: pscr,
6157 Psi: Psi,
6158 psi: psi,
6159 puncsp: puncsp,
6160 Qfr: Qfr,
6161 qfr: qfr,
6162 qint: qint,
6163 qopf: qopf,
6164 Qopf: Qopf,
6165 qprime: qprime,
6166 Qscr: Qscr,
6167 qscr: qscr,
6168 quaternions: quaternions,
6169 quatint: quatint,
6170 quest: quest,
6171 questeq: questeq,
6172 quot: quot,
6173 QUOT: QUOT,
6174 rAarr: rAarr,
6175 race: race,
6176 Racute: Racute,
6177 racute: racute,
6178 radic: radic,
6179 raemptyv: raemptyv,
6180 rang: rang,
6181 Rang: Rang,
6182 rangd: rangd,
6183 range: range,
6184 rangle: rangle,
6185 raquo: raquo,
6186 rarrap: rarrap,
6187 rarrb: rarrb,
6188 rarrbfs: rarrbfs,
6189 rarrc: rarrc,
6190 rarr: rarr,
6191 Rarr: Rarr,
6192 rArr: rArr,
6193 rarrfs: rarrfs,
6194 rarrhk: rarrhk,
6195 rarrlp: rarrlp,
6196 rarrpl: rarrpl,
6197 rarrsim: rarrsim,
6198 Rarrtl: Rarrtl,
6199 rarrtl: rarrtl,
6200 rarrw: rarrw,
6201 ratail: ratail,
6202 rAtail: rAtail,
6203 ratio: ratio,
6204 rationals: rationals,
6205 rbarr: rbarr,
6206 rBarr: rBarr,
6207 RBarr: RBarr,
6208 rbbrk: rbbrk,
6209 rbrace: rbrace,
6210 rbrack: rbrack,
6211 rbrke: rbrke,
6212 rbrksld: rbrksld,
6213 rbrkslu: rbrkslu,
6214 Rcaron: Rcaron,
6215 rcaron: rcaron,
6216 Rcedil: Rcedil,
6217 rcedil: rcedil,
6218 rceil: rceil,
6219 rcub: rcub,
6220 Rcy: Rcy,
6221 rcy: rcy,
6222 rdca: rdca,
6223 rdldhar: rdldhar,
6224 rdquo: rdquo,
6225 rdquor: rdquor,
6226 rdsh: rdsh,
6227 real: real,
6228 realine: realine,
6229 realpart: realpart,
6230 reals: reals,
6231 Re: Re,
6232 rect: rect,
6233 reg: reg,
6234 REG: REG,
6235 ReverseElement: ReverseElement,
6236 ReverseEquilibrium: ReverseEquilibrium,
6237 ReverseUpEquilibrium: ReverseUpEquilibrium,
6238 rfisht: rfisht,
6239 rfloor: rfloor,
6240 rfr: rfr,
6241 Rfr: Rfr,
6242 rHar: rHar,
6243 rhard: rhard,
6244 rharu: rharu,
6245 rharul: rharul,
6246 Rho: Rho,
6247 rho: rho,
6248 rhov: rhov,
6249 RightAngleBracket: RightAngleBracket,
6250 RightArrowBar: RightArrowBar,
6251 rightarrow: rightarrow,
6252 RightArrow: RightArrow,
6253 Rightarrow: Rightarrow,
6254 RightArrowLeftArrow: RightArrowLeftArrow,
6255 rightarrowtail: rightarrowtail,
6256 RightCeiling: RightCeiling,
6257 RightDoubleBracket: RightDoubleBracket,
6258 RightDownTeeVector: RightDownTeeVector,
6259 RightDownVectorBar: RightDownVectorBar,
6260 RightDownVector: RightDownVector,
6261 RightFloor: RightFloor,
6262 rightharpoondown: rightharpoondown,
6263 rightharpoonup: rightharpoonup,
6264 rightleftarrows: rightleftarrows,
6265 rightleftharpoons: rightleftharpoons,
6266 rightrightarrows: rightrightarrows,
6267 rightsquigarrow: rightsquigarrow,
6268 RightTeeArrow: RightTeeArrow,
6269 RightTee: RightTee,
6270 RightTeeVector: RightTeeVector,
6271 rightthreetimes: rightthreetimes,
6272 RightTriangleBar: RightTriangleBar,
6273 RightTriangle: RightTriangle,
6274 RightTriangleEqual: RightTriangleEqual,
6275 RightUpDownVector: RightUpDownVector,
6276 RightUpTeeVector: RightUpTeeVector,
6277 RightUpVectorBar: RightUpVectorBar,
6278 RightUpVector: RightUpVector,
6279 RightVectorBar: RightVectorBar,
6280 RightVector: RightVector,
6281 ring: ring,
6282 risingdotseq: risingdotseq,
6283 rlarr: rlarr,
6284 rlhar: rlhar,
6285 rlm: rlm,
6286 rmoustache: rmoustache,
6287 rmoust: rmoust,
6288 rnmid: rnmid,
6289 roang: roang,
6290 roarr: roarr,
6291 robrk: robrk,
6292 ropar: ropar,
6293 ropf: ropf,
6294 Ropf: Ropf,
6295 roplus: roplus,
6296 rotimes: rotimes,
6297 RoundImplies: RoundImplies,
6298 rpar: rpar,
6299 rpargt: rpargt,
6300 rppolint: rppolint,
6301 rrarr: rrarr,
6302 Rrightarrow: Rrightarrow,
6303 rsaquo: rsaquo,
6304 rscr: rscr,
6305 Rscr: Rscr,
6306 rsh: rsh,
6307 Rsh: Rsh,
6308 rsqb: rsqb,
6309 rsquo: rsquo,
6310 rsquor: rsquor,
6311 rthree: rthree,
6312 rtimes: rtimes,
6313 rtri: rtri,
6314 rtrie: rtrie,
6315 rtrif: rtrif,
6316 rtriltri: rtriltri,
6317 RuleDelayed: RuleDelayed,
6318 ruluhar: ruluhar,
6319 rx: rx,
6320 Sacute: Sacute,
6321 sacute: sacute,
6322 sbquo: sbquo,
6323 scap: scap,
6324 Scaron: Scaron,
6325 scaron: scaron,
6326 Sc: Sc,
6327 sc: sc,
6328 sccue: sccue,
6329 sce: sce,
6330 scE: scE,
6331 Scedil: Scedil,
6332 scedil: scedil,
6333 Scirc: Scirc,
6334 scirc: scirc,
6335 scnap: scnap,
6336 scnE: scnE,
6337 scnsim: scnsim,
6338 scpolint: scpolint,
6339 scsim: scsim,
6340 Scy: Scy,
6341 scy: scy,
6342 sdotb: sdotb,
6343 sdot: sdot,
6344 sdote: sdote,
6345 searhk: searhk,
6346 searr: searr,
6347 seArr: seArr,
6348 searrow: searrow,
6349 sect: sect,
6350 semi: semi,
6351 seswar: seswar,
6352 setminus: setminus,
6353 setmn: setmn,
6354 sext: sext,
6355 Sfr: Sfr,
6356 sfr: sfr,
6357 sfrown: sfrown,
6358 sharp: sharp,
6359 SHCHcy: SHCHcy,
6360 shchcy: shchcy,
6361 SHcy: SHcy,
6362 shcy: shcy,
6363 ShortDownArrow: ShortDownArrow,
6364 ShortLeftArrow: ShortLeftArrow,
6365 shortmid: shortmid,
6366 shortparallel: shortparallel,
6367 ShortRightArrow: ShortRightArrow,
6368 ShortUpArrow: ShortUpArrow,
6369 shy: shy,
6370 Sigma: Sigma,
6371 sigma: sigma,
6372 sigmaf: sigmaf,
6373 sigmav: sigmav,
6374 sim: sim,
6375 simdot: simdot,
6376 sime: sime,
6377 simeq: simeq,
6378 simg: simg,
6379 simgE: simgE,
6380 siml: siml,
6381 simlE: simlE,
6382 simne: simne,
6383 simplus: simplus,
6384 simrarr: simrarr,
6385 slarr: slarr,
6386 SmallCircle: SmallCircle,
6387 smallsetminus: smallsetminus,
6388 smashp: smashp,
6389 smeparsl: smeparsl,
6390 smid: smid,
6391 smile: smile,
6392 smt: smt,
6393 smte: smte,
6394 smtes: smtes,
6395 SOFTcy: SOFTcy,
6396 softcy: softcy,
6397 solbar: solbar,
6398 solb: solb,
6399 sol: sol,
6400 Sopf: Sopf,
6401 sopf: sopf,
6402 spades: spades,
6403 spadesuit: spadesuit,
6404 spar: spar,
6405 sqcap: sqcap,
6406 sqcaps: sqcaps,
6407 sqcup: sqcup,
6408 sqcups: sqcups,
6409 Sqrt: Sqrt,
6410 sqsub: sqsub,
6411 sqsube: sqsube,
6412 sqsubset: sqsubset,
6413 sqsubseteq: sqsubseteq,
6414 sqsup: sqsup,
6415 sqsupe: sqsupe,
6416 sqsupset: sqsupset,
6417 sqsupseteq: sqsupseteq,
6418 square: square,
6419 Square: Square,
6420 SquareIntersection: SquareIntersection,
6421 SquareSubset: SquareSubset,
6422 SquareSubsetEqual: SquareSubsetEqual,
6423 SquareSuperset: SquareSuperset,
6424 SquareSupersetEqual: SquareSupersetEqual,
6425 SquareUnion: SquareUnion,
6426 squarf: squarf,
6427 squ: squ,
6428 squf: squf,
6429 srarr: srarr,
6430 Sscr: Sscr,
6431 sscr: sscr,
6432 ssetmn: ssetmn,
6433 ssmile: ssmile,
6434 sstarf: sstarf,
6435 Star: Star,
6436 star: star,
6437 starf: starf,
6438 straightepsilon: straightepsilon,
6439 straightphi: straightphi,
6440 strns: strns,
6441 sub: sub,
6442 Sub: Sub,
6443 subdot: subdot,
6444 subE: subE,
6445 sube: sube,
6446 subedot: subedot,
6447 submult: submult,
6448 subnE: subnE,
6449 subne: subne,
6450 subplus: subplus,
6451 subrarr: subrarr,
6452 subset: subset,
6453 Subset: Subset,
6454 subseteq: subseteq,
6455 subseteqq: subseteqq,
6456 SubsetEqual: SubsetEqual,
6457 subsetneq: subsetneq,
6458 subsetneqq: subsetneqq,
6459 subsim: subsim,
6460 subsub: subsub,
6461 subsup: subsup,
6462 succapprox: succapprox,
6463 succ: succ,
6464 succcurlyeq: succcurlyeq,
6465 Succeeds: Succeeds,
6466 SucceedsEqual: SucceedsEqual,
6467 SucceedsSlantEqual: SucceedsSlantEqual,
6468 SucceedsTilde: SucceedsTilde,
6469 succeq: succeq,
6470 succnapprox: succnapprox,
6471 succneqq: succneqq,
6472 succnsim: succnsim,
6473 succsim: succsim,
6474 SuchThat: SuchThat,
6475 sum: sum,
6476 Sum: Sum,
6477 sung: sung,
6478 sup1: sup1,
6479 sup2: sup2,
6480 sup3: sup3,
6481 sup: sup,
6482 Sup: Sup,
6483 supdot: supdot,
6484 supdsub: supdsub,
6485 supE: supE,
6486 supe: supe,
6487 supedot: supedot,
6488 Superset: Superset,
6489 SupersetEqual: SupersetEqual,
6490 suphsol: suphsol,
6491 suphsub: suphsub,
6492 suplarr: suplarr,
6493 supmult: supmult,
6494 supnE: supnE,
6495 supne: supne,
6496 supplus: supplus,
6497 supset: supset,
6498 Supset: Supset,
6499 supseteq: supseteq,
6500 supseteqq: supseteqq,
6501 supsetneq: supsetneq,
6502 supsetneqq: supsetneqq,
6503 supsim: supsim,
6504 supsub: supsub,
6505 supsup: supsup,
6506 swarhk: swarhk,
6507 swarr: swarr,
6508 swArr: swArr,
6509 swarrow: swarrow,
6510 swnwar: swnwar,
6511 szlig: szlig,
6512 Tab: Tab,
6513 target: target,
6514 Tau: Tau,
6515 tau: tau,
6516 tbrk: tbrk,
6517 Tcaron: Tcaron,
6518 tcaron: tcaron,
6519 Tcedil: Tcedil,
6520 tcedil: tcedil,
6521 Tcy: Tcy,
6522 tcy: tcy,
6523 tdot: tdot,
6524 telrec: telrec,
6525 Tfr: Tfr,
6526 tfr: tfr,
6527 there4: there4,
6528 therefore: therefore,
6529 Therefore: Therefore,
6530 Theta: Theta,
6531 theta: theta,
6532 thetasym: thetasym,
6533 thetav: thetav,
6534 thickapprox: thickapprox,
6535 thicksim: thicksim,
6536 ThickSpace: ThickSpace,
6537 ThinSpace: ThinSpace,
6538 thinsp: thinsp,
6539 thkap: thkap,
6540 thksim: thksim,
6541 THORN: THORN,
6542 thorn: thorn,
6543 tilde: tilde,
6544 Tilde: Tilde,
6545 TildeEqual: TildeEqual,
6546 TildeFullEqual: TildeFullEqual,
6547 TildeTilde: TildeTilde,
6548 timesbar: timesbar,
6549 timesb: timesb,
6550 times: times,
6551 timesd: timesd,
6552 tint: tint,
6553 toea: toea,
6554 topbot: topbot,
6555 topcir: topcir,
6556 top: top,
6557 Topf: Topf,
6558 topf: topf,
6559 topfork: topfork,
6560 tosa: tosa,
6561 tprime: tprime,
6562 trade: trade,
6563 TRADE: TRADE,
6564 triangle: triangle,
6565 triangledown: triangledown,
6566 triangleleft: triangleleft,
6567 trianglelefteq: trianglelefteq,
6568 triangleq: triangleq,
6569 triangleright: triangleright,
6570 trianglerighteq: trianglerighteq,
6571 tridot: tridot,
6572 trie: trie,
6573 triminus: triminus,
6574 TripleDot: TripleDot,
6575 triplus: triplus,
6576 trisb: trisb,
6577 tritime: tritime,
6578 trpezium: trpezium,
6579 Tscr: Tscr,
6580 tscr: tscr,
6581 TScy: TScy,
6582 tscy: tscy,
6583 TSHcy: TSHcy,
6584 tshcy: tshcy,
6585 Tstrok: Tstrok,
6586 tstrok: tstrok,
6587 twixt: twixt,
6588 twoheadleftarrow: twoheadleftarrow,
6589 twoheadrightarrow: twoheadrightarrow,
6590 Uacute: Uacute,
6591 uacute: uacute,
6592 uarr: uarr,
6593 Uarr: Uarr,
6594 uArr: uArr,
6595 Uarrocir: Uarrocir,
6596 Ubrcy: Ubrcy,
6597 ubrcy: ubrcy,
6598 Ubreve: Ubreve,
6599 ubreve: ubreve,
6600 Ucirc: Ucirc,
6601 ucirc: ucirc,
6602 Ucy: Ucy,
6603 ucy: ucy,
6604 udarr: udarr,
6605 Udblac: Udblac,
6606 udblac: udblac,
6607 udhar: udhar,
6608 ufisht: ufisht,
6609 Ufr: Ufr,
6610 ufr: ufr,
6611 Ugrave: Ugrave,
6612 ugrave: ugrave,
6613 uHar: uHar,
6614 uharl: uharl,
6615 uharr: uharr,
6616 uhblk: uhblk,
6617 ulcorn: ulcorn,
6618 ulcorner: ulcorner,
6619 ulcrop: ulcrop,
6620 ultri: ultri,
6621 Umacr: Umacr,
6622 umacr: umacr,
6623 uml: uml,
6624 UnderBar: UnderBar,
6625 UnderBrace: UnderBrace,
6626 UnderBracket: UnderBracket,
6627 UnderParenthesis: UnderParenthesis,
6628 Union: Union,
6629 UnionPlus: UnionPlus,
6630 Uogon: Uogon,
6631 uogon: uogon,
6632 Uopf: Uopf,
6633 uopf: uopf,
6634 UpArrowBar: UpArrowBar,
6635 uparrow: uparrow,
6636 UpArrow: UpArrow,
6637 Uparrow: Uparrow,
6638 UpArrowDownArrow: UpArrowDownArrow,
6639 updownarrow: updownarrow,
6640 UpDownArrow: UpDownArrow,
6641 Updownarrow: Updownarrow,
6642 UpEquilibrium: UpEquilibrium,
6643 upharpoonleft: upharpoonleft,
6644 upharpoonright: upharpoonright,
6645 uplus: uplus,
6646 UpperLeftArrow: UpperLeftArrow,
6647 UpperRightArrow: UpperRightArrow,
6648 upsi: upsi,
6649 Upsi: Upsi,
6650 upsih: upsih,
6651 Upsilon: Upsilon,
6652 upsilon: upsilon,
6653 UpTeeArrow: UpTeeArrow,
6654 UpTee: UpTee,
6655 upuparrows: upuparrows,
6656 urcorn: urcorn,
6657 urcorner: urcorner,
6658 urcrop: urcrop,
6659 Uring: Uring,
6660 uring: uring,
6661 urtri: urtri,
6662 Uscr: Uscr,
6663 uscr: uscr,
6664 utdot: utdot,
6665 Utilde: Utilde,
6666 utilde: utilde,
6667 utri: utri,
6668 utrif: utrif,
6669 uuarr: uuarr,
6670 Uuml: Uuml,
6671 uuml: uuml,
6672 uwangle: uwangle,
6673 vangrt: vangrt,
6674 varepsilon: varepsilon,
6675 varkappa: varkappa,
6676 varnothing: varnothing,
6677 varphi: varphi,
6678 varpi: varpi,
6679 varpropto: varpropto,
6680 varr: varr,
6681 vArr: vArr,
6682 varrho: varrho,
6683 varsigma: varsigma,
6684 varsubsetneq: varsubsetneq,
6685 varsubsetneqq: varsubsetneqq,
6686 varsupsetneq: varsupsetneq,
6687 varsupsetneqq: varsupsetneqq,
6688 vartheta: vartheta,
6689 vartriangleleft: vartriangleleft,
6690 vartriangleright: vartriangleright,
6691 vBar: vBar,
6692 Vbar: Vbar,
6693 vBarv: vBarv,
6694 Vcy: Vcy,
6695 vcy: vcy,
6696 vdash: vdash,
6697 vDash: vDash,
6698 Vdash: Vdash,
6699 VDash: VDash,
6700 Vdashl: Vdashl,
6701 veebar: veebar,
6702 vee: vee,
6703 Vee: Vee,
6704 veeeq: veeeq,
6705 vellip: vellip,
6706 verbar: verbar,
6707 Verbar: Verbar,
6708 vert: vert,
6709 Vert: Vert,
6710 VerticalBar: VerticalBar,
6711 VerticalLine: VerticalLine,
6712 VerticalSeparator: VerticalSeparator,
6713 VerticalTilde: VerticalTilde,
6714 VeryThinSpace: VeryThinSpace,
6715 Vfr: Vfr,
6716 vfr: vfr,
6717 vltri: vltri,
6718 vnsub: vnsub,
6719 vnsup: vnsup,
6720 Vopf: Vopf,
6721 vopf: vopf,
6722 vprop: vprop,
6723 vrtri: vrtri,
6724 Vscr: Vscr,
6725 vscr: vscr,
6726 vsubnE: vsubnE,
6727 vsubne: vsubne,
6728 vsupnE: vsupnE,
6729 vsupne: vsupne,
6730 Vvdash: Vvdash,
6731 vzigzag: vzigzag,
6732 Wcirc: Wcirc,
6733 wcirc: wcirc,
6734 wedbar: wedbar,
6735 wedge: wedge,
6736 Wedge: Wedge,
6737 wedgeq: wedgeq,
6738 weierp: weierp,
6739 Wfr: Wfr,
6740 wfr: wfr,
6741 Wopf: Wopf,
6742 wopf: wopf,
6743 wp: wp,
6744 wr: wr,
6745 wreath: wreath,
6746 Wscr: Wscr,
6747 wscr: wscr,
6748 xcap: xcap,
6749 xcirc: xcirc,
6750 xcup: xcup,
6751 xdtri: xdtri,
6752 Xfr: Xfr,
6753 xfr: xfr,
6754 xharr: xharr,
6755 xhArr: xhArr,
6756 Xi: Xi,
6757 xi: xi,
6758 xlarr: xlarr,
6759 xlArr: xlArr,
6760 xmap: xmap,
6761 xnis: xnis,
6762 xodot: xodot,
6763 Xopf: Xopf,
6764 xopf: xopf,
6765 xoplus: xoplus,
6766 xotime: xotime,
6767 xrarr: xrarr,
6768 xrArr: xrArr,
6769 Xscr: Xscr,
6770 xscr: xscr,
6771 xsqcup: xsqcup,
6772 xuplus: xuplus,
6773 xutri: xutri,
6774 xvee: xvee,
6775 xwedge: xwedge,
6776 Yacute: Yacute,
6777 yacute: yacute,
6778 YAcy: YAcy,
6779 yacy: yacy,
6780 Ycirc: Ycirc,
6781 ycirc: ycirc,
6782 Ycy: Ycy,
6783 ycy: ycy,
6784 yen: yen,
6785 Yfr: Yfr,
6786 yfr: yfr,
6787 YIcy: YIcy,
6788 yicy: yicy,
6789 Yopf: Yopf,
6790 yopf: yopf,
6791 Yscr: Yscr,
6792 yscr: yscr,
6793 YUcy: YUcy,
6794 yucy: yucy,
6795 yuml: yuml,
6796 Yuml: Yuml,
6797 Zacute: Zacute,
6798 zacute: zacute,
6799 Zcaron: Zcaron,
6800 zcaron: zcaron,
6801 Zcy: Zcy,
6802 zcy: zcy,
6803 Zdot: Zdot,
6804 zdot: zdot,
6805 zeetrf: zeetrf,
6806 ZeroWidthSpace: ZeroWidthSpace,
6807 Zeta: Zeta,
6808 zeta: zeta,
6809 zfr: zfr,
6810 Zfr: Zfr,
6811 ZHcy: ZHcy,
6812 zhcy: zhcy,
6813 zigrarr: zigrarr,
6814 zopf: zopf,
6815 Zopf: Zopf,
6816 Zscr: Zscr,
6817 zscr: zscr,
6818 zwj: zwj,
6819 zwnj: zwnj,
6820 'default': entities
6821 });
6822
6823 var Aacute$1 = "Á";
6824 var aacute$1 = "á";
6825 var Acirc$1 = "Â";
6826 var acirc$1 = "â";
6827 var acute$1 = "´";
6828 var AElig$1 = "Æ";
6829 var aelig$1 = "æ";
6830 var Agrave$1 = "À";
6831 var agrave$1 = "à";
6832 var amp$1 = "&";
6833 var AMP$1 = "&";
6834 var Aring$1 = "Å";
6835 var aring$1 = "å";
6836 var Atilde$1 = "Ã";
6837 var atilde$1 = "ã";
6838 var Auml$1 = "Ä";
6839 var auml$1 = "ä";
6840 var brvbar$1 = "¦";
6841 var Ccedil$1 = "Ç";
6842 var ccedil$1 = "ç";
6843 var cedil$1 = "¸";
6844 var cent$1 = "¢";
6845 var copy$1 = "©";
6846 var COPY$1 = "©";
6847 var curren$1 = "¤";
6848 var deg$1 = "°";
6849 var divide$1 = "÷";
6850 var Eacute$1 = "É";
6851 var eacute$1 = "é";
6852 var Ecirc$1 = "Ê";
6853 var ecirc$1 = "ê";
6854 var Egrave$1 = "È";
6855 var egrave$1 = "è";
6856 var ETH$1 = "Ð";
6857 var eth$1 = "ð";
6858 var Euml$1 = "Ë";
6859 var euml$1 = "ë";
6860 var frac12$1 = "½";
6861 var frac14$1 = "¼";
6862 var frac34$1 = "¾";
6863 var gt$1 = ">";
6864 var GT$1 = ">";
6865 var Iacute$1 = "Í";
6866 var iacute$1 = "í";
6867 var Icirc$1 = "Î";
6868 var icirc$1 = "î";
6869 var iexcl$1 = "¡";
6870 var Igrave$1 = "Ì";
6871 var igrave$1 = "ì";
6872 var iquest$1 = "¿";
6873 var Iuml$1 = "Ï";
6874 var iuml$1 = "ï";
6875 var laquo$1 = "«";
6876 var lt$1 = "<";
6877 var LT$1 = "<";
6878 var macr$1 = "¯";
6879 var micro$1 = "µ";
6880 var middot$1 = "·";
6881 var nbsp$1 = " ";
6882 var not$1 = "¬";
6883 var Ntilde$1 = "Ñ";
6884 var ntilde$1 = "ñ";
6885 var Oacute$1 = "Ó";
6886 var oacute$1 = "ó";
6887 var Ocirc$1 = "Ô";
6888 var ocirc$1 = "ô";
6889 var Ograve$1 = "Ò";
6890 var ograve$1 = "ò";
6891 var ordf$1 = "ª";
6892 var ordm$1 = "º";
6893 var Oslash$1 = "Ø";
6894 var oslash$1 = "ø";
6895 var Otilde$1 = "Õ";
6896 var otilde$1 = "õ";
6897 var Ouml$1 = "Ö";
6898 var ouml$1 = "ö";
6899 var para$1 = "¶";
6900 var plusmn$1 = "±";
6901 var pound$1 = "£";
6902 var quot$1 = "\"";
6903 var QUOT$1 = "\"";
6904 var raquo$1 = "»";
6905 var reg$1 = "®";
6906 var REG$1 = "®";
6907 var sect$1 = "§";
6908 var shy$1 = "­";
6909 var sup1$1 = "¹";
6910 var sup2$1 = "²";
6911 var sup3$1 = "³";
6912 var szlig$1 = "ß";
6913 var THORN$1 = "Þ";
6914 var thorn$1 = "þ";
6915 var times$1 = "×";
6916 var Uacute$1 = "Ú";
6917 var uacute$1 = "ú";
6918 var Ucirc$1 = "Û";
6919 var ucirc$1 = "û";
6920 var Ugrave$1 = "Ù";
6921 var ugrave$1 = "ù";
6922 var uml$1 = "¨";
6923 var Uuml$1 = "Ü";
6924 var uuml$1 = "ü";
6925 var Yacute$1 = "Ý";
6926 var yacute$1 = "ý";
6927 var yen$1 = "¥";
6928 var yuml$1 = "ÿ";
6929 var legacy = {
6930 Aacute: Aacute$1,
6931 aacute: aacute$1,
6932 Acirc: Acirc$1,
6933 acirc: acirc$1,
6934 acute: acute$1,
6935 AElig: AElig$1,
6936 aelig: aelig$1,
6937 Agrave: Agrave$1,
6938 agrave: agrave$1,
6939 amp: amp$1,
6940 AMP: AMP$1,
6941 Aring: Aring$1,
6942 aring: aring$1,
6943 Atilde: Atilde$1,
6944 atilde: atilde$1,
6945 Auml: Auml$1,
6946 auml: auml$1,
6947 brvbar: brvbar$1,
6948 Ccedil: Ccedil$1,
6949 ccedil: ccedil$1,
6950 cedil: cedil$1,
6951 cent: cent$1,
6952 copy: copy$1,
6953 COPY: COPY$1,
6954 curren: curren$1,
6955 deg: deg$1,
6956 divide: divide$1,
6957 Eacute: Eacute$1,
6958 eacute: eacute$1,
6959 Ecirc: Ecirc$1,
6960 ecirc: ecirc$1,
6961 Egrave: Egrave$1,
6962 egrave: egrave$1,
6963 ETH: ETH$1,
6964 eth: eth$1,
6965 Euml: Euml$1,
6966 euml: euml$1,
6967 frac12: frac12$1,
6968 frac14: frac14$1,
6969 frac34: frac34$1,
6970 gt: gt$1,
6971 GT: GT$1,
6972 Iacute: Iacute$1,
6973 iacute: iacute$1,
6974 Icirc: Icirc$1,
6975 icirc: icirc$1,
6976 iexcl: iexcl$1,
6977 Igrave: Igrave$1,
6978 igrave: igrave$1,
6979 iquest: iquest$1,
6980 Iuml: Iuml$1,
6981 iuml: iuml$1,
6982 laquo: laquo$1,
6983 lt: lt$1,
6984 LT: LT$1,
6985 macr: macr$1,
6986 micro: micro$1,
6987 middot: middot$1,
6988 nbsp: nbsp$1,
6989 not: not$1,
6990 Ntilde: Ntilde$1,
6991 ntilde: ntilde$1,
6992 Oacute: Oacute$1,
6993 oacute: oacute$1,
6994 Ocirc: Ocirc$1,
6995 ocirc: ocirc$1,
6996 Ograve: Ograve$1,
6997 ograve: ograve$1,
6998 ordf: ordf$1,
6999 ordm: ordm$1,
7000 Oslash: Oslash$1,
7001 oslash: oslash$1,
7002 Otilde: Otilde$1,
7003 otilde: otilde$1,
7004 Ouml: Ouml$1,
7005 ouml: ouml$1,
7006 para: para$1,
7007 plusmn: plusmn$1,
7008 pound: pound$1,
7009 quot: quot$1,
7010 QUOT: QUOT$1,
7011 raquo: raquo$1,
7012 reg: reg$1,
7013 REG: REG$1,
7014 sect: sect$1,
7015 shy: shy$1,
7016 sup1: sup1$1,
7017 sup2: sup2$1,
7018 sup3: sup3$1,
7019 szlig: szlig$1,
7020 THORN: THORN$1,
7021 thorn: thorn$1,
7022 times: times$1,
7023 Uacute: Uacute$1,
7024 uacute: uacute$1,
7025 Ucirc: Ucirc$1,
7026 ucirc: ucirc$1,
7027 Ugrave: Ugrave$1,
7028 ugrave: ugrave$1,
7029 uml: uml$1,
7030 Uuml: Uuml$1,
7031 uuml: uuml$1,
7032 Yacute: Yacute$1,
7033 yacute: yacute$1,
7034 yen: yen$1,
7035 yuml: yuml$1
7036 };
7037
7038 var legacy$1 = /*#__PURE__*/Object.freeze({
7039 __proto__: null,
7040 Aacute: Aacute$1,
7041 aacute: aacute$1,
7042 Acirc: Acirc$1,
7043 acirc: acirc$1,
7044 acute: acute$1,
7045 AElig: AElig$1,
7046 aelig: aelig$1,
7047 Agrave: Agrave$1,
7048 agrave: agrave$1,
7049 amp: amp$1,
7050 AMP: AMP$1,
7051 Aring: Aring$1,
7052 aring: aring$1,
7053 Atilde: Atilde$1,
7054 atilde: atilde$1,
7055 Auml: Auml$1,
7056 auml: auml$1,
7057 brvbar: brvbar$1,
7058 Ccedil: Ccedil$1,
7059 ccedil: ccedil$1,
7060 cedil: cedil$1,
7061 cent: cent$1,
7062 copy: copy$1,
7063 COPY: COPY$1,
7064 curren: curren$1,
7065 deg: deg$1,
7066 divide: divide$1,
7067 Eacute: Eacute$1,
7068 eacute: eacute$1,
7069 Ecirc: Ecirc$1,
7070 ecirc: ecirc$1,
7071 Egrave: Egrave$1,
7072 egrave: egrave$1,
7073 ETH: ETH$1,
7074 eth: eth$1,
7075 Euml: Euml$1,
7076 euml: euml$1,
7077 frac12: frac12$1,
7078 frac14: frac14$1,
7079 frac34: frac34$1,
7080 gt: gt$1,
7081 GT: GT$1,
7082 Iacute: Iacute$1,
7083 iacute: iacute$1,
7084 Icirc: Icirc$1,
7085 icirc: icirc$1,
7086 iexcl: iexcl$1,
7087 Igrave: Igrave$1,
7088 igrave: igrave$1,
7089 iquest: iquest$1,
7090 Iuml: Iuml$1,
7091 iuml: iuml$1,
7092 laquo: laquo$1,
7093 lt: lt$1,
7094 LT: LT$1,
7095 macr: macr$1,
7096 micro: micro$1,
7097 middot: middot$1,
7098 nbsp: nbsp$1,
7099 not: not$1,
7100 Ntilde: Ntilde$1,
7101 ntilde: ntilde$1,
7102 Oacute: Oacute$1,
7103 oacute: oacute$1,
7104 Ocirc: Ocirc$1,
7105 ocirc: ocirc$1,
7106 Ograve: Ograve$1,
7107 ograve: ograve$1,
7108 ordf: ordf$1,
7109 ordm: ordm$1,
7110 Oslash: Oslash$1,
7111 oslash: oslash$1,
7112 Otilde: Otilde$1,
7113 otilde: otilde$1,
7114 Ouml: Ouml$1,
7115 ouml: ouml$1,
7116 para: para$1,
7117 plusmn: plusmn$1,
7118 pound: pound$1,
7119 quot: quot$1,
7120 QUOT: QUOT$1,
7121 raquo: raquo$1,
7122 reg: reg$1,
7123 REG: REG$1,
7124 sect: sect$1,
7125 shy: shy$1,
7126 sup1: sup1$1,
7127 sup2: sup2$1,
7128 sup3: sup3$1,
7129 szlig: szlig$1,
7130 THORN: THORN$1,
7131 thorn: thorn$1,
7132 times: times$1,
7133 Uacute: Uacute$1,
7134 uacute: uacute$1,
7135 Ucirc: Ucirc$1,
7136 ucirc: ucirc$1,
7137 Ugrave: Ugrave$1,
7138 ugrave: ugrave$1,
7139 uml: uml$1,
7140 Uuml: Uuml$1,
7141 uuml: uuml$1,
7142 Yacute: Yacute$1,
7143 yacute: yacute$1,
7144 yen: yen$1,
7145 yuml: yuml$1,
7146 'default': legacy
7147 });
7148
7149 var amp$2 = "&";
7150 var apos$1 = "'";
7151 var gt$2 = ">";
7152 var lt$2 = "<";
7153 var quot$2 = "\"";
7154 var xml = {
7155 amp: amp$2,
7156 apos: apos$1,
7157 gt: gt$2,
7158 lt: lt$2,
7159 quot: quot$2
7160 };
7161
7162 var xml$1 = /*#__PURE__*/Object.freeze({
7163 __proto__: null,
7164 amp: amp$2,
7165 apos: apos$1,
7166 gt: gt$2,
7167 lt: lt$2,
7168 quot: quot$2,
7169 'default': xml
7170 });
7171
7172 var decode = {
7173 "0": 65533,
7174 "128": 8364,
7175 "130": 8218,
7176 "131": 402,
7177 "132": 8222,
7178 "133": 8230,
7179 "134": 8224,
7180 "135": 8225,
7181 "136": 710,
7182 "137": 8240,
7183 "138": 352,
7184 "139": 8249,
7185 "140": 338,
7186 "142": 381,
7187 "145": 8216,
7188 "146": 8217,
7189 "147": 8220,
7190 "148": 8221,
7191 "149": 8226,
7192 "150": 8211,
7193 "151": 8212,
7194 "152": 732,
7195 "153": 8482,
7196 "154": 353,
7197 "155": 8250,
7198 "156": 339,
7199 "158": 382,
7200 "159": 376
7201 };
7202
7203 var decode$1 = /*#__PURE__*/Object.freeze({
7204 __proto__: null,
7205 'default': decode
7206 });
7207
7208 var require$$0 = getCjsExportFromNamespace(decode$1);
7209
7210 var decode_codepoint = createCommonjsModule(function (module, exports) {
7211 var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
7212 return (mod && mod.__esModule) ? mod : { "default": mod };
7213 };
7214 Object.defineProperty(exports, "__esModule", { value: true });
7215 var decode_json_1 = __importDefault(require$$0);
7216 // modified version of https://github.com/mathiasbynens/he/blob/master/src/he.js#L94-L119
7217 function decodeCodePoint(codePoint) {
7218 if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) {
7219 return "\uFFFD";
7220 }
7221 if (codePoint in decode_json_1.default) {
7222 codePoint = decode_json_1.default[codePoint];
7223 }
7224 var output = "";
7225 if (codePoint > 0xffff) {
7226 codePoint -= 0x10000;
7227 output += String.fromCharCode(((codePoint >>> 10) & 0x3ff) | 0xd800);
7228 codePoint = 0xdc00 | (codePoint & 0x3ff);
7229 }
7230 output += String.fromCharCode(codePoint);
7231 return output;
7232 }
7233 exports.default = decodeCodePoint;
7234 });
7235
7236 unwrapExports(decode_codepoint);
7237
7238 var require$$1 = getCjsExportFromNamespace(entities$1);
7239
7240 var require$$1$1 = getCjsExportFromNamespace(legacy$1);
7241
7242 var require$$0$1 = getCjsExportFromNamespace(xml$1);
7243
7244 var decode$2 = createCommonjsModule(function (module, exports) {
7245 var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
7246 return (mod && mod.__esModule) ? mod : { "default": mod };
7247 };
7248 Object.defineProperty(exports, "__esModule", { value: true });
7249 exports.decodeHTML = exports.decodeHTMLStrict = exports.decodeXML = void 0;
7250 var entities_json_1 = __importDefault(require$$1);
7251 var legacy_json_1 = __importDefault(require$$1$1);
7252 var xml_json_1 = __importDefault(require$$0$1);
7253 var decode_codepoint_1 = __importDefault(decode_codepoint);
7254 exports.decodeXML = getStrictDecoder(xml_json_1.default);
7255 exports.decodeHTMLStrict = getStrictDecoder(entities_json_1.default);
7256 function getStrictDecoder(map) {
7257 var keys = Object.keys(map).join("|");
7258 var replace = getReplacer(map);
7259 keys += "|#[xX][\\da-fA-F]+|#\\d+";
7260 var re = new RegExp("&(?:" + keys + ");", "g");
7261 return function (str) { return String(str).replace(re, replace); };
7262 }
7263 var sorter = function (a, b) { return (a < b ? 1 : -1); };
7264 exports.decodeHTML = (function () {
7265 var legacy = Object.keys(legacy_json_1.default).sort(sorter);
7266 var keys = Object.keys(entities_json_1.default).sort(sorter);
7267 for (var i = 0, j = 0; i < keys.length; i++) {
7268 if (legacy[j] === keys[i]) {
7269 keys[i] += ";?";
7270 j++;
7271 }
7272 else {
7273 keys[i] += ";";
7274 }
7275 }
7276 var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g");
7277 var replace = getReplacer(entities_json_1.default);
7278 function replacer(str) {
7279 if (str.substr(-1) !== ";")
7280 str += ";";
7281 return replace(str);
7282 }
7283 //TODO consider creating a merged map
7284 return function (str) { return String(str).replace(re, replacer); };
7285 })();
7286 function getReplacer(map) {
7287 return function replace(str) {
7288 if (str.charAt(1) === "#") {
7289 var secondChar = str.charAt(2);
7290 if (secondChar === "X" || secondChar === "x") {
7291 return decode_codepoint_1.default(parseInt(str.substr(3), 16));
7292 }
7293 return decode_codepoint_1.default(parseInt(str.substr(2), 10));
7294 }
7295 return map[str.slice(1, -1)];
7296 };
7297 }
7298 });
7299
7300 unwrapExports(decode$2);
7301 var decode_1 = decode$2.decodeHTML;
7302 var decode_2 = decode$2.decodeHTMLStrict;
7303 var decode_3 = decode$2.decodeXML;
7304
7305 var encode$1 = createCommonjsModule(function (module, exports) {
7306 var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
7307 return (mod && mod.__esModule) ? mod : { "default": mod };
7308 };
7309 Object.defineProperty(exports, "__esModule", { value: true });
7310 exports.escape = exports.encodeHTML = exports.encodeXML = void 0;
7311 var xml_json_1 = __importDefault(require$$0$1);
7312 var inverseXML = getInverseObj(xml_json_1.default);
7313 var xmlReplacer = getInverseReplacer(inverseXML);
7314 exports.encodeXML = getInverse(inverseXML, xmlReplacer);
7315 var entities_json_1 = __importDefault(require$$1);
7316 var inverseHTML = getInverseObj(entities_json_1.default);
7317 var htmlReplacer = getInverseReplacer(inverseHTML);
7318 exports.encodeHTML = getInverse(inverseHTML, htmlReplacer);
7319 function getInverseObj(obj) {
7320 return Object.keys(obj)
7321 .sort()
7322 .reduce(function (inverse, name) {
7323 inverse[obj[name]] = "&" + name + ";";
7324 return inverse;
7325 }, {});
7326 }
7327 function getInverseReplacer(inverse) {
7328 var single = [];
7329 var multiple = [];
7330 for (var _i = 0, _a = Object.keys(inverse); _i < _a.length; _i++) {
7331 var k = _a[_i];
7332 if (k.length === 1) {
7333 // Add value to single array
7334 single.push("\\" + k);
7335 }
7336 else {
7337 // Add value to multiple array
7338 multiple.push(k);
7339 }
7340 }
7341 // Add ranges to single characters.
7342 single.sort();
7343 for (var start = 0; start < single.length - 1; start++) {
7344 // Find the end of a run of characters
7345 var end = start;
7346 while (end < single.length - 1 &&
7347 single[end].charCodeAt(1) + 1 === single[end + 1].charCodeAt(1)) {
7348 end += 1;
7349 }
7350 var count = 1 + end - start;
7351 // We want to replace at least three characters
7352 if (count < 3)
7353 continue;
7354 single.splice(start, count, single[start] + "-" + single[end]);
7355 }
7356 multiple.unshift("[" + single.join("") + "]");
7357 return new RegExp(multiple.join("|"), "g");
7358 }
7359 var reNonASCII = /(?:[\x80-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g;
7360 function singleCharReplacer(c) {
7361 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7362 return "&#x" + c.codePointAt(0).toString(16).toUpperCase() + ";";
7363 }
7364 function getInverse(inverse, re) {
7365 return function (data) {
7366 return data
7367 .replace(re, function (name) { return inverse[name]; })
7368 .replace(reNonASCII, singleCharReplacer);
7369 };
7370 }
7371 var reXmlChars = getInverseReplacer(inverseXML);
7372 function escape(data) {
7373 return data
7374 .replace(reXmlChars, singleCharReplacer)
7375 .replace(reNonASCII, singleCharReplacer);
7376 }
7377 exports.escape = escape;
7378 });
7379
7380 unwrapExports(encode$1);
7381 var encode_1$1 = encode$1.escape;
7382 var encode_2 = encode$1.encodeHTML;
7383 var encode_3 = encode$1.encodeXML;
7384
7385 var lib = createCommonjsModule(function (module, exports) {
7386 Object.defineProperty(exports, "__esModule", { value: true });
7387 exports.encode = exports.decodeStrict = exports.decode = void 0;
7388
7389
7390 /**
7391 * Decodes a string with entities.
7392 *
7393 * @param data String to decode.
7394 * @param level Optional level to decode at. 0 = XML, 1 = HTML. Default is 0.
7395 */
7396 function decode(data, level) {
7397 return (!level || level <= 0 ? decode$2.decodeXML : decode$2.decodeHTML)(data);
7398 }
7399 exports.decode = decode;
7400 /**
7401 * Decodes a string with entities. Does not allow missing trailing semicolons for entities.
7402 *
7403 * @param data String to decode.
7404 * @param level Optional level to decode at. 0 = XML, 1 = HTML. Default is 0.
7405 */
7406 function decodeStrict(data, level) {
7407 return (!level || level <= 0 ? decode$2.decodeXML : decode$2.decodeHTMLStrict)(data);
7408 }
7409 exports.decodeStrict = decodeStrict;
7410 /**
7411 * Encodes a string with entities.
7412 *
7413 * @param data String to encode.
7414 * @param level Optional level to encode at. 0 = XML, 1 = HTML. Default is 0.
7415 */
7416 function encode(data, level) {
7417 return (!level || level <= 0 ? encode$1.encodeXML : encode$1.encodeHTML)(data);
7418 }
7419 exports.encode = encode;
7420 var encode_2 = encode$1;
7421 Object.defineProperty(exports, "encodeXML", { enumerable: true, get: function () { return encode_2.encodeXML; } });
7422 Object.defineProperty(exports, "encodeHTML", { enumerable: true, get: function () { return encode_2.encodeHTML; } });
7423 Object.defineProperty(exports, "escape", { enumerable: true, get: function () { return encode_2.escape; } });
7424 // Legacy aliases
7425 Object.defineProperty(exports, "encodeHTML4", { enumerable: true, get: function () { return encode_2.encodeHTML; } });
7426 Object.defineProperty(exports, "encodeHTML5", { enumerable: true, get: function () { return encode_2.encodeHTML; } });
7427 var decode_2 = decode$2;
7428 Object.defineProperty(exports, "decodeXML", { enumerable: true, get: function () { return decode_2.decodeXML; } });
7429 Object.defineProperty(exports, "decodeHTML", { enumerable: true, get: function () { return decode_2.decodeHTML; } });
7430 Object.defineProperty(exports, "decodeHTMLStrict", { enumerable: true, get: function () { return decode_2.decodeHTMLStrict; } });
7431 // Legacy aliases
7432 Object.defineProperty(exports, "decodeHTML4", { enumerable: true, get: function () { return decode_2.decodeHTML; } });
7433 Object.defineProperty(exports, "decodeHTML5", { enumerable: true, get: function () { return decode_2.decodeHTML; } });
7434 Object.defineProperty(exports, "decodeHTML4Strict", { enumerable: true, get: function () { return decode_2.decodeHTMLStrict; } });
7435 Object.defineProperty(exports, "decodeHTML5Strict", { enumerable: true, get: function () { return decode_2.decodeHTMLStrict; } });
7436 Object.defineProperty(exports, "decodeXMLStrict", { enumerable: true, get: function () { return decode_2.decodeXML; } });
7437 });
7438
7439 unwrapExports(lib);
7440 var lib_1 = lib.encode;
7441 var lib_2 = lib.decodeStrict;
7442 var lib_3 = lib.decode;
7443 var lib_4 = lib.encodeXML;
7444 var lib_5 = lib.encodeHTML;
7445 var lib_6 = lib.encodeHTML4;
7446 var lib_7 = lib.encodeHTML5;
7447 var lib_8 = lib.decodeXML;
7448 var lib_9 = lib.decodeHTML;
7449 var lib_10 = lib.decodeHTMLStrict;
7450 var lib_11 = lib.decodeHTML4;
7451 var lib_12 = lib.decodeHTML5;
7452 var lib_13 = lib.decodeHTML4Strict;
7453 var lib_14 = lib.decodeHTML5Strict;
7454 var lib_15 = lib.decodeXMLStrict;
7455
7456 var C_BACKSLASH = 92;
7457
7458 var ENTITY = "&(?:#x[a-f0-9]{1,6}|#[0-9]{1,7}|[a-z][a-z0-9]{1,31});";
7459
7460 var TAGNAME = "[A-Za-z][A-Za-z0-9-]*";
7461 var ATTRIBUTENAME = "[a-zA-Z_:][a-zA-Z0-9:._-]*";
7462 var UNQUOTEDVALUE = "[^\"'=<>`\\x00-\\x20]+";
7463 var SINGLEQUOTEDVALUE = "'[^']*'";
7464 var DOUBLEQUOTEDVALUE = '"[^"]*"';
7465 var ATTRIBUTEVALUE =
7466 "(?:" +
7467 UNQUOTEDVALUE +
7468 "|" +
7469 SINGLEQUOTEDVALUE +
7470 "|" +
7471 DOUBLEQUOTEDVALUE +
7472 ")";
7473 var ATTRIBUTEVALUESPEC = "(?:" + "\\s*=" + "\\s*" + ATTRIBUTEVALUE + ")";
7474 var ATTRIBUTE = "(?:" + "\\s+" + ATTRIBUTENAME + ATTRIBUTEVALUESPEC + "?)";
7475 var OPENTAG = "<" + TAGNAME + ATTRIBUTE + "*" + "\\s*/?>";
7476 var CLOSETAG = "</" + TAGNAME + "\\s*[>]";
7477 var HTMLCOMMENT = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->";
7478 var PROCESSINGINSTRUCTION = "[<][?][\\s\\S]*?[?][>]";
7479 var DECLARATION = "<![A-Z]+" + "\\s+[^>]*>";
7480 var CDATA = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>";
7481 var HTMLTAG =
7482 "(?:" +
7483 OPENTAG +
7484 "|" +
7485 CLOSETAG +
7486 "|" +
7487 HTMLCOMMENT +
7488 "|" +
7489 PROCESSINGINSTRUCTION +
7490 "|" +
7491 DECLARATION +
7492 "|" +
7493 CDATA +
7494 ")";
7495 var reHtmlTag = new RegExp("^" + HTMLTAG);
7496
7497 var reBackslashOrAmp = /[\\&]/;
7498
7499 var ESCAPABLE = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]";
7500
7501 var reEntityOrEscapedChar = new RegExp("\\\\" + ESCAPABLE + "|" + ENTITY, "gi");
7502
7503 var XMLSPECIAL = '[&<>"]';
7504
7505 var reXmlSpecial = new RegExp(XMLSPECIAL, "g");
7506
7507 var unescapeChar = function(s) {
7508 if (s.charCodeAt(0) === C_BACKSLASH) {
7509 return s.charAt(1);
7510 } else {
7511 return lib_9(s);
7512 }
7513 };
7514
7515 // Replace entities and backslash escapes with literal characters.
7516 var unescapeString = function(s) {
7517 if (reBackslashOrAmp.test(s)) {
7518 return s.replace(reEntityOrEscapedChar, unescapeChar);
7519 } else {
7520 return s;
7521 }
7522 };
7523
7524 var normalizeURI = function(uri) {
7525 try {
7526 return encode_1(uri);
7527 } catch (err) {
7528 return uri;
7529 }
7530 };
7531
7532 var replaceUnsafeChar = function(s) {
7533 switch (s) {
7534 case "&":
7535 return "&amp;";
7536 case "<":
7537 return "&lt;";
7538 case ">":
7539 return "&gt;";
7540 case '"':
7541 return "&quot;";
7542 default:
7543 return s;
7544 }
7545 };
7546
7547 var escapeXml = function(s) {
7548 if (reXmlSpecial.test(s)) {
7549 return s.replace(reXmlSpecial, replaceUnsafeChar);
7550 } else {
7551 return s;
7552 }
7553 };
7554
7555 // derived from https://github.com/mathiasbynens/String.fromCodePoint
7556 /*! http://mths.be/fromcodepoint v0.2.1 by @mathias */
7557
7558 var _fromCodePoint;
7559
7560 function fromCodePoint(_) {
7561 return _fromCodePoint(_);
7562 }
7563
7564 if (String.fromCodePoint) {
7565 _fromCodePoint = function(_) {
7566 try {
7567 return String.fromCodePoint(_);
7568 } catch (e) {
7569 if (e instanceof RangeError) {
7570 return String.fromCharCode(0xfffd);
7571 }
7572 throw e;
7573 }
7574 };
7575 } else {
7576 var stringFromCharCode = String.fromCharCode;
7577 var floor = Math.floor;
7578 _fromCodePoint = function() {
7579 var MAX_SIZE = 0x4000;
7580 var codeUnits = [];
7581 var highSurrogate;
7582 var lowSurrogate;
7583 var index = -1;
7584 var length = arguments.length;
7585 if (!length) {
7586 return "";
7587 }
7588 var result = "";
7589 while (++index < length) {
7590 var codePoint = Number(arguments[index]);
7591 if (
7592 !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
7593 codePoint < 0 || // not a valid Unicode code point
7594 codePoint > 0x10ffff || // not a valid Unicode code point
7595 floor(codePoint) !== codePoint // not an integer
7596 ) {
7597 return String.fromCharCode(0xfffd);
7598 }
7599 if (codePoint <= 0xffff) {
7600 // BMP code point
7601 codeUnits.push(codePoint);
7602 } else {
7603 // Astral code point; split in surrogate halves
7604 // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
7605 codePoint -= 0x10000;
7606 highSurrogate = (codePoint >> 10) + 0xd800;
7607 lowSurrogate = (codePoint % 0x400) + 0xdc00;
7608 codeUnits.push(highSurrogate, lowSurrogate);
7609 }
7610 if (index + 1 === length || codeUnits.length > MAX_SIZE) {
7611 result += stringFromCharCode.apply(null, codeUnits);
7612 codeUnits.length = 0;
7613 }
7614 }
7615 return result;
7616 };
7617 }
7618
7619 /*! http://mths.be/repeat v0.2.0 by @mathias */
7620 if (!String.prototype.repeat) {
7621 (function() {
7622 var defineProperty = (function() {
7623 // IE 8 only supports `Object.defineProperty` on DOM elements
7624 try {
7625 var object = {};
7626 var $defineProperty = Object.defineProperty;
7627 var result = $defineProperty(object, object, object) && $defineProperty;
7628 } catch(error) {}
7629 return result;
7630 }());
7631 var repeat = function(count) {
7632 if (this == null) {
7633 throw TypeError();
7634 }
7635 var string = String(this);
7636 // `ToInteger`
7637 var n = count ? Number(count) : 0;
7638 if (n != n) { // better `isNaN`
7639 n = 0;
7640 }
7641 // Account for out-of-bounds indices
7642 if (n < 0 || n == Infinity) {
7643 throw RangeError();
7644 }
7645 var result = '';
7646 while (n) {
7647 if (n % 2 == 1) {
7648 result += string;
7649 }
7650 if (n > 1) {
7651 string += string;
7652 }
7653 n >>= 1;
7654 }
7655 return result;
7656 };
7657 if (defineProperty) {
7658 defineProperty(String.prototype, 'repeat', {
7659 'value': repeat,
7660 'configurable': true,
7661 'writable': true
7662 });
7663 } else {
7664 String.prototype.repeat = repeat;
7665 }
7666 }());
7667 }
7668
7669 var normalizeURI$1 = normalizeURI;
7670 var unescapeString$1 = unescapeString;
7671
7672 // Constants for character codes:
7673
7674 var C_NEWLINE = 10;
7675 var C_ASTERISK = 42;
7676 var C_UNDERSCORE = 95;
7677 var C_BACKTICK = 96;
7678 var C_OPEN_BRACKET = 91;
7679 var C_CLOSE_BRACKET = 93;
7680 var C_LESSTHAN = 60;
7681 var C_BANG = 33;
7682 var C_BACKSLASH$1 = 92;
7683 var C_AMPERSAND = 38;
7684 var C_OPEN_PAREN = 40;
7685 var C_CLOSE_PAREN = 41;
7686 var C_COLON = 58;
7687 var C_SINGLEQUOTE = 39;
7688 var C_DOUBLEQUOTE = 34;
7689
7690 // Some regexps used in inline parser:
7691
7692 var ESCAPABLE$1 = ESCAPABLE;
7693 var ESCAPED_CHAR = "\\\\" + ESCAPABLE$1;
7694
7695 var ENTITY$1 = ENTITY;
7696 var reHtmlTag$1 = reHtmlTag;
7697
7698 var rePunctuation = new RegExp(
7699 /^[!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]/
7700 );
7701
7702 var reLinkTitle = new RegExp(
7703 '^(?:"(' +
7704 ESCAPED_CHAR +
7705 '|[^"\\x00])*"' +
7706 "|" +
7707 "'(" +
7708 ESCAPED_CHAR +
7709 "|[^'\\x00])*'" +
7710 "|" +
7711 "\\((" +
7712 ESCAPED_CHAR +
7713 "|[^()\\x00])*\\))"
7714 );
7715
7716 var reLinkDestinationBraces = /^(?:<(?:[^<>\n\\\x00]|\\.)*>)/;
7717
7718 var reEscapable = new RegExp("^" + ESCAPABLE$1);
7719
7720 var reEntityHere = new RegExp("^" + ENTITY$1, "i");
7721
7722 var reTicks = /`+/;
7723
7724 var reTicksHere = /^`+/;
7725
7726 var reEllipses = /\.\.\./g;
7727
7728 var reDash = /--+/g;
7729
7730 var reEmailAutolink = /^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/;
7731
7732 var reAutolink = /^<[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*>/i;
7733
7734 var reSpnl = /^ *(?:\n *)?/;
7735
7736 var reWhitespaceChar = /^[ \t\n\x0b\x0c\x0d]/;
7737
7738 var reUnicodeWhitespaceChar = /^\s/;
7739
7740 var reFinalSpace = / *$/;
7741
7742 var reInitialSpace = /^ */;
7743
7744 var reSpaceAtEndOfLine = /^ *(?:\n|$)/;
7745
7746 var reLinkLabel = /^\[(?:[^\\\[\]]|\\.){0,1000}\]/s;
7747
7748 // Matches a string of non-special characters.
7749 var reMain = /^[^\n`\[\]\\!<&*_'"]+/m;
7750
7751 var text = function(s) {
7752 var node = new Node("text");
7753 node._literal = s;
7754 return node;
7755 };
7756
7757 // normalize a reference in reference link (remove []s, trim,
7758 // collapse internal space, unicode case fold.
7759 // See commonmark/commonmark.js#168.
7760 var normalizeReference = function(string) {
7761 return string
7762 .slice(1, string.length - 1)
7763 .trim()
7764 .replace(/[ \t\r\n]+/, " ")
7765 .toLowerCase()
7766 .toUpperCase();
7767 };
7768
7769 // INLINE PARSER
7770
7771 // These are methods of an InlineParser object, defined below.
7772 // An InlineParser keeps track of a subject (a string to be
7773 // parsed) and a position in that subject.
7774
7775 // If re matches at current position in the subject, advance
7776 // position in subject and return the match; otherwise return null.
7777 var match = function(re) {
7778 var m = re.exec(this.subject.slice(this.pos));
7779 if (m === null) {
7780 return null;
7781 } else {
7782 this.pos += m.index + m[0].length;
7783 return m[0];
7784 }
7785 };
7786
7787 // Returns the code for the character at the current subject position, or -1
7788 // there are no more characters.
7789 var peek = function() {
7790 if (this.pos < this.subject.length) {
7791 return this.subject.charCodeAt(this.pos);
7792 } else {
7793 return -1;
7794 }
7795 };
7796
7797 // Parse zero or more space characters, including at most one newline
7798 var spnl = function() {
7799 this.match(reSpnl);
7800 return true;
7801 };
7802
7803 // All of the parsers below try to match something at the current position
7804 // in the subject. If they succeed in matching anything, they
7805 // return the inline matched, advancing the subject.
7806
7807 // Attempt to parse backticks, adding either a backtick code span or a
7808 // literal sequence of backticks.
7809 var parseBackticks = function(block) {
7810 var ticks = this.match(reTicksHere);
7811 if (ticks === null) {
7812 return false;
7813 }
7814 var afterOpenTicks = this.pos;
7815 var matched;
7816 var node;
7817 var contents;
7818 while ((matched = this.match(reTicks)) !== null) {
7819 if (matched === ticks) {
7820 node = new Node("code");
7821 contents = this.subject
7822 .slice(afterOpenTicks, this.pos - ticks.length)
7823 .replace(/\n/gm, " ");
7824 if (
7825 contents.length > 0 &&
7826 contents.match(/[^ ]/) !== null &&
7827 contents[0] == " " &&
7828 contents[contents.length - 1] == " "
7829 ) {
7830 node._literal = contents.slice(1, contents.length - 1);
7831 } else {
7832 node._literal = contents;
7833 }
7834 const doc = this.options.autoDoc;
7835 if (doc) {
7836 const decl_hash = doc.detectDeclPath(contents);
7837 if (decl_hash) {
7838 var l = new Node("link");
7839 l.destination = decl_hash;
7840 l.appendChild(node);
7841 node = l;
7842 }
7843 }
7844 block.appendChild(node);
7845 return true;
7846 }
7847 }
7848 // If we got here, we didn't match a closing backtick sequence.
7849 this.pos = afterOpenTicks;
7850 block.appendChild(text(ticks));
7851 return true;
7852 };
7853
7854 // Parse a backslash-escaped special character, adding either the escaped
7855 // character, a hard line break (if the backslash is followed by a newline),
7856 // or a literal backslash to the block's children. Assumes current character
7857 // is a backslash.
7858 var parseBackslash = function(block) {
7859 var subj = this.subject;
7860 var node;
7861 this.pos += 1;
7862 if (this.peek() === C_NEWLINE) {
7863 this.pos += 1;
7864 node = new Node("linebreak");
7865 block.appendChild(node);
7866 } else if (reEscapable.test(subj.charAt(this.pos))) {
7867 block.appendChild(text(subj.charAt(this.pos)));
7868 this.pos += 1;
7869 } else {
7870 block.appendChild(text("\\"));
7871 }
7872 return true;
7873 };
7874
7875 // Attempt to parse an autolink (URL or email in pointy brackets).
7876 var parseAutolink = function(block) {
7877 var m;
7878 var dest;
7879 var node;
7880 if ((m = this.match(reEmailAutolink))) {
7881 dest = m.slice(1, m.length - 1);
7882 node = new Node("link");
7883 node._destination = normalizeURI$1("mailto:" + dest);
7884 node._title = "";
7885 node.appendChild(text(dest));
7886 block.appendChild(node);
7887 return true;
7888 } else if ((m = this.match(reAutolink))) {
7889 dest = m.slice(1, m.length - 1);
7890 node = new Node("link");
7891 node._destination = normalizeURI$1(dest);
7892 node._title = "";
7893 node.appendChild(text(dest));
7894 block.appendChild(node);
7895 return true;
7896 } else {
7897 return false;
7898 }
7899 };
7900
7901 // Attempt to parse a raw HTML tag.
7902 var parseHtmlTag = function(block) {
7903 var m = this.match(reHtmlTag$1);
7904 if (m === null) {
7905 return false;
7906 } else {
7907 var node = new Node("html_inline");
7908 node._literal = m;
7909 block.appendChild(node);
7910 return true;
7911 }
7912 };
7913
7914 // Scan a sequence of characters with code cc, and return information about
7915 // the number of delimiters and whether they are positioned such that
7916 // they can open and/or close emphasis or strong emphasis. A utility
7917 // function for strong/emph parsing.
7918 var scanDelims = function(cc) {
7919 var numdelims = 0;
7920 var char_before, char_after, cc_after;
7921 var startpos = this.pos;
7922 var left_flanking, right_flanking, can_open, can_close;
7923 var after_is_whitespace,
7924 after_is_punctuation,
7925 before_is_whitespace,
7926 before_is_punctuation;
7927
7928 if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE) {
7929 numdelims++;
7930 this.pos++;
7931 } else {
7932 while (this.peek() === cc) {
7933 numdelims++;
7934 this.pos++;
7935 }
7936 }
7937
7938 if (numdelims === 0) {
7939 return null;
7940 }
7941
7942 char_before = startpos === 0 ? "\n" : this.subject.charAt(startpos - 1);
7943
7944 cc_after = this.peek();
7945 if (cc_after === -1) {
7946 char_after = "\n";
7947 } else {
7948 char_after = fromCodePoint(cc_after);
7949 }
7950
7951 after_is_whitespace = reUnicodeWhitespaceChar.test(char_after);
7952 after_is_punctuation = rePunctuation.test(char_after);
7953 before_is_whitespace = reUnicodeWhitespaceChar.test(char_before);
7954 before_is_punctuation = rePunctuation.test(char_before);
7955
7956 left_flanking =
7957 !after_is_whitespace &&
7958 (!after_is_punctuation ||
7959 before_is_whitespace ||
7960 before_is_punctuation);
7961 right_flanking =
7962 !before_is_whitespace &&
7963 (!before_is_punctuation || after_is_whitespace || after_is_punctuation);
7964 if (cc === C_UNDERSCORE) {
7965 can_open = left_flanking && (!right_flanking || before_is_punctuation);
7966 can_close = right_flanking && (!left_flanking || after_is_punctuation);
7967 } else if (cc === C_SINGLEQUOTE || cc === C_DOUBLEQUOTE) {
7968 can_open = left_flanking && !right_flanking;
7969 can_close = right_flanking;
7970 } else {
7971 can_open = left_flanking;
7972 can_close = right_flanking;
7973 }
7974 this.pos = startpos;
7975 return { numdelims: numdelims, can_open: can_open, can_close: can_close };
7976 };
7977
7978 // Handle a delimiter marker for emphasis or a quote.
7979 var handleDelim = function(cc, block) {
7980 var res = this.scanDelims(cc);
7981 if (!res) {
7982 return false;
7983 }
7984 var numdelims = res.numdelims;
7985 var startpos = this.pos;
7986 var contents;
7987
7988 this.pos += numdelims;
7989 if (cc === C_SINGLEQUOTE) {
7990 contents = "\u2019";
7991 } else if (cc === C_DOUBLEQUOTE) {
7992 contents = "\u201C";
7993 } else {
7994 contents = this.subject.slice(startpos, this.pos);
7995 }
7996 var node = text(contents);
7997 block.appendChild(node);
7998
7999 // Add entry to stack for this opener
8000 if (
8001 (res.can_open || res.can_close) &&
8002 (this.options.smart || (cc !== C_SINGLEQUOTE && cc !== C_DOUBLEQUOTE))
8003 ) {
8004 this.delimiters = {
8005 cc: cc,
8006 numdelims: numdelims,
8007 origdelims: numdelims,
8008 node: node,
8009 previous: this.delimiters,
8010 next: null,
8011 can_open: res.can_open,
8012 can_close: res.can_close
8013 };
8014 if (this.delimiters.previous !== null) {
8015 this.delimiters.previous.next = this.delimiters;
8016 }
8017 }
8018
8019 return true;
8020 };
8021
8022 var removeDelimiter = function(delim) {
8023 if (delim.previous !== null) {
8024 delim.previous.next = delim.next;
8025 }
8026 if (delim.next === null) {
8027 // top of stack
8028 this.delimiters = delim.previous;
8029 } else {
8030 delim.next.previous = delim.previous;
8031 }
8032 };
8033
8034 var removeDelimitersBetween = function(bottom, top) {
8035 if (bottom.next !== top) {
8036 bottom.next = top;
8037 top.previous = bottom;
8038 }
8039 };
8040
8041 var processEmphasis = function(stack_bottom) {
8042 var opener, closer, old_closer;
8043 var opener_inl, closer_inl;
8044 var tempstack;
8045 var use_delims;
8046 var tmp, next;
8047 var opener_found;
8048 var openers_bottom = [];
8049 var openers_bottom_index;
8050 var odd_match = false;
8051
8052 for (var i = 0; i < 8; i++) {
8053 openers_bottom[i] = stack_bottom;
8054 }
8055 // find first closer above stack_bottom:
8056 closer = this.delimiters;
8057 while (closer !== null && closer.previous !== stack_bottom) {
8058 closer = closer.previous;
8059 }
8060 // move forward, looking for closers, and handling each
8061 while (closer !== null) {
8062 var closercc = closer.cc;
8063 if (!closer.can_close) {
8064 closer = closer.next;
8065 } else {
8066 // found emphasis closer. now look back for first matching opener:
8067 opener = closer.previous;
8068 opener_found = false;
8069 switch (closercc) {
8070 case C_SINGLEQUOTE:
8071 openers_bottom_index = 0;
8072 break;
8073 case C_DOUBLEQUOTE:
8074 openers_bottom_index = 1;
8075 break;
8076 case C_UNDERSCORE:
8077 openers_bottom_index = 2;
8078 break;
8079 case C_ASTERISK:
8080 openers_bottom_index = 3 + (closer.can_open ? 3 : 0)
8081 + (closer.origdelims % 3);
8082 break;
8083 }
8084 while (
8085 opener !== null &&
8086 opener !== stack_bottom &&
8087 opener !== openers_bottom[openers_bottom_index]
8088 ) {
8089 odd_match =
8090 (closer.can_open || opener.can_close) &&
8091 closer.origdelims % 3 !== 0 &&
8092 (opener.origdelims + closer.origdelims) % 3 === 0;
8093 if (opener.cc === closer.cc && opener.can_open && !odd_match) {
8094 opener_found = true;
8095 break;
8096 }
8097 opener = opener.previous;
8098 }
8099 old_closer = closer;
8100
8101 if (closercc === C_ASTERISK || closercc === C_UNDERSCORE) {
8102 if (!opener_found) {
8103 closer = closer.next;
8104 } else {
8105 // calculate actual number of delimiters used from closer
8106 use_delims =
8107 closer.numdelims >= 2 && opener.numdelims >= 2 ? 2 : 1;
8108
8109 opener_inl = opener.node;
8110 closer_inl = closer.node;
8111
8112 // remove used delimiters from stack elts and inlines
8113 opener.numdelims -= use_delims;
8114 closer.numdelims -= use_delims;
8115 opener_inl._literal = opener_inl._literal.slice(
8116 0,
8117 opener_inl._literal.length - use_delims
8118 );
8119 closer_inl._literal = closer_inl._literal.slice(
8120 0,
8121 closer_inl._literal.length - use_delims
8122 );
8123
8124 // build contents for new emph element
8125 var emph = new Node(use_delims === 1 ? "emph" : "strong");
8126
8127 tmp = opener_inl._next;
8128 while (tmp && tmp !== closer_inl) {
8129 next = tmp._next;
8130 tmp.unlink();
8131 emph.appendChild(tmp);
8132 tmp = next;
8133 }
8134
8135 opener_inl.insertAfter(emph);
8136
8137 // remove elts between opener and closer in delimiters stack
8138 removeDelimitersBetween(opener, closer);
8139
8140 // if opener has 0 delims, remove it and the inline
8141 if (opener.numdelims === 0) {
8142 opener_inl.unlink();
8143 this.removeDelimiter(opener);
8144 }
8145
8146 if (closer.numdelims === 0) {
8147 closer_inl.unlink();
8148 tempstack = closer.next;
8149 this.removeDelimiter(closer);
8150 closer = tempstack;
8151 }
8152 }
8153 } else if (closercc === C_SINGLEQUOTE) {
8154 closer.node._literal = "\u2019";
8155 if (opener_found) {
8156 opener.node._literal = "\u2018";
8157 }
8158 closer = closer.next;
8159 } else if (closercc === C_DOUBLEQUOTE) {
8160 closer.node._literal = "\u201D";
8161 if (opener_found) {
8162 opener.node.literal = "\u201C";
8163 }
8164 closer = closer.next;
8165 }
8166 if (!opener_found) {
8167 // Set lower bound for future searches for openers:
8168 openers_bottom[openers_bottom_index] =
8169 old_closer.previous;
8170 if (!old_closer.can_open) {
8171 // We can remove a closer that can't be an opener,
8172 // once we've seen there's no matching opener:
8173 this.removeDelimiter(old_closer);
8174 }
8175 }
8176 }
8177 }
8178
8179 // remove all delimiters
8180 while (this.delimiters !== null && this.delimiters !== stack_bottom) {
8181 this.removeDelimiter(this.delimiters);
8182 }
8183 };
8184
8185 // Attempt to parse link title (sans quotes), returning the string
8186 // or null if no match.
8187 var parseLinkTitle = function() {
8188 var title = this.match(reLinkTitle);
8189 if (title === null) {
8190 return null;
8191 } else {
8192 // chop off quotes from title and unescape:
8193 return unescapeString$1(title.substr(1, title.length - 2));
8194 }
8195 };
8196
8197 // Attempt to parse link destination, returning the string or
8198 // null if no match.
8199 var parseLinkDestination = function() {
8200 var res = this.match(reLinkDestinationBraces);
8201 if (res === null) {
8202 if (this.peek() === C_LESSTHAN) {
8203 return null;
8204 }
8205 // TODO handrolled parser; res should be null or the string
8206 var savepos = this.pos;
8207 var openparens = 0;
8208 var c;
8209 while ((c = this.peek()) !== -1) {
8210 if (
8211 c === C_BACKSLASH$1 &&
8212 reEscapable.test(this.subject.charAt(this.pos + 1))
8213 ) {
8214 this.pos += 1;
8215 if (this.peek() !== -1) {
8216 this.pos += 1;
8217 }
8218 } else if (c === C_OPEN_PAREN) {
8219 this.pos += 1;
8220 openparens += 1;
8221 } else if (c === C_CLOSE_PAREN) {
8222 if (openparens < 1) {
8223 break;
8224 } else {
8225 this.pos += 1;
8226 openparens -= 1;
8227 }
8228 } else if (reWhitespaceChar.exec(fromCodePoint(c)) !== null) {
8229 break;
8230 } else {
8231 this.pos += 1;
8232 }
8233 }
8234 if (this.pos === savepos && c !== C_CLOSE_PAREN) {
8235 return null;
8236 }
8237 if (openparens !== 0) {
8238 return null;
8239 }
8240 res = this.subject.substr(savepos, this.pos - savepos);
8241 return normalizeURI$1(unescapeString$1(res));
8242 } else {
8243 // chop off surrounding <..>:
8244 return normalizeURI$1(unescapeString$1(res.substr(1, res.length - 2)));
8245 }
8246 };
8247
8248 // Attempt to parse a link label, returning number of characters parsed.
8249 var parseLinkLabel = function() {
8250 var m = this.match(reLinkLabel);
8251 if (m === null || m.length > 1001) {
8252 return 0;
8253 } else {
8254 return m.length;
8255 }
8256 };
8257
8258 // Add open bracket to delimiter stack and add a text node to block's children.
8259 var parseOpenBracket = function(block) {
8260 var startpos = this.pos;
8261 this.pos += 1;
8262
8263 var node = text("[");
8264 block.appendChild(node);
8265
8266 // Add entry to stack for this opener
8267 this.addBracket(node, startpos, false);
8268 return true;
8269 };
8270
8271 // IF next character is [, and ! delimiter to delimiter stack and
8272 // add a text node to block's children. Otherwise just add a text node.
8273 var parseBang = function(block) {
8274 var startpos = this.pos;
8275 this.pos += 1;
8276 if (this.peek() === C_OPEN_BRACKET) {
8277 this.pos += 1;
8278
8279 var node = text("![");
8280 block.appendChild(node);
8281
8282 // Add entry to stack for this opener
8283 this.addBracket(node, startpos + 1, true);
8284 } else {
8285 block.appendChild(text("!"));
8286 }
8287 return true;
8288 };
8289
8290 // Try to match close bracket against an opening in the delimiter
8291 // stack. Add either a link or image, or a plain [ character,
8292 // to block's children. If there is a matching delimiter,
8293 // remove it from the delimiter stack.
8294 var parseCloseBracket = function(block) {
8295 var startpos;
8296 var is_image;
8297 var dest;
8298 var title;
8299 var matched = false;
8300 var reflabel;
8301 var opener;
8302
8303 this.pos += 1;
8304 startpos = this.pos;
8305
8306 // get last [ or ![
8307 opener = this.brackets;
8308
8309 if (opener === null) {
8310 // no matched opener, just return a literal
8311 block.appendChild(text("]"));
8312 return true;
8313 }
8314
8315 if (!opener.active) {
8316 // no matched opener, just return a literal
8317 block.appendChild(text("]"));
8318 // take opener off brackets stack
8319 this.removeBracket();
8320 return true;
8321 }
8322
8323 // If we got here, open is a potential opener
8324 is_image = opener.image;
8325
8326 // Check to see if we have a link/image
8327
8328 var savepos = this.pos;
8329
8330 // Inline link?
8331 if (this.peek() === C_OPEN_PAREN) {
8332 this.pos++;
8333 if (
8334 this.spnl() &&
8335 (dest = this.parseLinkDestination()) !== null &&
8336 this.spnl() &&
8337 // make sure there's a space before the title:
8338 ((reWhitespaceChar.test(this.subject.charAt(this.pos - 1)) &&
8339 (title = this.parseLinkTitle())) ||
8340 true) &&
8341 this.spnl() &&
8342 this.peek() === C_CLOSE_PAREN
8343 ) {
8344 this.pos += 1;
8345 matched = true;
8346 } else {
8347 this.pos = savepos;
8348 }
8349 }
8350
8351 if (!matched) {
8352 // Next, see if there's a link label
8353 var beforelabel = this.pos;
8354 var n = this.parseLinkLabel();
8355 if (n > 2) {
8356 reflabel = this.subject.slice(beforelabel, beforelabel + n);
8357 } else if (!opener.bracketAfter) {
8358 // Empty or missing second label means to use the first label as the reference.
8359 // The reference must not contain a bracket. If we know there's a bracket, we don't even bother checking it.
8360 reflabel = this.subject.slice(opener.index, startpos);
8361 }
8362 if (n === 0) {
8363 // If shortcut reference link, rewind before spaces we skipped.
8364 this.pos = savepos;
8365 }
8366
8367 if (reflabel) {
8368 // lookup rawlabel in refmap
8369 var link = this.refmap[normalizeReference(reflabel)];
8370 if (link) {
8371 dest = link.destination;
8372 title = link.title;
8373 matched = true;
8374 }
8375 }
8376 }
8377
8378 if (matched) {
8379 var node = new Node(is_image ? "image" : "link");
8380 node._destination = dest;
8381 node._title = title || "";
8382
8383 var tmp, next;
8384 tmp = opener.node._next;
8385 while (tmp) {
8386 next = tmp._next;
8387 tmp.unlink();
8388 node.appendChild(tmp);
8389 tmp = next;
8390 }
8391 block.appendChild(node);
8392 this.processEmphasis(opener.previousDelimiter);
8393 this.removeBracket();
8394 opener.node.unlink();
8395
8396 // We remove this bracket and processEmphasis will remove later delimiters.
8397 // Now, for a link, we also deactivate earlier link openers.
8398 // (no links in links)
8399 if (!is_image) {
8400 opener = this.brackets;
8401 while (opener !== null) {
8402 if (!opener.image) {
8403 opener.active = false; // deactivate this opener
8404 }
8405 opener = opener.previous;
8406 }
8407 }
8408
8409 return true;
8410 } else {
8411 // no match
8412
8413 this.removeBracket(); // remove this opener from stack
8414 this.pos = startpos;
8415 block.appendChild(text("]"));
8416 return true;
8417 }
8418 };
8419
8420 var addBracket = function(node, index, image) {
8421 if (this.brackets !== null) {
8422 this.brackets.bracketAfter = true;
8423 }
8424 this.brackets = {
8425 node: node,
8426 previous: this.brackets,
8427 previousDelimiter: this.delimiters,
8428 index: index,
8429 image: image,
8430 active: true
8431 };
8432 };
8433
8434 var removeBracket = function() {
8435 this.brackets = this.brackets.previous;
8436 };
8437
8438 // Attempt to parse an entity.
8439 var parseEntity = function(block) {
8440 var m;
8441 if ((m = this.match(reEntityHere))) {
8442 block.appendChild(text(lib_9(m)));
8443 return true;
8444 } else {
8445 return false;
8446 }
8447 };
8448
8449 // Parse a run of ordinary characters, or a single character with
8450 // a special meaning in markdown, as a plain string.
8451 var parseString = function(block) {
8452 var m;
8453 if ((m = this.match(reMain))) {
8454 if (this.options.smart) {
8455 block.appendChild(
8456 text(
8457 m
8458 .replace(reEllipses, "\u2026")
8459 .replace(reDash, function(chars) {
8460 var enCount = 0;
8461 var emCount = 0;
8462 if (chars.length % 3 === 0) {
8463 // If divisible by 3, use all em dashes
8464 emCount = chars.length / 3;
8465 } else if (chars.length % 2 === 0) {
8466 // If divisible by 2, use all en dashes
8467 enCount = chars.length / 2;
8468 } else if (chars.length % 3 === 2) {
8469 // If 2 extra dashes, use en dash for last 2; em dashes for rest
8470 enCount = 1;
8471 emCount = (chars.length - 2) / 3;
8472 } else {
8473 // Use en dashes for last 4 hyphens; em dashes for rest
8474 enCount = 2;
8475 emCount = (chars.length - 4) / 3;
8476 }
8477 return (
8478 "\u2014".repeat(emCount) +
8479 "\u2013".repeat(enCount)
8480 );
8481 })
8482 )
8483 );
8484 } else {
8485 block.appendChild(text(m));
8486 }
8487 return true;
8488 } else {
8489 return false;
8490 }
8491 };
8492
8493 // Parse a newline. If it was preceded by two spaces, return a hard
8494 // line break; otherwise a soft line break.
8495 var parseNewline = function(block) {
8496 this.pos += 1; // assume we're at a \n
8497 // check previous node for trailing spaces
8498 var lastc = block._lastChild;
8499 if (
8500 lastc &&
8501 lastc.type === "text" &&
8502 lastc._literal[lastc._literal.length - 1] === " "
8503 ) {
8504 var hardbreak = lastc._literal[lastc._literal.length - 2] === " ";
8505 lastc._literal = lastc._literal.replace(reFinalSpace, "");
8506 block.appendChild(new Node(hardbreak ? "linebreak" : "softbreak"));
8507 } else {
8508 block.appendChild(new Node("softbreak"));
8509 }
8510 this.match(reInitialSpace); // gobble leading spaces in next line
8511 return true;
8512 };
8513
8514 // Attempt to parse a link reference, modifying refmap.
8515 var parseReference = function(s, refmap) {
8516 this.subject = s;
8517 this.pos = 0;
8518 var rawlabel;
8519 var dest;
8520 var title;
8521 var matchChars;
8522 var startpos = this.pos;
8523
8524 // label:
8525 matchChars = this.parseLinkLabel();
8526 if (matchChars === 0) {
8527 return 0;
8528 } else {
8529 rawlabel = this.subject.substr(0, matchChars);
8530 }
8531
8532 // colon:
8533 if (this.peek() === C_COLON) {
8534 this.pos++;
8535 } else {
8536 this.pos = startpos;
8537 return 0;
8538 }
8539
8540 // link url
8541 this.spnl();
8542
8543 dest = this.parseLinkDestination();
8544 if (dest === null) {
8545 this.pos = startpos;
8546 return 0;
8547 }
8548
8549 var beforetitle = this.pos;
8550 this.spnl();
8551 if (this.pos !== beforetitle) {
8552 title = this.parseLinkTitle();
8553 }
8554 if (title === null) {
8555 title = "";
8556 // rewind before spaces
8557 this.pos = beforetitle;
8558 }
8559
8560 // make sure we're at line end:
8561 var atLineEnd = true;
8562 if (this.match(reSpaceAtEndOfLine) === null) {
8563 if (title === "") {
8564 atLineEnd = false;
8565 } else {
8566 // the potential title we found is not at the line end,
8567 // but it could still be a legal link reference if we
8568 // discard the title
8569 title = "";
8570 // rewind before spaces
8571 this.pos = beforetitle;
8572 // and instead check if the link URL is at the line end
8573 atLineEnd = this.match(reSpaceAtEndOfLine) !== null;
8574 }
8575 }
8576
8577 if (!atLineEnd) {
8578 this.pos = startpos;
8579 return 0;
8580 }
8581
8582 var normlabel = normalizeReference(rawlabel);
8583 if (normlabel === "") {
8584 // label must contain non-whitespace characters
8585 this.pos = startpos;
8586 return 0;
8587 }
8588
8589 if (!refmap[normlabel]) {
8590 refmap[normlabel] = { destination: dest, title: title };
8591 }
8592 return this.pos - startpos;
8593 };
8594
8595 // Parse the next inline element in subject, advancing subject position.
8596 // On success, add the result to block's children and return true.
8597 // On failure, return false.
8598 var parseInline = function(block) {
8599 var res = false;
8600 var c = this.peek();
8601 if (c === -1) {
8602 return false;
8603 }
8604 switch (c) {
8605 case C_NEWLINE:
8606 res = this.parseNewline(block);
8607 break;
8608 case C_BACKSLASH$1:
8609 res = this.parseBackslash(block);
8610 break;
8611 case C_BACKTICK:
8612 res = this.parseBackticks(block);
8613 break;
8614 case C_ASTERISK:
8615 case C_UNDERSCORE:
8616 res = this.handleDelim(c, block);
8617 break;
8618 case C_SINGLEQUOTE:
8619 case C_DOUBLEQUOTE:
8620 res = this.options.smart && this.handleDelim(c, block);
8621 break;
8622 case C_OPEN_BRACKET:
8623 res = this.parseOpenBracket(block);
8624 break;
8625 case C_BANG:
8626 res = this.parseBang(block);
8627 break;
8628 case C_CLOSE_BRACKET:
8629 res = this.parseCloseBracket(block);
8630 break;
8631 case C_LESSTHAN:
8632 res = this.parseAutolink(block) || this.parseHtmlTag(block);
8633 break;
8634 case C_AMPERSAND:
8635 res = this.parseEntity(block);
8636 break;
8637 default:
8638 res = this.parseString(block);
8639 break;
8640 }
8641 if (!res) {
8642 this.pos += 1;
8643 block.appendChild(text(fromCodePoint(c)));
8644 }
8645
8646 return true;
8647 };
8648
8649 // Parse string content in block into inline children,
8650 // using refmap to resolve references.
8651 var parseInlines = function(block) {
8652 this.subject = block._string_content.trim();
8653 this.pos = 0;
8654 this.delimiters = null;
8655 this.brackets = null;
8656 while (this.parseInline(block)) {}
8657 block._string_content = null; // allow raw string to be garbage collected
8658 this.processEmphasis(null);
8659 };
8660
8661 // The InlineParser object.
8662 function InlineParser(options) {
8663 return {
8664 subject: "",
8665 delimiters: null, // used by handleDelim method
8666 brackets: null,
8667 pos: 0,
8668 refmap: {},
8669 match: match,
8670 peek: peek,
8671 spnl: spnl,
8672 parseBackticks: parseBackticks,
8673 parseBackslash: parseBackslash,
8674 parseAutolink: parseAutolink,
8675 parseHtmlTag: parseHtmlTag,
8676 scanDelims: scanDelims,
8677 handleDelim: handleDelim,
8678 parseLinkTitle: parseLinkTitle,
8679 parseLinkDestination: parseLinkDestination,
8680 parseLinkLabel: parseLinkLabel,
8681 parseOpenBracket: parseOpenBracket,
8682 parseBang: parseBang,
8683 parseCloseBracket: parseCloseBracket,
8684 addBracket: addBracket,
8685 removeBracket: removeBracket,
8686 parseEntity: parseEntity,
8687 parseString: parseString,
8688 parseNewline: parseNewline,
8689 parseReference: parseReference,
8690 parseInline: parseInline,
8691 processEmphasis: processEmphasis,
8692 removeDelimiter: removeDelimiter,
8693 options: options || {},
8694 parse: parseInlines
8695 };
8696 }
8697
8698 var CODE_INDENT = 4;
8699
8700 var C_TAB = 9;
8701 var C_NEWLINE$1 = 10;
8702 var C_GREATERTHAN = 62;
8703 var C_LESSTHAN$1 = 60;
8704 var C_SPACE = 32;
8705 var C_OPEN_BRACKET$1 = 91;
8706
8707 var reHtmlBlockOpen = [
8708 /./, // dummy for 0
8709 /^<(?:script|pre|textarea|style)(?:\s|>|$)/i,
8710 /^<!--/,
8711 /^<[?]/,
8712 /^<![A-Z]/,
8713 /^<!\[CDATA\[/,
8714 /^<[/]?(?:address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[123456]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(?:\s|[/]?[>]|$)/i,
8715 new RegExp("^(?:" + OPENTAG + "|" + CLOSETAG + ")\\s*$", "i")
8716 ];
8717
8718 var reHtmlBlockClose = [
8719 /./, // dummy for 0
8720 /<\/(?:script|pre|textarea|style)>/i,
8721 /-->/,
8722 /\?>/,
8723 />/,
8724 /\]\]>/
8725 ];
8726
8727 var reThematicBreak = /^(?:\*[ \t]*){3,}$|^(?:_[ \t]*){3,}$|^(?:-[ \t]*){3,}$/;
8728
8729 var reMaybeSpecial = /^[#`~*+_=<>0-9-]/;
8730
8731 var reNonSpace = /[^ \t\f\v\r\n]/;
8732
8733 var reBulletListMarker = /^[*+-]/;
8734
8735 var reOrderedListMarker = /^(\d{1,9})([.)])/;
8736
8737 var reATXHeadingMarker = /^#{1,6}(?:[ \t]+|$)/;
8738
8739 var reCodeFence = /^`{3,}(?!.*`)|^~{3,}/;
8740
8741 var reClosingCodeFence = /^(?:`{3,}|~{3,})(?= *$)/;
8742
8743 var reSetextHeadingLine = /^(?:=+|-+)[ \t]*$/;
8744
8745 var reLineEnding = /\r\n|\n|\r/;
8746
8747 // Returns true if string contains only space characters.
8748 var isBlank = function(s) {
8749 return !reNonSpace.test(s);
8750 };
8751
8752 var isSpaceOrTab = function(c) {
8753 return c === C_SPACE || c === C_TAB;
8754 };
8755
8756 var peek$1 = function(ln, pos) {
8757 if (pos < ln.length) {
8758 return ln.charCodeAt(pos);
8759 } else {
8760 return -1;
8761 }
8762 };
8763
8764 // DOC PARSER
8765
8766 // These are methods of a Parser object, defined below.
8767
8768 // Returns true if block ends with a blank line, descending if needed
8769 // into lists and sublists.
8770 var endsWithBlankLine = function(block) {
8771 while (block) {
8772 if (block._lastLineBlank) {
8773 return true;
8774 }
8775 var t = block.type;
8776 if (!block._lastLineChecked && (t === "list" || t === "item")) {
8777 block._lastLineChecked = true;
8778 block = block._lastChild;
8779 } else {
8780 block._lastLineChecked = true;
8781 break;
8782 }
8783 }
8784 return false;
8785 };
8786
8787 // Add a line to the block at the tip. We assume the tip
8788 // can accept lines -- that check should be done before calling this.
8789 var addLine = function() {
8790 if (this.partiallyConsumedTab) {
8791 this.offset += 1; // skip over tab
8792 // add space characters:
8793 var charsToTab = 4 - (this.column % 4);
8794 this.tip._string_content += " ".repeat(charsToTab);
8795 }
8796 this.tip._string_content += this.currentLine.slice(this.offset) + "\n";
8797 };
8798
8799 // Add block of type tag as a child of the tip. If the tip can't
8800 // accept children, close and finalize it and try its parent,
8801 // and so on til we find a block that can accept children.
8802 var addChild = function(tag, offset) {
8803 while (!this.blocks[this.tip.type].canContain(tag)) {
8804 this.finalize(this.tip, this.lineNumber - 1);
8805 }
8806
8807 var column_number = offset + 1; // offset 0 = column 1
8808 var newBlock = new Node(tag, [
8809 [this.lineNumber, column_number],
8810 [0, 0]
8811 ]);
8812 newBlock._string_content = "";
8813 this.tip.appendChild(newBlock);
8814 this.tip = newBlock;
8815 return newBlock;
8816 };
8817
8818 // Parse a list marker and return data on the marker (type,
8819 // start, delimiter, bullet character, padding) or null.
8820 var parseListMarker = function(parser, container) {
8821 var rest = parser.currentLine.slice(parser.nextNonspace);
8822 var match;
8823 var nextc;
8824 var spacesStartCol;
8825 var spacesStartOffset;
8826 var data = {
8827 type: null,
8828 tight: true, // lists are tight by default
8829 bulletChar: null,
8830 start: null,
8831 delimiter: null,
8832 padding: null,
8833 markerOffset: parser.indent
8834 };
8835 if (parser.indent >= 4) {
8836 return null;
8837 }
8838 if ((match = rest.match(reBulletListMarker))) {
8839 data.type = "bullet";
8840 data.bulletChar = match[0][0];
8841 } else if (
8842 (match = rest.match(reOrderedListMarker)) &&
8843 (container.type !== "paragraph" || match[1] == 1)
8844 ) {
8845 data.type = "ordered";
8846 data.start = parseInt(match[1]);
8847 data.delimiter = match[2];
8848 } else {
8849 return null;
8850 }
8851 // make sure we have spaces after
8852 nextc = peek$1(parser.currentLine, parser.nextNonspace + match[0].length);
8853 if (!(nextc === -1 || nextc === C_TAB || nextc === C_SPACE)) {
8854 return null;
8855 }
8856
8857 // if it interrupts paragraph, make sure first line isn't blank
8858 if (
8859 container.type === "paragraph" &&
8860 !parser.currentLine
8861 .slice(parser.nextNonspace + match[0].length)
8862 .match(reNonSpace)
8863 ) {
8864 return null;
8865 }
8866
8867 // we've got a match! advance offset and calculate padding
8868 parser.advanceNextNonspace(); // to start of marker
8869 parser.advanceOffset(match[0].length, true); // to end of marker
8870 spacesStartCol = parser.column;
8871 spacesStartOffset = parser.offset;
8872 do {
8873 parser.advanceOffset(1, true);
8874 nextc = peek$1(parser.currentLine, parser.offset);
8875 } while (parser.column - spacesStartCol < 5 && isSpaceOrTab(nextc));
8876 var blank_item = peek$1(parser.currentLine, parser.offset) === -1;
8877 var spaces_after_marker = parser.column - spacesStartCol;
8878 if (spaces_after_marker >= 5 || spaces_after_marker < 1 || blank_item) {
8879 data.padding = match[0].length + 1;
8880 parser.column = spacesStartCol;
8881 parser.offset = spacesStartOffset;
8882 if (isSpaceOrTab(peek$1(parser.currentLine, parser.offset))) {
8883 parser.advanceOffset(1, true);
8884 }
8885 } else {
8886 data.padding = match[0].length + spaces_after_marker;
8887 }
8888 return data;
8889 };
8890
8891 // Returns true if the two list items are of the same type,
8892 // with the same delimiter and bullet character. This is used
8893 // in agglomerating list items into lists.
8894 var listsMatch = function(list_data, item_data) {
8895 return (
8896 list_data.type === item_data.type &&
8897 list_data.delimiter === item_data.delimiter &&
8898 list_data.bulletChar === item_data.bulletChar
8899 );
8900 };
8901
8902 // Finalize and close any unmatched blocks.
8903 var closeUnmatchedBlocks = function() {
8904 if (!this.allClosed) {
8905 // finalize any blocks not matched
8906 while (this.oldtip !== this.lastMatchedContainer) {
8907 var parent = this.oldtip._parent;
8908 this.finalize(this.oldtip, this.lineNumber - 1);
8909 this.oldtip = parent;
8910 }
8911 this.allClosed = true;
8912 }
8913 };
8914
8915 // 'finalize' is run when the block is closed.
8916 // 'continue' is run to check whether the block is continuing
8917 // at a certain line and offset (e.g. whether a block quote
8918 // contains a `>`. It returns 0 for matched, 1 for not matched,
8919 // and 2 for "we've dealt with this line completely, go to next."
8920 var blocks = {
8921 document: {
8922 continue: function() {
8923 return 0;
8924 },
8925 finalize: function() {
8926 return;
8927 },
8928 canContain: function(t) {
8929 return t !== "item";
8930 },
8931 acceptsLines: false
8932 },
8933 list: {
8934 continue: function() {
8935 return 0;
8936 },
8937 finalize: function(parser, block) {
8938 var item = block._firstChild;
8939 while (item) {
8940 // check for non-final list item ending with blank line:
8941 if (endsWithBlankLine(item) && item._next) {
8942 block._listData.tight = false;
8943 break;
8944 }
8945 // recurse into children of list item, to see if there are
8946 // spaces between any of them:
8947 var subitem = item._firstChild;
8948 while (subitem) {
8949 if (
8950 endsWithBlankLine(subitem) &&
8951 (item._next || subitem._next)
8952 ) {
8953 block._listData.tight = false;
8954 break;
8955 }
8956 subitem = subitem._next;
8957 }
8958 item = item._next;
8959 }
8960 },
8961 canContain: function(t) {
8962 return t === "item";
8963 },
8964 acceptsLines: false
8965 },
8966 block_quote: {
8967 continue: function(parser) {
8968 var ln = parser.currentLine;
8969 if (
8970 !parser.indented &&
8971 peek$1(ln, parser.nextNonspace) === C_GREATERTHAN
8972 ) {
8973 parser.advanceNextNonspace();
8974 parser.advanceOffset(1, false);
8975 if (isSpaceOrTab(peek$1(ln, parser.offset))) {
8976 parser.advanceOffset(1, true);
8977 }
8978 } else {
8979 return 1;
8980 }
8981 return 0;
8982 },
8983 finalize: function() {
8984 return;
8985 },
8986 canContain: function(t) {
8987 return t !== "item";
8988 },
8989 acceptsLines: false
8990 },
8991 item: {
8992 continue: function(parser, container) {
8993 if (parser.blank) {
8994 if (container._firstChild == null) {
8995 // Blank line after empty list item
8996 return 1;
8997 } else {
8998 parser.advanceNextNonspace();
8999 }
9000 } else if (
9001 parser.indent >=
9002 container._listData.markerOffset + container._listData.padding
9003 ) {
9004 parser.advanceOffset(
9005 container._listData.markerOffset +
9006 container._listData.padding,
9007 true
9008 );
9009 } else {
9010 return 1;
9011 }
9012 return 0;
9013 },
9014 finalize: function() {
9015 return;
9016 },
9017 canContain: function(t) {
9018 return t !== "item";
9019 },
9020 acceptsLines: false
9021 },
9022 heading: {
9023 continue: function() {
9024 // a heading can never container > 1 line, so fail to match:
9025 return 1;
9026 },
9027 finalize: function() {
9028 return;
9029 },
9030 canContain: function() {
9031 return false;
9032 },
9033 acceptsLines: false
9034 },
9035 thematic_break: {
9036 continue: function() {
9037 // a thematic break can never container > 1 line, so fail to match:
9038 return 1;
9039 },
9040 finalize: function() {
9041 return;
9042 },
9043 canContain: function() {
9044 return false;
9045 },
9046 acceptsLines: false
9047 },
9048 code_block: {
9049 continue: function(parser, container) {
9050 var ln = parser.currentLine;
9051 var indent = parser.indent;
9052 if (container._isFenced) {
9053 // fenced
9054 var match =
9055 indent <= 3 &&
9056 ln.charAt(parser.nextNonspace) === container._fenceChar &&
9057 ln.slice(parser.nextNonspace).match(reClosingCodeFence);
9058 if (match && match[0].length >= container._fenceLength) {
9059 // closing fence - we're at end of line, so we can return
9060 parser.lastLineLength =
9061 parser.offset + indent + match[0].length;
9062 parser.finalize(container, parser.lineNumber);
9063 return 2;
9064 } else {
9065 // skip optional spaces of fence offset
9066 var i = container._fenceOffset;
9067 while (i > 0 && isSpaceOrTab(peek$1(ln, parser.offset))) {
9068 parser.advanceOffset(1, true);
9069 i--;
9070 }
9071 }
9072 } else {
9073 // indented
9074 if (indent >= CODE_INDENT) {
9075 parser.advanceOffset(CODE_INDENT, true);
9076 } else if (parser.blank) {
9077 parser.advanceNextNonspace();
9078 } else {
9079 return 1;
9080 }
9081 }
9082 return 0;
9083 },
9084 finalize: function(parser, block) {
9085 if (block._isFenced) {
9086 // fenced
9087 // first line becomes info string
9088 var content = block._string_content;
9089 var newlinePos = content.indexOf("\n");
9090 var firstLine = content.slice(0, newlinePos);
9091 var rest = content.slice(newlinePos + 1);
9092 block.info = unescapeString(firstLine.trim());
9093 block._literal = rest;
9094 } else {
9095 // indented
9096 block._literal = block._string_content.replace(
9097 /(\n *)+$/,
9098 "\n"
9099 );
9100 }
9101 block._string_content = null; // allow GC
9102 },
9103 canContain: function() {
9104 return false;
9105 },
9106 acceptsLines: true
9107 },
9108 html_block: {
9109 continue: function(parser, container) {
9110 return parser.blank &&
9111 (container._htmlBlockType === 6 ||
9112 container._htmlBlockType === 7)
9113 ? 1
9114 : 0;
9115 },
9116 finalize: function(parser, block) {
9117 block._literal = block._string_content.replace(/(\n *)+$/, "");
9118 block._string_content = null; // allow GC
9119 },
9120 canContain: function() {
9121 return false;
9122 },
9123 acceptsLines: true
9124 },
9125 paragraph: {
9126 continue: function(parser) {
9127 return parser.blank ? 1 : 0;
9128 },
9129 finalize: function(parser, block) {
9130 var pos;
9131 var hasReferenceDefs = false;
9132
9133 // try parsing the beginning as link reference definitions:
9134 while (
9135 peek$1(block._string_content, 0) === C_OPEN_BRACKET$1 &&
9136 (pos = parser.inlineParser.parseReference(
9137 block._string_content,
9138 parser.refmap
9139 ))
9140 ) {
9141 block._string_content = block._string_content.slice(pos);
9142 hasReferenceDefs = true;
9143 }
9144 if (hasReferenceDefs && isBlank(block._string_content)) {
9145 block.unlink();
9146 }
9147 },
9148 canContain: function() {
9149 return false;
9150 },
9151 acceptsLines: true
9152 }
9153 };
9154
9155 // block start functions. Return values:
9156 // 0 = no match
9157 // 1 = matched container, keep going
9158 // 2 = matched leaf, no more block starts
9159 var blockStarts = [
9160 // block quote
9161 function(parser) {
9162 if (
9163 !parser.indented &&
9164 peek$1(parser.currentLine, parser.nextNonspace) === C_GREATERTHAN
9165 ) {
9166 parser.advanceNextNonspace();
9167 parser.advanceOffset(1, false);
9168 // optional following space
9169 if (isSpaceOrTab(peek$1(parser.currentLine, parser.offset))) {
9170 parser.advanceOffset(1, true);
9171 }
9172 parser.closeUnmatchedBlocks();
9173 parser.addChild("block_quote", parser.nextNonspace);
9174 return 1;
9175 } else {
9176 return 0;
9177 }
9178 },
9179
9180 // ATX heading
9181 function(parser) {
9182 var match;
9183 if (
9184 !parser.indented &&
9185 (match = parser.currentLine
9186 .slice(parser.nextNonspace)
9187 .match(reATXHeadingMarker))
9188 ) {
9189 parser.advanceNextNonspace();
9190 parser.advanceOffset(match[0].length, false);
9191 parser.closeUnmatchedBlocks();
9192 var container = parser.addChild("heading", parser.nextNonspace);
9193 container.level = match[0].trim().length; // number of #s
9194 // remove trailing ###s:
9195 container._string_content = parser.currentLine
9196 .slice(parser.offset)
9197 .replace(/^[ \t]*#+[ \t]*$/, "")
9198 .replace(/[ \t]+#+[ \t]*$/, "");
9199 parser.advanceOffset(parser.currentLine.length - parser.offset);
9200 return 2;
9201 } else {
9202 return 0;
9203 }
9204 },
9205
9206 // Fenced code block
9207 function(parser) {
9208 var match;
9209 if (
9210 !parser.indented &&
9211 (match = parser.currentLine
9212 .slice(parser.nextNonspace)
9213 .match(reCodeFence))
9214 ) {
9215 var fenceLength = match[0].length;
9216 parser.closeUnmatchedBlocks();
9217 var container = parser.addChild("code_block", parser.nextNonspace);
9218 container._isFenced = true;
9219 container._fenceLength = fenceLength;
9220 container._fenceChar = match[0][0];
9221 container._fenceOffset = parser.indent;
9222 parser.advanceNextNonspace();
9223 parser.advanceOffset(fenceLength, false);
9224 return 2;
9225 } else {
9226 return 0;
9227 }
9228 },
9229
9230 // HTML block
9231 function(parser, container) {
9232 if (
9233 !parser.indented &&
9234 peek$1(parser.currentLine, parser.nextNonspace) === C_LESSTHAN$1
9235 ) {
9236 var s = parser.currentLine.slice(parser.nextNonspace);
9237 var blockType;
9238
9239 for (blockType = 1; blockType <= 7; blockType++) {
9240 if (
9241 reHtmlBlockOpen[blockType].test(s) &&
9242 (blockType < 7 || (container.type !== "paragraph" &&
9243 !(!parser.allClosed && !parser.blank &&
9244 parser.tip.type === "paragraph") // maybe lazy
9245 ))
9246 ) {
9247 parser.closeUnmatchedBlocks();
9248 // We don't adjust parser.offset;
9249 // spaces are part of the HTML block:
9250 var b = parser.addChild("html_block", parser.offset);
9251 b._htmlBlockType = blockType;
9252 return 2;
9253 }
9254 }
9255 }
9256
9257 return 0;
9258 },
9259
9260 // Setext heading
9261 function(parser, container) {
9262 var match;
9263 if (
9264 !parser.indented &&
9265 container.type === "paragraph" &&
9266 (match = parser.currentLine
9267 .slice(parser.nextNonspace)
9268 .match(reSetextHeadingLine))
9269 ) {
9270 parser.closeUnmatchedBlocks();
9271 // resolve reference link definitiosn
9272 var pos;
9273 while (
9274 peek$1(container._string_content, 0) === C_OPEN_BRACKET$1 &&
9275 (pos = parser.inlineParser.parseReference(
9276 container._string_content,
9277 parser.refmap
9278 ))
9279 ) {
9280 container._string_content = container._string_content.slice(
9281 pos
9282 );
9283 }
9284 if (container._string_content.length > 0) {
9285 var heading = new Node("heading", container.sourcepos);
9286 heading.level = match[0][0] === "=" ? 1 : 2;
9287 heading._string_content = container._string_content;
9288 container.insertAfter(heading);
9289 container.unlink();
9290 parser.tip = heading;
9291 parser.advanceOffset(
9292 parser.currentLine.length - parser.offset,
9293 false
9294 );
9295 return 2;
9296 } else {
9297 return 0;
9298 }
9299 } else {
9300 return 0;
9301 }
9302 },
9303
9304 // thematic break
9305 function(parser) {
9306 if (
9307 !parser.indented &&
9308 reThematicBreak.test(parser.currentLine.slice(parser.nextNonspace))
9309 ) {
9310 parser.closeUnmatchedBlocks();
9311 parser.addChild("thematic_break", parser.nextNonspace);
9312 parser.advanceOffset(
9313 parser.currentLine.length - parser.offset,
9314 false
9315 );
9316 return 2;
9317 } else {
9318 return 0;
9319 }
9320 },
9321
9322 // list item
9323 function(parser, container) {
9324 var data;
9325
9326 if (
9327 (!parser.indented || container.type === "list") &&
9328 (data = parseListMarker(parser, container))
9329 ) {
9330 parser.closeUnmatchedBlocks();
9331
9332 // add the list if needed
9333 if (
9334 parser.tip.type !== "list" ||
9335 !listsMatch(container._listData, data)
9336 ) {
9337 container = parser.addChild("list", parser.nextNonspace);
9338 container._listData = data;
9339 }
9340
9341 // add the list item
9342 container = parser.addChild("item", parser.nextNonspace);
9343 container._listData = data;
9344 return 1;
9345 } else {
9346 return 0;
9347 }
9348 },
9349
9350 // indented code block
9351 function(parser) {
9352 if (
9353 parser.indented &&
9354 parser.tip.type !== "paragraph" &&
9355 !parser.blank
9356 ) {
9357 // indented code
9358 parser.advanceOffset(CODE_INDENT, true);
9359 parser.closeUnmatchedBlocks();
9360 parser.addChild("code_block", parser.offset);
9361 return 2;
9362 } else {
9363 return 0;
9364 }
9365 }
9366 ];
9367
9368 var advanceOffset = function(count, columns) {
9369 var currentLine = this.currentLine;
9370 var charsToTab, charsToAdvance;
9371 var c;
9372 while (count > 0 && (c = currentLine[this.offset])) {
9373 if (c === "\t") {
9374 charsToTab = 4 - (this.column % 4);
9375 if (columns) {
9376 this.partiallyConsumedTab = charsToTab > count;
9377 charsToAdvance = charsToTab > count ? count : charsToTab;
9378 this.column += charsToAdvance;
9379 this.offset += this.partiallyConsumedTab ? 0 : 1;
9380 count -= charsToAdvance;
9381 } else {
9382 this.partiallyConsumedTab = false;
9383 this.column += charsToTab;
9384 this.offset += 1;
9385 count -= 1;
9386 }
9387 } else {
9388 this.partiallyConsumedTab = false;
9389 this.offset += 1;
9390 this.column += 1; // assume ascii; block starts are ascii
9391 count -= 1;
9392 }
9393 }
9394 };
9395
9396 var advanceNextNonspace = function() {
9397 this.offset = this.nextNonspace;
9398 this.column = this.nextNonspaceColumn;
9399 this.partiallyConsumedTab = false;
9400 };
9401
9402 var findNextNonspace = function() {
9403 var currentLine = this.currentLine;
9404 var i = this.offset;
9405 var cols = this.column;
9406 var c;
9407
9408 while ((c = currentLine.charAt(i)) !== "") {
9409 if (c === " ") {
9410 i++;
9411 cols++;
9412 } else if (c === "\t") {
9413 i++;
9414 cols += 4 - (cols % 4);
9415 } else {
9416 break;
9417 }
9418 }
9419 this.blank = c === "\n" || c === "\r" || c === "";
9420 this.nextNonspace = i;
9421 this.nextNonspaceColumn = cols;
9422 this.indent = this.nextNonspaceColumn - this.column;
9423 this.indented = this.indent >= CODE_INDENT;
9424 };
9425
9426 // Analyze a line of text and update the document appropriately.
9427 // We parse markdown text by calling this on each line of input,
9428 // then finalizing the document.
9429 var incorporateLine = function(ln) {
9430 var all_matched = true;
9431 var t;
9432
9433 var container = this.doc;
9434 this.oldtip = this.tip;
9435 this.offset = 0;
9436 this.column = 0;
9437 this.blank = false;
9438 this.partiallyConsumedTab = false;
9439 this.lineNumber += 1;
9440
9441 // replace NUL characters for security
9442 if (ln.indexOf("\u0000") !== -1) {
9443 ln = ln.replace(/\0/g, "\uFFFD");
9444 }
9445
9446 this.currentLine = ln;
9447
9448 // For each containing block, try to parse the associated line start.
9449 // Bail out on failure: container will point to the last matching block.
9450 // Set all_matched to false if not all containers match.
9451 var lastChild;
9452 while ((lastChild = container._lastChild) && lastChild._open) {
9453 container = lastChild;
9454
9455 this.findNextNonspace();
9456
9457 switch (this.blocks[container.type].continue(this, container)) {
9458 case 0: // we've matched, keep going
9459 break;
9460 case 1: // we've failed to match a block
9461 all_matched = false;
9462 break;
9463 case 2: // we've hit end of line for fenced code close and can return
9464 return;
9465 default:
9466 throw "continue returned illegal value, must be 0, 1, or 2";
9467 }
9468 if (!all_matched) {
9469 container = container._parent; // back up to last matching block
9470 break;
9471 }
9472 }
9473
9474 this.allClosed = container === this.oldtip;
9475 this.lastMatchedContainer = container;
9476
9477 var matchedLeaf =
9478 container.type !== "paragraph" && blocks[container.type].acceptsLines;
9479 var starts = this.blockStarts;
9480 var startsLen = starts.length;
9481 // Unless last matched container is a code block, try new container starts,
9482 // adding children to the last matched container:
9483 while (!matchedLeaf) {
9484 this.findNextNonspace();
9485
9486 // this is a little performance optimization:
9487 if (
9488 !this.indented &&
9489 !reMaybeSpecial.test(ln.slice(this.nextNonspace))
9490 ) {
9491 this.advanceNextNonspace();
9492 break;
9493 }
9494
9495 var i = 0;
9496 while (i < startsLen) {
9497 var res = starts[i](this, container);
9498 if (res === 1) {
9499 container = this.tip;
9500 break;
9501 } else if (res === 2) {
9502 container = this.tip;
9503 matchedLeaf = true;
9504 break;
9505 } else {
9506 i++;
9507 }
9508 }
9509
9510 if (i === startsLen) {
9511 // nothing matched
9512 this.advanceNextNonspace();
9513 break;
9514 }
9515 }
9516
9517 // What remains at the offset is a text line. Add the text to the
9518 // appropriate container.
9519
9520 // First check for a lazy paragraph continuation:
9521 if (!this.allClosed && !this.blank && this.tip.type === "paragraph") {
9522 // lazy paragraph continuation
9523 this.addLine();
9524 } else {
9525 // not a lazy continuation
9526
9527 // finalize any blocks not matched
9528 this.closeUnmatchedBlocks();
9529 if (this.blank && container.lastChild) {
9530 container.lastChild._lastLineBlank = true;
9531 }
9532
9533 t = container.type;
9534
9535 // Block quote lines are never blank as they start with >
9536 // and we don't count blanks in fenced code for purposes of tight/loose
9537 // lists or breaking out of lists. We also don't set _lastLineBlank
9538 // on an empty list item, or if we just closed a fenced block.
9539 var lastLineBlank =
9540 this.blank &&
9541 !(
9542 t === "block_quote" ||
9543 (t === "code_block" && container._isFenced) ||
9544 (t === "item" &&
9545 !container._firstChild &&
9546 container.sourcepos[0][0] === this.lineNumber)
9547 );
9548
9549 // propagate lastLineBlank up through parents:
9550 var cont = container;
9551 while (cont) {
9552 cont._lastLineBlank = lastLineBlank;
9553 cont = cont._parent;
9554 }
9555
9556 if (this.blocks[t].acceptsLines) {
9557 this.addLine();
9558 // if HtmlBlock, check for end condition
9559 if (
9560 t === "html_block" &&
9561 container._htmlBlockType >= 1 &&
9562 container._htmlBlockType <= 5 &&
9563 reHtmlBlockClose[container._htmlBlockType].test(
9564 this.currentLine.slice(this.offset)
9565 )
9566 ) {
9567 this.lastLineLength = ln.length;
9568 this.finalize(container, this.lineNumber);
9569 }
9570 } else if (this.offset < ln.length && !this.blank) {
9571 // create paragraph container for line
9572 container = this.addChild("paragraph", this.offset);
9573 this.advanceNextNonspace();
9574 this.addLine();
9575 }
9576 }
9577 this.lastLineLength = ln.length;
9578 };
9579
9580 // Finalize a block. Close it and do any necessary postprocessing,
9581 // e.g. creating string_content from strings, setting the 'tight'
9582 // or 'loose' status of a list, and parsing the beginnings
9583 // of paragraphs for reference definitions. Reset the tip to the
9584 // parent of the closed block.
9585 var finalize = function(block, lineNumber) {
9586 var above = block._parent;
9587 block._open = false;
9588 block.sourcepos[1] = [lineNumber, this.lastLineLength];
9589
9590 this.blocks[block.type].finalize(this, block);
9591
9592 this.tip = above;
9593 };
9594
9595 // Walk through a block & children recursively, parsing string content
9596 // into inline content where appropriate.
9597 var processInlines = function(block) {
9598 var node, event, t;
9599 var walker = block.walker();
9600 this.inlineParser.refmap = this.refmap;
9601 this.inlineParser.options = this.options;
9602 while ((event = walker.next())) {
9603 node = event.node;
9604 t = node.type;
9605 if (!event.entering && (t === "paragraph" || t === "heading")) {
9606 this.inlineParser.parse(node);
9607 }
9608 }
9609 };
9610
9611 var Document = function() {
9612 var doc = new Node("document", [
9613 [1, 1],
9614 [0, 0]
9615 ]);
9616 return doc;
9617 };
9618
9619 // The main parsing function. Returns a parsed document AST.
9620 var parse = function(input) {
9621 this.doc = new Document();
9622 this.tip = this.doc;
9623 this.refmap = {};
9624 this.lineNumber = 0;
9625 this.lastLineLength = 0;
9626 this.offset = 0;
9627 this.column = 0;
9628 this.lastMatchedContainer = this.doc;
9629 this.currentLine = "";
9630 if (this.options.time) {
9631 console.time("preparing input");
9632 }
9633 var lines = input.split(reLineEnding);
9634 var len = lines.length;
9635 if (input.charCodeAt(input.length - 1) === C_NEWLINE$1) {
9636 // ignore last blank line created by final newline
9637 len -= 1;
9638 }
9639 if (this.options.time) {
9640 console.timeEnd("preparing input");
9641 }
9642 if (this.options.time) {
9643 console.time("block parsing");
9644 }
9645 for (var i = 0; i < len; i++) {
9646 this.incorporateLine(lines[i]);
9647 }
9648 while (this.tip) {
9649 this.finalize(this.tip, len);
9650 }
9651 if (this.options.time) {
9652 console.timeEnd("block parsing");
9653 }
9654 if (this.options.time) {
9655 console.time("inline parsing");
9656 }
9657 this.processInlines(this.doc);
9658 if (this.options.time) {
9659 console.timeEnd("inline parsing");
9660 }
9661 return this.doc;
9662 };
9663
9664 // The Parser object.
9665 function Parser(options) {
9666 return {
9667 doc: new Document(),
9668 blocks: blocks,
9669 blockStarts: blockStarts,
9670 tip: this.doc,
9671 oldtip: this.doc,
9672 currentLine: "",
9673 lineNumber: 0,
9674 offset: 0,
9675 column: 0,
9676 nextNonspace: 0,
9677 nextNonspaceColumn: 0,
9678 indent: 0,
9679 indented: false,
9680 blank: false,
9681 partiallyConsumedTab: false,
9682 allClosed: true,
9683 lastMatchedContainer: this.doc,
9684 refmap: {},
9685 lastLineLength: 0,
9686 inlineParser: new InlineParser(options),
9687 findNextNonspace: findNextNonspace,
9688 advanceOffset: advanceOffset,
9689 advanceNextNonspace: advanceNextNonspace,
9690 addLine: addLine,
9691 addChild: addChild,
9692 incorporateLine: incorporateLine,
9693 finalize: finalize,
9694 processInlines: processInlines,
9695 closeUnmatchedBlocks: closeUnmatchedBlocks,
9696 parse: parse,
9697 options: options || {}
9698 };
9699 }
9700
9701 function Renderer() {}
9702
9703 /**
9704 * Walks the AST and calls member methods for each Node type.
9705 *
9706 * @param ast {Node} The root of the abstract syntax tree.
9707 */
9708 function render(ast) {
9709 var walker = ast.walker(),
9710 event,
9711 type;
9712
9713 this.buffer = "";
9714 this.lastOut = "\n";
9715 this.heading_count = 0;
9716
9717 while ((event = walker.next())) {
9718 type = event.node.type;
9719 if (this[type]) {
9720 this[type](event.node, event.entering);
9721 }
9722 }
9723 return this.buffer;
9724 }
9725
9726 /**
9727 * Concatenate a literal string to the buffer.
9728 *
9729 * @param str {String} The string to concatenate.
9730 */
9731 function lit(str) {
9732 this.buffer += str;
9733 this.lastOut = str;
9734 }
9735
9736 /**
9737 * Output a newline to the buffer.
9738 */
9739 function cr() {
9740 if (this.lastOut !== "\n") {
9741 this.lit("\n");
9742 }
9743 }
9744
9745 /**
9746 * Concatenate a string to the buffer possibly escaping the content.
9747 *
9748 * Concrete renderer implementations should override this method.
9749 *
9750 * @param str {String} The string to concatenate.
9751 */
9752 function out(str) {
9753 this.lit(str);
9754 }
9755
9756 /**
9757 * Escape a string for the target renderer.
9758 *
9759 * Abstract function that should be implemented by concrete
9760 * renderer implementations.
9761 *
9762 * @param str {String} The string to escape.
9763 */
9764 function esc(str) {
9765 return str;
9766 }
9767
9768 Renderer.prototype.render = render;
9769 Renderer.prototype.out = out;
9770 Renderer.prototype.lit = lit;
9771 Renderer.prototype.cr = cr;
9772 Renderer.prototype.esc = esc;
9773
9774 var reUnsafeProtocol = /^javascript:|vbscript:|file:|data:/i;
9775 var reSafeDataProtocol = /^data:image\/(?:png|gif|jpeg|webp)/i;
9776
9777 var potentiallyUnsafe = function(url) {
9778 return reUnsafeProtocol.test(url) && !reSafeDataProtocol.test(url);
9779 };
9780
9781 // Helper function to produce an HTML tag.
9782 function tag(name, attrs, selfclosing) {
9783 if (this.disableTags > 0) {
9784 return;
9785 }
9786 this.buffer += "<" + name;
9787 if (attrs && attrs.length > 0) {
9788 var i = 0;
9789 var attrib;
9790 while ((attrib = attrs[i]) !== undefined) {
9791 this.buffer += " " + attrib[0] + '="' + attrib[1] + '"';
9792 i++;
9793 }
9794 }
9795 if (selfclosing) {
9796 this.buffer += " /";
9797 }
9798 this.buffer += ">";
9799 this.lastOut = ">";
9800 }
9801
9802 function HtmlRenderer(options) {
9803 options = options || {};
9804 // by default, soft breaks are rendered as newlines in HTML
9805 options.softbreak = options.softbreak || "\n";
9806 // set to "<br />" to make them hard breaks
9807 // set to " " if you want to ignore line wrapping in source
9808 this.esc = options.esc || escapeXml;
9809 // escape html with a custom function
9810 // else use escapeXml
9811
9812 this.disableTags = 0;
9813 this.lastOut = "\n";
9814 this.options = options;
9815 }
9816
9817 /* Node methods */
9818
9819 function text$1(node) {
9820 this.out(node.literal);
9821 }
9822
9823 function softbreak() {
9824 this.lit(this.options.softbreak);
9825 }
9826
9827 function linebreak() {
9828 this.tag("br", [], true);
9829 this.cr();
9830 }
9831
9832 function link(node, entering) {
9833 var attrs = this.attrs(node);
9834 if (entering) {
9835 if (!(this.options.safe && potentiallyUnsafe(node.destination))) {
9836 attrs.push(["href", this.esc(node.destination)]);
9837 }
9838 if (node.title) {
9839 attrs.push(["title", this.esc(node.title)]);
9840 }
9841 this.tag("a", attrs);
9842 } else {
9843 this.tag("/a");
9844 }
9845 }
9846
9847 function image$1(node, entering) {
9848 if (entering) {
9849 if (this.disableTags === 0) {
9850 if (this.options.safe && potentiallyUnsafe(node.destination)) {
9851 this.lit('<img src="" alt="');
9852 } else {
9853 this.lit('<img src="' + this.esc(node.destination) + '" alt="');
9854 }
9855 }
9856 this.disableTags += 1;
9857 } else {
9858 this.disableTags -= 1;
9859 if (this.disableTags === 0) {
9860 if (node.title) {
9861 this.lit('" title="' + this.esc(node.title));
9862 }
9863 this.lit('" />');
9864 }
9865 }
9866 }
9867
9868 function emph(node, entering) {
9869 this.tag(entering ? "em" : "/em");
9870 }
9871
9872 function strong(node, entering) {
9873 this.tag(entering ? "strong" : "/strong");
9874 }
9875
9876 function paragraph(node, entering) {
9877 var grandparent = node.parent.parent,
9878 attrs = this.attrs(node);
9879 if (grandparent !== null && grandparent.type === "list") {
9880 if (grandparent.listTight) {
9881 return;
9882 }
9883 }
9884 if (entering) {
9885 this.cr();
9886 this.tag("p", attrs);
9887 } else {
9888 this.tag("/p");
9889 this.cr();
9890 }
9891 }
9892
9893 function heading(node, entering) {
9894 var tagname = "h" + node.level,
9895 attrs = this.attrs(node);
9896 if (entering) {
9897 if (node.level != 1) {
9898 attrs.push(["id", ":" + this.heading_count]);
9899 this.heading_count += 1;
9900 }
9901 this.cr();
9902 this.tag(tagname, attrs);
9903 } else {
9904 this.tag("/" + tagname);
9905 this.cr();
9906 }
9907 }
9908
9909 function code(node) {
9910 this.tag("code");
9911 this.out(node.literal);
9912 this.tag("/code");
9913 }
9914
9915 function code_block(node) {
9916 var info_words = node.info ? node.info.split(/\s+/) : [],
9917 attrs = this.attrs(node);
9918 if (info_words.length > 0 && info_words[0].length > 0) {
9919 attrs.push(["class", "language-" + this.esc(info_words[0])]);
9920 }
9921 this.cr();
9922 this.tag("pre");
9923 this.tag("code", attrs);
9924 this.out(node.literal);
9925 this.tag("/code");
9926 this.tag("/pre");
9927 this.cr();
9928 }
9929
9930 function thematic_break(node) {
9931 var attrs = this.attrs(node);
9932 this.cr();
9933 this.tag("hr", attrs, true);
9934 this.cr();
9935 }
9936
9937 function block_quote(node, entering) {
9938 var attrs = this.attrs(node);
9939 if (entering) {
9940 this.cr();
9941 this.tag("blockquote", attrs);
9942 this.cr();
9943 } else {
9944 this.cr();
9945 this.tag("/blockquote");
9946 this.cr();
9947 }
9948 }
9949
9950 function list(node, entering) {
9951 var tagname = node.listType === "bullet" ? "ul" : "ol",
9952 attrs = this.attrs(node);
9953
9954 if (entering) {
9955 var start = node.listStart;
9956 if (start !== null && start !== 1) {
9957 attrs.push(["start", start.toString()]);
9958 }
9959 this.cr();
9960 this.tag(tagname, attrs);
9961 this.cr();
9962 } else {
9963 this.cr();
9964 this.tag("/" + tagname);
9965 this.cr();
9966 }
9967 }
9968
9969 function item(node, entering) {
9970 var attrs = this.attrs(node);
9971 if (entering) {
9972 this.tag("li", attrs);
9973 } else {
9974 this.tag("/li");
9975 this.cr();
9976 }
9977 }
9978
9979 function html_inline(node) {
9980 if (this.options.safe) {
9981 this.lit("<!-- raw HTML omitted -->");
9982 } else {
9983 this.lit(node.literal);
9984 }
9985 }
9986
9987 function html_block(node) {
9988 this.cr();
9989 if (this.options.safe) {
9990 this.lit("<!-- raw HTML omitted -->");
9991 } else {
9992 this.lit(node.literal);
9993 }
9994 this.cr();
9995 }
9996
9997 function custom_inline(node, entering) {
9998 if (entering && node.onEnter) {
9999 this.lit(node.onEnter);
10000 } else if (!entering && node.onExit) {
10001 this.lit(node.onExit);
10002 }
10003 }
10004
10005 function custom_block(node, entering) {
10006 this.cr();
10007 if (entering && node.onEnter) {
10008 this.lit(node.onEnter);
10009 } else if (!entering && node.onExit) {
10010 this.lit(node.onExit);
10011 }
10012 this.cr();
10013 }
10014
10015 /* Helper methods */
10016
10017 function out$1(s) {
10018 this.lit(this.esc(s));
10019 }
10020
10021 function attrs(node) {
10022 var att = [];
10023 if (this.options.sourcepos) {
10024 var pos = node.sourcepos;
10025 if (pos) {
10026 att.push([
10027 "data-sourcepos",
10028 String(pos[0][0]) +
10029 ":" +
10030 String(pos[0][1]) +
10031 "-" +
10032 String(pos[1][0]) +
10033 ":" +
10034 String(pos[1][1])
10035 ]);
10036 }
10037 }
10038 return att;
10039 }
10040
10041 // quick browser-compatible inheritance
10042 HtmlRenderer.prototype = Object.create(Renderer.prototype);
10043
10044 HtmlRenderer.prototype.text = text$1;
10045 HtmlRenderer.prototype.html_inline = html_inline;
10046 HtmlRenderer.prototype.html_block = html_block;
10047 HtmlRenderer.prototype.softbreak = softbreak;
10048 HtmlRenderer.prototype.linebreak = linebreak;
10049 HtmlRenderer.prototype.link = link;
10050 HtmlRenderer.prototype.image = image$1;
10051 HtmlRenderer.prototype.emph = emph;
10052 HtmlRenderer.prototype.strong = strong;
10053 HtmlRenderer.prototype.paragraph = paragraph;
10054 HtmlRenderer.prototype.heading = heading;
10055 HtmlRenderer.prototype.code = code;
10056 HtmlRenderer.prototype.code_block = code_block;
10057 HtmlRenderer.prototype.thematic_break = thematic_break;
10058 HtmlRenderer.prototype.block_quote = block_quote;
10059 HtmlRenderer.prototype.list = list;
10060 HtmlRenderer.prototype.item = item;
10061 HtmlRenderer.prototype.custom_inline = custom_inline;
10062 HtmlRenderer.prototype.custom_block = custom_block;
10063
10064 HtmlRenderer.prototype.esc = escapeXml;
10065
10066 HtmlRenderer.prototype.out = out$1;
10067 HtmlRenderer.prototype.tag = tag;
10068 HtmlRenderer.prototype.attrs = attrs;
10069
10070 var reXMLTag = /\<[^>]*\>/;
10071
10072 function toTagName(s) {
10073 return s.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
10074 }
10075
10076 function XmlRenderer(options) {
10077 options = options || {};
10078
10079 this.disableTags = 0;
10080 this.lastOut = "\n";
10081
10082 this.indentLevel = 0;
10083 this.indent = " ";
10084
10085 this.esc = options.esc || escapeXml;
10086 // escape html with a custom function
10087 // else use escapeXml
10088
10089 this.options = options;
10090 }
10091
10092 function render$1(ast) {
10093 this.buffer = "";
10094
10095 var attrs;
10096 var tagname;
10097 var walker = ast.walker();
10098 var event, node, entering;
10099 var container;
10100 var selfClosing;
10101 var nodetype;
10102
10103 var options = this.options;
10104
10105 if (options.time) {
10106 console.time("rendering");
10107 }
10108
10109 this.buffer += '<?xml version="1.0" encoding="UTF-8"?>\n';
10110 this.buffer += '<!DOCTYPE document SYSTEM "CommonMark.dtd">\n';
10111
10112 while ((event = walker.next())) {
10113 entering = event.entering;
10114 node = event.node;
10115 nodetype = node.type;
10116
10117 container = node.isContainer;
10118
10119 selfClosing =
10120 nodetype === "thematic_break" ||
10121 nodetype === "linebreak" ||
10122 nodetype === "softbreak";
10123
10124 tagname = toTagName(nodetype);
10125
10126 if (entering) {
10127 attrs = [];
10128
10129 switch (nodetype) {
10130 case "document":
10131 attrs.push(["xmlns", "http://commonmark.org/xml/1.0"]);
10132 break;
10133 case "list":
10134 if (node.listType !== null) {
10135 attrs.push(["type", node.listType.toLowerCase()]);
10136 }
10137 if (node.listStart !== null) {
10138 attrs.push(["start", String(node.listStart)]);
10139 }
10140 if (node.listTight !== null) {
10141 attrs.push([
10142 "tight",
10143 node.listTight ? "true" : "false"
10144 ]);
10145 }
10146 var delim = node.listDelimiter;
10147 if (delim !== null) {
10148 var delimword = "";
10149 if (delim === ".") {
10150 delimword = "period";
10151 } else {
10152 delimword = "paren";
10153 }
10154 attrs.push(["delimiter", delimword]);
10155 }
10156 break;
10157 case "code_block":
10158 if (node.info) {
10159 attrs.push(["info", node.info]);
10160 }
10161 break;
10162 case "heading":
10163 attrs.push(["level", String(node.level)]);
10164 break;
10165 case "link":
10166 case "image":
10167 attrs.push(["destination", node.destination]);
10168 attrs.push(["title", node.title]);
10169 break;
10170 case "custom_inline":
10171 case "custom_block":
10172 attrs.push(["on_enter", node.onEnter]);
10173 attrs.push(["on_exit", node.onExit]);
10174 break;
10175 }
10176 if (options.sourcepos) {
10177 var pos = node.sourcepos;
10178 if (pos) {
10179 attrs.push([
10180 "sourcepos",
10181 String(pos[0][0]) +
10182 ":" +
10183 String(pos[0][1]) +
10184 "-" +
10185 String(pos[1][0]) +
10186 ":" +
10187 String(pos[1][1])
10188 ]);
10189 }
10190 }
10191
10192 this.cr();
10193 this.out(this.tag(tagname, attrs, selfClosing));
10194 if (container) {
10195 this.indentLevel += 1;
10196 } else if (!container && !selfClosing) {
10197 var lit = node.literal;
10198 if (lit) {
10199 this.out(this.esc(lit));
10200 }
10201 this.out(this.tag("/" + tagname));
10202 }
10203 } else {
10204 this.indentLevel -= 1;
10205 this.cr();
10206 this.out(this.tag("/" + tagname));
10207 }
10208 }
10209 if (options.time) {
10210 console.timeEnd("rendering");
10211 }
10212 this.buffer += "\n";
10213 return this.buffer;
10214 }
10215
10216 function out$2(s) {
10217 if (this.disableTags > 0) {
10218 this.buffer += s.replace(reXMLTag, "");
10219 } else {
10220 this.buffer += s;
10221 }
10222 this.lastOut = s;
10223 }
10224
10225 function cr$1() {
10226 if (this.lastOut !== "\n") {
10227 this.buffer += "\n";
10228 this.lastOut = "\n";
10229 for (var i = this.indentLevel; i > 0; i--) {
10230 this.buffer += this.indent;
10231 }
10232 }
10233 }
10234
10235 // Helper function to produce an XML tag.
10236 function tag$1(name, attrs, selfclosing) {
10237 var result = "<" + name;
10238 if (attrs && attrs.length > 0) {
10239 var i = 0;
10240 var attrib;
10241 while ((attrib = attrs[i]) !== undefined) {
10242 result += " " + attrib[0] + '="' + this.esc(attrib[1]) + '"';
10243 i++;
10244 }
10245 }
10246 if (selfclosing) {
10247 result += " /";
10248 }
10249 result += ">";
10250 return result;
10251 }
10252
10253 // quick browser-compatible inheritance
10254 XmlRenderer.prototype = Object.create(Renderer.prototype);
10255
10256 XmlRenderer.prototype.render = render$1;
10257 XmlRenderer.prototype.out = out$2;
10258 XmlRenderer.prototype.cr = cr$1;
10259 XmlRenderer.prototype.tag = tag$1;
10260 XmlRenderer.prototype.esc = escapeXml;
10261
10262 exports.HtmlRenderer = HtmlRenderer;
10263 exports.Node = Node;
10264 exports.Parser = Parser;
10265 exports.Renderer = Renderer;
10266 exports.XmlRenderer = XmlRenderer;
10267
10268 Object.defineProperty(exports, '__esModule', { value: true });
10269
10270})));
lib/docs/index.html+249-1079
......@@ -1,634 +1,185 @@
11<!doctype html>
2<html lang="en">
2<html>
33 <head>
44 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6 <title>Documentation - Zig</title>
7 <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
5 <title>Zig Documentation</title>
86 <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
9 <style>
10 :root {
11 font-size: 1em;
12 --ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
13 --mono: "Source Code Pro", monospace;
14 --tx-color: #141414;
15 --bg-color: #ffffff;
16 --link-color: #2A6286;
17 --sidebar-sh-color: rgba(0, 0, 0, 0.09);
18 --sidebar-mod-bg-color: #f1f1f1;
19 --sidebar-modlnk-tx-color: #141414;
20 --sidebar-modlnk-tx-color-hover: #fff;
21 --sidebar-modlnk-tx-color-active: #000;
22 --sidebar-modlnk-bg-color: transparent;
23 --sidebar-modlnk-bg-color-hover: #555;
24 --sidebar-modlnk-bg-color-active: #FFBB4D;
25 --search-bg-color: #f3f3f3;
26 --search-bg-color-focus: #ffffff;
27 --search-sh-color: rgba(0, 0, 0, 0.18);
28 --search-other-results-color: rgb(100, 100, 100);
29 --modal-sh-color: rgba(0, 0, 0, 0.75);
30 --modal-bg-color: #aaa;
31 --warning-popover-bg-color: #ff4747;
7 <style type="text/css">
8 body {
9 font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
10 color: #000000;
3211 }
33
34 html, body { margin: 0; padding: 0; height: 100%; }
35
36 a {
37 text-decoration: none;
38 }
39
40 pre a {
41 text-decoration: underline;
42 color: unset;
43 }
44
45 a:hover {
46 text-decoration: underline;
47 }
48
49 a[href^="src/"] {
50 border-bottom: 2px dotted var(--tx-color);
51 }
52
5312 .hidden {
54 display: none !important;
55 }
56
57 /* layout */
58 .canvas {
59 display:flex;
60 flex-direction: column;
61 width: 100vw;
62 height: 100vh;
63 margin: 0;
64 padding: 0;
65 font-family: var(--ui);
66 color: var(--tx-color);
67 background-color: var(--bg-color);
68 }
69
70 .flex-main {
71 display: flex;
72 flex-direction: column;
73 justify-content: center;
74
75 height: 100%;
76 overflow: hidden;
77
78
79 z-index: 100;
80 }
81
82 .flex-horizontal {
83 display: flex;
84 flex-direction: row;
85 align-items: center;
86 }
87
88 .flex-filler {
89 flex-grow: 1;
90 flex-shrink: 1;
91 }
92
93 .flex-left {
94 overflow: auto;
95 -webkit-overflow-scrolling: touch;
96 overflow-wrap: break-word;
97 flex-shrink: 0;
98 flex-grow: 0;
99 margin-right: 0.5rem;
100
101 z-index: 300;
102 }
103
104 .flex-right {
105 display: flex;
106 flex-direction: column;
107 overflow: auto;
108 -webkit-overflow-scrolling: touch;
109 flex-grow: 1;
110 flex-shrink: 1;
111
112 z-index: 200;
113 }
114
115 .flex-right > .wrap {
116 width: 60rem;
117 max-width: 85vw;
118 flex-shrink: 1;
119 }
120
121 .modal-container {
122 z-index: 400;
123 }
124
125 .understated {
126 color: var(--search-other-results-color);
127 }
128
129 .sidebar {
130 background-color: var(--bg-color);
131 box-shadow: 0 0 1rem var(--sidebar-sh-color);
132 clip-path: inset(0px -15px 0px 0px);
133 }
134
135 .logo {
136 margin: 0.5rem;
137 width: 130px;
138 }
139
140 .logo > svg {
141 display: block;
142 }
143
144 ul.guides-api-switch {
145 display: flex;
146 flex-direction: row;
147 justify-content: center;
148 text-align: center;
149 list-style-type: none;
150 margin: 0;
151 padding: 0;
152 }
153
154 .guides-api-switch a {
155 display: block;
156 padding: 0.5rem 1rem;
157 color: var(--sidebar-modlnk-tx-color);
158 background-color: var(--sidebar-modlnk-bg-color);
159 border: 1px solid var(--tx-color);
160 }
161
162
163 #ApiSwitch {
164 border-radius: 10px 0 0 10px;
165 }
166
167 #guideSwitch {
168 border-radius: 0 10px 10px 0;
169 }
170
171
172 #ApiSwitch:hover, #guideSwitch:hover {
173 text-decoration: none;
174 }
175
176 #ApiSwitch:hover:not(.active), #guideSwitch:hover:not(.active) {
177 color: var(--sidebar-modlnk-tx-color-hover);
178 background-color: var(--sidebar-modlnk-bg-color-hover);
179 }
180
181 .guides-api-switch .active {
182 color: var(--sidebar-modlnk-tx-color-active);
183 background-color: var(--sidebar-modlnk-bg-color-active);
184 }
185
186 #guidesMenu {
187 height: 100%;
188 overflow: hidden;
189 width: 30%;
190 margin-right: 2rem;
191 }
192
193 #activeGuide {
194 overflow-y: scroll;
195 height: 100%;
196 width: 70%;
197 padding-right: 1rem;
13 display: none;
19814 }
199 .sidebar h2 {
200 margin: 0.5rem;
201 padding: 0;
202 font-size: 1.2rem;
15 table {
16 width: 100%;
20317 }
204
205 .sidebar h2 > span {
206 border-bottom: 0.125rem dotted var(--tx-color);
18 a {
19 color: #2A6286;
20720 }
208
209 .sidebar .modules {
210 list-style-type: none;
21 pre{
22 font-family:"Source Code Pro",monospace;
23 font-size:1em;
24 background-color:#F5F5F5;
25 padding: 1em;
21126 margin: 0;
212 padding: 0;
213 background-color: var(--sidebar-mod-bg-color);
214 }
215
216 .sidebar .modules > li > a {
217 display: block;
218 padding: 0.5rem 1rem;
219 color: var(--sidebar-modlnk-tx-color);
220 background-color: var(--sidebar-modlnk-bg-color);
221 text-decoration: none;
222 }
223
224 .sidebar .modules > li > a:hover {
225 color: var(--sidebar-modlnk-tx-color-hover);
226 background-color: var(--sidebar-modlnk-bg-color-hover);
227 }
228
229 .sidebar .modules > li > a.active {
230 color: var(--sidebar-modlnk-tx-color-active);
231 background-color: var(--sidebar-modlnk-bg-color-active);
232 }
233
234 .sidebar p.str {
235 margin: 0.5rem;
236 font-family: var(--mono);
27 overflow-x: auto;
23728 }
238
239 #guideTocList {
240 padding: 0 1rem;
29 code {
30 font-family:"Source Code Pro",monospace;
31 font-size: 0.9em;
24132 }
242
243 #guideTocList ul {
244 padding-left: 1rem;
245 margin: 0;
33 code a {
34 color: #000000;
24635 }
247
248 #guides {
249 box-sizing: border-box;
250 font-size: 1rem;
251 background-color: var(--bg-color);
252 overflow-wrap: break-word;
36 #listFields > div, #listParams > div {
37 margin-bottom: 1em;
25338 }
254
255 /* docs section */
256 .docs {
257 flex-grow: 2;
258 padding: 0rem 0.7rem 0rem 1.4rem;
259 font-size: 1rem;
260 background-color: var(--bg-color);
261 overflow-wrap: break-word;
262 height: 100%;
263 overflow-y: scroll;
39 #hdrName a {
40 font-size: 0.7em;
41 padding-left: 1em;
26442 }
265
266 #noDocsNamespaces {
267 margin: 1rem;
268 border: 1px solid var(--search-other-results-color);
269 padding: 0.5rem 1rem;
270 background-color: var(--help-bg-color);
43 .fieldDocs {
44 border: 1px solid #F5F5F5;
45 border-top: 0px;
46 padding: 1px 1em;
27147 }
27248
273 .column {
274 flex-basis: 0;
275 flex-grow: 1;
276 min-width: min(24rem, 90%);
49 #logo {
50 width: 8em;
51 padding: 0.5em 1em;
27752 }
27853
279
280 .search-container {
281 flex-grow: 2;
54 #navWrap {
55 width: -moz-available;
56 width: -webkit-fill-available;
57 width: stretch;
58 margin-left: 11em;
28259 }
28360
284 .search {
61 #search {
28562 width: 100%;
286 padding: 0.5rem;
287 font-family: var(--ui);
288 font-size: 1rem;
289 color: var(--tx-color);
290 background-color: var(--search-bg-color);
291 border-top: 0;
292 border-left: 0;
293 border-right: 0;
294 border-bottom-width: 0.125rem;
295 border-bottom-style: solid;
296 border-bottom-color: var(--tx-color);
297 outline: none;
298 transition: border-bottom-color 0.35s, background 0.35s, box-shadow 0.35s;
299 border-radius: 0;
300 -webkit-appearance: none;
301 }
302
303 .search:focus {
304 background-color: var(--search-bg-color-focus);
305 border-bottom-color: #ffbb4d;
306 box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);
307 }
308
309 #searchPlaceholder {
310 position: absolute;
311 pointer-events: none;
312 height: 100%;
313 display: flex;
314 align-items: center;
315 padding-left: 5px;
31663 }
31764
318 #searchPlaceholderTextMobile {
319 display: none;
320 }
321
322 #dotsPopover:before {
323 position: absolute;
324 content: "";
325 left: 20px;
326 top: -8px;
327 border-style: solid;
328 border-width: 0 10px 10px 10px;
329 border-color: transparent transparent var(--warning-popover-bg-color) transparent;
330 transition-duration: 0.3s;
331 transition-property: transform;
332 z-index: 10;
333 }
334
335 #dotsPopover {
336 position: absolute;
337 opacity: 0;
338 visibility: hidden;
339 background-color: var(--warning-popover-bg-color);
340 border-radius: 10px;
341 left: 10px;
342 transform: translate(0, -20px);
343 padding: 0.5rem 1rem;
344 box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
345 transition: all 0.5s cubic-bezier(0.75, -0.02, 0.2, 0.97);
346 z-index: 20;
347 }
348
349 #dotsPopover.active {
350 opacity: 1;
351 visibility: visible;
352 transform: translate(0, 0);
353 }
354
355 #sectSearchResults {
356 box-sizing: border-box;
357 }
358
359 #searchHelp summary {
360 color: red;
361 list-style-position: outside;
362 }
363
364 #searchHelp summary.normal {
365 color: var(--search-other-results-color);
366 transition: all 0.5s cubic-bezier(0.75, -0.02, 0.2, 0.97);
367 }
368
369 #searchHelp div {
370 background-color: var(--modal-bg-color);
371 padding: 0.5rem 1rem;
65 nav {
66 width: 10em;
67 float: left;
37268 }
373
374 .other-results {
375 line-height: 1em;
376 position: relative;
377 outline: 0;
378 border: 0;
379 color: var(--search-other-results-color);
69 nav h2 {
70 font-size: 1.2em;
71 text-decoration: underline;
72 margin: 0;
73 padding: 0.5em 0;
38074 text-align: center;
381 height: 1.5em;
382 opacity: .5;
383 }
384 .other-results:before {
385 content: '';
386 background: var(--search-other-results-color);
387 position: absolute;
388 left: 0;
389 top: 50%;
390 width: 100%;
391 height: 1px;
392 }
393
394 .other-results:after {
395 content: "other results";
396 position: relative;
397 display: inline-block;
398 padding: 0 .5em;
399 line-height: 1.5em;
400 color: var(--search-other-results-color);
401 background-color: var(--bg-color);
40275 }
403
404
405 a {
406 color: var(--link-color);
407 }
408
409 p {
410 margin: 0.8rem 0;
411 }
412
413 pre {
414 font-family: var(--mono);
415 font-size: 1em;
416 background-color: #F5F5F5;
417 padding: 1em;
418 overflow-x: auto;
419 }
420
421 pre.inline {
422 background-color: var(--bg-color);
76 nav p {
77 margin: 0;
42378 padding: 0;
424 display: inline;
79 text-align: center;
42580 }
426
427
428 code {
429 font-family: var(--mono);
430 font-size: 1em;
81 section {
82 clear: both;
83 padding-top: 1em;
43184 }
432
433 h1 {
434 font-size: 1.4em;
435 margin: 0.8em 0;
436 padding: 0;
437 border-bottom: 0.0625rem dashed;
85 section h1 {
86 border-bottom: 1px dashed;
87 margin: 0 0;
43888 }
439
440 h2 {
89 section h2 {
44190 font-size: 1.3em;
44291 margin: 0.5em 0;
44392 padding: 0;
444 border-bottom: 0.0625rem solid;
93 border-bottom: 1px solid;
44594 }
446 .listNav {
95 #listNav {
44796 list-style-type: none;
448 margin: 0;
97 margin: 0.5em 0 0 0;
44998 padding: 0;
45099 overflow: hidden;
451100 background-color: #f1f1f1;
452 display: flex;
453 flex-direction: row;
454101 }
455 .listNav li {
456
102 #listNav li {
103 float:left;
457104 }
458 .listNav li a {
105 #listNav li a {
459106 display: block;
460107 color: #000;
461108 text-align: center;
462109 padding: .5em .8em;
463110 text-decoration: none;
464111 }
465 .listNav li a:hover {
112 #listNav li a:hover {
466113 background-color: #555;
467114 color: #fff;
468115 }
469 .listNav li a.active {
116 #listNav li a.active {
470117 background-color: #FFBB4D;
471118 color: #000;
472119 }
473120
474 #listSearchResults li.selected {
475 background-color: #93e196;
476 }
477
478 #tableFnErrors dt {
479 font-weight: bold;
480 }
481
482 .expand[open] .sum-less {
483 display: none;
484 }
485
486 .expand[open] .sum-more {
487 display: block;
488 }
489
490 .expand .sum-more {
491 display: none;
492 }
493
494 .expand {
495 position: relative;
496 }
497
498 .expand .button:before {
499 content: "[+] ";
500 font-family: var(--mono);
501 color: var(--link-color);
502 position: sticky;
503 float: left;
504 top: 0.5em;
505 right: -16px;
506 z-index: 1;
507 margin-left: -2em;
508 pointer-events: all;
509 cursor: pointer;
510 }
511
512 .expand[open] .button:before {
513 content: "[-] ";
514 }
515
516 .examples {
517 list-style-type: none;
518 margin: 0;
519 padding: 0;
520 }
521 .examples li {
522 padding: 0.5em 0;
523 white-space: nowrap;
524 overflow-x: auto;
525 }
526
527 .docs td {
528 margin: 0;
529 padding: 0.5em;
530 max-width: 27em;
531 text-overflow: ellipsis;
532 overflow-x: hidden;
533 }
534
535 .fieldHasDocs {
536 margin-bottom: 0;
537 }
538
539 .fieldDocs {
540 border: 1px solid #F5F5F5;
541 border-top: 0px;
542 padding: 1px 1em;
543 }
544
545 /* modals */
546 .modal-container {
547 display: flex;
548 width: 100%;
549 height: 100%;
121 #helpDialog {
122 width: 21em;
123 height: 21em;
550124 position: fixed;
551125 top: 0;
552126 left: 0;
553 justify-content: center;
554 align-items: center;
555 background-color: rgba(0, 0, 0, 0.15);
556 backdrop-filter: blur(0.3em);
557 }
558
559 .modal-container > .modal {
560 max-width: 97vw;
561 max-height: 97vh;
562 overflow: auto;
563 font-size: 1rem;
127 background-color: #333;
564128 color: #fff;
565 background-color: var(--modal-bg-color);
566 border: 0.125rem solid #000;
567 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--modal-sh-color);
129 border: 1px solid #fff;
568130 }
569
570 .modal-container h1 {
571 margin: 0.75em 2.5em 1em 2.5em;
572 font-size: 1.5em;
131 #helpDialog h1 {
573132 text-align: center;
133 font-size: 1.5em;
574134 }
575
576 .modal-container dt, .modal-container dd {
135 #helpDialog dt, #helpDialog dd {
577136 display: inline;
578137 margin: 0 0.2em;
579138 }
580
581 .modal-container dl {
582 margin-left: 0.5em;
583 margin-right: 0.5em;
584 }
585
586 .prefs-list {
587 list-style: none;
588 padding: 0;
589 margin-left: 0.5em;
590 margin-right: 0.5em;
591 }
592
593139 kbd {
594 display: inline-block;
595 padding: 0.3em 0.2em;
596 font-family: var(--mono);
597 font-size: 1em;
598 line-height: 0.8em;
599 vertical-align: middle;
600140 color: #000;
601141 background-color: #fafbfc;
602142 border-color: #d1d5da;
603143 border-bottom-color: #c6cbd1;
604 border: solid 0.0625em;
605 border-radius: 0.1875em;
606 box-shadow: inset 0 -0.2em 0 #c6cbd1;
144 box-shadow-color: #c6cbd1;
145 display: inline-block;
146 padding: 0.3em 0.2em;
147 font: 1.2em monospace;
148 line-height: 0.8em;
149 vertical-align: middle;
150 border: solid 1px;
151 border-radius: 3px;
152 box-shadow: inset 0 -1px 0;
607153 cursor: default;
608154 }
609
610 #listFns > div {
611 padding-bottom: 10px;
155
156 #listSearchResults li.selected {
157 background-color: #93e196;
158 }
159
160 #tableFnErrors dt {
161 font-weight: bold;
612162 }
613163
614 #listFns dt {
615 font-family: var(--mono);
616 display: flex;
617 flex-direction: colunm;
618 justify-content: space-between;
164 dl > div {
165 padding: 0.5em;
166 border: 1px solid #c0c0c0;
167 margin-top: 0.5em;
619168 }
620
621 #listFns dt .fnSignature {
622 overflow-x: hidden;
623 white-space: nowrap;
169
170 td {
171 vertical-align: top;
172 margin: 0;
173 padding: 0.5em;
174 max-width: 20em;
624175 text-overflow: ellipsis;
176 overflow-x: hidden;
625177 }
626
627 .argBreaker {
628 display: none;
178
179 ul.columns {
180 column-width: 20em;
629181 }
630182
631 /* tokens */
632183 .tok-kw {
633184 color: #333;
634185 font-weight: bold;
......@@ -657,51 +208,36 @@
657208 color: #458;
658209 font-weight: bold;
659210 }
660 .tok-decl-ref {
661 color: #0086b3;
662 font-weight: bold;
663 }
664211
665 /* dark mode */
666212 @media (prefers-color-scheme: dark) {
667 :root {
668 --tx-color: #bbb;
669 --bg-color: #111;
670 --link-color: #88f;
671 --sidebar-sh-color: rgba(128, 128, 128, 0.5);
672 --sidebar-mod-bg-color: #333;
673 --sidebar-modlnk-tx-color: #fff;
674 --sidebar-modlnk-tx-color-hover: #fff;
675 --sidebar-modlnk-tx-color-active: #000;
676 --sidebar-modlnk-bg-color: transparent;
677 --sidebar-modlnk-bg-color-hover: #555;
678 --sidebar-modlnk-bg-color-active: #FFBB4D;
679 --search-bg-color: #3c3c3c;
680 --search-bg-color-focus: #000;
681 --search-sh-color: rgba(255, 255, 255, 0.28);
682 --search-other-results-color: rgba(255, 255, 255, 0.28);
683 --modal-sh-color: rgba(142, 142, 142, 0.5);
684 --modal-bg-color: #333;
685 --warning-popover-bg-color: #600000;
213 body {
214 background-color: #111;
215 color: #bbb;
686216 }
687
688217 pre {
689 background-color:#2A2A2A;
218 background-color: #222;
219 color: #ccc;
220 }
221 a {
222 color: #88f;
223 }
224 code a {
225 color: #ccc;
690226 }
691227 .fieldDocs {
692228 border-color:#2A2A2A;
693229 }
694 .listNav {
230 #listNav {
695231 background-color: #333;
696232 }
697 .listNav li a {
233 #listNav li a {
698234 color: #fff;
699235 }
700 .listNav li a:hover {
236 #listNav li a:hover {
701237 background-color: #555;
702238 color: #fff;
703239 }
704 .listNav li a.active {
240 #listNav li a.active {
705241 background-color: #FFBB4D;
706242 color: #000;
707243 }
......@@ -711,6 +247,9 @@
711247 #listSearchResults li.selected a {
712248 color: #fff;
713249 }
250 dl > div {
251 border-color: #373737;
252 }
714253 .tok-kw {
715254 color: #eee;
716255 }
......@@ -724,7 +263,7 @@
724263 color: #aa7;
725264 }
726265 .tok-fn {
727 color: #e33;
266 color: #B1A0F8;
728267 }
729268 .tok-null {
730269 color: #ff8080;
......@@ -735,511 +274,142 @@
735274 .tok-type {
736275 color: #68f;
737276 }
738 .tok-decl-ref {
739 color: lightblue;
740 }
741277 }
742
743 @media only screen and (max-width: 750px) {
744 .canvas {
745 overflow: auto;
746 }
747 .flex-main {
748 flex-direction: column;
749 }
750 .sidebar {
751 min-width: calc(100vw - 2.8rem);
752 padding-left: 1.4rem;
753 padding-right: 1.4rem;
754 }
755 .flex-main > .flex-filler {
756 display: none;
757 }
758 .flex-main > .flex-right > .flex-filler {
759 display: none;
760 }
761 .flex-main > .flex-right > .wrap {
762 max-width: 100vw;
763 }
764 .flex-main > .flex-right > .wrap > .docs {
765 padding-right: 1.4rem;
766 background: transparent;
767 }
768 .modules {
769 display: flex;
770 flex-wrap: wrap;
771 }
772 .table-container table {
773 display: flex;
774 flex-direction: column;
775 }
776 .table-container tr {
777 display: flex;
778 flex-direction: column;
779 }
780 .examples {
781 overflow-x: scroll;
782 -webkit-overflow-scrolling: touch;
783 max-width: 100vw;
784 margin-left: -1.4rem;
785 margin-right: -1.4rem;
786 }
787 .examples li {
788 width: max-content;
789 padding-left: 1.4rem;
790 padding-right: 1.4rem;
791 }
792 .mobile-scroll-container {
793 overflow-x: scroll;
794 -webkit-overflow-scrolling: touch;
795 margin-left: -1.4rem;
796 margin-right: -1.4rem;
797 max-width: 100vw;
798 }
799 .mobile-scroll-container > .scroll-item {
800 margin-left: 1.4rem;
801 margin-right: 1.4rem;
802 box-sizing: border-box;
803 width: max-content;
804 display: inline-block;
805 min-width: calc(100% - 2.8rem);
806 }
807 #searchPlaceholderText {
808 display: none;
809 }
810 #searchPlaceholderTextMobile {
811 display: inline;
812 }
813 }
814 .banner {
815 background-color: orange;
816 text-align: center;
817 color: black;
818 padding: 5px 5px;
819 }
820 .banner a {
821 color: black;
822 text-decoration: underline;
823 }
824
825 </style>
826
827 <style>
828 pre {
829 --zig-keyword: #333;
830 --zig-builtin: #0086b3;
831 --zig-identifier: black;
832 --zig-decl-identifier: #0086b3;
833 --zig-string-literal: #d14;
834 --zig-type: #458;
835 --zig-fn: #900;
836 }
837
838 @media (prefers-color-scheme: dark) {
839 pre {
840 --zig-keyword: #eee;
841 --zig-builtin: #ff894c;
842 --zig-identifier: #bbbbbb;
843 --zig-decl-identifier: lightblue;
844 --zig-string-literal: #2e5;
845 --zig-type: #68f;
846 --zig-fn: #e33;
847 }
848 }
849
850 .zig_keyword_addrspace,
851 .zig_keyword_align,
852 .zig_keyword_and,
853 .zig_keyword_asm,
854 .zig_keyword_async,
855 .zig_keyword_await,
856 .zig_keyword_break,
857 .zig_keyword_catch,
858 .zig_keyword_comptime,
859 .zig_keyword_const,
860 .zig_keyword_continue,
861 .zig_keyword_defer,
862 .zig_keyword_else,
863 .zig_keyword_enum,
864 .zig_keyword_errdefer,
865 .zig_keyword_error,
866 .zig_keyword_export,
867 .zig_keyword_extern,
868 .zig_keyword_for,
869 .zig_keyword_if,
870 .zig_keyword_inline,
871 .zig_keyword_noalias,
872 .zig_keyword_noinline,
873 .zig_keyword_nosuspend,
874 .zig_keyword_opaque,
875 .zig_keyword_or,
876 .zig_keyword_orelse,
877 .zig_keyword_packed,
878 .zig_keyword_anyframe,
879 .zig_keyword_pub,
880 .zig_keyword_resume,
881 .zig_keyword_return,
882 .zig_keyword_linksection,
883 .zig_keyword_callconv,
884 .zig_keyword_struct,
885 .zig_keyword_suspend,
886 .zig_keyword_switch,
887 .zig_keyword_test,
888 .zig_keyword_threadlocal,
889 .zig_keyword_try,
890 .zig_keyword_union,
891 .zig_keyword_unreachable,
892 .zig_keyword_usingnamespace,
893 .zig_keyword_var,
894 .zig_keyword_volatile,
895 .zig_keyword_allowzero,
896 .zig_keyword_while,
897 .zig_keyword_anytype,
898 .zig_keyword_fn
899 {
900 color: var(--zig-keyword);
901 font-weight: bold;
902 }
903
904
905 .zig_string_literal,
906 .zig_multiline_string_literal_line,
907 .zig_char_literal
908 {
909 color: var(--zig-string-literal);
910 }
911
912 .zig_builtin
913 {
914 color: var(--zig-builtin);
915 }
916
917 .zig_doc_comment,
918 .zig_container_doc_comment,
919 .zig_line_comment {
920 color: #545454;
921 font-style: italic;
922 }
923
924 .zig_identifier {
925 color: var(--zig-identifier);
926 font-weight: bold;
927 }
928
929 .zig_decl_identifier {
930 color: var(--zig-decl-identifier);
931 font-weight: bold;
932 }
933
934 .zig_number_literal,
935 .zig_special {
936 color: #ff8080;
937 }
938
939 .zig_type {
940 color: var(--zig-type);
941 font-weight: bold;
942 }
943
944 .zig_fn {
945 color: var(--zig-fn);
946 font-weight: bold;
947 }
948
949278 </style>
950279 </head>
951 <body class="canvas">
952 <div id="banner" class="banner">
953 This is a beta autodoc build; expect bugs and missing information.
954 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>,
955 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
956 <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
280 <body>
281 <nav>
282 <a class="logo" href="#">
283 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
284 <g fill="#F7A41D">
285 <g>
286 <polygon points="46,22 28,44 19,30"/>
287 <polygon points="46,22 33,33 28,44 22,44 22,95 31,95 20,100 12,117 0,117 0,22" shape-rendering="crispEdges"/>
288 <polygon points="31,95 12,117 4,106"/>
289 </g>
290 <g>
291 <polygon points="56,22 62,36 37,44"/>
292 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
293 <polygon points="116,95 97,117 90,104"/>
294 <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
295 <polygon points="150,0 52,117 3,140 101,22"/>
296 </g>
297 <g>
298 <polygon points="141,22 140,40 122,45"/>
299 <polygon points="153,22 153,117 106,117 120,105 125,95 131,95 131,45 122,45 132,36 141,22" shape-rendering="crispEdges"/>
300 <polygon points="125,95 130,110 106,117"/>
301 </g>
302 </g>
303 <style>
304 #text { fill: #121212 }
305 @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
306 </style>
307 <g id="text">
308 <g>
309 <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
310 <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
311 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
312 </g>
313 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
314 <g>
315 <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
316 <polygon points="360,68 376,81 346,67"/>
317 <path d="M394,106c-10.2,7.3-24,12-37.7,12c-29,0-51.1-20.8-51.1-48.3c0-27.3,22.5-48.1,52-48.1 c14.3,0,29.2,5.5,38.9,14l-13,15c-7.1-6.3-16.8-10-25.9-10c-17,0-30.2,12.9-30.2,29.5c0,16.8,13.3,29.6,30.3,29.6 c5.7,0,12.8-2.3,19-5.5L394,106z"/>
318 </g>
319 </g>
320 </svg>
321 </a>
322 </nav>
323 <div id="navWrap">
324 <input type="search" id="search" autocomplete="off" spellcheck="false" placeholder="`s` to search, `?` to see more options">
325 <div id="sectNav" class="hidden"><ul id="listNav"></ul></div>
957326 </div>
958 <div id="main" class="flex-main">
959 <div class="flex-horizontal" style="justify-content: center; padding: 0 0.5rem;">
960 <div class="flex-left">
961 <div class="logo">
962 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
963 <g fill="#F7A41D">
964 <g>
965 <polygon points="46,22 28,44 19,30"/>
966 <polygon points="46,22 33,33 28,44 22,44 22,95 31,95 20,100 12,117 0,117 0,22" shape-rendering="crispEdges"/>
967 <polygon points="31,95 12,117 4,106"/>
968 </g>
969 <g>
970 <polygon points="56,22 62,36 37,44"/>
971 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
972 <polygon points="116,95 97,117 90,104"/>
973 <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
974 <polygon points="150,0 52,117 3,140 101,22"/>
975 </g>
976 <g>
977 <polygon points="141,22 140,40 122,45"/>
978 <polygon points="153,22 153,117 106,117 120,105 125,95 131,95 131,45 122,45 132,36 141,22" shape-rendering="crispEdges"/>
979 <polygon points="125,95 130,110 106,117"/>
980 </g>
981 </g>
982 <style>
983 #text { fill: #121212 }
984 @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
985 </style>
986 <g id="text">
987 <g>
988 <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
989 <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
990 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
991 </g>
992 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
993 <g>
994 <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
995 <polygon points="360,68 376,81 346,67"/>
996 <path d="M394,106c-10.2,7.3-24,12-37.7,12c-29,0-51.1-20.8-51.1-48.3c0-27.3,22.5-48.1,52-48.1 c14.3,0,29.2,5.5,38.9,14l-13,15c-7.1-6.3-16.8-10-25.9-10c-17,0-30.2,12.9-30.2,29.5c0,16.8,13.3,29.6,30.3,29.6 c5.7,0,12.8-2.3,19-5.5L394,106z"/>
997 </g>
998 </g>
999 </svg>
1000 </div>
1001 <div id="sectGuideApiSwitch">
1002 <ul class="guides-api-switch">
1003 <li><a id="ApiSwitch" class="active" href="#A;">API</a></li>
1004 <li><a id="guideSwitch" class="" href="#G;">Guides</a></li>
1005 </ul>
1006 </div>
1007 </div>
1008 <div class="flex-right" style="padding-top: 0.5rem;overflow:visible;">
1009 <div class="search-container" style="position:relative;">
1010 <div id="searchPlaceholder">
1011 <span id="searchPlaceholderText"><!-- populated by setPrefSlashSearch --></span>
1012 <span id="searchPlaceholderTextMobile">Search</span>
1013 </div>
1014 <input type="search" class="search" id="search" autocomplete="off" spellcheck="false" disabled>
1015 <div id="dotsPopover">
1016 Use spaces instead of dots. See $resource for more info.
1017 </div>
1018 </div>
1019 <div id="sectNavAPI" style="margin-top: 0.5rem;"><ul id="listNavAPI" class="listNav"></ul></div>
1020 <div id="sectNavGuides" class="hidden" style="margin-top: 0.5rem">
1021 <ul id="listNavGuides" class="listNav">
1022 <li>
1023 <a href="#G;" class="active">Index</a>
1024 </li>
1025 <li style="flex-grow:1;">
1026 <a href="#G;" class="active" onclick="scrollGuidesTop(event);"></a>
1027 </li>
1028 </ul>
1029 </div>
1030 </div>
1031 </div>
1032 <div style="height:100%; overflow:hidden;">
1033 <div id="sectSearchResults" class="docs hidden">
1034 <details id="searchHelp">
1035 <summary id="searchHelpSummary" class="normal">How to search effectively</summary>
1036 <div>
1037 <h2>How To Search Effectively</h2>
1038 <h3>Matching</h3>
1039 <ul>
1040 <li>Search is case-insensitive by default.</li>
1041 <li>Using uppercase letters in your query will make the search
1042 case-sensitive.</li>
1043 <li>Given <code>ArrayListUnmanaged</code>:
1044 <ul>
1045 <li>the following search terms (and their prefixes) will match:
1046 <ul>
1047 <li><code>array</code></li>
1048 <li><code>list</code></li>
1049 <li><code>unmanaged</code></li>
1050 </ul>
1051 </li>
1052 <li>the following search terms will <b>NOT</b> match:
1053 <ul>
1054 <li><code>stun</code></li>
1055 <li><code>ray</code></li>
1056 <li><code>managed</code></li>
1057 </ul>
1058 </li>
1059 </ul>
1060 </li>
1061 <li>More precisely, the search system is based on a Radix Tree. The Radix Tree contains full decl names plus some suffixes, split by following the official style guide (e.g. <code>HashMapUnmanaged</code> also produces <code>MapUnmanaged</code> and <code>Unmanaged</code>, same with snake_case and camelCase names). </li>
1062 </ul>
1063
1064 <h3>Multiple terms</h3>
1065
1066 <ul>
1067 <li>When a search query contains multiple terms, order doesn't matter when
1068 all terms match within a single decl name (e.g. "map auto" will match <code>AutoHashMap</code>).</li>
1069 <li>Query term order does matter when matching different decls alognside
1070 a path (e.g. "js parse" matching <code>std.json.parse</code>), in which
1071 case the order of the terms will determine whether the match goes above or
1072 below the "other results" line.</li>
1073 <li>As an example, "fs create" will put above the line all things related to the creation of files and directories inside of `std.fs`, while still showing (but below the line) matches from `std.Bulild`.</li>
1074 <li>As another example, "fs windows" will prioritize windows-related results in `std.fs`, while "windows fs" will prioritize "fs"-related results in `std.windows`.</li>
1075 <li>This means that if you're searching inside a target namespace, you never have to read below the "other results" line.</li>
1076 <li>Since matching doesn't have to be perfect, you can also target a group of namespaces to search into. For example "array orderedremove" will show you all "Array-" namespaces that support <code>orderedRemove</code>.</li>
1077 <li>Periods are replaced by spaces because the Radix Tree doesn't index full paths, and in practice you should expect the match scoring system to consistently give you what you're looking for even when your query path is split into multiple terms.</li>
1078 </ul>
1079 </div>
1080 </details>
1081 <h2>Search Results</h2>
1082 <ul id="listSearchResults"></ul>
1083 <p id="sectSearchAllResultsLink" class="hidden"><a href="">show all results</a></p>
1084 </div>
1085 <div id="sectSearchNoResults" class="docs hidden">
1086 <h2>No Results Found</h2>
1087 <p>Here are some things you can try:</p>
1088 <ul>
1089 <li>Check out the <a id="langRefLink">Language Reference</a> for the language itself.</li>
1090 <li>Check out the <a href="https://ziglang.org/learn/">Learn page</a> for other helpful resources for learning Zig.</li>
1091 <li>Use your search engine.</li>
1092 </ul>
1093 <p>Press <kbd>?</kbd> to see keyboard shortcuts and <kbd>Esc</kbd> to return.</p>
1094 </div>
1095 <div id="guides" class="flex-horizontal hidden" style="align-items:flex-start;height:100%;overflow:hidden;">
1096 <div id="guidesMenu" class="sidebar">
1097 <h2 id="guidesMenuTitle">Table of Contents</h2>
1098 <div id="guideTocListEmpty" style="margin:0 1rem;"><i>No content to display.</i></div>
1099 <div id="guideTocList" style="height:100%;overflow-y:scroll;"></div>
1100 </div>
1101 <div id="activeGuide" class="hidden"></div>
1102 </div>
1103 <div id="docs" class="hidden" style="align-items:flex-start;height:100%;overflow:hidden;">
1104 <section id="docs-scroll" class="docs">
1105 <p id="status">Loading...</p>
1106 <div id="fnProto" class="hidden">
1107 <div class="mobile-scroll-container"><pre id="fnProtoCode" class="scroll-item"></pre></div>
1108 <div id="fnSourceLink" style="display:flex;flex-direction:row;justify-content:flex-end;"></div>
1109 </div>
1110 <h1 id="hdrName" class="hidden"></h1>
1111 <div id="fnNoExamples" class="hidden">
1112 <p>This function is not tested or referenced.</p>
1113 </div>
1114 <div id="declNoRef" class="hidden">
1115 <p>
1116 This declaration is not tested or referenced, and it has therefore not been included in
1117 semantic analysis, which means the only documentation available is whatever is in the
1118 doc comments.
1119 </p>
1120 </div>
1121 <div id="tldDocs" class="hidden"></div>
1122 <div id="sectParams" class="hidden">
1123 <h2>Parameters</h2>
1124 <div id="listParams"></div>
1125 </div>
1126 <div id="sectFnErrors" class="hidden">
1127 <h2>Errors</h2>
1128 <div id="fnErrorsAnyError">
1129 <p><span class="tok-type">anyerror</span> means the error set is known only at runtime.</p>
1130 </div>
1131 <div id="tableFnErrors"><dl id="listFnErrors"></dl></div>
1132 </div>
1133 <div id="sectFields" class="hidden">
1134 <h2>Fields</h2>
1135 <div id="listFields"></div>
1136 </div>
1137 <div id="sectNamespaces" class="hidden">
1138 <div style="position:relative;">
1139 <h2 style="position:sticky; top:0; background-color:var(--bg-color)">Namespaces</h2>
1140 <div class="flex-horizontal" style="justify-content:space-around;align-items:flex-start;flex-wrap:wrap;">
1141 <ul id="listNamespacesLeft" class="column"></ul>
1142 <ul id="listNamespacesRight" class="column"></ul>
1143 </div>
1144 </div>
1145 <h3>Other Namespaces <span style="font-size:1.1rem; cursor:pointer;" title="This box contains namespaces that are exported without a doc comment.">&#9432;</span></h3>
1146 <div id="noDocsNamespaces"></div>
1147 </div>
1148 <div id="sectTypes" class="hidden">
1149 <div style="position:relative;">
1150 <h2 style="position:sticky; top:0; background-color:var(--bg-color)">Types</h2>
1151 <div class="flex-horizontal" style="justify-content:space-around;align-items:flex-start;flex-wrap:wrap;">
1152 <ul id="listTypesLeft" class="column"></ul>
1153 <ul id="listTypesRight" class="column"></ul>
1154 </div>
1155 </div>
1156 </div>
1157 <div id="sectGlobalVars" class="hidden">
1158 <h2>Global Variables</h2>
1159 <div class="table-container">
1160 <table>
1161 <tbody id="listGlobalVars"></tbody>
1162 </table>
1163 </div>
1164 </div>
1165 <div id="sectFns" class="hidden">
1166 <h2>Functions</h2>
1167 <div class="table-container">
1168 <dl id="listFns"></dl>
1169 </div>
1170 </div>
1171 <div id="sectValues" class="hidden">
1172 <h2>Values</h2>
1173 <div class="table-container">
1174 <table>
1175 <tbody id="listValues"></tbody>
1176 </table>
1177 </div>
1178 </div>
1179 <div id="sectErrSets" class="hidden">
1180 <h2>Error Sets</h2>
1181 <ul id="listErrSets"></ul>
1182 </div>
1183 <div id="fnExamples" class="hidden">
1184 <h2>Examples</h2>
1185 <ul id="listFnExamples" class="examples"></ul>
1186 </div>
1187 <div id="sectDocTests" class="hidden">
1188 <h2>Usage Examples <span style="font-size:1.1rem; cursor:pointer;" title="See `doctests` in the language reference to learn more.">&#9432;</span></h2>
1189 <pre id="docTestsCode"></pre>
1190 </div>
1191 <div id="sectTests" class="hidden">
1192 <h2>Tests</h2>
1193 <div class="table-container">
1194 <table>
1195 <tbody id="listTests"></tbody>
1196 </table>
1197 </div>
1198 </div>
1199 </section>
1200 </div>
1201 <div class="flex-filler"></div>
327 <section>
328 <p id="status">Loading...</p>
329 <h1 id="hdrName" class="hidden"><span></span><a href="#">[src]</a></h1>
330 <div id="fnProto" class="hidden">
331 <pre><code id="fnProtoCode"></code></pre>
332 </div>
333 <div id="tldDocs" class="hidden"></div>
334 <div id="sectParams" class="hidden">
335 <h2>Parameters</h2>
336 <div id="listParams">
1202337 </div>
1203338 </div>
1204 <div id="helpModal" class="hidden">
1205 <div class="modal-container">
1206 <div class="modal">
1207 <h1>Keyboard Shortcuts</h1>
1208 <dl><dt><kbd>?</kbd></dt><dd>Toggle this help modal</dd></dl>
1209 <dl><dt id="searchKeys"><!-- populated by setPrefSlashSearch --></dt><dd>Focus the search field</dd></dl>
1210 <div style="margin-left: 1em">
1211 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl>
1212 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>
1213 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>
1214 </div>
1215 <dl><dt><kbd>p</kbd></dt><dd>Open preferences</dd></dl>
1216 <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this modal</dd></dl>
1217 </div>
339 <div id="sectFnErrors" class="hidden">
340 <h2>Errors</h2>
341 <div id="fnErrorsAnyError">
342 <p><span class="tok-type">anyerror</span> means the error set is known only at runtime.</p>
1218343 </div>
344 <div id="tableFnErrors"><dl id="listFnErrors"></dl></div>
1219345 </div>
1220 <div id="prefsModal" class="hidden">
1221 <div class="modal-container">
1222 <div class="modal">
1223 <h1>Preferences</h1>
1224 <ul class="prefs-list">
1225 <li><input id="prefSlashSearch" type="checkbox"><label for="prefSlashSearch">Enable <kbd>/</kbd> for search</label></li>
1226 </ul>
1227 </div>
346 <div id="sectSearchResults" class="hidden">
347 <h2>Search Results</h2>
348 <ul id="listSearchResults"></ul>
349 </div>
350 <div id="sectSearchNoResults" class="hidden">
351 <h2>No Results Found</h2>
352 <p>Press escape to exit search and then '?' to see more options.</p>
353 </div>
354 <div id="sectFields" class="hidden">
355 <h2>Fields</h2>
356 <div id="listFields">
1228357 </div>
1229358 </div>
1230 <script src="data-typeKinds.js"></script>
1231 <script src="data-rootMod.js"></script>
1232 <script src="data-modules.js"></script>
1233 <script src="data-files.js"></script>
1234 <script src="data-calls.js"></script>
1235 <script src="data-types.js"></script>
1236 <script src="data-decls.js"></script>
1237 <script src="data-exprs.js"></script>
1238 <script src="data-astNodes.js"></script>
1239 <script src="data-comptimeExprs.js"></script>
1240 <script src="data-guideSections.js"></script>
1241 <script src="commonmark.js"></script>
1242 <script src="ziglexer.js"></script>
359 <div id="sectTypes" class="hidden">
360 <h2>Types</h2>
361 <ul id="listTypes" class="columns">
362 </ul>
363 </div>
364 <div id="sectNamespaces" class="hidden">
365 <h2>Namespaces</h2>
366 <ul id="listNamespaces" class="columns">
367 </ul>
368 </div>
369 <div id="sectGlobalVars" class="hidden">
370 <h2>Global Variables</h2>
371 <table>
372 <tbody id="listGlobalVars">
373 </tbody>
374 </table>
375 </div>
376 <div id="sectValues" class="hidden">
377 <h2>Values</h2>
378 <table>
379 <tbody id="listValues">
380 </tbody>
381 </table>
382 </div>
383 <div id="sectFns" class="hidden">
384 <h2>Functions</h2>
385 <dl id="listFns">
386 </dl>
387 </div>
388 <div id="sectErrSets" class="hidden">
389 <h2>Error Sets</h2>
390 <ul id="listErrSets" class="columns">
391 </ul>
392 </div>
393 <div id="sectDocTests" class="hidden">
394 <h2>Example Usage</h2>
395 <pre><code id="docTestsCode"></code></pre>
396 </div>
397 <div id="sectSource" class="hidden">
398 <h2>Source Code</h2>
399 <pre><code id="sourceText"></code></pre>
400 </div>
401 </section>
402 <div id="helpDialog" class="hidden">
403 <h1>Keyboard Shortcuts</h1>
404 <dl><dt><kbd>?</kbd></dt><dd>Show this help dialog</dd></dl>
405 <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this dialog</dd></dl>
406 <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl>
407 <dl><dt><kbd>u</kbd></dt><dd>Go to source code</dd></dl>
408 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl>
409 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>
410 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>
411 </div>
1243412 <script src="main.js"></script>
1244413 </body>
1245414</html>
415
lib/docs/main.js+824-5079
......@@ -1,5242 +1,987 @@
1"use strict";
2
3var zigAnalysis = {
4 typeKinds,
5 rootMod,
6 modules,
7 astNodes,
8 calls,
9 files,
10 decls,
11 exprs,
12 types,
13 comptimeExprs,
14 guideSections
15};
16
17let skipNextHashChange = null;
18
19const NAV_MODES = {
20 API: "#A;",
21 GUIDES: "#G;",
22};
23
24
25var scrollHistory = {};
26
271(function() {
28 const domBanner = document.getElementById("banner");
29 const domMain = document.getElementById("main");
30 const domStatus = document.getElementById("status");
31 const domSectNavAPI = document.getElementById("sectNavAPI");
32 const domListNavAPI = document.getElementById("listNavAPI");
33 const domSectNavGuides = document.getElementById("sectNavGuides");
34 const domListNavGuides = document.getElementById("listNavGuides");
35 const domApiSwitch = document.getElementById("ApiSwitch");
36 const domGuideSwitch = document.getElementById("guideSwitch");
37 const domGuidesMenu = document.getElementById("guidesMenu");
38 const domGuidesMenuTitle = document.getElementById("guidesMenuTitle");
39 const domGuideTocList = document.getElementById("guideTocList");
40 const domGuideTocListEmtpy = document.getElementById("guideTocListEmpty");
41 const domListMods = document.getElementById("listMods");
42 const domSectTypes = document.getElementById("sectTypes");
43 const domListTypesLeft = document.getElementById("listTypesLeft");
44 const domListTypesRight = document.getElementById("listTypesRight");
45 const domSectTests = document.getElementById("sectTests");
46 const domListTests = document.getElementById("listTests");
47 const domSectDocTests = document.getElementById("sectDocTests");
48 const domDocTestsCode = document.getElementById("docTestsCode");
49 const domSectNamespaces = document.getElementById("sectNamespaces");
50 const domListNamespacesLeft = document.getElementById("listNamespacesLeft");
51 const domListNamespacesRight = document.getElementById("listNamespacesRight");
52 const domNoDocsNamespaces = document.getElementById("noDocsNamespaces");
53 const domSectErrSets = document.getElementById("sectErrSets");
54 const domListErrSets = document.getElementById("listErrSets");
55 const domSectFns = document.getElementById("sectFns");
56 const domListFns = document.getElementById("listFns");
57 const domSectFields = document.getElementById("sectFields");
58 const domListFields = document.getElementById("listFields");
59 const domSectGlobalVars = document.getElementById("sectGlobalVars");
60 const domListGlobalVars = document.getElementById("listGlobalVars");
61 const domSectValues = document.getElementById("sectValues");
62 const domListValues = document.getElementById("listValues");
63 const domFnProto = document.getElementById("fnProto");
64 const domFnProtoCode = document.getElementById("fnProtoCode");
65 const domFnSourceLink = document.getElementById("fnSourceLink");
66 const domSectParams = document.getElementById("sectParams");
67 const domListParams = document.getElementById("listParams");
68 const domTldDocs = document.getElementById("tldDocs");
69 const domSectFnErrors = document.getElementById("sectFnErrors");
70 const domListFnErrors = document.getElementById("listFnErrors");
71 const domTableFnErrors = document.getElementById("tableFnErrors");
72 const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
73 const domFnExamples = document.getElementById("fnExamples");
74 // const domListFnExamples = (document.getElementById("listFnExamples"));
75 const domFnNoExamples = document.getElementById("fnNoExamples");
76 const domDeclNoRef = document.getElementById("declNoRef");
77 const domSearch = document.getElementById("search");
78 const domSearchHelp = document.getElementById("searchHelp");
79 const domSearchHelpSummary = document.getElementById("searchHelpSummary");
80 const domSectSearchResults = document.getElementById("sectSearchResults");
81 const domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink");
82 const domDocs = document.getElementById("docs");
83 const domDocsScroll = document.getElementById("docs-scroll");
84 const domGuidesSection = document.getElementById("guides");
85 const domActiveGuide = document.getElementById("activeGuide");
86
87 const domListSearchResults = document.getElementById("listSearchResults");
88 const domSectSearchNoResults = document.getElementById("sectSearchNoResults");
89 // const domTdTarget = (document.getElementById("tdTarget"));
90 const domTdZigVer = document.getElementById("tdZigVer");
91 const domHdrName = document.getElementById("hdrName");
92 const domHelpModal = document.getElementById("helpModal");
93 const domSearchKeys = document.getElementById("searchKeys");
94 const domPrefsModal = document.getElementById("prefsModal");
95 const domSearchPlaceholder = document.getElementById("searchPlaceholder");
96 const domSearchPlaceholderText = document.getElementById("searchPlaceholderText");
97 const sourceFileUrlTemplate = "src/{{mod}}/{{file}}.html#L{{line}}"
98 const domLangRefLink = document.getElementById("langRefLink");
99
100 const domPrefSlashSearch = document.getElementById("prefSlashSearch");
101 const prefs = getLocalStorage();
102 loadPrefs();
103
104 domPrefSlashSearch.addEventListener("change", () => setPrefSlashSearch(domPrefSlashSearch.checked));
105
106 const scrollMonitor = [
107 domActiveGuide,
108 domGuideTocList,
109 domDocsScroll,
110 domSectSearchResults,
111 ];
112
113 computeGuideHashes();
114
115 let searchTimer = null;
116 let searchTrimResults = true;
117
118 let escapeHtmlReplacements = {
119 "&": "&amp;",
120 '"': "&quot;",
121 "<": "&lt;",
122 ">": "&gt;",
123 };
124
125 let typeKinds = indexTypeKinds();
126 let typeTypeId = findTypeTypeId();
127 let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
128
129 let declSearchIndex = new RadixTree();
130 window.search = declSearchIndex;
131
132 // for each module, is an array with modules to get to this one
133 let canonModPaths = computeCanonicalModulePaths();
134
135 // for each decl, is an array with {declNames, modNames} to get to this one
136 let canonDeclPaths = null; // lazy; use getCanonDeclPath
137
138 // for each type, is an array with {declNames, modNames} to get to this one
139 let canonTypeDecls = null; // lazy; use getCanonTypeDecl
140
141 let curNav = {
142 hash: "",
143 mode: NAV_MODES.API,
144 activeGuide: "",
145 activeGuideScrollTo: null,
146 // each element is a module name, e.g. @import("a") then within there @import("b")
147 // starting implicitly from root module
148 modNames: [],
149 // same as above except actual modules, not names
150 modObjs: [],
151 // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc.
152 // empty array means refers to the module itself
153 declNames: [],
154 // these will be all types, except the last one may be a type or a decl
155 declObjs: [],
156 // (a, b, c, d) comptime call; result is the value the docs refer to
157 callName: null,
158 };
159
160 let curNavSearch = "";
161 let curSearchIndex = -1;
162 let imFeelingLucky = false;
163
164 let rootIsStd = detectRootIsStd();
165
166 // map of decl index to list of non-generic fn indexes
167 // let nodesToFnsMap = indexNodesToFns();
168 // map of decl index to list of comptime fn calls
169 // let nodesToCallsMap = indexNodesToCalls();
2 const CAT_namespace = 0;
3 const CAT_global_variable = 1;
4 const CAT_function = 2;
5 const CAT_primitive = 3;
6 const CAT_error_set = 4;
7 const CAT_global_const = 5;
8 const CAT_alias = 6;
9 const CAT_type = 7;
10 const CAT_type_type = 8;
11 const CAT_type_function = 9;
12
13 const domDocTestsCode = document.getElementById("docTestsCode");
14 const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
15 const domFnProto = document.getElementById("fnProto");
16 const domFnProtoCode = document.getElementById("fnProtoCode");
17 const domHdrName = document.getElementById("hdrName");
18 const domHelpModal = document.getElementById("helpDialog");
19 const domListErrSets = document.getElementById("listErrSets");
20 const domListFields = document.getElementById("listFields");
21 const domListParams = document.getElementById("listParams");
22 const domListFnErrors = document.getElementById("listFnErrors");
23 const domListFns = document.getElementById("listFns");
24 const domListGlobalVars = document.getElementById("listGlobalVars");
25 const domListInfo = document.getElementById("listInfo");
26 const domListNamespaces = document.getElementById("listNamespaces");
27 const domListNav = document.getElementById("listNav");
28 const domListSearchResults = document.getElementById("listSearchResults");
29 const domListTypes = document.getElementById("listTypes");
30 const domListValues = document.getElementById("listValues");
31 const domSearch = document.getElementById("search");
32 const domSectDocTests = document.getElementById("sectDocTests");
33 const domSectErrSets = document.getElementById("sectErrSets");
34 const domSectFields = document.getElementById("sectFields");
35 const domSectParams = document.getElementById("sectParams");
36 const domSectFnErrors = document.getElementById("sectFnErrors");
37 const domSectFns = document.getElementById("sectFns");
38 const domSectGlobalVars = document.getElementById("sectGlobalVars");
39 const domSectNamespaces = document.getElementById("sectNamespaces");
40 const domSectNav = document.getElementById("sectNav");
41 const domSectSearchNoResults = document.getElementById("sectSearchNoResults");
42 const domSectSearchResults = document.getElementById("sectSearchResults");
43 const domSectSource = document.getElementById("sectSource");
44 const domSectTypes = document.getElementById("sectTypes");
45 const domSectValues = document.getElementById("sectValues");
46 const domSourceText = document.getElementById("sourceText");
47 const domStatus = document.getElementById("status");
48 const domTableFnErrors = document.getElementById("tableFnErrors");
49 const domTldDocs = document.getElementById("tldDocs");
50
51 var searchTimer = null;
52
53 const curNav = {
54 // 0 = home
55 // 1 = decl (decl)
56 // 2 = source (path)
57 tag: 0,
58 // unsigned int: decl index
59 decl: null,
60 // string file name matching tarball path
61 path: null,
62
63 // when this is populated, pressing the "view source" command will
64 // navigate to this hash.
65 viewSourceHash: null,
66 };
67 var curNavSearch = "";
68 var curSearchIndex = -1;
69 var imFeelingLucky = false;
17070
171 let guidesSearchIndex = {};
172 window.guideSearch = guidesSearchIndex;
173 parseGuides();
71 // names of modules in the same order as wasm
72 const moduleList = [];
17473
175 // identifiers can contain modal trigger characters so we want to allow typing
176 // such characters when the search is focused instead of toggling the modal
177 let canToggleModal = true;
74 let wasm_promise = fetch("main.wasm");
75 let sources_promise = fetch("sources.tar").then(function(response) {
76 if (!response.ok) throw new Error("unable to download sources");
77 return response.arrayBuffer();
78 });
79 var wasm_exports = null;
17880
179 domSearch.disabled = false;
180 domSearch.addEventListener("keydown", onSearchKeyDown, false);
181 domSearch.addEventListener("input", onSearchInput, false);
182 domSearch.addEventListener("focus", ev => {
183 domSearchPlaceholder.classList.add("hidden");
184 canToggleModal = false;
185 });
186 domSearch.addEventListener("blur", ev => {
187 if (domSearch.value.length == 0)
188 domSearchPlaceholder.classList.remove("hidden");
189 canToggleModal = true;
190 });
191 domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
192 function onClickSearchShowAllResults(ev) {
193 ev.preventDefault();
194 ev.stopPropagation();
195 searchTrimResults = false;
196 onHashChange();
197 }
81 const text_decoder = new TextDecoder();
82 const text_encoder = new TextEncoder();
19883
199 if (location.hash == "") {
200 location.hash = "#A;";
201 }
84 WebAssembly.instantiateStreaming(wasm_promise, {
85 js: {
86 log: function(ptr, len) {
87 const msg = decodeString(ptr, len);
88 console.log(msg);
89 },
90 panic: function (ptr, len) {
91 const msg = decodeString(ptr, len);
92 throw new Error("panic: " + msg);
93 },
94 },
95 }).then(function(obj) {
96 wasm_exports = obj.instance.exports;
97 window.wasm = obj; // for debugging
98
99 sources_promise.then(function(buffer) {
100 const js_array = new Uint8Array(buffer);
101 const ptr = wasm_exports.alloc(js_array.length);
102 const wasm_array = new Uint8Array(wasm_exports.memory.buffer, ptr, js_array.length);
103 wasm_array.set(js_array);
104 wasm_exports.unpack(ptr, js_array.length);
105
106 updateModuleList();
107
108 window.addEventListener('popstate', onPopState, false);
109 domSearch.addEventListener('keydown', onSearchKeyDown, false);
110 domSearch.addEventListener('input', onSearchChange, false);
111 window.addEventListener('keydown', onWindowKeyDown, false);
112 onHashChange(null);
113 });
114 });
202115
203 // make the modal disappear if you click outside it
204 function handleModalClick(ev) {
205 if (ev.target.classList.contains("modal-container")) {
206 hideModal(this);
116 function renderTitle() {
117 const suffix = " - Zig Documentation";
118 if (curNavSearch.length > 0) {
119 document.title = curNavSearch + " - Search" + suffix;
120 } else if (curNav.decl != null) {
121 document.title = fullyQualifiedName(curNav.decl) + suffix;
122 } else if (curNav.path != null) {
123 document.title = curNav.path + suffix;
124 } else {
125 document.title = moduleList[0] + suffix; // Home
126 }
127 }
128
129 function render() {
130 domFnErrorsAnyError.classList.add("hidden");
131 domFnProto.classList.add("hidden");
132 domHdrName.classList.add("hidden");
133 domHelpModal.classList.add("hidden");
134 domSectErrSets.classList.add("hidden");
135 domSectDocTests.classList.add("hidden");
136 domSectFields.classList.add("hidden");
137 domSectParams.classList.add("hidden");
138 domSectFnErrors.classList.add("hidden");
139 domSectFns.classList.add("hidden");
140 domSectGlobalVars.classList.add("hidden");
141 domSectNamespaces.classList.add("hidden");
142 domSectNav.classList.add("hidden");
143 domSectSearchNoResults.classList.add("hidden");
144 domSectSearchResults.classList.add("hidden");
145 domSectSource.classList.add("hidden");
146 domSectTypes.classList.add("hidden");
147 domSectValues.classList.add("hidden");
148 domStatus.classList.add("hidden");
149 domTableFnErrors.classList.add("hidden");
150 domTldDocs.classList.add("hidden");
151
152 renderTitle();
153
154 if (curNavSearch !== "") return renderSearch();
155
156 switch (curNav.tag) {
157 case 0: return renderHome();
158 case 1:
159 if (curNav.decl == null) {
160 return renderNotFound();
161 } else {
162 return renderDecl(curNav.decl);
163 }
164 case 2: return renderSource(curNav.path);
165 default: throw new Error("invalid navigation state");
166 }
207167 }
208 }
209 domHelpModal.addEventListener("click", handleModalClick);
210 domPrefsModal.addEventListener("click", handleModalClick);
211
212 window.addEventListener("hashchange", onHashChange, false);
213 window.addEventListener("keydown", onWindowKeyDown, false);
214 onHashChange();
215
216 // TODO: fix this once langref becomes part of autodoc
217 let langRefVersion = "master";
218 domLangRefLink.href = `https://ziglang.org/documentation/${langRefVersion}/`;
219168
220 function renderTitle() {
221 let suffix = " - Zig";
222 switch (curNav.mode) {
223 case NAV_MODES.API:
224 let list = curNav.modNames.concat(curNav.declNames);
225 if (list.length === 0) {
226 document.title = zigAnalysis.modules[zigAnalysis.rootMod].name + suffix;
227 } else {
228 document.title = list.join(".") + suffix;
229 }
230 return;
231 case NAV_MODES.GUIDES:
232 document.title = "[G] " + curNav.activeGuide + suffix;
169 function renderHome() {
170 if (moduleList.length == 0) {
171 domStatus.textContent = "sources.tar contains no modules";
172 domStatus.classList.remove("hidden");
233173 return;
174 }
175 return renderModule(0);
234176 }
235 }
236177
237 function isDecl(x) {
238 return "value" in x;
239 }
240
241 function isType(x) {
242 return "kind" in x && !("value" in x);
243 }
244
245 function isContainerType(x) {
246 return isType(x) && typeKindIsContainer(x.kind);
247 }
248
249 function typeShorthandName(expr) {
250 let resolvedExpr = resolveValue({ expr: expr });
251 if (!("type" in resolvedExpr)) {
252 return null;
178 function renderModule(pkg_index) {
179 const root_decl = wasm_exports.find_module_root(pkg_index);
180 return renderDecl(root_decl);
253181 }
254 let type = getType(resolvedExpr.type);
255182
256 outer: for (let i = 0; i < 10000; i += 1) {
257 switch (type.kind) {
258 case typeKinds.Optional:
259 case typeKinds.Pointer:
260 let child = type.child;
261 let resolvedChild = resolveValue(child);
262 if ("type" in resolvedChild) {
263 type = getType(resolvedChild.type);
264 continue;
265 } else {
266 return null;
267 }
183 function renderDecl(decl_index) {
184 const category = wasm_exports.categorize_decl(decl_index, 0);
185 switch (category) {
186 case CAT_namespace:
187 return renderNamespacePage(decl_index);
188 case CAT_global_variable:
189 case CAT_primitive:
190 case CAT_global_const:
191 case CAT_type:
192 case CAT_type_type:
193 return renderGlobal(decl_index);
194 case CAT_function:
195 return renderFunction(decl_index);
196 case CAT_type_function:
197 return renderTypeFunction(decl_index);
198 case CAT_error_set:
199 return renderErrorSetPage(decl_index);
200 case CAT_alias:
201 return renderDecl(wasm_exports.get_aliasee());
268202 default:
269 break outer;
203 throw new Error("unrecognized category " + category);
270204 }
271
272 if (i == 9999) throw "Exhausted typeShorthandName quota";
273 }
274
275 let name = undefined;
276 if (type.kind === typeKinds.Struct) {
277 name = "struct";
278 } else if (type.kind === typeKinds.Enum) {
279 name = "enum";
280 } else if (type.kind === typeKinds.Union) {
281 name = "union";
282 } else {
283 console.log("TODO: unhandled case in typeShortName");
284 return null;
285205 }
286206
287 return escapeHtml(name);
288 }
207 function renderSource(path) {
208 const decl_index = findFileRoot(path);
209 if (decl_index == null) return renderNotFound();
289210
290 function typeKindIsContainer(typeKind) {
291 return (
292 typeKind === typeKinds.Struct ||
293 typeKind === typeKinds.Union ||
294 typeKind === typeKinds.Enum ||
295 typeKind === typeKinds.Opaque
296 );
297 }
211 renderNavFancy(decl_index, [{
212 name: "[src]",
213 href: location.hash,
214 }]);
298215
299 function declCanRepresentTypeKind(typeKind) {
300 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
301 }
216 domSourceText.innerHTML = declSourceHtml(decl_index);
302217
303 //
304 // function findCteInRefPath(path) {
305 // for (let i = path.length - 1; i >= 0; i -= 1) {
306 // const ref = path[i];
307 // if ("string" in ref) continue;
308 // if ("comptimeExpr" in ref) return ref;
309 // if ("refPath" in ref) return findCteInRefPath(ref.refPath);
310 // return null;
311 // }
312
313 // return null;
314 // }
315
316 function resolveValue(value, trackDecls) {
317 let seenDecls = [];
318 let i = 0;
319 while (true) {
320 i += 1;
321 if (i >= 10000) {
322 throw "resolveValue quota exceeded"
323 }
324
325 if ("refPath" in value.expr) {
326 value = { expr: value.expr.refPath[value.expr.refPath.length - 1] };
327 continue;
328 }
218 domSectSource.classList.remove("hidden");
219 }
329220
330 if ("declRef" in value.expr) {
331 seenDecls.push(value.expr.declRef);
332 value = getDecl(value.expr.declRef).value;
333 continue;
334 }
221 function renderDeclHeading(decl_index) {
222 curNav.viewSourceHash = "#src/" + unwrapString(wasm_exports.decl_file_path(decl_index));
335223
336 if ("as" in value.expr) {
337 value = {
338 typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
339 expr: zigAnalysis.exprs[value.expr.as.exprArg],
340 };
341 continue;
342 }
224 const hdrNameSpan = domHdrName.children[0];
225 const srcLink = domHdrName.children[1];
226 hdrNameSpan.innerText = unwrapString(wasm_exports.decl_category_name(decl_index));
227 srcLink.setAttribute('href', curNav.viewSourceHash);
228 domHdrName.classList.remove("hidden");
343229
344 if (trackDecls) return { value, seenDecls };
345 return value;
230 renderTopLevelDocs(decl_index);
346231 }
347 }
348
349 function resolveGenericRet(genericFunc) {
350 if (genericFunc.generic_ret == null) return null;
351 let result = resolveValue({ expr: genericFunc.generic_ret });
352
353 let i = 0;
354 while (true) {
355 i += 1;
356 if (i >= 10000) {
357 throw "resolveGenericRet quota exceeded"
358 }
359232
360 if ("call" in result.expr) {
361 let call = zigAnalysis.calls[result.expr.call];
362 let resolvedFunc = resolveValue({ expr: call.func });
363 if (!("type" in resolvedFunc.expr)) return null;
364 let callee = getType(resolvedFunc.expr.type);
365 if (!callee.generic_ret) return null;
366 result = resolveValue({ expr: callee.generic_ret });
367 continue;
233 function renderTopLevelDocs(decl_index) {
234 const tld_docs_html = unwrapString(wasm_exports.decl_docs_html(decl_index, false));
235 if (tld_docs_html.length > 0) {
236 domTldDocs.innerHTML = tld_docs_html;
237 domTldDocs.classList.remove("hidden");
368238 }
369
370 return result;
371239 }
372 }
373240
374 // function typeOfDecl(decl){
375 // return decl.value.typeRef;
376 //
377 // let i = 0;
378 // while(i < 1000) {
379 // i += 1;
380 // console.assert(isDecl(decl));
381 // if ("type" in decl.value) {
382 // return ({ type: typeTypeId });
383 // }
384 //
385 //// if ("string" in decl.value) {
386 //// return ({ type: {
387 //// kind: typeKinds.Pointer,
388 //// size: pointerSizeEnum.One,
389 //// child: });
390 //// }
391 //
392 // if ("refPath" in decl.value) {
393 // decl = ({
394 // value: decl.value.refPath[decl.value.refPath.length -1]
395 // });
396 // continue;
397 // }
398 //
399 // if ("declRef" in decl.value) {
400 // decl = zigAnalysis.decls[decl.value.declRef];
401 // continue;
402 // }
403 //
404 // if ("int" in decl.value) {
405 // return decl.value.int.typeRef;
406 // }
407 //
408 // if ("float" in decl.value) {
409 // return decl.value.float.typeRef;
410 // }
411 //
412 // if ("array" in decl.value) {
413 // return decl.value.array.typeRef;
414 // }
415 //
416 // if ("struct" in decl.value) {
417 // return decl.value.struct.typeRef;
418 // }
419 //
420 // if ("comptimeExpr" in decl.value) {
421 // const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
422 // return cte.typeRef;
423 // }
424 //
425 // if ("call" in decl.value) {
426 // const fn_call = zigAnalysis.calls[decl.value.call];
427 // let fn_decl = undefined;
428 // if ("declRef" in fn_call.func) {
429 // fn_decl = zigAnalysis.decls[fn_call.func.declRef];
430 // } else if ("refPath" in fn_call.func) {
431 // console.assert("declRef" in fn_call.func.refPath[fn_call.func.refPath.length -1]);
432 // fn_decl = zigAnalysis.decls[fn_call.func.refPath[fn_call.func.refPath.length -1].declRef];
433 // } else throw {};
434 //
435 // const fn_decl_value = resolveValue(fn_decl.value);
436 // console.assert("type" in fn_decl_value); //TODO handle comptimeExpr
437 // const fn_type = (zigAnalysis.types[fn_decl_value.type]);
438 // console.assert(fn_type.kind === typeKinds.Fn);
439 // return fn_type.ret;
440 // }
441 //
442 // if ("void" in decl.value) {
443 // return ({ type: typeTypeId });
444 // }
445 //
446 // if ("bool" in decl.value) {
447 // return ({ type: typeKinds.Bool });
448 // }
449 //
450 // console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
451 // console.assert(false);
452 // throw {};
453 // }
454 // console.assert(false);
455 // return ({});
456 // }
457 function detectDeclPath(text, context) {
458 let result = "";
459 let separator = ":";
460 const components = text.split(".");
461 let curDeclOrType = undefined;
462
463 let curContext = context;
464 let limit = 10000;
465 while (curContext) {
466 limit -= 1;
467
468 if (limit == 0) {
469 throw "too many iterations";
470 }
471
472 curDeclOrType = findSubDecl(curContext, components[0]);
473
474 if (!curDeclOrType) {
475 if (curContext.parent_container == null) break;
476 curContext = getType(curContext.parent_container);
477 continue;
478 }
241 function renderNav(cur_nav_decl, list) {
242 return renderNavFancy(cur_nav_decl, []);
243 }
479244
480 if (curContext == context) {
481 separator = '.';
482 result = location.hash + separator + components[0];
483 } else {
484 // We had to go up, which means we need a new path!
485 const canonPath = getCanonDeclPath(curDeclOrType.find_subdecl_idx);
486 if (!canonPath) return;
487
488 let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
489 let fullPath = lastModName + ":" + canonPath.declNames.join(".");
490
491 separator = '.';
492 result = "#A;" + fullPath;
245 function renderNavFancy(cur_nav_decl, list) {
246 {
247 // First, walk backwards the decl parents within a file.
248 let decl_it = cur_nav_decl;
249 let prev_decl_it = null;
250 while (decl_it != null) {
251 list.push({
252 name: declIndexName(decl_it),
253 href: navLinkDeclIndex(decl_it),
254 });
255 prev_decl_it = decl_it;
256 decl_it = declParent(decl_it);
257 }
258
259 // Next, walk backwards the file path segments.
260 if (prev_decl_it != null) {
261 const file_path = fullyQualifiedName(prev_decl_it);
262 const parts = file_path.split(".");
263 parts.pop(); // skip last
264 for (;;) {
265 const href = navLinkFqn(parts.join("."));
266 const part = parts.pop();
267 if (!part) break;
268 list.push({
269 name: part,
270 href: href,
271 });
272 }
493273 }
494274
495 break;
496 }
275 list.reverse();
276 }
277 resizeDomList(domListNav, list.length, '<li><a href="#"></a></li>');
497278
498 if (!curDeclOrType) {
499 for (let i = 0; i < zigAnalysis.modules.length; i += 1){
500 const p = zigAnalysis.modules[i];
501 if (p.name == components[0]) {
502 curDeclOrType = getType(p.main);
503 result += "#A;" + components[0];
504 break;
279 for (let i = 0; i < list.length; i += 1) {
280 const liDom = domListNav.children[i];
281 const aDom = liDom.children[0];
282 aDom.textContent = list[i].name;
283 aDom.setAttribute('href', list[i].href);
284 if (i + 1 == list.length) {
285 aDom.classList.add("active");
286 } else {
287 aDom.classList.remove("active");
505288 }
506 }
507289 }
508290
509 if (!curDeclOrType) return null;
510
511 for (let i = 1; i < components.length; i += 1) {
512 curDeclOrType = findSubDecl(curDeclOrType, components[i]);
513 if (!curDeclOrType) return null;
514 result += separator + components[i];
515 separator = '.';
516 }
291 domSectNav.classList.remove("hidden");
292 }
517293
518 return result;
519
294 function renderNotFound() {
295 domStatus.textContent = "Declaration not found.";
296 domStatus.classList.remove("hidden");
520297 }
521
522 function renderGuides() {
523 renderTitle();
524298
525 // set guide mode
526 domGuideSwitch.classList.add("active");
527 domApiSwitch.classList.remove("active");
528 domDocs.classList.add("hidden");
529 domSectNavAPI.classList.add("hidden");
530 domSectNavGuides.classList.remove("hidden");
531 domGuidesSection.classList.remove("hidden");
532 domActiveGuide.classList.add("hidden");
533 domSectSearchResults.classList.add("hidden");
534 domSectSearchAllResultsLink.classList.add("hidden");
535 domSectSearchNoResults.classList.add("hidden");
536 if (curNavSearch !== "") {
537 return renderSearchGuides();
299 function navLinkFqn(full_name) {
300 return '#' + full_name;
538301 }
539302
540 let activeGuide = undefined;
541 outer: for (let i = 0; i < zigAnalysis.guideSections.length; i += 1) {
542 const section = zigAnalysis.guideSections[i];
543 for (let j = 0; j < section.guides.length; j += 1) {
544 const guide = section.guides[j];
545 if (guide.name == curNav.activeGuide) {
546 activeGuide = guide;
547 break outer;
303 function navLinkDeclIndex(decl_index) {
304 return navLinkFqn(fullyQualifiedName(decl_index));
305 }
306
307 function resizeDomList(listDom, desiredLen, templateHtml) {
308 // add the missing dom entries
309 var i, ev;
310 for (i = listDom.childElementCount; i < desiredLen; i += 1) {
311 listDom.insertAdjacentHTML('beforeend', templateHtml);
312 }
313 // remove extra dom entries
314 while (desiredLen < listDom.childElementCount) {
315 listDom.removeChild(listDom.lastChild);
548316 }
549 }
550317 }
551318
319 function renderErrorSetPage(decl_index) {
320 renderNav(decl_index);
321 renderDeclHeading(decl_index);
552322
553 // navigation bar
554
555 const guideIndexDom = domListNavGuides.children[0].children[0];
556 const guideDom = domListNavGuides.children[1].children[0];
557 if (activeGuide){
558 guideDom.textContent = activeGuide.title;
559 guideDom.setAttribute("href", location.hash);
560 guideDom.classList.remove("hidden");
561 guideIndexDom.classList.remove("active");
562 } else {
563 guideDom.classList.add("hidden");
564 guideIndexDom.classList.add("active");
565 }
323 const errorSetList = declErrorSet(decl_index).slice();
324 renderErrorSet(decl_index, errorSetList);
325 }
566326
567 // main content
568 domGuidesMenuTitle.textContent = "Table of Contents";
569 if (activeGuide) {
570 if (activeGuide.toc != "") {
571 domGuideTocList.innerHTML = activeGuide.toc;
572 // add js callbacks to all links
573 function onLinkClick(ev) {
574 const link = ev.target.getAttribute("href");
575 skipNextHashChange = link;
576 location.replace(link);
577 scrollToHeading(":" + link.split(":")[1], true);
578 ev.preventDefault();
579 ev.stopPropagation();
580 }
581 for (let a of domGuideTocList.querySelectorAll("a")) {
582 a.addEventListener('click', onLinkClick, false);
583 }
584 domGuideTocList.classList.remove("hidden");
585 domGuideTocListEmtpy.classList.add("hidden");
327 function renderErrorSet(base_decl, errorSetList) {
328 if (errorSetList == null) {
329 domFnErrorsAnyError.classList.remove("hidden");
586330 } else {
587 domGuideTocListEmtpy.classList.remove("hidden");
588 domGuideTocList.classList.add("hidden");
589 }
590
591 let reader = new commonmark.Parser({
592 smart: true,
593 autoDoc: {
594 detectDeclPath: detectDeclPath,
331 resizeDomList(domListFnErrors, errorSetList.length, '<div></div>');
332 for (let i = 0; i < errorSetList.length; i += 1) {
333 const divDom = domListFnErrors.children[i];
334 const html = unwrapString(wasm_exports.error_html(base_decl, errorSetList[i]));
335 divDom.innerHTML = html;
595336 }
596 });
597 let ast = reader.parse(activeGuide.body);
598 let writer = new commonmark.HtmlRenderer();
599 let result = writer.render(ast);
600 domActiveGuide.innerHTML = result;
601 if (curNav.activeGuideScrollTo !== null) {
602 scrollToHeading(curNav.activeGuideScrollTo, false);
603 }
604 } else {
605 domGuideTocList.classList.add("hidden");
606 domGuideTocListEmtpy.classList.remove("hidden");
607
608 if (zigAnalysis.guideSections.length > 1 || (zigAnalysis.guideSections[0].guides.length > 0)) {
609 renderGuidesIndex();
610 } else {
611 noGuidesAtAll();
337 domTableFnErrors.classList.remove("hidden");
612338 }
339 domSectFnErrors.classList.remove("hidden");
613340 }
614341
615 domGuidesMenu.classList.remove("hidden");
616 domActiveGuide.classList.remove("hidden");
617 }
618
619 // TODO: ensure unique hashes
620 // TODO: hash also guides and their headings
621 function computeGuideHashes() {
622 for (let i = 1; i < zigAnalysis.guideSections.length; i += 1) {
623 const section = zigAnalysis.guideSections[i];
624 section.hash = "section-" + slugify(section.name || i);
625 }
626 }
627
628 function renderGuidesIndex() {
629 // main content
630 {
631 let html = "";
632 for (let i = 0; i < zigAnalysis.guideSections.length; i += 1) {
633 const section = zigAnalysis.guideSections[i];
634 if (i != 0) { // first section is the default section
635 html += "<h2 id='"+ section.hash +"'>" + section.name + "</h2>";
636 }
637 for (let guide of section.guides) {
638 html += "<ol><li><a href='"+ NAV_MODES.GUIDES + guide.name +"'>" + (guide.title || guide.name) + "</a></li>";
639 html += guide.toc + "</ol>";
342 function renderParams(decl_index) {
343 // Prevent params from being emptied next time wasm calls memory.grow.
344 const params = declParams(decl_index).slice();
345 if (params.length !== 0) {
346 resizeDomList(domListParams, params.length, '<div></div>');
347 for (let i = 0; i < params.length; i += 1) {
348 const divDom = domListParams.children[i];
349 divDom.innerHTML = unwrapString(wasm_exports.decl_param_html(decl_index, params[i]));
350 }
351 domSectParams.classList.remove("hidden");
640352 }
641353 }
642 domActiveGuide.innerHTML = html;
643 }
644354
645 // sidebar / fast navigation
646 {
647 domGuidesMenuTitle.textContent = "Sections";
648 if (zigAnalysis.guideSections.length > 1) {
649 let html = "";
650 for (let i = 1; i < zigAnalysis.guideSections.length; i += 1) {
651 const section = zigAnalysis.guideSections[i];
652 html += "<li><a href='"+ NAV_MODES.GUIDES + ":" + section.hash +"'>" + section.name + "</a></li>";
653 }
654 domGuideTocList.innerHTML = "<ul>"+html+"</ul>";
355 function renderTypeFunction(decl_index) {
356 renderNav(decl_index);
357 renderDeclHeading(decl_index);
358 renderTopLevelDocs(decl_index);
359 renderParams(decl_index);
360 renderDocTests(decl_index);
655361
656 function onLinkClick(ev) {
657 const link = ev.target.getAttribute("href");
658 skipNextHashChange = link;
659 location.replace(link);
660 scrollToHeading(link.split(":")[1], true);
661 ev.preventDefault();
662 ev.stopPropagation();
663 }
664 for (let a of domGuideTocList.querySelectorAll("a")) {
665 a.addEventListener('click', onLinkClick, false);
666 }
667
668 domGuideTocList.classList.remove("hidden");
669 domGuideTocListEmtpy.classList.add("hidden");
362 const members = unwrapSlice32(wasm_exports.type_fn_members(decl_index, false)).slice();
363 const fields = unwrapSlice32(wasm_exports.type_fn_fields(decl_index)).slice();
364 if (members.length !== 0 || fields.length !== 0) {
365 renderNamespace(decl_index, members, fields);
670366 } else {
671 domGuideTocList.classList.add("hidden");
672 domGuideTocListEmtpy.classList.remove("hidden");
367 domSourceText.innerHTML = declSourceHtml(decl_index);
368 domSectSource.classList.remove("hidden");
673369 }
674 }
675 }
370 }
676371
677 function noGuidesAtAll() {
678 const root_file_idx = zigAnalysis.modules[zigAnalysis.rootMod].file;
679 const root_file_name = getFile(root_file_idx).name;
680 let reader = new commonmark.Parser({smart: true});
681 let ast = reader.parse(`
682# No Guides
683These autodocs don't contain any guide.
372 function renderDocTests(decl_index) {
373 const doctest_html = declDoctestHtml(decl_index);
374 if (doctest_html.length > 0) {
375 domDocTestsCode.innerHTML = doctest_html;
376 domSectDocTests.classList.remove("hidden");
377 }
378 }
684379
685While the API section is a reference guide autogenerated from Zig source code,
686guides are meant to be handwritten explanations that provide for example:
380 function renderFunction(decl_index) {
381 renderNav(decl_index);
382 renderDeclHeading(decl_index);
383 renderTopLevelDocs(decl_index);
384 renderParams(decl_index);
385 renderDocTests(decl_index);
687386
688- how-to explanations for common use-cases
689- technical documentation
690- information about advanced usage patterns
387 domFnProtoCode.innerHTML = fnProtoHtml(decl_index, false);
388 domFnProto.classList.remove("hidden");
691389
692You can add guides by specifying which markdown files to include
693in the top level doc comment of your root file, like so:
694390
695(At the top of *${root_file_name}*)
696\`\`\`
697//!zig-autodoc-guide: intro.md
698//!zig-autodoc-guide: quickstart.md
699//!zig-autodoc-guide: advanced-docs/advanced-stuff.md
700\`\`\`
391 const errorSetNode = fnErrorSet(decl_index);
392 if (errorSetNode != null) {
393 const base_decl = wasm_exports.fn_error_set_decl(decl_index, errorSetNode);
394 renderErrorSet(base_decl, errorSetNodeList(decl_index, errorSetNode));
395 }
701396
702You can also create sections to group guides together:
397 domSourceText.innerHTML = declSourceHtml(decl_index);
398 domSectSource.classList.remove("hidden");
399 }
703400
704\`\`\`
705//!zig-autodoc-section: CLI Usage
706//!zig-autodoc-guide: cli-basics.md
707//!zig-autodoc-guide: cli-advanced.md
708\`\`\`
709
401 function renderGlobal(decl_index) {
402 renderNav(decl_index);
403 renderDeclHeading(decl_index);
710404
711**Note that this feature is still under heavy development so expect bugs**
712**and missing features!**
405 const docs_html = declDocsHtmlShort(decl_index);
406 if (docs_html.length > 0) {
407 domTldDocs.innerHTML = docs_html;
408 domTldDocs.classList.remove("hidden");
409 }
713410
714Happy writing!
715`);
411 domSourceText.innerHTML = declSourceHtml(decl_index);
412 domSectSource.classList.remove("hidden");
413 }
716414
717 let writer = new commonmark.HtmlRenderer();
718 let result = writer.render(ast);
719 domActiveGuide.innerHTML = result;
415 function renderNamespace(base_decl, members, fields) {
416 const typesList = [];
417 const namespacesList = [];
418 const errSetsList = [];
419 const fnsList = [];
420 const varsList = [];
421 const valsList = [];
720422
721 }
423 member_loop: for (let i = 0; i < members.length; i += 1) {
424 let member = members[i];
425 const original = member;
426 while (true) {
427 const member_category = wasm_exports.categorize_decl(member, 0);
428 switch (member_category) {
429 case CAT_namespace:
430 if (wasm_exports.decl_field_count(member) > 0) {
431 typesList.push({original: original, member: member});
432 } else {
433 namespacesList.push({original: original, member: member});
434 }
435 continue member_loop;
436 case CAT_namespace:
437 namespacesList.push({original: original, member: member});
438 continue member_loop;
439 case CAT_global_variable:
440 varsList.push(member);
441 continue member_loop;
442 case CAT_function:
443 fnsList.push(member);
444 continue member_loop;
445 case CAT_type:
446 case CAT_type_type:
447 case CAT_type_function:
448 typesList.push({original: original, member: member});
449 continue member_loop;
450 case CAT_error_set:
451 errSetsList.push({original: original, member: member});
452 continue member_loop;
453 case CAT_global_const:
454 case CAT_primitive:
455 valsList.push({original: original, member: member});
456 continue member_loop;
457 case CAT_alias:
458 member = wasm_exports.get_aliasee();
459 continue;
460 default:
461 throw new Error("uknown category: " + member_category);
462 }
463 }
464 }
465
466 typesList.sort(byDeclIndexName2);
467 namespacesList.sort(byDeclIndexName2);
468 errSetsList.sort(byDeclIndexName2);
469 fnsList.sort(byDeclIndexName);
470 varsList.sort(byDeclIndexName);
471 valsList.sort(byDeclIndexName2);
472
473 if (typesList.length !== 0) {
474 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');
475 for (let i = 0; i < typesList.length; i += 1) {
476 const liDom = domListTypes.children[i];
477 const aDom = liDom.children[0];
478 const original_decl = typesList[i].original;
479 const decl = typesList[i].member;
480 aDom.textContent = declIndexName(original_decl);
481 aDom.setAttribute('href', navLinkDeclIndex(decl));
482 }
483 domSectTypes.classList.remove("hidden");
484 }
485 if (namespacesList.length !== 0) {
486 resizeDomList(domListNamespaces, namespacesList.length, '<li><a href="#"></a></li>');
487 for (let i = 0; i < namespacesList.length; i += 1) {
488 const liDom = domListNamespaces.children[i];
489 const aDom = liDom.children[0];
490 const original_decl = namespacesList[i].original;
491 const decl = namespacesList[i].member;
492 aDom.textContent = declIndexName(original_decl);
493 aDom.setAttribute('href', navLinkDeclIndex(decl));
494 }
495 domSectNamespaces.classList.remove("hidden");
496 }
497
498 if (errSetsList.length !== 0) {
499 resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>');
500 for (let i = 0; i < errSetsList.length; i += 1) {
501 const liDom = domListErrSets.children[i];
502 const aDom = liDom.children[0];
503 const original_decl = errSetsList[i].original;
504 const decl = errSetsList[i].member;
505 aDom.textContent = declIndexName(original_decl);
506 aDom.setAttribute('href', navLinkDeclIndex(decl));
507 }
508 domSectErrSets.classList.remove("hidden");
509 }
510
511 if (fnsList.length !== 0) {
512 resizeDomList(domListFns, fnsList.length,
513 '<div><dt><code></code></dt><dd></dd></div>');
514 for (let i = 0; i < fnsList.length; i += 1) {
515 const decl = fnsList[i];
516 const divDom = domListFns.children[i];
517
518 const dtDom = divDom.children[0];
519 const ddDocs = divDom.children[1];
520 const protoCodeDom = dtDom.children[0];
521
522 protoCodeDom.innerHTML = fnProtoHtml(decl, true);
523 ddDocs.innerHTML = declDocsHtmlShort(decl);
524 }
525 domSectFns.classList.remove("hidden");
526 }
527
528 if (fields.length !== 0) {
529 resizeDomList(domListFields, fields.length, '<div></div>');
530 for (let i = 0; i < fields.length; i += 1) {
531 const divDom = domListFields.children[i];
532 divDom.innerHTML = unwrapString(wasm_exports.decl_field_html(base_decl, fields[i]));
533 }
534 domSectFields.classList.remove("hidden");
535 }
536
537 if (varsList.length !== 0) {
538 resizeDomList(domListGlobalVars, varsList.length,
539 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
540 for (let i = 0; i < varsList.length; i += 1) {
541 const decl = varsList[i];
542 const trDom = domListGlobalVars.children[i];
543
544 const tdName = trDom.children[0];
545 const tdNameA = tdName.children[0];
546 const tdType = trDom.children[1];
547 const tdDesc = trDom.children[2];
548
549 tdNameA.setAttribute('href', navLinkDeclIndex(decl));
550 tdNameA.textContent = declIndexName(decl);
722551
723 function renderApi() {
724 // set Api mode
725 domApiSwitch.classList.add("active");
726 domGuideSwitch.classList.remove("active");
727 domGuidesSection.classList.add("hidden");
728 domSectNavAPI.classList.remove("hidden");
729 domSectNavGuides.classList.add("hidden");
730 domDocs.classList.remove("hidden");
731 domGuidesMenu.classList.add("hidden");
732 domStatus.classList.add("hidden");
733 domFnProto.classList.add("hidden");
734 domSectParams.classList.add("hidden");
735 domTldDocs.classList.add("hidden");
736 domSectTypes.classList.add("hidden");
737 domSectTests.classList.add("hidden");
738 domSectDocTests.classList.add("hidden");
739 domSectNamespaces.classList.add("hidden");
740 domListNamespacesLeft.classList.add("hidden");
741 domListNamespacesRight.classList.add("hidden");
742 domNoDocsNamespaces.classList.add("hidden");
743 domSectErrSets.classList.add("hidden");
744 domSectFns.classList.add("hidden");
745 domSectFields.classList.add("hidden");
746 domSectSearchResults.classList.add("hidden");
747 domSectSearchAllResultsLink.classList.add("hidden");
748 domSectSearchNoResults.classList.add("hidden");
749 domHdrName.classList.add("hidden");
750 domSectFnErrors.classList.add("hidden");
751 domFnExamples.classList.add("hidden");
752 domFnNoExamples.classList.add("hidden");
753 domFnSourceLink.classList.add("hidden");
754 domDeclNoRef.classList.add("hidden");
755 domFnErrorsAnyError.classList.add("hidden");
756 domTableFnErrors.classList.add("hidden");
757 domSectGlobalVars.classList.add("hidden");
758 domSectValues.classList.add("hidden");
552 tdType.innerHTML = declTypeHtml(decl);
553 tdDesc.innerHTML = declDocsHtmlShort(decl);
554 }
555 domSectGlobalVars.classList.remove("hidden");
556 }
759557
760 renderTitle();
558 if (valsList.length !== 0) {
559 resizeDomList(domListValues, valsList.length,
560 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
561 for (let i = 0; i < valsList.length; i += 1) {
562 const trDom = domListValues.children[i];
563 const tdName = trDom.children[0];
564 const tdNameA = tdName.children[0];
565 const tdType = trDom.children[1];
566 const tdDesc = trDom.children[2];
761567
762 if (curNavSearch !== "") {
763 return renderSearchAPI();
764 }
568 const original_decl = valsList[i].original;
569 const decl = valsList[i].member;
570 tdNameA.setAttribute('href', navLinkDeclIndex(decl));
571 tdNameA.textContent = declIndexName(original_decl);
765572
766 let rootMod = zigAnalysis.modules[zigAnalysis.rootMod];
767 let mod = rootMod;
768 curNav.modObjs = [mod];
769 for (let i = 0; i < curNav.modNames.length; i += 1) {
770 let childMod = zigAnalysis.modules[mod.table[curNav.modNames[i]]];
771 if (childMod == null) {
772 return render404();
573 tdType.innerHTML = declTypeHtml(decl);
574 tdDesc.innerHTML = declDocsHtmlShort(decl);
575 }
576 domSectValues.classList.remove("hidden");
773577 }
774 mod = childMod;
775 curNav.modObjs.push(mod);
776578 }
777579
778 let currentType = getType(mod.main);
779 curNav.declObjs = [currentType];
780 let lastDecl = mod.main;
781 for (let i = 0; i < curNav.declNames.length; i += 1) {
782 let childDecl = findSubDecl(currentType, curNav.declNames[i]);
783 window.last_decl = childDecl;
784 if (childDecl == null || childDecl.is_private === true) {
785 return render404();
786 }
787 lastDecl = childDecl;
580 function renderNamespacePage(decl_index) {
581 renderNav(decl_index);
582 renderDeclHeading(decl_index);
583 const members = namespaceMembers(decl_index, false).slice();
584 const fields = declFields(decl_index).slice();
585 renderNamespace(decl_index, members, fields);
586 }
788587
789 let childDeclValue = resolveValue(childDecl.value).expr;
790 if ("type" in childDeclValue) {
791 const t = getType(childDeclValue.type);
792 if (t.kind != typeKinds.Fn) {
793 childDecl = t;
588 function operatorCompare(a, b) {
589 if (a === b) {
590 return 0;
591 } else if (a < b) {
592 return -1;
593 } else {
594 return 1;
794595 }
795 }
796
797 currentType = childDecl;
798 curNav.declObjs.push(currentType);
799596 }
800597
598 function updateCurNav(location_hash) {
599 curNav.tag = 0;
600 curNav.decl = null;
601 curNav.path = null;
602 curNav.viewSourceHash = null;
603 curNavSearch = "";
801604
605 if (location_hash.length > 1 && location_hash[0] === '#') {
606 const query = location_hash.substring(1);
607 const qpos = query.indexOf("?");
608 let nonSearchPart;
609 if (qpos === -1) {
610 nonSearchPart = query;
611 } else {
612 nonSearchPart = query.substring(0, qpos);
613 curNavSearch = decodeURIComponent(query.substring(qpos + 1));
614 }
802615
803 window.x = currentType;
804
805 renderNav();
806
807 let last = curNav.declObjs[curNav.declObjs.length - 1];
808 let lastIsDecl = isDecl(last);
809 let lastIsType = isType(last);
810 let lastIsContainerType = isContainerType(last);
811
812 renderDocTest(lastDecl);
813
814 if (lastIsContainerType) {
815 return renderContainer(last);
816 }
817
818 if (!lastIsDecl && !lastIsType) {
819 return renderUnknownDecl(last);
616 if (nonSearchPart.length > 0) {
617 const source_mode = nonSearchPart.startsWith("src/");
618 if (source_mode) {
619 curNav.tag = 2;
620 curNav.path = nonSearchPart.substring(4);
621 } else {
622 curNav.tag = 1;
623 curNav.decl = findDecl(nonSearchPart);
624 }
625 }
626 }
820627 }
821628
822 if (lastIsType) {
823 return renderType(last);
629 function onHashChange(state) {
630 history.replaceState({}, "");
631 navigate(location.hash);
632 if (state == null) window.scrollTo({top: 0});
824633 }
825634
826 if (lastIsDecl && last.kind === "var") {
827 return renderVar(last);
635 function onPopState(ev) {
636 onHashChange(ev.state);
828637 }
829638
830 if (lastIsDecl && last.kind === "const") {
831 const value = resolveValue(last.value);
832 if ("type" in value.expr) {
833 let typeObj = getType(value.expr.type);
834 if (typeObj.kind === typeKinds.Fn) {
835 return renderFn(last);
836 }
639 function navigate(location_hash) {
640 updateCurNav(location_hash);
641 if (domSearch.value !== curNavSearch) {
642 domSearch.value = curNavSearch;
643 }
644 render();
645 if (imFeelingLucky) {
646 imFeelingLucky = false;
647 activateSelectedResult();
837648 }
838 return renderValue(last);
839649 }
840650
841 }
651 function activateSelectedResult() {
652 if (domSectSearchResults.classList.contains("hidden")) {
653 return;
654 }
842655
843 function render() {
844 switch (curNav.mode) {
845 case NAV_MODES.API:
846 return renderApi();
847 case NAV_MODES.GUIDES:
848 return renderGuides();
849 default:
850 throw "?";
656 var liDom = domListSearchResults.children[curSearchIndex];
657 if (liDom == null && domListSearchResults.children.length !== 0) {
658 liDom = domListSearchResults.children[0];
659 }
660 if (liDom != null) {
661 var aDom = liDom.children[0];
662 location.href = aDom.getAttribute("href");
663 curSearchIndex = -1;
664 }
665 domSearch.blur();
851666 }
852 }
853667
668 function onSearchKeyDown(ev) {
669 switch (ev.which) {
670 case 13:
671 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
854672
855 function renderDocTest(decl) {
856 if (!decl.decltest) return;
857 const astNode = getAstNode(decl.decltest);
858 domSectDocTests.classList.remove("hidden");
859 domDocTestsCode.innerHTML = renderTokens(
860 DecoratedTokenizer(astNode.code, decl));
861 }
673 clearAsyncSearch();
674 imFeelingLucky = true;
675 location.hash = computeSearchHash();
862676
863 function renderUnknownDecl(decl) {
864 domDeclNoRef.classList.remove("hidden");
865
866 let docs = getAstNode(decl.src).docs;
867 if (docs != null) {
868 domTldDocs.innerHTML = markdown(docs);
869 } else {
870 domTldDocs.innerHTML =
871 "<p>There are no doc comments for this declaration.</p>";
872 }
873 domTldDocs.classList.remove("hidden");
874 }
677 ev.preventDefault();
678 ev.stopPropagation();
679 return;
680 case 27:
681 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
875682
876 function typeIsErrSet(typeIndex) {
877 let typeObj = getType(typeIndex);
878 return typeObj.kind === typeKinds.ErrorSet;
879 }
683 domSearch.value = "";
684 domSearch.blur();
685 curSearchIndex = -1;
686 ev.preventDefault();
687 ev.stopPropagation();
688 startSearch();
689 return;
690 case 38:
691 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
880692
881 function typeIsStructWithNoFields(typeIndex) {
882 let typeObj = getType(typeIndex);
883 if (typeObj.kind !== typeKinds.Struct) return false;
884 return typeObj.field_types.length == 0;
885 }
693 moveSearchCursor(-1);
694 ev.preventDefault();
695 ev.stopPropagation();
696 return;
697 case 40:
698 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
886699
887 function typeIsGenericFn(typeIndex) {
888 let typeObj = getType(typeIndex);
889 if (typeObj.kind !== typeKinds.Fn) {
890 return false;
700 moveSearchCursor(1);
701 ev.preventDefault();
702 ev.stopPropagation();
703 return;
704 default:
705 ev.stopPropagation(); // prevent keyboard shortcuts
706 return;
707 }
891708 }
892 return typeObj.generic_ret != null;
893 }
894709
895 function renderFn(fnDecl) {
896 if ("refPath" in fnDecl.value.expr) {
897 let last = fnDecl.value.expr.refPath.length - 1;
898 let lastExpr = fnDecl.value.expr.refPath[last];
899 console.assert("declRef" in lastExpr);
900 fnDecl = getDecl(lastExpr.declRef);
710 function onSearchChange(ev) {
711 curSearchIndex = -1;
712 startAsyncSearch();
901713 }
902714
903 let value = resolveValue(fnDecl.value);
904 console.assert("type" in value.expr);
905 let typeObj = getType(value.expr.type);
906
907 domFnProtoCode.innerHTML = renderTokens(ex(value.expr, { fnDecl: fnDecl }));
908 domFnSourceLink.classList.remove("hidden");
909 domFnSourceLink.innerHTML = "[<a target=\"_blank\" href=\"" + sourceFileLink(fnDecl) + "\">src</a>]";
910
911 let docsSource = null;
912 let srcNode = getAstNode(fnDecl.src);
913 if (srcNode.docs != null) {
914 docsSource = srcNode.docs;
715 function moveSearchCursor(dir) {
716 if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) {
717 if (dir > 0) {
718 curSearchIndex = -1 + dir;
719 } else if (dir < 0) {
720 curSearchIndex = domListSearchResults.children.length + dir;
721 }
722 } else {
723 curSearchIndex += dir;
724 }
725 if (curSearchIndex < 0) {
726 curSearchIndex = 0;
727 }
728 if (curSearchIndex >= domListSearchResults.children.length) {
729 curSearchIndex = domListSearchResults.children.length - 1;
730 }
731 renderSearchCursor();
915732 }
916733
917 renderFnParamDocs(fnDecl, typeObj);
918
919 let retExpr = resolveValue({ expr: typeObj.ret }).expr;
920 if ("type" in retExpr) {
921 let retIndex = retExpr.type;
922 let errSetTypeIndex = null;
923 let retType = getType(retIndex);
924 if (retType.kind === typeKinds.ErrorSet) {
925 errSetTypeIndex = retIndex;
926 } else if (retType.kind === typeKinds.ErrorUnion) {
927 errSetTypeIndex = retType.err.type;
928 }
929 if (errSetTypeIndex != null) {
930 let errSetType = getType(errSetTypeIndex);
931 renderErrorSet(errSetType);
932 }
734 function onWindowKeyDown(ev) {
735 switch (ev.which) {
736 case 27:
737 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
738 if (!domHelpModal.classList.contains("hidden")) {
739 domHelpModal.classList.add("hidden");
740 ev.preventDefault();
741 ev.stopPropagation();
742 }
743 break;
744 case 83:
745 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
746 domSearch.focus();
747 domSearch.select();
748 ev.preventDefault();
749 ev.stopPropagation();
750 startAsyncSearch();
751 break;
752 case 85:
753 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
754 ev.preventDefault();
755 ev.stopPropagation();
756 navigateToSource();
757 break;
758 case 191:
759 if (!ev.shiftKey || ev.ctrlKey || ev.altKey) return;
760 ev.preventDefault();
761 ev.stopPropagation();
762 showHelpModal();
763 break;
764 }
933765 }
934766
935 let protoSrcIndex = fnDecl.src;
936 if (typeIsGenericFn(value.expr.type)) {
937 // does the generic_ret contain a container?
938 var resolvedGenericRet = resolveValue({ expr: typeObj.generic_ret });
939
940 if ("call" in resolvedGenericRet.expr) {
941 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
942 let resolvedFunc = resolveValue({ expr: call.func });
943 if (!("type" in resolvedFunc.expr)) return;
944 let callee = getType(resolvedFunc.expr.type);
945 if (!callee.generic_ret) return;
946 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
947 }
948
949 // TODO: see if unwrapping the `as` here is a good idea or not.
950 if ("as" in resolvedGenericRet.expr) {
951 resolvedGenericRet = {
952 expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg],
953 };
954 }
767 function showHelpModal() {
768 domHelpModal.classList.remove("hidden");
769 domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";
770 domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";
771 domHelpModal.focus();
772 }
955773
956 if (!("type" in resolvedGenericRet.expr)) return;
957 const genericType = getType(resolvedGenericRet.expr.type);
958 if (isContainerType(genericType)) {
959 renderContainer(genericType);
774 function navigateToSource() {
775 if (curNav.viewSourceHash != null) {
776 location.hash = curNav.viewSourceHash;
960777 }
961
962 // old code
963 // let instantiations = nodesToFnsMap[protoSrcIndex];
964 // let calls = nodesToCallsMap[protoSrcIndex];
965 // if (instantiations == null && calls == null) {
966 // domFnNoExamples.classList.remove("hidden");
967 // } else if (calls != null) {
968 // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
969 // if (fnObj.combined != null) renderContainer(fnObj.combined);
970
971 // resizeDomList(domListFnExamples, calls.length, '<li></li>');
972
973 // for (let callI = 0; callI < calls.length; callI += 1) {
974 // let liDom = domListFnExamples.children[callI];
975 // liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
976 // }
977
978 // domFnExamples.classList.remove("hidden");
979 // } else if (instantiations != null) {
980 // // TODO
981 // }
982 } else {
983 domFnExamples.classList.add("hidden");
984 domFnNoExamples.classList.add("hidden");
985778 }
986779
987 let protoSrcNode = getAstNode(protoSrcIndex);
988 if (
989 docsSource == null &&
990 protoSrcNode != null &&
991 protoSrcNode.docs != null
992 ) {
993 docsSource = protoSrcNode.docs;
994 }
995 if (docsSource != null) {
996 domTldDocs.innerHTML = markdown(docsSource, fnDecl);
997 domTldDocs.classList.remove("hidden");
780 function clearAsyncSearch() {
781 if (searchTimer != null) {
782 clearTimeout(searchTimer);
783 searchTimer = null;
784 }
998785 }
999 domFnProto.classList.remove("hidden");
1000 }
1001
1002 function renderFnParamDocs(fnDecl, typeObj) {
1003 let docCount = 0;
1004786
1005 let fnNode = getAstNode(fnDecl.src);
1006 let fields = fnNode.fields;
1007 if (fields === null) {
1008 fields = getAstNode(typeObj.src).fields;
787 function startAsyncSearch() {
788 clearAsyncSearch();
789 searchTimer = setTimeout(startSearch, 10);
1009790 }
1010 let isVarArgs = typeObj.is_var_args;
1011
1012 for (let i = 0; i < fields.length; i += 1) {
1013 let field = fields[i];
1014 let fieldNode = getAstNode(field);
1015 if (fieldNode.docs != null) {
1016 docCount += 1;
1017 }
791 function computeSearchHash() {
792 // How location.hash works:
793 // 1. http://example.com/ => ""
794 // 2. http://example.com/# => ""
795 // 3. http://example.com/#foo => "#foo"
796 // wat
797 const oldWatHash = location.hash;
798 const oldHash = oldWatHash.startsWith("#") ? oldWatHash : "#" + oldWatHash;
799 const parts = oldHash.split("?");
800 const newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
801 return parts[0] + newPart2;
1018802 }
1019 if (docCount == 0) {
1020 return;
803 function startSearch() {
804 clearAsyncSearch();
805 navigate(computeSearchHash());
1021806 }
807 function renderSearch() {
808 renderNav(curNav.decl);
1022809
1023 resizeDomList(domListParams, docCount, "<div></div>");
1024 let domIndex = 0;
810 const ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);
811 const results = executeQuery(curNavSearch, ignoreCase);
1025812
1026 for (let i = 0; i < fields.length; i += 1) {
1027 let field = fields[i];
1028 let fieldNode = getAstNode(field);
1029 let docs = fieldNode.docs;
1030 if (fieldNode.docs == null) {
1031 continue;
1032 }
1033 let docsNonEmpty = docs !== "";
1034 let divDom = domListParams.children[domIndex];
1035 domIndex += 1;
813 if (results.length !== 0) {
814 resizeDomList(domListSearchResults, results.length, '<li><a href="#"></a></li>');
815
816 for (let i = 0; i < results.length; i += 1) {
817 const liDom = domListSearchResults.children[i];
818 const aDom = liDom.children[0];
819 const match = results[i];
820 const full_name = fullyQualifiedName(match);
821 aDom.textContent = full_name;
822 aDom.setAttribute('href', navLinkFqn(full_name));
823 }
824 renderSearchCursor();
1036825
1037 let value = typeObj.params[i];
1038 let preClass = docsNonEmpty ? ' class="fieldHasDocs"' : "";
1039 let html = "<pre" + preClass + ">" + renderTokens((function*() {
1040 yield Tok.identifier(fieldNode.name);
1041 yield Tok.colon;
1042 yield Tok.space;
1043 if (isVarArgs && i === typeObj.params.length - 1) {
1044 yield Tok.period;
1045 yield Tok.period;
1046 yield Tok.period;
826 domSectSearchResults.classList.remove("hidden");
1047827 } else {
1048 yield* ex(value, {});
828 domSectSearchNoResults.classList.remove("hidden");
1049829 }
1050 yield Tok.comma;
1051 }()));
1052
1053 html += "</pre>";
1054
1055 if (docsNonEmpty) {
1056 html += '<div class="fieldDocs">' + markdown(docs) + "</div>";
1057 }
1058 divDom.innerHTML = html;
1059830 }
1060 domSectParams.classList.remove("hidden");
1061 }
1062831
1063 function renderNav() {
1064 let len = curNav.modNames.length + curNav.declNames.length;
1065 resizeDomList(domListNavAPI, len, '<li><a href="#"></a></li>');
1066 let list = [];
1067 let hrefModNames = [];
1068 let hrefDeclNames = [];
1069 for (let i = 0; i < curNav.modNames.length; i += 1) {
1070 hrefModNames.push(curNav.modNames[i]);
1071 let name = curNav.modNames[i];
1072 list.push({
1073 name: name,
1074 link: navLink(hrefModNames, hrefDeclNames),
1075 });
1076 }
1077 for (let i = 0; i < curNav.declNames.length; i += 1) {
1078 hrefDeclNames.push(curNav.declNames[i]);
1079 list.push({
1080 name: curNav.declNames[i],
1081 link: navLink(hrefModNames, hrefDeclNames),
1082 });
832 function renderSearchCursor() {
833 for (let i = 0; i < domListSearchResults.children.length; i += 1) {
834 var liDom = domListSearchResults.children[i];
835 if (curSearchIndex === i) {
836 liDom.classList.add("selected");
837 } else {
838 liDom.classList.remove("selected");
839 }
840 }
1083841 }
1084842
1085 for (let i = 0; i < list.length; i += 1) {
1086 let liDom = domListNavAPI.children[i];
1087 let aDom = liDom.children[0];
1088 aDom.textContent = list[i].name;
1089 aDom.setAttribute("href", list[i].link);
1090 if (i + 1 == list.length) {
1091 aDom.classList.add("active");
1092 } else {
1093 aDom.classList.remove("active");
843 function updateModuleList() {
844 moduleList.length = 0;
845 for (let i = 0;; i += 1) {
846 const name = unwrapString(wasm_exports.module_name(i));
847 if (name.length == 0) break;
848 moduleList.push(name);
1094849 }
1095850 }
1096851
1097 }
1098
1099
1100 function render404() {
1101 domStatus.textContent = "404 Not Found";
1102 domStatus.classList.remove("hidden");
1103 }
1104
1105 // function renderModList() {
1106 // const rootMod = zigAnalysis.modules[zigAnalysis.rootMod];
1107 // let list = [];
1108 // for (let key in rootMod.table) {
1109 // let modIndex = rootMod.table[key];
1110 // if (zigAnalysis.modules[modIndex] == null) continue;
1111 // if (key == rootMod.name) continue;
1112 // list.push({
1113 // name: key,
1114 // mod: modIndex,
1115 // });
1116 // }
1117
1118 // {
1119 // let aDom = domSectMainMod.children[1].children[0].children[0];
1120 // aDom.textContent = rootMod.name;
1121 // aDom.setAttribute("href", navLinkMod(zigAnalysis.rootMod));
1122 // if (rootMod.name === curNav.modNames[0]) {
1123 // aDom.classList.add("active");
1124 // } else {
1125 // aDom.classList.remove("active");
1126 // }
1127 // domSectMainMod.classList.remove("hidden");
1128 // }
1129
1130 // list.sort(function (a, b) {
1131 // return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
1132 // });
1133
1134 // if (list.length !== 0) {
1135 // resizeDomList(domListMods, list.length, '<li><a href="#"></a></li>');
1136 // for (let i = 0; i < list.length; i += 1) {
1137 // let liDom = domListMods.children[i];
1138 // let aDom = liDom.children[0];
1139 // aDom.textContent = list[i].name;
1140 // aDom.setAttribute("href", navLinkMod(list[i].mod));
1141 // if (list[i].name === curNav.modNames[0]) {
1142 // aDom.classList.add("active");
1143 // } else {
1144 // aDom.classList.remove("active");
1145 // }
1146 // }
1147
1148 // domSectMods.classList.remove("hidden");
1149 // }
1150 // }
1151
1152 function navLink(modNames, declNames, callName) {
1153 let base = curNav.mode;
1154
1155 if (modNames.length === 0 && declNames.length === 0) {
1156 return base;
1157 } else if (declNames.length === 0 && callName == null) {
1158 return base + modNames.join(".");
1159 } else if (callName == null) {
1160 return base + modNames.join(".") + ":" + declNames.join(".");
1161 } else {
1162 return (
1163 base + modNames.join(".") + ":" + declNames.join(".") + ";" + callName
1164 );
852 function byDeclIndexName(a, b) {
853 const a_name = declIndexName(a);
854 const b_name = declIndexName(b);
855 return operatorCompare(a_name, b_name);
1165856 }
1166 }
1167
1168 function navLinkMod(modIndex) {
1169 return navLink(canonModPaths[modIndex], []);
1170 }
1171
1172 function navLinkDecl(childName) {
1173 return navLink(curNav.modNames, curNav.declNames.concat([childName]));
1174 }
1175857
1176 function findDeclNavLink(declName) {
1177 if (curNav.declObjs.length == 0) return null;
1178 const curFile = getAstNode(curNav.declObjs[curNav.declObjs.length - 1].src).file;
1179
1180 for (let i = curNav.declObjs.length - 1; i >= 0; i--) {
1181 const curDecl = curNav.declObjs[i];
1182 const curDeclName = curNav.declNames[i - 1];
1183 if (curDeclName == declName) {
1184 const declPath = curNav.declNames.slice(0, i);
1185 return navLink(curNav.modNames, declPath);
1186 }
1187
1188 const subDecl = findSubDecl(curDecl, declName);
1189
1190 if (subDecl != null) {
1191 if (subDecl.is_private === true) {
1192 return sourceFileLink(subDecl);
1193 } else {
1194 const declPath = curNav.declNames.slice(0, i).concat([declName]);
1195 return navLink(curNav.modNames, declPath);
1196 }
1197 }
858 function byDeclIndexName2(a, b) {
859 const a_name = declIndexName(a.original);
860 const b_name = declIndexName(b.original);
861 return operatorCompare(a_name, b_name);
1198862 }
1199863
1200 //throw("could not resolve links for '" + declName + "'");
1201 }
1202
1203 //
1204 // function navLinkCall(callObj) {
1205 // let declNamesCopy = curNav.declNames.concat([]);
1206 // let callName = (declNamesCopy.pop());
1207
1208 // callName += '(';
1209 // for (let arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
1210 // if (arg_i !== 0) callName += ',';
1211 // let argObj = callObj.args[arg_i];
1212 // callName += getValueText(argObj, argObj, false, false);
1213 // }
1214 // callName += ')';
864 function decodeString(ptr, len) {
865 if (len === 0) return "";
866 return text_decoder.decode(new Uint8Array(wasm_exports.memory.buffer, ptr, len));
867 }
1215868
1216 // declNamesCopy.push(callName);
1217 // return navLink(curNav.modNames, declNamesCopy);
1218 // }
869 function unwrapString(bigint) {
870 const ptr = Number(bigint & 0xffffffffn);
871 const len = Number(bigint >> 32n);
872 return decodeString(ptr, len);
873 }
1219874
1220 function resizeDomListDl(dlDom, desiredLen) {
1221 // add the missing dom entries
1222 for (let i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {
1223 dlDom.insertAdjacentHTML("beforeend", "<dt></dt><dd></dd>");
875 function declTypeHtml(decl_index) {
876 return unwrapString(wasm_exports.decl_type_html(decl_index));
1224877 }
1225 // remove extra dom entries
1226 while (desiredLen < dlDom.childElementCount / 2) {
1227 dlDom.removeChild(dlDom.lastChild);
1228 dlDom.removeChild(dlDom.lastChild);
878
879 function declDocsHtmlShort(decl_index) {
880 return unwrapString(wasm_exports.decl_docs_html(decl_index, true));
1229881 }
1230 }
1231882
1232 function resizeDomList(listDom, desiredLen, templateHtml) {
1233 // add the missing dom entries
1234 for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
1235 listDom.insertAdjacentHTML("beforeend", templateHtml);
883 function fullyQualifiedName(decl_index) {
884 return unwrapString(wasm_exports.decl_fqn(decl_index));
1236885 }
1237 // remove extra dom entries
1238 while (desiredLen < listDom.childElementCount) {
1239 listDom.removeChild(listDom.lastChild);
886
887 function declIndexName(decl_index) {
888 return unwrapString(wasm_exports.decl_name(decl_index));
1240889 }
1241 }
1242890
1243 function walkResultTypeRef(wr) {
1244 if (wr.typeRef) return wr.typeRef;
1245 let resolved = resolveValue(wr);
1246 if (wr === resolved) {
1247 return { "undefined": {} };
891 function declSourceHtml(decl_index) {
892 return unwrapString(wasm_exports.decl_source_html(decl_index));
1248893 }
1249 return walkResultTypeRef(resolved);
1250 }
1251894
1252 function* DecoratedTokenizer(src, context) {
1253 let tok_it = Tokenizer(src);
1254 for (let t of tok_it) {
1255 if (t.tag == Tag.identifier) {
1256 const link = detectDeclPath(t.src, context);
1257 if (link) {
1258 t.link = link;
1259 }
1260 }
895 function declDoctestHtml(decl_index) {
896 return unwrapString(wasm_exports.decl_doctest_html(decl_index));
897 }
1261898
1262 yield t;
899 function fnProtoHtml(decl_index, linkify_fn_name) {
900 return unwrapString(wasm_exports.decl_fn_proto_html(decl_index, linkify_fn_name));
1263901 }
1264 }
1265902
903 function setQueryString(s) {
904 const jsArray = text_encoder.encode(s);
905 const len = jsArray.length;
906 const ptr = wasm_exports.query_begin(len);
907 const wasmArray = new Uint8Array(wasm_exports.memory.buffer, ptr, len);
908 wasmArray.set(jsArray);
909 }
1266910
1267 function renderSingleToken(t) {
911 function executeQuery(query_string, ignore_case) {
912 setQueryString(query_string);
913 const ptr = wasm_exports.query_exec(ignore_case);
914 const head = new Uint32Array(wasm_exports.memory.buffer, ptr, 1);
915 const len = head[0];
916 return new Uint32Array(wasm_exports.memory.buffer, ptr + 4, len);
917 }
1268918
1269 if (t.tag == Tag.whitespace) {
1270 return t.src;
919 function namespaceMembers(decl_index, include_private) {
920 return unwrapSlice32(wasm_exports.namespace_members(decl_index, include_private));
1271921 }
1272922
1273 let src = t.src;
1274 // if (t.tag == Tag.identifier) {
1275 // src = escapeHtml(src);
1276 // }
1277 let result = "";
1278 if (t.tag == Tag.identifier && isSimpleType(t.src)) {
1279 result = `<span class="zig_type">${src}</span>`;
1280 } else if (t.tag == Tag.identifier && isSpecialIndentifier(t.src)) {
1281 result = `<span class="zig_special">${src}</span>`;
1282 } else if (t.tag == Tag.identifier && t.fnDecl) {
1283 result = `<span class="zig_fn">${src}</span>`;
1284 } else if (t.tag == Tag.identifier && t.isDecl) {
1285 result = `<span class="zig_decl_identifier">${src}</span>`;
1286 } else {
1287 result = `<span class="zig_${t.tag}">${src}</span>`;
923 function declFields(decl_index) {
924 return unwrapSlice32(wasm_exports.decl_fields(decl_index));
1288925 }
1289926
1290 if (t.link) {
1291 result = `<a href="${t.link}">` + result + "</a>";
927 function declParams(decl_index) {
928 return unwrapSlice32(wasm_exports.decl_params(decl_index));
1292929 }
1293930
1294 return result;
1295 }
931 function declErrorSet(decl_index) {
932 return unwrapSlice64(wasm_exports.decl_error_set(decl_index));
933 }
1296934
1297 function renderTokens(tok_it) {
1298 var html = [];
935 function errorSetNodeList(base_decl, err_set_node) {
936 return unwrapSlice64(wasm_exports.error_set_node_list(base_decl, err_set_node));
937 }
1299938
1300 const max_iter = 100000;
1301 let i = 0;
1302 for (const t of tok_it) {
1303 i += 1;
1304 if (i > max_iter)
1305 throw "too many iterations";
939 function unwrapSlice32(bigint) {
940 const ptr = Number(bigint & 0xffffffffn);
941 const len = Number(bigint >> 32n);
942 if (len === 0) return [];
943 return new Uint32Array(wasm_exports.memory.buffer, ptr, len);
944 }
1306945
1307 if (t.tag == Tag.eof)
1308 break;
946 function unwrapSlice64(bigint) {
947 const ptr = Number(bigint & 0xffffffffn);
948 const len = Number(bigint >> 32n);
949 if (len === 0) return [];
950 return new BigUint64Array(wasm_exports.memory.buffer, ptr, len);
951 }
1309952
1310 html.push(renderSingleToken(t));
953 function findDecl(fqn) {
954 setInputString(fqn);
955 const result = wasm_exports.find_decl();
956 if (result === -1) return null;
957 return result;
1311958 }
1312959
1313 return html.join("");
1314 }
960 function findFileRoot(path) {
961 setInputString(path);
962 const result = wasm_exports.find_file_root();
963 if (result === -1) return null;
964 return result;
965 }
1315966
1316 function* ex(expr, opts) {
1317 switch (Object.keys(expr)[0]) {
1318 default:
1319 throw "this expression is not implemented yet: " + Object.keys(expr)[0];
1320 case "comptimeExpr": {
1321 const src = zigAnalysis.comptimeExprs[expr.comptimeExpr].code;
1322 yield* DecoratedTokenizer(src);
1323 return;
1324 }
1325 case "declName": {
1326 yield { src: expr.declName, tag: Tag.identifier };
1327 return;
1328 }
1329 case "declRef": {
1330 const name = getDecl(expr.declRef).name;
1331 const link = declLinkOrSrcLink(expr.declRef);
1332 if (link) {
1333 yield { src: name, tag: Tag.identifier, isDecl: true, link };
1334 } else {
1335 yield { src: name, tag: Tag.identifier, isDecl: true };
1336 }
1337 return;
1338 }
1339 case "refPath": {
1340 for (let i = 0; i < expr.refPath.length; i += 1) {
1341 if (i > 0) yield Tok.period;
1342 yield* ex(expr.refPath[i], opts);
1343 }
1344 return;
1345 }
1346 case "fieldRef": {
1347 const field_idx = expr.fieldRef.index;
1348 const type = getType(expr.fieldRef.type);
1349 const field = getAstNode(type.src).fields[field_idx];
1350 const name = getAstNode(field).name;
1351 yield { src: name, tag: Tag.identifier };
1352 return;
1353 }
1354 case "bool": {
1355 if (expr.bool) {
1356 yield { src: "true", tag: Tag.identifier };
1357 return;
1358 }
1359 yield { src: "false", tag: Tag.identifier };
1360 return;
1361 }
967 function declParent(decl_index) {
968 const result = wasm_exports.decl_parent(decl_index);
969 if (result === -1) return null;
970 return result;
971 }
1362972
1363 case "unreachable": {
1364 yield { src: "unreachable", tag: Tag.identifier };
1365 return;
1366 }
973 function fnErrorSet(decl_index) {
974 const result = wasm_exports.fn_error_set(decl_index);
975 if (result === 0) return null;
976 return result;
977 }
1367978
1368 case "&": {
1369 yield { src: "&", tag: Tag.ampersand };
1370 yield* ex(zigAnalysis.exprs[expr["&"]], opts);
1371 return;
1372 }
1373
1374 case "load": {
1375 yield* ex(zigAnalysis.exprs[expr.load], opts);
1376 yield Tok.period;
1377 yield Tok.asterisk;
1378 return;
1379 }
1380
1381 case "call": {
1382
1383 let call = zigAnalysis.calls[expr.call];
1384
1385 switch (Object.keys(call.func)[0]) {
1386 default:
1387 throw "TODO";
1388 case "declRef":
1389 case "refPath": {
1390 yield* ex(call.func, opts);
1391 break;
1392 }
1393 }
1394 yield Tok.l_paren;
1395
1396 for (let i = 0; i < call.args.length; i++) {
1397 if (i != 0) {
1398 yield Tok.comma;
1399 yield Tok.space;
1400 }
1401 yield* ex(call.args[i], opts);
1402 }
1403
1404 yield Tok.r_paren;
1405 return;
1406 }
1407 case "typeOf_peer": {
1408 yield { src: "@TypeOf", tag: Tag.builtin };
1409 yield { src: "(", tag: Tag.l_paren };
1410 for (let i = 0; i < expr.typeOf_peer.length; i+=1) {
1411 const elem = zigAnalysis.exprs[expr.typeOf_peer[i]];
1412 yield* ex(elem, opts);
1413 if (i != expr.typeOf_peer.length - 1) {
1414 yield Tok.comma;
1415 yield Tok.space;
1416 }
1417 }
1418 yield { src: ")", tag: Tag.r_paren };
1419 return;
1420 }
1421 case "sizeOf": {
1422 const sizeOf = zigAnalysis.exprs[expr.sizeOf];
1423 yield { src: "@sizeOf", tag: Tag.builtin };
1424 yield Tok.l_paren;
1425 yield* ex(sizeOf, opts);
1426 yield Tok.r_paren;
1427 return;
1428 }
1429 case "bitSizeOf": {
1430 const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];
1431 yield { src: "@bitSizeOf", tag: Tag.builtin };
1432 yield Tok.l_paren;
1433 yield* ex(bitSizeOf, opts);
1434 yield Tok.r_paren;
1435 return;
1436 }
1437
1438 case "as": {
1439 const exprArg = zigAnalysis.exprs[expr.as.exprArg];
1440 yield* ex(exprArg, opts);
1441 return;
1442 }
1443
1444 case "int": {
1445 yield { src: expr.int, tag: Tag.number_literal };
1446 return;
1447 }
1448
1449 case "int_big": {
1450 if (expr.int_big.negated) {
1451 yield { src: "-", tag: Tag.minus };
1452 }
1453 yield { src: expr.int_big.value, tag: Tag.number_literal };
1454 return;
1455 }
1456
1457 case "float": {
1458 let float = expr.float;
1459 if (Number.isSafeInteger(float)) float = float.toFixed(1);
1460 yield { src: float, tag: Tag.number_literal };
1461 return;
1462 }
1463
1464 case "float128": {
1465 yield { src: expr.float128, tag: Tag.number_literal };
1466 return;
1467 }
1468
1469 case "array": {
1470 yield Tok.period;
1471 yield Tok.l_brace;
1472 for (let i = 0; i < expr.array.length; i++) {
1473 if (i != 0) {
1474 yield Tok.comma;
1475 yield Tok.space;
1476 }
1477 let elem = zigAnalysis.exprs[expr.array[i]];
1478 yield* ex(elem, opts);
1479 }
1480 yield Tok.r_brace;
1481 return;
1482 }
1483
1484 case "compileError": {
1485 yield { src: "@compileError", tag: Tag.builtin };
1486 yield Tok.l_paren;
1487 yield* ex(zigAnalysis.exprs[expr.compileError], opts);
1488 yield Tok.r_paren;
1489 return;
1490 }
1491
1492 case "optionalPayload": {
1493 const opt = zigAnalysis.exprs[expr.optionalPayload];
1494 yield* ex(opt, opts);
1495 yield Tok.period;
1496 yield Tok.question_mark;
1497 return;
1498 }
1499
1500 case "elemVal": {
1501 const lhs = zigAnalysis.exprs[expr.elemVal.lhs];
1502 const rhs = zigAnalysis.exprs[expr.elemVal.rhs];
1503 yield* ex(lhs);
1504 yield Tok.l_bracket;
1505 yield* ex(rhs);
1506 yield Tok.r_bracket;
1507 return;
1508 }
1509
1510 case "sliceIndex": {
1511 const slice = zigAnalysis.exprs[expr.sliceIndex];
1512 yield* ex(slice, opts);
1513 return;
1514 }
1515
1516 case "slice": {
1517 const slice = expr.slice;
1518 const lhs = zigAnalysis.exprs[slice.lhs];
1519 const start = zigAnalysis.exprs[slice.start];
1520 yield* ex(lhs, opts);
1521 yield Tok.l_bracket;
1522 yield* ex(start, opts);
1523 yield Tok.period;
1524 yield Tok.period;
1525 if (slice.end !== null) {
1526 const end = zigAnalysis.exprs[slice.end];
1527 yield* ex(end, opts);
1528 }
1529 if (slice.sentinel !== null) {
1530 yield Tok.colon;
1531 const sent = zigAnalysis.exprs[slice.sentinel];
1532 yield* ex(sent, opts);
1533 }
1534 yield Tok.r_brace;
1535 return;
1536 }
1537
1538 case "sliceLength": {
1539 const slice = expr.sliceLength;
1540 const lhs = zigAnalysis.exprs[slice.lhs];
1541 const start = zigAnalysis.exprs[slice.start];
1542 const len = zigAnalysis.exprs[slice.len];
1543 yield* ex(lhs, opts);
1544 yield Tok.l_bracket;
1545 yield* ex(start, opts);
1546 yield Tok.period;
1547 yield Tok.period;
1548 yield Tok.r_bracket;
1549 yield Tok.l_bracket;
1550 yield { src: "0", tag: Tag.number_literal };
1551 yield Tok.period;
1552 yield Tok.period;
1553 yield* ex(len, opts);
1554 if (slice.sentinel !== null) {
1555 yield Tok.colon;
1556 const sent = zigAnalysis.exprs[slice.sentinel];
1557 yield* ex(sent, opts);
1558 }
1559 yield Tok.r_brace;
1560 return;
1561 }
1562
1563 case "string": {
1564 yield { src: '"' + expr.string + '"', tag: Tag.string_literal };
1565 return;
1566 }
1567
1568 case "struct": {
1569 yield Tok.period;
1570 yield Tok.l_brace;
1571 if (expr.struct.length > 0) yield Tok.space;
1572
1573 for (let i = 0; i < expr.struct.length; i++) {
1574 const fv = expr.struct[i];
1575 const field_name = fv.name;
1576 const field_expr = zigAnalysis.exprs[fv.val.expr];
1577 const field_value = ex(field_expr, opts);
1578 yield Tok.period;
1579 yield { src: field_name, tag: Tag.identifier };
1580 yield Tok.space;
1581 yield Tok.eql;
1582 yield Tok.space;
1583 yield* field_value;
1584 if (i !== expr.struct.length - 1) {
1585 yield Tok.comma;
1586 yield Tok.space;
1587 } else {
1588 yield Tok.space;
1589 }
1590 }
1591 yield Tok.r_brace;
1592 return;
1593 }
1594
1595 case "unOpIndex": {
1596 const unOp = zigAnalysis.exprs[expr.unOpIndex];
1597 yield* ex(unOp, opts);
1598 return;
1599 }
1600
1601 case "unOp": {
1602 const param = zigAnalysis.exprs[expr.unOp.param];
1603
1604 switch (expr.unOp.name) {
1605 case "bit_not": {
1606 yield { src: "~", tag: Tag.tilde };
1607 break;
1608 }
1609 case "bool_not": {
1610 yield { src: "!", tag: Tag.bang };
1611 break;
1612 }
1613 case "negate_wrap": {
1614 yield { src: "-%", tag: Tag.minus_percent };
1615 break;
1616 }
1617 case "negate": {
1618 yield { src: "-", tag: Tag.minus };
1619 break;
1620 }
1621 default:
1622 throw "unOp: `" + expr.unOp.name + "` not implemented yet!"
1623 }
1624
1625 if (param["binOpIndex"] !== undefined) {
1626 yield Tok.l_paren;
1627 yield* ex(param, opts);
1628 yield Tok.r_paren;
1629 } else {
1630 yield* ex(param, opts);
1631 }
1632 return;
1633 }
1634
1635 case "fieldVal": {
1636 const fv = expr.fieldVal;
1637 const field_name = fv.name;
1638 yield { src: field_name, tag: Tag.identifier };
1639 return;
1640 }
1641
1642 case "binOpIndex": {
1643 const binOp = zigAnalysis.exprs[expr.binOpIndex];
1644 yield* ex(binOp, opts);
1645 return;
1646 }
1647
1648 case "binOp": {
1649 const lhsOp = zigAnalysis.exprs[expr.binOp.lhs];
1650 const rhsOp = zigAnalysis.exprs[expr.binOp.rhs];
1651
1652 if (lhsOp["binOpIndex"] !== undefined) {
1653 yield Tok.l_paren;
1654 yield* ex(lhsOp, opts);
1655 yield Tok.r_paren;
1656 } else {
1657 yield* ex(lhsOp, opts);
1658 }
1659
1660 yield Tok.space;
1661
1662 switch (expr.binOp.name) {
1663 case "add": {
1664 yield { src: "+", tag: Tag.plus };
1665 break;
1666 }
1667 case "addwrap": {
1668 yield { src: "+%", tag: Tag.plus_percent };
1669 break;
1670 }
1671 case "add_sat": {
1672 yield { src: "+|", tag: Tag.plus_pipe };
1673 break;
1674 }
1675 case "sub": {
1676 yield { src: "-", tag: Tag.minus };
1677 break;
1678 }
1679 case "subwrap": {
1680 yield { src: "-%", tag: Tag.minus_percent };
1681 break;
1682 }
1683 case "sub_sat": {
1684 yield { src: "-|", tag: Tag.minus_pipe };
1685 break;
1686 }
1687 case "mul": {
1688 yield { src: "*", tag: Tag.asterisk };
1689 break;
1690 }
1691 case "mulwrap": {
1692 yield { src: "*%", tag: Tag.asterisk_percent };
1693 break;
1694 }
1695 case "mul_sat": {
1696 yield { src: "*|", tag: Tag.asterisk_pipe };
1697 break;
1698 }
1699 case "div": {
1700 yield { src: "/", tag: Tag.slash };
1701 break;
1702 }
1703 case "xor": {
1704 yield { src: "^", tag: Tag.caret };
1705 break;
1706 }
1707 case "shl": {
1708 yield { src: "<<", tag: Tag.angle_bracket_angle_bracket_left };
1709 break;
1710 }
1711 case "shl_sat": {
1712 yield { src: "<<|", tag: Tag.angle_bracket_angle_bracket_left_pipe };
1713 break;
1714 }
1715 case "shr": {
1716 yield { src: ">>", tag: Tag.angle_bracket_angle_bracket_right };
1717 break;
1718 }
1719 case "bit_or": {
1720 yield { src: "|", tag: Tag.pipe };
1721 break;
1722 }
1723 case "bit_and": {
1724 yield { src: "&", tag: Tag.ampersand };
1725 break;
1726 }
1727 case "array_cat": {
1728 yield { src: "++", tag: Tag.plus_plus };
1729 break;
1730 }
1731 case "array_mul": {
1732 yield { src: "**", tag: Tag.asterisk_asterisk };
1733 break;
1734 }
1735 case "cmp_eq": {
1736 yield { src: "==", tag: Tag.equal_equal };
1737 break;
1738 }
1739 case "cmp_neq": {
1740 yield { src: "!=", tag: Tag.bang_equal };
1741 break;
1742 }
1743 case "cmp_gt": {
1744 yield { src: ">", tag: Tag.angle_bracket_right };
1745 break;
1746 }
1747 case "cmp_gte": {
1748 yield { src: ">=", tag: Tag.angle_bracket_right_equal };
1749 break;
1750 }
1751 case "cmp_lt": {
1752 yield { src: "<", tag: Tag.angle_bracket_left };
1753 break;
1754 }
1755 case "cmp_lte": {
1756 yield { src: "<=", tag: Tag.angle_bracket_left_equal };
1757 break;
1758 }
1759 case "bool_br_and": {
1760 yield { src: "and", tag: Tag.keyword_and };
1761 break;
1762 }
1763 case "bool_br_or": {
1764 yield { src: "or", tag: Tag.keyword_or };
1765 break;
1766 }
1767 default:
1768 console.log("operator not handled yet or doesn't exist!");
1769 }
1770
1771 yield Tok.space;
1772
1773 if (rhsOp["binOpIndex"] !== undefined) {
1774 yield Tok.l_paren;
1775 yield* ex(rhsOp, opts);
1776 yield Tok.r_paren;
1777 } else {
1778 yield* ex(rhsOp, opts);
1779 }
1780 return;
1781 }
1782
1783 case "builtinIndex": {
1784 const builtin = zigAnalysis.exprs[expr.builtinIndex];
1785 yield* ex(builtin, opts);
1786 return;
1787 }
1788
1789 case "builtin": {
1790 const builtin = expr.builtin;
1791 let name = "@";
1792 const param = zigAnalysis.exprs[builtin.param];
1793 switch (builtin.name) {
1794 case "align_of": { name += "alignOf"; break; }
1795 case "int_from_bool": { name += "intFromBool"; break; }
1796 case "embed_file": { name += "embedFile"; break; }
1797 case "error_name": { name += "errorName"; break; }
1798 case "panic": { name += "panic"; break; }
1799 case "set_runtime_safety": { name += "setRuntimeSafety"; break; }
1800 case "sqrt": { name += "sqrt"; break; }
1801 case "sin": { name += "sin"; break; }
1802 case "cos": { name += "cos"; break; }
1803 case "tan": { name += "tan"; break; }
1804 case "exp": { name += "exp"; break; }
1805 case "exp2": { name += "exp2"; break; }
1806 case "log": { name += "log"; break; }
1807 case "log2": { name += "log2"; break; }
1808 case "log10": { name += "log10"; break; }
1809 case "fabs": { name += "fabs"; break; }
1810 case "floor": { name += "floor"; break; }
1811 case "ceil": { name += "ceil"; break; }
1812 case "trunc": { name += "trunc"; break; }
1813 case "round": { name += "round"; break; }
1814 case "tag_name": { name += "tagName"; break; }
1815 case "type_name": { name += "typeName"; break; }
1816 case "type_info": { name += "typeInfo"; break; }
1817 case "frame_type": { name += "Frame"; break; }
1818 case "frame_size": { name += "frameSize"; break; }
1819 case "int_from_ptr": { name += "intFromPtr"; break; }
1820 case "int_from_enum": { name += "intFromEnum"; break; }
1821 case "clz": { name += "clz"; break; }
1822 case "ctz": { name += "ctz"; break; }
1823 case "pop_count": { name += "popCount"; break; }
1824 case "byte_swap": { name += "byteSwap"; break; }
1825 case "bit_reverse": { name += "bitReverse"; break; }
1826 default: throw "builtin: `" + builtin.name + "` not implemented yet!";
1827 }
1828 yield { src: name, tag: Tag.builtin };
1829 yield Tok.l_paren;
1830 yield* ex(param, opts);
1831 yield Tok.r_paren;
1832 return;
1833 }
1834
1835 case "builtinBinIndex": {
1836 const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex];
1837 yield* ex(builtinBinIndex, opts);
1838 return;
1839 }
1840
1841 case "builtinBin": {
1842 const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs];
1843 const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs];
1844
1845 let builtinName = "@";
1846 switch (expr.builtinBin.name) {
1847 case "int_from_float": {
1848 builtinName += "intFromFloat";
1849 break;
1850 }
1851 case "float_from_int": {
1852 builtinName += "floatFromInt";
1853 break;
1854 }
1855 case "ptr_from_int": {
1856 builtinName += "ptrFromInt";
1857 break;
1858 }
1859 case "enum_from_int": {
1860 builtinName += "enumFromInt";
1861 break;
1862 }
1863 case "float_cast": {
1864 builtinName += "floatCast";
1865 break;
1866 }
1867 case "int_cast": {
1868 builtinName += "intCast";
1869 break;
1870 }
1871 case "ptr_cast": {
1872 builtinName += "ptrCast";
1873 break;
1874 }
1875 case "const_cast": {
1876 builtinName += "constCast";
1877 break;
1878 }
1879 case "volatile_cast": {
1880 builtinName += "volatileCast";
1881 break;
1882 }
1883 case "truncate": {
1884 builtinName += "truncate";
1885 break;
1886 }
1887 case "has_decl": {
1888 builtinName += "hasDecl";
1889 break;
1890 }
1891 case "has_field": {
1892 builtinName += "hasField";
1893 break;
1894 }
1895 case "bit_reverse": {
1896 builtinName += "bitReverse";
1897 break;
1898 }
1899 case "div_exact": {
1900 builtinName += "divExact";
1901 break;
1902 }
1903 case "div_floor": {
1904 builtinName += "divFloor";
1905 break;
1906 }
1907 case "div_trunc": {
1908 builtinName += "divTrunc";
1909 break;
1910 }
1911 case "mod": {
1912 builtinName += "mod";
1913 break;
1914 }
1915 case "rem": {
1916 builtinName += "rem";
1917 break;
1918 }
1919 case "mod_rem": {
1920 builtinName += "rem";
1921 break;
1922 }
1923 case "shl_exact": {
1924 builtinName += "shlExact";
1925 break;
1926 }
1927 case "shr_exact": {
1928 builtinName += "shrExact";
1929 break;
1930 }
1931 case "bitcast": {
1932 builtinName += "bitCast";
1933 break;
1934 }
1935 case "align_cast": {
1936 builtinName += "alignCast";
1937 break;
1938 }
1939 case "vector_type": {
1940 builtinName += "Vector";
1941 break;
1942 }
1943 case "reduce": {
1944 builtinName += "reduce";
1945 break;
1946 }
1947 case "splat": {
1948 builtinName += "splat";
1949 break;
1950 }
1951 case "offset_of": {
1952 builtinName += "offsetOf";
1953 break;
1954 }
1955 case "bit_offset_of": {
1956 builtinName += "bitOffsetOf";
1957 break;
1958 }
1959 default:
1960 console.log("builtin function not handled yet or doesn't exist!");
1961 }
1962
1963 yield { src: builtinName, tag: Tag.builtin };
1964 yield Tok.l_paren;
1965 yield* ex(lhsOp, opts);
1966 yield Tok.comma;
1967 yield Tok.space;
1968 yield* ex(rhsOp, opts);
1969 yield Tok.r_paren;
1970 return;
1971 }
1972
1973 case "unionInit": {
1974 let ui = expr.unionInit;
1975 let type = zigAnalysis.exprs[ui.type];
1976 let field = zigAnalysis.exprs[ui.field];
1977 let init = zigAnalysis.exprs[ui.init];
1978 yield { src: "@unionInit", tag: Tag.builtin };
1979 yield Tok.l_paren;
1980 yield* ex(type, opts);
1981 yield Tok.comma;
1982 yield Tok.space;
1983 yield* ex(field, opts);
1984 yield Tok.comma;
1985 yield Tok.space;
1986 yield* ex(init, opts);
1987 yield Tok.r_paren;
1988 return;
1989 }
1990
1991 case "builtinCall": {
1992 let bcall = expr.builtinCall;
1993 let mods = zigAnalysis.exprs[bcall.modifier];
1994 let calee = zigAnalysis.exprs[bcall.function];
1995 let args = zigAnalysis.exprs[bcall.args];
1996 yield { src: "@call", tag: Tag.builtin };
1997 yield Tok.l_paren;
1998 yield* ex(mods, opts);
1999 yield Tok.comma;
2000 yield Tok.space;
2001 yield* ex(calee, opts);
2002 yield Tok.comma;
2003 yield Tok.space;
2004 yield* ex(args, opts);
2005 yield Tok.r_paren;
2006 return;
2007 }
2008
2009 case "mulAdd": {
2010 let muladd = expr.mulAdd;
2011 let mul1 = zigAnalysis.exprs[muladd.mulend1];
2012 let mul2 = zigAnalysis.exprs[muladd.mulend2];
2013 let add = zigAnalysis.exprs[muladd.addend];
2014 let type = zigAnalysis.exprs[muladd.type];
2015 yield { src: "@mulAdd", tag: Tag.builtin };
2016 yield Tok.l_paren;
2017 yield* ex(type, opts);
2018 yield Tok.comma;
2019 yield Tok.space;
2020 yield* ex(mul1, opts);
2021 yield Tok.comma;
2022 yield Tok.space;
2023 yield* ex(mul2, opts);
2024 yield Tok.comma;
2025 yield Tok.space;
2026 yield* ex(add, opts);
2027 yield Tok.r_paren;
2028 return;
2029 }
2030
2031 case "cmpxchgIndex": {
2032 const cmpxchg = zigAnalysis.exprs[expr.cmpxchgIndex];
2033 yield* ex(cmpxchg, opts);
2034 return;
2035 }
2036
2037 case "cmpxchg": {
2038 const type = zigAnalysis.exprs[expr.cmpxchg.type];
2039 const ptr = zigAnalysis.exprs[expr.cmpxchg.ptr];
2040 const expectedValue = zigAnalysis.exprs[expr.cmpxchg.expected_value];
2041 const newValue = zigAnalysis.exprs[expr.cmpxchg.new_value];
2042 const successOrder = zigAnalysis.exprs[expr.cmpxchg.success_order];
2043 const failureOrder = zigAnalysis.exprs[expr.cmpxchg.failure_order];
2044
2045 let fnName = "@";
2046 switch (expr.cmpxchg.name) {
2047 case "cmpxchg_strong": {
2048 fnName += "cmpxchgStrong";
2049 break;
2050 }
2051 case "cmpxchg_weak": {
2052 fnName += "cmpxchgWeak";
2053 break;
2054 }
2055 default:
2056 throw "Unexpected cmpxchg name: `" + expr.cmpxchg.name + "`!";
2057 }
2058 yield { src: fnName, tag: Tag.builtin };
2059 yield Tok.l_paren;
2060 yield* ex(type, opts);
2061 yield Tok.comma;
2062 yield Tok.space;
2063 yield* ex(ptr, opts);
2064 yield Tok.comma;
2065 yield Tok.space;
2066 yield* ex(expectedValue, opts);
2067 yield Tok.comma;
2068 yield Tok.space;
2069 yield* ex(newValue, opts);
2070 yield Tok.comma;
2071 yield Tok.space;
2072 yield* ex(successOrder, opts);
2073 yield Tok.comma;
2074 yield Tok.space;
2075 yield* ex(failureOrder, opts);
2076 yield Tok.r_paren;
2077 return;
2078 }
2079
2080 case "enumLiteral": {
2081 let literal = expr.enumLiteral;
2082 yield Tok.period;
2083 yield { src: literal, tag: Tag.identifier };
2084 return;
2085 }
2086
2087 case "void": {
2088 yield { src: "void", tag: Tag.identifier };
2089 return;
2090 }
2091
2092 case "null": {
2093 yield { src: "null", tag: Tag.identifier };
2094 return;
2095 }
2096
2097 case "undefined": {
2098 yield { src: "undefined", tag: Tag.identifier };
2099 return;
2100 }
2101
2102 case "anytype": {
2103 yield { src: "anytype", tag: Tag.keyword_anytype };
2104 return;
2105 }
2106
2107 case "this": {
2108 yield { src: "@This", tag: Tag.builtin };
2109 yield Tok.l_paren;
2110 yield Tok.r_paren;
2111 return;
2112 }
2113
2114 case "switchIndex": {
2115 const switchIndex = zigAnalysis.exprs[expr.switchIndex];
2116 yield* ex(switchIndex, opts);
2117 return;
2118 }
2119
2120 case "errorSets": {
2121 const errSetsObj = getType(expr.errorSets);
2122 yield* ex(errSetsObj.lhs, opts);
2123 yield Tok.space;
2124 yield { src: "||", tag: Tag.pipe_pipe };
2125 yield Tok.space;
2126 yield* ex(errSetsObj.rhs, opts);
2127 return;
2128 }
2129
2130 case "errorUnion": {
2131 const errUnionObj = getType(expr.errorUnion);
2132 yield* ex(errUnionObj.lhs, opts);
2133 yield { src: "!", tag: Tag.bang };
2134 yield* ex(errUnionObj.rhs, opts);
2135 return;
2136 }
2137
2138 case "type": {
2139 let name = "";
2140
2141 let typeObj = expr.type;
2142 if (typeof typeObj === "number") typeObj = getType(typeObj);
2143 switch (typeObj.kind) {
2144 default:
2145 throw "TODO: " + typeObj.kind;
2146 case typeKinds.Type: {
2147 yield { src: typeObj.name, tag: Tag.identifier };
2148 return;
2149 }
2150 case typeKinds.Void: {
2151 yield { src: "void", tag: Tag.identifier };
2152 return;
2153 }
2154 case typeKinds.NoReturn: {
2155 yield { src: "noreturn", tag: Tag.identifier };
2156 return;
2157 }
2158 case typeKinds.ComptimeExpr: {
2159 yield { src: "anyopaque", tag: Tag.identifier };
2160 return;
2161 }
2162 case typeKinds.Bool: {
2163 yield { src: "bool", tag: Tag.identifier };
2164 return;
2165 }
2166 case typeKinds.ComptimeInt: {
2167 yield { src: "comptime_int", tag: Tag.identifier };
2168 return;
2169 }
2170 case typeKinds.ComptimeFloat: {
2171 yield { src: "comptime_float", tag: Tag.identifier };
2172 return;
2173 }
2174 case typeKinds.Int: {
2175 yield { src: typeObj.name, tag: Tag.identifier };
2176 return;
2177 }
2178 case typeKinds.Float: {
2179 yield { src: typeObj.name, tag: Tag.identifier };
2180 return;
2181 }
2182 case typeKinds.Array: {
2183 yield Tok.l_bracket;
2184 yield* ex(typeObj.len, opts);
2185 if (typeObj.sentinel) {
2186 yield Tok.colon;
2187 yield* ex(typeObj.sentinel, opts);
2188 }
2189 yield Tok.r_bracket;
2190 yield* ex(typeObj.child, opts);
2191 return;
2192 }
2193 case typeKinds.Optional: {
2194 yield Tok.question_mark;
2195 yield* ex(typeObj.child, opts);
2196 return;
2197 }
2198 case typeKinds.Pointer: {
2199 let ptrObj = typeObj;
2200 switch (ptrObj.size) {
2201 default:
2202 console.log("TODO: implement unhandled pointer size case");
2203 case pointerSizeEnum.One:
2204 yield { src: "*", tag: Tag.asterisk };
2205 break;
2206 case pointerSizeEnum.Many:
2207 yield Tok.l_bracket;
2208 yield { src: "*", tag: Tag.asterisk };
2209 if (ptrObj.sentinel !== null) {
2210 yield Tok.colon;
2211 yield* ex(ptrObj.sentinel, opts);
2212 }
2213 yield Tok.r_bracket;
2214 break;
2215 case pointerSizeEnum.Slice:
2216 if (ptrObj.is_ref) {
2217 yield { src: "*", tag: Tag.asterisk };
2218 }
2219 yield Tok.l_bracket;
2220 if (ptrObj.sentinel !== null) {
2221 yield Tok.colon;
2222 yield* ex(ptrObj.sentinel, opts);
2223 }
2224 yield Tok.r_bracket;
2225 break;
2226 case pointerSizeEnum.C:
2227 yield Tok.l_bracket;
2228 yield { src: "*", tag: Tag.asterisk };
2229 yield { src: "c", tag: Tag.identifier };
2230 if (typeObj.sentinel !== null) {
2231 yield Tok.colon;
2232 yield* ex(ptrObj.sentinel, opts);
2233 }
2234 yield Tok.r_bracket;
2235 break;
2236 }
2237 if (!ptrObj.is_mutable) {
2238 yield Tok.const;
2239 yield Tok.space;
2240 }
2241 if (ptrObj.is_allowzero) {
2242 yield { src: "allowzero", tag: Tag.keyword_allowzero };
2243 yield Tok.space;
2244 }
2245 if (ptrObj.is_volatile) {
2246 yield { src: "volatile", tag: Tag.keyword_volatile };
2247 }
2248 if (ptrObj.has_addrspace) {
2249 yield { src: "addrspace", tag: Tag.keyword_addrspace };
2250 yield Tok.l_paren;
2251 yield Tok.period;
2252 yield Tok.r_paren;
2253 }
2254 if (ptrObj.has_align) {
2255 yield { src: "align", tag: Tag.keyword_align };
2256 yield Tok.l_paren;
2257 yield* ex(ptrObj.align, opts);
2258 if (ptrObj.hostIntBytes !== undefined && ptrObj.hostIntBytes !== null) {
2259 yield Tok.colon;
2260 yield* ex(ptrObj.bitOffsetInHost, opts);
2261 yield Tok.colon;
2262 yield* ex(ptrObj.hostIntBytes, opts);
2263 }
2264 yield Tok.r_paren;
2265 yield Tok.space;
2266 }
2267 yield* ex(ptrObj.child, opts);
2268 return;
2269 }
2270 case typeKinds.Struct: {
2271 let structObj = typeObj;
2272 if (structObj.layout !== null) {
2273 switch (structObj.layout.enumLiteral) {
2274 case "Packed": {
2275 yield { src: "packed", tag: Tag.keyword_packed };
2276 break;
2277 }
2278 case "Extern": {
2279 yield { src: "extern", tag: Tag.keyword_extern };
2280 break;
2281 }
2282 }
2283 yield Tok.space;
2284 }
2285 yield { src: "struct", tag: Tag.keyword_struct };
2286 if (structObj.backing_int !== null) {
2287 yield Tok.l_paren;
2288 yield* ex(structObj.backing_int, opts);
2289 yield Tok.r_paren;
2290 }
2291 yield Tok.space;
2292 yield Tok.l_brace;
2293
2294 if (structObj.field_types.length > 1) {
2295 yield Tok.enter;
2296 } else {
2297 yield Tok.space;
2298 }
2299
2300 let indent = 0;
2301 if (structObj.field_types.length > 1) {
2302 indent = 1;
2303 }
2304 if (opts.indent && structObj.field_types.length > 1) {
2305 indent += opts.ident;
2306 }
2307
2308 let structNode = getAstNode(structObj.src);
2309 for (let i = 0; i < structObj.field_types.length; i += 1) {
2310 let fieldNode = getAstNode(structNode.fields[i]);
2311 let fieldName = fieldNode.name;
2312
2313 for (let j = 0; j < indent; j += 1) {
2314 yield Tok.tab;
2315 }
2316
2317 if (!typeObj.is_tuple) {
2318 yield { src: fieldName, tag: Tag.identifier };
2319 }
2320
2321 let fieldTypeExpr = structObj.field_types[i];
2322 if (!typeObj.is_tuple) {
2323 yield Tok.colon;
2324 yield Tok.space;
2325 }
2326 yield* ex(fieldTypeExpr, { ...opts, indent: indent });
2327
2328 if (structObj.field_defaults[i] !== null) {
2329 yield Tok.space;
2330 yield Tok.eql;
2331 yield Tok.space;
2332 yield* ex(structObj.field_defaults[i], opts);
2333 }
2334
2335 if (structObj.field_types.length > 1) {
2336 yield Tok.comma;
2337 yield Tok.enter;
2338 } else {
2339 yield Tok.space;
2340 }
2341 }
2342 yield Tok.r_brace;
2343 return;
2344 }
2345 case typeKinds.Enum: {
2346 let enumObj = typeObj;
2347 yield { src: "enum", tag: Tag.keyword_enum };
2348 if (enumObj.tag) {
2349 yield Tok.l_paren;
2350 yield* ex(enumObj.tag, opts);
2351 yield Tok.r_paren;
2352 }
2353 yield Tok.space;
2354 yield Tok.l_brace;
2355
2356 let enumNode = getAstNode(enumObj.src);
2357 let fields_len = enumNode.fields.length;
2358 if (enumObj.nonexhaustive) {
2359 fields_len += 1;
2360 }
2361
2362 if (fields_len > 1) {
2363 yield Tok.enter;
2364 } else {
2365 yield Tok.space;
2366 }
2367
2368 let indent = 0;
2369 if (fields_len > 1) {
2370 indent = 1;
2371 }
2372 if (opts.indent) {
2373 indent += opts.indent;
2374 }
2375
2376 for (let i = 0; i < enumNode.fields.length; i += 1) {
2377 let fieldNode = getAstNode(enumNode.fields[i]);
2378 let fieldName = fieldNode.name;
2379
2380 for (let j = 0; j < indent; j += 1) yield Tok.tab;
2381 yield { src: fieldName, tag: Tag.identifier };
2382
2383 if (enumObj.values[i] !== null) {
2384 yield Tok.space;
2385 yield Tok.eql;
2386 yield Tok.space;
2387 yield* ex(enumObj.values[i], opts);
2388 }
2389
2390 if (fields_len > 1) {
2391 yield Tok.comma;
2392 yield Tok.enter;
2393 }
2394 }
2395 if (enumObj.nonexhaustive) {
2396 for (let j = 0; j < indent; j += 1) yield Tok.tab;
2397
2398 yield { src: "_", tag: Tag.identifier };
2399
2400 if (fields_len > 1) {
2401 yield Tok.comma;
2402 yield Tok.enter;
2403 }
2404 }
2405 if (opts.indent) {
2406 for (let j = 0; j < opts.indent; j += 1) yield Tok.tab;
2407 }
2408 yield Tok.r_brace;
2409 return;
2410 }
2411 case typeKinds.Union: {
2412 let unionObj = typeObj;
2413 if (unionObj.layout !== null) {
2414 switch (unionObj.layout.enumLiteral) {
2415 case "Packed": {
2416 yield { src: "packed", tag: Tag.keyword_packed };
2417 break;
2418 }
2419 case "Extern": {
2420 yield { src: "extern", tag: Tag.keyword_extern };
2421 break;
2422 }
2423 }
2424 yield Tok.space;
2425 }
2426 yield { src: "union", tag: Tag.keyword_union };
2427 if (unionObj.auto_tag) {
2428 yield Tok.l_paren;
2429 yield { src: "enum", tag: Tag.keyword_enum };
2430 if (unionObj.tag) {
2431 yield Tok.l_paren;
2432 yield* ex(unionObj.tag, opts);
2433 yield Tok.r_paren;
2434 yield Tok.r_paren;
2435 } else {
2436 yield Tok.r_paren;
2437 }
2438 } else if (unionObj.tag) {
2439 yield Tok.l_paren;
2440 yield* ex(unionObj.tag, opts);
2441 yield Tok.r_paren;
2442 }
2443 yield Tok.space;
2444 yield Tok.l_brace;
2445 if (unionObj.field_types.length > 1) {
2446 yield Tok.enter;
2447 } else {
2448 yield Tok.space;
2449 }
2450 let indent = 0;
2451 if (unionObj.field_types.length > 1) {
2452 indent = 1;
2453 }
2454 if (opts.indent) {
2455 indent += opts.indent;
2456 }
2457 let unionNode = getAstNode(unionObj.src);
2458 for (let i = 0; i < unionObj.field_types.length; i += 1) {
2459 let fieldNode = getAstNode(unionNode.fields[i]);
2460 let fieldName = fieldNode.name;
2461 for (let j = 0; j < indent; j += 1) yield Tok.tab;
2462 yield { src: fieldName, tag: Tag.identifier };
2463
2464 let fieldTypeExpr = unionObj.field_types[i];
2465 yield Tok.colon;
2466 yield Tok.space;
2467
2468 yield* ex(fieldTypeExpr, { ...opts, indent: indent });
2469
2470 if (unionObj.field_types.length > 1) {
2471 yield Tok.comma;
2472 yield Tok.enter;
2473 } else {
2474 yield Tok.space;
2475 }
2476 }
2477 if (opts.indent) {
2478 for (let j = 0; j < opts.indent; j += 1) yield Tok.tab;
2479 }
2480 yield Tok.r_brace;
2481 return;
2482 }
2483 case typeKinds.Opaque: {
2484 yield { src: "opaque", tag: Tag.keyword_opaque };
2485 yield Tok.space;
2486 yield Tok.l_brace;
2487 yield Tok.r_brace;
2488 return;
2489 }
2490 case typeKinds.EnumLiteral: {
2491 yield { src: "(enum literal)", tag: Tag.identifier };
2492 return;
2493 }
2494 case typeKinds.ErrorSet: {
2495 let errSetObj = typeObj;
2496 if (errSetObj.fields === null) {
2497 yield { src: "anyerror", tag: Tag.identifier };
2498 } else if (errSetObj.fields.length == 0) {
2499 yield { src: "error", tag: Tag.keyword_error };
2500 yield Tok.l_brace;
2501 yield Tok.r_brace;
2502 } else if (errSetObj.fields.length == 1) {
2503 yield { src: "error", tag: Tag.keyword_error };
2504 yield Tok.l_brace;
2505 yield { src: errSetObj.fields[0].name, tag: Tag.identifier };
2506 yield Tok.r_brace;
2507 } else {
2508 yield { src: "error", tag: Tag.keyword_error };
2509 yield Tok.l_brace;
2510 yield { src: errSetObj.fields[0].name, tag: Tag.identifier };
2511 for (let i = 1; i < errSetObj.fields.length; i++) {
2512 yield Tok.comma;
2513 yield Tok.space;
2514 yield { src: errSetObj.fields[i].name, tag: Tag.identifier };
2515 }
2516 yield Tok.r_brace;
2517 }
2518 return;
2519 }
2520 case typeKinds.ErrorUnion: {
2521 let errUnionObj = typeObj;
2522 yield* ex(errUnionObj.lhs, opts);
2523 yield { src: "!", tag: Tag.bang };
2524 yield* ex(errUnionObj.rhs, opts);
2525 return;
2526 }
2527 case typeKinds.InferredErrorUnion: {
2528 let errUnionObj = typeObj;
2529 yield { src: "!", tag: Tag.bang };
2530 yield* ex(errUnionObj.payload, opts);
2531 return;
2532 }
2533 case typeKinds.Fn: {
2534 let fnObj = typeObj;
2535 let fnDecl = opts.fnDecl;
2536 let linkFnNameDecl = opts.linkFnNameDecl;
2537 opts.fnDecl = null;
2538 opts.linkFnNameDecl = null;
2539 if (opts.addParensIfFnSignature && fnObj.src == 0) {
2540 yield Tok.l_paren;
2541 }
2542 if (fnObj.is_extern) {
2543 yield { src: "extern", tag: Tag.keyword_extern };
2544 yield Tok.space;
2545 } else if (fnObj.has_cc) {
2546 let cc_expr = zigAnalysis.exprs[fnObj.cc];
2547 if (cc_expr.enumLiteral === "Inline") {
2548 yield { src: "inline", tag: Tag.keyword_inline };
2549 yield Tok.space;
2550 }
2551 }
2552 if (fnObj.has_lib_name) {
2553 yield { src: '"' + fnObj.lib_name + '"', tag: Tag.string_literal };
2554 yield Tok.space;
2555 }
2556 yield { src: "fn", tag: Tag.keyword_fn };
2557 yield Tok.space;
2558 if (fnDecl) {
2559 if (linkFnNameDecl) {
2560 yield { src: fnDecl.name, tag: Tag.identifier, link: linkFnNameDecl, fnDecl: false };
2561 } else {
2562 yield { src: fnDecl.name, tag: Tag.identifier, fnDecl: true };
2563 }
2564 }
2565 yield Tok.l_paren;
2566 if (fnObj.params) {
2567 let fields = null;
2568 let isVarArgs = false;
2569 if (fnObj.src != 0) {
2570 let fnNode = getAstNode(fnObj.src);
2571 fields = fnNode.fields;
2572 isVarArgs = fnNode.varArgs;
2573 }
2574
2575 for (let i = 0; i < fnObj.params.length; i += 1) {
2576 if (i != 0) {
2577 yield Tok.comma;
2578 yield Tok.space;
2579 }
2580
2581 let value = fnObj.params[i];
2582 let paramValue = resolveValue({ expr: value });
2583
2584 if (fields != null) {
2585 let paramNode = getAstNode(fields[i]);
2586
2587 if (paramNode.varArgs) {
2588 yield Tok.period;
2589 yield Tok.period;
2590 yield Tok.period;
2591 continue;
2592 }
2593
2594 if (paramNode.noalias) {
2595 yield { src: "noalias", tag: Tag.keyword_noalias };
2596 yield Tok.space;
2597 }
2598
2599 if (paramNode.comptime) {
2600 yield { src: "comptime", tag: Tag.keyword_comptime };
2601 yield Tok.space;
2602 }
2603
2604 let paramName = paramNode.name;
2605 if (paramName != null) {
2606 // skip if it matches the type name
2607 if (!shouldSkipParamName(paramValue, paramName)) {
2608 if (paramName === "") {
2609 paramName = "_";
2610 }
2611 yield { src: paramName, tag: Tag.identifier };
2612 yield Tok.colon;
2613 yield Tok.space;
2614 }
2615 }
2616 }
2617
2618 // TODO: most of this seems redundant
2619 if (isVarArgs && i === fnObj.params.length - 1) {
2620 yield Tok.period;
2621 yield Tok.period;
2622 yield Tok.period;
2623 } else if ("alignOf" in value) {
2624 yield* ex(value, opts);
2625 } else if ("typeOf" in value) {
2626 yield* ex(value, opts);
2627 } else if ("typeOf_peer" in value) {
2628 yield* ex(value, opts);
2629 } else if ("declRef" in value) {
2630 yield* ex(value, opts);
2631 } else if ("call" in value) {
2632 yield* ex(value, opts);
2633 } else if ("refPath" in value) {
2634 yield* ex(value, opts);
2635 } else if ("type" in value) {
2636 yield* ex(value, opts);
2637 //payloadHtml += '<span class="tok-kw">' + name + "</span>";
2638 } else if ("binOpIndex" in value) {
2639 yield* ex(value, opts);
2640 } else if ("comptimeExpr" in value) {
2641 let comptimeExpr =
2642 zigAnalysis.comptimeExprs[value.comptimeExpr].code;
2643 yield* Tokenizer(comptimeExpr);
2644 } else {
2645 yield { src: "anytype", tag: Tag.keyword_anytype };
2646 }
2647 }
2648 }
2649
2650 yield Tok.r_paren;
2651 yield Tok.space;
2652
2653 if (fnObj.has_align) {
2654 let align = zigAnalysis.exprs[fnObj.align];
2655 yield { src: "align", tag: Tag.keyword_align };
2656 yield Tok.l_paren;
2657 yield* ex(align, opts);
2658 yield Tok.r_paren;
2659 yield Tok.space;
2660 }
2661 if (fnObj.has_cc) {
2662 let cc = zigAnalysis.exprs[fnObj.cc];
2663 if (cc) {
2664 if (cc.enumLiteral !== "Inline") {
2665 yield { src: "callconv", tag: Tag.keyword_callconv };
2666 yield Tok.l_paren;
2667 yield* ex(cc, opts);
2668 yield Tok.r_paren;
2669 yield Tok.space;
2670 }
2671 }
2672 }
2673
2674 if (fnObj.is_inferred_error) {
2675 yield { src: "!", tag: Tag.bang };
2676 }
2677 if (fnObj.ret != null) {
2678 yield* ex(fnObj.ret, {
2679 ...opts,
2680 addParensIfFnSignature: true,
2681 });
2682 } else {
2683 yield { src: "anytype", tag: Tag.keyword_anytype };
2684 }
2685
2686 if (opts.addParensIfFnSignature && fnObj.src == 0) {
2687 yield Tok.r_paren;
2688 }
2689 return;
2690 }
2691 }
2692 }
2693
2694 case "typeOf": {
2695 const typeRefArg = zigAnalysis.exprs[expr.typeOf];
2696 yield { src: "@TypeOf", tag: Tag.builtin };
2697 yield Tok.l_paren;
2698 yield* ex(typeRefArg, opts);
2699 yield Tok.r_paren;
2700 return;
2701 }
2702
2703 case "builtinField": {
2704 yield { src: expr.builtinField, tag: Tag.identifier };
2705 return;
2706 }
2707 }
2708
2709
2710 }
2711
2712
2713
2714 function shouldSkipParamName(typeRef, paramName) {
2715 let resolvedTypeRef = resolveValue({ expr: typeRef });
2716 if ("type" in resolvedTypeRef) {
2717 let typeObj = getType(resolvedTypeRef.type);
2718 if (typeObj.kind === typeKinds.Pointer) {
2719 let ptrObj = typeObj;
2720 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
2721 const value = resolveValue(ptrObj.child);
2722 return typeValueName(value, false, true).toLowerCase() === paramName;
2723 }
2724 }
2725 }
2726 return false;
2727 }
2728
2729 function getPtrSize(typeObj) {
2730 return typeObj.size == null ? pointerSizeEnum.One : typeObj.size;
2731 }
2732
2733 function renderType(typeObj) {
2734 let name;
2735 if (
2736 rootIsStd &&
2737 typeObj ===
2738 getType(zigAnalysis.modules[zigAnalysis.rootMod].main)
2739 ) {
2740 name = renderSingleToken(Tok.identifier("std"));
2741 } else {
2742 name = renderTokens(ex({ type: typeObj }));
2743 }
2744 if (name != null && name != "") {
2745 domHdrName.innerHTML = "<pre class='inline'>" + name + "</pre> ("
2746 + zigAnalysis.typeKinds[typeObj.kind] + ")";
2747 domHdrName.classList.remove("hidden");
2748 }
2749 if (typeObj.kind == typeKinds.ErrorSet) {
2750 renderErrorSet(typeObj);
2751 }
2752 }
2753
2754 function renderErrorSet(errSetType) {
2755 if (errSetType.fields == null) {
2756 domFnErrorsAnyError.classList.remove("hidden");
2757 } else {
2758 let errorList = [];
2759 for (let i = 0; i < errSetType.fields.length; i += 1) {
2760 let errObj = errSetType.fields[i];
2761 //let srcObj = zigAnalysis.astNodes[errObj.src];
2762 errorList.push(errObj);
2763 }
2764 errorList.sort(function(a, b) {
2765 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
2766 });
2767
2768 resizeDomListDl(domListFnErrors, errorList.length);
2769 for (let i = 0; i < errorList.length; i += 1) {
2770 let nameTdDom = domListFnErrors.children[i * 2 + 0];
2771 let descTdDom = domListFnErrors.children[i * 2 + 1];
2772 nameTdDom.textContent = errorList[i].name;
2773 let docs = errorList[i].docs;
2774 if (docs != null) {
2775 descTdDom.innerHTML = markdown(docs);
2776 } else {
2777 descTdDom.textContent = "";
2778 }
2779 }
2780 domTableFnErrors.classList.remove("hidden");
2781 }
2782 domSectFnErrors.classList.remove("hidden");
2783 }
2784
2785 // function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
2786 // let srcIndex = zigAnalysis.fns[value].src;
2787 // let calls = nodesToCallsMap[srcIndex];
2788 // if (calls == null) return false;
2789 // for (let i = 0; i < calls.length; i += 1) {
2790 // let call = zigAnalysis.calls[calls[i]];
2791 // if (call.result.type !== typeTypeId) return false;
2792 // }
2793 // return true;
2794 // }
2795 //
2796 // function allCompTimeFnCallsResult(calls) {
2797 // let firstTypeObj = null;
2798 // let containerObj = {
2799 // privDecls: [],
2800 // };
2801 // for (let callI = 0; callI < calls.length; callI += 1) {
2802 // let call = zigAnalysis.calls[calls[callI]];
2803 // if (call.result.type !== typeTypeId) return null;
2804 // let typeObj = zigAnalysis.types[call.result.value];
2805 // if (!typeKindIsContainer(typeObj.kind)) return null;
2806 // if (firstTypeObj == null) {
2807 // firstTypeObj = typeObj;
2808 // containerObj.src = typeObj.src;
2809 // } else if (firstTypeObj.src !== typeObj.src) {
2810 // return null;
2811 // }
2812 //
2813 // if (containerObj.fields == null) {
2814 // containerObj.fields = (typeObj.fields || []).concat([]);
2815 // } else for (let fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
2816 // let prev = containerObj.fields[fieldI];
2817 // let next = typeObj.fields[fieldI];
2818 // if (prev === next) continue;
2819 // if (typeof(prev) === 'object') {
2820 // if (prev[next] == null) prev[next] = typeObj;
2821 // } else {
2822 // containerObj.fields[fieldI] = {};
2823 // containerObj.fields[fieldI][prev] = firstTypeObj;
2824 // containerObj.fields[fieldI][next] = typeObj;
2825 // }
2826 // }
2827 //
2828 // if (containerObj.pubDecls == null) {
2829 // containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
2830 // } else for (let declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
2831 // let prev = containerObj.pubDecls[declI];
2832 // let next = typeObj.pubDecls[declI];
2833 // if (prev === next) continue;
2834 // // TODO instead of showing "examples" as the public declarations,
2835 // // do logic like this:
2836 // //if (typeof(prev) !== 'object') {
2837 // // let newDeclId = zigAnalysis.decls.length;
2838 // // prev = clone(zigAnalysis.decls[prev]);
2839 // // prev.id = newDeclId;
2840 // // zigAnalysis.decls.push(prev);
2841 // // containerObj.pubDecls[declI] = prev;
2842 // //}
2843 // //mergeDecls(prev, next, firstTypeObj, typeObj);
2844 // }
2845 // }
2846 // for (let declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
2847 // let decl = containerObj.pubDecls[declI];
2848 // if (typeof(decl) === 'object') {
2849 // containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
2850 // }
2851 // }
2852 // return containerObj;
2853 // }
2854
2855 function renderValue(decl) {
2856 let resolvedValue = resolveValue(decl.value);
2857 if (resolvedValue.expr.fieldRef) {
2858 const declRef = decl.value.expr.refPath[0].declRef;
2859 const type = getDecl(declRef);
2860
2861 domFnProtoCode.innerHTML = renderTokens(
2862 (function*() {
2863 yield Tok.const;
2864 yield Tok.space;
2865 yield Tok.identifier(decl.name);
2866 yield Tok.colon;
2867 yield Tok.space;
2868 yield Tok.identifier(type.name);
2869 yield Tok.space;
2870 yield Tok.eql;
2871 yield Tok.space;
2872 yield* ex(decl.value.expr, {});
2873 yield Tok.semi;
2874 })());
2875 } else if (
2876 resolvedValue.expr.string !== undefined ||
2877 resolvedValue.expr.call !== undefined ||
2878 resolvedValue.expr.comptimeExpr !== undefined
2879 ) {
2880 // TODO: we're using the resolved value but
2881 // not keeping track of how we got there
2882 // that's important context that should
2883 // be shown to the user!
2884 domFnProtoCode.innerHTML = renderTokens(
2885 (function*() {
2886 yield Tok.const;
2887 yield Tok.space;
2888 yield Tok.identifier(decl.name);
2889 if (decl.value.typeRef) {
2890 yield Tok.colon;
2891 yield Tok.space;
2892 yield* ex(decl.value.typeRef, {});
2893 }
2894 yield Tok.space;
2895 yield Tok.eql;
2896 yield Tok.space;
2897 yield* ex(resolvedValue.expr, {});
2898 yield Tok.semi;
2899 })());
2900 } else if (resolvedValue.expr.compileError) {
2901 domFnProtoCode.innerHTML = renderTokens(
2902 (function*() {
2903 yield Tok.const;
2904 yield Tok.space;
2905 yield Tok.identifier(decl.name);
2906 yield Tok.space;
2907 yield Tok.eql;
2908 yield Tok.space;
2909 yield* ex(decl.value.expr, {});
2910 yield Tok.semi;
2911 })());
2912 } else {
2913 const parent = getType(decl.parent_container);
2914 domFnProtoCode.innerHTML = renderTokens(
2915 (function*() {
2916 yield Tok.const;
2917 yield Tok.space;
2918 yield Tok.identifier(decl.name);
2919 if (decl.value.typeRef !== null) {
2920 yield Tok.colon;
2921 yield Tok.space;
2922 yield* ex(decl.value.typeRef, {});
2923 }
2924 yield Tok.space;
2925 yield Tok.eql;
2926 yield Tok.space;
2927 yield* ex(decl.value.expr, {});
2928 yield Tok.semi;
2929 })());
2930 }
2931
2932 let docs = getAstNode(decl.src).docs;
2933 if (docs != null) {
2934 // TODO: it shouldn't just be decl.parent_container, but rather
2935 // the type that the decl holds (if the value is a type)
2936 domTldDocs.innerHTML = markdown(docs, decl);
2937
2938 domTldDocs.classList.remove("hidden");
2939 }
2940
2941 domFnProto.classList.remove("hidden");
2942 }
2943
2944 function renderVar(decl) {
2945 let resolvedVar = resolveValue(decl.value);
2946
2947 if (resolvedVar.expr.fieldRef) {
2948 const declRef = decl.value.expr.refPath[0].declRef;
2949 const type = getDecl(declRef);
2950 domFnProtoCode.innerHTML = renderTokens(
2951 (function*() {
2952 yield Tok.var;
2953 yield Tok.space;
2954 yield Tok.identifier(decl.name);
2955 yield Tok.colon;
2956 yield Tok.space;
2957 yield Tok.identifier(type.name);
2958 yield Tok.space;
2959 yield Tok.eql;
2960 yield Tok.space;
2961 yield* ex(decl.value.expr, {});
2962 yield Tok.semi;
2963 })());
2964 } else if (
2965 resolvedVar.expr.string !== undefined ||
2966 resolvedVar.expr.call !== undefined ||
2967 resolvedVar.expr.comptimeExpr !== undefined
2968 ) {
2969 domFnProtoCode.innerHTML = renderTokens(
2970 (function*() {
2971 yield Tok.var;
2972 yield Tok.space;
2973 yield Tok.identifier(decl.name);
2974 if (decl.value.typeRef) {
2975 yield Tok.colon;
2976 yield Tok.space;
2977 yield* ex(decl.value.typeRef, {});
2978 }
2979 yield Tok.space;
2980 yield Tok.eql;
2981 yield Tok.space;
2982 yield* ex(decl.value.expr, {});
2983 yield Tok.semi;
2984 })());
2985 } else if (resolvedVar.expr.compileError) {
2986 domFnProtoCode.innerHTML = renderTokens(
2987 (function*() {
2988 yield Tok.var;
2989 yield Tok.space;
2990 yield Tok.identifier(decl.name);
2991 yield Tok.space;
2992 yield Tok.eql;
2993 yield Tok.space;
2994 yield* ex(decl.value.expr, {});
2995 yield Tok.semi;
2996 })());
2997 } else {
2998 domFnProtoCode.innerHTML = renderTokens(
2999 (function*() {
3000 yield Tok.var;
3001 yield Tok.space;
3002 yield Tok.identifier(decl.name);
3003 yield Tok.colon;
3004 yield Tok.space;
3005 yield* ex(resolvedVar.typeRef, {});
3006 yield Tok.space;
3007 yield Tok.eql;
3008 yield Tok.space;
3009 yield* ex(decl.value.expr, {});
3010 yield Tok.semi;
3011 })());
3012 }
3013
3014 let docs = getAstNode(decl.src).docs;
3015 if (docs != null) {
3016 domTldDocs.innerHTML = markdown(docs);
3017 domTldDocs.classList.remove("hidden");
3018 }
3019
3020 domFnProto.classList.remove("hidden");
3021 }
3022
3023 function categorizeDecls(
3024 decls,
3025 typesList,
3026 namespacesWithDocsList,
3027 namespacesNoDocsList,
3028 errSetsList,
3029 fnsList,
3030 varsList,
3031 valsList,
3032 testsList,
3033 unsList
3034 ) {
3035 for (let i = 0; i < decls.length; i += 1) {
3036 let decl = getDecl(decls[i]);
3037 let declValue = resolveValue(decl.value);
3038
3039 // if (decl.isTest) {
3040 // testsList.push(decl);
3041 // continue;
3042 // }
3043
3044 if (decl.kind === "var") {
3045 varsList.push(decl);
3046 continue;
3047 }
3048
3049 if (decl.kind === "const") {
3050 if ("type" in declValue.expr) {
3051 // We have the actual type expression at hand.
3052 const typeExpr = getType(declValue.expr.type);
3053 if (typeExpr.kind == typeKinds.Fn) {
3054 const funcRetExpr = resolveValue({
3055 expr: typeExpr.ret,
3056 });
3057 if (
3058 "type" in funcRetExpr.expr &&
3059 funcRetExpr.expr.type == typeTypeId
3060 ) {
3061 if (typeIsErrSet(declValue.expr.type)) {
3062 errSetsList.push(decl);
3063 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
3064
3065 let docs = getAstNode(decl.src).docs;
3066 if (!docs) {
3067 // If this is a re-export, try to fetch docs from the actual definition
3068 const { value, seenDecls } = resolveValue(decl.value, true);
3069 if (seenDecls.length > 0) {
3070 const definitionDecl = getDecl(seenDecls[seenDecls.length - 1]);
3071 docs = getAstNode(definitionDecl.src).docs;
3072 } else {
3073 docs = getAstNode(getType(value.expr.type).src).docs;
3074 }
3075 }
3076
3077 if (docs) {
3078 namespacesWithDocsList.push({decl, docs});
3079 } else {
3080 namespacesNoDocsList.push(decl);
3081 }
3082 } else {
3083 typesList.push(decl);
3084 }
3085 } else {
3086 fnsList.push(decl);
3087 }
3088 } else {
3089 if (typeIsErrSet(declValue.expr.type)) {
3090 errSetsList.push(decl);
3091 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
3092 let docs = getAstNode(decl.src).docs;
3093 if (!docs) {
3094 // If this is a re-export, try to fetch docs from the actual definition
3095 const { value, seenDecls } = resolveValue(decl.value, true);
3096 if (seenDecls.length > 0) {
3097 const definitionDecl = getDecl(seenDecls[seenDecls.length - 1]);
3098 docs = getAstNode(definitionDecl.src).docs;
3099 } else {
3100 docs = getAstNode(getType(value.expr.type).src).docs;
3101 }
3102 }
3103 if (docs) {
3104 namespacesWithDocsList.push({decl, docs});
3105 } else {
3106 namespacesNoDocsList.push(decl);
3107 }
3108 } else {
3109 typesList.push(decl);
3110 }
3111 }
3112 } else if (declValue.typeRef) {
3113 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
3114 // We don't know what the type expression is, but we know it's a type.
3115 typesList.push(decl);
3116 } else {
3117 valsList.push(decl);
3118 }
3119 } else {
3120 valsList.push(decl);
3121 }
3122 }
3123
3124 if (decl.is_uns) {
3125 unsList.push(decl);
3126 }
3127 }
3128 }
3129
3130 function sourceFileLink(decl) {
3131 const srcNode = getAstNode(decl.src);
3132 const srcFile = getFile(srcNode.file);
3133 return sourceFileUrlTemplate.
3134 replace("{{mod}}", zigAnalysis.modules[srcFile.modIndex].name).
3135 replace("{{file}}", srcFile.name).
3136 replace("{{line}}", srcNode.line + 1);
3137 }
3138
3139 function renderContainer(container) {
3140 let typesList = [];
3141
3142 let namespacesWithDocsList = [];
3143 let namespacesNoDocsList = [];
3144
3145 let errSetsList = [];
3146
3147 let fnsList = [];
3148
3149 let varsList = [];
3150
3151 let valsList = [];
3152
3153 let testsList = [];
3154
3155 let unsList = [];
3156
3157 categorizeDecls(
3158 container.pubDecls,
3159 typesList,
3160 namespacesWithDocsList,
3161 namespacesNoDocsList,
3162 errSetsList,
3163 fnsList,
3164 varsList,
3165 valsList,
3166 testsList,
3167 unsList
3168 );
3169 if (curNav.showPrivDecls)
3170 categorizeDecls(
3171 container.privDecls,
3172 typesList,
3173 namespacesWithDocsList,
3174 namespacesNoDocsList,
3175 errSetsList,
3176 fnsList,
3177 varsList,
3178 valsList,
3179 testsList,
3180 unsList
3181 );
3182
3183 while (unsList.length > 0) {
3184 let uns = unsList.shift();
3185 let declValue = resolveValue(uns.value);
3186 if (!("type" in declValue.expr)) continue;
3187 let uns_container = getType(declValue.expr.type);
3188 if (!isContainerType(uns_container)) continue;
3189 categorizeDecls(
3190 uns_container.pubDecls,
3191 typesList,
3192 namespacesWithDocsList,
3193 namespacesNoDocsList,
3194 errSetsList,
3195 fnsList,
3196 varsList,
3197 valsList,
3198 testsList,
3199 unsList
3200 );
3201 if (curNav.showPrivDecls)
3202 categorizeDecls(
3203 uns_container.privDecls,
3204 typesList,
3205 namespacesWithDocsList,
3206 namespacesNoDocsList,
3207 errSetsList,
3208 fnsList,
3209 varsList,
3210 valsList,
3211 testsList,
3212 unsList
3213 );
3214 }
3215
3216 typesList.sort(byNameProperty);
3217 namespacesWithDocsList.sort(byNameProperty);
3218 namespacesNoDocsList.sort(byNameProperty);
3219 errSetsList.sort(byNameProperty);
3220 fnsList.sort(byNameProperty);
3221 varsList.sort(byNameProperty);
3222 valsList.sort(byNameProperty);
3223 testsList.sort(byNameProperty);
3224
3225 if (container.src != null) {
3226 let docs = getAstNode(container.src).docs;
3227 if (docs != null) {
3228 domTldDocs.innerHTML = markdown(docs, container);
3229 domTldDocs.classList.remove("hidden");
3230 }
3231 }
3232
3233 if (typesList.length !== 0) {
3234 const splitPoint = Math.ceil(typesList.length / 2);
3235 const template = '<li><a href="#"></a><div></div></li>';
3236 resizeDomList(domListTypesLeft, splitPoint, template);
3237 resizeDomList(domListTypesRight, typesList.length - splitPoint, template);
3238
3239 let activeList = domListTypesLeft;
3240 let offset = 0;
3241 for (let i = 0; i < typesList.length; i += 1) {
3242 let liDom = activeList.children[i - offset];
3243 let aDom = liDom.children[0];
3244 let decl = typesList[i];
3245 aDom.textContent = decl.name;
3246 aDom.setAttribute("href", navLinkDecl(decl.name));
3247
3248 let descDom = liDom.children[1];
3249 let docs = getAstNode(decl.src).docs;
3250 if (!docs) {
3251 // If this is a re-export, try to fetch docs from the actual definition
3252 const { value, seenDecls } = resolveValue(decl.value, true);
3253 if (seenDecls.length > 0) {
3254 const definitionDecl = getDecl(seenDecls[seenDecls.length - 1]);
3255 docs = getAstNode(definitionDecl.src).docs;
3256 } else {
3257 const type = getType(value.expr.type);
3258 if ("src" in type) {
3259 docs = getAstNode(type.src).docs;
3260 }
3261 }
3262 }
3263
3264 if (docs) {
3265 descDom.innerHTML = markdown(shortDesc(docs));
3266 } else {
3267 descDom.innerHTML = "<p class='understated'><i>No documentation provided.</i></p>";
3268 }
3269 if (i == splitPoint - 1) {
3270 activeList = domListTypesRight;
3271 offset = splitPoint;
3272 }
3273 }
3274 domSectTypes.classList.remove("hidden");
3275 }
3276
3277 if (namespacesWithDocsList.length !== 0) {
3278 const splitPoint = Math.ceil(namespacesWithDocsList.length / 2);
3279 const template = '<li><a href="#"></a><div></div></li>';
3280 resizeDomList(domListNamespacesLeft, splitPoint, template);
3281 resizeDomList(domListNamespacesRight,
3282 namespacesWithDocsList.length - splitPoint,
3283 template);
3284
3285 let activeList = domListNamespacesLeft;
3286 let offset = 0;
3287 for (let i = 0; i < namespacesWithDocsList.length; i += 1) {
3288 let liDom = activeList.children[i - offset];
3289 let aDom = liDom.children[0];
3290 let { decl, docs } = namespacesWithDocsList[i];
3291 aDom.textContent = decl.name;
3292 aDom.setAttribute("href", navLinkDecl(decl.name));
3293
3294
3295 let descDom = liDom.children[1];
3296 descDom.innerHTML = markdown(shortDesc(docs));
3297 if (i == splitPoint - 1) {
3298 activeList = domListNamespacesRight;
3299 offset = splitPoint;
3300 }
3301 }
3302
3303 domListNamespacesLeft.classList.remove("hidden");
3304 domListNamespacesRight.classList.remove("hidden");
3305 domSectNamespaces.classList.remove("hidden");
3306 }
3307
3308 if (namespacesNoDocsList.length !== 0) {
3309 resizeDomList(
3310 domNoDocsNamespaces,
3311 namespacesNoDocsList.length,
3312 '<span><a href="#"></a><span></span></span>'
3313 );
3314 for (let i = 0; i < namespacesNoDocsList.length; i += 1) {
3315 let aDom = domNoDocsNamespaces.children[i].children[0];
3316 let decl = namespacesNoDocsList[i];
3317 aDom.textContent = decl.name;
3318 aDom.setAttribute("href", navLinkDecl(decl.name));
3319 let comma = domNoDocsNamespaces.children[i].children[1];
3320 if (i == namespacesNoDocsList.length - 1) {
3321 comma.textContent = "";
3322 } else {
3323 comma.textContent = ", ";
3324 }
3325 }
3326
3327 domNoDocsNamespaces.classList.remove("hidden");
3328 domSectNamespaces.classList.remove("hidden");
3329 }
3330
3331
3332
3333
3334 if (errSetsList.length !== 0) {
3335 resizeDomList(
3336 domListErrSets,
3337 errSetsList.length,
3338 '<li><a href="#"></a></li>'
3339 );
3340 for (let i = 0; i < errSetsList.length; i += 1) {
3341 let liDom = domListErrSets.children[i];
3342 let aDom = liDom.children[0];
3343 let decl = errSetsList[i];
3344 aDom.textContent = decl.name;
3345 aDom.setAttribute("href", navLinkDecl(decl.name));
3346 }
3347 domSectErrSets.classList.remove("hidden");
3348 }
3349
3350 if (fnsList.length !== 0) {
3351 resizeDomList(
3352 domListFns,
3353 fnsList.length,
3354 '<div><dt><pre class="inline fnSignature"></pre><div></div></dt><dd></dd></div>'
3355 );
3356
3357 for (let i = 0; i < fnsList.length; i += 1) {
3358 let decl = fnsList[i];
3359 let trDom = domListFns.children[i];
3360
3361 let tdFnSignature = trDom.children[0].children[0];
3362 let tdFnSrc = trDom.children[0].children[1];
3363 let tdDesc = trDom.children[1];
3364
3365 let declType = resolveValue(decl.value);
3366 console.assert("type" in declType.expr);
3367 tdFnSignature.innerHTML = renderTokens(ex(declType.expr, {
3368 fnDecl: decl,
3369 linkFnNameDecl: navLinkDecl(decl.name),
3370 }));
3371 tdFnSrc.innerHTML = "<a style=\"float: right;\" target=\"_blank\" href=\"" +
3372 sourceFileLink(decl) + "\">[src]</a>";
3373
3374 let docs = getAstNode(decl.src).docs;
3375 if (docs != null) {
3376 docs = docs.trim();
3377 var short = shortDesc(docs);
3378 if (short != docs) {
3379 short = markdown(short, container);
3380 var long = markdown(docs, container); // TODO: this needs to be the file top lvl struct
3381 tdDesc.innerHTML =
3382 "<div class=\"expand\" ><span class=\"button\" onclick=\"toggleExpand(event)\"></span><div class=\"sum-less\">" + short + "</div>" + "<div class=\"sum-more\">" + long + "</div></details>";
3383 }
3384 else {
3385 tdDesc.innerHTML = markdown(short, container);
3386 }
3387 } else {
3388 tdDesc.innerHTML = "<p class='understated'><i>No documentation provided.</i><p>";
3389 }
3390 }
3391 domSectFns.classList.remove("hidden");
3392 }
3393
3394 let containerNode = getAstNode(container.src);
3395 if (containerNode.fields && containerNode.fields.length > 0) {
3396 resizeDomList(domListFields, containerNode.fields.length, "<div></div>");
3397
3398 for (let i = 0; i < containerNode.fields.length; i += 1) {
3399 let fieldNode = getAstNode(containerNode.fields[i]);
3400 let divDom = domListFields.children[i];
3401 let fieldName = fieldNode.name;
3402 let docs = fieldNode.docs;
3403 let docsNonEmpty = docs != null && docs !== "";
3404 let extraPreClass = docsNonEmpty ? " fieldHasDocs" : "";
3405
3406 let html =
3407 '<div class="mobile-scroll-container"><pre class="scroll-item' +
3408 extraPreClass +
3409 '">' +
3410 escapeHtml(fieldName);
3411
3412 if (container.kind === typeKinds.Enum) {
3413 let value = container.values[i];
3414 if (value !== null) {
3415 html += renderTokens((function*() {
3416 yield Tok.space;
3417 yield Tok.eql;
3418 yield Tok.space;
3419 yield* ex(value, {});
3420 })());
3421 }
3422 } else {
3423 let fieldTypeExpr = container.field_types[i];
3424 if (container.kind !== typeKinds.Struct || !container.is_tuple) {
3425 html += renderTokens((function*() {
3426 yield Tok.colon;
3427 yield Tok.space;
3428 })());
3429 }
3430 html += renderTokens(ex(fieldTypeExpr, {}));
3431 let tsn = typeShorthandName(fieldTypeExpr);
3432 if (tsn) {
3433 html += "<span> (" + tsn + ")</span>";
3434 }
3435 if (container.kind === typeKinds.Struct && !container.is_tuple) {
3436 let defaultInitExpr = container.field_defaults[i];
3437 if (defaultInitExpr !== null) {
3438 html += renderTokens((function*() {
3439 yield Tok.space;
3440 yield Tok.eql;
3441 yield Tok.space;
3442 yield* ex(defaultInitExpr, {});
3443 })());
3444 }
3445 }
3446 }
3447
3448 html += ",</pre></div>";
3449
3450 if (docsNonEmpty) {
3451 html += '<div class="fieldDocs">' + markdown(docs) + "</div>";
3452 }
3453 divDom.innerHTML = html;
3454 }
3455 domSectFields.classList.remove("hidden");
3456 }
3457
3458 if (varsList.length !== 0) {
3459 resizeDomList(
3460 domListGlobalVars,
3461 varsList.length,
3462 '<tr><td><a href="#"></a></td><td><pre class="inline"></pre></td><td></td></tr>'
3463 );
3464 for (let i = 0; i < varsList.length; i += 1) {
3465 let decl = varsList[i];
3466 let trDom = domListGlobalVars.children[i];
3467
3468 let tdName = trDom.children[0];
3469 let tdNameA = tdName.children[0];
3470 let tdType = trDom.children[1];
3471 let preType = tdType.children[0];
3472 let tdDesc = trDom.children[2];
3473
3474 tdNameA.setAttribute("href", navLinkDecl(decl.name));
3475 tdNameA.textContent = decl.name;
3476
3477 preType.innerHTML = renderTokens(ex(walkResultTypeRef(decl.value), {}));
3478
3479 let docs = getAstNode(decl.src).docs;
3480 if (docs != null) {
3481 tdDesc.innerHTML = shortDescMarkdown(docs);
3482 } else {
3483 tdDesc.textContent = "";
3484 }
3485 }
3486 domSectGlobalVars.classList.remove("hidden");
3487 }
3488
3489 if (valsList.length !== 0) {
3490 resizeDomList(
3491 domListValues,
3492 valsList.length,
3493 '<tr><td><a href="#"></a></td><td><pre class="inline"></pre></td><td></td></tr>'
3494 );
3495 for (let i = 0; i < valsList.length; i += 1) {
3496 let decl = valsList[i];
3497 let trDom = domListValues.children[i];
3498
3499 let tdName = trDom.children[0];
3500 let tdNameA = tdName.children[0];
3501 let tdType = trDom.children[1];
3502 let preType = tdType.children[0];
3503 let tdDesc = trDom.children[2];
3504
3505 tdNameA.setAttribute("href", navLinkDecl(decl.name));
3506 tdNameA.textContent = decl.name;
3507
3508 preType.innerHTML = renderTokens(ex(walkResultTypeRef(decl.value), {}));
3509
3510 let docs = getAstNode(decl.src).docs;
3511 if (docs != null) {
3512 tdDesc.innerHTML = shortDescMarkdown(docs);
3513 } else {
3514 tdDesc.textContent = "";
3515 }
3516 }
3517 domSectValues.classList.remove("hidden");
3518 }
3519
3520 if (testsList.length !== 0) {
3521 resizeDomList(
3522 domListTests,
3523 testsList.length,
3524 '<tr><td><pre class="inline"></pre></td><td><pre class="inline"></pre></td><td></td></tr>'
3525 );
3526 for (let i = 0; i < testsList.length; i += 1) {
3527 let decl = testsList[i];
3528 let trDom = domListTests.children[i];
3529
3530 let tdName = trDom.children[0];
3531 let tdNamePre = tdName.children[0];
3532 let tdType = trDom.children[1];
3533 let tdTypePre = tdType.children[0];
3534 let tdDesc = trDom.children[2];
3535
3536 tdNamePre.innerHTML = renderSingleToken(Tok.identifier(decl.name));
3537
3538 tdTypePre.innerHTML = ex(walkResultTypeRef(decl.value), {});
3539
3540 let docs = getAstNode(decl.src).docs;
3541 if (docs != null) {
3542 tdDesc.innerHTML = shortDescMarkdown(docs);
3543 } else {
3544 tdDesc.textContent = "";
3545 }
3546 }
3547 domSectTests.classList.remove("hidden");
3548 }
3549
3550 if (container.kind !== typeKinds.Struct || containerNode.fields.length > 0) {
3551 domHdrName.innerHTML = "<pre class='inline'>" +
3552 zigAnalysis.typeKinds[container.kind] +
3553 "</pre>";
3554 domHdrName.classList.remove("hidden");
3555 }
3556 }
3557
3558 function operatorCompare(a, b) {
3559 if (a === b) {
3560 return 0;
3561 } else if (a < b) {
3562 return -1;
3563 } else {
3564 return 1;
3565 }
3566 }
3567
3568 function detectRootIsStd() {
3569 let rootMod = zigAnalysis.modules[zigAnalysis.rootMod];
3570 if (rootMod.table["std"] == null) {
3571 // no std mapped into the root module
3572 return false;
3573 }
3574 let stdMod = zigAnalysis.modules[rootMod.table["std"]];
3575 if (stdMod == null) return false;
3576 return rootMod.file === stdMod.file;
3577 }
3578
3579 function indexTypeKinds() {
3580 let map = {};
3581 for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
3582 map[zigAnalysis.typeKinds[i]] = i;
3583 }
3584 // This is just for debugging purposes, not needed to function
3585 let assertList = [
3586 "Type",
3587 "Void",
3588 "Bool",
3589 "NoReturn",
3590 "Int",
3591 "Float",
3592 "Pointer",
3593 "Array",
3594 "Struct",
3595 "ComptimeFloat",
3596 "ComptimeInt",
3597 "Undefined",
3598 "Null",
3599 "Optional",
3600 "ErrorUnion",
3601 "ErrorSet",
3602 "Enum",
3603 "Union",
3604 "Fn",
3605 "Opaque",
3606 "Frame",
3607 "AnyFrame",
3608 "Vector",
3609 "EnumLiteral",
3610 ];
3611 for (let i = 0; i < assertList.length; i += 1) {
3612 if (map[assertList[i]] == null)
3613 throw new Error("No type kind '" + assertList[i] + "' found");
3614 }
3615 return map;
3616 }
3617
3618 function findTypeTypeId() {
3619 for (let i = 0; i < zigAnalysis.types.length; i += 1) {
3620 if (getType(i).kind == typeKinds.Type) {
3621 return i;
3622 }
3623 }
3624 throw new Error("No type 'type' found");
3625 }
3626
3627
3628 function updateCurNav() {
3629 curNav = {
3630 hash: location.hash,
3631 mode: NAV_MODES.API,
3632 modNames: [],
3633 modObjs: [],
3634 declNames: [],
3635 declObjs: [],
3636 callName: null,
3637 activeGuide: null,
3638 activeGuideScrollTo: null,
3639 };
3640 curNavSearch = "";
3641
3642 const mode = location.hash.substring(0, 3);
3643 let query = location.hash.substring(3);
3644
3645 let qpos = query.indexOf("?");
3646 let nonSearchPart;
3647 if (qpos === -1) {
3648 nonSearchPart = query;
3649 } else {
3650 nonSearchPart = query.substring(0, qpos);
3651 curNavSearch = decodeURIComponent(query.substring(qpos + 1));
3652 }
3653
3654 const DEFAULT_HASH = NAV_MODES.API + zigAnalysis.modules[zigAnalysis.rootMod].name;
3655 switch (mode) {
3656 case NAV_MODES.API:
3657 // #A;MODULE:decl.decl.decl?search-term
3658 curNav.mode = mode;
3659 {
3660 let parts = nonSearchPart.split(":");
3661 if (parts[0] == "") {
3662 location.hash = DEFAULT_HASH;
3663 } else {
3664 curNav.modNames = decodeURIComponent(parts[0]).split(".");
3665 }
3666
3667 if (parts[1] != null) {
3668 curNav.declNames = decodeURIComponent(parts[1]).split(".");
3669 }
3670 }
3671 return;
3672 case NAV_MODES.GUIDES:
3673 curNav.mode = mode;
3674
3675 {
3676 let parts = nonSearchPart.split(":");
3677 curNav.activeGuide = parts[0];
3678 if (parts[1] != null) {
3679 curNav.activeGuideScrollTo = decodeURIComponent(":" + parts[1]);
3680 }
3681 }
3682 return;
3683 default:
3684 location.hash = DEFAULT_HASH;
3685 return;
3686 }
3687 }
3688
3689 function onHashChange(ev) {
3690 scrollHistory[curNav.hash] = scrollMonitor.map(function (x) {
3691 return [x, x.scrollTop]
3692 });
3693
3694 if (skipNextHashChange == decodeURIComponent(location.hash)) {
3695 skipNextHashChange = null;
3696 return;
3697 }
3698 skipNextHashChange = null;
3699 updateCurNav();
3700
3701 if (domSearch.value !== curNavSearch) {
3702 domSearch.value = curNavSearch;
3703 if (domSearch.value.length == 0)
3704 domSearchPlaceholder.classList.remove("hidden");
3705 else
3706 domSearchPlaceholder.classList.add("hidden");
3707 }
3708 render();
3709 if (imFeelingLucky) {
3710 imFeelingLucky = false;
3711 activateSelectedResult();
3712 }
3713
3714 scroll();
3715 }
3716
3717 function scroll() {
3718 const cur = scrollHistory[location.hash];
3719 if (cur) {
3720 for (let [elem, offset] of cur) {
3721 elem.scrollTo(0, offset);
3722 }
3723 } else {
3724 if (curNav.activeGuideScrollTo) return;
3725 for (let elem of scrollMonitor) {
3726 elem.scrollTo(0, 0);
3727 }
3728 }
3729 }
3730
3731 function findSubDecl(parentTypeOrDecl, childName) {
3732 let parentType = parentTypeOrDecl;
3733 {
3734 // Generic functions / resolving decls
3735 if ("value" in parentType) {
3736 const rv = resolveValue(parentType.value);
3737 if ("type" in rv.expr) {
3738 const t = getType(rv.expr.type);
3739 parentType = t;
3740 if (t.kind == typeKinds.Fn && t.generic_ret != null) {
3741 let resolvedGenericRet = resolveValue({ expr: t.generic_ret });
3742
3743 if ("call" in resolvedGenericRet.expr) {
3744 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
3745 let resolvedFunc = resolveValue({ expr: call.func });
3746 if (!("type" in resolvedFunc.expr)) return null;
3747 let callee = getType(resolvedFunc.expr.type);
3748 if (!callee.generic_ret) return null;
3749 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
3750 }
3751
3752 if ("type" in resolvedGenericRet.expr) {
3753 parentType = getType(resolvedGenericRet.expr.type);
3754 }
3755 }
3756 }
3757 }
3758 }
3759
3760 if (parentType.pubDecls) {
3761 for (let i = 0; i < parentType.pubDecls.length; i += 1) {
3762 let declIndex = parentType.pubDecls[i];
3763 let childDecl = getDecl(declIndex);
3764 if (childDecl.name === childName) {
3765 childDecl.find_subdecl_idx = declIndex;
3766 return childDecl;
3767 } else if (childDecl.is_uns) {
3768 let declValue = resolveValue(childDecl.value);
3769 if (!("type" in declValue.expr)) continue;
3770 let uns_container = getType(declValue.expr.type);
3771 let uns_res = findSubDecl(uns_container, childName);
3772 if (uns_res !== null) return uns_res;
3773 }
3774 }
3775 }
3776
3777 if (parentType.privDecls) {
3778 for (let i = 0; i < parentType.privDecls.length; i += 1) {
3779 let declIndex = parentType.privDecls[i];
3780 let childDecl = getDecl(declIndex);
3781 if (childDecl.name === childName) {
3782 childDecl.find_subdecl_idx = declIndex;
3783 childDecl.is_private = true;
3784 return childDecl;
3785 } else if (childDecl.is_uns) {
3786 let declValue = resolveValue(childDecl.value);
3787 if (!("type" in declValue.expr)) continue;
3788 let uns_container = getType(declValue.expr.type);
3789 let uns_res = findSubDecl(uns_container, childName);
3790 uns_res.is_private = true;
3791 if (uns_res !== null) return uns_res;
3792 }
3793 }
3794 }
3795
3796 return null;
3797 }
3798
3799 function computeCanonicalModulePaths() {
3800 let list = new Array(zigAnalysis.modules.length);
3801 // Now we try to find all the modules from root.
3802 let rootMod = zigAnalysis.modules[zigAnalysis.rootMod];
3803 // Breadth-first to keep the path shortest possible.
3804 let stack = [
3805 {
3806 path: [],
3807 mod: rootMod,
3808 },
3809 ];
3810 while (stack.length !== 0) {
3811 let item = stack.shift();
3812 for (let key in item.mod.table) {
3813 let childModIndex = item.mod.table[key];
3814 if (list[childModIndex] != null) continue;
3815 let childMod = zigAnalysis.modules[childModIndex];
3816 if (childMod == null) continue;
3817
3818 let newPath = item.path.concat([key]);
3819 list[childModIndex] = newPath;
3820 stack.push({
3821 path: newPath,
3822 mod: childMod,
3823 });
3824 }
3825 }
3826
3827 for (let i = 0; i < zigAnalysis.modules.length; i += 1) {
3828 const p = zigAnalysis.modules[i];
3829 // TODO
3830 // declSearchIndex.add(p.name, {moduleId: i});
3831 }
3832 return list;
3833 }
3834
3835 function computeCanonDeclPaths() {
3836 let list = new Array(zigAnalysis.decls.length);
3837 canonTypeDecls = new Array(zigAnalysis.types.length);
3838
3839 for (let modI = 0; modI < zigAnalysis.modules.length; modI += 1) {
3840 let mod = zigAnalysis.modules[modI];
3841 let modNames = canonModPaths[modI];
3842 if (modNames === undefined) continue;
3843
3844 let stack = [
3845 {
3846 declNames: [],
3847 declIndexes: [],
3848 type: getType(mod.main),
3849 },
3850 ];
3851 while (stack.length !== 0) {
3852 let item = stack.shift();
3853
3854 if (isContainerType(item.type)) {
3855 let t = item.type;
3856
3857 let len = t.pubDecls ? t.pubDecls.length : 0;
3858 for (let declI = 0; declI < len; declI += 1) {
3859 let declIndex = t.pubDecls[declI];
3860 if (list[declIndex] != null) continue;
3861
3862 let decl = getDecl(declIndex);
3863
3864 if (decl.is_uns) {
3865 let unsDeclList = [decl];
3866 while (unsDeclList.length != 0) {
3867 let unsDecl = unsDeclList.pop();
3868 let unsDeclVal = resolveValue(unsDecl.value);
3869 if (!("type" in unsDeclVal.expr)) continue;
3870 let unsType = getType(unsDeclVal.expr.type);
3871 if (!isContainerType(unsType)) continue;
3872 let unsPubDeclLen = unsType.pubDecls ? unsType.pubDecls.length : 0;
3873 for (let unsDeclI = 0; unsDeclI < unsPubDeclLen; unsDeclI += 1) {
3874 let childDeclIndex = unsType.pubDecls[unsDeclI];
3875 let childDecl = getDecl(childDeclIndex);
3876
3877 if (childDecl.is_uns) {
3878 unsDeclList.push(childDecl);
3879 } else {
3880 addDeclToSearchResults(childDecl, childDeclIndex, modNames, item, list, stack);
3881 }
3882 }
3883 }
3884 } else {
3885 addDeclToSearchResults(decl, declIndex, modNames, item, list, stack);
3886 }
3887 }
3888 }
3889 }
3890 }
3891 window.cdp = list;
3892 return list;
3893 }
3894
3895 function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
3896 let {value: declVal, seenDecls} = resolveValue(decl.value, true);
3897 let declNames = item.declNames.concat([decl.name]);
3898 let declIndexes = item.declIndexes.concat([declIndex]);
3899
3900 if (list[declIndex] != null) return;
3901 list[declIndex] = {
3902 modNames: modNames,
3903 declNames: declNames,
3904 declIndexes: declIndexes,
3905 };
3906
3907 for (let sd of seenDecls) {
3908 if (list[sd] != null) continue;
3909 list[sd] = {
3910 modNames: modNames,
3911 declNames: declNames,
3912 declIndexes: declIndexes,
3913 };
3914 }
3915
3916 // add to search index
3917 {
3918 declSearchIndex.add(decl.name, { declIndex });
3919 }
3920
3921
3922 if ("type" in declVal.expr) {
3923 let value = getType(declVal.expr.type);
3924 if (declCanRepresentTypeKind(value.kind)) {
3925 canonTypeDecls[declVal.type] = declIndex;
3926 }
3927
3928 if (isContainerType(value)) {
3929 stack.push({
3930 declNames: declNames,
3931 declIndexes: declIndexes,
3932 type: value,
3933 });
3934 }
3935
3936 // Generic function
3937 if (typeIsGenericFn(declVal.expr.type)) {
3938 let ret = resolveGenericRet(value);
3939 if (ret != null && "type" in ret.expr) {
3940 let generic_type = getType(ret.expr.type);
3941 if (isContainerType(generic_type)) {
3942 stack.push({
3943 declNames: declNames,
3944 declIndexes: declIndexes,
3945 type: generic_type,
3946 });
3947 }
3948 }
3949 }
3950 }
3951 }
3952
3953 function declLinkOrSrcLink(index) {
3954
3955 let match = getCanonDeclPath(index);
3956 if (match) return navLink(match.modNames, match.declNames);
3957
3958 // could not find a precomputed decl path
3959 const decl = getDecl(index);
3960
3961 // try to find a public decl by scanning declRefs and declPaths
3962 let value = decl.value;
3963 let i = 0;
3964 while (true) {
3965 i += 1;
3966 if (i >= 10000) {
3967 throw "getCanonDeclPath quota exceeded"
3968 }
3969
3970 if ("refPath" in value.expr) {
3971 value = { expr: value.expr.refPath[value.expr.refPath.length - 1] };
3972 continue;
3973 }
3974
3975 if ("declRef" in value.expr) {
3976 let cp = canonDeclPaths[value.expr.declRef];
3977 if (cp) return navLink(cp.modNames, cp.declNames);
3978
3979 value = getDecl(value.expr.declRef).value;
3980 continue;
3981 }
3982
3983 if ("as" in value.expr) {
3984 value = {
3985 typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
3986 expr: zigAnalysis.exprs[value.expr.as.exprArg],
3987 };
3988 continue;
3989 }
3990
3991 // if we got here it means that we failed
3992 // produce a link to source code instead
3993 return sourceFileLink(decl);
3994
3995 }
3996
3997 }
3998
3999 function getCanonDeclPath(index) {
4000 if (canonDeclPaths == null) {
4001 canonDeclPaths = computeCanonDeclPaths();
4002 }
4003
4004 return canonDeclPaths[index];
4005
4006
4007 }
4008
4009 function getCanonTypeDecl(index) {
4010 getCanonDeclPath(0);
4011 //let ct = (canonTypeDecls);
4012 return canonTypeDecls[index];
4013 }
4014
4015 function escapeHtml(text) {
4016 return text.replace(/[&"<>]/g, function(m) {
4017 return escapeHtmlReplacements[m];
4018 });
4019 }
4020
4021 function shortDesc(docs) {
4022 const trimmed_docs = docs.trim();
4023 let index = trimmed_docs.indexOf("\n\n");
4024 let cut = false;
4025
4026 if (index < 0 || index > 130) {
4027 if (trimmed_docs.length > 130) {
4028 index = 130;
4029 cut = true;
4030 } else {
4031 index = trimmed_docs.length;
4032 }
4033 }
4034
4035 let slice = trimmed_docs.slice(0, index);
4036 if (cut) slice += "...";
4037 return slice;
4038 }
4039
4040 function shortDescMarkdown(docs) {
4041 return markdown(shortDesc(docs));
4042 }
4043
4044 function parseGuides() {
4045 for (let j = 0; j < zigAnalysis.guideSections.length; j += 1) {
4046 const section = zigAnalysis.guideSections[j];
4047 for (let i = 0; i < section.guides.length; i += 1) {
4048 let reader = new commonmark.Parser({ smart: true });
4049 const guide = section.guides[i];
4050
4051 // Find the first text thing to use as a sidebar title
4052 guide.title = null;
4053 guide.toc = "";
4054
4055 // Discover Title & TOC for this guide
4056 {
4057 let reader = new commonmark.Parser({smart: true});
4058 let ast = reader.parse(guide.body);
4059 let walker = ast.walker();
4060 let heading_idx = 0;
4061 let event, node, doc, last, last_ul;
4062 while ((event = walker.next())) {
4063 node = event.node;
4064 if (event.entering) {
4065 if (node.type === 'document') {
4066 doc = node;
4067 continue;
4068 }
4069
4070
4071 if (node.next) {
4072 walker.resumeAt(node.next, true);
4073 } else {
4074 walker.resumeAt(node, false);
4075 }
4076 node.unlink();
4077
4078 if (node.type === 'heading') {
4079 if (node.level == 1) {
4080 if (guide.title == null) {
4081 let doc_node = new commonmark.Node("document", node.sourcepos);
4082 while (node.firstChild) {
4083 doc_node.appendChild(node.firstChild);
4084 }
4085 let writer = new commonmark.HtmlRenderer();
4086 let result = writer.render(doc_node);
4087 guide.title = result;
4088 }
4089
4090 continue; // don't index H1
4091 }
4092
4093 // turn heading node into list item & add link node to it
4094 {
4095 node._type = "link";
4096 node.destination = NAV_MODES.GUIDES + guide.name + ":" + heading_idx;
4097 heading_idx += 1;
4098 let listItem = new commonmark.Node("item", node.sourcepos);
4099 // TODO: strip links from inside node
4100 listItem.appendChild(node);
4101 listItem.level = node.level;
4102 node = listItem;
4103 }
4104
4105 if (last_ul) {
4106 // are we inside or outside of it?
4107
4108 let target_ul = last_ul;
4109 while(target_ul.level > node.level) {
4110 target_ul = target_ul.parent;
4111 }
4112 while(target_ul.level < node.level) {
4113 let ul_node = new commonmark.Node("list", node.sourcepos);
4114 ul_node.level = target_ul.level + 1;
4115 ul_node.listType = "bullet";
4116 ul_node.listStart = null;
4117 target_ul.appendChild(ul_node);
4118 target_ul = ul_node;
4119 }
4120
4121 target_ul.appendChild(node);
4122 last_ul = target_ul;
4123 } else {
4124 let ul_node = new commonmark.Node("list", node.sourcepos);
4125 ul_node.level = 2;
4126 ul_node.listType = "bullet";
4127 ul_node.listStart = null;
4128 doc.prependChild(ul_node);
4129
4130 while (ul_node.level < node.level) {
4131 let current_ul_node = new commonmark.Node("list", node.sourcepos);
4132 current_ul_node.level = ul_node.level + 1;
4133 current_ul_node.listType = "bullet";
4134 current_ul_node.listStart = null;
4135 ul_node.appendChild(current_ul_node);
4136 ul_node = current_ul_node;
4137 }
4138
4139 last_ul = ul_node;
4140
4141 ul_node.appendChild(node);
4142 }
4143 }
4144 }
4145 }
4146
4147 let writer = new commonmark.HtmlRenderer();
4148 let result = writer.render(ast);
4149 guide.toc = result;
4150 }
4151
4152 // Index this guide
4153 {
4154 // let walker = guide.ast.walker();
4155 // let event, node;
4156 // while ((event = walker.next())) {
4157 // node = event.node;
4158 // if (event.entering == true && node.type === 'text') {
4159 // indexTextForGuide(j, i, node);
4160 // }
4161 // }
4162 }
4163 }
4164 }
4165 }
4166
4167 function indexTextForGuide(section_idx, guide_idx, node) {
4168 const terms = node.literal.split(" ");
4169 for (let i = 0; i < terms.length; i += 1) {
4170 const t = terms[i];
4171 if (!guidesSearchIndex[t]) guidesSearchIndex[t] = new Set();
4172 node.guide = { section_idx, guide_idx };
4173 guidesSearchIndex[t].add(node);
4174 }
4175 }
4176
4177
4178 function markdown(input, contextType) {
4179 const parsed = new commonmark.Parser({ smart: true }).parse(input);
4180
4181 // Look for decl references in inline code (`ref`)
4182 const walker = parsed.walker();
4183 let event;
4184 while ((event = walker.next())) {
4185 const node = event.node;
4186 if (node.type === "code") {
4187 const declHash = detectDeclPath(node.literal, contextType);
4188 if (declHash) {
4189 const link = new commonmark.Node("link");
4190 link.destination = declHash;
4191 node.insertBefore(link);
4192 link.appendChild(node);
4193 }
4194 }
4195 }
4196
4197 return new commonmark.HtmlRenderer({ safe: true }).render(parsed);
4198
4199 }
4200
4201
4202
4203 // function detectDeclPath(text, context) {
4204 // let result = "";
4205 // let separator = ":";
4206 // const components = text.split(".");
4207 // let curDeclOrType = undefined;
4208
4209 // let curContext = context;
4210 // let limit = 10000;
4211 // while (curContext) {
4212 // limit -= 1;
4213
4214 // if (limit == 0) {
4215 // throw "too many iterations";
4216 // }
4217
4218 // curDeclOrType = findSubDecl(curContext, components[0]);
4219
4220 // if (!curDeclOrType) {
4221 // if (curContext.parent_container == null) break;
4222 // curContext = getType(curContext.parent_container);
4223 // continue;
4224 // }
4225
4226 // if (curContext == context) {
4227 // separator = '.';
4228 // result = location.hash + separator + components[0];
4229 // } else {
4230 // // We had to go up, which means we need a new path!
4231 // const canonPath = getCanonDeclPath(curDeclOrType.find_subdecl_idx);
4232 // if (!canonPath) return;
4233
4234 // let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
4235 // let fullPath = lastModName + ":" + canonPath.declNames.join(".");
4236
4237 // separator = '.';
4238 // result = "#A;" + fullPath;
4239 // }
4240
4241 // break;
4242 // }
4243
4244 // if (!curDeclOrType) {
4245 // for (let i = 0; i < zigAnalysis.modules.length; i += 1) {
4246 // const p = zigAnalysis.modules[i];
4247 // if (p.name == components[0]) {
4248 // curDeclOrType = getType(p.main);
4249 // result += "#A;" + components[0];
4250 // break;
4251 // }
4252 // }
4253 // }
4254
4255 // if (!curDeclOrType) return null;
4256
4257 // for (let i = 1; i < components.length; i += 1) {
4258 // curDeclOrType = findSubDecl(curDeclOrType, components[i]);
4259 // if (!curDeclOrType) return null;
4260 // result += separator + components[i];
4261 // separator = '.';
4262 // }
4263
4264 // return result;
4265
4266 // }
4267
4268 function activateSelectedResult() {
4269 if (domSectSearchResults.classList.contains("hidden")) {
4270 return;
4271 }
4272
4273 const searchResults = domListSearchResults.getElementsByTagName("li");
4274 let liDom = searchResults[curSearchIndex];
4275 if (liDom == null && searchResults.length !== 0) {
4276 liDom = searchResults[0];
4277 }
4278 if (liDom != null) {
4279 let aDom = liDom.children[0];
4280 location.href = aDom.getAttribute("href");
4281 curSearchIndex = -1;
4282 }
4283 domSearch.blur();
4284 }
4285
4286 // hide the modal if it's visible or return to the previous result page and unfocus the search
4287 function onEscape(ev) {
4288 if (isModalVisible(domHelpModal)) {
4289 hideModal(domHelpModal);
4290 ev.preventDefault();
4291 ev.stopPropagation();
4292 } else if (isModalVisible(domPrefsModal)) {
4293 hideModal(domPrefsModal);
4294 ev.preventDefault();
4295 ev.stopPropagation();
4296 } else {
4297 domSearch.value = "";
4298 domSearch.blur();
4299 domSearchPlaceholder.classList.remove("hidden");
4300 curSearchIndex = -1;
4301 ev.preventDefault();
4302 ev.stopPropagation();
4303 startSearch();
4304 }
4305 }
4306
4307
4308 function onSearchKeyDown(ev) {
4309 switch (getKeyString(ev)) {
4310 case "Enter":
4311 // detect if this search changes anything
4312 let terms1 = getSearchTerms();
4313 startSearch();
4314 updateCurNav();
4315 let terms2 = getSearchTerms();
4316 // we might have to wait for onHashChange to trigger
4317 imFeelingLucky = terms1.join(" ") !== terms2.join(" ");
4318 if (!imFeelingLucky) activateSelectedResult();
4319
4320 ev.preventDefault();
4321 ev.stopPropagation();
4322 return;
4323 case "Esc":
4324 onEscape(ev);
4325 return
4326 case "Up":
4327 moveSearchCursor(-1);
4328 ev.preventDefault();
4329 ev.stopPropagation();
4330 return;
4331 case "Down":
4332 // TODO: make the page scroll down if the search cursor is out of the screen
4333 moveSearchCursor(1);
4334 ev.preventDefault();
4335 ev.stopPropagation();
4336 return;
4337 default:
4338 // Search is triggered via an `input` event handler, not on arbitrary `keydown` events.
4339 ev.stopPropagation();
4340 return;
4341 }
4342 }
4343
4344 let domDotsToggleTimeout = null;
4345 function onSearchInput(ev) {
4346 curSearchIndex = -1;
4347
4348 let replaced = domSearch.value.replaceAll(".", " ")
4349
4350 // Ping red the help text if the user typed a dot.
4351 if (replaced != domSearch.value) {
4352 domSearchHelpSummary.classList.remove("normal");
4353 if (domDotsToggleTimeout != null) {
4354 clearTimeout(domDotsToggleTimeout);
4355 domDotsToggleTimeout = null;
4356 }
4357 domDotsToggleTimeout = setTimeout(function () {
4358 domSearchHelpSummary.classList.add("normal");
4359 }, 1000);
4360 }
4361
4362 replaced = replaced.replace(/ +/g, ' ');
4363 if (replaced != domSearch.value) {
4364 domSearch.value = replaced;
4365 }
4366
4367 startAsyncSearch();
4368 }
4369
4370 function moveSearchCursor(dir) {
4371 const searchResults = domListSearchResults.getElementsByTagName("li");
4372 if (
4373 curSearchIndex < 0 ||
4374 curSearchIndex >= searchResults.length
4375 ) {
4376 if (dir > 0) {
4377 curSearchIndex = -1 + dir;
4378 } else if (dir < 0) {
4379 curSearchIndex = searchResults.length + dir;
4380 }
4381 } else {
4382 curSearchIndex += dir;
4383 }
4384 if (curSearchIndex < 0) {
4385 curSearchIndex = 0;
4386 }
4387 if (curSearchIndex >= searchResults.length) {
4388 curSearchIndex = searchResults.length - 1;
4389 }
4390 renderSearchCursor();
4391 }
4392
4393 function getKeyString(ev) {
4394 let name;
4395 let ignoreShift = false;
4396 switch (ev.which) {
4397 case 13:
4398 name = "Enter";
4399 break;
4400 case 27:
4401 name = "Esc";
4402 break;
4403 case 38:
4404 name = "Up";
4405 break;
4406 case 40:
4407 name = "Down";
4408 break;
4409 default:
4410 ignoreShift = true;
4411 name =
4412 ev.key != null
4413 ? ev.key
4414 : String.fromCharCode(ev.charCode || ev.keyCode);
4415 }
4416 if (!ignoreShift && ev.shiftKey) name = "Shift+" + name;
4417 if (ev.altKey) name = "Alt+" + name;
4418 if (ev.ctrlKey) name = "Ctrl+" + name;
4419 return name;
4420 }
4421
4422 function onWindowKeyDown(ev) {
4423 switch (getKeyString(ev)) {
4424 case "Esc":
4425 onEscape(ev);
4426 break;
4427 case "/":
4428 if (!getPrefSlashSearch()) break;
4429 // fallthrough
4430 case "s":
4431 if (!isModalVisible(domHelpModal) && !isModalVisible(domPrefsModal)) {
4432 if (ev.target == domSearch) break;
4433
4434 domSearch.focus();
4435 domSearch.select();
4436 domDocs.scrollTo(0, 0);
4437 ev.preventDefault();
4438 ev.stopPropagation();
4439 startAsyncSearch();
4440 }
4441 break;
4442 case "?":
4443 if (!canToggleModal) break;
4444
4445 if (isModalVisible(domPrefsModal)) {
4446 hideModal(domPrefsModal);
4447 }
4448
4449 // toggle the help modal
4450 if (isModalVisible(domHelpModal)) {
4451 hideModal(domHelpModal);
4452 } else {
4453 showModal(domHelpModal);
4454 }
4455 ev.preventDefault();
4456 ev.stopPropagation();
4457 break;
4458 case "p":
4459 if (!canToggleModal) break;
4460
4461 if (isModalVisible(domHelpModal)) {
4462 hideModal(domHelpModal);
4463 }
4464
4465 // toggle the preferences modal
4466 if (isModalVisible(domPrefsModal)) {
4467 hideModal(domPrefsModal);
4468 } else {
4469 showModal(domPrefsModal);
4470 }
4471 ev.preventDefault();
4472 ev.stopPropagation();
4473 }
4474 }
4475
4476 function isModalVisible(modal) {
4477 return !modal.classList.contains("hidden");
4478 }
4479
4480 function showModal(modal) {
4481 modal.classList.remove("hidden");
4482 modal.style.left =
4483 window.innerWidth / 2 - modal.clientWidth / 2 + "px";
4484 modal.style.top =
4485 window.innerHeight / 2 - modal.clientHeight / 2 + "px";
4486 const firstInput = modal.querySelector("input");
4487 if (firstInput) {
4488 firstInput.focus();
4489 } else {
4490 modal.focus();
4491 }
4492 domSearch.blur();
4493 domBanner.inert = true;
4494 domMain.inert = true;
4495 }
4496
4497 function hideModal(modal) {
4498 modal.classList.add("hidden");
4499 domBanner.inert = false;
4500 domMain.inert = false;
4501 modal.blur();
4502 }
4503
4504 function clearAsyncSearch() {
4505 if (searchTimer != null) {
4506 clearTimeout(searchTimer);
4507 searchTimer = null;
4508 }
4509 }
4510
4511 function startAsyncSearch() {
4512 clearAsyncSearch();
4513 searchTimer = setTimeout(startSearch, 100);
4514 }
4515 function startSearch() {
4516 clearAsyncSearch();
4517 let oldHash = location.hash;
4518 let parts = oldHash.split("?");
4519 let newPart2 = domSearch.value === "" ? "" : "?" + domSearch.value;
4520 location.replace(parts.length === 1 ? oldHash + newPart2 : parts[0] + newPart2);
4521 }
4522 function getSearchTerms() {
4523 let list = curNavSearch.trim().split(/[ \r\n\t]+/);
4524 return list;
4525 }
4526
4527 function renderSearchGuides() {
4528 const searchTrimmed = false;
4529 let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
4530
4531 let terms = getSearchTerms();
4532 let matchedItems = new Set();
4533
4534 for (let i = 0; i < terms.length; i += 1) {
4535 const nodes = guidesSearchIndex[terms[i]];
4536 if (nodes) {
4537 for (const n of nodes) {
4538 matchedItems.add(n);
4539 }
4540 }
4541 }
4542
4543
4544
4545 if (matchedItems.size !== 0) {
4546 // Build up the list of search results
4547 let matchedItemsHTML = "";
4548
4549 for (const node of matchedItems) {
4550 const text = node.literal;
4551 const href = "";
4552
4553 matchedItemsHTML += "<li><a href=\"" + href + "\">" + text + "</a></li>";
4554 }
4555
4556 // Replace the search results using our newly constructed HTML string
4557 domListSearchResults.innerHTML = matchedItemsHTML;
4558 if (searchTrimmed) {
4559 domSectSearchAllResultsLink.classList.remove("hidden");
4560 }
4561 renderSearchCursor();
4562
4563 domSectSearchResults.classList.remove("hidden");
4564 } else {
4565 domSectSearchNoResults.classList.remove("hidden");
4566 }
4567 }
4568
4569 function renderSearchAPI() {
4570 domSectSearchResults.prepend(
4571 domSearchHelp.parentElement.removeChild(domSearchHelp)
4572 );
4573 if (canonDeclPaths == null) {
4574 canonDeclPaths = computeCanonDeclPaths();
4575 }
4576 let declSet = new Set();
4577 let otherDeclSet = new Set(); // for low quality results
4578 let declScores = {};
4579
4580 let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
4581 let term_list = getSearchTerms();
4582 for (let i = 0; i < term_list.length; i += 1) {
4583 let term = term_list[i];
4584 let result = declSearchIndex.search(term.toLowerCase());
4585 if (result == null) {
4586 domSectSearchNoResults.prepend(
4587 domSearchHelp.parentElement.removeChild(domSearchHelp)
4588 );
4589 domSectSearchNoResults.classList.remove("hidden");
4590
4591 domSectSearchResults.classList.add("hidden");
4592 return;
4593 }
4594
4595 let termSet = new Set();
4596 let termOtherSet = new Set();
4597
4598 for (let list of [result.full, result.partial]) {
4599 for (let r of list) {
4600 const d = r.declIndex;
4601 const decl = getDecl(d);
4602 const canonPath = getCanonDeclPath(d);
4603
4604 // collect unconditionally for the first term
4605 if (i == 0) {
4606 declSet.add(d);
4607 } else {
4608 // path intersection for subsequent terms
4609 let found = false;
4610 for (let p of canonPath.declIndexes) {
4611 if (declSet.has(p)) {
4612 found = true;
4613 break;
4614 }
4615 }
4616 if (!found) {
4617 otherDeclSet.add(d);
4618 } else {
4619 termSet.add(d);
4620 }
4621 }
4622
4623 if (declScores[d] == undefined) declScores[d] = 0;
4624
4625 // scores (lower is better)
4626 let decl_name = decl.name;
4627 if (ignoreCase) decl_name = decl_name.toLowerCase();
4628
4629 // shallow path are preferable
4630 const path_depth = canonPath.declNames.length * 50;
4631 // matching the start of a decl name is good
4632 const match_from_start = decl_name.startsWith(term) ? -term.length * (2 - ignoreCase) : (decl_name.length - term.length) + 1;
4633 // being a perfect match is good
4634 const is_full_match = (decl_name === term) ? -decl_name.length * (1 - ignoreCase) : Math.abs(decl_name.length - term.length);
4635 // matching the end of a decl name is good
4636 const matches_the_end = decl_name.endsWith(term) ? -term.length * (1 - ignoreCase) : (decl_name.length - term.length) + 1;
4637 // explicitly penalizing scream case decls
4638 const decl_is_scream_case = decl.name.toUpperCase() != decl.name ? 0 : decl.name.length;
4639
4640 const score = path_depth
4641 + match_from_start
4642 + is_full_match
4643 + matches_the_end
4644 + decl_is_scream_case;
4645
4646 declScores[d] += score;
4647 }
4648 }
4649 if (i != 0) {
4650 for (let d of declSet) {
4651 if (termSet.has(d)) continue;
4652 let found = false;
4653 for (let p of getCanonDeclPath(d).declIndexes) {
4654 if (termSet.has(p) || otherDeclSet.has(p)) {
4655 found = true;
4656 break;
4657 }
4658 }
4659 if (found) {
4660 declScores[d] = declScores[d] / term_list.length;
4661 }
4662
4663 termOtherSet.add(d);
4664 }
4665 declSet = termSet;
4666 for (let d of termOtherSet) {
4667 otherDeclSet.add(d);
4668 }
4669
4670 }
4671 }
4672
4673 let matchedItems = {
4674 high_quality: [],
4675 low_quality: [],
4676 };
4677 for (let idx of declSet) {
4678 matchedItems.high_quality.push({ points: declScores[idx], declIndex: idx })
4679 }
4680 for (let idx of otherDeclSet) {
4681 matchedItems.low_quality.push({ points: declScores[idx], declIndex: idx })
4682 }
4683
4684 matchedItems.high_quality.sort(function(a, b) {
4685 let cmp = operatorCompare(a.points, b.points);
4686 return cmp;
4687 });
4688 matchedItems.low_quality.sort(function(a, b) {
4689 let cmp = operatorCompare(a.points, b.points);
4690 return cmp;
4691 });
4692
4693 // Build up the list of search results
4694 let matchedItemsHTML = "";
4695
4696 for (let list of [matchedItems.high_quality, matchedItems.low_quality]) {
4697 if (list == matchedItems.low_quality && list.length > 0) {
4698 matchedItemsHTML += "<hr class='other-results'>"
4699 }
4700 for (let result of list) {
4701 const points = result.points;
4702 const match = result.declIndex;
4703
4704 let canonPath = getCanonDeclPath(match);
4705 if (canonPath == null) continue;
4706
4707 let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
4708 let text = lastModName + "." + canonPath.declNames.join(".");
4709
4710
4711 const href = navLink(canonPath.modNames, canonPath.declNames);
4712
4713 matchedItemsHTML += "<li><a href=\"" + href + "\">" + text + "</a></li>";
4714 }
4715 }
4716
4717 // Replace the search results using our newly constructed HTML string
4718 domListSearchResults.innerHTML = matchedItemsHTML;
4719 renderSearchCursor();
4720
4721 domSectSearchResults.classList.remove("hidden");
4722 }
4723
4724
4725
4726 function renderSearchCursor() {
4727 const searchResults = domListSearchResults.getElementsByTagName("li");
4728 for (let i = 0; i < searchResults.length; i += 1) {
4729 let liDom = searchResults[i];
4730 if (curSearchIndex === i) {
4731 liDom.classList.add("selected");
4732 } else {
4733 liDom.classList.remove("selected");
4734 }
4735 }
4736 }
4737
4738 function scrollGuidesTop(ev) {
4739 document.getElementById("activeGuide").children[0].scrollIntoView({
4740 behavior: "smooth",
4741 });
4742 ev.preventDefault();
4743 ev.stopPropagation();
4744 }
4745 document.scrollGuidesTop = scrollGuidesTop;
4746
4747 function scrollToHeading(id, alreadyThere) {
4748 // Don't scroll if the current location has a scrolling history.
4749 if (scrollHistory[location.hash]) return;
4750
4751 const c = document.getElementById(id);
4752 if (c && alreadyThere) {
4753 requestAnimationFrame(() => c.scrollIntoView({behavior: "smooth"}));
4754 } else {
4755 requestAnimationFrame(() => c.scrollIntoView());
4756 }
4757 return;
4758 }
4759 // function indexNodesToCalls() {
4760 // let map = {};
4761 // for (let i = 0; i < zigAnalysis.calls.length; i += 1) {
4762 // let call = zigAnalysis.calls[i];
4763 // let fn = zigAnalysis.fns[call.fn];
4764 // if (map[fn.src] == null) {
4765 // map[fn.src] = [i];
4766 // } else {
4767 // map[fn.src].push(i);
4768 // }
4769 // }
4770 // return map;
4771 // }
4772
4773 function byNameProperty(a, b) {
4774 return operatorCompare(a.name, b.name);
4775 }
4776
4777
4778 function getDecl(idx) {
4779 const decl = zigAnalysis.decls[idx];
4780 return {
4781 name: decl[0],
4782 kind: decl[1],
4783 src: decl[2],
4784 value: decl[3],
4785 decltest: decl[4],
4786 is_uns: decl[5],
4787 parent_container: decl[6],
4788 };
4789 }
4790
4791 function getAstNode(idx) {
4792 const ast = zigAnalysis.astNodes[idx];
4793 return {
4794 file: ast[0],
4795 line: ast[1],
4796 col: ast[2],
4797 name: ast[3],
4798 code: ast[4],
4799 docs: ast[5],
4800 fields: ast[6],
4801 comptime: ast[7],
4802 };
4803 }
4804
4805 function getFile(idx) {
4806 const file = zigAnalysis.files[idx];
4807 return {
4808 name: file[0],
4809 modIndex: file[1],
4810 };
4811 }
4812
4813 function getType(idx) {
4814 const ty = zigAnalysis.types[idx];
4815 switch (ty[0]) {
4816 default:
4817 throw "unhandled type kind!";
4818 case typeKinds.Unanalyzed:
4819 throw "unanalyzed type!";
4820 case typeKinds.Type:
4821 case typeKinds.Void:
4822 case typeKinds.Bool:
4823 case typeKinds.NoReturn:
4824 case typeKinds.Int:
4825 case typeKinds.Float:
4826 return { kind: ty[0], name: ty[1] };
4827 case typeKinds.Pointer:
4828 return {
4829 kind: ty[0],
4830 size: ty[1],
4831 child: ty[2],
4832 sentinel: ty[3],
4833 align: ty[4],
4834 address_space: ty[5],
4835 bit_start: ty[6],
4836 host_size: ty[7],
4837 is_ref: ty[8],
4838 is_allowzero: ty[9],
4839 is_mutable: ty[10],
4840 is_volatile: ty[11],
4841 has_sentinel: ty[12],
4842 has_align: ty[13],
4843 has_addrspace: ty[14],
4844 has_bit_range: ty[15],
4845 };
4846 case typeKinds.Array:
4847 return {
4848 kind: ty[0],
4849 len: ty[1],
4850 child: ty[2],
4851 sentinel: ty[3],
4852 };
4853 case typeKinds.Struct:
4854 return {
4855 kind: ty[0],
4856 name: ty[1],
4857 src: ty[2],
4858 privDecls: ty[3],
4859 pubDecls: ty[4],
4860 field_types: ty[5],
4861 field_defaults: ty[6],
4862 backing_int: ty[7],
4863 is_tuple: ty[8],
4864 line_number: ty[9],
4865 parent_container: ty[10],
4866 layout: ty[11],
4867 };
4868 case typeKinds.ComptimeExpr:
4869 case typeKinds.ComptimeFloat:
4870 case typeKinds.ComptimeInt:
4871 case typeKinds.Undefined:
4872 case typeKinds.Null:
4873 return { kind: ty[0], name: ty[1] };
4874 case typeKinds.Optional:
4875 return {
4876 kind: ty[0],
4877 name: ty[1],
4878 child: ty[2],
4879 };
4880 case typeKinds.ErrorUnion:
4881 return {
4882 kind: ty[0],
4883 lhs: ty[1],
4884 rhs: ty[2],
4885 };
4886 case typeKinds.InferredErrorUnion:
4887 return {
4888 kind: ty[0],
4889 payload: ty[1],
4890 };
4891 case typeKinds.ErrorSet:
4892 return {
4893 kind: ty[0],
4894 name: ty[1],
4895 fields: ty[2],
4896 };
4897 case typeKinds.Enum:
4898 return {
4899 kind: ty[0],
4900 name: ty[1],
4901 src: ty[2],
4902 privDecls: ty[3],
4903 pubDecls: ty[4],
4904 tag: ty[5],
4905 values: ty[6],
4906 nonexhaustive: ty[7],
4907 parent_container: ty[8],
4908 };
4909 case typeKinds.Union:
4910 return {
4911 kind: ty[0],
4912 name: ty[1],
4913 src: ty[2],
4914 privDecls: ty[3],
4915 pubDecls: ty[4],
4916 field_types: ty[5],
4917 tag: ty[6],
4918 auto_tag: ty[7],
4919 parent_container: ty[8],
4920 layout: ty[9],
4921 };
4922 case typeKinds.Fn:
4923 return {
4924 kind: ty[0],
4925 name: ty[1],
4926 src: ty[2],
4927 ret: ty[3],
4928 generic_ret: ty[4],
4929 params: ty[5],
4930 lib_name: ty[6],
4931 is_var_args: ty[7],
4932 is_inferred_error: ty[8],
4933 has_lib_name: ty[9],
4934 has_cc: ty[10],
4935 cc: ty[11],
4936 align: ty[12],
4937 has_align: ty[13],
4938 is_test: ty[14],
4939 is_extern: ty[15],
4940 };
4941 case typeKinds.Opaque:
4942 return {
4943 kind: ty[0],
4944 name: ty[1],
4945 src: ty[2],
4946 privDecls: ty[3],
4947 pubDecls: ty[4],
4948 parent_container: ty[5],
4949 };
4950 case typeKinds.Frame:
4951 case typeKinds.AnyFrame:
4952 case typeKinds.Vector:
4953 case typeKinds.EnumLiteral:
4954 return { kind: ty[0], name: ty[1] };
4955 }
4956 }
4957
4958 function getLocalStorage() {
4959 if ("localStorage" in window) {
4960 try {
4961 return window.localStorage;
4962 } catch (ignored) {
4963 // localStorage may be disabled (SecurityError)
4964 }
4965 }
4966 // If localStorage isn't available, persist preferences only for the current session
4967 const sessionPrefs = {};
4968 return {
4969 getItem(key) {
4970 return key in sessionPrefs ? sessionPrefs[key] : null;
4971 },
4972 setItem(key, value) {
4973 sessionPrefs[key] = String(value);
4974 },
4975 };
4976 }
4977
4978 function loadPrefs() {
4979 const storedPrefSlashSearch = prefs.getItem("slashSearch");
4980 if (storedPrefSlashSearch === null) {
4981 // Slash search defaults to enabled for all browsers except Firefox
4982 setPrefSlashSearch(navigator.userAgent.indexOf("Firefox") === -1);
4983 } else {
4984 setPrefSlashSearch(storedPrefSlashSearch === "true");
979 function setInputString(s) {
980 const jsArray = text_encoder.encode(s);
981 const len = jsArray.length;
982 const ptr = wasm_exports.set_input_string(len);
983 const wasmArray = new Uint8Array(wasm_exports.memory.buffer, ptr, len);
984 wasmArray.set(jsArray);
4985985 }
4986 }
4987
4988 function getPrefSlashSearch() {
4989 return prefs.getItem("slashSearch") === "true";
4990 }
4991
4992 function setPrefSlashSearch(enabled) {
4993 prefs.setItem("slashSearch", String(enabled));
4994 domPrefSlashSearch.checked = enabled;
4995 const searchKeys = enabled ? "<kbd>/</kbd> or <kbd>s</kbd>" : "<kbd>s</kbd>";
4996 domSearchKeys.innerHTML = searchKeys;
4997 domSearchPlaceholderText.innerHTML = searchKeys + " to search, <kbd>?</kbd> for more options";
4998 }
4999986})();
5000987
5001function toggleExpand(event) {
5002 const parent = event.target.parentElement;
5003 parent.toggleAttribute("open");
5004
5005 if (!parent.open && parent.getBoundingClientRect().top < 0) {
5006 parent.parentElement.parentElement.scrollIntoView(true);
5007 }
5008}
5009
5010function RadixTree() {
5011 this.root = null;
5012
5013 RadixTree.prototype.search = function(query) {
5014 return this.root.search(query);
5015
5016 }
5017
5018 RadixTree.prototype.add = function(declName, value) {
5019 if (this.root == null) {
5020 this.root = new Node(declName.toLowerCase(), null, [value]);
5021 } else {
5022 this.root.add(declName.toLowerCase(), value);
5023 }
5024
5025 const not_scream_case = declName.toUpperCase() != declName;
5026 let found_separator = false;
5027 for (let i = 1; i < declName.length; i += 1) {
5028 if (declName[i] == '_' || declName[i] == '.') {
5029 found_separator = true;
5030 continue;
5031 }
5032
5033
5034 if (found_separator || (declName[i].toLowerCase() !== declName[i])) {
5035 if (declName.length > i + 1
5036 && declName[i + 1].toLowerCase() != declName[i + 1]) continue;
5037 let suffix = declName.slice(i);
5038 this.root.add(suffix.toLowerCase(), value);
5039 found_separator = false;
5040 }
5041 }
5042 }
5043
5044 function Node(labels, next, values) {
5045 this.labels = labels;
5046 this.next = next;
5047 this.values = values;
5048 }
5049
5050 Node.prototype.isCompressed = function() {
5051 return !Array.isArray(this.next);
5052 }
5053
5054 Node.prototype.search = function(word) {
5055 let full_matches = [];
5056 let partial_matches = [];
5057 let subtree_root = null;
5058
5059 let cn = this;
5060 char_loop: for (let i = 0; i < word.length;) {
5061 if (cn.isCompressed()) {
5062 for (let j = 0; j < cn.labels.length; j += 1) {
5063 let current_idx = i + j;
5064
5065 if (current_idx == word.length) {
5066 partial_matches = cn.values;
5067 subtree_root = cn.next;
5068 break char_loop;
5069 }
5070
5071 if (word[current_idx] != cn.labels[j]) return null;
5072 }
5073
5074 // the full label matched
5075 let new_idx = i + cn.labels.length;
5076 if (new_idx == word.length) {
5077 full_matches = cn.values;
5078 subtree_root = cn.next;
5079 break char_loop;
5080 }
5081
5082
5083 i = new_idx;
5084 cn = cn.next;
5085 continue;
5086 } else {
5087 for (let j = 0; j < cn.labels.length; j += 1) {
5088 if (word[i] == cn.labels[j]) {
5089 if (i == word.length - 1) {
5090 full_matches = cn.values[j];
5091 subtree_root = cn.next[j];
5092 break char_loop;
5093 }
5094
5095 let next = cn.next[j];
5096 if (next == null) return null;
5097 cn = next;
5098 i += 1;
5099 continue char_loop;
5100 }
5101 }
5102
5103 // didn't find a match
5104 return null;
5105 }
5106 }
5107
5108 // Match was found, let's collect all other
5109 // partial matches from the subtree
5110 let stack = [subtree_root];
5111 let node;
5112 while (node = stack.pop()) {
5113 if (node.isCompressed()) {
5114 partial_matches = partial_matches.concat(node.values);
5115 if (node.next != null) {
5116 stack.push(node.next);
5117 }
5118 } else {
5119 for (let v of node.values) {
5120 partial_matches = partial_matches.concat(v);
5121 }
5122
5123 for (let n of node.next) {
5124 if (n != null) stack.push(n);
5125 }
5126 }
5127 }
5128
5129 return { full: full_matches, partial: partial_matches };
5130 }
5131
5132 Node.prototype.add = function(word, value) {
5133 let cn = this;
5134 char_loop: for (let i = 0; i < word.length;) {
5135 if (cn.isCompressed()) {
5136 for (let j = 0; j < cn.labels.length; j += 1) {
5137 let current_idx = i + j;
5138
5139 if (current_idx == word.length) {
5140 if (j < cn.labels.length - 1) {
5141 let node = new Node(cn.labels.slice(j), cn.next, cn.values);
5142 cn.labels = cn.labels.slice(0, j);
5143 cn.next = node;
5144 cn.values = [];
5145 }
5146 cn.values.push(value);
5147 return;
5148 }
5149
5150 if (word[current_idx] == cn.labels[j]) continue;
5151
5152 // if we're here, a mismatch was found
5153 if (j != cn.labels.length - 1) {
5154 // create a suffix node
5155 const label_suffix = cn.labels.slice(j + 1);
5156 let node = new Node(label_suffix, cn.next, [...cn.values]);
5157 cn.next = node;
5158 cn.values = [];
5159 }
5160
5161 // turn current node into a split node
5162 let node = null;
5163 let word_values = [];
5164 if (current_idx == word.length - 1) {
5165 // mismatch happened in the last character of word
5166 // meaning that the current node should hold its value
5167 word_values.push(value);
5168 } else {
5169 node = new Node(word.slice(current_idx + 1), null, [value]);
5170 }
5171
5172 cn.labels = cn.labels[j] + word[current_idx];
5173 cn.next = [cn.next, node];
5174 cn.values = [cn.values, word_values];
5175
5176 if (j != 0) {
5177 // current node must be turned into a prefix node
5178 let splitNode = new Node(cn.labels, cn.next, cn.values);
5179 cn.labels = word.slice(i, current_idx);
5180 cn.next = splitNode;
5181 cn.values = [];
5182 }
5183
5184 return;
5185 }
5186 // label matched fully with word, are there any more chars?
5187 const new_idx = i + cn.labels.length;
5188 if (new_idx == word.length) {
5189 cn.values.push(value);
5190 return;
5191 } else {
5192 if (cn.next == null) {
5193 let node = new Node(word.slice(new_idx), null, [value]);
5194 cn.next = node;
5195 return;
5196 } else {
5197 cn = cn.next;
5198 i = new_idx;
5199 continue;
5200 }
5201 }
5202 } else { // node is not compressed
5203 let letter = word[i];
5204 for (let j = 0; j < cn.labels.length; j += 1) {
5205 if (letter == cn.labels[j]) {
5206 if (i == word.length - 1) {
5207 cn.values[j].push(value);
5208 return;
5209 }
5210 if (cn.next[j] == null) {
5211 let node = new Node(word.slice(i + 1), null, [value]);
5212 cn.next[j] = node;
5213 return;
5214 } else {
5215 cn = cn.next[j];
5216 i += 1;
5217 continue char_loop;
5218 }
5219 }
5220 }
5221
5222 // if we're here we didn't find a match
5223 cn.labels += letter;
5224 if (i == word.length - 1) {
5225 cn.next.push(null);
5226 cn.values.push([value]);
5227 } else {
5228 let node = new Node(word.slice(i + 1), null, [value]);
5229 cn.next.push(node);
5230 cn.values.push([]);
5231 }
5232 return;
5233 }
5234 }
5235 }
5236}
5237
5238
5239function slugify(str) {
5240 return str.toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/[\s_-]+/g, '-').replace(/^-+|-+$/g, '');
5241}
5242
lib/docs/wasm/Decl.zig created+226
......@@ -0,0 +1,226 @@
1ast_node: Ast.Node.Index,
2file: Walk.File.Index,
3/// The decl whose namespace this is in.
4parent: Index,
5
6pub const ExtraInfo = struct {
7 is_pub: bool,
8 name: []const u8,
9 /// This might not be a doc_comment token in which case there are no doc comments.
10 first_doc_comment: Ast.TokenIndex,
11};
12
13pub const Index = enum(u32) {
14 none = std.math.maxInt(u32),
15 _,
16
17 pub fn get(i: Index) *Decl {
18 return &Walk.decls.items[@intFromEnum(i)];
19 }
20};
21
22pub fn is_pub(d: *const Decl) bool {
23 return d.extra_info().is_pub;
24}
25
26pub fn extra_info(d: *const Decl) ExtraInfo {
27 const ast = d.file.get_ast();
28 const token_tags = ast.tokens.items(.tag);
29 const node_tags = ast.nodes.items(.tag);
30 switch (node_tags[d.ast_node]) {
31 .root => return .{
32 .name = "",
33 .is_pub = true,
34 .first_doc_comment = if (token_tags[0] == .container_doc_comment)
35 0
36 else
37 token_tags.len - 1,
38 },
39
40 .global_var_decl,
41 .local_var_decl,
42 .simple_var_decl,
43 .aligned_var_decl,
44 => {
45 const var_decl = ast.fullVarDecl(d.ast_node).?;
46 const name_token = var_decl.ast.mut_token + 1;
47 assert(token_tags[name_token] == .identifier);
48 const ident_name = ast.tokenSlice(name_token);
49 return .{
50 .name = ident_name,
51 .is_pub = var_decl.visib_token != null,
52 .first_doc_comment = findFirstDocComment(ast, var_decl.firstToken()),
53 };
54 },
55
56 .fn_proto,
57 .fn_proto_multi,
58 .fn_proto_one,
59 .fn_proto_simple,
60 .fn_decl,
61 => {
62 var buf: [1]Ast.Node.Index = undefined;
63 const fn_proto = ast.fullFnProto(&buf, d.ast_node).?;
64 const name_token = fn_proto.name_token.?;
65 assert(token_tags[name_token] == .identifier);
66 const ident_name = ast.tokenSlice(name_token);
67 return .{
68 .name = ident_name,
69 .is_pub = fn_proto.visib_token != null,
70 .first_doc_comment = findFirstDocComment(ast, fn_proto.firstToken()),
71 };
72 },
73
74 else => |t| {
75 log.debug("hit '{s}'", .{@tagName(t)});
76 unreachable;
77 },
78 }
79}
80
81pub fn value_node(d: *const Decl) ?Ast.Node.Index {
82 const ast = d.file.get_ast();
83 const node_tags = ast.nodes.items(.tag);
84 const token_tags = ast.tokens.items(.tag);
85 return switch (node_tags[d.ast_node]) {
86 .fn_proto,
87 .fn_proto_multi,
88 .fn_proto_one,
89 .fn_proto_simple,
90 .fn_decl,
91 .root,
92 => d.ast_node,
93
94 .global_var_decl,
95 .local_var_decl,
96 .simple_var_decl,
97 .aligned_var_decl,
98 => {
99 const var_decl = ast.fullVarDecl(d.ast_node).?;
100 if (token_tags[var_decl.ast.mut_token] == .keyword_const)
101 return var_decl.ast.init_node;
102
103 return null;
104 },
105
106 else => null,
107 };
108}
109
110pub fn categorize(decl: *const Decl) Walk.Category {
111 return decl.file.categorize_decl(decl.ast_node);
112}
113
114/// Looks up a direct child of `decl` by name.
115pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {
116 switch (decl.categorize()) {
117 .alias => |aliasee| return aliasee.get().get_child(name),
118 .namespace => |node| {
119 const file = decl.file.get();
120 const scope = file.scopes.get(node) orelse return null;
121 const child_node = scope.get_child(name) orelse return null;
122 return file.node_decls.get(child_node);
123 },
124 else => return null,
125 }
126}
127
128/// Looks up a decl by name accessible in `decl`'s namespace.
129pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index {
130 const namespace_node = switch (decl.categorize()) {
131 .namespace => |node| node,
132 else => decl.parent.get().ast_node,
133 };
134 const file = decl.file.get();
135 const scope = file.scopes.get(namespace_node) orelse return null;
136 const resolved_node = scope.lookup(&file.ast, name) orelse return null;
137 return file.node_decls.get(resolved_node);
138}
139
140/// Appends the fully qualified name to `out`.
141pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {
142 try decl.append_path(out);
143 if (decl.parent != .none) {
144 try append_parent_ns(out, decl.parent);
145 try out.appendSlice(gpa, decl.extra_info().name);
146 } else {
147 out.items.len -= 1; // remove the trailing '.'
148 }
149}
150
151pub fn reset_with_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void {
152 list.clearRetainingCapacity();
153 try append_path(decl, list);
154}
155
156pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void {
157 const start = list.items.len;
158 // Prefer the module name alias.
159 for (Walk.modules.keys(), Walk.modules.values()) |pkg_name, pkg_file| {
160 if (pkg_file == decl.file) {
161 try list.ensureUnusedCapacity(gpa, pkg_name.len + 1);
162 list.appendSliceAssumeCapacity(pkg_name);
163 list.appendAssumeCapacity('.');
164 return;
165 }
166 }
167
168 const file_path = decl.file.path();
169 try list.ensureUnusedCapacity(gpa, file_path.len + 1);
170 list.appendSliceAssumeCapacity(file_path);
171 for (list.items[start..]) |*byte| switch (byte.*) {
172 '/' => byte.* = '.',
173 else => continue,
174 };
175 if (std.mem.endsWith(u8, list.items, ".zig")) {
176 list.items.len -= 3;
177 } else {
178 list.appendAssumeCapacity('.');
179 }
180}
181
182pub fn append_parent_ns(list: *std.ArrayListUnmanaged(u8), parent: Decl.Index) Oom!void {
183 assert(parent != .none);
184 const decl = parent.get();
185 if (decl.parent != .none) {
186 try append_parent_ns(list, decl.parent);
187 try list.appendSlice(gpa, decl.extra_info().name);
188 try list.append(gpa, '.');
189 }
190}
191
192pub fn findFirstDocComment(ast: *const Ast, token: Ast.TokenIndex) Ast.TokenIndex {
193 const token_tags = ast.tokens.items(.tag);
194 var it = token;
195 while (it > 0) {
196 it -= 1;
197 if (token_tags[it] != .doc_comment) {
198 return it + 1;
199 }
200 }
201 return it;
202}
203
204/// Successively looks up each component.
205pub fn find(search_string: []const u8) Decl.Index {
206 var path_components = std.mem.splitScalar(u8, search_string, '.');
207 const file = Walk.modules.get(path_components.first()) orelse return .none;
208 var current_decl_index = file.findRootDecl();
209 while (path_components.next()) |component| {
210 while (true) switch (current_decl_index.get().categorize()) {
211 .alias => |aliasee| current_decl_index = aliasee,
212 else => break,
213 };
214 current_decl_index = current_decl_index.get().get_child(component) orelse return .none;
215 }
216 return current_decl_index;
217}
218
219const Decl = @This();
220const std = @import("std");
221const Ast = std.zig.Ast;
222const Walk = @import("Walk.zig");
223const gpa = std.heap.wasm_allocator;
224const assert = std.debug.assert;
225const log = std.log;
226const Oom = error{OutOfMemory};
lib/docs/wasm/Walk.zig created+1122
......@@ -0,0 +1,1122 @@
1//! Find and annotate identifiers with links to their declarations.
2pub var files: std.StringArrayHashMapUnmanaged(File) = .{};
3pub var decls: std.ArrayListUnmanaged(Decl) = .{};
4pub var modules: std.StringArrayHashMapUnmanaged(File.Index) = .{};
5
6file: File.Index,
7
8/// keep in sync with "CAT_" constants in main.js
9pub const Category = union(enum(u8)) {
10 namespace: Ast.Node.Index,
11 global_variable: Ast.Node.Index,
12 /// A function that has not been detected as returning a type.
13 function: Ast.Node.Index,
14 primitive: Ast.Node.Index,
15 error_set: Ast.Node.Index,
16 global_const: Ast.Node.Index,
17 alias: Decl.Index,
18 /// A primitive identifier that is also a type.
19 type,
20 /// Specifically it is the literal `type`.
21 type_type,
22 /// A function that returns a type.
23 type_function: Ast.Node.Index,
24
25 pub const Tag = @typeInfo(Category).Union.tag_type.?;
26};
27
28pub const File = struct {
29 ast: Ast,
30 /// Maps identifiers to the declarations they point to.
31 ident_decls: std.AutoArrayHashMapUnmanaged(Ast.TokenIndex, Ast.Node.Index) = .{},
32 /// Maps field access identifiers to the containing field access node.
33 token_parents: std.AutoArrayHashMapUnmanaged(Ast.TokenIndex, Ast.Node.Index) = .{},
34 /// Maps declarations to their global index.
35 node_decls: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, Decl.Index) = .{},
36 /// Maps function declarations to doctests.
37 doctests: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, Ast.Node.Index) = .{},
38 /// root node => its namespace scope
39 /// struct/union/enum/opaque decl node => its namespace scope
40 /// local var decl node => its local variable scope
41 scopes: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, *Scope) = .{},
42
43 pub fn lookup_token(file: *File, token: Ast.TokenIndex) Decl.Index {
44 const decl_node = file.ident_decls.get(token) orelse return .none;
45 return file.node_decls.get(decl_node) orelse return .none;
46 }
47
48 pub fn field_count(file: *const File, node: Ast.Node.Index) u32 {
49 const scope = file.scopes.get(node) orelse return 0;
50 if (scope.tag != .namespace) return 0;
51 const namespace = @fieldParentPtr(Scope.Namespace, "base", scope);
52 return namespace.field_count;
53 }
54
55 pub const Index = enum(u32) {
56 _,
57
58 fn add_decl(i: Index, node: Ast.Node.Index, parent_decl: Decl.Index) Oom!Decl.Index {
59 try decls.append(gpa, .{
60 .ast_node = node,
61 .file = i,
62 .parent = parent_decl,
63 });
64 const decl_index: Decl.Index = @enumFromInt(decls.items.len - 1);
65 try i.get().node_decls.put(gpa, node, decl_index);
66 return decl_index;
67 }
68
69 pub fn get(i: File.Index) *File {
70 return &files.values()[@intFromEnum(i)];
71 }
72
73 pub fn get_ast(i: File.Index) *Ast {
74 return &i.get().ast;
75 }
76
77 pub fn path(i: File.Index) []const u8 {
78 return files.keys()[@intFromEnum(i)];
79 }
80
81 pub fn findRootDecl(file_index: File.Index) Decl.Index {
82 return file_index.get().node_decls.values()[0];
83 }
84
85 pub fn categorize_decl(file_index: File.Index, node: Ast.Node.Index) Category {
86 const ast = file_index.get_ast();
87 const node_tags = ast.nodes.items(.tag);
88 const token_tags = ast.tokens.items(.tag);
89 switch (node_tags[node]) {
90 .root => return .{ .namespace = node },
91
92 .global_var_decl,
93 .local_var_decl,
94 .simple_var_decl,
95 .aligned_var_decl,
96 => {
97 const var_decl = ast.fullVarDecl(node).?;
98 if (token_tags[var_decl.ast.mut_token] == .keyword_var)
99 return .{ .global_variable = node };
100
101 return categorize_expr(file_index, var_decl.ast.init_node);
102 },
103
104 .fn_proto,
105 .fn_proto_multi,
106 .fn_proto_one,
107 .fn_proto_simple,
108 .fn_decl,
109 => {
110 var buf: [1]Ast.Node.Index = undefined;
111 const full = ast.fullFnProto(&buf, node).?;
112 return categorize_func(file_index, node, full);
113 },
114
115 else => unreachable,
116 }
117 }
118
119 pub fn categorize_func(
120 file_index: File.Index,
121 node: Ast.Node.Index,
122 full: Ast.full.FnProto,
123 ) Category {
124 return switch (categorize_expr(file_index, full.ast.return_type)) {
125 .namespace, .error_set, .type_type => .{ .type_function = node },
126 else => .{ .function = node },
127 };
128 }
129
130 pub fn categorize_expr_deep(file_index: File.Index, node: Ast.Node.Index) Category {
131 return switch (categorize_expr(file_index, node)) {
132 .alias => |aliasee| aliasee.get().categorize(),
133 else => |result| result,
134 };
135 }
136
137 pub fn categorize_expr(file_index: File.Index, node: Ast.Node.Index) Category {
138 const file = file_index.get();
139 const ast = file_index.get_ast();
140 const node_tags = ast.nodes.items(.tag);
141 const node_datas = ast.nodes.items(.data);
142 const main_tokens = ast.nodes.items(.main_token);
143 //log.debug("categorize_expr tag {s}", .{@tagName(node_tags[node])});
144 return switch (node_tags[node]) {
145 .container_decl,
146 .container_decl_trailing,
147 .container_decl_arg,
148 .container_decl_arg_trailing,
149 .container_decl_two,
150 .container_decl_two_trailing,
151 .tagged_union,
152 .tagged_union_trailing,
153 .tagged_union_enum_tag,
154 .tagged_union_enum_tag_trailing,
155 .tagged_union_two,
156 .tagged_union_two_trailing,
157 => .{ .namespace = node },
158
159 .error_set_decl,
160 .merge_error_sets,
161 => .{ .error_set = node },
162
163 .identifier => {
164 const name_token = ast.nodes.items(.main_token)[node];
165 const ident_name = ast.tokenSlice(name_token);
166 if (std.mem.eql(u8, ident_name, "type"))
167 return .type_type;
168
169 if (isPrimitiveNonType(ident_name))
170 return .{ .primitive = node };
171
172 if (std.zig.primitives.isPrimitive(ident_name))
173 return .type;
174
175 if (file.ident_decls.get(name_token)) |decl_node| {
176 const decl_index = file.node_decls.get(decl_node) orelse .none;
177 if (decl_index != .none) return .{ .alias = decl_index };
178 return categorize_decl(file_index, decl_node);
179 }
180
181 return .{ .global_const = node };
182 },
183
184 .field_access => {
185 const object_node = node_datas[node].lhs;
186 const dot_token = main_tokens[node];
187 const field_ident = dot_token + 1;
188 const field_name = ast.tokenSlice(field_ident);
189
190 switch (categorize_expr(file_index, object_node)) {
191 .alias => |aliasee| if (aliasee.get().get_child(field_name)) |decl_index| {
192 return .{ .alias = decl_index };
193 },
194 else => {},
195 }
196
197 return .{ .global_const = node };
198 },
199
200 .builtin_call_two, .builtin_call_two_comma => {
201 if (node_datas[node].lhs == 0) {
202 const params = [_]Ast.Node.Index{};
203 return categorize_builtin_call(file_index, node, &params);
204 } else if (node_datas[node].rhs == 0) {
205 const params = [_]Ast.Node.Index{node_datas[node].lhs};
206 return categorize_builtin_call(file_index, node, &params);
207 } else {
208 const params = [_]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
209 return categorize_builtin_call(file_index, node, &params);
210 }
211 },
212 .builtin_call, .builtin_call_comma => {
213 const params = ast.extra_data[node_datas[node].lhs..node_datas[node].rhs];
214 return categorize_builtin_call(file_index, node, params);
215 },
216
217 .call_one,
218 .call_one_comma,
219 .async_call_one,
220 .async_call_one_comma,
221 .call,
222 .call_comma,
223 .async_call,
224 .async_call_comma,
225 => {
226 var buf: [1]Ast.Node.Index = undefined;
227 return categorize_call(file_index, node, ast.fullCall(&buf, node).?);
228 },
229
230 .if_simple,
231 .@"if",
232 => {
233 const if_full = ast.fullIf(node).?;
234 if (if_full.ast.else_expr != 0) {
235 const then_cat = categorize_expr_deep(file_index, if_full.ast.then_expr);
236 const else_cat = categorize_expr_deep(file_index, if_full.ast.else_expr);
237 if (then_cat == .type_type and else_cat == .type_type) {
238 return .type_type;
239 } else if (then_cat == .error_set and else_cat == .error_set) {
240 return .{ .error_set = node };
241 } else if (then_cat == .type or else_cat == .type or
242 then_cat == .namespace or else_cat == .namespace or
243 then_cat == .error_set or else_cat == .error_set or
244 then_cat == .type_function or else_cat == .type_function)
245 {
246 return .type;
247 }
248 }
249 return .{ .global_const = node };
250 },
251
252 .@"switch", .switch_comma => return categorize_switch(file_index, node),
253
254 .optional_type,
255 .array_type,
256 .array_type_sentinel,
257 .ptr_type_aligned,
258 .ptr_type_sentinel,
259 .ptr_type,
260 .ptr_type_bit_range,
261 .anyframe_type,
262 => .type,
263
264 else => .{ .global_const = node },
265 };
266 }
267
268 fn categorize_call(
269 file_index: File.Index,
270 node: Ast.Node.Index,
271 call: Ast.full.Call,
272 ) Category {
273 return switch (categorize_expr(file_index, call.ast.fn_expr)) {
274 .type_function => .type,
275 .alias => |aliasee| categorize_decl_as_callee(aliasee, node),
276 else => .{ .global_const = node },
277 };
278 }
279
280 fn categorize_decl_as_callee(decl_index: Decl.Index, call_node: Ast.Node.Index) Category {
281 return switch (decl_index.get().categorize()) {
282 .type_function => .type,
283 .alias => |aliasee| categorize_decl_as_callee(aliasee, call_node),
284 else => .{ .global_const = call_node },
285 };
286 }
287
288 fn categorize_builtin_call(
289 file_index: File.Index,
290 node: Ast.Node.Index,
291 params: []const Ast.Node.Index,
292 ) Category {
293 const ast = file_index.get_ast();
294 const main_tokens = ast.nodes.items(.main_token);
295 const builtin_token = main_tokens[node];
296 const builtin_name = ast.tokenSlice(builtin_token);
297 if (std.mem.eql(u8, builtin_name, "@import")) {
298 const str_lit_token = main_tokens[params[0]];
299 const str_bytes = ast.tokenSlice(str_lit_token);
300 const file_path = std.zig.string_literal.parseAlloc(gpa, str_bytes) catch @panic("OOM");
301 defer gpa.free(file_path);
302 if (modules.get(file_path)) |imported_file_index| {
303 return .{ .alias = File.Index.findRootDecl(imported_file_index) };
304 }
305 const base_path = file_index.path();
306 const resolved_path = std.fs.path.resolvePosix(gpa, &.{
307 base_path, "..", file_path,
308 }) catch @panic("OOM");
309 defer gpa.free(resolved_path);
310 log.debug("from '{s}' @import '{s}' resolved='{s}'", .{
311 base_path, file_path, resolved_path,
312 });
313 if (files.getIndex(resolved_path)) |imported_file_index| {
314 return .{ .alias = File.Index.findRootDecl(@enumFromInt(imported_file_index)) };
315 } else {
316 log.warn("import target '{s}' did not resolve to any file", .{resolved_path});
317 }
318 } else if (std.mem.eql(u8, builtin_name, "@This")) {
319 if (file_index.get().node_decls.get(node)) |decl_index| {
320 return .{ .alias = decl_index };
321 } else {
322 log.warn("@This() is missing link to Decl.Index", .{});
323 }
324 }
325
326 return .{ .global_const = node };
327 }
328
329 fn categorize_switch(file_index: File.Index, node: Ast.Node.Index) Category {
330 const ast = file_index.get_ast();
331 const node_datas = ast.nodes.items(.data);
332 const extra = ast.extraData(node_datas[node].rhs, Ast.Node.SubRange);
333 const case_nodes = ast.extra_data[extra.start..extra.end];
334 var all_type_type = true;
335 var all_error_set = true;
336 var any_type = false;
337 if (case_nodes.len == 0) return .{ .global_const = node };
338 for (case_nodes) |case_node| {
339 const case = ast.fullSwitchCase(case_node).?;
340 switch (categorize_expr_deep(file_index, case.ast.target_expr)) {
341 .type_type => {
342 any_type = true;
343 all_error_set = false;
344 },
345 .error_set => {
346 any_type = true;
347 all_type_type = false;
348 },
349 .type, .namespace, .type_function => {
350 any_type = true;
351 all_error_set = false;
352 all_type_type = false;
353 },
354 else => {
355 all_error_set = false;
356 all_type_type = false;
357 },
358 }
359 }
360 if (all_type_type) return .type_type;
361 if (all_error_set) return .{ .error_set = node };
362 if (any_type) return .type;
363 return .{ .global_const = node };
364 }
365 };
366};
367
368pub const ModuleIndex = enum(u32) {
369 _,
370};
371
372pub fn add_file(file_name: []const u8, bytes: []u8) !File.Index {
373 const ast = try parse(bytes);
374 const file_index: File.Index = @enumFromInt(files.entries.len);
375 try files.put(gpa, file_name, .{ .ast = ast });
376
377 if (ast.errors.len > 0) {
378 log.err("can't index '{s}' because it has syntax errors", .{file_index.path()});
379 return file_index;
380 }
381
382 var w: Walk = .{
383 .file = file_index,
384 };
385 const scope = try gpa.create(Scope);
386 scope.* = .{ .tag = .top };
387
388 const decl_index = try file_index.add_decl(0, .none);
389 try struct_decl(&w, scope, decl_index, 0, ast.containerDeclRoot());
390
391 const file = file_index.get();
392 shrinkToFit(&file.ident_decls);
393 shrinkToFit(&file.token_parents);
394 shrinkToFit(&file.node_decls);
395 shrinkToFit(&file.doctests);
396 shrinkToFit(&file.scopes);
397
398 return file_index;
399}
400
401fn parse(source: []u8) Oom!Ast {
402 // Require every source file to end with a newline so that Zig's tokenizer
403 // can continue to require null termination and Autodoc implementation can
404 // avoid copying source bytes from the decompressed tar file buffer.
405 const adjusted_source: [:0]const u8 = s: {
406 if (source.len == 0)
407 break :s "";
408
409 assert(source[source.len - 1] == '\n');
410 source[source.len - 1] = 0;
411 break :s source[0 .. source.len - 1 :0];
412 };
413
414 return Ast.parse(gpa, adjusted_source, .zig);
415}
416
417pub const Scope = struct {
418 tag: Tag,
419
420 const Tag = enum { top, local, namespace };
421
422 const Local = struct {
423 base: Scope = .{ .tag = .local },
424 parent: *Scope,
425 var_node: Ast.Node.Index,
426 };
427
428 const Namespace = struct {
429 base: Scope = .{ .tag = .namespace },
430 parent: *Scope,
431 names: std.StringArrayHashMapUnmanaged(Ast.Node.Index) = .{},
432 doctests: std.StringArrayHashMapUnmanaged(Ast.Node.Index) = .{},
433 decl_index: Decl.Index,
434 field_count: u32,
435 };
436
437 fn getNamespaceDecl(start_scope: *Scope) Decl.Index {
438 var it: *Scope = start_scope;
439 while (true) switch (it.tag) {
440 .top => unreachable,
441 .local => {
442 const local = @fieldParentPtr(Local, "base", it);
443 it = local.parent;
444 },
445 .namespace => {
446 const namespace = @fieldParentPtr(Namespace, "base", it);
447 return namespace.decl_index;
448 },
449 };
450 }
451
452 pub fn get_child(scope: *Scope, name: []const u8) ?Ast.Node.Index {
453 switch (scope.tag) {
454 .top, .local => return null,
455 .namespace => {
456 const namespace = @fieldParentPtr(Namespace, "base", scope);
457 return namespace.names.get(name);
458 },
459 }
460 }
461
462 pub fn lookup(start_scope: *Scope, ast: *const Ast, name: []const u8) ?Ast.Node.Index {
463 const main_tokens = ast.nodes.items(.main_token);
464 var it: *Scope = start_scope;
465 while (true) switch (it.tag) {
466 .top => break,
467 .local => {
468 const local = @fieldParentPtr(Local, "base", it);
469 const name_token = main_tokens[local.var_node] + 1;
470 const ident_name = ast.tokenSlice(name_token);
471 if (std.mem.eql(u8, ident_name, name)) {
472 return local.var_node;
473 }
474 it = local.parent;
475 },
476 .namespace => {
477 const namespace = @fieldParentPtr(Namespace, "base", it);
478 if (namespace.names.get(name)) |node| {
479 return node;
480 }
481 it = namespace.parent;
482 },
483 };
484 return null;
485 }
486};
487
488fn struct_decl(
489 w: *Walk,
490 scope: *Scope,
491 parent_decl: Decl.Index,
492 node: Ast.Node.Index,
493 container_decl: Ast.full.ContainerDecl,
494) Oom!void {
495 const ast = w.file.get_ast();
496 const node_tags = ast.nodes.items(.tag);
497 const node_datas = ast.nodes.items(.data);
498
499 const namespace = try gpa.create(Scope.Namespace);
500 namespace.* = .{
501 .parent = scope,
502 .decl_index = parent_decl,
503 .field_count = 0,
504 };
505 try w.file.get().scopes.putNoClobber(gpa, node, &namespace.base);
506 try w.scanDecls(namespace, container_decl.ast.members);
507
508 for (container_decl.ast.members) |member| switch (node_tags[member]) {
509 .container_field_init,
510 .container_field_align,
511 .container_field,
512 => try w.container_field(&namespace.base, parent_decl, ast.fullContainerField(member).?),
513
514 .fn_proto,
515 .fn_proto_multi,
516 .fn_proto_one,
517 .fn_proto_simple,
518 .fn_decl,
519 => {
520 var buf: [1]Ast.Node.Index = undefined;
521 const full = ast.fullFnProto(&buf, member).?;
522 const fn_name_token = full.ast.fn_token + 1;
523 const fn_name = ast.tokenSlice(fn_name_token);
524 if (namespace.doctests.get(fn_name)) |doctest_node| {
525 try w.file.get().doctests.put(gpa, member, doctest_node);
526 }
527 const decl_index = try w.file.add_decl(member, parent_decl);
528 const body = if (node_tags[member] == .fn_decl) node_datas[member].rhs else 0;
529 try w.fn_decl(&namespace.base, decl_index, body, full);
530 },
531
532 .global_var_decl,
533 .local_var_decl,
534 .simple_var_decl,
535 .aligned_var_decl,
536 => {
537 const decl_index = try w.file.add_decl(member, parent_decl);
538 try w.global_var_decl(&namespace.base, decl_index, ast.fullVarDecl(member).?);
539 },
540
541 .@"comptime",
542 .@"usingnamespace",
543 => try w.expr(&namespace.base, parent_decl, node_datas[member].lhs),
544
545 .test_decl => try w.expr(&namespace.base, parent_decl, node_datas[member].rhs),
546
547 else => unreachable,
548 };
549}
550
551fn comptime_decl(
552 w: *Walk,
553 scope: *Scope,
554 parent_decl: Decl.Index,
555 full: Ast.full.VarDecl,
556) Oom!void {
557 try w.expr(scope, parent_decl, full.ast.type_node);
558 try w.maybe_expr(scope, parent_decl, full.ast.align_node);
559 try w.maybe_expr(scope, parent_decl, full.ast.addrspace_node);
560 try w.maybe_expr(scope, parent_decl, full.ast.section_node);
561 try w.expr(scope, parent_decl, full.ast.init_node);
562}
563
564fn global_var_decl(
565 w: *Walk,
566 scope: *Scope,
567 parent_decl: Decl.Index,
568 full: Ast.full.VarDecl,
569) Oom!void {
570 try w.maybe_expr(scope, parent_decl, full.ast.type_node);
571 try w.maybe_expr(scope, parent_decl, full.ast.align_node);
572 try w.maybe_expr(scope, parent_decl, full.ast.addrspace_node);
573 try w.maybe_expr(scope, parent_decl, full.ast.section_node);
574 try w.maybe_expr(scope, parent_decl, full.ast.init_node);
575}
576
577fn container_field(
578 w: *Walk,
579 scope: *Scope,
580 parent_decl: Decl.Index,
581 full: Ast.full.ContainerField,
582) Oom!void {
583 try w.maybe_expr(scope, parent_decl, full.ast.type_expr);
584 try w.maybe_expr(scope, parent_decl, full.ast.align_expr);
585 try w.maybe_expr(scope, parent_decl, full.ast.value_expr);
586}
587
588fn fn_decl(
589 w: *Walk,
590 scope: *Scope,
591 parent_decl: Decl.Index,
592 body: Ast.Node.Index,
593 full: Ast.full.FnProto,
594) Oom!void {
595 for (full.ast.params) |param| {
596 try expr(w, scope, parent_decl, param);
597 }
598 try expr(w, scope, parent_decl, full.ast.return_type);
599 try maybe_expr(w, scope, parent_decl, full.ast.align_expr);
600 try maybe_expr(w, scope, parent_decl, full.ast.addrspace_expr);
601 try maybe_expr(w, scope, parent_decl, full.ast.section_expr);
602 try maybe_expr(w, scope, parent_decl, full.ast.callconv_expr);
603 try maybe_expr(w, scope, parent_decl, body);
604}
605
606fn maybe_expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index) Oom!void {
607 if (node != 0) return expr(w, scope, parent_decl, node);
608}
609
610fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index) Oom!void {
611 assert(node != 0);
612 const ast = w.file.get_ast();
613 const node_tags = ast.nodes.items(.tag);
614 const node_datas = ast.nodes.items(.data);
615 const main_tokens = ast.nodes.items(.main_token);
616 switch (node_tags[node]) {
617 .root => unreachable, // Top-level declaration.
618 .@"usingnamespace" => unreachable, // Top-level declaration.
619 .test_decl => unreachable, // Top-level declaration.
620 .container_field_init => unreachable, // Top-level declaration.
621 .container_field_align => unreachable, // Top-level declaration.
622 .container_field => unreachable, // Top-level declaration.
623 .fn_decl => unreachable, // Top-level declaration.
624
625 .global_var_decl => unreachable, // Handled in `block`.
626 .local_var_decl => unreachable, // Handled in `block`.
627 .simple_var_decl => unreachable, // Handled in `block`.
628 .aligned_var_decl => unreachable, // Handled in `block`.
629 .@"defer" => unreachable, // Handled in `block`.
630 .@"errdefer" => unreachable, // Handled in `block`.
631
632 .switch_case => unreachable, // Handled in `switchExpr`.
633 .switch_case_inline => unreachable, // Handled in `switchExpr`.
634 .switch_case_one => unreachable, // Handled in `switchExpr`.
635 .switch_case_inline_one => unreachable, // Handled in `switchExpr`.
636
637 .asm_output => unreachable, // Handled in `asmExpr`.
638 .asm_input => unreachable, // Handled in `asmExpr`.
639
640 .for_range => unreachable, // Handled in `forExpr`.
641
642 .assign,
643 .assign_shl,
644 .assign_shl_sat,
645 .assign_shr,
646 .assign_bit_and,
647 .assign_bit_or,
648 .assign_bit_xor,
649 .assign_div,
650 .assign_sub,
651 .assign_sub_wrap,
652 .assign_sub_sat,
653 .assign_mod,
654 .assign_add,
655 .assign_add_wrap,
656 .assign_add_sat,
657 .assign_mul,
658 .assign_mul_wrap,
659 .assign_mul_sat,
660 .shl,
661 .shr,
662 .add,
663 .add_wrap,
664 .add_sat,
665 .sub,
666 .sub_wrap,
667 .sub_sat,
668 .mul,
669 .mul_wrap,
670 .mul_sat,
671 .div,
672 .mod,
673 .shl_sat,
674
675 .bit_and,
676 .bit_or,
677 .bit_xor,
678 .bang_equal,
679 .equal_equal,
680 .greater_than,
681 .greater_or_equal,
682 .less_than,
683 .less_or_equal,
684 .array_cat,
685
686 .array_mult,
687 .error_union,
688 .merge_error_sets,
689 .bool_and,
690 .bool_or,
691 .@"catch",
692 .@"orelse",
693 .array_type,
694 .array_access,
695 .switch_range,
696 => {
697 try expr(w, scope, parent_decl, node_datas[node].lhs);
698 try expr(w, scope, parent_decl, node_datas[node].rhs);
699 },
700
701 .assign_destructure => {
702 const extra_index = node_datas[node].lhs;
703 const lhs_count = ast.extra_data[extra_index];
704 const lhs_nodes: []const Ast.Node.Index = @ptrCast(ast.extra_data[extra_index + 1 ..][0..lhs_count]);
705 const rhs = node_datas[node].rhs;
706 for (lhs_nodes) |lhs_node| try expr(w, scope, parent_decl, lhs_node);
707 _ = try expr(w, scope, parent_decl, rhs);
708 },
709
710 .bool_not,
711 .bit_not,
712 .negation,
713 .negation_wrap,
714 .@"return",
715 .deref,
716 .address_of,
717 .optional_type,
718 .unwrap_optional,
719 .grouped_expression,
720 .@"comptime",
721 .@"nosuspend",
722 .@"suspend",
723 .@"await",
724 .@"resume",
725 .@"try",
726 => try maybe_expr(w, scope, parent_decl, node_datas[node].lhs),
727
728 .anyframe_type,
729 .@"break",
730 => try maybe_expr(w, scope, parent_decl, node_datas[node].rhs),
731
732 .identifier => {
733 const ident_token = main_tokens[node];
734 const ident_name = ast.tokenSlice(ident_token);
735 if (scope.lookup(ast, ident_name)) |var_node| {
736 try w.file.get().ident_decls.put(gpa, ident_token, var_node);
737 }
738 },
739 .field_access => {
740 const object_node = node_datas[node].lhs;
741 const dot_token = main_tokens[node];
742 const field_ident = dot_token + 1;
743 try w.file.get().token_parents.put(gpa, field_ident, node);
744 // This will populate the left-most field object if it is an
745 // identifier, allowing rendering code to piece together the link.
746 try expr(w, scope, parent_decl, object_node);
747 },
748
749 .string_literal,
750 .multiline_string_literal,
751 .number_literal,
752 .unreachable_literal,
753 .enum_literal,
754 .error_value,
755 .anyframe_literal,
756 .@"continue",
757 .char_literal,
758 .error_set_decl,
759 => {},
760
761 .asm_simple,
762 .@"asm",
763 => {
764 const full = ast.fullAsm(node).?;
765 for (full.ast.items) |n| {
766 // There is a missing call here to expr() for .asm_input and
767 // .asm_output nodes.
768 _ = n;
769 }
770 try expr(w, scope, parent_decl, full.ast.template);
771 },
772
773 .builtin_call_two, .builtin_call_two_comma => {
774 if (node_datas[node].lhs == 0) {
775 const params = [_]Ast.Node.Index{};
776 return builtin_call(w, scope, parent_decl, node, &params);
777 } else if (node_datas[node].rhs == 0) {
778 const params = [_]Ast.Node.Index{node_datas[node].lhs};
779 return builtin_call(w, scope, parent_decl, node, &params);
780 } else {
781 const params = [_]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
782 return builtin_call(w, scope, parent_decl, node, &params);
783 }
784 },
785 .builtin_call, .builtin_call_comma => {
786 const params = ast.extra_data[node_datas[node].lhs..node_datas[node].rhs];
787 return builtin_call(w, scope, parent_decl, node, params);
788 },
789
790 .call_one,
791 .call_one_comma,
792 .async_call_one,
793 .async_call_one_comma,
794 .call,
795 .call_comma,
796 .async_call,
797 .async_call_comma,
798 => {
799 var buf: [1]Ast.Node.Index = undefined;
800 const full = ast.fullCall(&buf, node).?;
801 try expr(w, scope, parent_decl, full.ast.fn_expr);
802 for (full.ast.params) |param| {
803 try expr(w, scope, parent_decl, param);
804 }
805 },
806
807 .if_simple,
808 .@"if",
809 => {
810 const full = ast.fullIf(node).?;
811 try expr(w, scope, parent_decl, full.ast.cond_expr);
812 try expr(w, scope, parent_decl, full.ast.then_expr);
813 try maybe_expr(w, scope, parent_decl, full.ast.else_expr);
814 },
815
816 .while_simple,
817 .while_cont,
818 .@"while",
819 => {
820 try while_expr(w, scope, parent_decl, ast.fullWhile(node).?);
821 },
822
823 .for_simple, .@"for" => {
824 const full = ast.fullFor(node).?;
825 for (full.ast.inputs) |input| {
826 if (node_tags[input] == .for_range) {
827 try expr(w, scope, parent_decl, node_datas[input].lhs);
828 try maybe_expr(w, scope, parent_decl, node_datas[input].rhs);
829 } else {
830 try expr(w, scope, parent_decl, input);
831 }
832 }
833 try expr(w, scope, parent_decl, full.ast.then_expr);
834 try maybe_expr(w, scope, parent_decl, full.ast.else_expr);
835 },
836
837 .slice => return slice(w, scope, parent_decl, ast.slice(node)),
838 .slice_open => return slice(w, scope, parent_decl, ast.sliceOpen(node)),
839 .slice_sentinel => return slice(w, scope, parent_decl, ast.sliceSentinel(node)),
840
841 .block_two, .block_two_semicolon => {
842 const statements = [2]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
843 if (node_datas[node].lhs == 0) {
844 return block(w, scope, parent_decl, statements[0..0]);
845 } else if (node_datas[node].rhs == 0) {
846 return block(w, scope, parent_decl, statements[0..1]);
847 } else {
848 return block(w, scope, parent_decl, statements[0..2]);
849 }
850 },
851 .block, .block_semicolon => {
852 const statements = ast.extra_data[node_datas[node].lhs..node_datas[node].rhs];
853 return block(w, scope, parent_decl, statements);
854 },
855
856 .ptr_type_aligned,
857 .ptr_type_sentinel,
858 .ptr_type,
859 .ptr_type_bit_range,
860 => {
861 const full = ast.fullPtrType(node).?;
862 try maybe_expr(w, scope, parent_decl, full.ast.align_node);
863 try maybe_expr(w, scope, parent_decl, full.ast.addrspace_node);
864 try maybe_expr(w, scope, parent_decl, full.ast.sentinel);
865 try maybe_expr(w, scope, parent_decl, full.ast.bit_range_start);
866 try maybe_expr(w, scope, parent_decl, full.ast.bit_range_end);
867 try expr(w, scope, parent_decl, full.ast.child_type);
868 },
869
870 .container_decl,
871 .container_decl_trailing,
872 .container_decl_arg,
873 .container_decl_arg_trailing,
874 .container_decl_two,
875 .container_decl_two_trailing,
876 .tagged_union,
877 .tagged_union_trailing,
878 .tagged_union_enum_tag,
879 .tagged_union_enum_tag_trailing,
880 .tagged_union_two,
881 .tagged_union_two_trailing,
882 => {
883 var buf: [2]Ast.Node.Index = undefined;
884 return struct_decl(w, scope, parent_decl, node, ast.fullContainerDecl(&buf, node).?);
885 },
886
887 .array_type_sentinel => {
888 const extra = ast.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel);
889 try expr(w, scope, parent_decl, node_datas[node].lhs);
890 try expr(w, scope, parent_decl, extra.elem_type);
891 try expr(w, scope, parent_decl, extra.sentinel);
892 },
893 .@"switch", .switch_comma => {
894 const operand_node = node_datas[node].lhs;
895 try expr(w, scope, parent_decl, operand_node);
896 const extra = ast.extraData(node_datas[node].rhs, Ast.Node.SubRange);
897 const case_nodes = ast.extra_data[extra.start..extra.end];
898 for (case_nodes) |case_node| {
899 const case = ast.fullSwitchCase(case_node).?;
900 for (case.ast.values) |value_node| {
901 try expr(w, scope, parent_decl, value_node);
902 }
903 try expr(w, scope, parent_decl, case.ast.target_expr);
904 }
905 },
906
907 .array_init_one,
908 .array_init_one_comma,
909 .array_init_dot_two,
910 .array_init_dot_two_comma,
911 .array_init_dot,
912 .array_init_dot_comma,
913 .array_init,
914 .array_init_comma,
915 => {
916 var buf: [2]Ast.Node.Index = undefined;
917 const full = ast.fullArrayInit(&buf, node).?;
918 try maybe_expr(w, scope, parent_decl, full.ast.type_expr);
919 for (full.ast.elements) |elem| {
920 try expr(w, scope, parent_decl, elem);
921 }
922 },
923
924 .struct_init_one,
925 .struct_init_one_comma,
926 .struct_init_dot_two,
927 .struct_init_dot_two_comma,
928 .struct_init_dot,
929 .struct_init_dot_comma,
930 .struct_init,
931 .struct_init_comma,
932 => {
933 var buf: [2]Ast.Node.Index = undefined;
934 const full = ast.fullStructInit(&buf, node).?;
935 try maybe_expr(w, scope, parent_decl, full.ast.type_expr);
936 for (full.ast.fields) |field| {
937 try expr(w, scope, parent_decl, field);
938 }
939 },
940
941 .fn_proto_simple,
942 .fn_proto_multi,
943 .fn_proto_one,
944 .fn_proto,
945 => {
946 var buf: [1]Ast.Node.Index = undefined;
947 return fn_decl(w, scope, parent_decl, 0, ast.fullFnProto(&buf, node).?);
948 },
949 }
950}
951
952fn slice(w: *Walk, scope: *Scope, parent_decl: Decl.Index, full: Ast.full.Slice) Oom!void {
953 try expr(w, scope, parent_decl, full.ast.sliced);
954 try expr(w, scope, parent_decl, full.ast.start);
955 try maybe_expr(w, scope, parent_decl, full.ast.end);
956 try maybe_expr(w, scope, parent_decl, full.ast.sentinel);
957}
958
959fn builtin_call(
960 w: *Walk,
961 scope: *Scope,
962 parent_decl: Decl.Index,
963 node: Ast.Node.Index,
964 params: []const Ast.Node.Index,
965) Oom!void {
966 const ast = w.file.get_ast();
967 const main_tokens = ast.nodes.items(.main_token);
968 const builtin_token = main_tokens[node];
969 const builtin_name = ast.tokenSlice(builtin_token);
970 if (std.mem.eql(u8, builtin_name, "@This")) {
971 try w.file.get().node_decls.put(gpa, node, scope.getNamespaceDecl());
972 }
973
974 for (params) |param| {
975 try expr(w, scope, parent_decl, param);
976 }
977}
978
979fn block(
980 w: *Walk,
981 parent_scope: *Scope,
982 parent_decl: Decl.Index,
983 statements: []const Ast.Node.Index,
984) Oom!void {
985 const ast = w.file.get_ast();
986 const node_tags = ast.nodes.items(.tag);
987 const node_datas = ast.nodes.items(.data);
988
989 var scope = parent_scope;
990
991 for (statements) |node| {
992 switch (node_tags[node]) {
993 .global_var_decl,
994 .local_var_decl,
995 .simple_var_decl,
996 .aligned_var_decl,
997 => {
998 const full = ast.fullVarDecl(node).?;
999 try global_var_decl(w, scope, parent_decl, full);
1000 const local = try gpa.create(Scope.Local);
1001 local.* = .{
1002 .parent = scope,
1003 .var_node = node,
1004 };
1005 try w.file.get().scopes.putNoClobber(gpa, node, &local.base);
1006 scope = &local.base;
1007 },
1008
1009 .assign_destructure => {
1010 log.debug("walk assign_destructure not implemented yet", .{});
1011 },
1012
1013 .grouped_expression => try expr(w, scope, parent_decl, node_datas[node].lhs),
1014
1015 .@"defer",
1016 .@"errdefer",
1017 => try expr(w, scope, parent_decl, node_datas[node].rhs),
1018
1019 else => try expr(w, scope, parent_decl, node),
1020 }
1021 }
1022}
1023
1024fn while_expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, full: Ast.full.While) Oom!void {
1025 try expr(w, scope, parent_decl, full.ast.cond_expr);
1026 try maybe_expr(w, scope, parent_decl, full.ast.cont_expr);
1027 try expr(w, scope, parent_decl, full.ast.then_expr);
1028 try maybe_expr(w, scope, parent_decl, full.ast.else_expr);
1029}
1030
1031fn scanDecls(w: *Walk, namespace: *Scope.Namespace, members: []const Ast.Node.Index) Oom!void {
1032 const ast = w.file.get_ast();
1033 const node_tags = ast.nodes.items(.tag);
1034 const main_tokens = ast.nodes.items(.main_token);
1035 const token_tags = ast.tokens.items(.tag);
1036 const node_datas = ast.nodes.items(.data);
1037
1038 for (members) |member_node| {
1039 const name_token = switch (node_tags[member_node]) {
1040 .global_var_decl,
1041 .local_var_decl,
1042 .simple_var_decl,
1043 .aligned_var_decl,
1044 => main_tokens[member_node] + 1,
1045
1046 .fn_proto_simple,
1047 .fn_proto_multi,
1048 .fn_proto_one,
1049 .fn_proto,
1050 .fn_decl,
1051 => blk: {
1052 const ident = main_tokens[member_node] + 1;
1053 if (token_tags[ident] != .identifier) continue;
1054 break :blk ident;
1055 },
1056
1057 .test_decl => {
1058 const ident_token = node_datas[member_node].lhs;
1059 const is_doctest = token_tags[ident_token] == .identifier;
1060 if (is_doctest) {
1061 const token_bytes = ast.tokenSlice(ident_token);
1062 try namespace.doctests.put(gpa, token_bytes, member_node);
1063 }
1064 continue;
1065 },
1066
1067 .container_field_init,
1068 .container_field_align,
1069 .container_field,
1070 => {
1071 namespace.field_count += 1;
1072 continue;
1073 },
1074
1075 else => continue,
1076 };
1077
1078 const token_bytes = ast.tokenSlice(name_token);
1079 try namespace.names.put(gpa, token_bytes, member_node);
1080 }
1081}
1082
1083pub fn isPrimitiveNonType(name: []const u8) bool {
1084 return std.mem.eql(u8, name, "undefined") or
1085 std.mem.eql(u8, name, "null") or
1086 std.mem.eql(u8, name, "true") or
1087 std.mem.eql(u8, name, "false");
1088}
1089
1090//test {
1091// const gpa = std.testing.allocator;
1092//
1093// var arena_instance = std.heap.ArenaAllocator.init(gpa);
1094// defer arena_instance.deinit();
1095// const arena = arena_instance.allocator();
1096//
1097// // example test command:
1098// // zig test --dep input.zig -Mroot=src/Walk.zig -Minput.zig=/home/andy/dev/zig/lib/std/fs/File/zig
1099// var ast = try Ast.parse(gpa, @embedFile("input.zig"), .zig);
1100// defer ast.deinit(gpa);
1101//
1102// var w: Walk = .{
1103// .arena = arena,
1104// .token_links = .{},
1105// .ast = &ast,
1106// };
1107//
1108// try w.root();
1109//}
1110
1111const Walk = @This();
1112const std = @import("std");
1113const Ast = std.zig.Ast;
1114const assert = std.debug.assert;
1115const Decl = @import("Decl.zig");
1116const log = std.log;
1117const gpa = std.heap.wasm_allocator;
1118const Oom = error{OutOfMemory};
1119
1120fn shrinkToFit(m: anytype) void {
1121 m.shrinkAndFree(gpa, m.entries.len);
1122}
lib/docs/wasm/main.zig created+1259
......@@ -0,0 +1,1259 @@
1/// Delete this to find out where URL escaping needs to be added.
2const missing_feature_url_escape = true;
3
4const gpa = std.heap.wasm_allocator;
5
6const std = @import("std");
7const log = std.log;
8const assert = std.debug.assert;
9const Ast = std.zig.Ast;
10const Walk = @import("Walk.zig");
11const markdown = @import("markdown.zig");
12const Decl = @import("Decl.zig");
13
14const js = struct {
15 extern "js" fn log(ptr: [*]const u8, len: usize) void;
16 extern "js" fn panic(ptr: [*]const u8, len: usize) noreturn;
17};
18
19pub const std_options: std.Options = .{
20 .logFn = logFn,
21 //.log_level = .debug,
22};
23
24pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn {
25 _ = st;
26 _ = addr;
27 log.err("panic: {s}", .{msg});
28 @trap();
29}
30
31fn logFn(
32 comptime message_level: log.Level,
33 comptime scope: @TypeOf(.enum_literal),
34 comptime format: []const u8,
35 args: anytype,
36) void {
37 const level_txt = comptime message_level.asText();
38 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
39 var buf: [500]u8 = undefined;
40 const line = std.fmt.bufPrint(&buf, level_txt ++ prefix2 ++ format, args) catch l: {
41 buf[buf.len - 3 ..][0..3].* = "...".*;
42 break :l &buf;
43 };
44 js.log(line.ptr, line.len);
45}
46
47export fn alloc(n: usize) [*]u8 {
48 const slice = gpa.alloc(u8, n) catch @panic("OOM");
49 return slice.ptr;
50}
51
52export fn unpack(tar_ptr: [*]u8, tar_len: usize) void {
53 const tar_bytes = tar_ptr[0..tar_len];
54 //log.debug("received {d} bytes of tar file", .{tar_bytes.len});
55
56 unpack_inner(tar_bytes) catch |err| {
57 fatal("unable to unpack tar: {s}", .{@errorName(err)});
58 };
59}
60
61var query_string: std.ArrayListUnmanaged(u8) = .{};
62var query_results: std.ArrayListUnmanaged(Decl.Index) = .{};
63
64/// Resizes the query string to be the correct length; returns the pointer to
65/// the query string.
66export fn query_begin(query_string_len: usize) [*]u8 {
67 query_string.resize(gpa, query_string_len) catch @panic("OOM");
68 return query_string.items.ptr;
69}
70
71/// Executes the query. Returns the pointer to the query results which is an
72/// array of u32.
73/// The first element is the length of the array.
74/// Subsequent elements are Decl.Index values which are all public
75/// declarations.
76export fn query_exec(ignore_case: bool) [*]Decl.Index {
77 const query = query_string.items;
78 log.debug("querying '{s}'", .{query});
79 query_exec_fallible(query, ignore_case) catch |err| switch (err) {
80 error.OutOfMemory => @panic("OOM"),
81 };
82 query_results.items[0] = @enumFromInt(query_results.items.len - 1);
83 return query_results.items.ptr;
84}
85
86const max_matched_items = 1000;
87
88fn query_exec_fallible(query: []const u8, ignore_case: bool) !void {
89 const Score = packed struct(u32) {
90 points: u16,
91 segments: u16,
92 };
93 const g = struct {
94 var full_path_search_text: std.ArrayListUnmanaged(u8) = .{};
95 var full_path_search_text_lower: std.ArrayListUnmanaged(u8) = .{};
96 var doc_search_text: std.ArrayListUnmanaged(u8) = .{};
97 /// Each element matches a corresponding query_results element.
98 var scores: std.ArrayListUnmanaged(Score) = .{};
99 };
100
101 // First element stores the size of the list.
102 try query_results.resize(gpa, 1);
103 // Corresponding point value is meaningless and therefore undefined.
104 try g.scores.resize(gpa, 1);
105
106 decl_loop: for (Walk.decls.items, 0..) |*decl, decl_index| {
107 const info = decl.extra_info();
108 if (!info.is_pub) continue;
109
110 try decl.reset_with_path(&g.full_path_search_text);
111 if (decl.parent != .none)
112 try Decl.append_parent_ns(&g.full_path_search_text, decl.parent);
113 try g.full_path_search_text.appendSlice(gpa, info.name);
114
115 try g.full_path_search_text_lower.resize(gpa, g.full_path_search_text.items.len);
116 @memcpy(g.full_path_search_text_lower.items, g.full_path_search_text.items);
117
118 const ast = decl.file.get_ast();
119 try collect_docs(&g.doc_search_text, ast, info.first_doc_comment);
120
121 if (ignore_case) {
122 ascii_lower(g.full_path_search_text_lower.items);
123 ascii_lower(g.doc_search_text.items);
124 }
125
126 var it = std.mem.tokenizeScalar(u8, query, ' ');
127 var points: u16 = 0;
128 var bypass_limit = false;
129 while (it.next()) |term| {
130 // exact, case sensitive match of full decl path
131 if (std.mem.eql(u8, g.full_path_search_text.items, term)) {
132 points += 4;
133 bypass_limit = true;
134 continue;
135 }
136 // exact, case sensitive match of just decl name
137 if (std.mem.eql(u8, info.name, term)) {
138 points += 3;
139 bypass_limit = true;
140 continue;
141 }
142 // substring, case insensitive match of full decl path
143 if (std.mem.indexOf(u8, g.full_path_search_text_lower.items, term) != null) {
144 points += 2;
145 continue;
146 }
147 if (std.mem.indexOf(u8, g.doc_search_text.items, term) != null) {
148 points += 1;
149 continue;
150 }
151 continue :decl_loop;
152 }
153
154 if (query_results.items.len < max_matched_items or bypass_limit) {
155 try query_results.append(gpa, @enumFromInt(decl_index));
156 try g.scores.append(gpa, .{
157 .points = points,
158 .segments = @intCast(count_scalar(g.full_path_search_text.items, '.')),
159 });
160 }
161 }
162
163 const sort_context: struct {
164 pub fn swap(sc: @This(), a_index: usize, b_index: usize) void {
165 _ = sc;
166 std.mem.swap(Score, &g.scores.items[a_index], &g.scores.items[b_index]);
167 std.mem.swap(Decl.Index, &query_results.items[a_index], &query_results.items[b_index]);
168 }
169
170 pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool {
171 _ = sc;
172 const a_score = g.scores.items[a_index];
173 const b_score = g.scores.items[b_index];
174 if (b_score.points < a_score.points) {
175 return true;
176 } else if (b_score.points > a_score.points) {
177 return false;
178 } else if (a_score.segments < b_score.segments) {
179 return true;
180 } else if (a_score.segments > b_score.segments) {
181 return false;
182 } else {
183 const a_decl = query_results.items[a_index];
184 const b_decl = query_results.items[b_index];
185 const a_file_path = a_decl.get().file.path();
186 const b_file_path = b_decl.get().file.path();
187 // This neglects to check the local namespace inside the file.
188 return std.mem.lessThan(u8, b_file_path, a_file_path);
189 }
190 }
191 } = .{};
192
193 std.mem.sortUnstableContext(1, query_results.items.len, sort_context);
194
195 if (query_results.items.len > max_matched_items)
196 query_results.shrinkRetainingCapacity(max_matched_items);
197}
198
199const String = Slice(u8);
200
201fn Slice(T: type) type {
202 return packed struct(u64) {
203 ptr: u32,
204 len: u32,
205
206 fn init(s: []const T) @This() {
207 return .{
208 .ptr = @intFromPtr(s.ptr),
209 .len = s.len,
210 };
211 }
212 };
213}
214
215const ErrorIdentifier = packed struct(u64) {
216 token_index: Ast.TokenIndex,
217 decl_index: Decl.Index,
218
219 fn hasDocs(ei: ErrorIdentifier) bool {
220 const decl_index = ei.decl_index;
221 const ast = decl_index.get().file.get_ast();
222 const token_tags = ast.tokens.items(.tag);
223 const token_index = ei.token_index;
224 if (token_index == 0) return false;
225 return token_tags[token_index - 1] == .doc_comment;
226 }
227
228 fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void {
229 const decl_index = ei.decl_index;
230 const ast = decl_index.get().file.get_ast();
231 const name = ast.tokenSlice(ei.token_index);
232 const first_doc_comment = Decl.findFirstDocComment(ast, ei.token_index);
233 const has_docs = ast.tokens.items(.tag)[first_doc_comment] == .doc_comment;
234 const has_link = base_decl != decl_index;
235
236 try out.appendSlice(gpa, "<dt>");
237 try out.appendSlice(gpa, name);
238 if (has_link) {
239 try out.appendSlice(gpa, " <a href=\"#");
240 _ = missing_feature_url_escape;
241 try decl_index.get().fqn(out);
242 try out.appendSlice(gpa, "\">");
243 try out.appendSlice(gpa, decl_index.get().extra_info().name);
244 try out.appendSlice(gpa, "</a>");
245 }
246 try out.appendSlice(gpa, "</dt>");
247
248 if (has_docs) {
249 try out.appendSlice(gpa, "<dd>");
250 try render_docs(out, decl_index, first_doc_comment, false);
251 try out.appendSlice(gpa, "</dd>");
252 }
253 }
254};
255
256var string_result: std.ArrayListUnmanaged(u8) = .{};
257var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .{};
258
259export fn decl_error_set(decl_index: Decl.Index) Slice(ErrorIdentifier) {
260 return Slice(ErrorIdentifier).init(decl_error_set_fallible(decl_index) catch @panic("OOM"));
261}
262
263export fn error_set_node_list(base_decl: Decl.Index, node: Ast.Node.Index) Slice(ErrorIdentifier) {
264 error_set_result.clearRetainingCapacity();
265 addErrorsFromExpr(base_decl, &error_set_result, node) catch @panic("OOM");
266 sort_error_set_result();
267 return Slice(ErrorIdentifier).init(error_set_result.values());
268}
269
270export fn fn_error_set_decl(decl_index: Decl.Index, node: Ast.Node.Index) Decl.Index {
271 return switch (decl_index.get().file.categorize_expr(node)) {
272 .alias => |aliasee| fn_error_set_decl(aliasee, aliasee.get().ast_node),
273 else => decl_index,
274 };
275}
276
277export fn decl_field_count(decl_index: Decl.Index) u32 {
278 switch (decl_index.get().categorize()) {
279 .namespace => |node| return decl_index.get().file.get().field_count(node),
280 else => return 0,
281 }
282}
283
284fn decl_error_set_fallible(decl_index: Decl.Index) Oom![]ErrorIdentifier {
285 error_set_result.clearRetainingCapacity();
286 try addErrorsFromDecl(decl_index, &error_set_result);
287 sort_error_set_result();
288 return error_set_result.values();
289}
290
291fn sort_error_set_result() void {
292 const sort_context: struct {
293 pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool {
294 _ = sc;
295 const a_name = error_set_result.keys()[a_index];
296 const b_name = error_set_result.keys()[b_index];
297 return std.mem.lessThan(u8, a_name, b_name);
298 }
299 } = .{};
300 error_set_result.sortUnstable(sort_context);
301}
302
303fn addErrorsFromDecl(
304 decl_index: Decl.Index,
305 out: *std.StringArrayHashMapUnmanaged(ErrorIdentifier),
306) Oom!void {
307 switch (decl_index.get().categorize()) {
308 .error_set => |node| try addErrorsFromExpr(decl_index, out, node),
309 .alias => |aliasee| try addErrorsFromDecl(aliasee, out),
310 else => |cat| log.debug("unable to addErrorsFromDecl: {any}", .{cat}),
311 }
312}
313
314fn addErrorsFromExpr(
315 decl_index: Decl.Index,
316 out: *std.StringArrayHashMapUnmanaged(ErrorIdentifier),
317 node: Ast.Node.Index,
318) Oom!void {
319 const decl = decl_index.get();
320 const ast = decl.file.get_ast();
321 const node_tags = ast.nodes.items(.tag);
322 const node_datas = ast.nodes.items(.data);
323
324 switch (decl.file.categorize_expr(node)) {
325 .error_set => |n| switch (node_tags[n]) {
326 .error_set_decl => {
327 try addErrorsFromNode(decl_index, out, node);
328 },
329 .merge_error_sets => {
330 try addErrorsFromExpr(decl_index, out, node_datas[node].lhs);
331 try addErrorsFromExpr(decl_index, out, node_datas[node].rhs);
332 },
333 else => unreachable,
334 },
335 .alias => |aliasee| {
336 try addErrorsFromDecl(aliasee, out);
337 },
338 else => return,
339 }
340}
341
342fn addErrorsFromNode(
343 decl_index: Decl.Index,
344 out: *std.StringArrayHashMapUnmanaged(ErrorIdentifier),
345 node: Ast.Node.Index,
346) Oom!void {
347 const decl = decl_index.get();
348 const ast = decl.file.get_ast();
349 const main_tokens = ast.nodes.items(.main_token);
350 const token_tags = ast.tokens.items(.tag);
351 const error_token = main_tokens[node];
352 var tok_i = error_token + 2;
353 while (true) : (tok_i += 1) switch (token_tags[tok_i]) {
354 .doc_comment, .comma => {},
355 .identifier => {
356 const name = ast.tokenSlice(tok_i);
357 const gop = try out.getOrPut(gpa, name);
358 // If there are more than one, take the one with doc comments.
359 // If they both have doc comments, prefer the existing one.
360 const new: ErrorIdentifier = .{
361 .token_index = tok_i,
362 .decl_index = decl_index,
363 };
364 if (!gop.found_existing or
365 (!gop.value_ptr.hasDocs() and new.hasDocs()))
366 {
367 gop.value_ptr.* = new;
368 }
369 },
370 .r_brace => break,
371 else => unreachable,
372 };
373}
374
375export fn type_fn_fields(decl_index: Decl.Index) Slice(Ast.Node.Index) {
376 return decl_fields(decl_index);
377}
378
379export fn decl_fields(decl_index: Decl.Index) Slice(Ast.Node.Index) {
380 return Slice(Ast.Node.Index).init(decl_fields_fallible(decl_index) catch @panic("OOM"));
381}
382
383export fn decl_params(decl_index: Decl.Index) Slice(Ast.Node.Index) {
384 return Slice(Ast.Node.Index).init(decl_params_fallible(decl_index) catch @panic("OOM"));
385}
386
387fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
388 const g = struct {
389 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .{};
390 };
391 g.result.clearRetainingCapacity();
392 const decl = decl_index.get();
393 const ast = decl.file.get_ast();
394 const node_tags = ast.nodes.items(.tag);
395 const value_node = decl.value_node() orelse return &.{};
396 var buf: [2]Ast.Node.Index = undefined;
397 const container_decl = ast.fullContainerDecl(&buf, value_node) orelse return &.{};
398 for (container_decl.ast.members) |member_node| switch (node_tags[member_node]) {
399 .container_field_init,
400 .container_field_align,
401 .container_field,
402 => try g.result.append(gpa, member_node),
403
404 else => continue,
405 };
406 return g.result.items;
407}
408
409fn decl_params_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
410 const g = struct {
411 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .{};
412 };
413 g.result.clearRetainingCapacity();
414 const decl = decl_index.get();
415 const ast = decl.file.get_ast();
416 const value_node = decl.value_node() orelse return &.{};
417 var buf: [1]Ast.Node.Index = undefined;
418 const fn_proto = ast.fullFnProto(&buf, value_node) orelse return &.{};
419 try g.result.appendSlice(gpa, fn_proto.ast.params);
420 return g.result.items;
421}
422
423export fn error_html(base_decl: Decl.Index, error_identifier: ErrorIdentifier) String {
424 string_result.clearRetainingCapacity();
425 error_identifier.html(base_decl, &string_result) catch @panic("OOM");
426 return String.init(string_result.items);
427}
428
429export fn decl_field_html(decl_index: Decl.Index, field_node: Ast.Node.Index) String {
430 string_result.clearRetainingCapacity();
431 decl_field_html_fallible(&string_result, decl_index, field_node) catch @panic("OOM");
432 return String.init(string_result.items);
433}
434
435export fn decl_param_html(decl_index: Decl.Index, param_node: Ast.Node.Index) String {
436 string_result.clearRetainingCapacity();
437 decl_param_html_fallible(&string_result, decl_index, param_node) catch @panic("OOM");
438 return String.init(string_result.items);
439}
440
441fn decl_field_html_fallible(
442 out: *std.ArrayListUnmanaged(u8),
443 decl_index: Decl.Index,
444 field_node: Ast.Node.Index,
445) !void {
446 const decl = decl_index.get();
447 const ast = decl.file.get_ast();
448 try out.appendSlice(gpa, "<pre><code>");
449 try file_source_html(decl.file, out, field_node, .{});
450 try out.appendSlice(gpa, "</code></pre>");
451
452 const field = ast.fullContainerField(field_node).?;
453 const first_doc_comment = Decl.findFirstDocComment(ast, field.firstToken());
454
455 if (ast.tokens.items(.tag)[first_doc_comment] == .doc_comment) {
456 try out.appendSlice(gpa, "<div class=\"fieldDocs\">");
457 try render_docs(out, decl_index, first_doc_comment, false);
458 try out.appendSlice(gpa, "</div>");
459 }
460}
461
462fn decl_param_html_fallible(
463 out: *std.ArrayListUnmanaged(u8),
464 decl_index: Decl.Index,
465 param_node: Ast.Node.Index,
466) !void {
467 const decl = decl_index.get();
468 const ast = decl.file.get_ast();
469 const token_tags = ast.tokens.items(.tag);
470 const colon = ast.firstToken(param_node) - 1;
471 const name_token = colon - 1;
472 const first_doc_comment = f: {
473 var it = ast.firstToken(param_node);
474 while (it > 0) {
475 it -= 1;
476 switch (token_tags[it]) {
477 .doc_comment, .colon, .identifier, .keyword_comptime, .keyword_noalias => {},
478 else => break,
479 }
480 }
481 break :f it + 1;
482 };
483 const name = ast.tokenSlice(name_token);
484
485 try out.appendSlice(gpa, "<pre><code>");
486 try appendEscaped(out, name);
487 try out.appendSlice(gpa, ": ");
488 try file_source_html(decl.file, out, param_node, .{});
489 try out.appendSlice(gpa, "</code></pre>");
490
491 if (ast.tokens.items(.tag)[first_doc_comment] == .doc_comment) {
492 try out.appendSlice(gpa, "<div class=\"fieldDocs\">");
493 try render_docs(out, decl_index, first_doc_comment, false);
494 try out.appendSlice(gpa, "</div>");
495 }
496}
497
498export fn decl_fn_proto_html(decl_index: Decl.Index, linkify_fn_name: bool) String {
499 const decl = decl_index.get();
500 const ast = decl.file.get_ast();
501 const node_tags = ast.nodes.items(.tag);
502 const node_datas = ast.nodes.items(.data);
503 const proto_node = switch (node_tags[decl.ast_node]) {
504 .fn_decl => node_datas[decl.ast_node].lhs,
505
506 .fn_proto,
507 .fn_proto_one,
508 .fn_proto_simple,
509 .fn_proto_multi,
510 => decl.ast_node,
511
512 else => unreachable,
513 };
514
515 string_result.clearRetainingCapacity();
516 file_source_html(decl.file, &string_result, proto_node, .{
517 .skip_doc_comments = true,
518 .skip_comments = true,
519 .collapse_whitespace = true,
520 .fn_link = if (linkify_fn_name) decl_index else .none,
521 }) catch |err| {
522 fatal("unable to render source: {s}", .{@errorName(err)});
523 };
524 return String.init(string_result.items);
525}
526
527export fn decl_source_html(decl_index: Decl.Index) String {
528 const decl = decl_index.get();
529
530 string_result.clearRetainingCapacity();
531 file_source_html(decl.file, &string_result, decl.ast_node, .{}) catch |err| {
532 fatal("unable to render source: {s}", .{@errorName(err)});
533 };
534 return String.init(string_result.items);
535}
536
537export fn decl_doctest_html(decl_index: Decl.Index) String {
538 const decl = decl_index.get();
539 const doctest_ast_node = decl.file.get().doctests.get(decl.ast_node) orelse
540 return String.init("");
541
542 string_result.clearRetainingCapacity();
543 file_source_html(decl.file, &string_result, doctest_ast_node, .{}) catch |err| {
544 fatal("unable to render source: {s}", .{@errorName(err)});
545 };
546 return String.init(string_result.items);
547}
548
549export fn decl_fqn(decl_index: Decl.Index) String {
550 const decl = decl_index.get();
551 string_result.clearRetainingCapacity();
552 decl.fqn(&string_result) catch @panic("OOM");
553 return String.init(string_result.items);
554}
555
556export fn decl_parent(decl_index: Decl.Index) Decl.Index {
557 const decl = decl_index.get();
558 return decl.parent;
559}
560
561export fn fn_error_set(decl_index: Decl.Index) Ast.Node.Index {
562 const decl = decl_index.get();
563 const ast = decl.file.get_ast();
564 var buf: [1]Ast.Node.Index = undefined;
565 const full = ast.fullFnProto(&buf, decl.ast_node).?;
566 const node_tags = ast.nodes.items(.tag);
567 const node_datas = ast.nodes.items(.data);
568 return switch (node_tags[full.ast.return_type]) {
569 .error_set_decl => full.ast.return_type,
570 .error_union => node_datas[full.ast.return_type].lhs,
571 else => 0,
572 };
573}
574
575export fn decl_file_path(decl_index: Decl.Index) String {
576 string_result.clearRetainingCapacity();
577 string_result.appendSlice(gpa, decl_index.get().file.path()) catch @panic("OOM");
578 return String.init(string_result.items);
579}
580
581export fn decl_category_name(decl_index: Decl.Index) String {
582 const decl = decl_index.get();
583 const ast = decl.file.get_ast();
584 const token_tags = ast.tokens.items(.tag);
585 const name = switch (decl.categorize()) {
586 .namespace => |node| {
587 const node_tags = ast.nodes.items(.tag);
588 if (node_tags[decl.ast_node] == .root)
589 return String.init("struct");
590 string_result.clearRetainingCapacity();
591 var buf: [2]Ast.Node.Index = undefined;
592 const container_decl = ast.fullContainerDecl(&buf, node).?;
593 if (container_decl.layout_token) |t| {
594 if (token_tags[t] == .keyword_extern) {
595 string_result.appendSlice(gpa, "extern ") catch @panic("OOM");
596 }
597 }
598 const main_token_tag = token_tags[container_decl.ast.main_token];
599 string_result.appendSlice(gpa, main_token_tag.lexeme().?) catch @panic("OOM");
600 return String.init(string_result.items);
601 },
602 .global_variable => "Global Variable",
603 .function => "Function",
604 .type_function => "Type Function",
605 .type, .type_type => "Type",
606 .error_set => "Error Set",
607 .global_const => "Constant",
608 .primitive => "Primitive Value",
609 .alias => "Alias",
610 };
611 return String.init(name);
612}
613
614export fn decl_name(decl_index: Decl.Index) String {
615 const decl = decl_index.get();
616 string_result.clearRetainingCapacity();
617 const name = n: {
618 if (decl.parent == .none) {
619 // Then it is the root struct of a file.
620 break :n std.fs.path.stem(decl.file.path());
621 }
622 break :n decl.extra_info().name;
623 };
624 string_result.appendSlice(gpa, name) catch @panic("OOM");
625 return String.init(string_result.items);
626}
627
628export fn decl_docs_html(decl_index: Decl.Index, short: bool) String {
629 const decl = decl_index.get();
630 string_result.clearRetainingCapacity();
631 render_docs(&string_result, decl_index, decl.extra_info().first_doc_comment, short) catch @panic("OOM");
632 return String.init(string_result.items);
633}
634
635fn collect_docs(
636 list: *std.ArrayListUnmanaged(u8),
637 ast: *const Ast,
638 first_doc_comment: Ast.TokenIndex,
639) Oom!void {
640 const token_tags = ast.tokens.items(.tag);
641 list.clearRetainingCapacity();
642 var it = first_doc_comment;
643 while (true) : (it += 1) switch (token_tags[it]) {
644 .doc_comment, .container_doc_comment => {
645 // It is tempting to trim this string but think carefully about how
646 // that will affect the markdown parser.
647 const line = ast.tokenSlice(it)[3..];
648 try list.appendSlice(gpa, line);
649 },
650 else => break,
651 };
652}
653
654fn render_docs(
655 out: *std.ArrayListUnmanaged(u8),
656 decl_index: Decl.Index,
657 first_doc_comment: Ast.TokenIndex,
658 short: bool,
659) Oom!void {
660 const decl = decl_index.get();
661 const ast = decl.file.get_ast();
662 const token_tags = ast.tokens.items(.tag);
663
664 var parser = try markdown.Parser.init(gpa);
665 defer parser.deinit();
666 var it = first_doc_comment;
667 while (true) : (it += 1) switch (token_tags[it]) {
668 .doc_comment, .container_doc_comment => {
669 const line = ast.tokenSlice(it)[3..];
670 if (short and line.len == 0) break;
671 try parser.feedLine(line);
672 },
673 else => break,
674 };
675
676 var parsed_doc = try parser.endInput();
677 defer parsed_doc.deinit(gpa);
678
679 const g = struct {
680 var link_buffer: std.ArrayListUnmanaged(u8) = .{};
681 };
682
683 const Writer = std.ArrayListUnmanaged(u8).Writer;
684 const Renderer = markdown.Renderer(Writer, Decl.Index);
685 const renderer: Renderer = .{
686 .context = decl_index,
687 .renderFn = struct {
688 fn render(
689 r: Renderer,
690 doc: markdown.Document,
691 node: markdown.Document.Node.Index,
692 writer: Writer,
693 ) !void {
694 const data = doc.nodes.items(.data)[@intFromEnum(node)];
695 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
696 .code_span => {
697 try writer.writeAll("<code>");
698 const content = doc.string(data.text.content);
699 if (resolve_decl_path(r.context, content)) |resolved_decl_index| {
700 g.link_buffer.clearRetainingCapacity();
701 try resolve_decl_link(resolved_decl_index, &g.link_buffer);
702
703 try writer.writeAll("<a href=\"#");
704 _ = missing_feature_url_escape;
705 try writer.writeAll(g.link_buffer.items);
706 try writer.print("\">{}</a>", .{markdown.fmtHtml(content)});
707 } else {
708 try writer.print("{}", .{markdown.fmtHtml(content)});
709 }
710
711 try writer.writeAll("</code>");
712 },
713
714 else => try Renderer.renderDefault(r, doc, node, writer),
715 }
716 }
717 }.render,
718 };
719 try renderer.render(parsed_doc, out.writer(gpa));
720}
721
722fn resolve_decl_path(decl_index: Decl.Index, path: []const u8) ?Decl.Index {
723 var path_components = std.mem.splitScalar(u8, path, '.');
724 var current_decl_index = decl_index.get().lookup(path_components.first()) orelse return null;
725 while (path_components.next()) |component| {
726 switch (current_decl_index.get().categorize()) {
727 .alias => |aliasee| current_decl_index = aliasee,
728 else => {},
729 }
730 current_decl_index = current_decl_index.get().get_child(component) orelse return null;
731 }
732 return current_decl_index;
733}
734
735export fn decl_type_html(decl_index: Decl.Index) String {
736 const decl = decl_index.get();
737 const ast = decl.file.get_ast();
738 string_result.clearRetainingCapacity();
739 t: {
740 // If there is an explicit type, use it.
741 if (ast.fullVarDecl(decl.ast_node)) |var_decl| {
742 if (var_decl.ast.type_node != 0) {
743 string_result.appendSlice(gpa, "<code>") catch @panic("OOM");
744 file_source_html(decl.file, &string_result, var_decl.ast.type_node, .{
745 .skip_comments = true,
746 .collapse_whitespace = true,
747 }) catch |e| {
748 fatal("unable to render html: {s}", .{@errorName(e)});
749 };
750 string_result.appendSlice(gpa, "</code>") catch @panic("OOM");
751 break :t;
752 }
753 }
754 }
755 return String.init(string_result.items);
756}
757
758const Oom = error{OutOfMemory};
759
760fn unpack_inner(tar_bytes: []u8) !void {
761 var fbs = std.io.fixedBufferStream(tar_bytes);
762 var file_name_buffer: [1024]u8 = undefined;
763 var link_name_buffer: [1024]u8 = undefined;
764 var it = std.tar.iterator(fbs.reader(), .{
765 .file_name_buffer = &file_name_buffer,
766 .link_name_buffer = &link_name_buffer,
767 });
768 while (try it.next()) |tar_file| {
769 switch (tar_file.kind) {
770 .normal => {
771 if (tar_file.size == 0 and tar_file.name.len == 0) break;
772 if (std.mem.endsWith(u8, tar_file.name, ".zig")) {
773 log.debug("found file: '{s}'", .{tar_file.name});
774 const file_name = try gpa.dupe(u8, tar_file.name);
775 if (std.mem.indexOfScalar(u8, file_name, '/')) |pkg_name_end| {
776 const pkg_name = file_name[0..pkg_name_end];
777 const gop = try Walk.modules.getOrPut(gpa, pkg_name);
778 const file: Walk.File.Index = @enumFromInt(Walk.files.entries.len);
779 if (!gop.found_existing or
780 std.mem.eql(u8, file_name[pkg_name_end..], "/root.zig") or
781 std.mem.eql(u8, file_name[pkg_name_end + 1 .. file_name.len - ".zig".len], pkg_name))
782 {
783 gop.value_ptr.* = file;
784 }
785 const file_bytes = tar_bytes[fbs.pos..][0..@intCast(tar_file.size)];
786 assert(file == try Walk.add_file(file_name, file_bytes));
787 }
788 } else {
789 log.warn("skipping: '{s}' - the tar creation should have done that", .{
790 tar_file.name,
791 });
792 }
793 try tar_file.skip();
794 },
795 else => continue,
796 }
797 }
798}
799
800fn fatal(comptime format: []const u8, args: anytype) noreturn {
801 var buf: [500]u8 = undefined;
802 const line = std.fmt.bufPrint(&buf, format, args) catch l: {
803 buf[buf.len - 3 ..][0..3].* = "...".*;
804 break :l &buf;
805 };
806 js.panic(line.ptr, line.len);
807}
808
809fn ascii_lower(bytes: []u8) void {
810 for (bytes) |*b| b.* = std.ascii.toLower(b.*);
811}
812
813export fn module_name(index: u32) String {
814 const names = Walk.modules.keys();
815 return String.init(if (index >= names.len) "" else names[index]);
816}
817
818export fn find_module_root(pkg: Walk.ModuleIndex) Decl.Index {
819 const root_file = Walk.modules.values()[@intFromEnum(pkg)];
820 const result = root_file.findRootDecl();
821 assert(result != .none);
822 return result;
823}
824
825/// Set by `set_input_string`.
826var input_string: std.ArrayListUnmanaged(u8) = .{};
827
828export fn set_input_string(len: usize) [*]u8 {
829 input_string.resize(gpa, len) catch @panic("OOM");
830 return input_string.items.ptr;
831}
832
833/// Looks up the root struct decl corresponding to a file by path.
834/// Uses `input_string`.
835export fn find_file_root() Decl.Index {
836 const file: Walk.File.Index = @enumFromInt(Walk.files.getIndex(input_string.items) orelse return .none);
837 return file.findRootDecl();
838}
839
840/// Uses `input_string`.
841/// Tries to look up the Decl component-wise but then falls back to a file path
842/// based scan.
843export fn find_decl() Decl.Index {
844 const result = Decl.find(input_string.items);
845 if (result != .none) return result;
846
847 const g = struct {
848 var match_fqn: std.ArrayListUnmanaged(u8) = .{};
849 };
850 for (Walk.decls.items, 0..) |*decl, decl_index| {
851 g.match_fqn.clearRetainingCapacity();
852 decl.fqn(&g.match_fqn) catch @panic("OOM");
853 if (std.mem.eql(u8, g.match_fqn.items, input_string.items)) {
854 //const path = @as(Decl.Index, @enumFromInt(decl_index)).get().file.path();
855 //log.debug("find_decl '{s}' found in {s}", .{ input_string.items, path });
856 return @enumFromInt(decl_index);
857 }
858 }
859 return .none;
860}
861
862/// Set only by `categorize_decl`; read only by `get_aliasee`, valid only
863/// when `categorize_decl` returns `.alias`.
864var global_aliasee: Decl.Index = .none;
865
866export fn get_aliasee() Decl.Index {
867 return global_aliasee;
868}
869export fn categorize_decl(decl_index: Decl.Index, resolve_alias_count: usize) Walk.Category.Tag {
870 global_aliasee = .none;
871 var chase_alias_n = resolve_alias_count;
872 var decl = decl_index.get();
873 while (true) {
874 const result = decl.categorize();
875 switch (result) {
876 .alias => |new_index| {
877 assert(new_index != .none);
878 global_aliasee = new_index;
879 if (chase_alias_n > 0) {
880 chase_alias_n -= 1;
881 decl = new_index.get();
882 continue;
883 }
884 },
885 else => {},
886 }
887 return result;
888 }
889}
890
891export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {
892 return namespace_members(parent, include_private);
893}
894
895export fn namespace_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {
896 const g = struct {
897 var members: std.ArrayListUnmanaged(Decl.Index) = .{};
898 };
899
900 g.members.clearRetainingCapacity();
901
902 for (Walk.decls.items, 0..) |*decl, i| {
903 if (decl.parent == parent) {
904 if (include_private or decl.is_pub()) {
905 g.members.append(gpa, @enumFromInt(i)) catch @panic("OOM");
906 }
907 }
908 }
909
910 return Slice(Decl.Index).init(g.members.items);
911}
912
913const RenderSourceOptions = struct {
914 skip_doc_comments: bool = false,
915 skip_comments: bool = false,
916 collapse_whitespace: bool = false,
917 fn_link: Decl.Index = .none,
918};
919
920fn file_source_html(
921 file_index: Walk.File.Index,
922 out: *std.ArrayListUnmanaged(u8),
923 root_node: Ast.Node.Index,
924 options: RenderSourceOptions,
925) !void {
926 const ast = file_index.get_ast();
927 const file = file_index.get();
928
929 const g = struct {
930 var field_access_buffer: std.ArrayListUnmanaged(u8) = .{};
931 };
932
933 const token_tags = ast.tokens.items(.tag);
934 const token_starts = ast.tokens.items(.start);
935 const main_tokens = ast.nodes.items(.main_token);
936
937 const start_token = ast.firstToken(root_node);
938 const end_token = ast.lastToken(root_node) + 1;
939
940 var cursor: usize = token_starts[start_token];
941
942 for (
943 token_tags[start_token..end_token],
944 token_starts[start_token..end_token],
945 start_token..,
946 ) |tag, start, token_index| {
947 const between = ast.source[cursor..start];
948 if (std.mem.trim(u8, between, " \t\r\n").len > 0) {
949 if (!options.skip_comments) {
950 try out.appendSlice(gpa, "<span class=\"tok-comment\">");
951 try appendEscaped(out, between);
952 try out.appendSlice(gpa, "</span>");
953 }
954 } else if (between.len > 0) {
955 if (options.collapse_whitespace) {
956 if (out.items.len > 0 and out.items[out.items.len - 1] != ' ')
957 try out.append(gpa, ' ');
958 } else {
959 try out.appendSlice(gpa, between);
960 }
961 }
962 if (tag == .eof) break;
963 const slice = ast.tokenSlice(token_index);
964 cursor = start + slice.len;
965 switch (tag) {
966 .eof => unreachable,
967
968 .keyword_addrspace,
969 .keyword_align,
970 .keyword_and,
971 .keyword_asm,
972 .keyword_async,
973 .keyword_await,
974 .keyword_break,
975 .keyword_catch,
976 .keyword_comptime,
977 .keyword_const,
978 .keyword_continue,
979 .keyword_defer,
980 .keyword_else,
981 .keyword_enum,
982 .keyword_errdefer,
983 .keyword_error,
984 .keyword_export,
985 .keyword_extern,
986 .keyword_for,
987 .keyword_if,
988 .keyword_inline,
989 .keyword_noalias,
990 .keyword_noinline,
991 .keyword_nosuspend,
992 .keyword_opaque,
993 .keyword_or,
994 .keyword_orelse,
995 .keyword_packed,
996 .keyword_anyframe,
997 .keyword_pub,
998 .keyword_resume,
999 .keyword_return,
1000 .keyword_linksection,
1001 .keyword_callconv,
1002 .keyword_struct,
1003 .keyword_suspend,
1004 .keyword_switch,
1005 .keyword_test,
1006 .keyword_threadlocal,
1007 .keyword_try,
1008 .keyword_union,
1009 .keyword_unreachable,
1010 .keyword_usingnamespace,
1011 .keyword_var,
1012 .keyword_volatile,
1013 .keyword_allowzero,
1014 .keyword_while,
1015 .keyword_anytype,
1016 .keyword_fn,
1017 => {
1018 try out.appendSlice(gpa, "<span class=\"tok-kw\">");
1019 try appendEscaped(out, slice);
1020 try out.appendSlice(gpa, "</span>");
1021 },
1022
1023 .string_literal,
1024 .char_literal,
1025 .multiline_string_literal_line,
1026 => {
1027 try out.appendSlice(gpa, "<span class=\"tok-str\">");
1028 try appendEscaped(out, slice);
1029 try out.appendSlice(gpa, "</span>");
1030 },
1031
1032 .builtin => {
1033 try out.appendSlice(gpa, "<span class=\"tok-builtin\">");
1034 try appendEscaped(out, slice);
1035 try out.appendSlice(gpa, "</span>");
1036 },
1037
1038 .doc_comment,
1039 .container_doc_comment,
1040 => {
1041 if (!options.skip_doc_comments) {
1042 try out.appendSlice(gpa, "<span class=\"tok-comment\">");
1043 try appendEscaped(out, slice);
1044 try out.appendSlice(gpa, "</span>");
1045 }
1046 },
1047
1048 .identifier => i: {
1049 if (options.fn_link != .none) {
1050 const fn_link = options.fn_link.get();
1051 const fn_token = main_tokens[fn_link.ast_node];
1052 if (token_index == fn_token + 1) {
1053 try out.appendSlice(gpa, "<a class=\"tok-fn\" href=\"#");
1054 _ = missing_feature_url_escape;
1055 try fn_link.fqn(out);
1056 try out.appendSlice(gpa, "\">");
1057 try appendEscaped(out, slice);
1058 try out.appendSlice(gpa, "</a>");
1059 break :i;
1060 }
1061 }
1062
1063 if (token_index > 0 and token_tags[token_index - 1] == .keyword_fn) {
1064 try out.appendSlice(gpa, "<span class=\"tok-fn\">");
1065 try appendEscaped(out, slice);
1066 try out.appendSlice(gpa, "</span>");
1067 break :i;
1068 }
1069
1070 if (Walk.isPrimitiveNonType(slice)) {
1071 try out.appendSlice(gpa, "<span class=\"tok-null\">");
1072 try appendEscaped(out, slice);
1073 try out.appendSlice(gpa, "</span>");
1074 break :i;
1075 }
1076
1077 if (std.zig.primitives.isPrimitive(slice)) {
1078 try out.appendSlice(gpa, "<span class=\"tok-type\">");
1079 try appendEscaped(out, slice);
1080 try out.appendSlice(gpa, "</span>");
1081 break :i;
1082 }
1083
1084 if (file.token_parents.get(token_index)) |field_access_node| {
1085 g.field_access_buffer.clearRetainingCapacity();
1086 try walk_field_accesses(file_index, &g.field_access_buffer, field_access_node);
1087 if (g.field_access_buffer.items.len > 0) {
1088 try out.appendSlice(gpa, "<a href=\"#");
1089 _ = missing_feature_url_escape;
1090 try out.appendSlice(gpa, g.field_access_buffer.items);
1091 try out.appendSlice(gpa, "\">");
1092 try appendEscaped(out, slice);
1093 try out.appendSlice(gpa, "</a>");
1094 } else {
1095 try appendEscaped(out, slice);
1096 }
1097 break :i;
1098 }
1099
1100 {
1101 g.field_access_buffer.clearRetainingCapacity();
1102 try resolve_ident_link(file_index, &g.field_access_buffer, token_index);
1103 if (g.field_access_buffer.items.len > 0) {
1104 try out.appendSlice(gpa, "<a href=\"#");
1105 _ = missing_feature_url_escape;
1106 try out.appendSlice(gpa, g.field_access_buffer.items);
1107 try out.appendSlice(gpa, "\">");
1108 try appendEscaped(out, slice);
1109 try out.appendSlice(gpa, "</a>");
1110 break :i;
1111 }
1112 }
1113
1114 try appendEscaped(out, slice);
1115 },
1116
1117 .number_literal => {
1118 try out.appendSlice(gpa, "<span class=\"tok-number\">");
1119 try appendEscaped(out, slice);
1120 try out.appendSlice(gpa, "</span>");
1121 },
1122
1123 .bang,
1124 .pipe,
1125 .pipe_pipe,
1126 .pipe_equal,
1127 .equal,
1128 .equal_equal,
1129 .equal_angle_bracket_right,
1130 .bang_equal,
1131 .l_paren,
1132 .r_paren,
1133 .semicolon,
1134 .percent,
1135 .percent_equal,
1136 .l_brace,
1137 .r_brace,
1138 .l_bracket,
1139 .r_bracket,
1140 .period,
1141 .period_asterisk,
1142 .ellipsis2,
1143 .ellipsis3,
1144 .caret,
1145 .caret_equal,
1146 .plus,
1147 .plus_plus,
1148 .plus_equal,
1149 .plus_percent,
1150 .plus_percent_equal,
1151 .plus_pipe,
1152 .plus_pipe_equal,
1153 .minus,
1154 .minus_equal,
1155 .minus_percent,
1156 .minus_percent_equal,
1157 .minus_pipe,
1158 .minus_pipe_equal,
1159 .asterisk,
1160 .asterisk_equal,
1161 .asterisk_asterisk,
1162 .asterisk_percent,
1163 .asterisk_percent_equal,
1164 .asterisk_pipe,
1165 .asterisk_pipe_equal,
1166 .arrow,
1167 .colon,
1168 .slash,
1169 .slash_equal,
1170 .comma,
1171 .ampersand,
1172 .ampersand_equal,
1173 .question_mark,
1174 .angle_bracket_left,
1175 .angle_bracket_left_equal,
1176 .angle_bracket_angle_bracket_left,
1177 .angle_bracket_angle_bracket_left_equal,
1178 .angle_bracket_angle_bracket_left_pipe,
1179 .angle_bracket_angle_bracket_left_pipe_equal,
1180 .angle_bracket_right,
1181 .angle_bracket_right_equal,
1182 .angle_bracket_angle_bracket_right,
1183 .angle_bracket_angle_bracket_right_equal,
1184 .tilde,
1185 => try appendEscaped(out, slice),
1186
1187 .invalid, .invalid_periodasterisks => return error.InvalidToken,
1188 }
1189 }
1190}
1191
1192fn resolve_ident_link(
1193 file_index: Walk.File.Index,
1194 out: *std.ArrayListUnmanaged(u8),
1195 ident_token: Ast.TokenIndex,
1196) Oom!void {
1197 const decl_index = file_index.get().lookup_token(ident_token);
1198 if (decl_index == .none) return;
1199 try resolve_decl_link(decl_index, out);
1200}
1201
1202fn resolve_decl_link(decl_index: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void {
1203 const decl = decl_index.get();
1204 switch (decl.categorize()) {
1205 .alias => |alias_decl| try alias_decl.get().fqn(out),
1206 else => try decl.fqn(out),
1207 }
1208}
1209
1210fn walk_field_accesses(
1211 file_index: Walk.File.Index,
1212 out: *std.ArrayListUnmanaged(u8),
1213 node: Ast.Node.Index,
1214) Oom!void {
1215 const ast = file_index.get_ast();
1216 const node_tags = ast.nodes.items(.tag);
1217 assert(node_tags[node] == .field_access);
1218 const node_datas = ast.nodes.items(.data);
1219 const main_tokens = ast.nodes.items(.main_token);
1220 const object_node = node_datas[node].lhs;
1221 const dot_token = main_tokens[node];
1222 const field_ident = dot_token + 1;
1223 switch (node_tags[object_node]) {
1224 .identifier => {
1225 const lhs_ident = main_tokens[object_node];
1226 try resolve_ident_link(file_index, out, lhs_ident);
1227 },
1228 .field_access => {
1229 try walk_field_accesses(file_index, out, object_node);
1230 },
1231 else => {},
1232 }
1233 if (out.items.len > 0) {
1234 try out.append(gpa, '.');
1235 try out.appendSlice(gpa, ast.tokenSlice(field_ident));
1236 }
1237}
1238
1239fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {
1240 for (s) |c| {
1241 try out.ensureUnusedCapacity(gpa, 6);
1242 switch (c) {
1243 '&' => out.appendSliceAssumeCapacity("&amp;"),
1244 '<' => out.appendSliceAssumeCapacity("&lt;"),
1245 '>' => out.appendSliceAssumeCapacity("&gt;"),
1246 '"' => out.appendSliceAssumeCapacity("&quot;"),
1247 else => out.appendAssumeCapacity(c),
1248 }
1249 }
1250}
1251
1252fn count_scalar(haystack: []const u8, needle: u8) usize {
1253 var total: usize = 0;
1254 for (haystack) |elem| {
1255 if (elem == needle)
1256 total += 1;
1257 }
1258 return total;
1259}
lib/docs/wasm/markdown.zig created+940
......@@ -0,0 +1,940 @@
1//! Markdown parsing and rendering support.
2//!
3//! A Markdown document consists of a series of blocks. Depending on its type,
4//! each block may contain other blocks, inline content, or nothing. The
5//! supported blocks are as follows:
6//!
7//! - **List** - a sequence of list items of the same type.
8//!
9//! - **List item** - unordered list items start with `-`, `*`, or `+` followed
10//! by a space. Ordered list items start with a number between 0 and
11//! 999,999,999, followed by a `.` or `)` and a space. The number of an
12//! ordered list item only matters for the first item in the list (to
13//! determine the starting number of the list). All subsequent ordered list
14//! items will have sequentially increasing numbers.
15//!
16//! All list items may contain block content. Any content indented at least as
17//! far as the end of the list item marker (including the space after it) is
18//! considered part of the list item.
19//!
20//! Lists which have no blank lines between items or between direct children
21//! of items are considered _tight_, and direct child paragraphs of tight list
22//! items are rendered without `<p>` tags.
23//!
24//! - **Table** - a sequence of adjacent table row lines, where each line starts
25//! and ends with a `|`, and cells within the row are delimited by `|`s.
26//!
27//! The first or second row of a table may be a _header delimiter row_, which
28//! is a row consisting of cells of the pattern `---` (for unset column
29//! alignment), `:--` (for left alignment), `:-:` (for center alignment), or
30//! `--:` (for right alignment). The number of `-`s must be at least one, but
31//! is otherwise arbitrary. If there is a row just before the header delimiter
32//! row, it becomes the header row for the table (a table need not have a
33//! header row at all).
34//!
35//! - **Heading** - a sequence of between 1 and 6 `#` characters, followed by a
36//! space and further inline content on the same line.
37//!
38//! - **Code block** - a sequence of at least 3 `` ` `` characters (a _fence_),
39//! optionally followed by a "tag" on the same line, and continuing until a
40//! line consisting only of a closing fence whose length matches the opening
41//! fence, or until the end of the containing block.
42//!
43//! The content of a code block is not parsed as inline content. It is
44//! included verbatim in the output document (minus leading indentation up to
45//! the position of the opening fence).
46//!
47//! - **Blockquote** - a sequence of lines preceded by `>` characters.
48//!
49//! - **Paragraph** - ordinary text, parsed as inline content, ending with a
50//! blank line or the end of the containing block.
51//!
52//! Paragraphs which are part of another block may be "lazily" continued by
53//! subsequent paragraph lines even if those lines would not ordinarily be
54//! considered part of the containing block. For example, this is a single
55//! list item, not a list item followed by a paragraph:
56//!
57//! ```markdown
58//! - First line of content.
59//! This content is still part of the paragraph,
60//! even though it isn't indented far enough.
61//! ```
62//!
63//! - **Thematic break** - a line consisting of at least three matching `-`,
64//! `_`, or `*` characters and, optionally, spaces.
65//!
66//! Indentation may consist of spaces and tabs. The use of tabs is not
67//! recommended: a tab is treated the same as a single space for the purpose of
68//! determining the indentation level, and is not recognized as a space for
69//! block starters which require one (for example, `-` followed by a tab is not
70//! a valid list item).
71//!
72//! The supported inlines are as follows:
73//!
74//! - **Link** - of the format `[text](target)`. `text` may contain inline
75//! content. `target` may contain `\`-escaped characters and balanced
76//! parentheses.
77//!
78//! - **Image** - a link directly preceded by a `!`. The link text is
79//! interpreted as the alt text of the image.
80//!
81//! - **Emphasis** - a run of `*` or `_` characters may be an emphasis opener,
82//! closer, or both. For `*` characters, the run may be an opener as long as
83//! it is not directly followed by a whitespace character (or the end of the
84//! inline content) and a closer as long as it is not directly preceded by
85//! one. For `_` characters, this rule is strengthened by requiring that the
86//! run also be preceded by a whitespace or punctuation character (for
87//! openers) or followed by one (for closers), to avoid mangling `snake_case`
88//! words.
89//!
90//! The rule for emphasis handling is greedy: any run that can close existing
91//! emphasis will do so, otherwise it will open emphasis. A single run may
92//! serve both functions: the middle `**` in the following example both closes
93//! the initial emphasis and opens a new one:
94//!
95//! ```markdown
96//! *one**two*
97//! ```
98//!
99//! A single `*` or `_` is used for normal emphasis (HTML `<em>`), and a
100//! double `**` or `__` is used for strong emphasis (HTML `<strong>`). Even
101//! longer runs may be used to produce further nested emphasis (though only
102//! `***` and `___` to produce `<em><strong>` is really useful).
103//!
104//! - **Code span** - a run of `` ` `` characters, terminated by a matching run
105//! or the end of inline content. The content of a code span is not parsed
106//! further.
107//!
108//! - **Text** - normal text is interpreted as-is, except that `\` may be used
109//! to escape any punctuation character, preventing it from being interpreted
110//! according to other syntax rules. A `\` followed by a line break within a
111//! paragraph is interpreted as a hard line break.
112//!
113//! Any null bytes or invalid UTF-8 bytes within text are replaced with Unicode
114//! replacement characters, `U+FFFD`.
115
116const std = @import("std");
117const testing = std.testing;
118
119pub const Document = @import("markdown/Document.zig");
120pub const Parser = @import("markdown/Parser.zig");
121pub const Renderer = @import("markdown/renderer.zig").Renderer;
122pub const renderNodeInlineText = @import("markdown/renderer.zig").renderNodeInlineText;
123pub const fmtHtml = @import("markdown/renderer.zig").fmtHtml;
124
125// Avoid exposing main to other files merely importing this one.
126pub const main = if (@import("root") == @This())
127 mainImpl
128else
129 @compileError("only available as root source file");
130
131fn mainImpl() !void {
132 const gpa = std.heap.c_allocator;
133
134 var parser = try Parser.init(gpa);
135 defer parser.deinit();
136
137 var stdin_buf = std.io.bufferedReader(std.io.getStdIn().reader());
138 var line_buf = std.ArrayList(u8).init(gpa);
139 defer line_buf.deinit();
140 while (stdin_buf.reader().streamUntilDelimiter(line_buf.writer(), '\n', null)) {
141 if (line_buf.getLastOrNull() == '\r') _ = line_buf.pop();
142 try parser.feedLine(line_buf.items);
143 line_buf.clearRetainingCapacity();
144 } else |err| switch (err) {
145 error.EndOfStream => {},
146 else => |e| return e,
147 }
148
149 var doc = try parser.endInput();
150 defer doc.deinit(gpa);
151
152 var stdout_buf = std.io.bufferedWriter(std.io.getStdOut().writer());
153 try doc.render(stdout_buf.writer());
154 try stdout_buf.flush();
155}
156
157test "empty document" {
158 try testRender("", "");
159 try testRender(" ", "");
160 try testRender("\n \n\t\n \n", "");
161}
162
163test "unordered lists" {
164 try testRender(
165 \\- Spam
166 \\- Spam
167 \\- Spam
168 \\- Eggs
169 \\- Bacon
170 \\- Spam
171 \\
172 \\* Spam
173 \\* Spam
174 \\* Spam
175 \\* Eggs
176 \\* Bacon
177 \\* Spam
178 \\
179 \\+ Spam
180 \\+ Spam
181 \\+ Spam
182 \\+ Eggs
183 \\+ Bacon
184 \\+ Spam
185 \\
186 ,
187 \\<ul>
188 \\<li>Spam</li>
189 \\<li>Spam</li>
190 \\<li>Spam</li>
191 \\<li>Eggs</li>
192 \\<li>Bacon</li>
193 \\<li>Spam</li>
194 \\</ul>
195 \\<ul>
196 \\<li>Spam</li>
197 \\<li>Spam</li>
198 \\<li>Spam</li>
199 \\<li>Eggs</li>
200 \\<li>Bacon</li>
201 \\<li>Spam</li>
202 \\</ul>
203 \\<ul>
204 \\<li>Spam</li>
205 \\<li>Spam</li>
206 \\<li>Spam</li>
207 \\<li>Eggs</li>
208 \\<li>Bacon</li>
209 \\<li>Spam</li>
210 \\</ul>
211 \\
212 );
213}
214
215test "ordered lists" {
216 try testRender(
217 \\1. Breakfast
218 \\2. Second breakfast
219 \\3. Lunch
220 \\2. Afternoon snack
221 \\1. Dinner
222 \\6. Dessert
223 \\7. Midnight snack
224 \\
225 \\1) Breakfast
226 \\2) Second breakfast
227 \\3) Lunch
228 \\2) Afternoon snack
229 \\1) Dinner
230 \\6) Dessert
231 \\7) Midnight snack
232 \\
233 \\1001. Breakfast
234 \\2. Second breakfast
235 \\3. Lunch
236 \\2. Afternoon snack
237 \\1. Dinner
238 \\6. Dessert
239 \\7. Midnight snack
240 \\
241 \\1001) Breakfast
242 \\2) Second breakfast
243 \\3) Lunch
244 \\2) Afternoon snack
245 \\1) Dinner
246 \\6) Dessert
247 \\7) Midnight snack
248 \\
249 ,
250 \\<ol>
251 \\<li>Breakfast</li>
252 \\<li>Second breakfast</li>
253 \\<li>Lunch</li>
254 \\<li>Afternoon snack</li>
255 \\<li>Dinner</li>
256 \\<li>Dessert</li>
257 \\<li>Midnight snack</li>
258 \\</ol>
259 \\<ol>
260 \\<li>Breakfast</li>
261 \\<li>Second breakfast</li>
262 \\<li>Lunch</li>
263 \\<li>Afternoon snack</li>
264 \\<li>Dinner</li>
265 \\<li>Dessert</li>
266 \\<li>Midnight snack</li>
267 \\</ol>
268 \\<ol start="1001">
269 \\<li>Breakfast</li>
270 \\<li>Second breakfast</li>
271 \\<li>Lunch</li>
272 \\<li>Afternoon snack</li>
273 \\<li>Dinner</li>
274 \\<li>Dessert</li>
275 \\<li>Midnight snack</li>
276 \\</ol>
277 \\<ol start="1001">
278 \\<li>Breakfast</li>
279 \\<li>Second breakfast</li>
280 \\<li>Lunch</li>
281 \\<li>Afternoon snack</li>
282 \\<li>Dinner</li>
283 \\<li>Dessert</li>
284 \\<li>Midnight snack</li>
285 \\</ol>
286 \\
287 );
288}
289
290test "nested lists" {
291 try testRender(
292 \\- - Item 1.
293 \\ - Item 2.
294 \\Item 2 continued.
295 \\ * New list.
296 \\
297 ,
298 \\<ul>
299 \\<li><ul>
300 \\<li>Item 1.</li>
301 \\<li>Item 2.
302 \\Item 2 continued.</li>
303 \\</ul>
304 \\<ul>
305 \\<li>New list.</li>
306 \\</ul>
307 \\</li>
308 \\</ul>
309 \\
310 );
311}
312
313test "lists with block content" {
314 try testRender(
315 \\1. Item 1.
316 \\2. Item 2.
317 \\
318 \\ This one has another paragraph.
319 \\3. Item 3.
320 \\
321 \\- > Blockquote.
322 \\- - Sub-list.
323 \\ - Sub-list continued.
324 \\ * Different sub-list.
325 \\- ## Heading.
326 \\
327 \\ Some contents below the heading.
328 \\ 1. Item 1.
329 \\ 2. Item 2.
330 \\ 3. Item 3.
331 \\
332 ,
333 \\<ol>
334 \\<li><p>Item 1.</p>
335 \\</li>
336 \\<li><p>Item 2.</p>
337 \\<p>This one has another paragraph.</p>
338 \\</li>
339 \\<li><p>Item 3.</p>
340 \\</li>
341 \\</ol>
342 \\<ul>
343 \\<li><blockquote>
344 \\<p>Blockquote.</p>
345 \\</blockquote>
346 \\</li>
347 \\<li><ul>
348 \\<li>Sub-list.</li>
349 \\<li>Sub-list continued.</li>
350 \\</ul>
351 \\<ul>
352 \\<li>Different sub-list.</li>
353 \\</ul>
354 \\</li>
355 \\<li><h2>Heading.</h2>
356 \\<p>Some contents below the heading.</p>
357 \\<ol>
358 \\<li>Item 1.</li>
359 \\<li>Item 2.</li>
360 \\<li>Item 3.</li>
361 \\</ol>
362 \\</li>
363 \\</ul>
364 \\
365 );
366}
367
368test "tables" {
369 try testRender(
370 \\| Operator | Meaning |
371 \\| :------: | ---------------- |
372 \\| `+` | Add |
373 \\| `-` | Subtract |
374 \\| `*` | Multiply |
375 \\| `/` | Divide |
376 \\| `??` | **Not sure yet** |
377 \\
378 \\| Item 1 | Value 1 |
379 \\| Item 2 | Value 2 |
380 \\| Item 3 | Value 3 |
381 \\| Item 4 | Value 4 |
382 \\
383 \\| :--- | :----: | ----: |
384 \\| Left | Center | Right |
385 \\
386 ,
387 \\<table>
388 \\<tr>
389 \\<th style="text-align: center">Operator</th>
390 \\<th>Meaning</th>
391 \\</tr>
392 \\<tr>
393 \\<td style="text-align: center"><code>+</code></td>
394 \\<td>Add</td>
395 \\</tr>
396 \\<tr>
397 \\<td style="text-align: center"><code>-</code></td>
398 \\<td>Subtract</td>
399 \\</tr>
400 \\<tr>
401 \\<td style="text-align: center"><code>*</code></td>
402 \\<td>Multiply</td>
403 \\</tr>
404 \\<tr>
405 \\<td style="text-align: center"><code>/</code></td>
406 \\<td>Divide</td>
407 \\</tr>
408 \\<tr>
409 \\<td style="text-align: center"><code>??</code></td>
410 \\<td><strong>Not sure yet</strong></td>
411 \\</tr>
412 \\</table>
413 \\<table>
414 \\<tr>
415 \\<td>Item 1</td>
416 \\<td>Value 1</td>
417 \\</tr>
418 \\<tr>
419 \\<td>Item 2</td>
420 \\<td>Value 2</td>
421 \\</tr>
422 \\<tr>
423 \\<td>Item 3</td>
424 \\<td>Value 3</td>
425 \\</tr>
426 \\<tr>
427 \\<td>Item 4</td>
428 \\<td>Value 4</td>
429 \\</tr>
430 \\</table>
431 \\<table>
432 \\<tr>
433 \\<td style="text-align: left">Left</td>
434 \\<td style="text-align: center">Center</td>
435 \\<td style="text-align: right">Right</td>
436 \\</tr>
437 \\</table>
438 \\
439 );
440}
441
442test "table with uneven number of columns" {
443 try testRender(
444 \\| One |
445 \\| :-- | :--: |
446 \\| One | Two | Three |
447 \\
448 ,
449 \\<table>
450 \\<tr>
451 \\<th style="text-align: left">One</th>
452 \\</tr>
453 \\<tr>
454 \\<td style="text-align: left">One</td>
455 \\<td style="text-align: center">Two</td>
456 \\<td>Three</td>
457 \\</tr>
458 \\</table>
459 \\
460 );
461}
462
463test "table with escaped pipes" {
464 try testRender(
465 \\| One \| Two |
466 \\| --- | --- |
467 \\| One \| Two |
468 \\
469 ,
470 \\<table>
471 \\<tr>
472 \\<th>One | Two</th>
473 \\</tr>
474 \\<tr>
475 \\<td>One | Two</td>
476 \\</tr>
477 \\</table>
478 \\
479 );
480}
481
482test "table with pipes in code spans" {
483 try testRender(
484 \\| `|` | Bitwise _OR_ |
485 \\| `||` | Combines error sets |
486 \\| `` `||` `` | Escaped version |
487 \\| ` ``||`` ` | Another escaped version |
488 \\| `Oops unterminated code span |
489 \\
490 ,
491 \\<table>
492 \\<tr>
493 \\<td><code>|</code></td>
494 \\<td>Bitwise <em>OR</em></td>
495 \\</tr>
496 \\<tr>
497 \\<td><code>||</code></td>
498 \\<td>Combines error sets</td>
499 \\</tr>
500 \\<tr>
501 \\<td><code>`||`</code></td>
502 \\<td>Escaped version</td>
503 \\</tr>
504 \\<tr>
505 \\<td><code>``||``</code></td>
506 \\<td>Another escaped version</td>
507 \\</tr>
508 \\</table>
509 \\<p>| <code>Oops unterminated code span |</code></p>
510 \\
511 );
512}
513
514test "tables require leading and trailing pipes" {
515 try testRender(
516 \\Not | a | table
517 \\
518 \\| But | this | is |
519 \\
520 \\Also not a table:
521 \\|
522 \\ |
523 \\
524 ,
525 \\<p>Not | a | table</p>
526 \\<table>
527 \\<tr>
528 \\<td>But</td>
529 \\<td>this</td>
530 \\<td>is</td>
531 \\</tr>
532 \\</table>
533 \\<p>Also not a table:
534 \\|
535 \\|</p>
536 \\
537 );
538}
539
540test "headings" {
541 try testRender(
542 \\# Level one
543 \\## Level two
544 \\### Level three
545 \\#### Level four
546 \\##### Level five
547 \\###### Level six
548 \\####### Not a heading
549 \\
550 ,
551 \\<h1>Level one</h1>
552 \\<h2>Level two</h2>
553 \\<h3>Level three</h3>
554 \\<h4>Level four</h4>
555 \\<h5>Level five</h5>
556 \\<h6>Level six</h6>
557 \\<p>####### Not a heading</p>
558 \\
559 );
560}
561
562test "headings with inline content" {
563 try testRender(
564 \\# Outline of `std.zig`
565 \\## **Important** notes
566 \\### ***Nested* inline content**
567 \\
568 ,
569 \\<h1>Outline of <code>std.zig</code></h1>
570 \\<h2><strong>Important</strong> notes</h2>
571 \\<h3><strong><em>Nested</em> inline content</strong></h3>
572 \\
573 );
574}
575
576test "code blocks" {
577 try testRender(
578 \\```
579 \\Hello, world!
580 \\This is some code.
581 \\```
582 \\``` zig test
583 \\const std = @import("std");
584 \\
585 \\test {
586 \\ try std.testing.expect(2 + 2 == 4);
587 \\}
588 \\```
589 \\
590 ,
591 \\<pre><code>Hello, world!
592 \\This is some code.
593 \\</code></pre>
594 \\<pre><code>const std = @import(&quot;std&quot;);
595 \\
596 \\test {
597 \\ try std.testing.expect(2 + 2 == 4);
598 \\}
599 \\</code></pre>
600 \\
601 );
602}
603
604test "blockquotes" {
605 try testRender(
606 \\> > You miss 100% of the shots you don't take.
607 \\> >
608 \\> > ~ Wayne Gretzky
609 \\>
610 \\> ~ Michael Scott
611 \\
612 ,
613 \\<blockquote>
614 \\<blockquote>
615 \\<p>You miss 100% of the shots you don't take.</p>
616 \\<p>~ Wayne Gretzky</p>
617 \\</blockquote>
618 \\<p>~ Michael Scott</p>
619 \\</blockquote>
620 \\
621 );
622}
623
624test "blockquote lazy continuation lines" {
625 try testRender(
626 \\>>>>Deeply nested blockquote
627 \\>>which continues on another line
628 \\and then yet another one.
629 \\>>
630 \\>> But now two of them have been closed.
631 \\
632 \\And then there were none.
633 \\
634 ,
635 \\<blockquote>
636 \\<blockquote>
637 \\<blockquote>
638 \\<blockquote>
639 \\<p>Deeply nested blockquote
640 \\which continues on another line
641 \\and then yet another one.</p>
642 \\</blockquote>
643 \\</blockquote>
644 \\<p>But now two of them have been closed.</p>
645 \\</blockquote>
646 \\</blockquote>
647 \\<p>And then there were none.</p>
648 \\
649 );
650}
651
652test "paragraphs" {
653 try testRender(
654 \\Paragraph one.
655 \\
656 \\Paragraph two.
657 \\Still in the paragraph.
658 \\ So is this.
659 \\
660 \\
661 \\
662 \\
663 \\ Last paragraph.
664 \\
665 ,
666 \\<p>Paragraph one.</p>
667 \\<p>Paragraph two.
668 \\Still in the paragraph.
669 \\So is this.</p>
670 \\<p>Last paragraph.</p>
671 \\
672 );
673}
674
675test "thematic breaks" {
676 try testRender(
677 \\---
678 \\***
679 \\___
680 \\ ---
681 \\ - - - - - - - - - - -
682 \\
683 ,
684 \\<hr />
685 \\<hr />
686 \\<hr />
687 \\<hr />
688 \\<hr />
689 \\
690 );
691}
692
693test "links" {
694 try testRender(
695 \\[Link](https://example.com)
696 \\[Link *with inlines*](https://example.com)
697 \\[Nested parens](https://example.com/nested(parens(inside)))
698 \\[Escaped parens](https://example.com/\)escaped\()
699 \\[Line break in target](test\
700 \\target)
701 \\
702 ,
703 \\<p><a href="https://example.com">Link</a>
704 \\<a href="https://example.com">Link <em>with inlines</em></a>
705 \\<a href="https://example.com/nested(parens(inside))">Nested parens</a>
706 \\<a href="https://example.com/)escaped(">Escaped parens</a>
707 \\<a href="test\
708 \\target">Line break in target</a></p>
709 \\
710 );
711}
712
713test "images" {
714 try testRender(
715 \\![Alt text](https://example.com/image.png)
716 \\![Alt text *with inlines*](https://example.com/image.png)
717 \\![Nested parens](https://example.com/nested(parens(inside)).png)
718 \\![Escaped parens](https://example.com/\)escaped\(.png)
719 \\![Line break in target](test\
720 \\target)
721 \\
722 ,
723 \\<p><img src="https://example.com/image.png" alt="Alt text" />
724 \\<img src="https://example.com/image.png" alt="Alt text with inlines" />
725 \\<img src="https://example.com/nested(parens(inside)).png" alt="Nested parens" />
726 \\<img src="https://example.com/)escaped(.png" alt="Escaped parens" />
727 \\<img src="test\
728 \\target" alt="Line break in target" /></p>
729 \\
730 );
731}
732
733test "emphasis" {
734 try testRender(
735 \\*Emphasis.*
736 \\**Strong.**
737 \\***Strong emphasis.***
738 \\****More...****
739 \\*****MORE...*****
740 \\******Even more...******
741 \\*******OK, this is enough.*******
742 \\
743 ,
744 \\<p><em>Emphasis.</em>
745 \\<strong>Strong.</strong>
746 \\<em><strong>Strong emphasis.</strong></em>
747 \\<em><strong><em>More...</em></strong></em>
748 \\<em><strong><strong>MORE...</strong></strong></em>
749 \\<em><strong><em><strong>Even more...</strong></em></strong></em>
750 \\<em><strong><em><strong><em>OK, this is enough.</em></strong></em></strong></em></p>
751 \\
752 );
753 try testRender(
754 \\_Emphasis._
755 \\__Strong.__
756 \\___Strong emphasis.___
757 \\____More...____
758 \\_____MORE..._____
759 \\______Even more...______
760 \\_______OK, this is enough._______
761 \\
762 ,
763 \\<p><em>Emphasis.</em>
764 \\<strong>Strong.</strong>
765 \\<em><strong>Strong emphasis.</strong></em>
766 \\<em><strong><em>More...</em></strong></em>
767 \\<em><strong><strong>MORE...</strong></strong></em>
768 \\<em><strong><em><strong>Even more...</strong></em></strong></em>
769 \\<em><strong><em><strong><em>OK, this is enough.</em></strong></em></strong></em></p>
770 \\
771 );
772}
773
774test "nested emphasis" {
775 try testRender(
776 \\**Hello, *world!***
777 \\*Hello, **world!***
778 \\**Hello, _world!_**
779 \\_Hello, **world!**_
780 \\*Hello, **nested** *world!**
781 \\***Hello,* world!**
782 \\__**Hello, world!**__
783 \\****Hello,** world!**
784 \\__Hello,_ world!_
785 \\*Test**123*
786 \\__Test____123__
787 \\
788 ,
789 \\<p><strong>Hello, <em>world!</em></strong>
790 \\<em>Hello, <strong>world!</strong></em>
791 \\<strong>Hello, <em>world!</em></strong>
792 \\<em>Hello, <strong>world!</strong></em>
793 \\<em>Hello, <strong>nested</strong> <em>world!</em></em>
794 \\<strong><em>Hello,</em> world!</strong>
795 \\<strong><strong>Hello, world!</strong></strong>
796 \\<strong><strong>Hello,</strong> world!</strong>
797 \\<em><em>Hello,</em> world!</em>
798 \\<em>Test</em><em>123</em>
799 \\<strong>Test____123</strong></p>
800 \\
801 );
802}
803
804test "emphasis precedence" {
805 try testRender(
806 \\*First one _wins*_.
807 \\_*No other __rule matters.*_
808 \\
809 ,
810 \\<p><em>First one _wins</em>_.
811 \\<em><em>No other __rule matters.</em></em></p>
812 \\
813 );
814}
815
816test "emphasis open and close" {
817 try testRender(
818 \\Cannot open: *
819 \\Cannot open: _
820 \\*Cannot close: *
821 \\_Cannot close: _
822 \\
823 \\foo*bar*baz
824 \\foo_bar_baz
825 \\foo**bar**baz
826 \\foo__bar__baz
827 \\
828 ,
829 \\<p>Cannot open: *
830 \\Cannot open: _
831 \\*Cannot close: *
832 \\_Cannot close: _</p>
833 \\<p>foo<em>bar</em>baz
834 \\foo_bar_baz
835 \\foo<strong>bar</strong>baz
836 \\foo__bar__baz</p>
837 \\
838 );
839}
840
841test "code spans" {
842 try testRender(
843 \\`Hello, world!`
844 \\```Multiple `backticks` can be used.```
845 \\`**This** does not produce emphasis.`
846 \\`` `Backtick enclosed string.` ``
847 \\`Delimiter lengths ```must``` match.`
848 \\
849 \\Unterminated ``code...
850 \\
851 \\Weird empty code span: `
852 \\
853 \\**Very important code: `hi`**
854 \\
855 ,
856 \\<p><code>Hello, world!</code>
857 \\<code>Multiple `backticks` can be used.</code>
858 \\<code>**This** does not produce emphasis.</code>
859 \\<code>`Backtick enclosed string.`</code>
860 \\<code>Delimiter lengths ```must``` match.</code></p>
861 \\<p>Unterminated <code>code...</code></p>
862 \\<p>Weird empty code span: <code></code></p>
863 \\<p><strong>Very important code: <code>hi</code></strong></p>
864 \\
865 );
866}
867
868test "backslash escapes" {
869 try testRender(
870 \\Not \*emphasized\*.
871 \\Literal \\backslashes\\.
872 \\Not code: \`hi\`.
873 \\\# Not a title.
874 \\#\# Also not a title.
875 \\\> Not a blockquote.
876 \\\- Not a list item.
877 \\\| Not a table. |
878 \\| Also not a table. \|
879 \\Any \punctuation\ characte\r can be escaped:
880 \\\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
881 \\
882 ,
883 \\<p>Not *emphasized*.
884 \\Literal \backslashes\.
885 \\Not code: `hi`.
886 \\# Not a title.
887 \\## Also not a title.
888 \\&gt; Not a blockquote.
889 \\- Not a list item.
890 \\| Not a table. |
891 \\| Also not a table. |
892 \\Any \punctuation\ characte\r can be escaped:
893 \\!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
894 \\
895 );
896}
897
898test "hard line breaks" {
899 try testRender(
900 \\The iguana sits\
901 \\Perched atop a short desk chair\
902 \\Writing code in Zig
903 \\
904 ,
905 \\<p>The iguana sits<br />
906 \\Perched atop a short desk chair<br />
907 \\Writing code in Zig</p>
908 \\
909 );
910}
911
912test "Unicode handling" {
913 // Null bytes must be replaced.
914 try testRender("\x00\x00\x00", "<p>\u{FFFD}\u{FFFD}\u{FFFD}</p>\n");
915
916 // Invalid UTF-8 must be replaced.
917 try testRender("\xC0\x80\xE0\x80\x80\xF0\x80\x80\x80", "<p>\u{FFFD}\u{FFFD}\u{FFFD}</p>\n");
918 try testRender("\xED\xA0\x80\xED\xBF\xBF", "<p>\u{FFFD}\u{FFFD}</p>\n");
919
920 // Incomplete UTF-8 must be replaced.
921 try testRender("\xE2\x82", "<p>\u{FFFD}</p>\n");
922}
923
924fn testRender(input: []const u8, expected: []const u8) !void {
925 var parser = try Parser.init(testing.allocator);
926 defer parser.deinit();
927
928 var lines = std.mem.split(u8, input, "\n");
929 while (lines.next()) |line| {
930 try parser.feedLine(line);
931 }
932 var doc = try parser.endInput();
933 defer doc.deinit(testing.allocator);
934
935 var actual = std.ArrayList(u8).init(testing.allocator);
936 defer actual.deinit();
937 try doc.render(actual.writer());
938
939 try testing.expectEqualStrings(expected, actual.items);
940}
lib/docs/wasm/markdown/Document.zig created+192
......@@ -0,0 +1,192 @@
1//! An abstract tree representation of a Markdown document.
2
3const std = @import("std");
4const builtin = @import("builtin");
5const assert = std.debug.assert;
6const Allocator = std.mem.Allocator;
7const Renderer = @import("renderer.zig").Renderer;
8
9nodes: Node.List.Slice,
10extra: []u32,
11string_bytes: []u8,
12
13const Document = @This();
14
15pub const Node = struct {
16 tag: Tag,
17 data: Data,
18
19 pub const Index = enum(u32) {
20 root = 0,
21 _,
22 };
23 pub const List = std.MultiArrayList(Node);
24
25 pub const Tag = enum {
26 /// Data is `container`.
27 root,
28
29 // Blocks
30 /// Data is `list`.
31 list,
32 /// Data is `list_item`.
33 list_item,
34 /// Data is `container`.
35 table,
36 /// Data is `container`.
37 table_row,
38 /// Data is `table_cell`.
39 table_cell,
40 /// Data is `heading`.
41 heading,
42 /// Data is `code_block`.
43 code_block,
44 /// Data is `container`.
45 blockquote,
46 /// Data is `container`.
47 paragraph,
48 /// Data is `none`.
49 thematic_break,
50
51 // Inlines
52 /// Data is `link`.
53 link,
54 /// Data is `link`.
55 image,
56 /// Data is `container`.
57 strong,
58 /// Data is `container`.
59 emphasis,
60 /// Data is `text`.
61 code_span,
62 /// Data is `text`.
63 text,
64 /// Data is `none`.
65 line_break,
66 };
67
68 pub const Data = union {
69 none: void,
70 container: struct {
71 children: ExtraIndex,
72 },
73 text: struct {
74 content: StringIndex,
75 },
76 list: struct {
77 start: ListStart,
78 children: ExtraIndex,
79 },
80 list_item: struct {
81 tight: bool,
82 children: ExtraIndex,
83 },
84 table_cell: struct {
85 info: packed struct {
86 alignment: TableCellAlignment,
87 header: bool,
88 },
89 children: ExtraIndex,
90 },
91 heading: struct {
92 /// Between 1 and 6, inclusive.
93 level: u3,
94 children: ExtraIndex,
95 },
96 code_block: struct {
97 tag: StringIndex,
98 content: StringIndex,
99 },
100 link: struct {
101 target: StringIndex,
102 children: ExtraIndex,
103 },
104
105 comptime {
106 // In Debug and ReleaseSafe builds, there may be hidden extra fields
107 // included for safety checks. Without such safety checks enabled,
108 // we always want this union to be 8 bytes.
109 if (builtin.mode != .Debug and builtin.mode != .ReleaseSafe) {
110 assert(@sizeOf(Data) == 8);
111 }
112 }
113 };
114
115 /// The starting number of a list. This is either a number between 0 and
116 /// 999,999,999, inclusive, or `unordered` to indicate an unordered list.
117 pub const ListStart = enum(u30) {
118 // When https://github.com/ziglang/zig/issues/104 is implemented, this
119 // type can be more naturally expressed as ?u30. As it is, we want
120 // values to fit within 4 bytes, so ?u30 does not yet suffice for
121 // storage.
122 unordered = std.math.maxInt(u30),
123 _,
124
125 pub fn asNumber(start: ListStart) ?u30 {
126 if (start == .unordered) return null;
127 assert(@intFromEnum(start) <= 999_999_999);
128 return @intFromEnum(start);
129 }
130 };
131
132 pub const TableCellAlignment = enum {
133 unset,
134 left,
135 center,
136 right,
137 };
138
139 /// Trailing: `len` times `Node.Index`
140 pub const Children = struct {
141 len: u32,
142 };
143};
144
145pub const ExtraIndex = enum(u32) { _ };
146
147/// The index of a null-terminated string in `string_bytes`.
148pub const StringIndex = enum(u32) {
149 empty = 0,
150 _,
151};
152
153pub fn deinit(doc: *Document, allocator: Allocator) void {
154 doc.nodes.deinit(allocator);
155 allocator.free(doc.extra);
156 allocator.free(doc.string_bytes);
157 doc.* = undefined;
158}
159
160/// Renders a document directly to a writer using the default renderer.
161pub fn render(doc: Document, writer: anytype) @TypeOf(writer).Error!void {
162 const renderer: Renderer(@TypeOf(writer), void) = .{ .context = {} };
163 try renderer.render(doc, writer);
164}
165
166pub fn ExtraData(comptime T: type) type {
167 return struct { data: T, end: usize };
168}
169
170pub fn extraData(doc: Document, comptime T: type, index: ExtraIndex) ExtraData(T) {
171 const fields = @typeInfo(T).Struct.fields;
172 var i: usize = @intFromEnum(index);
173 var result: T = undefined;
174 inline for (fields) |field| {
175 @field(result, field.name) = switch (field.type) {
176 u32 => doc.extra[i],
177 else => @compileError("bad field type"),
178 };
179 i += 1;
180 }
181 return .{ .data = result, .end = i };
182}
183
184pub fn extraChildren(doc: Document, index: ExtraIndex) []const Node.Index {
185 const children = doc.extraData(Node.Children, index);
186 return @ptrCast(doc.extra[children.end..][0..children.data.len]);
187}
188
189pub fn string(doc: Document, index: StringIndex) [:0]const u8 {
190 const start = @intFromEnum(index);
191 return std.mem.span(@as([*:0]u8, @ptrCast(doc.string_bytes[start..].ptr)));
192}
lib/docs/wasm/markdown/Parser.zig created+1501
......@@ -0,0 +1,1501 @@
1//! A Markdown parser producing `Document`s.
2//!
3//! The parser operates at two levels: at the outer level, the parser accepts
4//! the content of an input document line by line and begins building the _block
5//! structure_ of the document. This creates a stack of currently open blocks.
6//!
7//! When the parser detects the end of a block, it closes the block, popping it
8//! from the open block stack and completing any additional parsing of the
9//! block's content. For blocks which contain parseable inline content, this
10//! invokes the inner level of the parser, handling the _inline structure_ of
11//! the block.
12//!
13//! Inline parsing scans through the collected inline content of a block. When
14//! it encounters a character that could indicate the beginning of an inline, it
15//! either handles the inline right away (if possible) or adds it to a pending
16//! inlines stack. When an inline is completed, it is added to a list of
17//! completed inlines, which (along with any surrounding text nodes) will become
18//! the children of the parent inline or the block whose inline content is being
19//! parsed.
20
21const std = @import("std");
22const mem = std.mem;
23const assert = std.debug.assert;
24const isWhitespace = std.ascii.isWhitespace;
25const Allocator = mem.Allocator;
26const expectEqual = std.testing.expectEqual;
27const Document = @import("Document.zig");
28const Node = Document.Node;
29const ExtraIndex = Document.ExtraIndex;
30const ExtraData = Document.ExtraData;
31const StringIndex = Document.StringIndex;
32
33nodes: Node.List = .{},
34extra: std.ArrayListUnmanaged(u32) = .{},
35scratch_extra: std.ArrayListUnmanaged(u32) = .{},
36string_bytes: std.ArrayListUnmanaged(u8) = .{},
37scratch_string: std.ArrayListUnmanaged(u8) = .{},
38pending_blocks: std.ArrayListUnmanaged(Block) = .{},
39allocator: Allocator,
40
41const Parser = @This();
42
43/// An arbitrary limit on the maximum number of columns in a table so that
44/// table-related metadata maintained by the parser does not require dynamic
45/// memory allocation.
46const max_table_columns = 128;
47
48/// A block element which is still receiving children.
49const Block = struct {
50 tag: Tag,
51 data: Data,
52 extra_start: usize,
53 string_start: usize,
54
55 const Tag = enum {
56 /// Data is `list`.
57 list,
58 /// Data is `list_item`.
59 list_item,
60 /// Data is `table`.
61 table,
62 /// Data is `none`.
63 table_row,
64 /// Data is `heading`.
65 heading,
66 /// Data is `code_block`.
67 code_block,
68 /// Data is `none`.
69 blockquote,
70 /// Data is `none`.
71 paragraph,
72 /// Data is `none`.
73 thematic_break,
74 };
75
76 const Data = union {
77 none: void,
78 list: struct {
79 marker: ListMarker,
80 /// Between 0 and 999,999,999, inclusive.
81 start: u30,
82 tight: bool,
83 last_line_blank: bool = false,
84 },
85 list_item: struct {
86 continuation_indent: usize,
87 },
88 table: struct {
89 column_alignments: std.BoundedArray(Node.TableCellAlignment, max_table_columns) = .{},
90 },
91 heading: struct {
92 /// Between 1 and 6, inclusive.
93 level: u3,
94 },
95 code_block: struct {
96 tag: StringIndex,
97 fence_len: usize,
98 indent: usize,
99 },
100
101 const ListMarker = enum {
102 @"-",
103 @"*",
104 @"+",
105 number_dot,
106 number_paren,
107 };
108 };
109
110 const ContentType = enum {
111 blocks,
112 inlines,
113 raw_inlines,
114 nothing,
115 };
116
117 fn canAccept(b: Block) ContentType {
118 return switch (b.tag) {
119 .list,
120 .list_item,
121 .table,
122 .blockquote,
123 => .blocks,
124
125 .heading,
126 .paragraph,
127 => .inlines,
128
129 .code_block,
130 => .raw_inlines,
131
132 .table_row,
133 .thematic_break,
134 => .nothing,
135 };
136 }
137
138 /// Attempts to continue `b` using the contents of `line`. If successful,
139 /// returns the remaining portion of `line` to be considered part of `b`
140 /// (e.g. for a blockquote, this would be everything except the leading
141 /// `>`). If unsuccessful, returns null.
142 fn match(b: Block, line: []const u8) ?[]const u8 {
143 const unindented = mem.trimLeft(u8, line, " \t");
144 const indent = line.len - unindented.len;
145 return switch (b.tag) {
146 .list => line,
147 .list_item => if (indent >= b.data.list_item.continuation_indent)
148 line[b.data.list_item.continuation_indent..]
149 else if (unindented.len == 0)
150 // Blank lines should not close list items, since there may be
151 // more indented contents to follow after the blank line.
152 ""
153 else
154 null,
155 .table => if (unindented.len > 0) unindented else null,
156 .table_row => null,
157 .heading => null,
158 .code_block => code_block: {
159 const trimmed = mem.trimRight(u8, unindented, " \t");
160 if (mem.indexOfNone(u8, trimmed, "`") != null or trimmed.len != b.data.code_block.fence_len) {
161 const effective_indent = @min(indent, b.data.code_block.indent);
162 break :code_block line[effective_indent..];
163 } else {
164 break :code_block null;
165 }
166 },
167 .blockquote => if (mem.startsWith(u8, unindented, ">"))
168 unindented[1..]
169 else
170 null,
171 .paragraph => if (unindented.len > 0) unindented else null,
172 .thematic_break => null,
173 };
174 }
175};
176
177pub fn init(allocator: Allocator) Allocator.Error!Parser {
178 var p: Parser = .{ .allocator = allocator };
179 try p.nodes.append(allocator, .{
180 .tag = .root,
181 .data = undefined,
182 });
183 try p.string_bytes.append(allocator, 0);
184 return p;
185}
186
187pub fn deinit(p: *Parser) void {
188 p.nodes.deinit(p.allocator);
189 p.extra.deinit(p.allocator);
190 p.scratch_extra.deinit(p.allocator);
191 p.string_bytes.deinit(p.allocator);
192 p.scratch_string.deinit(p.allocator);
193 p.pending_blocks.deinit(p.allocator);
194 p.* = undefined;
195}
196
197/// Accepts a single line of content. `line` should not have a trailing line
198/// ending character.
199pub fn feedLine(p: *Parser, line: []const u8) Allocator.Error!void {
200 var rest_line = line;
201 const first_unmatched = for (p.pending_blocks.items, 0..) |b, i| {
202 if (b.match(rest_line)) |rest| {
203 rest_line = rest;
204 } else {
205 break i;
206 }
207 } else p.pending_blocks.items.len;
208
209 const in_code_block = p.pending_blocks.items.len > 0 and
210 p.pending_blocks.getLast().tag == .code_block;
211 const code_block_end = in_code_block and
212 first_unmatched + 1 == p.pending_blocks.items.len;
213 // New blocks cannot be started if we are actively inside a code block or
214 // are just closing one (to avoid interpreting the closing ``` as a new code
215 // block start).
216 var maybe_block_start = if (!in_code_block or first_unmatched + 2 <= p.pending_blocks.items.len)
217 try p.startBlock(rest_line)
218 else
219 null;
220
221 // This is a lazy continuation line if there are no new blocks to open and
222 // the last open block is a paragraph.
223 if (maybe_block_start == null and
224 !isBlank(rest_line) and
225 p.pending_blocks.items.len > 0 and
226 p.pending_blocks.getLast().tag == .paragraph)
227 {
228 try p.addScratchStringLine(rest_line);
229 return;
230 }
231
232 // If a new block needs to be started, any paragraph needs to be closed,
233 // even though this isn't detected as part of the closing condition for
234 // paragraphs.
235 if (maybe_block_start != null and
236 p.pending_blocks.items.len > 0 and
237 p.pending_blocks.getLast().tag == .paragraph)
238 {
239 try p.closeLastBlock();
240 }
241
242 while (p.pending_blocks.items.len > first_unmatched) {
243 try p.closeLastBlock();
244 }
245
246 while (maybe_block_start) |block_start| : (maybe_block_start = try p.startBlock(rest_line)) {
247 try p.appendBlockStart(block_start);
248 // There may be more blocks to start within the same line.
249 rest_line = block_start.rest;
250 // Headings may only contain inline content.
251 if (block_start.tag == .heading) break;
252 // An opening code fence does not contain any additional block or inline
253 // content to process.
254 if (block_start.tag == .code_block) return;
255 }
256
257 // Do not append the end of a code block (```) as textual content.
258 if (code_block_end) return;
259
260 const can_accept = if (p.pending_blocks.getLastOrNull()) |last_pending_block|
261 last_pending_block.canAccept()
262 else
263 .blocks;
264 const rest_line_trimmed = mem.trimLeft(u8, rest_line, " \t");
265 switch (can_accept) {
266 .blocks => {
267 // If we're inside a list item and the rest of the line is blank, it
268 // means that any subsequent child of the list item (or subsequent
269 // item in the list) will cause the containing list to be considered
270 // loose. However, we can't immediately declare that the list is
271 // loose, since we might just be looking at a blank line after the
272 // end of the last item in the list. The final determination will be
273 // made when appending the next child of the list or list item.
274 const maybe_containing_list = if (p.pending_blocks.items.len > 0 and p.pending_blocks.getLast().tag == .list_item)
275 &p.pending_blocks.items[p.pending_blocks.items.len - 2]
276 else
277 null;
278
279 if (rest_line_trimmed.len > 0) {
280 try p.appendBlockStart(.{
281 .tag = .paragraph,
282 .data = .{ .none = {} },
283 .rest = undefined,
284 });
285 try p.addScratchStringLine(rest_line_trimmed);
286 }
287
288 if (maybe_containing_list) |containing_list| {
289 containing_list.data.list.last_line_blank = rest_line_trimmed.len == 0;
290 }
291 },
292 .inlines => try p.addScratchStringLine(rest_line_trimmed),
293 .raw_inlines => try p.addScratchStringLine(rest_line),
294 .nothing => {},
295 }
296}
297
298/// Completes processing of the input and returns the parsed document.
299pub fn endInput(p: *Parser) Allocator.Error!Document {
300 while (p.pending_blocks.items.len > 0) {
301 try p.closeLastBlock();
302 }
303 // There should be no inline content pending after closing the last open
304 // block.
305 assert(p.scratch_string.items.len == 0);
306
307 const children = try p.addExtraChildren(@ptrCast(p.scratch_extra.items));
308 p.nodes.items(.data)[0] = .{ .container = .{ .children = children } };
309 p.scratch_string.items.len = 0;
310 p.scratch_extra.items.len = 0;
311
312 var nodes = p.nodes.toOwnedSlice();
313 errdefer nodes.deinit(p.allocator);
314 const extra = try p.extra.toOwnedSlice(p.allocator);
315 errdefer p.allocator.free(extra);
316 const string_bytes = try p.string_bytes.toOwnedSlice(p.allocator);
317 errdefer p.allocator.free(string_bytes);
318
319 return .{
320 .nodes = nodes,
321 .extra = extra,
322 .string_bytes = string_bytes,
323 };
324}
325
326/// Data describing the start of a new block element.
327const BlockStart = struct {
328 tag: Tag,
329 data: Data,
330 rest: []const u8,
331
332 const Tag = enum {
333 /// Data is `list_item`.
334 list_item,
335 /// Data is `table_row`.
336 table_row,
337 /// Data is `heading`.
338 heading,
339 /// Data is `code_block`.
340 code_block,
341 /// Data is `none`.
342 blockquote,
343 /// Data is `none`.
344 paragraph,
345 /// Data is `none`.
346 thematic_break,
347 };
348
349 const Data = union {
350 none: void,
351 list_item: struct {
352 marker: Block.Data.ListMarker,
353 number: u30,
354 continuation_indent: usize,
355 },
356 table_row: struct {
357 cells: std.BoundedArray([]const u8, max_table_columns),
358 },
359 heading: struct {
360 /// Between 1 and 6, inclusive.
361 level: u3,
362 },
363 code_block: struct {
364 tag: StringIndex,
365 fence_len: usize,
366 indent: usize,
367 },
368 };
369};
370
371fn appendBlockStart(p: *Parser, block_start: BlockStart) !void {
372 if (p.pending_blocks.getLastOrNull()) |last_pending_block| {
373 // Close the last block if it is a list and the new block is not a list item
374 // or not of the same marker type.
375 const should_close_list = last_pending_block.tag == .list and
376 (block_start.tag != .list_item or
377 block_start.data.list_item.marker != last_pending_block.data.list.marker);
378 // The last block should also be closed if the new block is not a table
379 // row, which is the only allowed child of a table.
380 const should_close_table = last_pending_block.tag == .table and
381 block_start.tag != .table_row;
382 if (should_close_list or should_close_table) {
383 try p.closeLastBlock();
384 }
385 }
386
387 if (p.pending_blocks.getLastOrNull()) |last_pending_block| {
388 // If the last block is a list or list item, check for tightness based
389 // on the last line.
390 const maybe_containing_list = switch (last_pending_block.tag) {
391 .list => &p.pending_blocks.items[p.pending_blocks.items.len - 1],
392 .list_item => &p.pending_blocks.items[p.pending_blocks.items.len - 2],
393 else => null,
394 };
395 if (maybe_containing_list) |containing_list| {
396 if (containing_list.data.list.last_line_blank) {
397 containing_list.data.list.tight = false;
398 }
399 }
400 }
401
402 // Start a new list if the new block is a list item and there is no
403 // containing list yet.
404 if (block_start.tag == .list_item and
405 (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().tag != .list))
406 {
407 try p.pending_blocks.append(p.allocator, .{
408 .tag = .list,
409 .data = .{ .list = .{
410 .marker = block_start.data.list_item.marker,
411 .start = block_start.data.list_item.number,
412 .tight = true,
413 } },
414 .string_start = p.scratch_string.items.len,
415 .extra_start = p.scratch_extra.items.len,
416 });
417 }
418
419 if (block_start.tag == .table_row) {
420 // Likewise, table rows start a table implicitly.
421 if (p.pending_blocks.items.len == 0 or p.pending_blocks.getLast().tag != .table) {
422 try p.pending_blocks.append(p.allocator, .{
423 .tag = .table,
424 .data = .{ .table = .{
425 .column_alignments = .{},
426 } },
427 .string_start = p.scratch_string.items.len,
428 .extra_start = p.scratch_extra.items.len,
429 });
430 }
431
432 const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().extra_start;
433 if (current_row <= 1) {
434 if (parseTableHeaderDelimiter(block_start.data.table_row.cells)) |alignments| {
435 p.pending_blocks.items[p.pending_blocks.items.len - 1].data.table.column_alignments = alignments;
436 if (current_row == 1) {
437 // We need to go back and mark the header row and its column
438 // alignments.
439 const datas = p.nodes.items(.data);
440 const header_data = datas[p.scratch_extra.getLast()];
441 for (p.extraChildren(header_data.container.children), 0..) |header_cell, i| {
442 const alignment = if (i < alignments.len) alignments.buffer[i] else .unset;
443 const cell_data = &datas[@intFromEnum(header_cell)].table_cell;
444 cell_data.info.alignment = alignment;
445 cell_data.info.header = true;
446 }
447 }
448 return;
449 }
450 }
451 }
452
453 const tag: Block.Tag, const data: Block.Data = switch (block_start.tag) {
454 .list_item => .{ .list_item, .{ .list_item = .{
455 .continuation_indent = block_start.data.list_item.continuation_indent,
456 } } },
457 .table_row => .{ .table_row, .{ .none = {} } },
458 .heading => .{ .heading, .{ .heading = .{
459 .level = block_start.data.heading.level,
460 } } },
461 .code_block => .{ .code_block, .{ .code_block = .{
462 .tag = block_start.data.code_block.tag,
463 .fence_len = block_start.data.code_block.fence_len,
464 .indent = block_start.data.code_block.indent,
465 } } },
466 .blockquote => .{ .blockquote, .{ .none = {} } },
467 .paragraph => .{ .paragraph, .{ .none = {} } },
468 .thematic_break => .{ .thematic_break, .{ .none = {} } },
469 };
470
471 try p.pending_blocks.append(p.allocator, .{
472 .tag = tag,
473 .data = data,
474 .string_start = p.scratch_string.items.len,
475 .extra_start = p.scratch_extra.items.len,
476 });
477
478 if (tag == .table_row) {
479 // Table rows are unique, since we already have all the children
480 // available in the BlockStart. We can immediately parse and append
481 // these children now.
482 const containing_table = p.pending_blocks.items[p.pending_blocks.items.len - 2];
483 const column_alignments = containing_table.data.table.column_alignments.slice();
484 for (block_start.data.table_row.cells.slice(), 0..) |cell_content, i| {
485 const cell_children = try p.parseInlines(cell_content);
486 const alignment = if (i < column_alignments.len) column_alignments[i] else .unset;
487 const cell = try p.addNode(.{
488 .tag = .table_cell,
489 .data = .{ .table_cell = .{
490 .info = .{
491 .alignment = alignment,
492 .header = false,
493 },
494 .children = cell_children,
495 } },
496 });
497 try p.addScratchExtraNode(cell);
498 }
499 }
500}
501
502fn startBlock(p: *Parser, line: []const u8) !?BlockStart {
503 const unindented = mem.trimLeft(u8, line, " \t");
504 const indent = line.len - unindented.len;
505 if (isThematicBreak(line)) {
506 // Thematic breaks take precedence over list items.
507 return .{
508 .tag = .thematic_break,
509 .data = .{ .none = {} },
510 .rest = "",
511 };
512 } else if (startListItem(unindented)) |list_item| {
513 return .{
514 .tag = .list_item,
515 .data = .{ .list_item = .{
516 .marker = list_item.marker,
517 .number = list_item.number,
518 .continuation_indent = list_item.continuation_indent,
519 } },
520 .rest = list_item.rest,
521 };
522 } else if (startTableRow(unindented)) |table_row| {
523 return .{
524 .tag = .table_row,
525 .data = .{ .table_row = .{
526 .cells = table_row.cells,
527 } },
528 .rest = "",
529 };
530 } else if (startHeading(unindented)) |heading| {
531 return .{
532 .tag = .heading,
533 .data = .{ .heading = .{
534 .level = heading.level,
535 } },
536 .rest = heading.rest,
537 };
538 } else if (try p.startCodeBlock(unindented)) |code_block| {
539 return .{
540 .tag = .code_block,
541 .data = .{ .code_block = .{
542 .tag = code_block.tag,
543 .fence_len = code_block.fence_len,
544 .indent = indent,
545 } },
546 .rest = "",
547 };
548 } else if (startBlockquote(unindented)) |rest| {
549 return .{
550 .tag = .blockquote,
551 .data = .{ .none = {} },
552 .rest = rest,
553 };
554 } else {
555 return null;
556 }
557}
558
559const ListItemStart = struct {
560 marker: Block.Data.ListMarker,
561 number: u30,
562 continuation_indent: usize,
563 rest: []const u8,
564};
565
566fn startListItem(unindented_line: []const u8) ?ListItemStart {
567 if (mem.startsWith(u8, unindented_line, "- ")) {
568 return .{
569 .marker = .@"-",
570 .number = undefined,
571 .continuation_indent = 2,
572 .rest = unindented_line[2..],
573 };
574 } else if (mem.startsWith(u8, unindented_line, "* ")) {
575 return .{
576 .marker = .@"*",
577 .number = undefined,
578 .continuation_indent = 2,
579 .rest = unindented_line[2..],
580 };
581 } else if (mem.startsWith(u8, unindented_line, "+ ")) {
582 return .{
583 .marker = .@"+",
584 .number = undefined,
585 .continuation_indent = 2,
586 .rest = unindented_line[2..],
587 };
588 }
589
590 const number_end = mem.indexOfNone(u8, unindented_line, "0123456789") orelse return null;
591 const after_number = unindented_line[number_end..];
592 const marker: Block.Data.ListMarker = if (mem.startsWith(u8, after_number, ". "))
593 .number_dot
594 else if (mem.startsWith(u8, after_number, ") "))
595 .number_paren
596 else
597 return null;
598 const number = std.fmt.parseInt(u30, unindented_line[0..number_end], 10) catch return null;
599 if (number > 999_999_999) return null;
600 return .{
601 .marker = marker,
602 .number = number,
603 .continuation_indent = number_end + 2,
604 .rest = after_number[2..],
605 };
606}
607
608const TableRowStart = struct {
609 cells: std.BoundedArray([]const u8, max_table_columns),
610};
611
612fn startTableRow(unindented_line: []const u8) ?TableRowStart {
613 if (unindented_line.len < 2 or
614 !mem.startsWith(u8, unindented_line, "|") or
615 mem.endsWith(u8, unindented_line, "\\|") or
616 !mem.endsWith(u8, unindented_line, "|")) return null;
617
618 var cells: std.BoundedArray([]const u8, max_table_columns) = .{};
619 const table_row_content = unindented_line[1 .. unindented_line.len - 1];
620 var cell_start: usize = 0;
621 var i: usize = 0;
622 while (i < table_row_content.len) : (i += 1) {
623 switch (table_row_content[i]) {
624 '\\' => i += 1,
625 '|' => {
626 cells.append(table_row_content[cell_start..i]) catch return null;
627 cell_start = i + 1;
628 },
629 '`' => {
630 // Ignoring pipes in code spans allows table cells to contain
631 // code using ||, for example.
632 const open_start = i;
633 i = mem.indexOfNonePos(u8, table_row_content, i, "`") orelse return null;
634 const open_len = i - open_start;
635 while (mem.indexOfScalarPos(u8, table_row_content, i, '`')) |close_start| {
636 i = mem.indexOfNonePos(u8, table_row_content, close_start, "`") orelse return null;
637 const close_len = i - close_start;
638 if (close_len == open_len) break;
639 } else return null;
640 },
641 else => {},
642 }
643 }
644 cells.append(table_row_content[cell_start..]) catch return null;
645
646 return .{ .cells = cells };
647}
648
649fn parseTableHeaderDelimiter(
650 row_cells: std.BoundedArray([]const u8, max_table_columns),
651) ?std.BoundedArray(Node.TableCellAlignment, max_table_columns) {
652 var alignments: std.BoundedArray(Node.TableCellAlignment, max_table_columns) = .{};
653 for (row_cells.slice()) |content| {
654 const alignment = parseTableHeaderDelimiterCell(content) orelse return null;
655 alignments.appendAssumeCapacity(alignment);
656 }
657 return alignments;
658}
659
660fn parseTableHeaderDelimiterCell(content: []const u8) ?Node.TableCellAlignment {
661 var state: enum {
662 before_rule,
663 after_left_anchor,
664 in_rule,
665 after_right_anchor,
666 after_rule,
667 } = .before_rule;
668 var left_anchor = false;
669 var right_anchor = false;
670 for (content) |c| {
671 switch (state) {
672 .before_rule => switch (c) {
673 ' ' => {},
674 ':' => {
675 left_anchor = true;
676 state = .after_left_anchor;
677 },
678 '-' => state = .in_rule,
679 else => return null,
680 },
681 .after_left_anchor => switch (c) {
682 '-' => state = .in_rule,
683 else => return null,
684 },
685 .in_rule => switch (c) {
686 '-' => {},
687 ':' => {
688 right_anchor = true;
689 state = .after_right_anchor;
690 },
691 ' ' => state = .after_rule,
692 else => return null,
693 },
694 .after_right_anchor => switch (c) {
695 ' ' => state = .after_rule,
696 else => return null,
697 },
698 .after_rule => switch (c) {
699 ' ' => {},
700 else => return null,
701 },
702 }
703 }
704
705 switch (state) {
706 .before_rule,
707 .after_left_anchor,
708 => return null,
709
710 .in_rule,
711 .after_right_anchor,
712 .after_rule,
713 => {},
714 }
715
716 return if (left_anchor and right_anchor)
717 .center
718 else if (left_anchor)
719 .left
720 else if (right_anchor)
721 .right
722 else
723 .unset;
724}
725
726test parseTableHeaderDelimiterCell {
727 try expectEqual(null, parseTableHeaderDelimiterCell(""));
728 try expectEqual(null, parseTableHeaderDelimiterCell(" "));
729 try expectEqual(.unset, parseTableHeaderDelimiterCell("-"));
730 try expectEqual(.unset, parseTableHeaderDelimiterCell(" - "));
731 try expectEqual(.unset, parseTableHeaderDelimiterCell("----"));
732 try expectEqual(.unset, parseTableHeaderDelimiterCell(" ---- "));
733 try expectEqual(null, parseTableHeaderDelimiterCell(":"));
734 try expectEqual(null, parseTableHeaderDelimiterCell("::"));
735 try expectEqual(.left, parseTableHeaderDelimiterCell(":-"));
736 try expectEqual(.left, parseTableHeaderDelimiterCell(" :----"));
737 try expectEqual(.center, parseTableHeaderDelimiterCell(":-:"));
738 try expectEqual(.center, parseTableHeaderDelimiterCell(":----:"));
739 try expectEqual(.center, parseTableHeaderDelimiterCell(" :----: "));
740 try expectEqual(.right, parseTableHeaderDelimiterCell("-:"));
741 try expectEqual(.right, parseTableHeaderDelimiterCell("----:"));
742 try expectEqual(.right, parseTableHeaderDelimiterCell(" ----: "));
743}
744
745const HeadingStart = struct {
746 level: u3,
747 rest: []const u8,
748};
749
750fn startHeading(unindented_line: []const u8) ?HeadingStart {
751 var level: u3 = 0;
752 return for (unindented_line, 0..) |c, i| {
753 switch (c) {
754 '#' => {
755 if (level == 6) break null;
756 level += 1;
757 },
758 ' ' => {
759 // We must have seen at least one # by this point, since
760 // unindented_line has no leading spaces.
761 assert(level > 0);
762 break .{
763 .level = level,
764 .rest = unindented_line[i + 1 ..],
765 };
766 },
767 else => break null,
768 }
769 } else null;
770}
771
772const CodeBlockStart = struct {
773 tag: StringIndex,
774 fence_len: usize,
775};
776
777fn startCodeBlock(p: *Parser, unindented_line: []const u8) !?CodeBlockStart {
778 var fence_len: usize = 0;
779 const tag_bytes = for (unindented_line, 0..) |c, i| {
780 switch (c) {
781 '`' => fence_len += 1,
782 else => break unindented_line[i..],
783 }
784 } else "";
785 // Code block tags may not contain backticks, since that would create
786 // potential confusion with inline code spans.
787 if (fence_len < 3 or mem.indexOfScalar(u8, tag_bytes, '`') != null) return null;
788 return .{
789 .tag = try p.addString(mem.trim(u8, tag_bytes, " ")),
790 .fence_len = fence_len,
791 };
792}
793
794fn startBlockquote(unindented_line: []const u8) ?[]const u8 {
795 return if (mem.startsWith(u8, unindented_line, ">"))
796 unindented_line[1..]
797 else
798 null;
799}
800
801fn isThematicBreak(line: []const u8) bool {
802 var char: ?u8 = null;
803 var count: usize = 0;
804 for (line) |c| {
805 switch (c) {
806 ' ' => {},
807 '-', '_', '*' => {
808 if (char != null and c != char.?) return false;
809 char = c;
810 count += 1;
811 },
812 else => return false,
813 }
814 }
815 return count >= 3;
816}
817
818fn closeLastBlock(p: *Parser) !void {
819 const b = p.pending_blocks.pop();
820 const node = switch (b.tag) {
821 .list => list: {
822 assert(b.string_start == p.scratch_string.items.len);
823
824 // Although tightness is parsed as a property of the list, it is
825 // stored at the list item level to make it possible to render each
826 // node without any context from its parents.
827 const list_items = p.scratch_extra.items[b.extra_start..];
828 const node_datas = p.nodes.items(.data);
829 if (!b.data.list.tight) {
830 for (list_items) |list_item| {
831 node_datas[list_item].list_item.tight = false;
832 }
833 }
834
835 const children = try p.addExtraChildren(@ptrCast(list_items));
836 break :list try p.addNode(.{
837 .tag = .list,
838 .data = .{ .list = .{
839 .start = switch (b.data.list.marker) {
840 .number_dot, .number_paren => @enumFromInt(b.data.list.start),
841 .@"-", .@"*", .@"+" => .unordered,
842 },
843 .children = children,
844 } },
845 });
846 },
847 .list_item => list_item: {
848 assert(b.string_start == p.scratch_string.items.len);
849 const children = try p.addExtraChildren(@ptrCast(p.scratch_extra.items[b.extra_start..]));
850 break :list_item try p.addNode(.{
851 .tag = .list_item,
852 .data = .{ .list_item = .{
853 .tight = true,
854 .children = children,
855 } },
856 });
857 },
858 .table => table: {
859 assert(b.string_start == p.scratch_string.items.len);
860 const children = try p.addExtraChildren(@ptrCast(p.scratch_extra.items[b.extra_start..]));
861 break :table try p.addNode(.{
862 .tag = .table,
863 .data = .{ .container = .{
864 .children = children,
865 } },
866 });
867 },
868 .table_row => table_row: {
869 assert(b.string_start == p.scratch_string.items.len);
870 const children = try p.addExtraChildren(@ptrCast(p.scratch_extra.items[b.extra_start..]));
871 break :table_row try p.addNode(.{
872 .tag = .table_row,
873 .data = .{ .container = .{
874 .children = children,
875 } },
876 });
877 },
878 .heading => heading: {
879 const children = try p.parseInlines(p.scratch_string.items[b.string_start..]);
880 break :heading try p.addNode(.{
881 .tag = .heading,
882 .data = .{ .heading = .{
883 .level = b.data.heading.level,
884 .children = children,
885 } },
886 });
887 },
888 .code_block => code_block: {
889 const content = try p.addString(p.scratch_string.items[b.string_start..]);
890 break :code_block try p.addNode(.{
891 .tag = .code_block,
892 .data = .{ .code_block = .{
893 .tag = b.data.code_block.tag,
894 .content = content,
895 } },
896 });
897 },
898 .blockquote => blockquote: {
899 assert(b.string_start == p.scratch_string.items.len);
900 const children = try p.addExtraChildren(@ptrCast(p.scratch_extra.items[b.extra_start..]));
901 break :blockquote try p.addNode(.{
902 .tag = .blockquote,
903 .data = .{ .container = .{
904 .children = children,
905 } },
906 });
907 },
908 .paragraph => paragraph: {
909 const children = try p.parseInlines(p.scratch_string.items[b.string_start..]);
910 break :paragraph try p.addNode(.{
911 .tag = .paragraph,
912 .data = .{ .container = .{
913 .children = children,
914 } },
915 });
916 },
917 .thematic_break => try p.addNode(.{
918 .tag = .thematic_break,
919 .data = .{ .none = {} },
920 }),
921 };
922 p.scratch_string.items.len = b.string_start;
923 p.scratch_extra.items.len = b.extra_start;
924 try p.addScratchExtraNode(node);
925}
926
927const InlineParser = struct {
928 parent: *Parser,
929 content: []const u8,
930 pos: usize = 0,
931 pending_inlines: std.ArrayListUnmanaged(PendingInline) = .{},
932 completed_inlines: std.ArrayListUnmanaged(CompletedInline) = .{},
933
934 const PendingInline = struct {
935 tag: Tag,
936 data: Data,
937 start: usize,
938
939 const Tag = enum {
940 /// Data is `emphasis`.
941 emphasis,
942 /// Data is `none`.
943 link,
944 /// Data is `none`.
945 image,
946 };
947
948 const Data = union {
949 none: void,
950 emphasis: struct {
951 underscore: bool,
952 run_len: usize,
953 },
954 };
955 };
956
957 const CompletedInline = struct {
958 node: Node.Index,
959 start: usize,
960 len: usize,
961 };
962
963 fn deinit(ip: *InlineParser) void {
964 ip.pending_inlines.deinit(ip.parent.allocator);
965 ip.completed_inlines.deinit(ip.parent.allocator);
966 }
967
968 /// Parses all of `ip.content`, returning the children of the node
969 /// containing the inline content.
970 fn parse(ip: *InlineParser) Allocator.Error!ExtraIndex {
971 while (ip.pos < ip.content.len) : (ip.pos += 1) {
972 switch (ip.content[ip.pos]) {
973 '\\' => ip.pos += 1,
974 '[' => try ip.pending_inlines.append(ip.parent.allocator, .{
975 .tag = .link,
976 .data = .{ .none = {} },
977 .start = ip.pos,
978 }),
979 '!' => if (ip.pos + 1 < ip.content.len and ip.content[ip.pos + 1] == '[') {
980 try ip.pending_inlines.append(ip.parent.allocator, .{
981 .tag = .image,
982 .data = .{ .none = {} },
983 .start = ip.pos,
984 });
985 ip.pos += 1;
986 },
987 ']' => try ip.parseLink(),
988 '*', '_' => try ip.parseEmphasis(),
989 '`' => try ip.parseCodeSpan(),
990 else => {},
991 }
992 }
993
994 const children = try ip.encodeChildren(0, ip.content.len);
995 // There may be pending inlines after parsing (e.g. unclosed emphasis
996 // runs), but there must not be any completed inlines, since those
997 // should all be part of `children`.
998 assert(ip.completed_inlines.items.len == 0);
999 return children;
1000 }
1001
1002 /// Parses a link, starting at the `]` at the end of the link text. `ip.pos`
1003 /// is left at the closing `)` of the link target or at the closing `]` if
1004 /// there is none.
1005 fn parseLink(ip: *InlineParser) !void {
1006 var i = ip.pending_inlines.items.len;
1007 while (i > 0) {
1008 i -= 1;
1009 if (ip.pending_inlines.items[i].tag == .link or
1010 ip.pending_inlines.items[i].tag == .image) break;
1011 } else return;
1012 const opener = ip.pending_inlines.items[i];
1013 ip.pending_inlines.shrinkRetainingCapacity(i);
1014 const text_start = switch (opener.tag) {
1015 .link => opener.start + 1,
1016 .image => opener.start + 2,
1017 else => unreachable,
1018 };
1019
1020 if (ip.pos + 1 >= ip.content.len or ip.content[ip.pos + 1] != '(') return;
1021 const text_end = ip.pos;
1022
1023 const target_start = text_end + 2;
1024 var target_end = target_start;
1025 var nesting_level: usize = 1;
1026 while (target_end < ip.content.len) : (target_end += 1) {
1027 switch (ip.content[target_end]) {
1028 '\\' => target_end += 1,
1029 '(' => nesting_level += 1,
1030 ')' => {
1031 if (nesting_level == 1) break;
1032 nesting_level -= 1;
1033 },
1034 else => {},
1035 }
1036 } else return;
1037 ip.pos = target_end;
1038
1039 const children = try ip.encodeChildren(text_start, text_end);
1040 const target = try ip.encodeLinkTarget(target_start, target_end);
1041
1042 const link = try ip.parent.addNode(.{
1043 .tag = switch (opener.tag) {
1044 .link => .link,
1045 .image => .image,
1046 else => unreachable,
1047 },
1048 .data = .{ .link = .{
1049 .target = target,
1050 .children = children,
1051 } },
1052 });
1053 try ip.completed_inlines.append(ip.parent.allocator, .{
1054 .node = link,
1055 .start = opener.start,
1056 .len = ip.pos - opener.start + 1,
1057 });
1058 }
1059
1060 fn encodeLinkTarget(ip: *InlineParser, start: usize, end: usize) !StringIndex {
1061 // For efficiency, we can encode directly into string_bytes rather than
1062 // creating a temporary string and then encoding it, since this process
1063 // is entirely linear.
1064 const string_top = ip.parent.string_bytes.items.len;
1065 errdefer ip.parent.string_bytes.shrinkRetainingCapacity(string_top);
1066
1067 var text_iter: TextIterator = .{ .content = ip.content[start..end] };
1068 while (text_iter.next()) |content| {
1069 switch (content) {
1070 .char => |c| try ip.parent.string_bytes.append(ip.parent.allocator, c),
1071 .text => |s| try ip.parent.string_bytes.appendSlice(ip.parent.allocator, s),
1072 .line_break => try ip.parent.string_bytes.appendSlice(ip.parent.allocator, "\\\n"),
1073 }
1074 }
1075 try ip.parent.string_bytes.append(ip.parent.allocator, 0);
1076 return @enumFromInt(string_top);
1077 }
1078
1079 /// Parses emphasis, starting at the beginning of a run of `*` or `_`
1080 /// characters. `ip.pos` is left at the last character in the run after
1081 /// parsing.
1082 fn parseEmphasis(ip: *InlineParser) !void {
1083 const char = ip.content[ip.pos];
1084 var start = ip.pos;
1085 while (ip.pos + 1 < ip.content.len and ip.content[ip.pos + 1] == char) {
1086 ip.pos += 1;
1087 }
1088 var len = ip.pos - start + 1;
1089 const underscore = char == '_';
1090 const space_before = start == 0 or isWhitespace(ip.content[start - 1]);
1091 const space_after = start + len == ip.content.len or isWhitespace(ip.content[start + len]);
1092 const punct_before = start == 0 or isPunctuation(ip.content[start - 1]);
1093 const punct_after = start + len == ip.content.len or isPunctuation(ip.content[start + len]);
1094 // The rules for when emphasis may be closed or opened are stricter for
1095 // underscores to avoid inappropriately interpreting snake_case words as
1096 // containing emphasis markers.
1097 const can_open = if (underscore)
1098 !space_after and (space_before or punct_before)
1099 else
1100 !space_after;
1101 const can_close = if (underscore)
1102 !space_before and (space_after or punct_after)
1103 else
1104 !space_before;
1105
1106 if (can_close and ip.pending_inlines.items.len > 0) {
1107 var i = ip.pending_inlines.items.len;
1108 while (i > 0 and len > 0) {
1109 i -= 1;
1110 const opener = &ip.pending_inlines.items[i];
1111 if (opener.tag != .emphasis or
1112 opener.data.emphasis.underscore != underscore) continue;
1113
1114 const close_len = @min(opener.data.emphasis.run_len, len);
1115 const opener_end = opener.start + opener.data.emphasis.run_len;
1116
1117 const emphasis = try ip.encodeEmphasis(opener_end, start, close_len);
1118 const emphasis_start = opener_end - close_len;
1119 const emphasis_len = start - emphasis_start + close_len;
1120 try ip.completed_inlines.append(ip.parent.allocator, .{
1121 .node = emphasis,
1122 .start = emphasis_start,
1123 .len = emphasis_len,
1124 });
1125
1126 // There may still be other openers further down in the
1127 // stack to close, or part of this run might serve as an
1128 // opener itself.
1129 start += close_len;
1130 len -= close_len;
1131
1132 // Remove any pending inlines above this on the stack, since
1133 // closing this emphasis will prevent them from being closed.
1134 // Additionally, if this opener is completely consumed by
1135 // being closed, it can be removed.
1136 opener.data.emphasis.run_len -= close_len;
1137 if (opener.data.emphasis.run_len == 0) {
1138 ip.pending_inlines.shrinkRetainingCapacity(i);
1139 } else {
1140 ip.pending_inlines.shrinkRetainingCapacity(i + 1);
1141 }
1142 }
1143 }
1144
1145 if (can_open and len > 0) {
1146 try ip.pending_inlines.append(ip.parent.allocator, .{
1147 .tag = .emphasis,
1148 .data = .{ .emphasis = .{
1149 .underscore = underscore,
1150 .run_len = len,
1151 } },
1152 .start = start,
1153 });
1154 }
1155 }
1156
1157 /// Encodes emphasis specified by a run of `run_len` emphasis characters,
1158 /// with `start..end` being the range of content contained within the
1159 /// emphasis.
1160 fn encodeEmphasis(ip: *InlineParser, start: usize, end: usize, run_len: usize) !Node.Index {
1161 const children = try ip.encodeChildren(start, end);
1162 var inner = switch (run_len % 3) {
1163 1 => try ip.parent.addNode(.{
1164 .tag = .emphasis,
1165 .data = .{ .container = .{
1166 .children = children,
1167 } },
1168 }),
1169 2 => try ip.parent.addNode(.{
1170 .tag = .strong,
1171 .data = .{ .container = .{
1172 .children = children,
1173 } },
1174 }),
1175 0 => strong_emphasis: {
1176 const strong = try ip.parent.addNode(.{
1177 .tag = .strong,
1178 .data = .{ .container = .{
1179 .children = children,
1180 } },
1181 });
1182 break :strong_emphasis try ip.parent.addNode(.{
1183 .tag = .emphasis,
1184 .data = .{ .container = .{
1185 .children = try ip.parent.addExtraChildren(&.{strong}),
1186 } },
1187 });
1188 },
1189 else => unreachable,
1190 };
1191
1192 var run_left = run_len;
1193 while (run_left > 3) : (run_left -= 3) {
1194 const strong = try ip.parent.addNode(.{
1195 .tag = .strong,
1196 .data = .{ .container = .{
1197 .children = try ip.parent.addExtraChildren(&.{inner}),
1198 } },
1199 });
1200 inner = try ip.parent.addNode(.{
1201 .tag = .emphasis,
1202 .data = .{ .container = .{
1203 .children = try ip.parent.addExtraChildren(&.{strong}),
1204 } },
1205 });
1206 }
1207
1208 return inner;
1209 }
1210
1211 /// Parses a code span, starting at the beginning of the opening backtick
1212 /// run. `ip.pos` is left at the last character in the closing run after
1213 /// parsing.
1214 fn parseCodeSpan(ip: *InlineParser) !void {
1215 const opener_start = ip.pos;
1216 ip.pos = mem.indexOfNonePos(u8, ip.content, ip.pos, "`") orelse ip.content.len;
1217 const opener_len = ip.pos - opener_start;
1218
1219 const start = ip.pos;
1220 const end = while (mem.indexOfScalarPos(u8, ip.content, ip.pos, '`')) |closer_start| {
1221 ip.pos = mem.indexOfNonePos(u8, ip.content, closer_start, "`") orelse ip.content.len;
1222 const closer_len = ip.pos - closer_start;
1223
1224 if (closer_len == opener_len) break closer_start;
1225 } else unterminated: {
1226 ip.pos = ip.content.len;
1227 break :unterminated ip.content.len;
1228 };
1229
1230 var content = if (start < ip.content.len)
1231 ip.content[start..end]
1232 else
1233 "";
1234 // This single space removal rule allows code spans to be written which
1235 // start or end with backticks.
1236 if (mem.startsWith(u8, content, " `")) content = content[1..];
1237 if (mem.endsWith(u8, content, "` ")) content = content[0 .. content.len - 1];
1238
1239 const text = try ip.parent.addNode(.{
1240 .tag = .code_span,
1241 .data = .{ .text = .{
1242 .content = try ip.parent.addString(content),
1243 } },
1244 });
1245 try ip.completed_inlines.append(ip.parent.allocator, .{
1246 .node = text,
1247 .start = opener_start,
1248 .len = ip.pos - opener_start,
1249 });
1250 // Ensure ip.pos is pointing at the last character of the
1251 // closer, not after it.
1252 ip.pos -= 1;
1253 }
1254
1255 /// Encodes children parsed in the content range `start..end`. The children
1256 /// will be text nodes and any completed inlines within the range.
1257 fn encodeChildren(ip: *InlineParser, start: usize, end: usize) !ExtraIndex {
1258 const scratch_extra_top = ip.parent.scratch_extra.items.len;
1259 defer ip.parent.scratch_extra.shrinkRetainingCapacity(scratch_extra_top);
1260
1261 var child_index = ip.completed_inlines.items.len;
1262 while (child_index > 0 and ip.completed_inlines.items[child_index - 1].start >= start) {
1263 child_index -= 1;
1264 }
1265 const start_child_index = child_index;
1266
1267 var pos = start;
1268 while (child_index < ip.completed_inlines.items.len) : (child_index += 1) {
1269 const child_inline = ip.completed_inlines.items[child_index];
1270 // Completed inlines must be strictly nested within the encodable
1271 // content.
1272 assert(child_inline.start >= pos and child_inline.start + child_inline.len <= end);
1273
1274 if (child_inline.start > pos) {
1275 try ip.encodeTextNode(pos, child_inline.start);
1276 }
1277 try ip.parent.addScratchExtraNode(child_inline.node);
1278
1279 pos = child_inline.start + child_inline.len;
1280 }
1281 ip.completed_inlines.shrinkRetainingCapacity(start_child_index);
1282
1283 if (pos < end) {
1284 try ip.encodeTextNode(pos, end);
1285 }
1286
1287 const children = ip.parent.scratch_extra.items[scratch_extra_top..];
1288 return try ip.parent.addExtraChildren(@ptrCast(children));
1289 }
1290
1291 /// Encodes textual content `ip.content[start..end]` to `scratch_extra`. The
1292 /// encoded content may include both `text` and `line_break` nodes.
1293 fn encodeTextNode(ip: *InlineParser, start: usize, end: usize) !void {
1294 // For efficiency, we can encode directly into string_bytes rather than
1295 // creating a temporary string and then encoding it, since this process
1296 // is entirely linear.
1297 const string_top = ip.parent.string_bytes.items.len;
1298 errdefer ip.parent.string_bytes.shrinkRetainingCapacity(string_top);
1299
1300 var string_start = string_top;
1301 var text_iter: TextIterator = .{ .content = ip.content[start..end] };
1302 while (text_iter.next()) |content| {
1303 switch (content) {
1304 .char => |c| try ip.parent.string_bytes.append(ip.parent.allocator, c),
1305 .text => |s| try ip.parent.string_bytes.appendSlice(ip.parent.allocator, s),
1306 .line_break => {
1307 if (ip.parent.string_bytes.items.len > string_start) {
1308 try ip.parent.string_bytes.append(ip.parent.allocator, 0);
1309 try ip.parent.addScratchExtraNode(try ip.parent.addNode(.{
1310 .tag = .text,
1311 .data = .{ .text = .{
1312 .content = @enumFromInt(string_start),
1313 } },
1314 }));
1315 string_start = ip.parent.string_bytes.items.len;
1316 }
1317 try ip.parent.addScratchExtraNode(try ip.parent.addNode(.{
1318 .tag = .line_break,
1319 .data = .{ .none = {} },
1320 }));
1321 },
1322 }
1323 }
1324 if (ip.parent.string_bytes.items.len > string_start) {
1325 try ip.parent.string_bytes.append(ip.parent.allocator, 0);
1326 try ip.parent.addScratchExtraNode(try ip.parent.addNode(.{
1327 .tag = .text,
1328 .data = .{ .text = .{
1329 .content = @enumFromInt(string_start),
1330 } },
1331 }));
1332 }
1333 }
1334
1335 /// An iterator over parts of textual content, handling unescaping of
1336 /// escaped characters and line breaks.
1337 const TextIterator = struct {
1338 content: []const u8,
1339 pos: usize = 0,
1340
1341 const Content = union(enum) {
1342 char: u8,
1343 text: []const u8,
1344 line_break,
1345 };
1346
1347 const replacement = "\u{FFFD}";
1348
1349 fn next(iter: *TextIterator) ?Content {
1350 if (iter.pos >= iter.content.len) return null;
1351 if (iter.content[iter.pos] == '\\') {
1352 iter.pos += 1;
1353 if (iter.pos == iter.content.len) {
1354 return .{ .char = '\\' };
1355 } else if (iter.content[iter.pos] == '\n') {
1356 iter.pos += 1;
1357 return .line_break;
1358 } else if (isPunctuation(iter.content[iter.pos])) {
1359 const c = iter.content[iter.pos];
1360 iter.pos += 1;
1361 return .{ .char = c };
1362 } else {
1363 return .{ .char = '\\' };
1364 }
1365 }
1366 return iter.nextCodepoint();
1367 }
1368
1369 fn nextCodepoint(iter: *TextIterator) ?Content {
1370 switch (iter.content[iter.pos]) {
1371 0 => {
1372 iter.pos += 1;
1373 return .{ .text = replacement };
1374 },
1375 1...127 => |c| {
1376 iter.pos += 1;
1377 return .{ .char = c };
1378 },
1379 else => |b| {
1380 const cp_len = std.unicode.utf8ByteSequenceLength(b) catch {
1381 iter.pos += 1;
1382 return .{ .text = replacement };
1383 };
1384 const is_valid = iter.pos + cp_len < iter.content.len and
1385 std.unicode.utf8ValidateSlice(iter.content[iter.pos..][0..cp_len]);
1386 const cp_encoded = if (is_valid)
1387 iter.content[iter.pos..][0..cp_len]
1388 else
1389 replacement;
1390 iter.pos += cp_len;
1391 return .{ .text = cp_encoded };
1392 },
1393 }
1394 }
1395 };
1396};
1397
1398fn parseInlines(p: *Parser, content: []const u8) !ExtraIndex {
1399 var ip: InlineParser = .{
1400 .parent = p,
1401 .content = mem.trim(u8, content, " \t\n"),
1402 };
1403 defer ip.deinit();
1404 return try ip.parse();
1405}
1406
1407pub fn extraData(p: Parser, comptime T: type, index: ExtraIndex) ExtraData(T) {
1408 const fields = @typeInfo(T).Struct.fields;
1409 var i: usize = @intFromEnum(index);
1410 var result: T = undefined;
1411 inline for (fields) |field| {
1412 @field(result, field.name) = switch (field.type) {
1413 u32 => p.extra.items[i],
1414 else => @compileError("bad field type"),
1415 };
1416 i += 1;
1417 }
1418 return .{ .data = result, .end = i };
1419}
1420
1421pub fn extraChildren(p: Parser, index: ExtraIndex) []const Node.Index {
1422 const children = p.extraData(Node.Children, index);
1423 return @ptrCast(p.extra.items[children.end..][0..children.data.len]);
1424}
1425
1426fn addNode(p: *Parser, node: Node) !Node.Index {
1427 const index: Node.Index = @enumFromInt(@as(u32, @intCast(p.nodes.len)));
1428 try p.nodes.append(p.allocator, node);
1429 return index;
1430}
1431
1432fn addString(p: *Parser, s: []const u8) !StringIndex {
1433 if (s.len == 0) return .empty;
1434
1435 const index: StringIndex = @enumFromInt(@as(u32, @intCast(p.string_bytes.items.len)));
1436 try p.string_bytes.ensureUnusedCapacity(p.allocator, s.len + 1);
1437 p.string_bytes.appendSliceAssumeCapacity(s);
1438 p.string_bytes.appendAssumeCapacity(0);
1439 return index;
1440}
1441
1442fn addExtraChildren(p: *Parser, nodes: []const Node.Index) !ExtraIndex {
1443 const index: ExtraIndex = @enumFromInt(@as(u32, @intCast(p.extra.items.len)));
1444 try p.extra.ensureUnusedCapacity(p.allocator, nodes.len + 1);
1445 p.extra.appendAssumeCapacity(@intCast(nodes.len));
1446 p.extra.appendSliceAssumeCapacity(@ptrCast(nodes));
1447 return index;
1448}
1449
1450fn addScratchExtraNode(p: *Parser, node: Node.Index) !void {
1451 try p.scratch_extra.append(p.allocator, @intFromEnum(node));
1452}
1453
1454fn addScratchStringLine(p: *Parser, line: []const u8) !void {
1455 try p.scratch_string.ensureUnusedCapacity(p.allocator, line.len + 1);
1456 p.scratch_string.appendSliceAssumeCapacity(line);
1457 p.scratch_string.appendAssumeCapacity('\n');
1458}
1459
1460fn isBlank(line: []const u8) bool {
1461 return mem.indexOfNone(u8, line, " \t") == null;
1462}
1463
1464fn isPunctuation(c: u8) bool {
1465 return switch (c) {
1466 '!',
1467 '"',
1468 '#',
1469 '$',
1470 '%',
1471 '&',
1472 '\'',
1473 '(',
1474 ')',
1475 '*',
1476 '+',
1477 ',',
1478 '-',
1479 '.',
1480 '/',
1481 ':',
1482 ';',
1483 '<',
1484 '=',
1485 '>',
1486 '?',
1487 '@',
1488 '[',
1489 '\\',
1490 ']',
1491 '^',
1492 '_',
1493 '`',
1494 '{',
1495 '|',
1496 '}',
1497 '~',
1498 => true,
1499 else => false,
1500 };
1501}
lib/docs/wasm/markdown/renderer.zig created+249
......@@ -0,0 +1,249 @@
1const std = @import("std");
2const Document = @import("Document.zig");
3const Node = Document.Node;
4
5/// A Markdown document renderer.
6///
7/// Each concrete `Renderer` type has a `renderDefault` function, with the
8/// intention that custom `renderFn` implementations can call `renderDefault`
9/// for node types for which they require no special rendering.
10pub fn Renderer(comptime Writer: type, comptime Context: type) type {
11 return struct {
12 renderFn: *const fn (
13 r: Self,
14 doc: Document,
15 node: Node.Index,
16 writer: Writer,
17 ) Writer.Error!void = renderDefault,
18 context: Context,
19
20 const Self = @This();
21
22 pub fn render(r: Self, doc: Document, writer: Writer) Writer.Error!void {
23 try r.renderFn(r, doc, .root, writer);
24 }
25
26 pub fn renderDefault(
27 r: Self,
28 doc: Document,
29 node: Node.Index,
30 writer: Writer,
31 ) Writer.Error!void {
32 const data = doc.nodes.items(.data)[@intFromEnum(node)];
33 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
34 .root => {
35 for (doc.extraChildren(data.container.children)) |child| {
36 try r.renderFn(r, doc, child, writer);
37 }
38 },
39 .list => {
40 if (data.list.start.asNumber()) |start| {
41 if (start == 1) {
42 try writer.writeAll("<ol>\n");
43 } else {
44 try writer.print("<ol start=\"{}\">\n", .{start});
45 }
46 } else {
47 try writer.writeAll("<ul>\n");
48 }
49 for (doc.extraChildren(data.list.children)) |child| {
50 try r.renderFn(r, doc, child, writer);
51 }
52 if (data.list.start.asNumber() != null) {
53 try writer.writeAll("</ol>\n");
54 } else {
55 try writer.writeAll("</ul>\n");
56 }
57 },
58 .list_item => {
59 try writer.writeAll("<li>");
60 for (doc.extraChildren(data.list_item.children)) |child| {
61 if (data.list_item.tight and doc.nodes.items(.tag)[@intFromEnum(child)] == .paragraph) {
62 const para_data = doc.nodes.items(.data)[@intFromEnum(child)];
63 for (doc.extraChildren(para_data.container.children)) |para_child| {
64 try r.renderFn(r, doc, para_child, writer);
65 }
66 } else {
67 try r.renderFn(r, doc, child, writer);
68 }
69 }
70 try writer.writeAll("</li>\n");
71 },
72 .table => {
73 try writer.writeAll("<table>\n");
74 for (doc.extraChildren(data.container.children)) |child| {
75 try r.renderFn(r, doc, child, writer);
76 }
77 try writer.writeAll("</table>\n");
78 },
79 .table_row => {
80 try writer.writeAll("<tr>\n");
81 for (doc.extraChildren(data.container.children)) |child| {
82 try r.renderFn(r, doc, child, writer);
83 }
84 try writer.writeAll("</tr>\n");
85 },
86 .table_cell => {
87 if (data.table_cell.info.header) {
88 try writer.writeAll("<th");
89 } else {
90 try writer.writeAll("<td");
91 }
92 switch (data.table_cell.info.alignment) {
93 .unset => try writer.writeAll(">"),
94 else => |a| try writer.print(" style=\"text-align: {s}\">", .{@tagName(a)}),
95 }
96
97 for (doc.extraChildren(data.table_cell.children)) |child| {
98 try r.renderFn(r, doc, child, writer);
99 }
100
101 if (data.table_cell.info.header) {
102 try writer.writeAll("</th>\n");
103 } else {
104 try writer.writeAll("</td>\n");
105 }
106 },
107 .heading => {
108 try writer.print("<h{}>", .{data.heading.level});
109 for (doc.extraChildren(data.heading.children)) |child| {
110 try r.renderFn(r, doc, child, writer);
111 }
112 try writer.print("</h{}>\n", .{data.heading.level});
113 },
114 .code_block => {
115 const content = doc.string(data.code_block.content);
116 try writer.print("<pre><code>{}</code></pre>\n", .{fmtHtml(content)});
117 },
118 .blockquote => {
119 try writer.writeAll("<blockquote>\n");
120 for (doc.extraChildren(data.container.children)) |child| {
121 try r.renderFn(r, doc, child, writer);
122 }
123 try writer.writeAll("</blockquote>\n");
124 },
125 .paragraph => {
126 try writer.writeAll("<p>");
127 for (doc.extraChildren(data.container.children)) |child| {
128 try r.renderFn(r, doc, child, writer);
129 }
130 try writer.writeAll("</p>\n");
131 },
132 .thematic_break => {
133 try writer.writeAll("<hr />\n");
134 },
135 .link => {
136 const target = doc.string(data.link.target);
137 try writer.print("<a href=\"{}\">", .{fmtHtml(target)});
138 for (doc.extraChildren(data.link.children)) |child| {
139 try r.renderFn(r, doc, child, writer);
140 }
141 try writer.writeAll("</a>");
142 },
143 .image => {
144 const target = doc.string(data.link.target);
145 try writer.print("<img src=\"{}\" alt=\"", .{fmtHtml(target)});
146 for (doc.extraChildren(data.link.children)) |child| {
147 try renderInlineNodeText(doc, child, writer);
148 }
149 try writer.writeAll("\" />");
150 },
151 .strong => {
152 try writer.writeAll("<strong>");
153 for (doc.extraChildren(data.container.children)) |child| {
154 try r.renderFn(r, doc, child, writer);
155 }
156 try writer.writeAll("</strong>");
157 },
158 .emphasis => {
159 try writer.writeAll("<em>");
160 for (doc.extraChildren(data.container.children)) |child| {
161 try r.renderFn(r, doc, child, writer);
162 }
163 try writer.writeAll("</em>");
164 },
165 .code_span => {
166 const content = doc.string(data.text.content);
167 try writer.print("<code>{}</code>", .{fmtHtml(content)});
168 },
169 .text => {
170 const content = doc.string(data.text.content);
171 try writer.print("{}", .{fmtHtml(content)});
172 },
173 .line_break => {
174 try writer.writeAll("<br />\n");
175 },
176 }
177 }
178 };
179}
180
181/// Renders an inline node as plain text. Asserts that the node is an inline and
182/// has no non-inline children.
183pub fn renderInlineNodeText(
184 doc: Document,
185 node: Node.Index,
186 writer: anytype,
187) @TypeOf(writer).Error!void {
188 const data = doc.nodes.items(.data)[@intFromEnum(node)];
189 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
190 .root,
191 .list,
192 .list_item,
193 .table,
194 .table_row,
195 .table_cell,
196 .heading,
197 .code_block,
198 .blockquote,
199 .paragraph,
200 .thematic_break,
201 => unreachable, // Blocks
202
203 .link, .image => {
204 for (doc.extraChildren(data.link.children)) |child| {
205 try renderInlineNodeText(doc, child, writer);
206 }
207 },
208 .strong => {
209 for (doc.extraChildren(data.container.children)) |child| {
210 try renderInlineNodeText(doc, child, writer);
211 }
212 },
213 .emphasis => {
214 for (doc.extraChildren(data.container.children)) |child| {
215 try renderInlineNodeText(doc, child, writer);
216 }
217 },
218 .code_span, .text => {
219 const content = doc.string(data.text.content);
220 try writer.print("{}", .{fmtHtml(content)});
221 },
222 .line_break => {
223 try writer.writeAll("\n");
224 },
225 }
226}
227
228pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter(formatHtml) {
229 return .{ .data = bytes };
230}
231
232fn formatHtml(
233 bytes: []const u8,
234 comptime fmt: []const u8,
235 options: std.fmt.FormatOptions,
236 writer: anytype,
237) !void {
238 _ = fmt;
239 _ = options;
240 for (bytes) |b| {
241 switch (b) {
242 '<' => try writer.writeAll("&lt;"),
243 '>' => try writer.writeAll("&gt;"),
244 '&' => try writer.writeAll("&amp;"),
245 '"' => try writer.writeAll("&quot;"),
246 else => try writer.writeByte(b),
247 }
248 }
249}
lib/docs/ziglexer.js deleted-2147
......@@ -1,2147 +0,0 @@
1'use strict';
2
3const Tag = {
4 whitespace: "whitespace",
5 invalid: "invalid",
6 identifier: "identifier",
7 string_literal: "string_literal",
8 multiline_string_literal_line: "multiline_string_literal_line",
9 char_literal: "char_literal",
10 eof: "eof",
11 builtin: "builtin",
12 number_literal: "number_literal",
13 doc_comment: "doc_comment",
14 container_doc_comment: "container_doc_comment",
15 line_comment: "line_comment",
16 invalid_periodasterisks: "invalid_periodasterisks",
17 bang: "bang",
18 pipe: "pipe",
19 pipe_pipe: "pipe_pipe",
20 pipe_equal: "pipe_equal",
21 equal: "equal",
22 equal_equal: "equal_equal",
23 equal_angle_bracket_right: "equal_angle_bracket_right",
24 bang_equal: "bang_equal",
25 l_paren: "l_paren",
26 r_paren: "r_paren",
27 semicolon: "semicolon",
28 percent: "percent",
29 percent_equal: "percent_equal",
30 l_brace: "l_brace",
31 r_brace: "r_brace",
32 l_bracket: "l_bracket",
33 r_bracket: "r_bracket",
34 period: "period",
35 period_asterisk: "period_asterisk",
36 ellipsis2: "ellipsis2",
37 ellipsis3: "ellipsis3",
38 caret: "caret",
39 caret_equal: "caret_equal",
40 plus: "plus",
41 plus_plus: "plus_plus",
42 plus_equal: "plus_equal",
43 plus_percent: "plus_percent",
44 plus_percent_equal: "plus_percent_equal",
45 plus_pipe: "plus_pipe",
46 plus_pipe_equal: "plus_pipe_equal",
47 minus: "minus",
48 minus_equal: "minus_equal",
49 minus_percent: "minus_percent",
50 minus_percent_equal: "minus_percent_equal",
51 minus_pipe: "minus_pipe",
52 minus_pipe_equal: "minus_pipe_equal",
53 asterisk: "asterisk",
54 asterisk_equal: "asterisk_equal",
55 asterisk_asterisk: "asterisk_asterisk",
56 asterisk_percent: "asterisk_percent",
57 asterisk_percent_equal: "asterisk_percent_equal",
58 asterisk_pipe: "asterisk_pipe",
59 asterisk_pipe_equal: "asterisk_pipe_equal",
60 arrow: "arrow",
61 colon: "colon",
62 slash: "slash",
63 slash_equal: "slash_equal",
64 comma: "comma",
65 ampersand: "ampersand",
66 ampersand_equal: "ampersand_equal",
67 question_mark: "question_mark",
68 angle_bracket_left: "angle_bracket_left",
69 angle_bracket_left_equal: "angle_bracket_left_equal",
70 angle_bracket_angle_bracket_left: "angle_bracket_angle_bracket_left",
71 angle_bracket_angle_bracket_left_equal: "angle_bracket_angle_bracket_left_equal",
72 angle_bracket_angle_bracket_left_pipe: "angle_bracket_angle_bracket_left_pipe",
73 angle_bracket_angle_bracket_left_pipe_equal: "angle_bracket_angle_bracket_left_pipe_equal",
74 angle_bracket_right: "angle_bracket_right",
75 angle_bracket_right_equal: "angle_bracket_right_equal",
76 angle_bracket_angle_bracket_right: "angle_bracket_angle_bracket_right",
77 angle_bracket_angle_bracket_right_equal: "angle_bracket_angle_bracket_right_equal",
78 tilde: "tilde",
79 keyword_addrspace: "keyword_addrspace",
80 keyword_align: "keyword_align",
81 keyword_allowzero: "keyword_allowzero",
82 keyword_and: "keyword_and",
83 keyword_anyframe: "keyword_anyframe",
84 keyword_anytype: "keyword_anytype",
85 keyword_asm: "keyword_asm",
86 keyword_async: "keyword_async",
87 keyword_await: "keyword_await",
88 keyword_break: "keyword_break",
89 keyword_callconv: "keyword_callconv",
90 keyword_catch: "keyword_catch",
91 keyword_comptime: "keyword_comptime",
92 keyword_const: "keyword_const",
93 keyword_continue: "keyword_continue",
94 keyword_defer: "keyword_defer",
95 keyword_else: "keyword_else",
96 keyword_enum: "keyword_enum",
97 keyword_errdefer: "keyword_errdefer",
98 keyword_error: "keyword_error",
99 keyword_export: "keyword_export",
100 keyword_extern: "keyword_extern",
101 keyword_fn: "keyword_fn",
102 keyword_for: "keyword_for",
103 keyword_if: "keyword_if",
104 keyword_inline: "keyword_inline",
105 keyword_noalias: "keyword_noalias",
106 keyword_noinline: "keyword_noinline",
107 keyword_nosuspend: "keyword_nosuspend",
108 keyword_opaque: "keyword_opaque",
109 keyword_or: "keyword_or",
110 keyword_orelse: "keyword_orelse",
111 keyword_packed: "keyword_packed",
112 keyword_pub: "keyword_pub",
113 keyword_resume: "keyword_resume",
114 keyword_return: "keyword_return",
115 keyword_linksection: "keyword_linksection",
116 keyword_struct: "keyword_struct",
117 keyword_suspend: "keyword_suspend",
118 keyword_switch: "keyword_switch",
119 keyword_test: "keyword_test",
120 keyword_threadlocal: "keyword_threadlocal",
121 keyword_try: "keyword_try",
122 keyword_union: "keyword_union",
123 keyword_unreachable: "keyword_unreachable",
124 keyword_usingnamespace: "keyword_usingnamespace",
125 keyword_var: "keyword_var",
126 keyword_volatile: "keyword_volatile",
127 keyword_while: "keyword_while"
128}
129
130const Tok = {
131 const: { src: "const", tag: Tag.keyword_const },
132 var: { src: "var", tag: Tag.keyword_var },
133 colon: { src: ":", tag: Tag.colon },
134 eql: { src: "=", tag: Tag.equals },
135 space: { src: " ", tag: Tag.whitespace },
136 tab: { src: " ", tag: Tag.whitespace },
137 enter: { src: "\n", tag: Tag.whitespace },
138 semi: { src: ";", tag: Tag.semicolon },
139 l_bracket: { src: "[", tag: Tag.l_bracket },
140 r_bracket: { src: "]", tag: Tag.r_bracket },
141 l_brace: { src: "{", tag: Tag.l_brace },
142 r_brace: { src: "}", tag: Tag.r_brace },
143 l_paren: { src: "(", tag: Tag.l_paren },
144 r_paren: { src: ")", tag: Tag.r_paren },
145 period: { src: ".", tag: Tag.period },
146 comma: { src: ",", tag: Tag.comma },
147 question_mark: { src: "?", tag: Tag.question_mark },
148 asterisk: { src: "*", tag: Tag.asterisk },
149 identifier: (name) => { return { src: name, tag: Tag.identifier } },
150};
151
152
153const State = {
154 start: 0,
155 identifier: 1,
156 builtin: 2,
157 string_literal: 3,
158 string_literal_backslash: 4,
159 multiline_string_literal_line: 5,
160 char_literal: 6,
161 char_literal_backslash: 7,
162 char_literal_hex_escape: 8,
163 char_literal_unicode_escape_saw_u: 9,
164 char_literal_unicode_escape: 10,
165 char_literal_unicode_invalid: 11,
166 char_literal_unicode: 12,
167 char_literal_end: 13,
168 backslash: 14,
169 equal: 15,
170 bang: 16,
171 pipe: 17,
172 minus: 18,
173 minus_percent: 19,
174 minus_pipe: 20,
175 asterisk: 21,
176 asterisk_percent: 22,
177 asterisk_pipe: 23,
178 slash: 24,
179 line_comment_start: 25,
180 line_comment: 26,
181 doc_comment_start: 27,
182 doc_comment: 28,
183 int: 29,
184 int_exponent: 30,
185 int_period: 31,
186 float: 32,
187 float_exponent: 33,
188 ampersand: 34,
189 caret: 35,
190 percent: 36,
191 plus: 37,
192 plus_percent: 38,
193 plus_pipe: 39,
194 angle_bracket_left: 40,
195 angle_bracket_angle_bracket_left: 41,
196 angle_bracket_angle_bracket_left_pipe: 42,
197 angle_bracket_right: 43,
198 angle_bracket_angle_bracket_right: 44,
199 period: 45,
200 period_2: 46,
201 period_asterisk: 47,
202 saw_at_sign: 48,
203 whitespace: 49,
204}
205
206const keywords = {
207 "addrspace": Tag.keyword_addrspace,
208 "align": Tag.keyword_align,
209 "allowzero": Tag.keyword_allowzero,
210 "and": Tag.keyword_and,
211 "anyframe": Tag.keyword_anyframe,
212 "anytype": Tag.keyword_anytype,
213 "asm": Tag.keyword_asm,
214 "async": Tag.keyword_async,
215 "await": Tag.keyword_await,
216 "break": Tag.keyword_break,
217 "callconv": Tag.keyword_callconv,
218 "catch": Tag.keyword_catch,
219 "comptime": Tag.keyword_comptime,
220 "const": Tag.keyword_const,
221 "continue": Tag.keyword_continue,
222 "defer": Tag.keyword_defer,
223 "else": Tag.keyword_else,
224 "enum": Tag.keyword_enum,
225 "errdefer": Tag.keyword_errdefer,
226 "error": Tag.keyword_error,
227 "export": Tag.keyword_export,
228 "extern": Tag.keyword_extern,
229 "fn": Tag.keyword_fn,
230 "for": Tag.keyword_for,
231 "if": Tag.keyword_if,
232 "inline": Tag.keyword_inline,
233 "noalias": Tag.keyword_noalias,
234 "noinline": Tag.keyword_noinline,
235 "nosuspend": Tag.keyword_nosuspend,
236 "opaque": Tag.keyword_opaque,
237 "or": Tag.keyword_or,
238 "orelse": Tag.keyword_orelse,
239 "packed": Tag.keyword_packed,
240 "pub": Tag.keyword_pub,
241 "resume": Tag.keyword_resume,
242 "return": Tag.keyword_return,
243 "linksection": Tag.keyword_linksection,
244 "struct": Tag.keyword_struct,
245 "suspend": Tag.keyword_suspend,
246 "switch": Tag.keyword_switch,
247 "test": Tag.keyword_test,
248 "threadlocal": Tag.keyword_threadlocal,
249 "try": Tag.keyword_try,
250 "union": Tag.keyword_union,
251 "unreachable": Tag.keyword_unreachable,
252 "usingnamespace": Tag.keyword_usingnamespace,
253 "var": Tag.keyword_var,
254 "volatile": Tag.keyword_volatile,
255 "while": Tag.keyword_while,
256};
257
258function make_token(tag, start, end) {
259 return {
260 tag: tag,
261 loc: {
262 start: start,
263 end: end
264 }
265 }
266
267}
268
269function dump_tokens(tokens, raw_source) {
270
271 //TODO: this is not very fast
272 function find_tag_key(tag) {
273 for (const [key, value] of Object.entries(Tag)) {
274 if (value == tag) return key;
275 }
276 }
277
278 for (let i = 0; i < tokens.length; i++) {
279 const tok = tokens[i];
280 const z = raw_source.substring(tok.loc.start, tok.loc.end).toLowerCase();
281 console.log(`${find_tag_key(tok.tag)} "${tok.tag}" '${z}'`)
282 }
283}
284
285function* Tokenizer(raw_source) {
286 let tokenizer = new InnerTokenizer(raw_source);
287 while (true) {
288 let t = tokenizer.next();
289 if (t.tag == Tag.eof)
290 return;
291
292 t.src = raw_source.slice(t.loc.start, t.loc.end);
293
294 yield t;
295 }
296
297}
298function InnerTokenizer(raw_source) {
299 this.index = 0;
300 this.flag = false;
301
302 this.seen_escape_digits = undefined;
303 this.remaining_code_units = undefined;
304
305 this.next = () => {
306 let state = State.start;
307
308 var result = {
309 tag: -1,
310 loc: {
311 start: this.index,
312 end: undefined,
313 },
314 src: undefined,
315 };
316
317 //having a while (true) loop seems like a bad idea the loop should never
318 //take more iterations than twice the length of the source code
319 const MAX_ITERATIONS = raw_source.length * 2;
320 let iterations = 0;
321
322 while (iterations <= MAX_ITERATIONS) {
323
324 if (this.flag) {
325 return make_token(Tag.eof, this.index - 2, this.index - 2);
326 }
327 iterations += 1; // avoid death loops
328
329 var c = raw_source[this.index];
330
331 if (c === undefined) {
332 c = ' '; // push the last token
333 this.flag = true;
334 }
335
336 switch (state) {
337 case State.start:
338 switch (c) {
339 case 0: {
340 if (this.index != raw_source.length) {
341 result.tag = Tag.invalid;
342 result.loc.start = this.index;
343 this.index += 1;
344 result.loc.end = this.index;
345 return result;
346 }
347 result.loc.end = this.index;
348 return result;
349 }
350 case ' ':
351 case '\n':
352 case '\t':
353 case '\r': {
354 state = State.whitespace;
355 result.tag = Tag.whitespace;
356 result.loc.start = this.index;
357 break;
358 }
359 case '"': {
360 state = State.string_literal;
361 result.tag = Tag.string_literal;
362 break;
363 }
364 case '\'': {
365 state = State.char_literal;
366 break;
367 }
368 case 'a':
369 case 'b':
370 case 'c':
371 case 'd':
372 case 'e':
373 case 'f':
374 case 'g':
375 case 'h':
376 case 'i':
377 case 'j':
378 case 'k':
379 case 'l':
380 case 'm':
381 case 'n':
382 case 'o':
383 case 'p':
384 case 'q':
385 case 'r':
386 case 's':
387 case 't':
388 case 'u':
389 case 'v':
390 case 'w':
391 case 'x':
392 case 'y':
393 case 'z':
394 case 'A':
395 case 'B':
396 case 'C':
397 case 'D':
398 case 'E':
399 case 'F':
400 case 'G':
401 case 'H':
402 case 'I':
403 case 'J':
404 case 'K':
405 case 'L':
406 case 'M':
407 case 'N':
408 case 'O':
409 case 'P':
410 case 'Q':
411 case 'R':
412 case 'S':
413 case 'T':
414 case 'U':
415 case 'V':
416 case 'W':
417 case 'X':
418 case 'Y':
419 case 'Z':
420 case '_': {
421 state = State.identifier;
422 result.tag = Tag.identifier;
423 break;
424 }
425 case '@': {
426 state = State.saw_at_sign;
427 break;
428 }
429 case '=': {
430 state = State.equal;
431 break;
432 }
433 case '!': {
434 state = State.bang;
435 break;
436 }
437 case '|': {
438 state = State.pipe;
439 break;
440 }
441 case '(': {
442 result.tag = Tag.l_paren;
443 this.index += 1;
444 result.loc.end = this.index;
445
446 return result;
447
448 }
449 case ')': {
450 result.tag = Tag.r_paren;
451 this.index += 1; result.loc.end = this.index;
452 return result;
453
454 }
455 case '[': {
456 result.tag = Tag.l_bracket;
457 this.index += 1; result.loc.end = this.index;
458 return result;
459
460 }
461 case ']': {
462 result.tag = Tag.r_bracket;
463 this.index += 1; result.loc.end = this.index;
464 return result;
465
466 }
467 case ';': {
468 result.tag = Tag.semicolon;
469 this.index += 1; result.loc.end = this.index;
470 return result;
471
472 }
473 case ',': {
474 result.tag = Tag.comma;
475 this.index += 1; result.loc.end = this.index;
476 return result;
477
478 }
479 case '?': {
480 result.tag = Tag.question_mark;
481 this.index += 1; result.loc.end = this.index;
482 return result;
483
484 }
485 case ':': {
486 result.tag = Tag.colon;
487 this.index += 1; result.loc.end = this.index;
488 return result;
489
490 }
491 case '%': {
492 state = State.percent; break;
493 }
494 case '*': {
495 state = State.asterisk; break;
496 }
497 case '+': {
498 state = State.plus; break;
499 }
500 case '<': {
501 state = State.angle_bracket_left; break;
502 }
503 case '>': {
504 state = State.angle_bracket_right; break;
505 }
506 case '^': {
507 state = State.caret; break;
508 }
509 case '\\': {
510 state = State.backslash;
511 result.tag = Tag.multiline_string_literal_line; break;
512 }
513 case '{': {
514 result.tag = Tag.l_brace;
515 this.index += 1; result.loc.end = this.index;
516 return result;
517
518 }
519 case '}': {
520 result.tag = Tag.r_brace;
521 this.index += 1; result.loc.end = this.index;
522 return result;
523
524 }
525 case '~': {
526 result.tag = Tag.tilde;
527 this.index += 1; result.loc.end = this.index;
528 return result;
529
530 }
531 case '.': {
532 state = State.period; break;
533 }
534 case '-': {
535 state = State.minus; break;
536 }
537 case '/': {
538 state = State.slash; break;
539 }
540 case '&': {
541 state = State.ampersand; break;
542 }
543 case '0':
544 case '1':
545 case '2':
546 case '3':
547 case '4':
548 case '5':
549 case '6':
550 case '7':
551 case '8':
552 case '9':
553 {
554 state = State.int;
555 result.tag = Tag.number_literal; break;
556 }
557 default: {
558 result.tag = Tag.invalid;
559 result.loc.end = this.index;
560 this.index += 1;
561 return result;
562 }
563 }
564 break;
565 case State.saw_at_sign:
566 switch (c) {
567 case '"': {
568 result.tag = Tag.identifier;
569 state = State.string_literal; break;
570 }
571 case 'a':
572 case 'b':
573 case 'c':
574 case 'd':
575 case 'e':
576 case 'f':
577 case 'g':
578 case 'h':
579 case 'i':
580 case 'j':
581 case 'k':
582 case 'l':
583 case 'm':
584 case 'n':
585 case 'o':
586 case 'p':
587 case 'q':
588 case 'r':
589 case 's':
590 case 't':
591 case 'u':
592 case 'v':
593 case 'w':
594 case 'x':
595 case 'y':
596 case 'z':
597 case 'A':
598 case 'B':
599 case 'C':
600 case 'D':
601 case 'E':
602 case 'F':
603 case 'G':
604 case 'H':
605 case 'I':
606 case 'J':
607 case 'K':
608 case 'L':
609 case 'M':
610 case 'N':
611 case 'O':
612 case 'P':
613 case 'Q':
614 case 'R':
615 case 'S':
616 case 'T':
617 case 'U':
618 case 'V':
619 case 'W':
620 case 'X':
621 case 'Y':
622 case 'Z':
623 case '_': {
624 state = State.builtin;
625 result.tag = Tag.builtin;
626 break;
627 }
628 default: {
629 result.tag = Tag.invalid;
630 result.loc.end = this.index;
631 return result;
632 }
633 }
634 break;
635 case State.ampersand:
636 switch (c) {
637 case '=': {
638 result.tag = Tag.ampersand_equal;
639 this.index += 1; result.loc.end = this.index;
640 return result;
641 }
642 default: {
643 result.tag = Tag.ampersand; result.loc.end = this.index;
644 return result;
645 }
646 }
647 break;
648 case State.asterisk: switch (c) {
649 case '=': {
650 result.tag = Tag.asterisk_equal;
651 this.index += 1; result.loc.end = this.index;
652 return result;
653 }
654 case '*': {
655 result.tag = Tag.asterisk_asterisk;
656 this.index += 1; result.loc.end = this.index;
657 return result;
658 }
659 case '%': {
660 state = State.asterisk_percent; break;
661 }
662 case '|': {
663 state = State.asterisk_pipe; break;
664 }
665 default: {
666 result.tag = Tag.asterisk;
667 result.loc.end = this.index;
668 return result;
669 }
670 }
671 break;
672 case State.asterisk_percent:
673 switch (c) {
674 case '=': {
675 result.tag = Tag.asterisk_percent_equal;
676 this.index += 1; result.loc.end = this.index;
677 return result;
678 }
679 default: {
680 result.tag = Tag.asterisk_percent;
681 result.loc.end = this.index;
682 return result;
683 }
684 }
685 break;
686 case State.asterisk_pipe:
687 switch (c) {
688 case '=': {
689 result.tag = Tag.asterisk_pipe_equal;
690 this.index += 1; result.loc.end = this.index;
691 return result;
692 }
693 default: {
694 result.tag = Tag.asterisk_pipe; result.loc.end = this.index;
695 return result;
696 }
697 }
698 break;
699 case State.percent:
700 switch (c) {
701 case '=': {
702 result.tag = Tag.percent_equal;
703 this.index += 1; result.loc.end = this.index;
704 return result;
705 }
706 default: {
707 result.tag = Tag.percent; result.loc.end = this.index;
708 return result;
709 }
710 }
711 break;
712 case State.plus:
713 switch (c) {
714 case '=': {
715 result.tag = Tag.plus_equal;
716 this.index += 1; result.loc.end = this.index;
717 return result;
718 }
719 case '+': {
720 result.tag = Tag.plus_plus;
721 this.index += 1; result.loc.end = this.index;
722 return result;
723 }
724 case '%': {
725 state = State.plus_percent; break;
726 }
727 case '|': {
728 state = State.plus_pipe; break;
729 }
730 default: {
731 result.tag = Tag.plus; result.loc.end = this.index;
732 return result;
733 }
734 }
735 break;
736 case State.plus_percent:
737 switch (c) {
738 case '=': {
739 result.tag = Tag.plus_percent_equal;
740 this.index += 1; result.loc.end = this.index;
741 return result;
742 }
743 default: {
744 result.tag = Tag.plus_percent; result.loc.end = this.index;
745 return result;
746 }
747 }
748 break;
749 case State.plus_pipe:
750 switch (c) {
751 case '=': {
752 result.tag = Tag.plus_pipe_equal;
753 this.index += 1; result.loc.end = this.index;
754 return result;
755 }
756 default: {
757 result.tag = Tag.plus_pipe; result.loc.end = this.index;
758 return result;
759 }
760 }
761 break;
762 case State.caret:
763 switch (c) {
764 case '=': {
765 result.tag = Tag.caret_equal;
766 this.index += 1; result.loc.end = this.index;
767 return result;
768 }
769 default: {
770 result.tag = Tag.caret; result.loc.end = this.index;
771 return result;
772 }
773 }
774 break;
775 case State.identifier:
776 switch (c) {
777 case 'a':
778 case 'b':
779 case 'c':
780 case 'd':
781 case 'e':
782 case 'f':
783 case 'g':
784 case 'h':
785 case 'i':
786 case 'j':
787 case 'k':
788 case 'l':
789 case 'm':
790 case 'n':
791 case 'o':
792 case 'p':
793 case 'q':
794 case 'r':
795 case 's':
796 case 't':
797 case 'u':
798 case 'v':
799 case 'w':
800 case 'x':
801 case 'y':
802 case 'z':
803 case 'A':
804 case 'B':
805 case 'C':
806 case 'D':
807 case 'E':
808 case 'F':
809 case 'G':
810 case 'H':
811 case 'I':
812 case 'J':
813 case 'K':
814 case 'L':
815 case 'M':
816 case 'N':
817 case 'O':
818 case 'P':
819 case 'Q':
820 case 'R':
821 case 'S':
822 case 'T':
823 case 'U':
824 case 'V':
825 case 'W':
826 case 'X':
827 case 'Y':
828 case 'Z':
829 case '_':
830 case '0':
831 case '1':
832 case '2':
833 case '3':
834 case '4':
835 case '5':
836 case '6':
837 case '7':
838 case '8':
839 case '9': break;
840 default: {
841 // if (Token.getKeyword(buffer[result.loc.start..this.index])) | tag | {
842 const z = raw_source.substring(result.loc.start, this.index);
843 if (z in keywords) {
844 result.tag = keywords[z];
845 }
846 result.loc.end = this.index;
847 return result;
848 }
849
850
851 }
852 break;
853 case State.builtin: switch (c) {
854 case 'a':
855 case 'b':
856 case 'c':
857 case 'd':
858 case 'e':
859 case 'f':
860 case 'g':
861 case 'h':
862 case 'i':
863 case 'j':
864 case 'k':
865 case 'l':
866 case 'm':
867 case 'n':
868 case 'o':
869 case 'p':
870 case 'q':
871 case 'r':
872 case 's':
873 case 't':
874 case 'u':
875 case 'v':
876 case 'w':
877 case 'x':
878 case 'y':
879 case 'z':
880 case 'A':
881 case 'B':
882 case 'C':
883 case 'D':
884 case 'E':
885 case 'F':
886 case 'G':
887 case 'H':
888 case 'I':
889 case 'J':
890 case 'K':
891 case 'L':
892 case 'M':
893 case 'N':
894 case 'O':
895 case 'P':
896 case 'Q':
897 case 'R':
898 case 'S':
899 case 'T':
900 case 'U':
901 case 'V':
902 case 'W':
903 case 'X':
904 case 'Y':
905 case 'Z':
906 case '_':
907 case '0':
908 case '1':
909 case '2':
910 case '3':
911 case '4':
912 case '5':
913 case '6':
914 case '7':
915 case '8':
916 case '9': break;
917 default: result.loc.end = this.index;
918 return result;
919 }
920 break;
921 case State.backslash:
922 switch (c) {
923 case '\\': {
924 state = State.multiline_string_literal_line;
925 break;
926 }
927 default: {
928 result.tag = Tag.invalid;
929 result.loc.end = this.index;
930 return result;
931 }
932 }
933 break;
934 case State.string_literal:
935 switch (c) {
936 case '\\': {
937 state = State.string_literal_backslash; break;
938 }
939 case '"': {
940 this.index += 1;
941 result.loc.end = this.index;
942
943 return result;
944 }
945 case 0: {
946 //TODO: PORT
947 // if (this.index == buffer.len) {
948 // result.tag = .invalid;
949 // break;
950 // } else {
951 // checkLiteralCharacter();
952 // }
953 result.loc.end = this.index;
954 return result;
955 }
956 case '\n': {
957 result.tag = Tag.invalid;
958 result.loc.end = this.index;
959 return result;
960 }
961 //TODO: PORT
962 //default: checkLiteralCharacter(),
963 }
964 break;
965 case State.string_literal_backslash:
966 switch (c) {
967 case 0:
968 case '\n': {
969 result.tag = Tag.invalid;
970 result.loc.end = this.index;
971 return result;
972 }
973 default: {
974 state = State.string_literal; break;
975 }
976 }
977 break;
978 case State.char_literal: switch (c) {
979 case 0: {
980 result.tag = Tag.invalid;
981 result.loc.end = this.index;
982 return result;
983 }
984 case '\\': {
985 state = State.char_literal_backslash;
986 break;
987 }
988 //TODO: PORT
989 // '\'', 0x80...0xbf, 0xf8...0xff => {
990 // result.tag = .invalid;
991 // break;
992 // },
993 // 0xc0...0xdf => { // 110xxxxx
994 // this.remaining_code_units = 1;
995 // state = .char_literal_unicode;
996 // },
997 // 0xe0...0xef => { // 1110xxxx
998 // this.remaining_code_units = 2;
999 // state = .char_literal_unicode;
1000 // },
1001 // 0xf0...0xf7 => { // 11110xxx
1002 // this.remaining_code_units = 3;
1003 // state = .char_literal_unicode;
1004 // },
1005
1006 // case 0x80:
1007 // case 0x81:
1008 // case 0x82:
1009 // case 0x83:
1010 // case 0x84:
1011 // case 0x85:
1012 // case 0x86:
1013 // case 0x87:
1014 // case 0x88:
1015 // case 0x89:
1016 // case 0x8a:
1017 // case 0x8b:
1018 // case 0x8c:
1019 // case 0x8d:
1020 // case 0x8e:
1021 // case 0x8f:
1022 // case 0x90:
1023 // case 0x91:
1024 // case 0x92:
1025 // case 0x93:
1026 // case 0x94:
1027 // case 0x95:
1028 // case 0x96:
1029 // case 0x97:
1030 // case 0x98:
1031 // case 0x99:
1032 // case 0x9a:
1033 // case 0x9b:
1034 // case 0x9c:
1035 // case 0x9d:
1036 // case 0x9e:
1037 // case 0x9f:
1038 // case 0xa0:
1039 // case 0xa1:
1040 // case 0xa2:
1041 // case 0xa3:
1042 // case 0xa4:
1043 // case 0xa5:
1044 // case 0xa6:
1045 // case 0xa7:
1046 // case 0xa8:
1047 // case 0xa9:
1048 // case 0xaa:
1049 // case 0xab:
1050 // case 0xac:
1051 // case 0xad:
1052 // case 0xae:
1053 // case 0xaf:
1054 // case 0xb0:
1055 // case 0xb1:
1056 // case 0xb2:
1057 // case 0xb3:
1058 // case 0xb4:
1059 // case 0xb5:
1060 // case 0xb6:
1061 // case 0xb7:
1062 // case 0xb8:
1063 // case 0xb9:
1064 // case 0xba:
1065 // case 0xbb:
1066 // case 0xbc:
1067 // case 0xbd:
1068 // case 0xbe:
1069 // case 0xbf:
1070 // case 0xf8:
1071 // case 0xf9:
1072 // case 0xfa:
1073 // case 0xfb:
1074 // case 0xfc:
1075 // case 0xfd:
1076 // case 0xfe:
1077 // case 0xff:
1078 // result.tag = .invalid;
1079 // break;
1080 // case 0xc0:
1081 // case 0xc1:
1082 // case 0xc2:
1083 // case 0xc3:
1084 // case 0xc4:
1085 // case 0xc5:
1086 // case 0xc6:
1087 // case 0xc7:
1088 // case 0xc8:
1089 // case 0xc9:
1090 // case 0xca:
1091 // case 0xcb:
1092 // case 0xcc:
1093 // case 0xcd:
1094 // case 0xce:
1095 // case 0xcf:
1096 // case 0xd0:
1097 // case 0xd1:
1098 // case 0xd2:
1099 // case 0xd3:
1100 // case 0xd4:
1101 // case 0xd5:
1102 // case 0xd6:
1103 // case 0xd7:
1104 // case 0xd8:
1105 // case 0xd9:
1106 // case 0xda:
1107 // case 0xdb:
1108 // case 0xdc:
1109 // case 0xdd:
1110 // case 0xde:
1111 // case 0xdf:
1112 // this.remaining_code_units = 1;
1113 // state = .char_literal_unicode;
1114 // case 0xe0:
1115 // case 0xe1:
1116 // case 0xe2:
1117 // case 0xe3:
1118 // case 0xe4:
1119 // case 0xe5:
1120 // case 0xe6:
1121 // case 0xe7:
1122 // case 0xe8:
1123 // case 0xe9:
1124 // case 0xea:
1125 // case 0xeb:
1126 // case 0xec:
1127 // case 0xed:
1128 // case 0xee:
1129 // case 0xef:
1130 // this.remaining_code_units = 2;
1131 // state = .char_literal_unicode;
1132 // case 0xf0:
1133 // case 0xf1:
1134 // case 0xf2:
1135 // case 0xf3:
1136 // case 0xf4:
1137 // case 0xf5:
1138 // case 0xf6:
1139 // case 0xf7:
1140 // this.remaining_code_units = 3;
1141 // state = .char_literal_unicode;
1142
1143 case '\n': {
1144 result.tag = Tag.invalid;
1145 result.loc.end = this.index;
1146 return result;
1147 }
1148 default: {
1149 state = State.char_literal_end; break;
1150 }
1151 }
1152 break;
1153 case State.char_literal_backslash:
1154 switch (c) {
1155 case 0:
1156 case '\n': {
1157 result.tag = Tag.invalid;
1158 result.loc.end = this.index;
1159 return result;
1160 }
1161 case 'x': {
1162 state = State.char_literal_hex_escape;
1163 this.seen_escape_digits = 0; break;
1164 }
1165 case 'u': {
1166 state = State.char_literal_unicode_escape_saw_u; break;
1167 }
1168 default: {
1169 state = State.char_literal_end; break;
1170 }
1171 }
1172 break;
1173 case State.char_literal_hex_escape:
1174 switch (c) {
1175 case '0':
1176 case '1':
1177 case '2':
1178 case '3':
1179 case '4':
1180 case '5':
1181 case '6':
1182 case '7':
1183 case '8':
1184 case '9':
1185 case 'a':
1186 case 'b':
1187 case 'c':
1188 case 'd':
1189 case 'e':
1190 case 'f':
1191 case 'A':
1192 case 'B':
1193 case 'C':
1194 case 'D':
1195 case 'E':
1196 case 'F': {
1197 this.seen_escape_digits += 1;
1198 if (this.seen_escape_digits == 2) {
1199 state = State.char_literal_end;
1200 } break;
1201 }
1202 default: {
1203 result.tag = Tag.invalid;
1204 esult.loc.end = this.index;
1205 return result;
1206 }
1207 }
1208 break;
1209 case State.char_literal_unicode_escape_saw_u:
1210 switch (c) {
1211 case 0: {
1212 result.tag = Tag.invalid;
1213 result.loc.end = this.index;
1214 return result;
1215 }
1216 case '{': {
1217 state = State.char_literal_unicode_escape; break;
1218 }
1219 default: {
1220 result.tag = Tag.invalid;
1221 state = State.char_literal_unicode_invalid; break;
1222 }
1223 }
1224 break;
1225 case State.char_literal_unicode_escape:
1226 switch (c) {
1227 case 0: {
1228 result.tag = Tag.invalid;
1229 result.loc.end = this.index;
1230 return result;
1231 }
1232 case '0':
1233 case '1':
1234 case '2':
1235 case '3':
1236 case '4':
1237 case '5':
1238 case '6':
1239 case '7':
1240 case '8':
1241 case '9':
1242 case 'a':
1243 case 'b':
1244 case 'c':
1245 case 'd':
1246 case 'e':
1247 case 'f':
1248 case 'A':
1249 case 'B':
1250 case 'C':
1251 case 'D':
1252 case 'E':
1253 case 'F': break;
1254 case '}': {
1255 state = State.char_literal_end; // too many/few digits handled later
1256 break;
1257 }
1258 default: {
1259 result.tag = Tag.invalid;
1260 state = State.char_literal_unicode_invalid; break;
1261 }
1262 }
1263 break;
1264 case State.char_literal_unicode_invalid:
1265 switch (c) {
1266 // Keep consuming characters until an obvious stopping point.
1267 // This consolidates e.g. `u{0ab1Q}` into a single invalid token
1268 // instead of creating the tokens `u{0ab1`, `Q`, `}`
1269 case 'a':
1270 case 'b':
1271 case 'c':
1272 case 'd':
1273 case 'e':
1274 case 'f':
1275 case 'g':
1276 case 'h':
1277 case 'i':
1278 case 'j':
1279 case 'k':
1280 case 'l':
1281 case 'm':
1282 case 'n':
1283 case 'o':
1284 case 'p':
1285 case 'q':
1286 case 'r':
1287 case 's':
1288 case 't':
1289 case 'u':
1290 case 'v':
1291 case 'w':
1292 case 'x':
1293 case 'y':
1294 case 'z':
1295 case 'A':
1296 case 'B':
1297 case 'C':
1298 case 'D':
1299 case 'E':
1300 case 'F':
1301 case 'G':
1302 case 'H':
1303 case 'I':
1304 case 'J':
1305 case 'K':
1306 case 'L':
1307 case 'M':
1308 case 'N':
1309 case 'O':
1310 case 'P':
1311 case 'Q':
1312 case 'R':
1313 case 'S':
1314 case 'T':
1315 case 'U':
1316 case 'V':
1317 case 'W':
1318 case 'X':
1319 case 'Y':
1320 case 'Z':
1321 case '}':
1322 case '0':
1323 case '1':
1324 case '2':
1325 case '3':
1326 case '4':
1327 case '5':
1328 case '6':
1329 case '7':
1330 case '8':
1331 case '9': break;
1332 default: break;
1333 }
1334 break;
1335 case State.char_literal_end:
1336 switch (c) {
1337 case '\'': {
1338 result.tag = Tag.char_literal;
1339 this.index += 1;
1340 result.loc.end = this.index;
1341 return result;
1342 }
1343 default: {
1344 result.tag = Tag.invalid;
1345 result.loc.end = this.index;
1346 return result;
1347 }
1348 }
1349 break;
1350 case State.char_literal_unicode:
1351 switch (c) {
1352 // 0x80...0xbf => {
1353 // this.remaining_code_units -= 1;
1354 // if (this.remaining_code_units == 0) {
1355 // state = .char_literal_end;
1356 // }
1357 // },
1358 default: {
1359 result.tag = Tag.invalid;
1360 result.loc.end = this.index;
1361 return result;
1362 }
1363 }
1364 break;
1365 case State.multiline_string_literal_line:
1366 switch (c) {
1367 case 0:
1368 result.loc.end = this.index;
1369 return result;
1370 case '\n': {
1371
1372 this.index += 1;
1373 result.loc.end = this.index;
1374 return result;
1375 }
1376 case '\t': break;
1377 //TODO: PORT
1378 //default: checkLiteralCharacter(),
1379
1380 }
1381 break;
1382 case State.bang:
1383 switch (c) {
1384 case '=': {
1385 result.tag = Tag.bang_equal;
1386 this.index += 1;
1387 result.loc.end = this.index;
1388 return result;
1389 }
1390 default: {
1391 result.tag = Tag.bang;
1392 result.loc.end = this.index;
1393 return result;
1394 }
1395 }
1396 break;
1397 case State.pipe:
1398 switch (c) {
1399 case '=': {
1400 result.tag = Tag.pipe_equal;
1401 this.index += 1;
1402 result.loc.end = this.index;
1403 return result;
1404 }
1405 case '|': {
1406 result.tag = Tag.pipe_pipe;
1407 this.index += 1;
1408 result.loc.end = this.index;
1409 return result;
1410 }
1411 default: {
1412 result.tag = Tag.pipe;
1413 result.loc.end = this.index;
1414 return result;
1415 }
1416 }
1417 break;
1418 case State.equal: switch (c) {
1419 case '=': {
1420 result.tag = Tag.equal_equal;
1421 this.index += 1;
1422 result.loc.end = this.index;
1423 return result;
1424 }
1425 case '>': {
1426 result.tag = Tag.equal_angle_bracket_right;
1427 this.index += 1;
1428 result.loc.end = this.index;
1429 return result;
1430 }
1431 default: {
1432 result.tag = Tag.equal;
1433 result.loc.end = this.index;
1434 return result;
1435 }
1436 }
1437 break;
1438 case State.minus: switch (c) {
1439 case '>': {
1440 result.tag = Tag.arrow;
1441 this.index += 1;
1442 result.loc.end = this.index;
1443 return result;
1444 }
1445 case '=': {
1446 result.tag = Tag.minus_equal;
1447 this.index += 1;
1448 result.loc.end = this.index;
1449 return result;
1450 }
1451 case '%': {
1452 state = State.minus_percent; break;
1453 }
1454 case '|': {
1455 state = State.minus_pipe; break;
1456 }
1457 default: {
1458 result.tag = Tag.minus;
1459 result.loc.end = this.index;
1460 return result;
1461 }
1462 }
1463 break;
1464 case State.minus_percent:
1465 switch (c) {
1466 case '=': {
1467 result.tag = Tag.minus_percent_equal;
1468 this.index += 1;
1469 result.loc.end = this.index;
1470 return result;
1471 }
1472 default: {
1473 result.tag = Tag.minus_percent;
1474 result.loc.end = this.index;
1475 return result;
1476 }
1477 }
1478 break;
1479 case State.minus_pipe:
1480 switch (c) {
1481 case '=': {
1482 result.tag = Tag.minus_pipe_equal;
1483 this.index += 1;
1484 result.loc.end = this.index;
1485 return result;
1486 }
1487 default: {
1488 result.tag = Tag.minus_pipe;
1489 result.loc.end = this.index;
1490 return result;
1491 }
1492 }
1493 break;
1494 case State.angle_bracket_left:
1495 switch (c) {
1496 case '<': {
1497 state = State.angle_bracket_angle_bracket_left; break;
1498 }
1499 case '=': {
1500 result.tag = Tag.angle_bracket_left_equal;
1501 this.index += 1;
1502 result.loc.end = this.index;
1503 return result;
1504 }
1505 default: {
1506 result.tag = Tag.angle_bracket_left;
1507 result.loc.end = this.index;
1508 return result;
1509 }
1510 }
1511 break;
1512 case State.angle_bracket_angle_bracket_left:
1513 switch (c) {
1514 case '=': {
1515 result.tag = Tag.angle_bracket_angle_bracket_left_equal;
1516 this.index += 1;
1517 result.loc.end = this.index;
1518 return result;
1519 }
1520 case '|': {
1521 state = State.angle_bracket_angle_bracket_left_pipe;
1522 }
1523 default: {
1524 result.tag = Tag.angle_bracket_angle_bracket_left;
1525 result.loc.end = this.index;
1526 return result;
1527 }
1528 }
1529 break;
1530 case State.angle_bracket_angle_bracket_left_pipe:
1531 switch (c) {
1532 case '=': {
1533 result.tag = Tag.angle_bracket_angle_bracket_left_pipe_equal;
1534 this.index += 1;
1535 result.loc.end = this.index;
1536 return result;
1537 }
1538 default: {
1539 result.tag = Tag.angle_bracket_angle_bracket_left_pipe;
1540 result.loc.end = this.index;
1541 return result;
1542 }
1543 }
1544 break;
1545 case State.angle_bracket_right:
1546 switch (c) {
1547 case '>': {
1548 state = State.angle_bracket_angle_bracket_right; break;
1549 }
1550 case '=': {
1551 result.tag = Tag.angle_bracket_right_equal;
1552 this.index += 1;
1553 result.loc.end = this.index;
1554 return result;
1555 }
1556 default: {
1557 result.tag = Tag.angle_bracket_right;
1558 result.loc.end = this.index;
1559 return result;
1560 }
1561 }
1562 break;
1563 case State.angle_bracket_angle_bracket_right:
1564 switch (c) {
1565 case '=': {
1566 result.tag = Tag.angle_bracket_angle_bracket_right_equal;
1567 this.index += 1;
1568 result.loc.end = this.index;
1569 return result;
1570 }
1571 default: {
1572 result.tag = Tag.angle_bracket_angle_bracket_right;
1573 result.loc.end = this.index;
1574 return result;
1575 }
1576 }
1577 break;
1578 case State.period:
1579 switch (c) {
1580 case '.': {
1581 state = State.period_2; break;
1582 }
1583 case '*': {
1584 state = State.period_asterisk; break;
1585 }
1586 default: {
1587 result.tag = Tag.period;
1588 result.loc.end = this.index;
1589 return result;
1590 }
1591 }
1592 break;
1593 case State.period_2:
1594 switch (c) {
1595 case '.': {
1596 result.tag = Tag.ellipsis3;
1597 this.index += 1;
1598 result.loc.end = this.index;
1599 return result;
1600 }
1601 default: {
1602 result.tag = Tag.ellipsis2;
1603 result.loc.end = this.index;
1604 return result;
1605 }
1606 }
1607 break;
1608 case State.period_asterisk:
1609 switch (c) {
1610 case '*': {
1611 result.tag = Tag.invalid_periodasterisks;
1612 result.loc.end = this.index;
1613 return result;
1614 }
1615 default: {
1616 result.tag = Tag.period_asterisk;
1617 result.loc.end = this.index;
1618 return result;
1619 }
1620 }
1621 break;
1622 case State.slash:
1623 switch (c) {
1624 case '/': {
1625 state = State.line_comment_start;
1626 break;
1627 }
1628 case '=': {
1629 result.tag = Tag.slash_equal;
1630 this.index += 1;
1631 result.loc.end = this.index;
1632 return result;
1633 }
1634 default: {
1635 result.tag = Tag.slash;
1636 result.loc.end = this.index;
1637 return result;
1638 }
1639 } break;
1640 case State.line_comment_start:
1641 switch (c) {
1642 case 0: {
1643 if (this.index != raw_source.length) {
1644 result.tag = Tag.invalid;
1645 this.index += 1;
1646 }
1647 result.loc.end = this.index;
1648 return result;
1649 }
1650 case '/': {
1651 state = State.doc_comment_start; break;
1652 }
1653 case '!': {
1654 result.tag = Tag.container_doc_comment;
1655 state = State.doc_comment; break;
1656 }
1657 case '\n': {
1658 state = State.start;
1659 result.loc.start = this.index + 1; break;
1660 }
1661 case '\t':
1662 state = State.line_comment; break;
1663 default: {
1664 state = State.line_comment;
1665 //TODO: PORT
1666 //checkLiteralCharacter();
1667 break;
1668 }
1669 } break;
1670 case State.doc_comment_start:
1671 switch (c) {
1672 case '/': {
1673 state = State.line_comment; break;
1674 }
1675 case 0:
1676 case '\n':
1677 {
1678 result.tag = Tag.doc_comment;
1679 result.loc.end = this.index;
1680 return result;
1681 }
1682 case '\t': {
1683 state = State.doc_comment;
1684 result.tag = Tag.doc_comment; break;
1685 }
1686 default: {
1687 state = State.doc_comment;
1688 result.tag = Tag.doc_comment;
1689 //TODO: PORT
1690 //checkLiteralCharacter();
1691 break;
1692 }
1693 } break;
1694 case State.line_comment:
1695 switch (c) {
1696 case 0: {
1697 if (this.index != raw_source.length) {
1698 result.tag = Tag.invalid;
1699 this.index += 1;
1700 }
1701 result.loc.end = this.index;
1702 return result;
1703 }
1704 case '\n': {
1705 result.tag = Tag.line_comment;
1706 result.loc.end = this.index;
1707 return result;
1708 }
1709 case '\t': break;
1710 //TODO: PORT
1711 //default: checkLiteralCharacter(),
1712 } break;
1713 case State.doc_comment:
1714 switch (c) {
1715 case 0://
1716 case '\n':
1717 result.loc.end = this.index;
1718 return result;
1719 case '\t': break;
1720 //TODOL PORT
1721 // default: checkLiteralCharacter(),
1722 default:
1723 break;
1724 } break;
1725 case State.int:
1726 switch (c) {
1727 case '.':
1728 state = State.int_period;
1729 break;
1730 case '_':
1731 case 'a':
1732 case 'b':
1733 case 'c':
1734 case 'd':
1735 case 'f':
1736 case 'g':
1737 case 'h':
1738 case 'i':
1739 case 'j':
1740 case 'k':
1741 case 'l':
1742 case 'm':
1743 case 'n':
1744 case 'o':
1745 case 'q':
1746 case 'r':
1747 case 's':
1748 case 't':
1749 case 'u':
1750 case 'v':
1751 case 'w':
1752 case 'x':
1753 case 'y':
1754 case 'z':
1755 case 'A':
1756 case 'B':
1757 case 'C':
1758 case 'D':
1759 case 'F':
1760 case 'G':
1761 case 'H':
1762 case 'I':
1763 case 'J':
1764 case 'K':
1765 case 'L':
1766 case 'M':
1767 case 'N':
1768 case 'O':
1769 case 'Q':
1770 case 'R':
1771 case 'S':
1772 case 'T':
1773 case 'U':
1774 case 'V':
1775 case 'W':
1776 case 'X':
1777 case 'Y':
1778 case 'Z':
1779 case '0':
1780 case '1':
1781 case '2':
1782 case '3':
1783 case '4':
1784 case '5':
1785 case '6':
1786 case '7':
1787 case '8':
1788 case '9':
1789 break;
1790 case 'e':
1791 case 'E':
1792 case 'p':
1793 case 'P':
1794 state = State.int_exponent;
1795 break;
1796 default: result.loc.end = this.index;
1797 return result;
1798 } break;
1799 case State.int_exponent:
1800 switch (c) {
1801 case '-':
1802 case '+':
1803 {
1804 ``
1805 state = State.float; break;
1806 }
1807 default: {
1808 this.index -= 1;
1809 state = State.int; break;
1810 }
1811 } break;
1812 case State.int_period: switch (c) {
1813 case '_':
1814 case 'a':
1815 case 'b':
1816 case 'c':
1817 case 'd':
1818 case 'f':
1819 case 'g':
1820 case 'h':
1821 case 'i':
1822 case 'j':
1823 case 'k':
1824 case 'l':
1825 case 'm':
1826 case 'n':
1827 case 'o':
1828 case 'q':
1829 case 'r':
1830 case 's':
1831 case 't':
1832 case 'u':
1833 case 'v':
1834 case 'w':
1835 case 'x':
1836 case 'y':
1837 case 'z':
1838 case 'A':
1839 case 'B':
1840 case 'C':
1841 case 'D':
1842 case 'F':
1843 case 'G':
1844 case 'H':
1845 case 'I':
1846 case 'J':
1847 case 'K':
1848 case 'L':
1849 case 'M':
1850 case 'N':
1851 case 'O':
1852 case 'Q':
1853 case 'R':
1854 case 'S':
1855 case 'T':
1856 case 'U':
1857 case 'V':
1858 case 'W':
1859 case 'X':
1860 case 'Y':
1861 case 'Z':
1862 case '0':
1863 case '1':
1864 case '2':
1865 case '3':
1866 case '4':
1867 case '5':
1868 case '6':
1869 case '7':
1870 case '8':
1871 case '9': {
1872 state = State.float; break;
1873 }
1874 case 'e':
1875 case 'E':
1876 case 'p':
1877 case 'P':
1878 state = State.float_exponent; break;
1879 default: {
1880 this.index -= 1;
1881 result.loc.end = this.index;
1882 return result;
1883 }
1884 } break;
1885 case State.float:
1886 switch (c) {
1887 case '_':
1888 case 'a':
1889 case 'b':
1890 case 'c':
1891 case 'd':
1892 case 'f':
1893 case 'g':
1894 case 'h':
1895 case 'i':
1896 case 'j':
1897 case 'k':
1898 case 'l':
1899 case 'm':
1900 case 'n':
1901 case 'o':
1902 case 'q':
1903 case 'r':
1904 case 's':
1905 case 't':
1906 case 'u':
1907 case 'v':
1908 case 'w':
1909 case 'x':
1910 case 'y':
1911 case 'z':
1912 case 'A':
1913 case 'B':
1914 case 'C':
1915 case 'D':
1916 case 'F':
1917 case 'G':
1918 case 'H':
1919 case 'I':
1920 case 'J':
1921 case 'K':
1922 case 'L':
1923 case 'M':
1924 case 'N':
1925 case 'O':
1926 case 'Q':
1927 case 'R':
1928 case 'S':
1929 case 'T':
1930 case 'U':
1931 case 'V':
1932 case 'W':
1933 case 'X':
1934 case 'Y':
1935 case 'Z':
1936 case '0':
1937 case '1':
1938 case '2':
1939 case '3':
1940 case '4':
1941 case '5':
1942 case '6':
1943 case '7':
1944 case '8':
1945 case '9':
1946 break;
1947
1948 case 'e':
1949 case 'E':
1950 case 'p':
1951 case 'P':
1952 state = State.float_exponent; break;
1953 default: result.loc.end = this.index;
1954 return result;
1955 } break;
1956 case State.float_exponent:
1957 switch (c) {
1958 case '-':
1959 case '+':
1960 state = State.float; break;
1961 default: {
1962 this.index -= 1;
1963 state = State.float; break;
1964 }
1965 }
1966 break;
1967
1968 case State.whitespace:
1969 switch(c) {
1970 case ' ':
1971 case '\n':
1972 case '\t':
1973 case '\r': {
1974 break;
1975 }
1976 default: {
1977 result.loc.end = this.index;
1978 return result;
1979 }
1980 }
1981 }
1982 this.index += 1;
1983 }
1984
1985 //TODO: PORT
1986 // if (result.tag == Tag.eof) {
1987 // if (pending_invalid_token) | token | {
1988 // pending_invalid_token = null;
1989 // return token;
1990 // }
1991 // result.loc.start = sindex;
1992 // }
1993
1994 result.loc.end = this.index;
1995 return result;
1996
1997 }
1998}
1999
2000
2001const builtin_types = [
2002 "f16", "f32", "f64", "f80", "f128",
2003 "c_longdouble", "c_short", "c_ushort", "c_int", "c_uint",
2004 "c_long", "c_ulong", "c_longlong", "c_ulonglong", "c_char",
2005 "anyopaque", "void", "bool", "isize", "usize",
2006 "noreturn", "type", "anyerror", "comptime_int", "comptime_float",
2007];
2008
2009function isSimpleType(typeName) {
2010 return builtin_types.includes(typeName) || isIntType(typeName);
2011}
2012
2013function isIntType(typeName) {
2014 if (typeName[0] != 'u' && typeName[0] != 'i') return false;
2015 let i = 1;
2016 if (i == typeName.length) return false;
2017 for (; i < typeName.length; i += 1) {
2018 if (typeName[i] < '0' || typeName[i] > '9') return false;
2019 }
2020 return true;
2021}
2022
2023function isSpecialIndentifier(identifier) {
2024 return ["null", "true", "false", ,"undefined"].includes(identifier);
2025}
2026
2027//const fs = require('fs');
2028//const src = fs.readFileSync("../std/c.zig", 'utf8');
2029//console.log(generate_html_for_src(src));
2030
2031
2032// gist for zig_lexer_test code: https://gist.github.com/Myvar/2684ba4fb86b975274629d6f21eddc7b
2033// // Just for testing not to commit in pr
2034// var isNode = new Function("try {return this===global;}catch(e){return false;}");
2035// if (isNode()) {
2036
2037
2038// //const s = "const std = @import(\"std\");";
2039// //const toksa = tokenize_zig_source(s);
2040// //dump_tokens(toksa, s);
2041// //console.log(JSON.stringify(toksa));
2042
2043// const fs = require('fs');
2044
2045// function testFile(fileName) {
2046// //console.log(fileName);
2047// var exec = require('child_process').execFileSync;
2048// var passed = true;
2049// const zig_data = exec('./zig_lexer_test', [fileName]);
2050// const data = fs.readFileSync(fileName, 'utf8');
2051
2052// const toks = tokenize_zig_source(data);
2053// const a_json = toks;
2054
2055// // dump_tokens(a_json, data);
2056// // return;
2057
2058// const b_json = JSON.parse(zig_data.toString());
2059
2060// if (a_json.length !== b_json.length) {
2061// console.log("FAILED a and be is not the same length");
2062// passed = false;
2063// //return;
2064// }
2065
2066// let len = a_json.length;
2067// if (len >= b_json.length) len = b_json.length;
2068
2069// for (let i = 0; i < len; i++) {
2070// const a = a_json[i];
2071// const b = b_json[i];
2072
2073// // console.log(a.tag + " == " + b.tag);
2074
2075// if (a.tag !== b.tag) {
2076
2077// // console.log("Around here:");
2078// // console.log(
2079// // data.substring(b_json[i - 2].loc.start, b_json[i - 2].loc.end),
2080// // data.substring(b_json[i - 1].loc.start, b_json[i - 1].loc.end),
2081// // data.substring(b_json[i].loc.start, b_json[i].loc.end),
2082// // data.substring(b_json[i + 1].loc.start, b_json[i + 1].loc.end),
2083// // data.substring(b_json[i + 2].loc.start, b_json[i + 2].loc.end),
2084// // );
2085
2086// console.log("TAG: a != b");
2087// console.log("js", a.tag);
2088// console.log("zig", b.tag);
2089// passed = false;
2090// return;
2091// }
2092
2093// if (a.tag !== Tag.eof && a.loc.start !== b.loc.start) {
2094// console.log("START: a != b");
2095
2096// console.log("js", "\"" + data.substring(a_json[i ].loc.start, a_json[i].loc.end) + "\"");
2097// console.log("zig", "\"" + data.substring(b_json[i ].loc.start, b_json[i].loc.end) + "\"");
2098
2099
2100// passed = false;
2101// return;
2102// }
2103
2104// // if (a.tag !== Tag.eof && a.loc.end !== b.loc.end) {
2105// // console.log("END: a != b");
2106// // // console.log("Around here:");
2107// // // console.log(
2108// // // // data.substring(b_json[i - 2].loc.start, b_json[i - 2].loc.end),
2109// // // // data.substring(b_json[i - 1].loc.start, b_json[i - 1].loc.end),
2110// // // data.substring(b_json[i ].loc.start, b_json[i].loc.end),
2111// // // // data.substring(b_json[i + 1].loc.start, b_json[i + 1].loc.end),
2112// // // // data.substring(b_json[i + 2].loc.start, b_json[i + 2].loc.end),
2113// // // );
2114// // console.log("js", "\"" + data.substring(a_json[i ].loc.start, a_json[i].loc.end) + "\"");
2115// // console.log("zig", "\"" + data.substring(b_json[i ].loc.start, b_json[i].loc.end) + "\"");
2116// // passed = false;
2117// // return;
2118// // }
2119// }
2120// return passed;
2121// }
2122// var path = require('path');
2123// function fromDir(startPath, filter) {
2124// if (!fs.existsSync(startPath)) {
2125// console.log("no dir ", startPath);
2126// return;
2127// }
2128// var files = fs.readdirSync(startPath);
2129// for (var i = 0; i < files.length; i++) {
2130// var filename = path.join(startPath, files[i]);
2131// var stat = fs.lstatSync(filename);
2132// if (stat.isDirectory()) {
2133// fromDir(filename, filter); //recurse
2134// } else if (filename.endsWith(filter)) {
2135// try {
2136// console.log('-- TESTING: ', filename);
2137// console.log("\t\t", testFile(filename));
2138// }
2139// catch {
2140// }
2141// };
2142// };
2143// };
2144// fromDir('../std', '.zig');
2145// //console.log(testFile("/home/myvar/code/zig/lib/std/fmt/errol.zig"));
2146// //console.log(testFile("test.zig"));
2147// }
\ No newline at end of file
lib/std/Thread/WaitGroup.zig+22
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const assert = std.debug.assert;
34const WaitGroup = @This();
......@@ -43,3 +44,24 @@ pub fn isDone(wg: *WaitGroup) bool {
4344
4445 return (state / one_pending) == 0;
4546}
47
48// Spawns a new thread for the task. This is appropriate when the callee
49// delegates all work.
50pub fn spawnManager(
51 wg: *WaitGroup,
52 comptime func: anytype,
53 args: anytype,
54) void {
55 if (builtin.single_threaded) {
56 @call(.auto, func, args);
57 return;
58 }
59 const Manager = struct {
60 fn run(wg_inner: *WaitGroup, args_inner: @TypeOf(args)) void {
61 defer wg_inner.finish();
62 @call(.auto, func, args_inner);
63 }
64 };
65 wg.start();
66 _ = std.Thread.spawn(.{}, Manager.run, .{ wg, args }) catch Manager.run(wg, args);
67}
lib/std/base64.zig+2
......@@ -1,3 +1,5 @@
1//! Base64 encoding/decoding.
2
13const std = @import("std.zig");
24const assert = std.debug.assert;
35const builtin = @import("builtin");
lib/std/builtin.zig+2
......@@ -1,3 +1,5 @@
1//! Types and values provided by the Zig language.
2
13const builtin = @import("builtin");
24
35/// `explicit_subsystem` is missing when the subsystem is automatically detected,
lib/std/compress.zig+2
......@@ -1,3 +1,5 @@
1//! Compression algorithms.
2
13const std = @import("std.zig");
24
35pub const flate = @import("compress/flate.zig");
lib/std/crypto.zig+2
......@@ -1,3 +1,5 @@
1//! Cryptography.
2
13const root = @import("root");
24
35/// Authenticated Encryption with Associated Data
lib/std/dwarf.zig+2
......@@ -1,3 +1,5 @@
1//! DWARF debugging data format.
2
13const builtin = @import("builtin");
24const std = @import("std.zig");
35const debug = std.debug;
lib/std/elf.zig+2
......@@ -1,3 +1,5 @@
1//! Executable and Linkable Format.
2
13const std = @import("std.zig");
24const math = std.math;
35const mem = std.mem;
lib/std/fmt.zig+2
......@@ -1,3 +1,5 @@
1//! String formatting and parsing.
2
13const std = @import("std.zig");
24const builtin = @import("builtin");
35
lib/std/fs.zig+2
......@@ -1,3 +1,5 @@
1//! File System.
2
13const std = @import("std.zig");
24const builtin = @import("builtin");
35const root = @import("root");
lib/std/io/Writer.zig+11
......@@ -58,3 +58,14 @@ pub fn writeStruct(self: Self, value: anytype) anyerror!void {
5858 comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != .Auto);
5959 return self.writeAll(mem.asBytes(&value));
6060}
61
62pub fn writeFile(self: Self, file: std.fs.File) anyerror!void {
63 // TODO: figure out how to adjust std lib abstractions so that this ends up
64 // doing sendfile or maybe even copy_file_range under the right conditions.
65 var buf: [4000]u8 = undefined;
66 while (true) {
67 const n = try file.readAll(&buf);
68 try self.writeAll(buf[0..n]);
69 if (n < buf.len) return;
70 }
71}
lib/std/net.zig+2
......@@ -1,3 +1,5 @@
1//! Cross-platform networking abstractions.
2
13const std = @import("std.zig");
24const builtin = @import("builtin");
35const assert = std.debug.assert;
lib/std/simd.zig+6-4
......@@ -1,7 +1,9 @@
1//! This module provides functions for working conveniently with SIMD (Single Instruction; Multiple Data),
2//! which may offer a potential boost in performance on some targets by performing the same operations on
3//! multiple elements at once.
4//! Please be aware that some functions are known to not work on MIPS.
1//! SIMD (Single Instruction; Multiple Data) convenience functions.
2//!
3//! May offer a potential boost in performance on some targets by performing
4//! the same operations on multiple elements at once.
5//!
6//! Some functions are known to not work on MIPS.
57
68const std = @import("std");
79const builtin = @import("builtin");
lib/std/std.zig-93
......@@ -55,149 +55,56 @@ pub const Tz = tz.Tz;
5555pub const Uri = @import("Uri.zig");
5656
5757pub const array_hash_map = @import("array_hash_map.zig");
58
59/// Memory ordering, atomic data structures, and operations.
6058pub const atomic = @import("atomic.zig");
61
62/// Base64 encoding/decoding.
6359pub const base64 = @import("base64.zig");
64
65/// Bit manipulation data structures.
6660pub const bit_set = @import("bit_set.zig");
67
68/// Comptime-available information about the build environment, such as the target and optimize mode.
6961pub const builtin = @import("builtin.zig");
70
7162pub const c = @import("c.zig");
72
73/// COFF format.
7463pub const coff = @import("coff.zig");
75
76/// Compression algorithms such as zlib, zstd, etc.
7764pub const compress = @import("compress.zig");
78
7965pub const comptime_string_map = @import("comptime_string_map.zig");
80
81/// Cryptography.
8266pub const crypto = @import("crypto.zig");
83
84/// Debug printing, allocation and other debug helpers.
8567pub const debug = @import("debug.zig");
86
87/// DWARF debugging data format.
8868pub const dwarf = @import("dwarf.zig");
89
90/// ELF format.
9169pub const elf = @import("elf.zig");
92
93/// Enum-related metaprogramming helpers.
9470pub const enums = @import("enums.zig");
95
96/// First in, first out data structures.
9771pub const fifo = @import("fifo.zig");
98
99/// String formatting and parsing (e.g. parsing numbers out of strings).
10072pub const fmt = @import("fmt.zig");
101
102/// File system-related functionality.
10373pub const fs = @import("fs.zig");
104
105/// GPU programming helpers.
10674pub const gpu = @import("gpu.zig");
107
108/// Fast hashing functions (i.e. not cryptographically secure).
10975pub const hash = @import("hash.zig");
11076pub const hash_map = @import("hash_map.zig");
111
112/// Allocator implementations.
11377pub const heap = @import("heap.zig");
114
115/// HTTP client and server.
11678pub const http = @import("http.zig");
117
118/// I/O streams, reader/writer interfaces and common helpers.
11979pub const io = @import("io.zig");
120
121/// JSON parsing and serialization.
12280pub const json = @import("json.zig");
123
124/// LEB128 encoding.
12581pub const leb = @import("leb128.zig");
126
127/// A standardized interface for logging.
12882pub const log = @import("log.zig");
129
130/// Mach-O format.
13183pub const macho = @import("macho.zig");
132
133/// Mathematical constants and operations.
13484pub const math = @import("math.zig");
135
136/// Functions for comparing, searching, and manipulating memory.
13785pub const mem = @import("mem.zig");
138
139/// Metaprogramming helpers.
14086pub const meta = @import("meta.zig");
141
142/// Networking.
14387pub const net = @import("net.zig");
144
145/// POSIX-like API layer.
14688pub const posix = @import("os.zig");
147
14889/// Non-portable Operating System-specific API.
14990pub const os = @import("os.zig");
150
15191pub const once = @import("once.zig").once;
152
153/// A set of array and slice types that bit-pack integer elements.
15492pub const packed_int_array = @import("packed_int_array.zig");
155
156/// PDB file format.
15793pub const pdb = @import("pdb.zig");
158
159/// Accessors for process-related info (e.g. command line arguments)
160/// and spawning of child processes.
16194pub const process = @import("process.zig");
162
16395/// Deprecated: use `Random` instead.
16496pub const rand = Random;
165
166/// Sorting.
16797pub const sort = @import("sort.zig");
168
169/// Single Instruction Multiple Data (SIMD) helpers.
17098pub const simd = @import("simd.zig");
171
172/// ASCII text processing.
17399pub const ascii = @import("ascii.zig");
174
175/// Tar archive format compression/decompression.
176100pub const tar = @import("tar.zig");
177
178/// Testing allocator, testing assertions, and other helpers for testing code.
179101pub const testing = @import("testing.zig");
180
181/// Sleep, obtaining the current time, conversion constants, and more.
182102pub const time = @import("time.zig");
183
184/// Time zones.
185103pub const tz = @import("tz.zig");
186
187/// UTF-8 and UTF-16LE encoding/decoding.
188104pub const unicode = @import("unicode.zig");
189
190/// Helpers for integrating with Valgrind.
191105pub const valgrind = @import("valgrind.zig");
192
193/// Constants and types representing the Wasm binary format.
194106pub const wasm = @import("wasm.zig");
195
196/// Builds of the Zig compiler are distributed partly in source form. That
197/// source lives here. These APIs are provided as-is and have absolutely no API
198/// guarantees whatsoever.
199107pub const zig = @import("zig.zig");
200
201108pub const start = @import("start.zig");
202109
203110const root = @import("root");
lib/std/tar.zig+19-17
......@@ -1,23 +1,25 @@
1/// Tar archive is single ordinary file which can contain many files (or
2/// directories, symlinks, ...). It's build by series of blocks each size of 512
3/// bytes. First block of each entry is header which defines type, name, size
4/// permissions and other attributes. Header is followed by series of blocks of
5/// file content, if any that entry has content. Content is padded to the block
6/// size, so next header always starts at block boundary.
7///
8/// This simple format is extended by GNU and POSIX pax extensions to support
9/// file names longer than 256 bytes and additional attributes.
10///
11/// This is not comprehensive tar parser. Here we are only file types needed to
12/// support Zig package manager; normal file, directory, symbolic link. And
13/// subset of attributes: name, size, permissions.
14///
15/// GNU tar reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html
16/// pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13
17///
1//! Tar archive is single ordinary file which can contain many files (or
2//! directories, symlinks, ...). It's build by series of blocks each size of 512
3//! bytes. First block of each entry is header which defines type, name, size
4//! permissions and other attributes. Header is followed by series of blocks of
5//! file content, if any that entry has content. Content is padded to the block
6//! size, so next header always starts at block boundary.
7//!
8//! This simple format is extended by GNU and POSIX pax extensions to support
9//! file names longer than 256 bytes and additional attributes.
10//!
11//! This is not comprehensive tar parser. Here we are only file types needed to
12//! support Zig package manager; normal file, directory, symbolic link. And
13//! subset of attributes: name, size, permissions.
14//!
15//! GNU tar reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html
16//! pax reference: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13
17
1818const std = @import("std.zig");
1919const assert = std.debug.assert;
2020
21pub const output = @import("tar/output.zig");
22
2123pub const Options = struct {
2224 /// Number of directory levels to skip when extracting files.
2325 strip_components: u32 = 0,
lib/std/tar/output.zig created+85
......@@ -0,0 +1,85 @@
1/// A struct that is exactly 512 bytes and matches tar file format. This is
2/// intended to be used for outputting tar files; for parsing there is
3/// `std.tar.Header`.
4pub const Header = extern struct {
5 // This struct was originally copied from
6 // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT
7 // licensed.
8
9 name: [100]u8,
10 mode: [7:0]u8,
11 uid: [7:0]u8,
12 gid: [7:0]u8,
13 size: [11:0]u8,
14 mtime: [11:0]u8,
15 checksum: [7:0]u8,
16 typeflag: FileType,
17 linkname: [100]u8,
18 magic: [5:0]u8,
19 version: [2]u8,
20 uname: [31:0]u8,
21 gname: [31:0]u8,
22 devmajor: [7:0]u8,
23 devminor: [7:0]u8,
24 prefix: [155]u8,
25 pad: [12]u8,
26
27 pub const FileType = enum(u8) {
28 regular = '0',
29 hard_link = '1',
30 symbolic_link = '2',
31 character = '3',
32 block = '4',
33 directory = '5',
34 fifo = '6',
35 reserved = '7',
36 pax_global = 'g',
37 extended = 'x',
38 _,
39 };
40
41 pub fn init() Header {
42 var ret = std.mem.zeroes(Header);
43 ret.magic = [_:0]u8{ 'u', 's', 't', 'a', 'r' };
44 ret.version = [_:0]u8{ '0', '0' };
45 return ret;
46 }
47
48 pub fn setPath(self: *Header, prefix: []const u8, path: []const u8) !void {
49 if (prefix.len + 1 + path.len > 100) {
50 var i: usize = 0;
51 while (i < path.len and path.len - i > 100) {
52 while (path[i] != '/') : (i += 1) {}
53 }
54
55 _ = try std.fmt.bufPrint(&self.prefix, "{s}/{s}", .{ prefix, path[0..i] });
56 _ = try std.fmt.bufPrint(&self.name, "{s}", .{path[i + 1 ..]});
57 } else {
58 _ = try std.fmt.bufPrint(&self.name, "{s}/{s}", .{ prefix, path });
59 }
60 }
61
62 pub fn setSize(self: *Header, size: u64) !void {
63 _ = try std.fmt.bufPrint(&self.size, "{o:0>11}", .{size});
64 }
65
66 pub fn updateChecksum(self: *Header) !void {
67 const offset = @offsetOf(Header, "checksum");
68 var checksum: usize = 0;
69 for (std.mem.asBytes(self), 0..) |val, i| {
70 checksum += if (i >= offset and i < offset + @sizeOf(@TypeOf(self.checksum)))
71 ' '
72 else
73 val;
74 }
75
76 _ = try std.fmt.bufPrint(&self.checksum, "{o:0>7}", .{checksum});
77 }
78
79 comptime {
80 assert(@sizeOf(Header) == 512);
81 }
82};
83
84const std = @import("../std.zig");
85const assert = std.debug.assert;
lib/std/zig.zig+4
......@@ -1,3 +1,7 @@
1//! Builds of the Zig compiler are distributed partly in source form. That
2//! source lives here. These APIs are provided as-is and have absolutely no API
3//! guarantees whatsoever.
4
15pub const ErrorBundle = @import("zig/ErrorBundle.zig");
26pub const Server = @import("zig/Server.zig");
37pub const Client = @import("zig/Client.zig");
src/Autodoc.zig deleted-6035
......@@ -1,6035 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const build_options = @import("build_options");
4const Ast = std.zig.Ast;
5const Autodoc = @This();
6const Compilation = @import("Compilation.zig");
7const Zcu = @import("Module.zig");
8const File = Zcu.File;
9const Module = @import("Package.zig").Module;
10const Tokenizer = std.zig.Tokenizer;
11const InternPool = @import("InternPool.zig");
12const Zir = std.zig.Zir;
13const Ref = Zir.Inst.Ref;
14const log = std.log.scoped(.autodoc);
15const renderer = @import("autodoc/render_source.zig");
16
17zcu: *Zcu,
18arena: std.mem.Allocator,
19
20// The goal of autodoc is to fill up these arrays
21// that will then be serialized as JSON and consumed
22// by the JS frontend.
23modules: std.AutoArrayHashMapUnmanaged(*Module, DocData.DocModule) = .{},
24files: std.AutoArrayHashMapUnmanaged(*File, usize) = .{},
25calls: std.ArrayListUnmanaged(DocData.Call) = .{},
26types: std.ArrayListUnmanaged(DocData.Type) = .{},
27decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
28exprs: std.ArrayListUnmanaged(DocData.Expr) = .{},
29ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
30comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
31guide_sections: std.ArrayListUnmanaged(Section) = .{},
32
33// These fields hold temporary state of the analysis process
34// and are mainly used by the decl path resolving algorithm.
35pending_ref_paths: std.AutoHashMapUnmanaged(
36 *DocData.Expr, // pointer to declpath tail end (ie `&decl_path[decl_path.len - 1]`)
37 std.ArrayListUnmanaged(RefPathResumeInfo),
38) = .{},
39ref_paths_pending_on_decls: std.AutoHashMapUnmanaged(
40 *Scope.DeclStatus,
41 std.ArrayListUnmanaged(RefPathResumeInfo),
42) = .{},
43ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
44 usize,
45 std.ArrayListUnmanaged(RefPathResumeInfo),
46) = .{},
47
48/// A set of ZIR instruction refs which have a meaning other than the
49/// instruction they refer to. For instance, during analysis of the arguments to
50/// a `call`, the index of the `call` itself is repurposed to refer to the
51/// parameter type.
52/// TODO: there should be some kind of proper handling for these instructions;
53/// currently we just ignore them!
54repurposed_insts: std.AutoHashMapUnmanaged(Zir.Inst.Index, void) = .{},
55
56const RefPathResumeInfo = struct {
57 file: *File,
58 ref_path: []DocData.Expr,
59};
60
61/// Used to accumulate src_node offsets.
62/// In ZIR, all ast node indices are relative to the parent decl.
63/// More concretely, `union_decl`, `struct_decl`, `enum_decl` and `opaque_decl`
64/// and the value of each of their decls participate in the relative offset
65/// counting, and nothing else.
66/// We keep track of the line and byte values for these instructions in order
67/// to avoid tokenizing every file (on new lines) from the start every time.
68const SrcLocInfo = struct {
69 bytes: u32 = 0,
70 line: usize = 0,
71 src_node: u32 = 0,
72};
73
74const Section = struct {
75 name: []const u8 = "", // empty string is the default section
76 guides: std.ArrayListUnmanaged(Guide) = .{},
77
78 const Guide = struct {
79 name: []const u8,
80 body: []const u8,
81 };
82};
83
84pub fn generate(zcu: *Zcu, output_dir: std.fs.Dir) !void {
85 var arena_allocator = std.heap.ArenaAllocator.init(zcu.gpa);
86 defer arena_allocator.deinit();
87 var autodoc: Autodoc = .{
88 .zcu = zcu,
89 .arena = arena_allocator.allocator(),
90 };
91 try autodoc.generateZirData(output_dir);
92
93 const lib_dir = zcu.comp.zig_lib_directory.handle;
94 try lib_dir.copyFile("docs/main.js", output_dir, "main.js", .{});
95 try lib_dir.copyFile("docs/ziglexer.js", output_dir, "ziglexer.js", .{});
96 try lib_dir.copyFile("docs/commonmark.js", output_dir, "commonmark.js", .{});
97 try lib_dir.copyFile("docs/index.html", output_dir, "index.html", .{});
98}
99
100fn generateZirData(self: *Autodoc, output_dir: std.fs.Dir) !void {
101 const root_src_path = self.zcu.main_mod.root_src_path;
102 const joined_src_path = try self.zcu.main_mod.root.joinString(self.arena, root_src_path);
103 defer self.arena.free(joined_src_path);
104
105 const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{ ".", joined_src_path });
106 defer self.arena.free(abs_root_src_path);
107
108 const file = self.zcu.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table
109 // Append all the types in Zir.Inst.Ref.
110 {
111 comptime std.debug.assert(@intFromEnum(InternPool.Index.first_type) == 0);
112 var i: u32 = 0;
113 while (i <= @intFromEnum(InternPool.Index.last_type)) : (i += 1) {
114 const ip_index = @as(InternPool.Index, @enumFromInt(i));
115 var tmpbuf = std.ArrayList(u8).init(self.arena);
116 if (ip_index == .generic_poison_type) {
117 // Not a real type, doesn't have a normal name
118 try tmpbuf.writer().writeAll("(generic poison)");
119 } else {
120 try @import("type.zig").Type.fromInterned(ip_index).fmt(self.zcu).format("", .{}, tmpbuf.writer());
121 }
122 try self.types.append(
123 self.arena,
124 switch (ip_index) {
125 .u0_type,
126 .i0_type,
127 .u1_type,
128 .u8_type,
129 .i8_type,
130 .u16_type,
131 .i16_type,
132 .u29_type,
133 .u32_type,
134 .i32_type,
135 .u64_type,
136 .i64_type,
137 .u80_type,
138 .u128_type,
139 .i128_type,
140 .usize_type,
141 .isize_type,
142 .c_char_type,
143 .c_short_type,
144 .c_ushort_type,
145 .c_int_type,
146 .c_uint_type,
147 .c_long_type,
148 .c_ulong_type,
149 .c_longlong_type,
150 .c_ulonglong_type,
151 => .{
152 .Int = .{ .name = try tmpbuf.toOwnedSlice() },
153 },
154 .f16_type,
155 .f32_type,
156 .f64_type,
157 .f80_type,
158 .f128_type,
159 .c_longdouble_type,
160 => .{
161 .Float = .{ .name = try tmpbuf.toOwnedSlice() },
162 },
163 .comptime_int_type => .{
164 .ComptimeInt = .{ .name = try tmpbuf.toOwnedSlice() },
165 },
166 .comptime_float_type => .{
167 .ComptimeFloat = .{ .name = try tmpbuf.toOwnedSlice() },
168 },
169
170 .anyopaque_type => .{
171 .ComptimeExpr = .{ .name = try tmpbuf.toOwnedSlice() },
172 },
173
174 .bool_type => .{
175 .Bool = .{ .name = try tmpbuf.toOwnedSlice() },
176 },
177 .noreturn_type => .{
178 .NoReturn = .{ .name = try tmpbuf.toOwnedSlice() },
179 },
180 .void_type => .{
181 .Void = .{ .name = try tmpbuf.toOwnedSlice() },
182 },
183 .type_info_type => .{
184 .ComptimeExpr = .{ .name = try tmpbuf.toOwnedSlice() },
185 },
186 .type_type => .{
187 .Type = .{ .name = try tmpbuf.toOwnedSlice() },
188 },
189 .anyerror_type => .{
190 .ErrorSet = .{ .name = try tmpbuf.toOwnedSlice() },
191 },
192 // should be different types but if we don't analyze std we don't get the ast nodes etc.
193 // since they're defined in std.builtin
194 .calling_convention_type,
195 .atomic_order_type,
196 .atomic_rmw_op_type,
197 .address_space_type,
198 .float_mode_type,
199 .reduce_op_type,
200 .call_modifier_type,
201 .prefetch_options_type,
202 .export_options_type,
203 .extern_options_type,
204 => .{
205 .Type = .{ .name = try tmpbuf.toOwnedSlice() },
206 },
207 .manyptr_u8_type => .{
208 .Pointer = .{
209 .size = .Many,
210 .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
211 .is_mutable = true,
212 },
213 },
214 .manyptr_const_u8_type => .{
215 .Pointer = .{
216 .size = .Many,
217 .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
218 },
219 },
220 .manyptr_const_u8_sentinel_0_type => .{
221 .Pointer = .{
222 .size = .Many,
223 .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
224 .sentinel = .{ .int = .{ .value = 0 } },
225 },
226 },
227 .single_const_pointer_to_comptime_int_type => .{
228 .Pointer = .{
229 .size = .One,
230 .child = .{ .type = @intFromEnum(InternPool.Index.comptime_int_type) },
231 },
232 },
233 .slice_const_u8_type => .{
234 .Pointer = .{
235 .size = .Slice,
236 .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
237 },
238 },
239 .slice_const_u8_sentinel_0_type => .{
240 .Pointer = .{
241 .size = .Slice,
242 .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
243 .sentinel = .{ .int = .{ .value = 0 } },
244 },
245 },
246 // Not fully correct
247 // since it actually has no src or line_number
248 .empty_struct_type => .{
249 .Struct = .{
250 .name = "",
251 .src = 0,
252 .is_tuple = false,
253 .line_number = 0,
254 .parent_container = null,
255 .layout = null,
256 },
257 },
258 .anyerror_void_error_union_type => .{
259 .ErrorUnion = .{
260 .lhs = .{ .type = @intFromEnum(InternPool.Index.anyerror_type) },
261 .rhs = .{ .type = @intFromEnum(InternPool.Index.void_type) },
262 },
263 },
264 .anyframe_type => .{
265 .AnyFrame = .{ .name = try tmpbuf.toOwnedSlice() },
266 },
267 .enum_literal_type => .{
268 .EnumLiteral = .{ .name = try tmpbuf.toOwnedSlice() },
269 },
270 .undefined_type => .{
271 .Undefined = .{ .name = try tmpbuf.toOwnedSlice() },
272 },
273 .null_type => .{
274 .Null = .{ .name = try tmpbuf.toOwnedSlice() },
275 },
276 .optional_noreturn_type => .{
277 .Optional = .{
278 .name = try tmpbuf.toOwnedSlice(),
279 .child = .{ .type = @intFromEnum(InternPool.Index.noreturn_type) },
280 },
281 },
282 // Poison and special tag
283 .generic_poison_type,
284 .var_args_param_type,
285 .adhoc_inferred_error_set_type,
286 => .{
287 .Type = .{ .name = try tmpbuf.toOwnedSlice() },
288 },
289 // We want to catch new types added to InternPool.Index
290 else => unreachable,
291 },
292 );
293 }
294 }
295
296 const rootName = blk: {
297 const rootName = std.fs.path.basename(self.zcu.main_mod.root_src_path);
298 break :blk rootName[0 .. rootName.len - 4];
299 };
300
301 const main_type_index = self.types.items.len;
302 {
303 try self.modules.put(self.arena, self.zcu.main_mod, .{
304 .name = rootName,
305 .main = main_type_index,
306 .table = .{},
307 });
308 try self.modules.entries.items(.value)[0].table.put(
309 self.arena,
310 self.zcu.main_mod,
311 .{
312 .name = rootName,
313 .value = 0,
314 },
315 );
316 }
317
318 var root_scope = Scope{
319 .parent = null,
320 .enclosing_type = null,
321 };
322
323 const tldoc_comment = try self.getTLDocComment(file);
324 const cleaned_tldoc_comment = try self.findGuidePaths(file, tldoc_comment);
325 defer self.arena.free(cleaned_tldoc_comment);
326 try self.ast_nodes.append(self.arena, .{
327 .name = "(root)",
328 .docs = cleaned_tldoc_comment,
329 });
330 try self.files.put(self.arena, file, main_type_index);
331
332 _ = try self.walkInstruction(
333 file,
334 &root_scope,
335 .{},
336 .main_struct_inst,
337 false,
338 null,
339 );
340
341 if (self.ref_paths_pending_on_decls.count() > 0) {
342 @panic("some decl paths were never fully analyzed (pending on decls)");
343 }
344
345 if (self.ref_paths_pending_on_types.count() > 0) {
346 @panic("some decl paths were never fully analyzed (pending on types)");
347 }
348
349 if (self.pending_ref_paths.count() > 0) {
350 @panic("some decl paths were never fully analyzed");
351 }
352
353 var data = DocData{
354 .modules = self.modules,
355 .files = self.files,
356 .calls = self.calls.items,
357 .types = self.types.items,
358 .decls = self.decls.items,
359 .exprs = self.exprs.items,
360 .astNodes = self.ast_nodes.items,
361 .comptimeExprs = self.comptime_exprs.items,
362 .guideSections = self.guide_sections,
363 };
364
365 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
366 const field_name = @tagName(f);
367 const file_name = "data-" ++ field_name ++ ".js";
368 const data_js_f = try output_dir.createFile(file_name, .{});
369 defer data_js_f.close();
370
371 var buffer = std.io.bufferedWriter(data_js_f.writer());
372 const out = buffer.writer();
373
374 try out.print("var {s} =", .{field_name});
375
376 var jsw = std.json.writeStream(out, .{
377 .whitespace = .minified,
378 .emit_null_optional_fields = true,
379 });
380
381 switch (f) {
382 .files => try writeFileTableToJson(data.files, data.modules, &jsw),
383 .guideSections => try writeGuidesToJson(data.guideSections, &jsw),
384 .modules => try jsw.write(data.modules.values()),
385 else => try jsw.write(@field(data, field_name)),
386 }
387
388 // try std.json.stringifyArbitraryDepth(
389 // self.arena,
390 // @field(data, field.name),
391 // .{
392 // .whitespace = .minified,
393 // .emit_null_optional_fields = true,
394 // },
395 // out,
396 // );
397 try out.print(";", .{});
398
399 // last thing (that can fail) that we do is flush
400 try buffer.flush();
401 }
402
403 {
404 output_dir.makeDir("src") catch |e| switch (e) {
405 error.PathAlreadyExists => {},
406 else => |err| return err,
407 };
408 const html_dir = try output_dir.openDir("src", .{});
409
410 var files_iterator = self.files.iterator();
411
412 while (files_iterator.next()) |entry| {
413 const sub_file_path = entry.key_ptr.*.sub_file_path;
414 const file_module = entry.key_ptr.*.mod;
415 const module_name = (self.modules.get(file_module) orelse continue).name;
416
417 const file_path = std.fs.path.dirname(sub_file_path) orelse "";
418 const file_name = if (file_path.len > 0) sub_file_path[file_path.len + 1 ..] else sub_file_path;
419
420 const html_file_name = try std.mem.concat(self.arena, u8, &.{ file_name, ".html" });
421 defer self.arena.free(html_file_name);
422
423 const dir_name = try std.fs.path.join(self.arena, &.{ module_name, file_path });
424 defer self.arena.free(dir_name);
425
426 var dir = try html_dir.makeOpenPath(dir_name, .{});
427 defer dir.close();
428
429 const html_file = dir.createFile(html_file_name, .{}) catch |err| switch (err) {
430 error.PathAlreadyExists => try dir.openFile(html_file_name, .{}),
431 else => return err,
432 };
433 defer html_file.close();
434 var buffer = std.io.bufferedWriter(html_file.writer());
435
436 const out = buffer.writer();
437
438 try renderer.genHtml(self.zcu.gpa, entry.key_ptr.*, out);
439 try buffer.flush();
440 }
441 }
442}
443
444/// Represents a chain of scopes, used to resolve decl references to the
445/// corresponding entry in `self.decls`. It also keeps track of whether
446/// a given decl has been analyzed or not.
447const Scope = struct {
448 parent: ?*Scope,
449 map: std.AutoHashMapUnmanaged(
450 Zir.NullTerminatedString, // index into the current file's string table (decl name)
451 *DeclStatus,
452 ) = .{},
453 captures: []const Zir.Inst.Capture = &.{},
454 enclosing_type: ?usize, // index into `types`, null = file top-level struct
455
456 pub const DeclStatus = union(enum) {
457 Analyzed: usize, // index into `decls`
458 Pending,
459 NotRequested: u32, // instr_index
460 };
461
462 fn getCapture(scope: Scope, idx: u16) struct {
463 union(enum) { inst: Zir.Inst.Index, decl: Zir.NullTerminatedString },
464 *Scope,
465 } {
466 const parent = scope.parent.?;
467 return switch (scope.captures[idx].unwrap()) {
468 .nested => |parent_idx| parent.getCapture(parent_idx),
469 .instruction => |inst| .{
470 .{ .inst = inst },
471 parent,
472 },
473 .decl_val, .decl_ref => |str| .{
474 .{ .decl = str },
475 parent,
476 },
477 };
478 }
479
480 /// Returns a pointer so that the caller has a chance to modify the value
481 /// in case they decide to start analyzing a previously not requested decl.
482 /// Another reason is that in some places we use the pointer to uniquely
483 /// refer to a decl, as we wait for it to be analyzed. This means that
484 /// those pointers must stay stable.
485 pub fn resolveDeclName(self: Scope, string_table_idx: Zir.NullTerminatedString, file: *File, inst: Zir.Inst.OptionalIndex) *DeclStatus {
486 var cur: ?*const Scope = &self;
487 return while (cur) |s| : (cur = s.parent) {
488 break s.map.get(string_table_idx) orelse continue;
489 } else {
490 printWithOptionalContext(
491 file,
492 inst,
493 "Could not find `{s}`\n\n",
494 .{file.zir.nullTerminatedString(string_table_idx)},
495 );
496 unreachable;
497 };
498 }
499
500 pub fn insertDeclRef(
501 self: *Scope,
502 arena: std.mem.Allocator,
503 decl_name_index: Zir.NullTerminatedString, // index into the current file's string table
504 decl_status: DeclStatus,
505 ) !void {
506 const decl_status_ptr = try arena.create(DeclStatus);
507 errdefer arena.destroy(decl_status_ptr);
508
509 decl_status_ptr.* = decl_status;
510 try self.map.put(arena, decl_name_index, decl_status_ptr);
511 }
512};
513
514/// The output of our analysis process.
515const DocData = struct {
516 // NOTE: editing fields of DocData requires also updating:
517 // - the deployment script for ziglang.org
518 // - imports in index.html
519 typeKinds: []const []const u8 = std.meta.fieldNames(DocTypeKinds),
520 rootMod: u32 = 0,
521 modules: std.AutoArrayHashMapUnmanaged(*Module, DocModule),
522
523 // non-hardcoded stuff
524 astNodes: []AstNode,
525 calls: []Call,
526 files: std.AutoArrayHashMapUnmanaged(*File, usize),
527 types: []Type,
528 decls: []Decl,
529 exprs: []Expr,
530 comptimeExprs: []ComptimeExpr,
531
532 guideSections: std.ArrayListUnmanaged(Section),
533
534 const Call = struct {
535 func: Expr,
536 args: []Expr,
537 ret: Expr,
538 };
539
540 /// All the type "families" as described by `std.builtin.TypeId`
541 /// plus a couple extra that are unique to our use case.
542 ///
543 /// `Unanalyzed` is used so that we can refer to types that have started
544 /// analysis but that haven't been fully analyzed yet (in case we find
545 /// self-referential stuff, like `@This()`).
546 ///
547 /// `ComptimeExpr` represents the result of a piece of comptime logic
548 /// that we weren't able to analyze fully. Examples of that are comptime
549 /// function calls and comptime if / switch / ... expressions.
550 const DocTypeKinds = @typeInfo(Type).Union.tag_type.?;
551
552 const ComptimeExpr = struct {
553 code: []const u8,
554 };
555 const DocModule = struct {
556 name: []const u8 = "(root)",
557 file: usize = 0, // index into `files`
558 main: usize = 0, // index into `types`
559 table: std.AutoHashMapUnmanaged(*Module, TableEntry),
560 pub const TableEntry = struct {
561 name: []const u8,
562 value: usize,
563 };
564
565 pub fn jsonStringify(self: DocModule, jsw: anytype) !void {
566 try jsw.beginObject();
567 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocModule))) |f| {
568 const f_name = @tagName(f);
569 try jsw.objectField(f_name);
570 switch (f) {
571 .table => try writeModuleTableToJson(self.table, jsw),
572 else => try jsw.write(@field(self, f_name)),
573 }
574 }
575 try jsw.endObject();
576 }
577 };
578
579 const Decl = struct {
580 name: []const u8,
581 kind: []const u8,
582 src: usize, // index into astNodes
583 value: WalkResult,
584 // The index in astNodes of the `test declname { }` node
585 decltest: ?usize = null,
586 is_uns: bool = false, // usingnamespace
587 parent_container: ?usize, // index into `types`
588
589 pub fn jsonStringify(self: Decl, jsw: anytype) !void {
590 try jsw.beginArray();
591 inline for (comptime std.meta.fields(Decl)) |f| {
592 try jsw.write(@field(self, f.name));
593 }
594 try jsw.endArray();
595 }
596 };
597
598 const AstNode = struct {
599 file: usize = 0, // index into files
600 line: usize = 0,
601 col: usize = 0,
602 name: ?[]const u8 = null,
603 code: ?[]const u8 = null,
604 docs: ?[]const u8 = null,
605 fields: ?[]usize = null, // index into astNodes
606 @"comptime": bool = false,
607
608 pub fn jsonStringify(self: AstNode, jsw: anytype) !void {
609 try jsw.beginArray();
610 inline for (comptime std.meta.fields(AstNode)) |f| {
611 try jsw.write(@field(self, f.name));
612 }
613 try jsw.endArray();
614 }
615 };
616
617 const Type = union(enum) {
618 Unanalyzed: struct {},
619 Type: struct { name: []const u8 },
620 Void: struct { name: []const u8 },
621 Bool: struct { name: []const u8 },
622 NoReturn: struct { name: []const u8 },
623 Int: struct { name: []const u8 },
624 Float: struct { name: []const u8 },
625 Pointer: struct {
626 size: std.builtin.Type.Pointer.Size,
627 child: Expr,
628 sentinel: ?Expr = null,
629 @"align": ?Expr = null,
630 address_space: ?Expr = null,
631 bit_start: ?Expr = null,
632 host_size: ?Expr = null,
633 is_ref: bool = false,
634 is_allowzero: bool = false,
635 is_mutable: bool = false,
636 is_volatile: bool = false,
637 has_sentinel: bool = false,
638 has_align: bool = false,
639 has_addrspace: bool = false,
640 has_bit_range: bool = false,
641 },
642 Array: struct {
643 len: Expr,
644 child: Expr,
645 sentinel: ?Expr = null,
646 },
647 Struct: struct {
648 name: []const u8,
649 src: usize, // index into astNodes
650 privDecls: []usize = &.{}, // index into decls
651 pubDecls: []usize = &.{}, // index into decls
652 field_types: []Expr = &.{}, // (use src->fields to find names)
653 field_defaults: []?Expr = &.{}, // default values is specified
654 backing_int: ?Expr = null, // backing integer if specified
655 is_tuple: bool,
656 line_number: usize,
657 parent_container: ?usize, // index into `types`
658 layout: ?Expr, // if different than Auto
659 },
660 ComptimeExpr: struct { name: []const u8 },
661 ComptimeFloat: struct { name: []const u8 },
662 ComptimeInt: struct { name: []const u8 },
663 Undefined: struct { name: []const u8 },
664 Null: struct { name: []const u8 },
665 Optional: struct {
666 name: []const u8,
667 child: Expr,
668 },
669 ErrorUnion: struct { lhs: Expr, rhs: Expr },
670 InferredErrorUnion: struct { payload: Expr },
671 ErrorSet: struct {
672 name: []const u8,
673 fields: ?[]const Field = null,
674 // TODO: fn field for inferred error sets?
675 },
676 Enum: struct {
677 name: []const u8,
678 src: usize, // index into astNodes
679 privDecls: []usize = &.{}, // index into decls
680 pubDecls: []usize = &.{}, // index into decls
681 // (use src->fields to find field names)
682 tag: ?Expr = null, // tag type if specified
683 values: []?Expr = &.{}, // tag values if specified
684 nonexhaustive: bool,
685 parent_container: ?usize, // index into `types`
686 },
687 Union: struct {
688 name: []const u8,
689 src: usize, // index into astNodes
690 privDecls: []usize = &.{}, // index into decls
691 pubDecls: []usize = &.{}, // index into decls
692 fields: []Expr = &.{}, // (use src->fields to find names)
693 tag: ?Expr, // tag type if specified
694 auto_enum: bool, // tag is an auto enum
695 parent_container: ?usize, // index into `types`
696 layout: ?Expr, // if different than Auto
697 },
698 Fn: struct {
699 name: []const u8,
700 src: ?usize = null, // index into `astNodes`
701 ret: Expr,
702 generic_ret: ?Expr = null,
703 params: ?[]Expr = null, // (use src->fields to find names)
704 lib_name: []const u8 = "",
705 is_var_args: bool = false,
706 is_inferred_error: bool = false,
707 has_lib_name: bool = false,
708 has_cc: bool = false,
709 cc: ?usize = null,
710 @"align": ?usize = null,
711 has_align: bool = false,
712 is_test: bool = false,
713 is_extern: bool = false,
714 },
715 Opaque: struct {
716 name: []const u8,
717 src: usize, // index into astNodes
718 privDecls: []usize = &.{}, // index into decls
719 pubDecls: []usize = &.{}, // index into decls
720 parent_container: ?usize, // index into `types`
721 },
722 Frame: struct { name: []const u8 },
723 AnyFrame: struct { name: []const u8 },
724 Vector: struct { name: []const u8 },
725 EnumLiteral: struct { name: []const u8 },
726
727 const Field = struct {
728 name: []const u8,
729 docs: []const u8,
730 };
731
732 pub fn jsonStringify(self: Type, jsw: anytype) !void {
733 const active_tag = std.meta.activeTag(self);
734 try jsw.beginArray();
735 try jsw.write(@intFromEnum(active_tag));
736 inline for (comptime std.meta.fields(Type)) |case| {
737 if (@field(Type, case.name) == active_tag) {
738 const current_value = @field(self, case.name);
739 inline for (comptime std.meta.fields(case.type)) |f| {
740 if (f.type == std.builtin.Type.Pointer.Size) {
741 try jsw.write(@intFromEnum(@field(current_value, f.name)));
742 } else {
743 try jsw.write(@field(current_value, f.name));
744 }
745 }
746 }
747 }
748 try jsw.endArray();
749 }
750 };
751
752 /// An Expr represents the (untyped) result of analyzing instructions.
753 /// The data is normalized, which means that an Expr that results in a
754 /// type definition will hold an index into `self.types`.
755 pub const Expr = union(enum) {
756 comptimeExpr: usize, // index in `comptimeExprs`
757 void: struct {},
758 @"unreachable": struct {},
759 null: struct {},
760 undefined: struct {},
761 @"struct": []FieldVal,
762 fieldVal: FieldVal,
763 bool: bool,
764 @"anytype": struct {},
765 @"&": usize, // index in `exprs`
766 type: usize, // index in `types`
767 this: usize, // index in `types`
768 declRef: *Scope.DeclStatus,
769 declIndex: usize, // index into `decls`, alternative repr for `declRef`
770 declName: []const u8, // unresolved decl name
771 builtinField: enum { len, ptr },
772 fieldRef: FieldRef,
773 refPath: []Expr,
774 int: struct {
775 value: u64, // direct value
776 negated: bool = false,
777 },
778 int_big: struct {
779 value: []const u8, // string representation
780 negated: bool = false,
781 },
782 float: f64, // direct value
783 float128: f128, // direct value
784 array: []usize, // index in `exprs`
785 call: usize, // index in `calls`
786 enumLiteral: []const u8, // direct value
787 typeOf: usize, // index in `exprs`
788 typeOf_peer: []usize,
789 errorUnion: usize, // index in `types`
790 as: As,
791 sizeOf: usize, // index in `exprs`
792 bitSizeOf: usize, // index in `exprs`
793 compileError: usize, // index in `exprs`
794 optionalPayload: usize, // index in `exprs`
795 elemVal: ElemVal,
796 errorSets: usize,
797 string: []const u8, // direct value
798 sliceIndex: usize,
799 slice: Slice,
800 sliceLength: SliceLength,
801 cmpxchgIndex: usize,
802 cmpxchg: Cmpxchg,
803 builtin: Builtin,
804 builtinIndex: usize,
805 builtinBin: BuiltinBin,
806 builtinBinIndex: usize,
807 unionInit: UnionInit,
808 builtinCall: BuiltinCall,
809 mulAdd: MulAdd,
810 switchIndex: usize, // index in `exprs`
811 switchOp: SwitchOp,
812 unOp: UnOp,
813 unOpIndex: usize,
814 binOp: BinOp,
815 binOpIndex: usize,
816 load: usize, // index in `exprs`
817 const UnOp = struct {
818 param: usize, // index in `exprs`
819 name: []const u8 = "", // tag name
820 };
821 const BinOp = struct {
822 lhs: usize, // index in `exprs`
823 rhs: usize, // index in `exprs`
824 name: []const u8 = "", // tag name
825 };
826 const SwitchOp = struct {
827 cond_index: usize,
828 file_name: []const u8,
829 src: usize,
830 outer_decl: usize, // index in `types`
831 };
832 const BuiltinBin = struct {
833 name: []const u8 = "", // fn name
834 lhs: usize, // index in `exprs`
835 rhs: usize, // index in `exprs`
836 };
837 const UnionInit = struct {
838 type: usize, // index in `exprs`
839 field: usize, // index in `exprs`
840 init: usize, // index in `exprs`
841 };
842 const Builtin = struct {
843 name: []const u8 = "", // fn name
844 param: usize, // index in `exprs`
845 };
846 const BuiltinCall = struct {
847 modifier: usize, // index in `exprs`
848 function: usize, // index in `exprs`
849 args: usize, // index in `exprs`
850 };
851 const MulAdd = struct {
852 mulend1: usize, // index in `exprs`
853 mulend2: usize, // index in `exprs`
854 addend: usize, // index in `exprs`
855 type: usize, // index in `exprs`
856 };
857 const Slice = struct {
858 lhs: usize, // index in `exprs`
859 start: usize,
860 end: ?usize = null,
861 sentinel: ?usize = null, // index in `exprs`
862 };
863 const SliceLength = struct {
864 lhs: usize,
865 start: usize,
866 len: usize,
867 sentinel: ?usize = null,
868 };
869 const Cmpxchg = struct {
870 name: []const u8,
871 type: usize,
872 ptr: usize,
873 expected_value: usize,
874 new_value: usize,
875 success_order: usize,
876 failure_order: usize,
877 };
878 const As = struct {
879 typeRefArg: ?usize, // index in `exprs`
880 exprArg: usize, // index in `exprs`
881 };
882 const FieldRef = struct {
883 type: usize, // index in `types`
884 index: usize, // index in type.fields
885 };
886
887 const FieldVal = struct {
888 name: []const u8,
889 val: struct {
890 typeRef: ?usize, // index in `exprs`
891 expr: usize, // index in `exprs`
892 },
893 };
894
895 const ElemVal = struct {
896 lhs: usize, // index in `exprs`
897 rhs: usize, // index in `exprs`
898 };
899
900 pub fn jsonStringify(self: Expr, jsw: anytype) !void {
901 const active_tag = std.meta.activeTag(self);
902 try jsw.beginObject();
903 if (active_tag == .declIndex) {
904 try jsw.objectField("declRef");
905 } else {
906 try jsw.objectField(@tagName(active_tag));
907 }
908 switch (self) {
909 .int => {
910 if (self.int.negated) {
911 try jsw.write(-@as(i65, self.int.value));
912 } else {
913 try jsw.write(self.int.value);
914 }
915 },
916 .builtinField => {
917 try jsw.write(@tagName(self.builtinField));
918 },
919 .declRef => {
920 try jsw.write(self.declRef.Analyzed);
921 },
922 else => {
923 inline for (comptime std.meta.fields(Expr)) |case| {
924 // TODO: this is super ugly, fix once `inline else` is a thing
925 if (comptime std.mem.eql(u8, case.name, "builtinField"))
926 continue;
927 if (comptime std.mem.eql(u8, case.name, "declRef"))
928 continue;
929 if (@field(Expr, case.name) == active_tag) {
930 try jsw.write(@field(self, case.name));
931 }
932 }
933 },
934 }
935 try jsw.endObject();
936 }
937 };
938
939 /// A WalkResult represents the result of the analysis process done to a
940 /// a Zir instruction. Walk results carry type information either inferred
941 /// from the context (eg string literals are pointers to null-terminated
942 /// arrays), or because of @as() instructions.
943 /// Since the type information is only needed in certain contexts, the
944 /// underlying normalized data (Expr) is untyped.
945 const WalkResult = struct {
946 typeRef: ?Expr = null,
947 expr: Expr,
948 };
949};
950
951const AutodocErrors = error{
952 OutOfMemory,
953 CurrentWorkingDirectoryUnlinked,
954 UnexpectedEndOfFile,
955 ModuleNotFound,
956 ImportOutsideModulePath,
957} || std.fs.File.OpenError || std.fs.File.ReadError;
958
959/// `call` instructions will have loopy references to themselves
960/// whenever an as_node is required for a complex expression.
961/// This type is used to keep track of dangerous instruction
962/// numbers that we definitely don't want to recurse into.
963const CallContext = struct {
964 inst: Zir.Inst.Index,
965 prev: ?*const CallContext,
966};
967
968/// Called when we need to analyze a Zir instruction.
969/// For example it gets called by `generateZirData` on instruction 0,
970/// which represents the top-level struct corresponding to the root file.
971/// Note that in some situations where we're analyzing code that only allows
972/// for a limited subset of Zig syntax, we don't always resort to calling
973/// `walkInstruction` and instead sometimes we handle Zir directly.
974/// The best example of that are instructions corresponding to function
975/// params, as those can only occur while analyzing a function definition.
976fn walkInstruction(
977 self: *Autodoc,
978 file: *File,
979 parent_scope: *Scope,
980 parent_src: SrcLocInfo,
981 inst: Zir.Inst.Index,
982 need_type: bool, // true if the caller needs us to provide also a typeRef
983 call_ctx: ?*const CallContext,
984) AutodocErrors!DocData.WalkResult {
985 const tags = file.zir.instructions.items(.tag);
986 const data = file.zir.instructions.items(.data);
987
988 if (self.repurposed_insts.contains(inst)) {
989 // TODO: better handling here
990 return .{ .expr = .{ .comptimeExpr = 0 } };
991 }
992
993 // We assume that the topmost ast_node entry corresponds to our decl
994 const self_ast_node_index = self.ast_nodes.items.len - 1;
995
996 switch (tags[@intFromEnum(inst)]) {
997 else => {
998 printWithContext(
999 file,
1000 inst,
1001 "TODO: implement `{s}` for walkInstruction\n\n",
1002 .{@tagName(tags[@intFromEnum(inst)])},
1003 );
1004 return self.cteTodo(@tagName(tags[@intFromEnum(inst)]));
1005 },
1006 .import => {
1007 const str_tok = data[@intFromEnum(inst)].str_tok;
1008 const path = str_tok.get(file.zir);
1009
1010 // importFile cannot error out since all files
1011 // are already loaded at this point
1012 if (file.mod.deps.get(path)) |other_module| {
1013 const result = try self.modules.getOrPut(self.arena, other_module);
1014
1015 // Immediately add this module to the import table of our
1016 // current module, regardless of wether it's new or not.
1017 if (self.modules.getPtr(file.mod)) |current_module| {
1018 // TODO: apparently, in the stdlib a file gets analyzed before
1019 // its module gets added. I guess we're importing a file
1020 // that belongs to another module through its file path?
1021 // (ie not through its module name).
1022 // We're bailing for now, but maybe we shouldn't?
1023 _ = try current_module.table.getOrPutValue(
1024 self.arena,
1025 other_module,
1026 .{
1027 .name = path,
1028 .value = self.modules.getIndex(other_module).?,
1029 },
1030 );
1031 }
1032
1033 if (result.found_existing) {
1034 return DocData.WalkResult{
1035 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
1036 .expr = .{ .type = result.value_ptr.main },
1037 };
1038 }
1039
1040 // create a new module entry
1041 const main_type_index = self.types.items.len;
1042 result.value_ptr.* = .{
1043 .name = path,
1044 .main = main_type_index,
1045 .table = .{},
1046 };
1047
1048 // TODO: Add this module as a dependency to the current module
1049 // TODO: this seems something that could be done in bulk
1050 // at the beginning or the end, or something.
1051 const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{
1052 ".",
1053 other_module.root.root_dir.path orelse ".",
1054 other_module.root.sub_path,
1055 other_module.root_src_path,
1056 });
1057 defer self.arena.free(abs_root_src_path);
1058
1059 const new_file = self.zcu.import_table.get(abs_root_src_path).?;
1060
1061 var root_scope = Scope{
1062 .parent = null,
1063 .enclosing_type = null,
1064 };
1065 const maybe_tldoc_comment = try self.getTLDocComment(file);
1066 try self.ast_nodes.append(self.arena, .{
1067 .name = "(root)",
1068 .docs = maybe_tldoc_comment,
1069 });
1070 try self.files.put(self.arena, new_file, main_type_index);
1071 return self.walkInstruction(
1072 new_file,
1073 &root_scope,
1074 .{},
1075 .main_struct_inst,
1076 false,
1077 call_ctx,
1078 );
1079 }
1080
1081 const new_file = try self.zcu.importFile(file, path);
1082 const result = try self.files.getOrPut(self.arena, new_file.file);
1083 if (result.found_existing) {
1084 return DocData.WalkResult{
1085 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
1086 .expr = .{ .type = result.value_ptr.* },
1087 };
1088 }
1089
1090 const maybe_tldoc_comment = try self.getTLDocComment(new_file.file);
1091 try self.ast_nodes.append(self.arena, .{
1092 .name = path,
1093 .docs = maybe_tldoc_comment,
1094 });
1095
1096 result.value_ptr.* = self.types.items.len;
1097
1098 var new_scope = Scope{
1099 .parent = null,
1100 .enclosing_type = null,
1101 };
1102
1103 return self.walkInstruction(
1104 new_file.file,
1105 &new_scope,
1106 .{},
1107 .main_struct_inst,
1108 need_type,
1109 call_ctx,
1110 );
1111 },
1112 .ret_type => {
1113 return DocData.WalkResult{
1114 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
1115 .expr = .{ .type = @intFromEnum(Ref.type_type) },
1116 };
1117 },
1118 .ret_node => {
1119 const un_node = data[@intFromEnum(inst)].un_node;
1120 return self.walkRef(
1121 file,
1122 parent_scope,
1123 parent_src,
1124 un_node.operand,
1125 false,
1126 call_ctx,
1127 );
1128 },
1129 .ret_load => {
1130 const un_node = data[@intFromEnum(inst)].un_node;
1131 const res_ptr_ref = un_node.operand;
1132 const res_ptr_inst = @intFromEnum(res_ptr_ref.toIndex().?);
1133 // TODO: this instruction doesn't let us know trivially if there's
1134 // branching involved or not. For now here's the strat:
1135 // We search backwarts until `ret_ptr` for `store_node`,
1136 // if we find only one, then that's our value, if we find more
1137 // than one, then it means that there's branching involved.
1138 // Maybe.
1139
1140 var i = @intFromEnum(inst) - 1;
1141 var result_ref: ?Ref = null;
1142 while (i > res_ptr_inst) : (i -= 1) {
1143 if (tags[i] == .store_node) {
1144 const pl_node = data[i].pl_node;
1145 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1146 if (extra.data.lhs == res_ptr_ref) {
1147 // this store_load instruction is indeed pointing at
1148 // the result location that we care about!
1149 if (result_ref != null) return DocData.WalkResult{
1150 .expr = .{ .comptimeExpr = 0 },
1151 };
1152 result_ref = extra.data.rhs;
1153 }
1154 }
1155 }
1156
1157 if (result_ref) |rr| {
1158 return self.walkRef(
1159 file,
1160 parent_scope,
1161 parent_src,
1162 rr,
1163 need_type,
1164 call_ctx,
1165 );
1166 }
1167
1168 return DocData.WalkResult{
1169 .expr = .{ .comptimeExpr = 0 },
1170 };
1171 },
1172 .str => {
1173 const str = data[@intFromEnum(inst)].str.get(file.zir);
1174
1175 const tRef: ?DocData.Expr = if (!need_type) null else blk: {
1176 const arrTypeId = self.types.items.len;
1177 try self.types.append(self.arena, .{
1178 .Array = .{
1179 .len = .{ .int = .{ .value = str.len } },
1180 .child = .{ .type = @intFromEnum(Ref.u8_type) },
1181 .sentinel = .{ .int = .{
1182 .value = 0,
1183 .negated = false,
1184 } },
1185 },
1186 });
1187 // const sentinel: ?usize = if (ptr.flags.has_sentinel) 0 else null;
1188 const ptrTypeId = self.types.items.len;
1189 try self.types.append(self.arena, .{
1190 .Pointer = .{
1191 .size = .One,
1192 .child = .{ .type = arrTypeId },
1193 .sentinel = .{ .int = .{
1194 .value = 0,
1195 .negated = false,
1196 } },
1197 .is_mutable = false,
1198 },
1199 });
1200 break :blk .{ .type = ptrTypeId };
1201 };
1202
1203 return DocData.WalkResult{
1204 .typeRef = tRef,
1205 .expr = .{ .string = str },
1206 };
1207 },
1208 .compile_error => {
1209 const un_node = data[@intFromEnum(inst)].un_node;
1210
1211 const operand: DocData.WalkResult = try self.walkRef(
1212 file,
1213 parent_scope,
1214 parent_src,
1215 un_node.operand,
1216 false,
1217 call_ctx,
1218 );
1219
1220 const operand_index = self.exprs.items.len;
1221 try self.exprs.append(self.arena, operand.expr);
1222
1223 return DocData.WalkResult{
1224 .expr = .{ .compileError = operand_index },
1225 };
1226 },
1227 .enum_literal => {
1228 const str_tok = data[@intFromEnum(inst)].str_tok;
1229 const literal = file.zir.nullTerminatedString(str_tok.start);
1230 const type_index = self.types.items.len;
1231 try self.types.append(self.arena, .{
1232 .EnumLiteral = .{ .name = "todo enum literal" },
1233 });
1234
1235 return DocData.WalkResult{
1236 .typeRef = .{ .type = type_index },
1237 .expr = .{ .enumLiteral = literal },
1238 };
1239 },
1240 .int => {
1241 const int = data[@intFromEnum(inst)].int;
1242 return DocData.WalkResult{
1243 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
1244 .expr = .{ .int = .{ .value = int } },
1245 };
1246 },
1247 .int_big => {
1248 // @check
1249 const str = data[@intFromEnum(inst)].str; //.get(file.zir);
1250 const byte_count = str.len * @sizeOf(std.math.big.Limb);
1251 const limb_bytes = file.zir.string_bytes[@intFromEnum(str.start)..][0..byte_count];
1252
1253 const limbs = try self.arena.alloc(std.math.big.Limb, str.len);
1254 @memcpy(std.mem.sliceAsBytes(limbs)[0..limb_bytes.len], limb_bytes);
1255
1256 const big_int = std.math.big.int.Const{
1257 .limbs = limbs,
1258 .positive = true,
1259 };
1260
1261 const as_string = try big_int.toStringAlloc(self.arena, 10, .lower);
1262
1263 return DocData.WalkResult{
1264 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
1265 .expr = .{ .int_big = .{ .value = as_string } },
1266 };
1267 },
1268 .@"unreachable" => {
1269 return DocData.WalkResult{
1270 .typeRef = .{ .type = @intFromEnum(Ref.noreturn_type) },
1271 .expr = .{ .@"unreachable" = .{} },
1272 };
1273 },
1274
1275 .slice_start => {
1276 const pl_node = data[@intFromEnum(inst)].pl_node;
1277 const extra = file.zir.extraData(Zir.Inst.SliceStart, pl_node.payload_index);
1278
1279 const slice_index = self.exprs.items.len;
1280 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1281
1282 const lhs: DocData.WalkResult = try self.walkRef(
1283 file,
1284 parent_scope,
1285 parent_src,
1286 extra.data.lhs,
1287 false,
1288 call_ctx,
1289 );
1290 const start: DocData.WalkResult = try self.walkRef(
1291 file,
1292 parent_scope,
1293 parent_src,
1294 extra.data.start,
1295 false,
1296 call_ctx,
1297 );
1298
1299 const lhs_index = self.exprs.items.len;
1300 try self.exprs.append(self.arena, lhs.expr);
1301 const start_index = self.exprs.items.len;
1302 try self.exprs.append(self.arena, start.expr);
1303 self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index } };
1304
1305 const typeRef = switch (lhs.expr) {
1306 .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
1307 else => null,
1308 };
1309
1310 return DocData.WalkResult{
1311 .typeRef = typeRef,
1312 .expr = .{ .sliceIndex = slice_index },
1313 };
1314 },
1315 .slice_end => {
1316 const pl_node = data[@intFromEnum(inst)].pl_node;
1317 const extra = file.zir.extraData(Zir.Inst.SliceEnd, pl_node.payload_index);
1318
1319 const slice_index = self.exprs.items.len;
1320 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1321
1322 const lhs: DocData.WalkResult = try self.walkRef(
1323 file,
1324 parent_scope,
1325 parent_src,
1326 extra.data.lhs,
1327 false,
1328 call_ctx,
1329 );
1330 const start: DocData.WalkResult = try self.walkRef(
1331 file,
1332 parent_scope,
1333 parent_src,
1334 extra.data.start,
1335 false,
1336 call_ctx,
1337 );
1338 const end: DocData.WalkResult = try self.walkRef(
1339 file,
1340 parent_scope,
1341 parent_src,
1342 extra.data.end,
1343 false,
1344 call_ctx,
1345 );
1346
1347 const lhs_index = self.exprs.items.len;
1348 try self.exprs.append(self.arena, lhs.expr);
1349 const start_index = self.exprs.items.len;
1350 try self.exprs.append(self.arena, start.expr);
1351 const end_index = self.exprs.items.len;
1352 try self.exprs.append(self.arena, end.expr);
1353 self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = end_index } };
1354
1355 const typeRef = switch (lhs.expr) {
1356 .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
1357 else => null,
1358 };
1359
1360 return DocData.WalkResult{
1361 .typeRef = typeRef,
1362 .expr = .{ .sliceIndex = slice_index },
1363 };
1364 },
1365 .slice_sentinel => {
1366 const pl_node = data[@intFromEnum(inst)].pl_node;
1367 const extra = file.zir.extraData(Zir.Inst.SliceSentinel, pl_node.payload_index);
1368
1369 const slice_index = self.exprs.items.len;
1370 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1371
1372 const lhs: DocData.WalkResult = try self.walkRef(
1373 file,
1374 parent_scope,
1375 parent_src,
1376 extra.data.lhs,
1377 false,
1378 call_ctx,
1379 );
1380 const start: DocData.WalkResult = try self.walkRef(
1381 file,
1382 parent_scope,
1383 parent_src,
1384 extra.data.start,
1385 false,
1386 call_ctx,
1387 );
1388 const end: DocData.WalkResult = try self.walkRef(
1389 file,
1390 parent_scope,
1391 parent_src,
1392 extra.data.end,
1393 false,
1394 call_ctx,
1395 );
1396 const sentinel: DocData.WalkResult = try self.walkRef(
1397 file,
1398 parent_scope,
1399 parent_src,
1400 extra.data.sentinel,
1401 false,
1402 call_ctx,
1403 );
1404
1405 const lhs_index = self.exprs.items.len;
1406 try self.exprs.append(self.arena, lhs.expr);
1407 const start_index = self.exprs.items.len;
1408 try self.exprs.append(self.arena, start.expr);
1409 const end_index = self.exprs.items.len;
1410 try self.exprs.append(self.arena, end.expr);
1411 const sentinel_index = self.exprs.items.len;
1412 try self.exprs.append(self.arena, sentinel.expr);
1413 self.exprs.items[slice_index] = .{ .slice = .{
1414 .lhs = lhs_index,
1415 .start = start_index,
1416 .end = end_index,
1417 .sentinel = sentinel_index,
1418 } };
1419
1420 const typeRef = switch (lhs.expr) {
1421 .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
1422 else => null,
1423 };
1424
1425 return DocData.WalkResult{
1426 .typeRef = typeRef,
1427 .expr = .{ .sliceIndex = slice_index },
1428 };
1429 },
1430 .slice_length => {
1431 const pl_node = data[@intFromEnum(inst)].pl_node;
1432 const extra = file.zir.extraData(Zir.Inst.SliceLength, pl_node.payload_index);
1433
1434 const slice_index = self.exprs.items.len;
1435 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1436
1437 const lhs: DocData.WalkResult = try self.walkRef(
1438 file,
1439 parent_scope,
1440 parent_src,
1441 extra.data.lhs,
1442 false,
1443 call_ctx,
1444 );
1445 const start: DocData.WalkResult = try self.walkRef(
1446 file,
1447 parent_scope,
1448 parent_src,
1449 extra.data.start,
1450 false,
1451 call_ctx,
1452 );
1453 const len: DocData.WalkResult = try self.walkRef(
1454 file,
1455 parent_scope,
1456 parent_src,
1457 extra.data.len,
1458 false,
1459 call_ctx,
1460 );
1461 const sentinel_opt: ?DocData.WalkResult = if (extra.data.sentinel != .none)
1462 try self.walkRef(
1463 file,
1464 parent_scope,
1465 parent_src,
1466 extra.data.sentinel,
1467 false,
1468 call_ctx,
1469 )
1470 else
1471 null;
1472
1473 const lhs_index = self.exprs.items.len;
1474 try self.exprs.append(self.arena, lhs.expr);
1475 const start_index = self.exprs.items.len;
1476 try self.exprs.append(self.arena, start.expr);
1477 const len_index = self.exprs.items.len;
1478 try self.exprs.append(self.arena, len.expr);
1479 const sentinel_index = if (sentinel_opt) |sentinel| sentinel_index: {
1480 const index = self.exprs.items.len;
1481 try self.exprs.append(self.arena, sentinel.expr);
1482 break :sentinel_index index;
1483 } else null;
1484 self.exprs.items[slice_index] = .{ .sliceLength = .{
1485 .lhs = lhs_index,
1486 .start = start_index,
1487 .len = len_index,
1488 .sentinel = sentinel_index,
1489 } };
1490
1491 const typeRef = switch (lhs.expr) {
1492 .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
1493 else => null,
1494 };
1495
1496 return DocData.WalkResult{
1497 .typeRef = typeRef,
1498 .expr = .{ .sliceIndex = slice_index },
1499 };
1500 },
1501
1502 .load => {
1503 const un_node = data[@intFromEnum(inst)].un_node;
1504 const operand = try self.walkRef(
1505 file,
1506 parent_scope,
1507 parent_src,
1508 un_node.operand,
1509 need_type,
1510 call_ctx,
1511 );
1512 const load_idx = self.exprs.items.len;
1513 try self.exprs.append(self.arena, operand.expr);
1514
1515 var typeRef: ?DocData.Expr = null;
1516 if (operand.typeRef) |ref| {
1517 switch (ref) {
1518 .type => |t_index| {
1519 switch (self.types.items[t_index]) {
1520 .Pointer => |p| typeRef = p.child,
1521 else => {},
1522 }
1523 },
1524 else => {},
1525 }
1526 }
1527
1528 return DocData.WalkResult{
1529 .typeRef = typeRef,
1530 .expr = .{ .load = load_idx },
1531 };
1532 },
1533 .ref => {
1534 const un_tok = data[@intFromEnum(inst)].un_tok;
1535 const operand = try self.walkRef(
1536 file,
1537 parent_scope,
1538 parent_src,
1539 un_tok.operand,
1540 need_type,
1541 call_ctx,
1542 );
1543 const ref_idx = self.exprs.items.len;
1544 try self.exprs.append(self.arena, operand.expr);
1545
1546 return DocData.WalkResult{
1547 .expr = .{ .@"&" = ref_idx },
1548 };
1549 },
1550
1551 .add,
1552 .addwrap,
1553 .add_sat,
1554 .sub,
1555 .subwrap,
1556 .sub_sat,
1557 .mul,
1558 .mulwrap,
1559 .mul_sat,
1560 .div,
1561 .shl,
1562 .shl_sat,
1563 .shr,
1564 .bit_or,
1565 .bit_and,
1566 .xor,
1567 .array_cat,
1568 => {
1569 const pl_node = data[@intFromEnum(inst)].pl_node;
1570 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1571
1572 const binop_index = self.exprs.items.len;
1573 try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
1574
1575 const lhs: DocData.WalkResult = try self.walkRef(
1576 file,
1577 parent_scope,
1578 parent_src,
1579 extra.data.lhs,
1580 false,
1581 call_ctx,
1582 );
1583 const rhs: DocData.WalkResult = try self.walkRef(
1584 file,
1585 parent_scope,
1586 parent_src,
1587 extra.data.rhs,
1588 false,
1589 call_ctx,
1590 );
1591
1592 const lhs_index = self.exprs.items.len;
1593 try self.exprs.append(self.arena, lhs.expr);
1594 const rhs_index = self.exprs.items.len;
1595 try self.exprs.append(self.arena, rhs.expr);
1596 self.exprs.items[binop_index] = .{ .binOp = .{
1597 .name = @tagName(tags[@intFromEnum(inst)]),
1598 .lhs = lhs_index,
1599 .rhs = rhs_index,
1600 } };
1601
1602 return DocData.WalkResult{
1603 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
1604 .expr = .{ .binOpIndex = binop_index },
1605 };
1606 },
1607 .array_mul => {
1608 const pl_node = data[@intFromEnum(inst)].pl_node;
1609 const extra = file.zir.extraData(Zir.Inst.ArrayMul, pl_node.payload_index);
1610
1611 const binop_index = self.exprs.items.len;
1612 try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
1613
1614 const lhs: DocData.WalkResult = try self.walkRef(
1615 file,
1616 parent_scope,
1617 parent_src,
1618 extra.data.lhs,
1619 false,
1620 call_ctx,
1621 );
1622 const rhs: DocData.WalkResult = try self.walkRef(
1623 file,
1624 parent_scope,
1625 parent_src,
1626 extra.data.rhs,
1627 false,
1628 call_ctx,
1629 );
1630 const res_ty: ?DocData.WalkResult = if (extra.data.res_ty != .none)
1631 try self.walkRef(
1632 file,
1633 parent_scope,
1634 parent_src,
1635 extra.data.res_ty,
1636 false,
1637 call_ctx,
1638 )
1639 else
1640 null;
1641
1642 const lhs_index = self.exprs.items.len;
1643 try self.exprs.append(self.arena, lhs.expr);
1644 const rhs_index = self.exprs.items.len;
1645 try self.exprs.append(self.arena, rhs.expr);
1646 self.exprs.items[binop_index] = .{ .binOp = .{
1647 .name = @tagName(tags[@intFromEnum(inst)]),
1648 .lhs = lhs_index,
1649 .rhs = rhs_index,
1650 } };
1651
1652 return DocData.WalkResult{
1653 .typeRef = if (res_ty) |rt| rt.expr else null,
1654 .expr = .{ .binOpIndex = binop_index },
1655 };
1656 },
1657 // compare operators
1658 .cmp_eq,
1659 .cmp_neq,
1660 .cmp_gt,
1661 .cmp_gte,
1662 .cmp_lt,
1663 .cmp_lte,
1664 => {
1665 const pl_node = data[@intFromEnum(inst)].pl_node;
1666 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1667
1668 const binop_index = self.exprs.items.len;
1669 try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
1670
1671 const lhs: DocData.WalkResult = try self.walkRef(
1672 file,
1673 parent_scope,
1674 parent_src,
1675 extra.data.lhs,
1676 false,
1677 call_ctx,
1678 );
1679 const rhs: DocData.WalkResult = try self.walkRef(
1680 file,
1681 parent_scope,
1682 parent_src,
1683 extra.data.rhs,
1684 false,
1685 call_ctx,
1686 );
1687
1688 const lhs_index = self.exprs.items.len;
1689 try self.exprs.append(self.arena, lhs.expr);
1690 const rhs_index = self.exprs.items.len;
1691 try self.exprs.append(self.arena, rhs.expr);
1692 self.exprs.items[binop_index] = .{ .binOp = .{
1693 .name = @tagName(tags[@intFromEnum(inst)]),
1694 .lhs = lhs_index,
1695 .rhs = rhs_index,
1696 } };
1697
1698 return DocData.WalkResult{
1699 .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
1700 .expr = .{ .binOpIndex = binop_index },
1701 };
1702 },
1703
1704 // builtin functions
1705 .align_of,
1706 .int_from_bool,
1707 .embed_file,
1708 .error_name,
1709 .panic,
1710 .set_runtime_safety, // @check
1711 .sqrt,
1712 .sin,
1713 .cos,
1714 .tan,
1715 .exp,
1716 .exp2,
1717 .log,
1718 .log2,
1719 .log10,
1720 .abs,
1721 .floor,
1722 .ceil,
1723 .trunc,
1724 .round,
1725 .tag_name,
1726 .type_name,
1727 .frame_type,
1728 .frame_size,
1729 .int_from_ptr,
1730 .type_info,
1731 // @check
1732 .clz,
1733 .ctz,
1734 .pop_count,
1735 .byte_swap,
1736 .bit_reverse,
1737 => {
1738 const un_node = data[@intFromEnum(inst)].un_node;
1739 const bin_index = self.exprs.items.len;
1740 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
1741 const param = try self.walkRef(
1742 file,
1743 parent_scope,
1744 parent_src,
1745 un_node.operand,
1746 false,
1747 call_ctx,
1748 );
1749
1750 const param_index = self.exprs.items.len;
1751 try self.exprs.append(self.arena, param.expr);
1752
1753 self.exprs.items[bin_index] = .{
1754 .builtin = .{
1755 .name = @tagName(tags[@intFromEnum(inst)]),
1756 .param = param_index,
1757 },
1758 };
1759
1760 return DocData.WalkResult{
1761 .typeRef = param.typeRef orelse .{ .type = @intFromEnum(Ref.type_type) },
1762 .expr = .{ .builtinIndex = bin_index },
1763 };
1764 },
1765 .bit_not,
1766 .bool_not,
1767 .negate_wrap,
1768 => {
1769 const un_node = data[@intFromEnum(inst)].un_node;
1770 const un_index = self.exprs.items.len;
1771 try self.exprs.append(self.arena, .{ .unOp = .{ .param = 0 } });
1772 const param = try self.walkRef(
1773 file,
1774 parent_scope,
1775 parent_src,
1776 un_node.operand,
1777 false,
1778 call_ctx,
1779 );
1780
1781 const param_index = self.exprs.items.len;
1782 try self.exprs.append(self.arena, param.expr);
1783
1784 self.exprs.items[un_index] = .{
1785 .unOp = .{
1786 .name = @tagName(tags[@intFromEnum(inst)]),
1787 .param = param_index,
1788 },
1789 };
1790
1791 return DocData.WalkResult{
1792 .typeRef = param.typeRef,
1793 .expr = .{ .unOpIndex = un_index },
1794 };
1795 },
1796 .bool_br_and, .bool_br_or => {
1797 const pl_node = data[@intFromEnum(inst)].pl_node;
1798 const extra = file.zir.extraData(Zir.Inst.BoolBr, pl_node.payload_index);
1799
1800 const bin_index = self.exprs.items.len;
1801 try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
1802
1803 const lhs = try self.walkRef(
1804 file,
1805 parent_scope,
1806 parent_src,
1807 extra.data.lhs,
1808 false,
1809 call_ctx,
1810 );
1811 const lhs_index = self.exprs.items.len;
1812 try self.exprs.append(self.arena, lhs.expr);
1813
1814 const rhs = try self.walkInstruction(
1815 file,
1816 parent_scope,
1817 parent_src,
1818 @enumFromInt(file.zir.extra[extra.end..][extra.data.body_len - 1]),
1819 false,
1820 call_ctx,
1821 );
1822 const rhs_index = self.exprs.items.len;
1823 try self.exprs.append(self.arena, rhs.expr);
1824
1825 self.exprs.items[bin_index] = .{ .binOp = .{ .name = @tagName(tags[@intFromEnum(inst)]), .lhs = lhs_index, .rhs = rhs_index } };
1826
1827 return DocData.WalkResult{
1828 .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
1829 .expr = .{ .binOpIndex = bin_index },
1830 };
1831 },
1832 .truncate => {
1833 // in the ZIR this node is a builtin `bin` but we want send it as a `un` builtin
1834 const pl_node = data[@intFromEnum(inst)].pl_node;
1835 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1836
1837 const rhs: DocData.WalkResult = try self.walkRef(
1838 file,
1839 parent_scope,
1840 parent_src,
1841 extra.data.rhs,
1842 false,
1843 call_ctx,
1844 );
1845
1846 const bin_index = self.exprs.items.len;
1847 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
1848
1849 const rhs_index = self.exprs.items.len;
1850 try self.exprs.append(self.arena, rhs.expr);
1851
1852 const lhs: DocData.WalkResult = try self.walkRef(
1853 file,
1854 parent_scope,
1855 parent_src,
1856 extra.data.lhs,
1857 false,
1858 call_ctx,
1859 );
1860
1861 self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[@intFromEnum(inst)]), .param = rhs_index } };
1862
1863 return DocData.WalkResult{
1864 .typeRef = lhs.expr,
1865 .expr = .{ .builtinIndex = bin_index },
1866 };
1867 },
1868 .int_from_float,
1869 .float_from_int,
1870 .ptr_from_int,
1871 .enum_from_int,
1872 .float_cast,
1873 .int_cast,
1874 .ptr_cast,
1875 .has_decl,
1876 .has_field,
1877 .div_exact,
1878 .div_floor,
1879 .div_trunc,
1880 .mod,
1881 .rem,
1882 .mod_rem,
1883 .shl_exact,
1884 .shr_exact,
1885 .bitcast,
1886 .vector_type,
1887 // @check
1888 .bit_offset_of,
1889 .offset_of,
1890 .splat,
1891 .reduce,
1892 .min,
1893 .max,
1894 => {
1895 const pl_node = data[@intFromEnum(inst)].pl_node;
1896 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1897
1898 const binop_index = self.exprs.items.len;
1899 try self.exprs.append(self.arena, .{ .builtinBin = .{ .lhs = 0, .rhs = 0 } });
1900
1901 const lhs: DocData.WalkResult = try self.walkRef(
1902 file,
1903 parent_scope,
1904 parent_src,
1905 extra.data.lhs,
1906 false,
1907 call_ctx,
1908 );
1909 const rhs: DocData.WalkResult = try self.walkRef(
1910 file,
1911 parent_scope,
1912 parent_src,
1913 extra.data.rhs,
1914 false,
1915 call_ctx,
1916 );
1917
1918 const lhs_index = self.exprs.items.len;
1919 try self.exprs.append(self.arena, lhs.expr);
1920 const rhs_index = self.exprs.items.len;
1921 try self.exprs.append(self.arena, rhs.expr);
1922 self.exprs.items[binop_index] = .{ .builtinBin = .{ .name = @tagName(tags[@intFromEnum(inst)]), .lhs = lhs_index, .rhs = rhs_index } };
1923
1924 return DocData.WalkResult{
1925 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
1926 .expr = .{ .builtinBinIndex = binop_index },
1927 };
1928 },
1929 .mul_add => {
1930 const pl_node = data[@intFromEnum(inst)].pl_node;
1931 const extra = file.zir.extraData(Zir.Inst.MulAdd, pl_node.payload_index);
1932
1933 const mul1: DocData.WalkResult = try self.walkRef(
1934 file,
1935 parent_scope,
1936 parent_src,
1937 extra.data.mulend1,
1938 false,
1939 call_ctx,
1940 );
1941 const mul2: DocData.WalkResult = try self.walkRef(
1942 file,
1943 parent_scope,
1944 parent_src,
1945 extra.data.mulend2,
1946 false,
1947 call_ctx,
1948 );
1949 const add: DocData.WalkResult = try self.walkRef(
1950 file,
1951 parent_scope,
1952 parent_src,
1953 extra.data.addend,
1954 false,
1955 call_ctx,
1956 );
1957
1958 const mul1_index = self.exprs.items.len;
1959 try self.exprs.append(self.arena, mul1.expr);
1960 const mul2_index = self.exprs.items.len;
1961 try self.exprs.append(self.arena, mul2.expr);
1962 const add_index = self.exprs.items.len;
1963 try self.exprs.append(self.arena, add.expr);
1964
1965 const type_index: usize = self.exprs.items.len;
1966 try self.exprs.append(self.arena, add.typeRef orelse .{ .type = @intFromEnum(Ref.type_type) });
1967
1968 return DocData.WalkResult{
1969 .typeRef = add.typeRef,
1970 .expr = .{
1971 .mulAdd = .{
1972 .mulend1 = mul1_index,
1973 .mulend2 = mul2_index,
1974 .addend = add_index,
1975 .type = type_index,
1976 },
1977 },
1978 };
1979 },
1980 .union_init => {
1981 const pl_node = data[@intFromEnum(inst)].pl_node;
1982 const extra = file.zir.extraData(Zir.Inst.UnionInit, pl_node.payload_index);
1983
1984 const union_type: DocData.WalkResult = try self.walkRef(
1985 file,
1986 parent_scope,
1987 parent_src,
1988 extra.data.union_type,
1989 false,
1990 call_ctx,
1991 );
1992 const field_name: DocData.WalkResult = try self.walkRef(
1993 file,
1994 parent_scope,
1995 parent_src,
1996 extra.data.field_name,
1997 false,
1998 call_ctx,
1999 );
2000 const init: DocData.WalkResult = try self.walkRef(
2001 file,
2002 parent_scope,
2003 parent_src,
2004 extra.data.init,
2005 false,
2006 call_ctx,
2007 );
2008
2009 const union_type_index = self.exprs.items.len;
2010 try self.exprs.append(self.arena, union_type.expr);
2011 const field_name_index = self.exprs.items.len;
2012 try self.exprs.append(self.arena, field_name.expr);
2013 const init_index = self.exprs.items.len;
2014 try self.exprs.append(self.arena, init.expr);
2015
2016 return DocData.WalkResult{
2017 .typeRef = union_type.expr,
2018 .expr = .{
2019 .unionInit = .{
2020 .type = union_type_index,
2021 .field = field_name_index,
2022 .init = init_index,
2023 },
2024 },
2025 };
2026 },
2027 .builtin_call => {
2028 const pl_node = data[@intFromEnum(inst)].pl_node;
2029 const extra = file.zir.extraData(Zir.Inst.BuiltinCall, pl_node.payload_index);
2030
2031 const modifier: DocData.WalkResult = try self.walkRef(
2032 file,
2033 parent_scope,
2034 parent_src,
2035 extra.data.modifier,
2036 false,
2037 call_ctx,
2038 );
2039
2040 const callee: DocData.WalkResult = try self.walkRef(
2041 file,
2042 parent_scope,
2043 parent_src,
2044 extra.data.callee,
2045 false,
2046 call_ctx,
2047 );
2048
2049 const args: DocData.WalkResult = try self.walkRef(
2050 file,
2051 parent_scope,
2052 parent_src,
2053 extra.data.args,
2054 false,
2055 call_ctx,
2056 );
2057
2058 const modifier_index = self.exprs.items.len;
2059 try self.exprs.append(self.arena, modifier.expr);
2060 const function_index = self.exprs.items.len;
2061 try self.exprs.append(self.arena, callee.expr);
2062 const args_index = self.exprs.items.len;
2063 try self.exprs.append(self.arena, args.expr);
2064
2065 return DocData.WalkResult{
2066 .expr = .{
2067 .builtinCall = .{
2068 .modifier = modifier_index,
2069 .function = function_index,
2070 .args = args_index,
2071 },
2072 },
2073 };
2074 },
2075 .error_union_type => {
2076 const pl_node = data[@intFromEnum(inst)].pl_node;
2077 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
2078
2079 const lhs: DocData.WalkResult = try self.walkRef(
2080 file,
2081 parent_scope,
2082 parent_src,
2083 extra.data.lhs,
2084 false,
2085 call_ctx,
2086 );
2087 const rhs: DocData.WalkResult = try self.walkRef(
2088 file,
2089 parent_scope,
2090 parent_src,
2091 extra.data.rhs,
2092 false,
2093 call_ctx,
2094 );
2095
2096 const type_slot_index = self.types.items.len;
2097 try self.types.append(self.arena, .{ .ErrorUnion = .{
2098 .lhs = lhs.expr,
2099 .rhs = rhs.expr,
2100 } });
2101
2102 return DocData.WalkResult{
2103 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2104 .expr = .{ .errorUnion = type_slot_index },
2105 };
2106 },
2107 .merge_error_sets => {
2108 const pl_node = data[@intFromEnum(inst)].pl_node;
2109 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
2110
2111 const lhs: DocData.WalkResult = try self.walkRef(
2112 file,
2113 parent_scope,
2114 parent_src,
2115 extra.data.lhs,
2116 false,
2117 call_ctx,
2118 );
2119 const rhs: DocData.WalkResult = try self.walkRef(
2120 file,
2121 parent_scope,
2122 parent_src,
2123 extra.data.rhs,
2124 false,
2125 call_ctx,
2126 );
2127 const type_slot_index = self.types.items.len;
2128 try self.types.append(self.arena, .{ .ErrorUnion = .{
2129 .lhs = lhs.expr,
2130 .rhs = rhs.expr,
2131 } });
2132
2133 return DocData.WalkResult{
2134 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2135 .expr = .{ .errorSets = type_slot_index },
2136 };
2137 },
2138 // .elem_type => {
2139 // const un_node = data[@intFromEnum(inst)].un_node;
2140
2141 // const operand: DocData.WalkResult = try self.walkRef(
2142 // file,
2143 // parent_scope, parent_src,
2144 // un_node.operand,
2145 // false,
2146 // );
2147
2148 // return operand;
2149 // },
2150 .ptr_type => {
2151 const ptr = data[@intFromEnum(inst)].ptr_type;
2152 const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);
2153 var extra_index = extra.end;
2154
2155 const elem_type_ref = try self.walkRef(
2156 file,
2157 parent_scope,
2158 parent_src,
2159 extra.data.elem_type,
2160 false,
2161 call_ctx,
2162 );
2163
2164 // @check if `addrspace`, `bit_start` and `host_size` really need to be
2165 // present in json
2166 var sentinel: ?DocData.Expr = null;
2167 if (ptr.flags.has_sentinel) {
2168 const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
2169 const ref_result = try self.walkRef(
2170 file,
2171 parent_scope,
2172 parent_src,
2173 ref,
2174 false,
2175 call_ctx,
2176 );
2177 sentinel = ref_result.expr;
2178 extra_index += 1;
2179 }
2180
2181 var @"align": ?DocData.Expr = null;
2182 if (ptr.flags.has_align) {
2183 const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
2184 const ref_result = try self.walkRef(
2185 file,
2186 parent_scope,
2187 parent_src,
2188 ref,
2189 false,
2190 call_ctx,
2191 );
2192 @"align" = ref_result.expr;
2193 extra_index += 1;
2194 }
2195 var address_space: ?DocData.Expr = null;
2196 if (ptr.flags.has_addrspace) {
2197 const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
2198 const ref_result = try self.walkRef(
2199 file,
2200 parent_scope,
2201 parent_src,
2202 ref,
2203 false,
2204 call_ctx,
2205 );
2206 address_space = ref_result.expr;
2207 extra_index += 1;
2208 }
2209 const bit_start: ?DocData.Expr = null;
2210 if (ptr.flags.has_bit_range) {
2211 const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
2212 const ref_result = try self.walkRef(
2213 file,
2214 parent_scope,
2215 parent_src,
2216 ref,
2217 false,
2218 call_ctx,
2219 );
2220 address_space = ref_result.expr;
2221 extra_index += 1;
2222 }
2223
2224 var host_size: ?DocData.Expr = null;
2225 if (ptr.flags.has_bit_range) {
2226 const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
2227 const ref_result = try self.walkRef(
2228 file,
2229 parent_scope,
2230 parent_src,
2231 ref,
2232 false,
2233 call_ctx,
2234 );
2235 host_size = ref_result.expr;
2236 }
2237
2238 const type_slot_index = self.types.items.len;
2239 try self.types.append(self.arena, .{
2240 .Pointer = .{
2241 .size = ptr.size,
2242 .child = elem_type_ref.expr,
2243 .has_align = ptr.flags.has_align,
2244 .@"align" = @"align",
2245 .has_addrspace = ptr.flags.has_addrspace,
2246 .address_space = address_space,
2247 .has_sentinel = ptr.flags.has_sentinel,
2248 .sentinel = sentinel,
2249 .is_mutable = ptr.flags.is_mutable,
2250 .is_volatile = ptr.flags.is_volatile,
2251 .has_bit_range = ptr.flags.has_bit_range,
2252 .bit_start = bit_start,
2253 .host_size = host_size,
2254 },
2255 });
2256 return DocData.WalkResult{
2257 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2258 .expr = .{ .type = type_slot_index },
2259 };
2260 },
2261 .array_type => {
2262 const pl_node = data[@intFromEnum(inst)].pl_node;
2263
2264 const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
2265 const len = try self.walkRef(
2266 file,
2267 parent_scope,
2268 parent_src,
2269 bin.lhs,
2270 false,
2271 call_ctx,
2272 );
2273 const child = try self.walkRef(
2274 file,
2275 parent_scope,
2276 parent_src,
2277 bin.rhs,
2278 false,
2279 call_ctx,
2280 );
2281
2282 const type_slot_index = self.types.items.len;
2283 try self.types.append(self.arena, .{
2284 .Array = .{
2285 .len = len.expr,
2286 .child = child.expr,
2287 },
2288 });
2289
2290 return DocData.WalkResult{
2291 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2292 .expr = .{ .type = type_slot_index },
2293 };
2294 },
2295 .array_type_sentinel => {
2296 const pl_node = data[@intFromEnum(inst)].pl_node;
2297 const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);
2298 const len = try self.walkRef(
2299 file,
2300 parent_scope,
2301 parent_src,
2302 extra.data.len,
2303 false,
2304 call_ctx,
2305 );
2306 const sentinel = try self.walkRef(
2307 file,
2308 parent_scope,
2309 parent_src,
2310 extra.data.sentinel,
2311 false,
2312 call_ctx,
2313 );
2314 const elem_type = try self.walkRef(
2315 file,
2316 parent_scope,
2317 parent_src,
2318 extra.data.elem_type,
2319 false,
2320 call_ctx,
2321 );
2322
2323 const type_slot_index = self.types.items.len;
2324 try self.types.append(self.arena, .{
2325 .Array = .{
2326 .len = len.expr,
2327 .child = elem_type.expr,
2328 .sentinel = sentinel.expr,
2329 },
2330 });
2331 return DocData.WalkResult{
2332 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2333 .expr = .{ .type = type_slot_index },
2334 };
2335 },
2336 .array_init => {
2337 const pl_node = data[@intFromEnum(inst)].pl_node;
2338 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
2339 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
2340 const array_data = try self.arena.alloc(usize, operands.len - 1);
2341
2342 std.debug.assert(operands.len > 0);
2343 const array_type = try self.walkRef(
2344 file,
2345 parent_scope,
2346 parent_src,
2347 operands[0],
2348 false,
2349 call_ctx,
2350 );
2351
2352 for (operands[1..], 0..) |op, idx| {
2353 const wr = try self.walkRef(
2354 file,
2355 parent_scope,
2356 parent_src,
2357 op,
2358 false,
2359 call_ctx,
2360 );
2361 const expr_index = self.exprs.items.len;
2362 try self.exprs.append(self.arena, wr.expr);
2363 array_data[idx] = expr_index;
2364 }
2365
2366 return DocData.WalkResult{
2367 .typeRef = array_type.expr,
2368 .expr = .{ .array = array_data },
2369 };
2370 },
2371 .array_init_anon => {
2372 const pl_node = data[@intFromEnum(inst)].pl_node;
2373 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
2374 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
2375 const array_data = try self.arena.alloc(usize, operands.len);
2376
2377 for (operands, 0..) |op, idx| {
2378 const wr = try self.walkRef(
2379 file,
2380 parent_scope,
2381 parent_src,
2382 op,
2383 false,
2384 call_ctx,
2385 );
2386 const expr_index = self.exprs.items.len;
2387 try self.exprs.append(self.arena, wr.expr);
2388 array_data[idx] = expr_index;
2389 }
2390
2391 return DocData.WalkResult{
2392 .typeRef = null,
2393 .expr = .{ .array = array_data },
2394 };
2395 },
2396 .array_init_ref => {
2397 const pl_node = data[@intFromEnum(inst)].pl_node;
2398 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
2399 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
2400 const array_data = try self.arena.alloc(usize, operands.len - 1);
2401
2402 std.debug.assert(operands.len > 0);
2403 const array_type = try self.walkRef(
2404 file,
2405 parent_scope,
2406 parent_src,
2407 operands[0],
2408 false,
2409 call_ctx,
2410 );
2411
2412 for (operands[1..], 0..) |op, idx| {
2413 const wr = try self.walkRef(
2414 file,
2415 parent_scope,
2416 parent_src,
2417 op,
2418 false,
2419 call_ctx,
2420 );
2421 const expr_index = self.exprs.items.len;
2422 try self.exprs.append(self.arena, wr.expr);
2423 array_data[idx] = expr_index;
2424 }
2425
2426 const type_slot_index = self.types.items.len;
2427 try self.types.append(self.arena, .{
2428 .Pointer = .{
2429 .size = .One,
2430 .child = array_type.expr,
2431 },
2432 });
2433
2434 const expr_index = self.exprs.items.len;
2435 try self.exprs.append(self.arena, .{ .array = array_data });
2436
2437 return DocData.WalkResult{
2438 .typeRef = .{ .type = type_slot_index },
2439 .expr = .{ .@"&" = expr_index },
2440 };
2441 },
2442 .float => {
2443 const float = data[@intFromEnum(inst)].float;
2444 return DocData.WalkResult{
2445 .typeRef = .{ .type = @intFromEnum(Ref.comptime_float_type) },
2446 .expr = .{ .float = float },
2447 };
2448 },
2449 // @check: In frontend I'm handling float128 with `.toFixed(2)`
2450 .float128 => {
2451 const pl_node = data[@intFromEnum(inst)].pl_node;
2452 const extra = file.zir.extraData(Zir.Inst.Float128, pl_node.payload_index);
2453 return DocData.WalkResult{
2454 .typeRef = .{ .type = @intFromEnum(Ref.comptime_float_type) },
2455 .expr = .{ .float128 = extra.data.get() },
2456 };
2457 },
2458 .negate => {
2459 const un_node = data[@intFromEnum(inst)].un_node;
2460
2461 var operand: DocData.WalkResult = try self.walkRef(
2462 file,
2463 parent_scope,
2464 parent_src,
2465 un_node.operand,
2466 need_type,
2467 call_ctx,
2468 );
2469 switch (operand.expr) {
2470 .int => |*int| int.negated = true,
2471 .int_big => |*int_big| int_big.negated = true,
2472 else => {
2473 const un_index = self.exprs.items.len;
2474 try self.exprs.append(self.arena, .{ .unOp = .{ .param = 0 } });
2475 const param_index = self.exprs.items.len;
2476 try self.exprs.append(self.arena, operand.expr);
2477 self.exprs.items[un_index] = .{
2478 .unOp = .{
2479 .name = @tagName(tags[@intFromEnum(inst)]),
2480 .param = param_index,
2481 },
2482 };
2483 return DocData.WalkResult{
2484 .typeRef = operand.typeRef,
2485 .expr = .{ .unOpIndex = un_index },
2486 };
2487 },
2488 }
2489 return operand;
2490 },
2491 .size_of => {
2492 const un_node = data[@intFromEnum(inst)].un_node;
2493
2494 const operand = try self.walkRef(
2495 file,
2496 parent_scope,
2497 parent_src,
2498 un_node.operand,
2499 false,
2500 call_ctx,
2501 );
2502 const operand_index = self.exprs.items.len;
2503 try self.exprs.append(self.arena, operand.expr);
2504 return DocData.WalkResult{
2505 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
2506 .expr = .{ .sizeOf = operand_index },
2507 };
2508 },
2509 .bit_size_of => {
2510 // not working correctly with `align()`
2511 const un_node = data[@intFromEnum(inst)].un_node;
2512
2513 const operand = try self.walkRef(
2514 file,
2515 parent_scope,
2516 parent_src,
2517 un_node.operand,
2518 need_type,
2519 call_ctx,
2520 );
2521 const operand_index = self.exprs.items.len;
2522 try self.exprs.append(self.arena, operand.expr);
2523
2524 return DocData.WalkResult{
2525 .typeRef = operand.typeRef,
2526 .expr = .{ .bitSizeOf = operand_index },
2527 };
2528 },
2529 .int_from_enum => {
2530 // not working correctly with `align()`
2531 const un_node = data[@intFromEnum(inst)].un_node;
2532 const operand = try self.walkRef(
2533 file,
2534 parent_scope,
2535 parent_src,
2536 un_node.operand,
2537 false,
2538 call_ctx,
2539 );
2540 const builtin_index = self.exprs.items.len;
2541 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
2542 const operand_index = self.exprs.items.len;
2543 try self.exprs.append(self.arena, operand.expr);
2544 self.exprs.items[builtin_index] = .{
2545 .builtin = .{
2546 .name = @tagName(tags[@intFromEnum(inst)]),
2547 .param = operand_index,
2548 },
2549 };
2550
2551 return DocData.WalkResult{
2552 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
2553 .expr = .{ .builtinIndex = builtin_index },
2554 };
2555 },
2556 .switch_block => {
2557 // WIP
2558 const pl_node = data[@intFromEnum(inst)].pl_node;
2559 const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
2560
2561 const switch_cond = try self.walkRef(
2562 file,
2563 parent_scope,
2564 parent_src,
2565 extra.data.operand,
2566 false,
2567 call_ctx,
2568 );
2569 const cond_index = self.exprs.items.len;
2570 try self.exprs.append(self.arena, switch_cond.expr);
2571 _ = cond_index;
2572
2573 // const ast_index = self.ast_nodes.items.len;
2574 // const type_index = self.types.items.len - 1;
2575
2576 // const ast_line = self.ast_nodes.items[ast_index - 1];
2577
2578 // const sep = "=" ** 200;
2579 // log.debug("{s}", .{sep});
2580 // log.debug("SWITCH BLOCK", .{});
2581 // log.debug("extra = {any}", .{extra});
2582 // log.debug("outer_decl = {any}", .{self.types.items[type_index]});
2583 // log.debug("ast_lines = {}", .{ast_line});
2584 // log.debug("{s}", .{sep});
2585
2586 const switch_index = self.exprs.items.len;
2587
2588 // const src_loc = try self.srcLocInfo(file, pl_node.src_node, parent_src);
2589
2590 const switch_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
2591 try self.exprs.append(self.arena, .{ .comptimeExpr = self.comptime_exprs.items.len });
2592 try self.comptime_exprs.append(self.arena, .{ .code = switch_expr });
2593 // try self.exprs.append(self.arena, .{ .switchOp = .{
2594 // .cond_index = cond_index,
2595 // .file_name = file.sub_file_path,
2596 // .src = ast_index,
2597 // .outer_decl = type_index,
2598 // } });
2599
2600 return DocData.WalkResult{
2601 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2602 .expr = .{ .switchIndex = switch_index },
2603 };
2604 },
2605
2606 .typeof => {
2607 const un_node = data[@intFromEnum(inst)].un_node;
2608
2609 const operand = try self.walkRef(
2610 file,
2611 parent_scope,
2612 parent_src,
2613 un_node.operand,
2614 need_type,
2615 call_ctx,
2616 );
2617 const operand_index = self.exprs.items.len;
2618 try self.exprs.append(self.arena, operand.expr);
2619
2620 return DocData.WalkResult{
2621 .typeRef = operand.typeRef,
2622 .expr = .{ .typeOf = operand_index },
2623 };
2624 },
2625 .typeof_builtin => {
2626 const pl_node = data[@intFromEnum(inst)].pl_node;
2627 const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
2628 const body = file.zir.extra[extra.end..][extra.data.body_len - 1];
2629 const operand: DocData.WalkResult = try self.walkRef(
2630 file,
2631 parent_scope,
2632 parent_src,
2633 data[body].@"break".operand,
2634 false,
2635 call_ctx,
2636 );
2637
2638 const operand_index = self.exprs.items.len;
2639 try self.exprs.append(self.arena, operand.expr);
2640
2641 return DocData.WalkResult{
2642 .typeRef = operand.typeRef,
2643 .expr = .{ .typeOf = operand_index },
2644 };
2645 },
2646 .as_node, .as_shift_operand => {
2647 const pl_node = data[@intFromEnum(inst)].pl_node;
2648 const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index);
2649
2650 // Skip the as_node if the destination type is a call instruction
2651 if (extra.data.dest_type.toIndex()) |dti| {
2652 var maybe_cc = call_ctx;
2653 while (maybe_cc) |cc| : (maybe_cc = cc.prev) {
2654 if (cc.inst == dti) {
2655 return try self.walkRef(
2656 file,
2657 parent_scope,
2658 parent_src,
2659 extra.data.operand,
2660 false,
2661 call_ctx,
2662 );
2663 }
2664 }
2665 }
2666
2667 const dest_type_walk = try self.walkRef(
2668 file,
2669 parent_scope,
2670 parent_src,
2671 extra.data.dest_type,
2672 false,
2673 call_ctx,
2674 );
2675
2676 const operand = try self.walkRef(
2677 file,
2678 parent_scope,
2679 parent_src,
2680 extra.data.operand,
2681 false,
2682 call_ctx,
2683 );
2684
2685 const operand_idx = self.exprs.items.len;
2686 try self.exprs.append(self.arena, operand.expr);
2687
2688 const dest_type_idx = self.exprs.items.len;
2689 try self.exprs.append(self.arena, dest_type_walk.expr);
2690
2691 // TODO: there's something wrong with how both `as` and `WalkrResult`
2692 // try to store type information.
2693 return DocData.WalkResult{
2694 .typeRef = dest_type_walk.expr,
2695 .expr = .{
2696 .as = .{
2697 .typeRefArg = dest_type_idx,
2698 .exprArg = operand_idx,
2699 },
2700 },
2701 };
2702 },
2703 .optional_type => {
2704 const un_node = data[@intFromEnum(inst)].un_node;
2705
2706 const operand: DocData.WalkResult = try self.walkRef(
2707 file,
2708 parent_scope,
2709 parent_src,
2710 un_node.operand,
2711 false,
2712 call_ctx,
2713 );
2714
2715 const operand_idx = self.types.items.len;
2716 try self.types.append(self.arena, .{
2717 .Optional = .{ .name = "?TODO", .child = operand.expr },
2718 });
2719
2720 return DocData.WalkResult{
2721 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2722 .expr = .{ .type = operand_idx },
2723 };
2724 },
2725 .decl_val, .decl_ref => {
2726 const str_tok = data[@intFromEnum(inst)].str_tok;
2727 const decl_status = parent_scope.resolveDeclName(str_tok.start, file, inst.toOptional());
2728 return DocData.WalkResult{
2729 .expr = .{ .declRef = decl_status },
2730 };
2731 },
2732 .field_val, .field_ptr => {
2733 const pl_node = data[@intFromEnum(inst)].pl_node;
2734 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
2735
2736 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
2737 try path.append(self.arena, .{
2738 .declName = file.zir.nullTerminatedString(extra.data.field_name_start),
2739 });
2740
2741 // Put inside path the starting index of each decl name that
2742 // we encounter as we navigate through all the field_*s
2743 const lhs_ref = blk: {
2744 var lhs_extra = extra;
2745 while (true) {
2746 const lhs = @intFromEnum(lhs_extra.data.lhs.toIndex() orelse {
2747 break :blk lhs_extra.data.lhs;
2748 });
2749
2750 if (tags[lhs] != .field_val and
2751 tags[lhs] != .field_ptr)
2752 {
2753 break :blk lhs_extra.data.lhs;
2754 }
2755
2756 lhs_extra = file.zir.extraData(
2757 Zir.Inst.Field,
2758 data[lhs].pl_node.payload_index,
2759 );
2760
2761 try path.append(self.arena, .{
2762 .declName = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
2763 });
2764 }
2765 };
2766
2767 // If the lhs is a `call` instruction, it means that we're inside
2768 // a function call and we're referring to one of its arguments.
2769 // We can't just blindly analyze the instruction or we will
2770 // start recursing forever.
2771 // TODO: add proper resolution of the container type for `calls`
2772 // TODO: we're like testing lhs as an instruction twice
2773 // (above and below) this todo, maybe a cleaer solution woul
2774 // avoid that.
2775 // TODO: double check that we really don't need type info here
2776
2777 const wr = blk: {
2778 if (lhs_ref.toIndex()) |lhs_inst| switch (tags[@intFromEnum(lhs_inst)]) {
2779 .call, .field_call => {
2780 break :blk DocData.WalkResult{
2781 .expr = .{
2782 .comptimeExpr = 0,
2783 },
2784 };
2785 },
2786 else => {},
2787 };
2788
2789 break :blk try self.walkRef(
2790 file,
2791 parent_scope,
2792 parent_src,
2793 lhs_ref,
2794 false,
2795 call_ctx,
2796 );
2797 };
2798 try path.append(self.arena, wr.expr);
2799
2800 // This way the data in `path` has the same ordering that the ref
2801 // path has in the text: most general component first.
2802 std.mem.reverse(DocData.Expr, path.items);
2803
2804 // Righ now, every element of `path` is a string except its first
2805 // element (at index 0). We're now going to attempt to resolve each
2806 // string. If one or more components in this path are not yet fully
2807 // analyzed, the path will only be solved partially, but we expect
2808 // to eventually solve it fully(or give up in case of a
2809 // comptimeExpr). This means that:
2810 // - (1) Paths can be not fully analyzed temporarily, so any code
2811 // that requires to know where a ref path leads to, neeeds to
2812 // implement support for lazyness (see self.pending_ref_paths)
2813 // - (2) Paths can sometimes never resolve fully. This means that
2814 // any value that depends on that will have to become a
2815 // comptimeExpr.
2816 try self.tryResolveRefPath(file, inst, path.items);
2817 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
2818 },
2819 .int_type => {
2820 const int_type = data[@intFromEnum(inst)].int_type;
2821 const sign = if (int_type.signedness == .unsigned) "u" else "i";
2822 const bits = int_type.bit_count;
2823 const name = try std.fmt.allocPrint(self.arena, "{s}{}", .{ sign, bits });
2824
2825 try self.types.append(self.arena, .{
2826 .Int = .{ .name = name },
2827 });
2828
2829 return DocData.WalkResult{
2830 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2831 .expr = .{ .type = self.types.items.len - 1 },
2832 };
2833 },
2834 .block => {
2835 const res = DocData.WalkResult{
2836 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2837 .expr = .{ .comptimeExpr = self.comptime_exprs.items.len },
2838 };
2839 const pl_node = data[@intFromEnum(inst)].pl_node;
2840 const block_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
2841 try self.comptime_exprs.append(self.arena, .{
2842 .code = block_expr,
2843 });
2844 return res;
2845 },
2846 .block_inline => {
2847 const pl_node = data[@intFromEnum(inst)].pl_node;
2848 const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
2849 return self.walkInlineBody(
2850 file,
2851 parent_scope,
2852 try self.srcLocInfo(file, pl_node.src_node, parent_src),
2853 parent_src,
2854 file.zir.bodySlice(extra.end, extra.data.body_len),
2855 need_type,
2856 call_ctx,
2857 );
2858 },
2859 .break_inline => {
2860 const @"break" = data[@intFromEnum(inst)].@"break";
2861 return try self.walkRef(
2862 file,
2863 parent_scope,
2864 parent_src,
2865 @"break".operand,
2866 need_type,
2867 call_ctx,
2868 );
2869 },
2870 .struct_init => {
2871 const pl_node = data[@intFromEnum(inst)].pl_node;
2872 const extra = file.zir.extraData(Zir.Inst.StructInit, pl_node.payload_index);
2873 const field_vals = try self.arena.alloc(
2874 DocData.Expr.FieldVal,
2875 extra.data.fields_len,
2876 );
2877
2878 var type_ref: DocData.Expr = undefined;
2879 var idx = extra.end;
2880 for (field_vals) |*fv| {
2881 const init_extra = file.zir.extraData(Zir.Inst.StructInit.Item, idx);
2882 defer idx = init_extra.end;
2883
2884 const field_name = blk: {
2885 const field_inst_index = @intFromEnum(init_extra.data.field_type);
2886 if (tags[field_inst_index] != .struct_init_field_type) unreachable;
2887 const field_pl_node = data[field_inst_index].pl_node;
2888 const field_extra = file.zir.extraData(
2889 Zir.Inst.FieldType,
2890 field_pl_node.payload_index,
2891 );
2892 const field_src = try self.srcLocInfo(
2893 file,
2894 field_pl_node.src_node,
2895 parent_src,
2896 );
2897
2898 // On first iteration use field info to find out the struct type
2899 if (idx == extra.end) {
2900 const wr = try self.walkRef(
2901 file,
2902 parent_scope,
2903 field_src,
2904 field_extra.data.container_type,
2905 false,
2906 call_ctx,
2907 );
2908 type_ref = wr.expr;
2909 }
2910 break :blk file.zir.nullTerminatedString(field_extra.data.name_start);
2911 };
2912 const value = try self.walkRef(
2913 file,
2914 parent_scope,
2915 parent_src,
2916 init_extra.data.init,
2917 need_type,
2918 call_ctx,
2919 );
2920 const exprIdx = self.exprs.items.len;
2921 try self.exprs.append(self.arena, value.expr);
2922 var typeRefIdx: ?usize = null;
2923 if (value.typeRef) |ref| {
2924 typeRefIdx = self.exprs.items.len;
2925 try self.exprs.append(self.arena, ref);
2926 }
2927 fv.* = .{
2928 .name = field_name,
2929 .val = .{
2930 .typeRef = typeRefIdx,
2931 .expr = exprIdx,
2932 },
2933 };
2934 }
2935
2936 return DocData.WalkResult{
2937 .typeRef = type_ref,
2938 .expr = .{ .@"struct" = field_vals },
2939 };
2940 },
2941 .struct_init_empty,
2942 .struct_init_empty_result,
2943 => {
2944 const un_node = data[@intFromEnum(inst)].un_node;
2945
2946 const operand: DocData.WalkResult = try self.walkRef(
2947 file,
2948 parent_scope,
2949 parent_src,
2950 un_node.operand,
2951 false,
2952 call_ctx,
2953 );
2954
2955 return DocData.WalkResult{
2956 .typeRef = operand.expr,
2957 .expr = .{ .@"struct" = &.{} },
2958 };
2959 },
2960 .struct_init_empty_ref_result => {
2961 const un_node = data[@intFromEnum(inst)].un_node;
2962
2963 const operand: DocData.WalkResult = try self.walkRef(
2964 file,
2965 parent_scope,
2966 parent_src,
2967 un_node.operand,
2968 false,
2969 call_ctx,
2970 );
2971
2972 const struct_init_idx = self.exprs.items.len;
2973 try self.exprs.append(self.arena, .{ .@"struct" = &.{} });
2974
2975 return DocData.WalkResult{
2976 .typeRef = operand.expr,
2977 .expr = .{ .@"&" = struct_init_idx },
2978 };
2979 },
2980 .struct_init_anon => {
2981 const pl_node = data[@intFromEnum(inst)].pl_node;
2982 const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
2983
2984 const field_vals = try self.arena.alloc(
2985 DocData.Expr.FieldVal,
2986 extra.data.fields_len,
2987 );
2988
2989 var idx = extra.end;
2990 for (field_vals) |*fv| {
2991 const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
2992 const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
2993 const value = try self.walkRef(
2994 file,
2995 parent_scope,
2996 parent_src,
2997 init_extra.data.init,
2998 need_type,
2999 call_ctx,
3000 );
3001
3002 const exprIdx = self.exprs.items.len;
3003 try self.exprs.append(self.arena, value.expr);
3004 var typeRefIdx: ?usize = null;
3005 if (value.typeRef) |ref| {
3006 typeRefIdx = self.exprs.items.len;
3007 try self.exprs.append(self.arena, ref);
3008 }
3009
3010 fv.* = .{
3011 .name = field_name,
3012 .val = .{
3013 .typeRef = typeRefIdx,
3014 .expr = exprIdx,
3015 },
3016 };
3017
3018 idx = init_extra.end;
3019 }
3020
3021 return DocData.WalkResult{
3022 .expr = .{ .@"struct" = field_vals },
3023 };
3024 },
3025 .error_set_decl => {
3026 const pl_node = data[@intFromEnum(inst)].pl_node;
3027 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
3028 const fields = try self.arena.alloc(
3029 DocData.Type.Field,
3030 extra.data.fields_len,
3031 );
3032 var idx = extra.end;
3033 for (fields) |*f| {
3034 const name = file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[idx]));
3035 idx += 1;
3036
3037 const docs = file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[idx]));
3038 idx += 1;
3039
3040 f.* = .{
3041 .name = name,
3042 .docs = docs,
3043 };
3044 }
3045
3046 const type_slot_index = self.types.items.len;
3047 try self.types.append(self.arena, .{
3048 .ErrorSet = .{
3049 .name = "todo errset",
3050 .fields = fields,
3051 },
3052 });
3053
3054 return DocData.WalkResult{
3055 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
3056 .expr = .{ .type = type_slot_index },
3057 };
3058 },
3059 .param_anytype, .param_anytype_comptime => {
3060 // @check if .param_anytype_comptime can be here
3061 // Analysis of anytype function params happens in `.func`.
3062 // This switch case handles the case where an expression depends
3063 // on an anytype field. E.g.: `fn foo(bar: anytype) @TypeOf(bar)`.
3064 // This means that we're looking at a generic expression.
3065 const str_tok = data[@intFromEnum(inst)].str_tok;
3066 const name = str_tok.get(file.zir);
3067 const cte_slot_index = self.comptime_exprs.items.len;
3068 try self.comptime_exprs.append(self.arena, .{
3069 .code = name,
3070 });
3071 return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
3072 },
3073 .param, .param_comptime => {
3074 // See .param_anytype for more information.
3075 const pl_tok = data[@intFromEnum(inst)].pl_tok;
3076 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
3077 const name = file.zir.nullTerminatedString(extra.data.name);
3078
3079 const cte_slot_index = self.comptime_exprs.items.len;
3080 try self.comptime_exprs.append(self.arena, .{
3081 .code = name,
3082 });
3083 return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
3084 },
3085 .call => {
3086 const pl_node = data[@intFromEnum(inst)].pl_node;
3087 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
3088
3089 const callee = try self.walkRef(
3090 file,
3091 parent_scope,
3092 parent_src,
3093 extra.data.callee,
3094 need_type,
3095 call_ctx,
3096 );
3097
3098 const args_len = extra.data.flags.args_len;
3099 var args = try self.arena.alloc(DocData.Expr, args_len);
3100 const body = file.zir.extra[extra.end..];
3101
3102 try self.repurposed_insts.put(self.arena, inst, {});
3103 defer _ = self.repurposed_insts.remove(inst);
3104
3105 var i: usize = 0;
3106 while (i < args_len) : (i += 1) {
3107 const arg_end = file.zir.extra[extra.end + i];
3108 const break_index = body[arg_end - 1];
3109 const ref = data[break_index].@"break".operand;
3110 // TODO: consider toggling need_type to true if we ever want
3111 // to show discrepancies between the types of provided
3112 // arguments and the types declared in the function
3113 // signature for its parameters.
3114 const wr = try self.walkRef(
3115 file,
3116 parent_scope,
3117 parent_src,
3118 ref,
3119 false,
3120 &.{
3121 .inst = inst,
3122 .prev = call_ctx,
3123 },
3124 );
3125 args[i] = wr.expr;
3126 }
3127
3128 const cte_slot_index = self.comptime_exprs.items.len;
3129 try self.comptime_exprs.append(self.arena, .{
3130 .code = "func call",
3131 });
3132
3133 const call_slot_index = self.calls.items.len;
3134 try self.calls.append(self.arena, .{
3135 .func = callee.expr,
3136 .args = args,
3137 .ret = .{ .comptimeExpr = cte_slot_index },
3138 });
3139
3140 return DocData.WalkResult{
3141 .typeRef = if (callee.typeRef) |tr| switch (tr) {
3142 .type => |func_type_idx| switch (self.types.items[func_type_idx]) {
3143 .Fn => |func| func.ret,
3144 else => blk: {
3145 printWithContext(
3146 file,
3147 inst,
3148 "unexpected callee type in walkInstruction.call: `{s}`\n",
3149 .{@tagName(self.types.items[func_type_idx])},
3150 );
3151
3152 break :blk null;
3153 },
3154 },
3155 else => null,
3156 } else null,
3157 .expr = .{ .call = call_slot_index },
3158 };
3159 },
3160 .field_call => {
3161 const pl_node = data[@intFromEnum(inst)].pl_node;
3162 const extra = file.zir.extraData(Zir.Inst.FieldCall, pl_node.payload_index);
3163
3164 const obj_ptr = try self.walkRef(
3165 file,
3166 parent_scope,
3167 parent_src,
3168 extra.data.obj_ptr,
3169 need_type,
3170 call_ctx,
3171 );
3172
3173 var field_call = try self.arena.alloc(DocData.Expr, 2);
3174
3175 if (obj_ptr.typeRef) |ref| {
3176 field_call[0] = ref;
3177 } else {
3178 field_call[0] = obj_ptr.expr;
3179 }
3180 field_call[1] = .{ .declName = file.zir.nullTerminatedString(extra.data.field_name_start) };
3181 try self.tryResolveRefPath(file, inst, field_call);
3182
3183 const args_len = extra.data.flags.args_len;
3184 var args = try self.arena.alloc(DocData.Expr, args_len);
3185 const body = file.zir.extra[extra.end..];
3186
3187 try self.repurposed_insts.put(self.arena, inst, {});
3188 defer _ = self.repurposed_insts.remove(inst);
3189
3190 var i: usize = 0;
3191 while (i < args_len) : (i += 1) {
3192 const arg_end = file.zir.extra[extra.end + i];
3193 const break_index = body[arg_end - 1];
3194 const ref = data[break_index].@"break".operand;
3195 // TODO: consider toggling need_type to true if we ever want
3196 // to show discrepancies between the types of provided
3197 // arguments and the types declared in the function
3198 // signature for its parameters.
3199 const wr = try self.walkRef(
3200 file,
3201 parent_scope,
3202 parent_src,
3203 ref,
3204 false,
3205 &.{
3206 .inst = inst,
3207 .prev = call_ctx,
3208 },
3209 );
3210 args[i] = wr.expr;
3211 }
3212
3213 const cte_slot_index = self.comptime_exprs.items.len;
3214 try self.comptime_exprs.append(self.arena, .{
3215 .code = "field call",
3216 });
3217
3218 const call_slot_index = self.calls.items.len;
3219 try self.calls.append(self.arena, .{
3220 .func = .{ .refPath = field_call },
3221 .args = args,
3222 .ret = .{ .comptimeExpr = cte_slot_index },
3223 });
3224
3225 return DocData.WalkResult{
3226 .expr = .{ .call = call_slot_index },
3227 };
3228 },
3229 .func, .func_inferred => {
3230 const type_slot_index = self.types.items.len;
3231 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
3232
3233 const result = self.analyzeFunction(
3234 file,
3235 parent_scope,
3236 parent_src,
3237 inst,
3238 self_ast_node_index,
3239 type_slot_index,
3240 tags[@intFromEnum(inst)] == .func_inferred,
3241 call_ctx,
3242 );
3243
3244 return result;
3245 },
3246 .func_fancy => {
3247 const type_slot_index = self.types.items.len;
3248 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
3249
3250 const result = self.analyzeFancyFunction(
3251 file,
3252 parent_scope,
3253 parent_src,
3254 inst,
3255 self_ast_node_index,
3256 type_slot_index,
3257 call_ctx,
3258 );
3259
3260 return result;
3261 },
3262 .optional_payload_safe, .optional_payload_unsafe => {
3263 const un_node = data[@intFromEnum(inst)].un_node;
3264 const operand = try self.walkRef(
3265 file,
3266 parent_scope,
3267 parent_src,
3268 un_node.operand,
3269 need_type,
3270 call_ctx,
3271 );
3272 const optional_idx = self.exprs.items.len;
3273 try self.exprs.append(self.arena, operand.expr);
3274
3275 var typeRef: ?DocData.Expr = null;
3276 if (operand.typeRef) |ref| {
3277 switch (ref) {
3278 .type => |t_index| {
3279 const t = self.types.items[t_index];
3280 switch (t) {
3281 .Optional => |opt| typeRef = opt.child,
3282 else => {
3283 printWithContext(file, inst, "Invalid type for optional_payload_*: {}\n", .{t});
3284 },
3285 }
3286 },
3287 else => {},
3288 }
3289 }
3290
3291 return DocData.WalkResult{
3292 .typeRef = typeRef,
3293 .expr = .{ .optionalPayload = optional_idx },
3294 };
3295 },
3296 .elem_val_node => {
3297 const pl_node = data[@intFromEnum(inst)].pl_node;
3298 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
3299 const lhs = try self.walkRef(
3300 file,
3301 parent_scope,
3302 parent_src,
3303 extra.data.lhs,
3304 need_type,
3305 call_ctx,
3306 );
3307 const rhs = try self.walkRef(
3308 file,
3309 parent_scope,
3310 parent_src,
3311 extra.data.rhs,
3312 need_type,
3313 call_ctx,
3314 );
3315 const lhs_idx = self.exprs.items.len;
3316 try self.exprs.append(self.arena, lhs.expr);
3317 const rhs_idx = self.exprs.items.len;
3318 try self.exprs.append(self.arena, rhs.expr);
3319 return DocData.WalkResult{
3320 .expr = .{
3321 .elemVal = .{
3322 .lhs = lhs_idx,
3323 .rhs = rhs_idx,
3324 },
3325 },
3326 };
3327 },
3328 .extended => {
3329 const extended = data[@intFromEnum(inst)].extended;
3330 switch (extended.opcode) {
3331 else => {
3332 printWithContext(
3333 file,
3334 inst,
3335 "TODO: implement `walkInstruction.extended` for {s}",
3336 .{@tagName(extended.opcode)},
3337 );
3338 return self.cteTodo(@tagName(extended.opcode));
3339 },
3340 .typeof_peer => {
3341 // Zir says it's a NodeMultiOp but in this case it's TypeOfPeer
3342 const extra = file.zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
3343 const args = file.zir.refSlice(extra.end, extended.small);
3344 const array_data = try self.arena.alloc(usize, args.len);
3345
3346 var array_type: ?DocData.Expr = null;
3347 for (args, 0..) |arg, idx| {
3348 const wr = try self.walkRef(
3349 file,
3350 parent_scope,
3351 parent_src,
3352 arg,
3353 idx == 0,
3354 call_ctx,
3355 );
3356 if (idx == 0) {
3357 array_type = wr.typeRef;
3358 }
3359
3360 const expr_index = self.exprs.items.len;
3361 try self.exprs.append(self.arena, wr.expr);
3362 array_data[idx] = expr_index;
3363 }
3364
3365 const type_slot_index = self.types.items.len;
3366 try self.types.append(self.arena, .{
3367 .Array = .{
3368 .len = .{
3369 .int = .{
3370 .value = args.len,
3371 .negated = false,
3372 },
3373 },
3374 .child = .{ .type = 0 },
3375 },
3376 });
3377 const result = DocData.WalkResult{
3378 .typeRef = .{ .type = type_slot_index },
3379 .expr = .{ .typeOf_peer = array_data },
3380 };
3381
3382 return result;
3383 },
3384 .opaque_decl => {
3385 const type_slot_index = self.types.items.len;
3386 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
3387
3388 var scope: Scope = .{
3389 .parent = parent_scope,
3390 .enclosing_type = type_slot_index,
3391 };
3392
3393 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
3394 const extra = file.zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
3395 var extra_index: usize = extra.end;
3396
3397 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
3398
3399 const captures_len = if (small.has_captures_len) blk: {
3400 const captures_len = file.zir.extra[extra_index];
3401 extra_index += 1;
3402 break :blk captures_len;
3403 } else 0;
3404
3405 if (small.has_decls_len) extra_index += 1;
3406
3407 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3408 extra_index += captures_len;
3409
3410 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3411 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3412
3413 extra_index = try self.analyzeAllDecls(
3414 file,
3415 &scope,
3416 inst,
3417 src_info,
3418 &decl_indexes,
3419 &priv_decl_indexes,
3420 call_ctx,
3421 );
3422
3423 self.types.items[type_slot_index] = .{
3424 .Opaque = .{
3425 .name = "todo_name",
3426 .src = self_ast_node_index,
3427 .privDecls = priv_decl_indexes.items,
3428 .pubDecls = decl_indexes.items,
3429 .parent_container = parent_scope.enclosing_type,
3430 },
3431 };
3432 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
3433 for (paths.items) |resume_info| {
3434 try self.tryResolveRefPath(
3435 resume_info.file,
3436 inst,
3437 resume_info.ref_path,
3438 );
3439 }
3440
3441 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
3442 // TODO: we should deallocate the arraylist that holds all the
3443 // decl paths. not doing it now since it's arena-allocated
3444 // anyway, but maybe we should put it elsewhere.
3445 }
3446 return DocData.WalkResult{
3447 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
3448 .expr = .{ .type = type_slot_index },
3449 };
3450 },
3451 .variable => {
3452 const extra = file.zir.extraData(Zir.Inst.ExtendedVar, extended.operand);
3453
3454 const small = @as(Zir.Inst.ExtendedVar.Small, @bitCast(extended.small));
3455 var extra_index: usize = extra.end;
3456 if (small.has_lib_name) extra_index += 1;
3457 if (small.has_align) extra_index += 1;
3458
3459 const var_type = try self.walkRef(
3460 file,
3461 parent_scope,
3462 parent_src,
3463 extra.data.var_type,
3464 need_type,
3465 call_ctx,
3466 );
3467
3468 var value: DocData.WalkResult = .{
3469 .typeRef = var_type.expr,
3470 .expr = .{ .undefined = .{} },
3471 };
3472
3473 if (small.has_init) {
3474 const var_init_ref = @as(Ref, @enumFromInt(file.zir.extra[extra_index]));
3475 const var_init = try self.walkRef(
3476 file,
3477 parent_scope,
3478 parent_src,
3479 var_init_ref,
3480 need_type,
3481 call_ctx,
3482 );
3483 value.expr = var_init.expr;
3484 value.typeRef = var_init.typeRef;
3485 }
3486
3487 return value;
3488 },
3489 .union_decl => {
3490 const type_slot_index = self.types.items.len;
3491 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
3492
3493 var scope: Scope = .{
3494 .parent = parent_scope,
3495 .enclosing_type = type_slot_index,
3496 };
3497
3498 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
3499 const extra = file.zir.extraData(Zir.Inst.UnionDecl, extended.operand);
3500 var extra_index: usize = extra.end;
3501
3502 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
3503
3504 // We delay analysis because union tags can refer to
3505 // decls defined inside the union itself.
3506 const tag_type_ref: ?Ref = if (small.has_tag_type) blk: {
3507 const tag_type = file.zir.extra[extra_index];
3508 extra_index += 1;
3509 const tag_ref = @as(Ref, @enumFromInt(tag_type));
3510 break :blk tag_ref;
3511 } else null;
3512
3513 const captures_len = if (small.has_captures_len) blk: {
3514 const captures_len = file.zir.extra[extra_index];
3515 extra_index += 1;
3516 break :blk captures_len;
3517 } else 0;
3518
3519 const body_len = if (small.has_body_len) blk: {
3520 const body_len = file.zir.extra[extra_index];
3521 extra_index += 1;
3522 break :blk body_len;
3523 } else 0;
3524
3525 const fields_len = if (small.has_fields_len) blk: {
3526 const fields_len = file.zir.extra[extra_index];
3527 extra_index += 1;
3528 break :blk fields_len;
3529 } else 0;
3530
3531 const layout_expr: ?DocData.Expr = switch (small.layout) {
3532 .Auto => null,
3533 else => .{ .enumLiteral = @tagName(small.layout) },
3534 };
3535
3536 if (small.has_decls_len) extra_index += 1;
3537
3538 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3539 extra_index += captures_len;
3540
3541 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3542 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3543
3544 extra_index = try self.analyzeAllDecls(
3545 file,
3546 &scope,
3547 inst,
3548 src_info,
3549 &decl_indexes,
3550 &priv_decl_indexes,
3551 call_ctx,
3552 );
3553
3554 // Analyze the tag once all decls have been analyzed
3555 const tag_type = if (tag_type_ref) |tt_ref| (try self.walkRef(
3556 file,
3557 &scope,
3558 parent_src,
3559 tt_ref,
3560 false,
3561 call_ctx,
3562 )).expr else null;
3563
3564 // Fields
3565 extra_index += body_len;
3566
3567 var field_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
3568 self.arena,
3569 fields_len,
3570 );
3571 var field_name_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
3572 self.arena,
3573 fields_len,
3574 );
3575 try self.collectUnionFieldInfo(
3576 file,
3577 &scope,
3578 src_info,
3579 fields_len,
3580 &field_type_refs,
3581 &field_name_indexes,
3582 extra_index,
3583 call_ctx,
3584 );
3585
3586 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
3587
3588 self.types.items[type_slot_index] = .{
3589 .Union = .{
3590 .name = "todo_name",
3591 .src = self_ast_node_index,
3592 .privDecls = priv_decl_indexes.items,
3593 .pubDecls = decl_indexes.items,
3594 .fields = field_type_refs.items,
3595 .tag = tag_type,
3596 .auto_enum = small.auto_enum_tag,
3597 .parent_container = parent_scope.enclosing_type,
3598 .layout = layout_expr,
3599 },
3600 };
3601
3602 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
3603 for (paths.items) |resume_info| {
3604 try self.tryResolveRefPath(
3605 resume_info.file,
3606 inst,
3607 resume_info.ref_path,
3608 );
3609 }
3610
3611 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
3612 // TODO: we should deallocate the arraylist that holds all the
3613 // decl paths. not doing it now since it's arena-allocated
3614 // anyway, but maybe we should put it elsewhere.
3615 }
3616
3617 return DocData.WalkResult{
3618 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
3619 .expr = .{ .type = type_slot_index },
3620 };
3621 },
3622 .enum_decl => {
3623 const type_slot_index = self.types.items.len;
3624 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
3625
3626 var scope: Scope = .{
3627 .parent = parent_scope,
3628 .enclosing_type = type_slot_index,
3629 };
3630
3631 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
3632 const extra = file.zir.extraData(Zir.Inst.EnumDecl, extended.operand);
3633 var extra_index: usize = extra.end;
3634
3635 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
3636
3637 const tag_type: ?DocData.Expr = if (small.has_tag_type) blk: {
3638 const tag_type = file.zir.extra[extra_index];
3639 extra_index += 1;
3640 const tag_ref = @as(Ref, @enumFromInt(tag_type));
3641 const wr = try self.walkRef(
3642 file,
3643 parent_scope,
3644 parent_src,
3645 tag_ref,
3646 false,
3647 call_ctx,
3648 );
3649 break :blk wr.expr;
3650 } else null;
3651
3652 const captures_len = if (small.has_captures_len) blk: {
3653 const captures_len = file.zir.extra[extra_index];
3654 extra_index += 1;
3655 break :blk captures_len;
3656 } else 0;
3657
3658 const body_len = if (small.has_body_len) blk: {
3659 const body_len = file.zir.extra[extra_index];
3660 extra_index += 1;
3661 break :blk body_len;
3662 } else 0;
3663
3664 const fields_len = if (small.has_fields_len) blk: {
3665 const fields_len = file.zir.extra[extra_index];
3666 extra_index += 1;
3667 break :blk fields_len;
3668 } else 0;
3669
3670 if (small.has_decls_len) extra_index += 1;
3671
3672 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3673 extra_index += captures_len;
3674
3675 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3676 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3677
3678 extra_index = try self.analyzeAllDecls(
3679 file,
3680 &scope,
3681 inst,
3682 src_info,
3683 &decl_indexes,
3684 &priv_decl_indexes,
3685 call_ctx,
3686 );
3687
3688 // const body = file.zir.extra[extra_index..][0..body_len];
3689 extra_index += body_len;
3690
3691 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
3692 var field_values: std.ArrayListUnmanaged(?DocData.Expr) = .{};
3693 {
3694 var bit_bag_idx = extra_index;
3695 var cur_bit_bag: u32 = undefined;
3696 extra_index += std.math.divCeil(usize, fields_len, 32) catch unreachable;
3697
3698 var idx: usize = 0;
3699 while (idx < fields_len) : (idx += 1) {
3700 if (idx % 32 == 0) {
3701 cur_bit_bag = file.zir.extra[bit_bag_idx];
3702 bit_bag_idx += 1;
3703 }
3704
3705 const has_value = @as(u1, @truncate(cur_bit_bag)) != 0;
3706 cur_bit_bag >>= 1;
3707
3708 const field_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
3709 extra_index += 1;
3710
3711 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
3712 extra_index += 1;
3713
3714 const value_expr: ?DocData.Expr = if (has_value) blk: {
3715 const value_ref = file.zir.extra[extra_index];
3716 extra_index += 1;
3717 const value = try self.walkRef(
3718 file,
3719 &scope,
3720 src_info,
3721 @as(Ref, @enumFromInt(value_ref)),
3722 false,
3723 call_ctx,
3724 );
3725 break :blk value.expr;
3726 } else null;
3727 try field_values.append(self.arena, value_expr);
3728
3729 const field_name = file.zir.nullTerminatedString(field_name_index);
3730
3731 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
3732 const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
3733 file.zir.nullTerminatedString(doc_comment_index)
3734 else
3735 null;
3736 try self.ast_nodes.append(self.arena, .{
3737 .name = field_name,
3738 .docs = doc_comment,
3739 });
3740 }
3741 }
3742
3743 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
3744
3745 self.types.items[type_slot_index] = .{
3746 .Enum = .{
3747 .name = "todo_name",
3748 .src = self_ast_node_index,
3749 .privDecls = priv_decl_indexes.items,
3750 .pubDecls = decl_indexes.items,
3751 .tag = tag_type,
3752 .values = field_values.items,
3753 .nonexhaustive = small.nonexhaustive,
3754 .parent_container = parent_scope.enclosing_type,
3755 },
3756 };
3757 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
3758 for (paths.items) |resume_info| {
3759 try self.tryResolveRefPath(
3760 resume_info.file,
3761 inst,
3762 resume_info.ref_path,
3763 );
3764 }
3765
3766 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
3767 // TODO: we should deallocate the arraylist that holds all the
3768 // decl paths. not doing it now since it's arena-allocated
3769 // anyway, but maybe we should put it elsewhere.
3770 }
3771 return DocData.WalkResult{
3772 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
3773 .expr = .{ .type = type_slot_index },
3774 };
3775 },
3776 .struct_decl => {
3777 const type_slot_index = self.types.items.len;
3778 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
3779
3780 var scope: Scope = .{
3781 .parent = parent_scope,
3782 .enclosing_type = type_slot_index,
3783 };
3784
3785 const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));
3786 const extra = file.zir.extraData(Zir.Inst.StructDecl, extended.operand);
3787 var extra_index: usize = extra.end;
3788
3789 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
3790
3791 const captures_len = if (small.has_captures_len) blk: {
3792 const captures_len = file.zir.extra[extra_index];
3793 extra_index += 1;
3794 break :blk captures_len;
3795 } else 0;
3796
3797 const fields_len = if (small.has_fields_len) blk: {
3798 const fields_len = file.zir.extra[extra_index];
3799 extra_index += 1;
3800 break :blk fields_len;
3801 } else 0;
3802
3803 // We don't care about decls yet
3804 if (small.has_decls_len) extra_index += 1;
3805
3806 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3807 extra_index += captures_len;
3808
3809 var backing_int: ?DocData.Expr = null;
3810 if (small.has_backing_int) {
3811 const backing_int_body_len = file.zir.extra[extra_index];
3812 extra_index += 1; // backing_int_body_len
3813 if (backing_int_body_len == 0) {
3814 const backing_int_ref = @as(Ref, @enumFromInt(file.zir.extra[extra_index]));
3815 const backing_int_res = try self.walkRef(
3816 file,
3817 &scope,
3818 src_info,
3819 backing_int_ref,
3820 true,
3821 call_ctx,
3822 );
3823 backing_int = backing_int_res.expr;
3824 extra_index += 1; // backing_int_ref
3825 } else {
3826 const backing_int_body = file.zir.bodySlice(extra_index, backing_int_body_len);
3827 const break_inst = backing_int_body[backing_int_body.len - 1];
3828 const operand = data[@intFromEnum(break_inst)].@"break".operand;
3829 const backing_int_res = try self.walkRef(
3830 file,
3831 &scope,
3832 src_info,
3833 operand,
3834 true,
3835 call_ctx,
3836 );
3837 backing_int = backing_int_res.expr;
3838 extra_index += backing_int_body_len; // backing_int_body_inst
3839 }
3840 }
3841
3842 const layout_expr: ?DocData.Expr = switch (small.layout) {
3843 .Auto => null,
3844 else => .{ .enumLiteral = @tagName(small.layout) },
3845 };
3846
3847 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3848 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3849
3850 extra_index = try self.analyzeAllDecls(
3851 file,
3852 &scope,
3853 inst,
3854 src_info,
3855 &decl_indexes,
3856 &priv_decl_indexes,
3857 call_ctx,
3858 );
3859
3860 // Inside field init bodies, the struct decl instruction is used to refer to the
3861 // field type during the second pass of analysis.
3862 try self.repurposed_insts.put(self.arena, inst, {});
3863 defer _ = self.repurposed_insts.remove(inst);
3864
3865 var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{};
3866 var field_default_refs: std.ArrayListUnmanaged(?DocData.Expr) = .{};
3867 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
3868 try self.collectStructFieldInfo(
3869 file,
3870 &scope,
3871 src_info,
3872 fields_len,
3873 &field_type_refs,
3874 &field_default_refs,
3875 &field_name_indexes,
3876 extra_index,
3877 small.is_tuple,
3878 call_ctx,
3879 );
3880
3881 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
3882
3883 self.types.items[type_slot_index] = .{
3884 .Struct = .{
3885 .name = "todo_name",
3886 .src = self_ast_node_index,
3887 .privDecls = priv_decl_indexes.items,
3888 .pubDecls = decl_indexes.items,
3889 .field_types = field_type_refs.items,
3890 .field_defaults = field_default_refs.items,
3891 .is_tuple = small.is_tuple,
3892 .backing_int = backing_int,
3893 .line_number = self.ast_nodes.items[self_ast_node_index].line,
3894 .parent_container = parent_scope.enclosing_type,
3895 .layout = layout_expr,
3896 },
3897 };
3898 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
3899 for (paths.items) |resume_info| {
3900 try self.tryResolveRefPath(
3901 resume_info.file,
3902 inst,
3903 resume_info.ref_path,
3904 );
3905 }
3906
3907 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
3908 // TODO: we should deallocate the arraylist that holds all the
3909 // decl paths. not doing it now since it's arena-allocated
3910 // anyway, but maybe we should put it elsewhere.
3911 }
3912 return DocData.WalkResult{
3913 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
3914 .expr = .{ .type = type_slot_index },
3915 };
3916 },
3917 .this => {
3918 return DocData.WalkResult{
3919 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
3920 .expr = .{
3921 .this = parent_scope.enclosing_type.?,
3922 // We know enclosing_type is always present
3923 // because it's only null for the top-level
3924 // struct instruction of a file.
3925 },
3926 };
3927 },
3928 .int_from_error,
3929 .error_from_int,
3930 .reify,
3931 => {
3932 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
3933 const bin_index = self.exprs.items.len;
3934 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
3935 const param = try self.walkRef(
3936 file,
3937 parent_scope,
3938 parent_src,
3939 extra.operand,
3940 false,
3941 call_ctx,
3942 );
3943
3944 const param_index = self.exprs.items.len;
3945 try self.exprs.append(self.arena, param.expr);
3946
3947 self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(extended.opcode), .param = param_index } };
3948
3949 return DocData.WalkResult{
3950 .typeRef = param.typeRef orelse .{ .type = @intFromEnum(Ref.type_type) },
3951 .expr = .{ .builtinIndex = bin_index },
3952 };
3953 },
3954 .work_item_id,
3955 .work_group_size,
3956 .work_group_id,
3957 => {
3958 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
3959 const bin_index = self.exprs.items.len;
3960 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
3961 const param = try self.walkRef(
3962 file,
3963 parent_scope,
3964 parent_src,
3965 extra.operand,
3966 false,
3967 call_ctx,
3968 );
3969
3970 const param_index = self.exprs.items.len;
3971 try self.exprs.append(self.arena, param.expr);
3972
3973 self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(extended.opcode), .param = param_index } };
3974
3975 return DocData.WalkResult{
3976 // from docs we know they return u32
3977 .typeRef = .{ .type = @intFromEnum(Ref.u32_type) },
3978 .expr = .{ .builtinIndex = bin_index },
3979 };
3980 },
3981 .cmpxchg => {
3982 const extra = file.zir.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
3983
3984 const last_type_index = self.exprs.items.len;
3985 const last_type = self.exprs.items[last_type_index - 1];
3986 const type_index = self.exprs.items.len;
3987 try self.exprs.append(self.arena, last_type);
3988
3989 const ptr_index = self.exprs.items.len;
3990 const ptr: DocData.WalkResult = try self.walkRef(
3991 file,
3992 parent_scope,
3993 parent_src,
3994 extra.ptr,
3995 false,
3996 call_ctx,
3997 );
3998 try self.exprs.append(self.arena, ptr.expr);
3999
4000 const expected_value_index = self.exprs.items.len;
4001 const expected_value: DocData.WalkResult = try self.walkRef(
4002 file,
4003 parent_scope,
4004 parent_src,
4005 extra.expected_value,
4006 false,
4007 call_ctx,
4008 );
4009 try self.exprs.append(self.arena, expected_value.expr);
4010
4011 const new_value_index = self.exprs.items.len;
4012 const new_value: DocData.WalkResult = try self.walkRef(
4013 file,
4014 parent_scope,
4015 parent_src,
4016 extra.new_value,
4017 false,
4018 call_ctx,
4019 );
4020 try self.exprs.append(self.arena, new_value.expr);
4021
4022 const success_order_index = self.exprs.items.len;
4023 const success_order: DocData.WalkResult = try self.walkRef(
4024 file,
4025 parent_scope,
4026 parent_src,
4027 extra.success_order,
4028 false,
4029 call_ctx,
4030 );
4031 try self.exprs.append(self.arena, success_order.expr);
4032
4033 const failure_order_index = self.exprs.items.len;
4034 const failure_order: DocData.WalkResult = try self.walkRef(
4035 file,
4036 parent_scope,
4037 parent_src,
4038 extra.failure_order,
4039 false,
4040 call_ctx,
4041 );
4042 try self.exprs.append(self.arena, failure_order.expr);
4043
4044 const cmpxchg_index = self.exprs.items.len;
4045 try self.exprs.append(self.arena, .{ .cmpxchg = .{
4046 .name = @tagName(tags[@intFromEnum(inst)]),
4047 .type = type_index,
4048 .ptr = ptr_index,
4049 .expected_value = expected_value_index,
4050 .new_value = new_value_index,
4051 .success_order = success_order_index,
4052 .failure_order = failure_order_index,
4053 } });
4054 return DocData.WalkResult{
4055 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
4056 .expr = .{ .cmpxchgIndex = cmpxchg_index },
4057 };
4058 },
4059 .closure_get => {
4060 const captured, const scope = parent_scope.getCapture(extended.small);
4061 switch (captured) {
4062 .inst => |cap_inst| return self.walkInstruction(file, scope, parent_src, cap_inst, need_type, call_ctx),
4063 .decl => |str| {
4064 const decl_status = parent_scope.resolveDeclName(str, file, inst.toOptional());
4065 return .{ .expr = .{ .declRef = decl_status } };
4066 },
4067 }
4068 },
4069 }
4070 },
4071 }
4072}
4073
4074/// Called by `walkInstruction` when encountering a container type.
4075/// Iterates over all decl definitions in its body and it also analyzes each
4076/// decl's body recursively by calling into `walkInstruction`.
4077///
4078/// Does not append to `self.decls` directly because `walkInstruction`
4079/// is expected to look-ahead scan all decls and reserve `body_len`
4080/// slots in `self.decls`, which are then filled out by this function.
4081fn analyzeAllDecls(
4082 self: *Autodoc,
4083 file: *File,
4084 scope: *Scope,
4085 parent_inst: Zir.Inst.Index,
4086 parent_src: SrcLocInfo,
4087 decl_indexes: *std.ArrayListUnmanaged(usize),
4088 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4089 call_ctx: ?*const CallContext,
4090) AutodocErrors!usize {
4091 const first_decl_indexes_slot = decl_indexes.items.len;
4092 const original_it = file.zir.declIterator(parent_inst);
4093
4094 // First loop to discover decl names
4095 {
4096 var it = original_it;
4097 while (it.next()) |zir_index| {
4098 const declaration, _ = file.zir.getDeclaration(zir_index);
4099 if (declaration.name.isNamedTest(file.zir)) continue;
4100 const decl_name = declaration.name.toString(file.zir) orelse continue;
4101 try scope.insertDeclRef(self.arena, decl_name, .Pending);
4102 }
4103 }
4104
4105 // Second loop to analyze `usingnamespace` decls
4106 {
4107 var it = original_it;
4108 var decl_indexes_slot = first_decl_indexes_slot;
4109 while (it.next()) |zir_index| : (decl_indexes_slot += 1) {
4110 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4111 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4112 if (extra.data.name != .@"usingnamespace") continue;
4113 try self.analyzeUsingnamespaceDecl(
4114 file,
4115 scope,
4116 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4117 decl_indexes,
4118 priv_decl_indexes,
4119 extra.data,
4120 @intCast(extra.end),
4121 call_ctx,
4122 );
4123 }
4124 }
4125
4126 // Third loop to analyze all remaining decls
4127 {
4128 var it = original_it;
4129 while (it.next()) |zir_index| {
4130 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4131 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4132 switch (extra.data.name) {
4133 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
4134 _ => if (extra.data.name.isNamedTest(file.zir)) continue,
4135 }
4136 try self.analyzeDecl(
4137 file,
4138 scope,
4139 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4140 decl_indexes,
4141 priv_decl_indexes,
4142 zir_index,
4143 extra.data,
4144 @intCast(extra.end),
4145 call_ctx,
4146 );
4147 }
4148 }
4149
4150 // Fourth loop to analyze decltests
4151 var it = original_it;
4152 while (it.next()) |zir_index| {
4153 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4154 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4155 if (extra.data.name != .decltest) continue;
4156 try self.analyzeDecltest(
4157 file,
4158 scope,
4159 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4160 extra.data,
4161 @intCast(extra.end),
4162 );
4163 }
4164
4165 return it.extra_index;
4166}
4167
4168fn walkInlineBody(
4169 autodoc: *Autodoc,
4170 file: *File,
4171 scope: *Scope,
4172 block_src: SrcLocInfo,
4173 parent_src: SrcLocInfo,
4174 body: []const Zir.Inst.Index,
4175 need_type: bool,
4176 call_ctx: ?*const CallContext,
4177) AutodocErrors!DocData.WalkResult {
4178 const tags = file.zir.instructions.items(.tag);
4179 const break_inst = switch (tags[@intFromEnum(body[body.len - 1])]) {
4180 .condbr_inline => {
4181 // Unresolvable.
4182 const res: DocData.WalkResult = .{
4183 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
4184 .expr = .{ .comptimeExpr = autodoc.comptime_exprs.items.len },
4185 };
4186 const source = (try file.getTree(autodoc.zcu.gpa)).getNodeSource(block_src.src_node);
4187 try autodoc.comptime_exprs.append(autodoc.arena, .{
4188 .code = source,
4189 });
4190 return res;
4191 },
4192 .break_inline => body[body.len - 1],
4193 else => unreachable,
4194 };
4195 const break_data = file.zir.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
4196 return autodoc.walkRef(file, scope, parent_src, break_data.operand, need_type, call_ctx);
4197}
4198
4199// Asserts the given decl is public
4200fn analyzeDecl(
4201 self: *Autodoc,
4202 file: *File,
4203 scope: *Scope,
4204 decl_src: SrcLocInfo,
4205 decl_indexes: *std.ArrayListUnmanaged(usize),
4206 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4207 decl_inst: Zir.Inst.Index,
4208 declaration: Zir.Inst.Declaration,
4209 extra_index: u32,
4210 call_ctx: ?*const CallContext,
4211) AutodocErrors!void {
4212 const bodies = declaration.getBodies(extra_index, file.zir);
4213 const name = file.zir.nullTerminatedString(declaration.name.toString(file.zir).?);
4214
4215 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4216 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
4217 else
4218 null;
4219
4220 // astnode
4221 const ast_node_index = idx: {
4222 const idx = self.ast_nodes.items.len;
4223 try self.ast_nodes.append(self.arena, .{
4224 .file = self.files.getIndex(file).?,
4225 .line = decl_src.line,
4226 .col = 0,
4227 .docs = doc_comment,
4228 .fields = null, // walkInstruction will fill `fields` if necessary
4229 });
4230 break :idx idx;
4231 };
4232
4233 const walk_result = try self.walkInlineBody(
4234 file,
4235 scope,
4236 decl_src,
4237 decl_src,
4238 bodies.value_body,
4239 true,
4240 call_ctx,
4241 );
4242
4243 const tree = try file.getTree(self.zcu.gpa);
4244 const kind_token = tree.nodes.items(.main_token)[decl_src.src_node];
4245 const kind: []const u8 = switch (tree.tokens.items(.tag)[kind_token]) {
4246 .keyword_var => "var",
4247 else => "const",
4248 };
4249
4250 const decls_slot_index = self.decls.items.len;
4251 try self.decls.append(self.arena, .{
4252 .name = name,
4253 .src = ast_node_index,
4254 .value = walk_result,
4255 .kind = kind,
4256 .parent_container = scope.enclosing_type,
4257 });
4258
4259 if (declaration.flags.is_pub) {
4260 try decl_indexes.append(self.arena, decls_slot_index);
4261 } else {
4262 try priv_decl_indexes.append(self.arena, decls_slot_index);
4263 }
4264
4265 const decl_status_ptr = scope.resolveDeclName(declaration.name.toString(file.zir).?, file, .none);
4266 std.debug.assert(decl_status_ptr.* == .Pending);
4267 decl_status_ptr.* = .{ .Analyzed = decls_slot_index };
4268
4269 // Unblock any pending decl path that was waiting for this decl.
4270 if (self.ref_paths_pending_on_decls.get(decl_status_ptr)) |paths| {
4271 for (paths.items) |resume_info| {
4272 try self.tryResolveRefPath(
4273 resume_info.file,
4274 decl_inst,
4275 resume_info.ref_path,
4276 );
4277 }
4278
4279 _ = self.ref_paths_pending_on_decls.remove(decl_status_ptr);
4280 // TODO: we should deallocate the arraylist that holds all the
4281 // ref paths. not doing it now since it's arena-allocated
4282 // anyway, but maybe we should put it elsewhere.
4283 }
4284}
4285
4286fn analyzeUsingnamespaceDecl(
4287 self: *Autodoc,
4288 file: *File,
4289 scope: *Scope,
4290 decl_src: SrcLocInfo,
4291 decl_indexes: *std.ArrayListUnmanaged(usize),
4292 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4293 declaration: Zir.Inst.Declaration,
4294 extra_index: u32,
4295 call_ctx: ?*const CallContext,
4296) AutodocErrors!void {
4297 const bodies = declaration.getBodies(extra_index, file.zir);
4298
4299 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4300 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
4301 else
4302 null;
4303
4304 // astnode
4305 const ast_node_index = idx: {
4306 const idx = self.ast_nodes.items.len;
4307 try self.ast_nodes.append(self.arena, .{
4308 .file = self.files.getIndex(file).?,
4309 .line = decl_src.line,
4310 .col = 0,
4311 .docs = doc_comment,
4312 .fields = null, // walkInstruction will fill `fields` if necessary
4313 });
4314 break :idx idx;
4315 };
4316
4317 const walk_result = try self.walkInlineBody(
4318 file,
4319 scope,
4320 decl_src,
4321 decl_src,
4322 bodies.value_body,
4323 true,
4324 call_ctx,
4325 );
4326
4327 const decl_slot_index = self.decls.items.len;
4328 try self.decls.append(self.arena, .{
4329 .name = "",
4330 .kind = "",
4331 .src = ast_node_index,
4332 .value = walk_result,
4333 .is_uns = true,
4334 .parent_container = scope.enclosing_type,
4335 });
4336
4337 if (declaration.flags.is_pub) {
4338 try decl_indexes.append(self.arena, decl_slot_index);
4339 } else {
4340 try priv_decl_indexes.append(self.arena, decl_slot_index);
4341 }
4342}
4343
4344fn analyzeDecltest(
4345 self: *Autodoc,
4346 file: *File,
4347 scope: *Scope,
4348 decl_src: SrcLocInfo,
4349 declaration: Zir.Inst.Declaration,
4350 extra_index: u32,
4351) AutodocErrors!void {
4352 std.debug.assert(declaration.flags.has_doc_comment);
4353 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
4354
4355 const test_source_code = (try file.getTree(self.zcu.gpa)).getNodeSource(decl_src.src_node);
4356
4357 const decl_name: ?[]const u8 = if (decl_name_index != .empty)
4358 file.zir.nullTerminatedString(decl_name_index)
4359 else
4360 null;
4361
4362 // astnode
4363 const ast_node_index = idx: {
4364 const idx = self.ast_nodes.items.len;
4365 try self.ast_nodes.append(self.arena, .{
4366 .file = self.files.getIndex(file).?,
4367 .line = decl_src.line,
4368 .col = 0,
4369 .name = decl_name,
4370 .code = test_source_code,
4371 });
4372 break :idx idx;
4373 };
4374
4375 const decl_status = scope.resolveDeclName(decl_name_index, file, .none);
4376
4377 switch (decl_status.*) {
4378 .Analyzed => |idx| {
4379 self.decls.items[idx].decltest = ast_node_index;
4380 },
4381 else => unreachable, // we assume analyzeAllDecls analyzed other decls by this point
4382 }
4383}
4384
4385/// An unresolved path has a non-string WalkResult at its beginnig, while every
4386/// other element is a string WalkResult. Resolving means iteratively map each
4387/// string to a Decl / Type / Call / etc.
4388///
4389/// If we encounter an unanalyzed decl during the process, we append the
4390/// unsolved sub-path to `self.ref_paths_pending_on_decls` and bail out.
4391/// Same happens when a decl holds a type definition that hasn't been fully
4392/// analyzed yet (except that we append to `self.ref_paths_pending_on_types`.
4393///
4394/// When analyzeAllDecls / walkInstruction finishes analyzing a decl / type, it will
4395/// then check if there's any pending ref path blocked on it and, if any, it
4396/// will progress their resolution by calling tryResolveRefPath again.
4397///
4398/// Ref paths can also depend on other ref paths. See
4399/// `self.pending_ref_paths` for more info.
4400///
4401/// A ref path that has a component that resolves into a comptimeExpr will
4402/// give up its resolution process entirely, leaving the remaining components
4403/// as strings.
4404fn tryResolveRefPath(
4405 self: *Autodoc,
4406 /// File from which the decl path originates.
4407 file: *File,
4408 inst: Zir.Inst.Index, // used only for panicWithContext
4409 path: []DocData.Expr,
4410) AutodocErrors!void {
4411 var i: usize = 0;
4412 outer: while (i < path.len - 1) : (i += 1) {
4413 const parent = path[i];
4414 const child_string = path[i + 1].declName; // we expect to find an unsolved decl
4415
4416 var resolved_parent = parent;
4417 var j: usize = 0;
4418 while (j < 10_000) : (j += 1) {
4419 switch (resolved_parent) {
4420 else => break,
4421 .this => |t| resolved_parent = .{ .type = t },
4422 .declIndex => |decl_index| {
4423 const decl = self.decls.items[decl_index];
4424 resolved_parent = decl.value.expr;
4425 continue;
4426 },
4427 .declRef => |decl_status_ptr| {
4428 // NOTE: must be kep in sync with `findNameInUnsDecls`
4429 switch (decl_status_ptr.*) {
4430 // The use of unreachable here is conservative.
4431 // It might be that it truly should be up to us to
4432 // request the analys of this decl, but it's not clear
4433 // at the moment of writing.
4434 .NotRequested => unreachable,
4435 .Analyzed => |decl_index| {
4436 const decl = self.decls.items[decl_index];
4437 resolved_parent = decl.value.expr;
4438 continue;
4439 },
4440 .Pending => {
4441 // This decl path is pending completion
4442 {
4443 const res = try self.pending_ref_paths.getOrPut(
4444 self.arena,
4445 &path[path.len - 1],
4446 );
4447 if (!res.found_existing) res.value_ptr.* = .{};
4448 }
4449
4450 const res = try self.ref_paths_pending_on_decls.getOrPut(
4451 self.arena,
4452 decl_status_ptr,
4453 );
4454 if (!res.found_existing) res.value_ptr.* = .{};
4455 try res.value_ptr.*.append(self.arena, .{
4456 .file = file,
4457 .ref_path = path[i..path.len],
4458 });
4459
4460 // We return instead doing `break :outer` to prevent the
4461 // code after the :outer while loop to run, as it assumes
4462 // that the path will have been fully analyzed (or we
4463 // have given up because of a comptimeExpr).
4464 return;
4465 },
4466 }
4467 },
4468 .refPath => |rp| {
4469 if (self.pending_ref_paths.getPtr(&rp[rp.len - 1])) |waiter_list| {
4470 try waiter_list.append(self.arena, .{
4471 .file = file,
4472 .ref_path = path[i..path.len],
4473 });
4474
4475 // This decl path is pending completion
4476 {
4477 const res = try self.pending_ref_paths.getOrPut(
4478 self.arena,
4479 &path[path.len - 1],
4480 );
4481 if (!res.found_existing) res.value_ptr.* = .{};
4482 }
4483
4484 return;
4485 }
4486
4487 // If the last element is a declName or a CTE, then we give up,
4488 // otherwise we resovle the parent to it and loop again.
4489 // NOTE: we assume that if we find a string, it's because of
4490 // a CTE component somewhere in the path. We know that the path
4491 // is not pending futher evaluation because we just checked!
4492 const last = rp[rp.len - 1];
4493 switch (last) {
4494 .comptimeExpr, .declName => break :outer,
4495 else => {
4496 resolved_parent = last;
4497 continue;
4498 },
4499 }
4500 },
4501 .fieldVal => |fv| {
4502 resolved_parent = self.exprs.items[fv.val.expr];
4503 },
4504 }
4505 } else {
4506 panicWithContext(
4507 file,
4508 inst,
4509 "exhausted eval quota for `{}`in tryResolveRefPath\n",
4510 .{resolved_parent},
4511 );
4512 }
4513
4514 switch (resolved_parent) {
4515 else => {
4516 // NOTE: indirect references to types / decls should be handled
4517 // in the switch above this one!
4518 printWithContext(
4519 file,
4520 inst,
4521 "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
4522 .{ @tagName(resolved_parent), resolved_parent },
4523 );
4524 // path[i + 1] = (try self.cteTodo("<match failure>")).expr;
4525 continue :outer;
4526 },
4527 .comptimeExpr, .call, .typeOf => {
4528 // Since we hit a cte, we leave the remaining strings unresolved
4529 // and completely give up on resolving this decl path.
4530 //decl_path.hasCte = true;
4531 break :outer;
4532 },
4533 .type => |t_index| switch (self.types.items[t_index]) {
4534 else => {
4535 panicWithContext(
4536 file,
4537 inst,
4538 "TODO: handle `{s}` in tryResolveDeclPath.type\nInfo: {}",
4539 .{ @tagName(self.types.items[t_index]), resolved_parent },
4540 );
4541 },
4542 .ComptimeExpr => {
4543 // Same as the comptimeExpr branch above
4544 break :outer;
4545 },
4546 .Unanalyzed => {
4547 // This decl path is pending completion
4548 {
4549 const res = try self.pending_ref_paths.getOrPut(
4550 self.arena,
4551 &path[path.len - 1],
4552 );
4553 if (!res.found_existing) res.value_ptr.* = .{};
4554 }
4555
4556 const res = try self.ref_paths_pending_on_types.getOrPut(
4557 self.arena,
4558 t_index,
4559 );
4560 if (!res.found_existing) res.value_ptr.* = .{};
4561 try res.value_ptr.*.append(self.arena, .{
4562 .file = file,
4563 .ref_path = path[i..path.len],
4564 });
4565
4566 return;
4567 },
4568 .Array => {
4569 if (std.mem.eql(u8, child_string, "len")) {
4570 path[i + 1] = .{
4571 .builtinField = .len,
4572 };
4573 } else {
4574 panicWithContext(
4575 file,
4576 inst,
4577 "TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
4578 .{ child_string, resolved_parent },
4579 );
4580 }
4581 },
4582 // TODO: the following searches could probably
4583 // be performed more efficiently on the corresponding
4584 // scope
4585 .Enum => |t_enum| { // foo.bar.baz
4586 // Look into locally-defined pub decls
4587 for (t_enum.pubDecls) |idx| {
4588 const d = self.decls.items[idx];
4589 if (d.is_uns) continue;
4590 if (std.mem.eql(u8, d.name, child_string)) {
4591 path[i + 1] = .{ .declIndex = idx };
4592 continue :outer;
4593 }
4594 }
4595
4596 // Look into locally-defined priv decls
4597 for (t_enum.privDecls) |idx| {
4598 const d = self.decls.items[idx];
4599 if (d.is_uns) continue;
4600 if (std.mem.eql(u8, d.name, child_string)) {
4601 path[i + 1] = .{ .declIndex = idx };
4602 continue :outer;
4603 }
4604 }
4605
4606 switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
4607 .Pending => return,
4608 .NotFound => {},
4609 .Found => |match| {
4610 path[i + 1] = match;
4611 continue :outer;
4612 },
4613 }
4614
4615 for (self.ast_nodes.items[t_enum.src].fields.?, 0..) |ast_node, idx| {
4616 const name = self.ast_nodes.items[ast_node].name.?;
4617 if (std.mem.eql(u8, name, child_string)) {
4618 // TODO: should we really create an artificial
4619 // decl for this type? Probably not.
4620
4621 path[i + 1] = .{
4622 .fieldRef = .{
4623 .type = t_index,
4624 .index = idx,
4625 },
4626 };
4627 continue :outer;
4628 }
4629 }
4630
4631 // if we got here, our search failed
4632 printWithContext(
4633 file,
4634 inst,
4635 "failed to match `{s}` in enum",
4636 .{child_string},
4637 );
4638
4639 path[i + 1] = (try self.cteTodo("match failure")).expr;
4640 continue :outer;
4641 },
4642 .Union => |t_union| {
4643 // Look into locally-defined pub decls
4644 for (t_union.pubDecls) |idx| {
4645 const d = self.decls.items[idx];
4646 if (d.is_uns) continue;
4647 if (std.mem.eql(u8, d.name, child_string)) {
4648 path[i + 1] = .{ .declIndex = idx };
4649 continue :outer;
4650 }
4651 }
4652
4653 // Look into locally-defined priv decls
4654 for (t_union.privDecls) |idx| {
4655 const d = self.decls.items[idx];
4656 if (d.is_uns) continue;
4657 if (std.mem.eql(u8, d.name, child_string)) {
4658 path[i + 1] = .{ .declIndex = idx };
4659 continue :outer;
4660 }
4661 }
4662
4663 switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
4664 .Pending => return,
4665 .NotFound => {},
4666 .Found => |match| {
4667 path[i + 1] = match;
4668 continue :outer;
4669 },
4670 }
4671
4672 for (self.ast_nodes.items[t_union.src].fields.?, 0..) |ast_node, idx| {
4673 const name = self.ast_nodes.items[ast_node].name.?;
4674 if (std.mem.eql(u8, name, child_string)) {
4675 // TODO: should we really create an artificial
4676 // decl for this type? Probably not.
4677
4678 path[i + 1] = .{
4679 .fieldRef = .{
4680 .type = t_index,
4681 .index = idx,
4682 },
4683 };
4684 continue :outer;
4685 }
4686 }
4687
4688 // if we got here, our search failed
4689 printWithContext(
4690 file,
4691 inst,
4692 "failed to match `{s}` in union",
4693 .{child_string},
4694 );
4695 path[i + 1] = (try self.cteTodo("match failure")).expr;
4696 continue :outer;
4697 },
4698
4699 .Struct => |t_struct| {
4700 // Look into locally-defined pub decls
4701 for (t_struct.pubDecls) |idx| {
4702 const d = self.decls.items[idx];
4703 if (d.is_uns) continue;
4704 if (std.mem.eql(u8, d.name, child_string)) {
4705 path[i + 1] = .{ .declIndex = idx };
4706 continue :outer;
4707 }
4708 }
4709
4710 // Look into locally-defined priv decls
4711 for (t_struct.privDecls) |idx| {
4712 const d = self.decls.items[idx];
4713 if (d.is_uns) continue;
4714 if (std.mem.eql(u8, d.name, child_string)) {
4715 path[i + 1] = .{ .declIndex = idx };
4716 continue :outer;
4717 }
4718 }
4719
4720 switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
4721 .Pending => return,
4722 .NotFound => {},
4723 .Found => |match| {
4724 path[i + 1] = match;
4725 continue :outer;
4726 },
4727 }
4728
4729 for (self.ast_nodes.items[t_struct.src].fields.?, 0..) |ast_node, idx| {
4730 const name = self.ast_nodes.items[ast_node].name.?;
4731 if (std.mem.eql(u8, name, child_string)) {
4732 // TODO: should we really create an artificial
4733 // decl for this type? Probably not.
4734
4735 path[i + 1] = .{
4736 .fieldRef = .{
4737 .type = t_index,
4738 .index = idx,
4739 },
4740 };
4741 continue :outer;
4742 }
4743 }
4744
4745 // if we got here, our search failed
4746 // printWithContext(
4747 // file,
4748 // inst,
4749 // "failed to match `{s}` in struct",
4750 // .{child_string},
4751 // );
4752 // path[i + 1] = (try self.cteTodo("match failure")).expr;
4753 //
4754 // that's working
4755 path[i + 1] = (try self.cteTodo(child_string)).expr;
4756 continue :outer;
4757 },
4758 .Opaque => |t_opaque| {
4759 // Look into locally-defined pub decls
4760 for (t_opaque.pubDecls) |idx| {
4761 const d = self.decls.items[idx];
4762 if (d.is_uns) continue;
4763 if (std.mem.eql(u8, d.name, child_string)) {
4764 path[i + 1] = .{ .declIndex = idx };
4765 continue :outer;
4766 }
4767 }
4768
4769 // Look into locally-defined priv decls
4770 for (t_opaque.privDecls) |idx| {
4771 const d = self.decls.items[idx];
4772 if (d.is_uns) continue;
4773 if (std.mem.eql(u8, d.name, child_string)) {
4774 path[i + 1] = .{ .declIndex = idx };
4775 continue :outer;
4776 }
4777 }
4778
4779 // We delay looking into Uns decls since they could be
4780 // not fully analyzed yet.
4781 switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
4782 .Pending => return,
4783 .NotFound => {},
4784 .Found => |match| {
4785 path[i + 1] = match;
4786 continue :outer;
4787 },
4788 }
4789
4790 // if we got here, our search failed
4791 printWithContext(
4792 file,
4793 inst,
4794 "failed to match `{s}` in opaque",
4795 .{child_string},
4796 );
4797
4798 path[i + 1] = (try self.cteTodo("match failure")).expr;
4799 continue :outer;
4800 },
4801 },
4802 .@"struct" => |st| {
4803 for (st) |field| {
4804 if (std.mem.eql(u8, field.name, child_string)) {
4805 path[i + 1] = .{ .fieldVal = field };
4806 continue :outer;
4807 }
4808 }
4809
4810 // if we got here, our search failed
4811 printWithContext(
4812 file,
4813 inst,
4814 "failed to match `{s}` in struct",
4815 .{child_string},
4816 );
4817
4818 path[i + 1] = (try self.cteTodo("match failure")).expr;
4819 continue :outer;
4820 },
4821 }
4822 }
4823
4824 if (self.pending_ref_paths.get(&path[path.len - 1])) |waiter_list| {
4825 // It's important to de-register ourselves as pending before
4826 // attempting to resolve any other decl.
4827 _ = self.pending_ref_paths.remove(&path[path.len - 1]);
4828
4829 for (waiter_list.items) |resume_info| {
4830 try self.tryResolveRefPath(resume_info.file, inst, resume_info.ref_path);
4831 }
4832 // TODO: this is where we should free waiter_list, but its in the arena
4833 // that said, we might want to store it elsewhere and reclaim memory asap
4834 }
4835}
4836
4837const UnsSearchResult = union(enum) {
4838 Found: DocData.Expr,
4839 Pending,
4840 NotFound,
4841};
4842
4843fn findNameInUnsDecls(
4844 self: *Autodoc,
4845 file: *File,
4846 tail: []DocData.Expr,
4847 uns_expr: DocData.Expr,
4848 name: []const u8,
4849) !UnsSearchResult {
4850 var to_analyze = std.SegmentedList(DocData.Expr, 1){};
4851 // TODO: make this an appendAssumeCapacity
4852 try to_analyze.append(self.arena, uns_expr);
4853
4854 while (to_analyze.pop()) |cte| {
4855 var container_expression = cte;
4856 for (0..10_000) |_| {
4857 // TODO: handle other types of indirection, like @import
4858 const type_index = switch (container_expression) {
4859 .type => |t| t,
4860 .declRef => |decl_status_ptr| {
4861 switch (decl_status_ptr.*) {
4862 // The use of unreachable here is conservative.
4863 // It might be that it truly should be up to us to
4864 // request the analys of this decl, but it's not clear
4865 // at the moment of writing.
4866 .NotRequested => unreachable,
4867 .Analyzed => |decl_index| {
4868 const decl = self.decls.items[decl_index];
4869 container_expression = decl.value.expr;
4870 continue;
4871 },
4872 .Pending => {
4873 // This decl path is pending completion
4874 {
4875 const res = try self.pending_ref_paths.getOrPut(
4876 self.arena,
4877 &tail[tail.len - 1],
4878 );
4879 if (!res.found_existing) res.value_ptr.* = .{};
4880 }
4881
4882 const res = try self.ref_paths_pending_on_decls.getOrPut(
4883 self.arena,
4884 decl_status_ptr,
4885 );
4886 if (!res.found_existing) res.value_ptr.* = .{};
4887 try res.value_ptr.*.append(self.arena, .{
4888 .file = file,
4889 .ref_path = tail,
4890 });
4891
4892 // TODO: save some state that keeps track of our
4893 // progress because, as things stand, we
4894 // always re-start the search from scratch
4895 return .Pending;
4896 },
4897 }
4898 },
4899 else => {
4900 log.debug(
4901 "Handle `{s}` in findNameInUnsDecls (first switch)",
4902 .{@tagName(cte)},
4903 );
4904 return .{ .Found = .{ .comptimeExpr = 0 } };
4905 },
4906 };
4907
4908 const t = self.types.items[type_index];
4909 const decls = switch (t) {
4910 else => {
4911 log.debug(
4912 "Handle `{s}` in findNameInUnsDecls (second switch)",
4913 .{@tagName(cte)},
4914 );
4915 return .{ .Found = .{ .comptimeExpr = 0 } };
4916 },
4917 inline .Struct, .Union, .Opaque, .Enum => |c| c.pubDecls,
4918 };
4919
4920 for (decls) |idx| {
4921 const d = self.decls.items[idx];
4922 if (d.is_uns) {
4923 try to_analyze.append(self.arena, d.value.expr);
4924 } else if (std.mem.eql(u8, d.name, name)) {
4925 return .{ .Found = .{ .declIndex = idx } };
4926 }
4927 }
4928 }
4929 }
4930
4931 return .NotFound;
4932}
4933
4934fn analyzeFancyFunction(
4935 self: *Autodoc,
4936 file: *File,
4937 scope: *Scope,
4938 parent_src: SrcLocInfo,
4939 inst: Zir.Inst.Index,
4940 self_ast_node_index: usize,
4941 type_slot_index: usize,
4942 call_ctx: ?*const CallContext,
4943) AutodocErrors!DocData.WalkResult {
4944 const tags = file.zir.instructions.items(.tag);
4945 const data = file.zir.instructions.items(.data);
4946 const fn_info = file.zir.getFnInfo(inst);
4947
4948 try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
4949 var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
4950 self.arena,
4951 fn_info.total_params_len,
4952 );
4953 var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
4954 self.arena,
4955 fn_info.total_params_len,
4956 );
4957
4958 // TODO: handle scope rules for fn parameters
4959 for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
4960 switch (tags[@intFromEnum(param_index)]) {
4961 else => {
4962 panicWithContext(
4963 file,
4964 param_index,
4965 "TODO: handle `{s}` in walkInstruction.func\n",
4966 .{@tagName(tags[@intFromEnum(param_index)])},
4967 );
4968 },
4969 .param_anytype, .param_anytype_comptime => {
4970 // TODO: where are the doc comments?
4971 const str_tok = data[@intFromEnum(param_index)].str_tok;
4972
4973 const name = str_tok.get(file.zir);
4974
4975 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
4976 self.ast_nodes.appendAssumeCapacity(.{
4977 .name = name,
4978 .docs = "",
4979 .@"comptime" = tags[@intFromEnum(param_index)] == .param_anytype_comptime,
4980 });
4981
4982 param_type_refs.appendAssumeCapacity(
4983 DocData.Expr{ .@"anytype" = .{} },
4984 );
4985 },
4986 .param, .param_comptime => {
4987 const pl_tok = data[@intFromEnum(param_index)].pl_tok;
4988 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
4989 const doc_comment = if (extra.data.doc_comment != .empty)
4990 file.zir.nullTerminatedString(extra.data.doc_comment)
4991 else
4992 "";
4993 const name = file.zir.nullTerminatedString(extra.data.name);
4994
4995 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
4996 try self.ast_nodes.append(self.arena, .{
4997 .name = name,
4998 .docs = doc_comment,
4999 .@"comptime" = tags[@intFromEnum(param_index)] == .param_comptime,
5000 });
5001
5002 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
5003 const break_operand = data[break_index].@"break".operand;
5004 const param_type_ref = try self.walkRef(
5005 file,
5006 scope,
5007 parent_src,
5008 break_operand,
5009 false,
5010 call_ctx,
5011 );
5012
5013 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
5014 },
5015 }
5016 }
5017
5018 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
5019
5020 const pl_node = data[@intFromEnum(inst)].pl_node;
5021 const extra = file.zir.extraData(Zir.Inst.FuncFancy, pl_node.payload_index);
5022
5023 var extra_index: usize = extra.end;
5024
5025 var lib_name: []const u8 = "";
5026 if (extra.data.bits.has_lib_name) {
5027 const lib_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
5028 lib_name = file.zir.nullTerminatedString(lib_name_index);
5029 extra_index += 1;
5030 }
5031
5032 var align_index: ?usize = null;
5033 if (extra.data.bits.has_align_ref) {
5034 const align_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
5035 align_index = self.exprs.items.len;
5036 _ = try self.walkRef(
5037 file,
5038 scope,
5039 parent_src,
5040 align_ref,
5041 false,
5042 call_ctx,
5043 );
5044 extra_index += 1;
5045 } else if (extra.data.bits.has_align_body) {
5046 const align_body_len = file.zir.extra[extra_index];
5047 extra_index += 1;
5048 const align_body = file.zir.extra[extra_index .. extra_index + align_body_len];
5049 _ = align_body;
5050 // TODO: analyze the block (or bail with a comptimeExpr)
5051 extra_index += align_body_len;
5052 } else {
5053 // default alignment
5054 }
5055
5056 var addrspace_index: ?usize = null;
5057 if (extra.data.bits.has_addrspace_ref) {
5058 const addrspace_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
5059 addrspace_index = self.exprs.items.len;
5060 _ = try self.walkRef(
5061 file,
5062 scope,
5063 parent_src,
5064 addrspace_ref,
5065 false,
5066 call_ctx,
5067 );
5068 extra_index += 1;
5069 } else if (extra.data.bits.has_addrspace_body) {
5070 const addrspace_body_len = file.zir.extra[extra_index];
5071 extra_index += 1;
5072 const addrspace_body = file.zir.extra[extra_index .. extra_index + addrspace_body_len];
5073 _ = addrspace_body;
5074 // TODO: analyze the block (or bail with a comptimeExpr)
5075 extra_index += addrspace_body_len;
5076 } else {
5077 // default alignment
5078 }
5079
5080 var section_index: ?usize = null;
5081 if (extra.data.bits.has_section_ref) {
5082 const section_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
5083 section_index = self.exprs.items.len;
5084 _ = try self.walkRef(
5085 file,
5086 scope,
5087 parent_src,
5088 section_ref,
5089 false,
5090 call_ctx,
5091 );
5092 extra_index += 1;
5093 } else if (extra.data.bits.has_section_body) {
5094 const section_body_len = file.zir.extra[extra_index];
5095 extra_index += 1;
5096 const section_body = file.zir.extra[extra_index .. extra_index + section_body_len];
5097 _ = section_body;
5098 // TODO: analyze the block (or bail with a comptimeExpr)
5099 extra_index += section_body_len;
5100 } else {
5101 // default alignment
5102 }
5103
5104 var cc_index: ?usize = null;
5105 if (extra.data.bits.has_cc_ref and !extra.data.bits.has_cc_body) {
5106 const cc_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
5107 const cc_expr = try self.walkRef(
5108 file,
5109 scope,
5110 parent_src,
5111 cc_ref,
5112 false,
5113 call_ctx,
5114 );
5115
5116 cc_index = self.exprs.items.len;
5117 try self.exprs.append(self.arena, cc_expr.expr);
5118
5119 extra_index += 1;
5120 } else if (extra.data.bits.has_cc_body) {
5121 const cc_body_len = file.zir.extra[extra_index];
5122 extra_index += 1;
5123 const cc_body = file.zir.bodySlice(extra_index, cc_body_len);
5124
5125 // We assume the body ends with a break_inline
5126 const break_index = cc_body[cc_body.len - 1];
5127 const break_operand = data[@intFromEnum(break_index)].@"break".operand;
5128 const cc_expr = try self.walkRef(
5129 file,
5130 scope,
5131 parent_src,
5132 break_operand,
5133 false,
5134 call_ctx,
5135 );
5136
5137 cc_index = self.exprs.items.len;
5138 try self.exprs.append(self.arena, cc_expr.expr);
5139
5140 extra_index += cc_body_len;
5141 } else {
5142 // auto calling convention
5143 }
5144
5145 // ret
5146 const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
5147 0 => switch (fn_info.ret_ty_ref) {
5148 .none => DocData.Expr{ .void = .{} },
5149 else => blk: {
5150 const ref = fn_info.ret_ty_ref;
5151 const wr = try self.walkRef(
5152 file,
5153 scope,
5154 parent_src,
5155 ref,
5156 false,
5157 call_ctx,
5158 );
5159 break :blk wr.expr;
5160 },
5161 },
5162 else => blk: {
5163 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
5164 const break_operand = data[@intFromEnum(last_instr_index)].@"break".operand;
5165 const wr = try self.walkRef(
5166 file,
5167 scope,
5168 parent_src,
5169 break_operand,
5170 false,
5171 call_ctx,
5172 );
5173 break :blk wr.expr;
5174 },
5175 };
5176
5177 // TODO: a complete version of this will probably need a scope
5178 // in order to evaluate correctly closures around funcion
5179 // parameters etc.
5180 const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
5181 .type => |t| blk: {
5182 if (fn_info.body.len == 0) break :blk null;
5183 if (t == @intFromEnum(Ref.type_type)) {
5184 break :blk try self.getGenericReturnType(
5185 file,
5186 scope,
5187 parent_src,
5188 fn_info.body,
5189 call_ctx,
5190 );
5191 } else {
5192 break :blk null;
5193 }
5194 },
5195 else => null,
5196 };
5197
5198 // if we're analyzing a function signature (ie without body), we
5199 // actually don't have an ast_node reserved for us, but since
5200 // we don't have a name, we don't need it.
5201 const src = if (fn_info.body.len == 0) 0 else self_ast_node_index;
5202
5203 self.types.items[type_slot_index] = .{
5204 .Fn = .{
5205 .name = "todo_name func",
5206 .src = src,
5207 .params = param_type_refs.items,
5208 .ret = ret_type_ref,
5209 .generic_ret = generic_ret,
5210 .is_extern = extra.data.bits.is_extern,
5211 .has_cc = cc_index != null,
5212 .has_align = align_index != null,
5213 .has_lib_name = extra.data.bits.has_lib_name,
5214 .lib_name = lib_name,
5215 .is_inferred_error = extra.data.bits.is_inferred_error,
5216 .cc = cc_index,
5217 .@"align" = align_index,
5218 },
5219 };
5220
5221 return DocData.WalkResult{
5222 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
5223 .expr = .{ .type = type_slot_index },
5224 };
5225}
5226fn analyzeFunction(
5227 self: *Autodoc,
5228 file: *File,
5229 scope: *Scope,
5230 parent_src: SrcLocInfo,
5231 inst: Zir.Inst.Index,
5232 self_ast_node_index: usize,
5233 type_slot_index: usize,
5234 ret_is_inferred_error_set: bool,
5235 call_ctx: ?*const CallContext,
5236) AutodocErrors!DocData.WalkResult {
5237 const tags = file.zir.instructions.items(.tag);
5238 const data = file.zir.instructions.items(.data);
5239 const fn_info = file.zir.getFnInfo(inst);
5240
5241 try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
5242 var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
5243 self.arena,
5244 fn_info.total_params_len,
5245 );
5246 var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
5247 self.arena,
5248 fn_info.total_params_len,
5249 );
5250
5251 // TODO: handle scope rules for fn parameters
5252 for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
5253 switch (tags[@intFromEnum(param_index)]) {
5254 else => {
5255 panicWithContext(
5256 file,
5257 param_index,
5258 "TODO: handle `{s}` in walkInstruction.func\n",
5259 .{@tagName(tags[@intFromEnum(param_index)])},
5260 );
5261 },
5262 .param_anytype, .param_anytype_comptime => {
5263 // TODO: where are the doc comments?
5264 const str_tok = data[@intFromEnum(param_index)].str_tok;
5265
5266 const name = str_tok.get(file.zir);
5267
5268 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
5269 self.ast_nodes.appendAssumeCapacity(.{
5270 .name = name,
5271 .docs = "",
5272 .@"comptime" = tags[@intFromEnum(param_index)] == .param_anytype_comptime,
5273 });
5274
5275 param_type_refs.appendAssumeCapacity(
5276 DocData.Expr{ .@"anytype" = .{} },
5277 );
5278 },
5279 .param, .param_comptime => {
5280 const pl_tok = data[@intFromEnum(param_index)].pl_tok;
5281 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
5282 const doc_comment = if (extra.data.doc_comment != .empty)
5283 file.zir.nullTerminatedString(extra.data.doc_comment)
5284 else
5285 "";
5286 const name = file.zir.nullTerminatedString(extra.data.name);
5287
5288 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
5289 try self.ast_nodes.append(self.arena, .{
5290 .name = name,
5291 .docs = doc_comment,
5292 .@"comptime" = tags[@intFromEnum(param_index)] == .param_comptime,
5293 });
5294
5295 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
5296 const break_operand = data[break_index].@"break".operand;
5297 const param_type_ref = try self.walkRef(
5298 file,
5299 scope,
5300 parent_src,
5301 break_operand,
5302 false,
5303 call_ctx,
5304 );
5305
5306 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
5307 },
5308 }
5309 }
5310
5311 // ret
5312 const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
5313 0 => switch (fn_info.ret_ty_ref) {
5314 .none => DocData.Expr{ .void = .{} },
5315 else => blk: {
5316 const ref = fn_info.ret_ty_ref;
5317 const wr = try self.walkRef(
5318 file,
5319 scope,
5320 parent_src,
5321 ref,
5322 false,
5323 call_ctx,
5324 );
5325 break :blk wr.expr;
5326 },
5327 },
5328 else => blk: {
5329 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
5330 const break_operand = data[@intFromEnum(last_instr_index)].@"break".operand;
5331 const wr = try self.walkRef(
5332 file,
5333 scope,
5334 parent_src,
5335 break_operand,
5336 false,
5337 call_ctx,
5338 );
5339 break :blk wr.expr;
5340 },
5341 };
5342
5343 // TODO: a complete version of this will probably need a scope
5344 // in order to evaluate correctly closures around funcion
5345 // parameters etc.
5346 const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
5347 .type => |t| blk: {
5348 if (fn_info.body.len == 0) break :blk null;
5349 if (t == @intFromEnum(Ref.type_type)) {
5350 break :blk try self.getGenericReturnType(
5351 file,
5352 scope,
5353 parent_src,
5354 fn_info.body,
5355 call_ctx,
5356 );
5357 } else {
5358 break :blk null;
5359 }
5360 },
5361 else => null,
5362 };
5363
5364 const ret_type: DocData.Expr = blk: {
5365 if (ret_is_inferred_error_set) {
5366 const ret_type_slot_index = self.types.items.len;
5367 try self.types.append(self.arena, .{
5368 .InferredErrorUnion = .{ .payload = ret_type_ref },
5369 });
5370 break :blk .{ .type = ret_type_slot_index };
5371 } else break :blk ret_type_ref;
5372 };
5373
5374 // if we're analyzing a function signature (ie without body), we
5375 // actually don't have an ast_node reserved for us, but since
5376 // we don't have a name, we don't need it.
5377 const src = if (fn_info.body.len == 0) 0 else self_ast_node_index;
5378
5379 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
5380 self.types.items[type_slot_index] = .{
5381 .Fn = .{
5382 .name = "todo_name func",
5383 .src = src,
5384 .params = param_type_refs.items,
5385 .ret = ret_type,
5386 .generic_ret = generic_ret,
5387 },
5388 };
5389
5390 return DocData.WalkResult{
5391 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
5392 .expr = .{ .type = type_slot_index },
5393 };
5394}
5395
5396fn getGenericReturnType(
5397 self: *Autodoc,
5398 file: *File,
5399 scope: *Scope,
5400 parent_src: SrcLocInfo, // function decl line
5401 body: []const Zir.Inst.Index,
5402 call_ctx: ?*const CallContext,
5403) !DocData.Expr {
5404 const tags = file.zir.instructions.items(.tag);
5405 if (body.len >= 4) {
5406 const maybe_ret_inst = body[body.len - 4];
5407 switch (tags[@intFromEnum(maybe_ret_inst)]) {
5408 .ret_node, .ret_load => {
5409 const wr = try self.walkInstruction(
5410 file,
5411 scope,
5412 parent_src,
5413 maybe_ret_inst,
5414 false,
5415 call_ctx,
5416 );
5417 return wr.expr;
5418 },
5419 else => {},
5420 }
5421 }
5422 return DocData.Expr{ .comptimeExpr = 0 };
5423}
5424
5425fn collectUnionFieldInfo(
5426 self: *Autodoc,
5427 file: *File,
5428 scope: *Scope,
5429 parent_src: SrcLocInfo,
5430 fields_len: usize,
5431 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
5432 field_name_indexes: *std.ArrayListUnmanaged(usize),
5433 ei: usize,
5434 call_ctx: ?*const CallContext,
5435) !void {
5436 if (fields_len == 0) return;
5437 var extra_index = ei;
5438
5439 const bits_per_field = 4;
5440 const fields_per_u32 = 32 / bits_per_field;
5441 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
5442 var bit_bag_index: usize = extra_index;
5443 extra_index += bit_bags_count;
5444
5445 var cur_bit_bag: u32 = undefined;
5446 var field_i: u32 = 0;
5447 while (field_i < fields_len) : (field_i += 1) {
5448 if (field_i % fields_per_u32 == 0) {
5449 cur_bit_bag = file.zir.extra[bit_bag_index];
5450 bit_bag_index += 1;
5451 }
5452 const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;
5453 cur_bit_bag >>= 1;
5454 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
5455 cur_bit_bag >>= 1;
5456 const has_tag = @as(u1, @truncate(cur_bit_bag)) != 0;
5457 cur_bit_bag >>= 1;
5458 const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
5459 cur_bit_bag >>= 1;
5460 _ = unused;
5461
5462 const field_name = file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]));
5463 extra_index += 1;
5464 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
5465 extra_index += 1;
5466 const field_type: Zir.Inst.Ref = if (has_type) @enumFromInt(file.zir.extra[extra_index]) else .void_type;
5467 if (has_type) extra_index += 1;
5468
5469 if (has_align) extra_index += 1;
5470 if (has_tag) extra_index += 1;
5471
5472 // type
5473 {
5474 const walk_result = try self.walkRef(
5475 file,
5476 scope,
5477 parent_src,
5478 field_type,
5479 false,
5480 call_ctx,
5481 );
5482 try field_type_refs.append(self.arena, walk_result.expr);
5483 }
5484
5485 // ast node
5486 {
5487 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
5488 const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
5489 file.zir.nullTerminatedString(doc_comment_index)
5490 else
5491 null;
5492 try self.ast_nodes.append(self.arena, .{
5493 .name = field_name,
5494 .docs = doc_comment,
5495 });
5496 }
5497 }
5498}
5499
5500fn collectStructFieldInfo(
5501 self: *Autodoc,
5502 file: *File,
5503 scope: *Scope,
5504 parent_src: SrcLocInfo,
5505 fields_len: usize,
5506 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
5507 field_default_refs: *std.ArrayListUnmanaged(?DocData.Expr),
5508 field_name_indexes: *std.ArrayListUnmanaged(usize),
5509 ei: usize,
5510 is_tuple: bool,
5511 call_ctx: ?*const CallContext,
5512) !void {
5513 if (fields_len == 0) return;
5514 var extra_index = ei;
5515
5516 const bits_per_field = 4;
5517 const fields_per_u32 = 32 / bits_per_field;
5518 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
5519
5520 const Field = struct {
5521 field_name: Zir.NullTerminatedString,
5522 doc_comment_index: Zir.NullTerminatedString,
5523 type_body_len: u32 = 0,
5524 align_body_len: u32 = 0,
5525 init_body_len: u32 = 0,
5526 type_ref: Zir.Inst.Ref = .none,
5527 };
5528 const fields = try self.arena.alloc(Field, fields_len);
5529
5530 var bit_bag_index: usize = extra_index;
5531 extra_index += bit_bags_count;
5532
5533 var cur_bit_bag: u32 = undefined;
5534 var field_i: u32 = 0;
5535 while (field_i < fields_len) : (field_i += 1) {
5536 if (field_i % fields_per_u32 == 0) {
5537 cur_bit_bag = file.zir.extra[bit_bag_index];
5538 bit_bag_index += 1;
5539 }
5540 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
5541 cur_bit_bag >>= 1;
5542 const has_default = @as(u1, @truncate(cur_bit_bag)) != 0;
5543 cur_bit_bag >>= 1;
5544 // const is_comptime = @truncate(u1, cur_bit_bag) != 0;
5545 cur_bit_bag >>= 1;
5546 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
5547 cur_bit_bag >>= 1;
5548
5549 const field_name: Zir.NullTerminatedString = if (!is_tuple) blk: {
5550 const fname = file.zir.extra[extra_index];
5551 extra_index += 1;
5552 break :blk @enumFromInt(fname);
5553 } else .empty;
5554
5555 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
5556 extra_index += 1;
5557
5558 fields[field_i] = .{
5559 .field_name = field_name,
5560 .doc_comment_index = doc_comment_index,
5561 };
5562
5563 if (has_type_body) {
5564 fields[field_i].type_body_len = file.zir.extra[extra_index];
5565 } else {
5566 fields[field_i].type_ref = @enumFromInt(file.zir.extra[extra_index]);
5567 }
5568 extra_index += 1;
5569
5570 if (has_align) {
5571 fields[field_i].align_body_len = file.zir.extra[extra_index];
5572 extra_index += 1;
5573 }
5574 if (has_default) {
5575 fields[field_i].init_body_len = file.zir.extra[extra_index];
5576 extra_index += 1;
5577 }
5578 }
5579
5580 const data = file.zir.instructions.items(.data);
5581
5582 for (fields) |field| {
5583 const type_expr = expr: {
5584 if (field.type_ref != .none) {
5585 const walk_result = try self.walkRef(
5586 file,
5587 scope,
5588 parent_src,
5589 field.type_ref,
5590 false,
5591 call_ctx,
5592 );
5593 break :expr walk_result.expr;
5594 }
5595
5596 std.debug.assert(field.type_body_len != 0);
5597 const body = file.zir.bodySlice(extra_index, field.type_body_len);
5598 extra_index += body.len;
5599
5600 const break_inst = body[body.len - 1];
5601 const operand = data[@intFromEnum(break_inst)].@"break".operand;
5602 try self.ast_nodes.append(self.arena, .{
5603 .file = self.files.getIndex(file).?,
5604 .line = parent_src.line,
5605 .col = 0,
5606 .fields = null, // walkInstruction will fill `fields` if necessary
5607 });
5608 const walk_result = try self.walkRef(
5609 file,
5610 scope,
5611 parent_src,
5612 operand,
5613 false,
5614 call_ctx,
5615 );
5616 break :expr walk_result.expr;
5617 };
5618
5619 extra_index += field.align_body_len;
5620
5621 const default_expr: ?DocData.Expr = def: {
5622 if (field.init_body_len == 0) {
5623 break :def null;
5624 }
5625
5626 const body = file.zir.bodySlice(extra_index, field.init_body_len);
5627 extra_index += body.len;
5628
5629 const break_inst = body[body.len - 1];
5630 const operand = data[@intFromEnum(break_inst)].@"break".operand;
5631 const walk_result = try self.walkRef(
5632 file,
5633 scope,
5634 parent_src,
5635 operand,
5636 false,
5637 call_ctx,
5638 );
5639 break :def walk_result.expr;
5640 };
5641
5642 try field_type_refs.append(self.arena, type_expr);
5643 try field_default_refs.append(self.arena, default_expr);
5644
5645 // ast node
5646 {
5647 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
5648 const doc_comment: ?[]const u8 = if (field.doc_comment_index != .empty)
5649 file.zir.nullTerminatedString(field.doc_comment_index)
5650 else
5651 null;
5652 const field_name: []const u8 = if (field.field_name != .empty)
5653 file.zir.nullTerminatedString(field.field_name)
5654 else
5655 "";
5656
5657 try self.ast_nodes.append(self.arena, .{
5658 .name = field_name,
5659 .docs = doc_comment,
5660 });
5661 }
5662 }
5663}
5664
5665/// A Zir Ref can either refer to common types and values, or to a Zir index.
5666/// WalkRef resolves common cases and delegates to `walkInstruction` otherwise.
5667fn walkRef(
5668 self: *Autodoc,
5669 file: *File,
5670 parent_scope: *Scope,
5671 parent_src: SrcLocInfo,
5672 ref: Ref,
5673 need_type: bool, // true when the caller needs also a typeRef for the return value
5674 call_ctx: ?*const CallContext,
5675) AutodocErrors!DocData.WalkResult {
5676 if (ref == .none) {
5677 return .{ .expr = .{ .comptimeExpr = 0 } };
5678 } else if (@intFromEnum(ref) <= @intFromEnum(InternPool.Index.last_type)) {
5679 // We can just return a type that indexes into `types` with the
5680 // enum value because in the beginning we pre-filled `types` with
5681 // the types that are listed in `Ref`.
5682 return DocData.WalkResult{
5683 .typeRef = .{ .type = @intFromEnum(std.builtin.TypeId.Type) },
5684 .expr = .{ .type = @intFromEnum(ref) },
5685 };
5686 } else if (ref.toIndex()) |zir_index| {
5687 return self.walkInstruction(
5688 file,
5689 parent_scope,
5690 parent_src,
5691 zir_index,
5692 need_type,
5693 call_ctx,
5694 );
5695 } else {
5696 switch (ref) {
5697 else => {
5698 panicWithOptionalContext(
5699 file,
5700 .none,
5701 "TODO: handle {s} in walkRef",
5702 .{@tagName(ref)},
5703 );
5704 },
5705 .undef => {
5706 return DocData.WalkResult{ .expr = .undefined };
5707 },
5708 .zero => {
5709 return DocData.WalkResult{
5710 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
5711 .expr = .{ .int = .{ .value = 0 } },
5712 };
5713 },
5714 .one => {
5715 return DocData.WalkResult{
5716 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
5717 .expr = .{ .int = .{ .value = 1 } },
5718 };
5719 },
5720 .negative_one => {
5721 return DocData.WalkResult{
5722 .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
5723 .expr = .{ .int = .{ .value = 1, .negated = true } },
5724 };
5725 },
5726 .zero_usize => {
5727 return DocData.WalkResult{
5728 .typeRef = .{ .type = @intFromEnum(Ref.usize_type) },
5729 .expr = .{ .int = .{ .value = 0 } },
5730 };
5731 },
5732 .one_usize => {
5733 return DocData.WalkResult{
5734 .typeRef = .{ .type = @intFromEnum(Ref.usize_type) },
5735 .expr = .{ .int = .{ .value = 1 } },
5736 };
5737 },
5738 .zero_u8 => {
5739 return DocData.WalkResult{
5740 .typeRef = .{ .type = @intFromEnum(Ref.u8_type) },
5741 .expr = .{ .int = .{ .value = 0 } },
5742 };
5743 },
5744 .one_u8 => {
5745 return DocData.WalkResult{
5746 .typeRef = .{ .type = @intFromEnum(Ref.u8_type) },
5747 .expr = .{ .int = .{ .value = 1 } },
5748 };
5749 },
5750 .four_u8 => {
5751 return DocData.WalkResult{
5752 .typeRef = .{ .type = @intFromEnum(Ref.u8_type) },
5753 .expr = .{ .int = .{ .value = 4 } },
5754 };
5755 },
5756
5757 .void_value => {
5758 return DocData.WalkResult{
5759 .typeRef = .{ .type = @intFromEnum(Ref.void_type) },
5760 .expr = .{ .void = .{} },
5761 };
5762 },
5763 .unreachable_value => {
5764 return DocData.WalkResult{
5765 .typeRef = .{ .type = @intFromEnum(Ref.noreturn_type) },
5766 .expr = .{ .@"unreachable" = .{} },
5767 };
5768 },
5769 .null_value => {
5770 return DocData.WalkResult{ .expr = .null };
5771 },
5772 .bool_true => {
5773 return DocData.WalkResult{
5774 .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
5775 .expr = .{ .bool = true },
5776 };
5777 },
5778 .bool_false => {
5779 return DocData.WalkResult{
5780 .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
5781 .expr = .{ .bool = false },
5782 };
5783 },
5784 .empty_struct => {
5785 return DocData.WalkResult{ .expr = .{ .@"struct" = &.{} } };
5786 },
5787 .calling_convention_type => {
5788 return DocData.WalkResult{
5789 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
5790 .expr = .{ .type = @intFromEnum(Ref.calling_convention_type) },
5791 };
5792 },
5793 .calling_convention_c => {
5794 return DocData.WalkResult{
5795 .typeRef = .{ .type = @intFromEnum(Ref.calling_convention_type) },
5796 .expr = .{ .enumLiteral = "C" },
5797 };
5798 },
5799 .calling_convention_inline => {
5800 return DocData.WalkResult{
5801 .typeRef = .{ .type = @intFromEnum(Ref.calling_convention_type) },
5802 .expr = .{ .enumLiteral = "Inline" },
5803 };
5804 },
5805 // .generic_poison => {
5806 // return DocData.WalkResult{ .int = .{
5807 // .type = @intFromEnum(Ref.comptime_int_type),
5808 // .value = 1,
5809 // } };
5810 // },
5811 }
5812 }
5813}
5814
5815fn printWithContext(
5816 file: *File,
5817 inst: Zir.Inst.Index,
5818 comptime fmt: []const u8,
5819 args: anytype,
5820) void {
5821 return printWithOptionalContext(file, inst.toOptional(), fmt, args);
5822}
5823
5824fn printWithOptionalContext(file: *File, inst: Zir.Inst.OptionalIndex, comptime fmt: []const u8, args: anytype) void {
5825 log.debug("Context [{s}] % {} \n " ++ fmt, .{ file.sub_file_path, inst } ++ args);
5826}
5827
5828fn panicWithContext(
5829 file: *File,
5830 inst: Zir.Inst.Index,
5831 comptime fmt: []const u8,
5832 args: anytype,
5833) noreturn {
5834 printWithOptionalContext(file, inst.toOptional(), fmt, args);
5835 unreachable;
5836}
5837
5838fn panicWithOptionalContext(
5839 file: *File,
5840 inst: Zir.Inst.OptionalIndex,
5841 comptime fmt: []const u8,
5842 args: anytype,
5843) noreturn {
5844 printWithOptionalContext(file, inst, fmt, args);
5845 unreachable;
5846}
5847
5848fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResult {
5849 const cte_slot_index = self.comptime_exprs.items.len;
5850 try self.comptime_exprs.append(self.arena, .{
5851 .code = msg,
5852 });
5853 return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
5854}
5855
5856fn writeFileTableToJson(
5857 map: std.AutoArrayHashMapUnmanaged(*File, usize),
5858 mods: std.AutoArrayHashMapUnmanaged(*Module, DocData.DocModule),
5859 jsw: anytype,
5860) !void {
5861 try jsw.beginArray();
5862 var it = map.iterator();
5863 while (it.next()) |entry| {
5864 try jsw.beginArray();
5865 try jsw.write(entry.key_ptr.*.sub_file_path);
5866 try jsw.write(mods.getIndex(entry.key_ptr.*.mod) orelse 0);
5867 try jsw.endArray();
5868 }
5869 try jsw.endArray();
5870}
5871
5872/// Writes the data like so:
5873/// ```
5874/// {
5875/// "<section name>": [{name: "<guide name>", text: "<guide contents>"},],
5876/// }
5877/// ```
5878fn writeGuidesToJson(sections: std.ArrayListUnmanaged(Section), jsw: anytype) !void {
5879 try jsw.beginArray();
5880
5881 for (sections.items) |s| {
5882 // section name
5883 try jsw.beginObject();
5884 try jsw.objectField("name");
5885 try jsw.write(s.name);
5886 try jsw.objectField("guides");
5887
5888 // section value
5889 try jsw.beginArray();
5890 for (s.guides.items) |g| {
5891 try jsw.beginObject();
5892 try jsw.objectField("name");
5893 try jsw.write(g.name);
5894 try jsw.objectField("body");
5895 try jsw.write(g.body);
5896 try jsw.endObject();
5897 }
5898 try jsw.endArray();
5899 try jsw.endObject();
5900 }
5901
5902 try jsw.endArray();
5903}
5904
5905fn writeModuleTableToJson(
5906 map: std.AutoHashMapUnmanaged(*Module, DocData.DocModule.TableEntry),
5907 jsw: anytype,
5908) !void {
5909 try jsw.beginObject();
5910 var it = map.valueIterator();
5911 while (it.next()) |entry| {
5912 try jsw.objectField(entry.name);
5913 try jsw.write(entry.value);
5914 }
5915 try jsw.endObject();
5916}
5917
5918fn srcLocInfo(
5919 self: Autodoc,
5920 file: *File,
5921 src_node: i32,
5922 parent_src: SrcLocInfo,
5923) !SrcLocInfo {
5924 const sn = @as(u32, @intCast(@as(i32, @intCast(parent_src.src_node)) + src_node));
5925 const tree = try file.getTree(self.zcu.gpa);
5926 const node_idx = @as(Ast.Node.Index, @bitCast(sn));
5927 const tokens = tree.nodes.items(.main_token);
5928
5929 const tok_idx = tokens[node_idx];
5930 const start = tree.tokens.items(.start)[tok_idx];
5931 const loc = tree.tokenLocation(parent_src.bytes, tok_idx);
5932 return SrcLocInfo{
5933 .line = parent_src.line + loc.line,
5934 .bytes = start,
5935 .src_node = sn,
5936 };
5937}
5938
5939fn declIsVar(
5940 self: Autodoc,
5941 file: *File,
5942 src_node: i32,
5943 parent_src: SrcLocInfo,
5944) !bool {
5945 const sn = @as(u32, @intCast(@as(i32, @intCast(parent_src.src_node)) + src_node));
5946 const tree = try file.getTree(self.zcu.gpa);
5947 const node_idx = @as(Ast.Node.Index, @bitCast(sn));
5948 const tokens = tree.nodes.items(.main_token);
5949 const tags = tree.tokens.items(.tag);
5950
5951 const tok_idx = tokens[node_idx];
5952
5953 // tags[tok_idx] is the token called 'mut token' in AstGen
5954 return (tags[tok_idx] == .keyword_var);
5955}
5956
5957fn getBlockSource(
5958 self: Autodoc,
5959 file: *File,
5960 parent_src: SrcLocInfo,
5961 block_src_node: i32,
5962) AutodocErrors![]const u8 {
5963 const tree = try file.getTree(self.zcu.gpa);
5964 const block_src = try self.srcLocInfo(file, block_src_node, parent_src);
5965 return tree.getNodeSource(block_src.src_node);
5966}
5967
5968fn getTLDocComment(self: *Autodoc, file: *File) ![]const u8 {
5969 const source = (try file.getSource(self.zcu.gpa)).bytes;
5970 var tokenizer = Tokenizer.init(source);
5971 var tok = tokenizer.next();
5972 var comment = std.ArrayList(u8).init(self.arena);
5973 while (tok.tag == .container_doc_comment) : (tok = tokenizer.next()) {
5974 try comment.appendSlice(source[tok.loc.start + "//!".len .. tok.loc.end + 1]);
5975 }
5976
5977 return comment.items;
5978}
5979
5980/// Returns the doc comment cleared of autodoc directives.
5981fn findGuidePaths(self: *Autodoc, file: *File, str: []const u8) ![]const u8 {
5982 const guide_prefix = "zig-autodoc-guide:";
5983 const section_prefix = "zig-autodoc-section:";
5984
5985 try self.guide_sections.append(self.arena, .{}); // add a default section
5986 var current_section = &self.guide_sections.items[self.guide_sections.items.len - 1];
5987
5988 var clean_docs: std.ArrayListUnmanaged(u8) = .{};
5989 errdefer clean_docs.deinit(self.arena);
5990
5991 // TODO: this algo is kinda inefficient
5992
5993 var it = std.mem.splitScalar(u8, str, '\n');
5994 while (it.next()) |line| {
5995 const trimmed_line = std.mem.trim(u8, line, " ");
5996 if (std.mem.startsWith(u8, trimmed_line, guide_prefix)) {
5997 const path = trimmed_line[guide_prefix.len..];
5998 const trimmed_path = std.mem.trim(u8, path, " ");
5999 try self.addGuide(file, trimmed_path, current_section);
6000 } else if (std.mem.startsWith(u8, trimmed_line, section_prefix)) {
6001 const section_name = trimmed_line[section_prefix.len..];
6002 const trimmed_section_name = std.mem.trim(u8, section_name, " ");
6003 try self.guide_sections.append(self.arena, .{
6004 .name = trimmed_section_name,
6005 });
6006 current_section = &self.guide_sections.items[self.guide_sections.items.len - 1];
6007 } else {
6008 try clean_docs.appendSlice(self.arena, line);
6009 try clean_docs.append(self.arena, '\n');
6010 }
6011 }
6012
6013 return clean_docs.toOwnedSlice(self.arena);
6014}
6015
6016fn addGuide(self: *Autodoc, file: *File, guide_path: []const u8, section: *Section) !void {
6017 if (guide_path.len == 0) return error.MissingAutodocGuideName;
6018
6019 const resolved_path = try std.fs.path.resolve(self.arena, &[_][]const u8{
6020 file.sub_file_path, "..", guide_path,
6021 });
6022
6023 var guide_file = try file.mod.root.openFile(resolved_path, .{});
6024 defer guide_file.close();
6025
6026 const guide = guide_file.reader().readAllAlloc(self.arena, 1 * 1024 * 1024) catch |err| switch (err) {
6027 error.StreamTooLong => @panic("stream too long"),
6028 else => |e| return e,
6029 };
6030
6031 try section.guides.append(self.arena, .{
6032 .name = resolved_path,
6033 .body = guide,
6034 });
6035}
src/Compilation.zig+261-25
......@@ -36,7 +36,6 @@ const Cache = std.Build.Cache;
3636const c_codegen = @import("codegen/c.zig");
3737const libtsan = @import("libtsan.zig");
3838const Zir = std.zig.Zir;
39const Autodoc = @import("Autodoc.zig");
4039const resinator = @import("resinator.zig");
4140const Builtin = @import("Builtin.zig");
4241const LlvmObject = @import("codegen/llvm.zig").Object;
......@@ -734,6 +733,8 @@ pub const MiscTask = enum {
734733 compiler_rt,
735734 zig_libc,
736735 analyze_mod,
736 docs_copy,
737 docs_wasm,
737738
738739 @"musl crti.o",
739740 @"musl crtn.o",
......@@ -2347,10 +2348,6 @@ fn flush(comp: *Compilation, arena: Allocator, prog_node: *std.Progress.Node) !v
23472348 try emitLlvmObject(comp, arena, default_emit, null, llvm_object, prog_node);
23482349 }
23492350 }
2350
2351 if (comp.totalErrorCount() == 0) {
2352 try maybeGenerateAutodocs(comp, prog_node);
2353 }
23542351}
23552352
23562353/// This function is called by the frontend before flush(). It communicates that
......@@ -2401,26 +2398,6 @@ fn renameTmpIntoCache(
24012398 }
24022399}
24032400
2404fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !void {
2405 const mod = comp.module orelse return;
2406 // TODO: do this in a separate job during performAllTheWork(). The
2407 // file copies at the end of generate() can also be extracted to
2408 // separate jobs
2409 if (!build_options.only_c and !build_options.only_core_functionality) {
2410 if (comp.docs_emit) |emit| {
2411 var dir = try emit.directory.handle.makeOpenPath(emit.sub_path, .{});
2412 defer dir.close();
2413
2414 var sub_prog_node = prog_node.start("Generating documentation", 0);
2415 sub_prog_node.activate();
2416 sub_prog_node.context.refresh();
2417 defer sub_prog_node.end();
2418
2419 try Autodoc.generate(mod, dir);
2420 }
2421 }
2422}
2423
24242401/// Communicate the output binary location to parent Compilations.
24252402fn wholeCacheModeSetBinFilePath(
24262403 comp: *Compilation,
......@@ -3346,6 +3323,9 @@ pub fn performAllTheWork(
33463323 var zir_prog_node = main_progress_node.start("AST Lowering", 0);
33473324 defer zir_prog_node.end();
33483325
3326 var wasm_prog_node = main_progress_node.start("Compile Autodocs", 0);
3327 defer wasm_prog_node.end();
3328
33493329 var c_obj_prog_node = main_progress_node.start("Compile C Objects", comp.c_source_files.len);
33503330 defer c_obj_prog_node.end();
33513331
......@@ -3355,6 +3335,13 @@ pub fn performAllTheWork(
33553335 comp.work_queue_wait_group.reset();
33563336 defer comp.work_queue_wait_group.wait();
33573337
3338 if (!build_options.only_c and !build_options.only_core_functionality) {
3339 if (comp.docs_emit != null) {
3340 try taskDocsCopy(comp, &comp.work_queue_wait_group);
3341 comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, &wasm_prog_node });
3342 }
3343 }
3344
33583345 {
33593346 const astgen_frame = tracy.namedFrame("astgen");
33603347 defer astgen_frame.end();
......@@ -3769,6 +3756,255 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
37693756 }
37703757}
37713758
3759fn taskDocsCopy(comp: *Compilation, wg: *WaitGroup) !void {
3760 wg.start();
3761 errdefer wg.finish();
3762 try comp.thread_pool.spawn(workerDocsCopy, .{ comp, wg });
3763}
3764
3765fn workerDocsCopy(comp: *Compilation, wg: *WaitGroup) void {
3766 defer wg.finish();
3767 docsCopyFallible(comp) catch |err| {
3768 return comp.lockAndSetMiscFailure(
3769 .docs_copy,
3770 "unable to copy autodocs artifacts: {s}",
3771 .{@errorName(err)},
3772 );
3773 };
3774}
3775
3776fn docsCopyFallible(comp: *Compilation) anyerror!void {
3777 const emit = comp.docs_emit.?;
3778 var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
3779 return comp.lockAndSetMiscFailure(
3780 .docs_copy,
3781 "unable to create output directory '{}{s}': {s}",
3782 .{ emit.directory, emit.sub_path, @errorName(err) },
3783 );
3784 };
3785 defer out_dir.close();
3786
3787 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {
3788 const basename = std.fs.path.basename(sub_path);
3789 comp.zig_lib_directory.handle.copyFile(sub_path, out_dir, basename, .{}) catch |err| {
3790 comp.lockAndSetMiscFailure(.docs_copy, "unable to copy {s}: {s}", .{
3791 sub_path,
3792 @errorName(err),
3793 });
3794 return;
3795 };
3796 }
3797
3798 var tar_file = out_dir.createFile("sources.tar", .{}) catch |err| {
3799 return comp.lockAndSetMiscFailure(
3800 .docs_copy,
3801 "unable to create '{}{s}/sources.tar': {s}",
3802 .{ emit.directory, emit.sub_path, @errorName(err) },
3803 );
3804 };
3805 defer tar_file.close();
3806
3807 const root = comp.root_mod.root;
3808 const sub_path = if (root.sub_path.len == 0) "." else root.sub_path;
3809 var mod_dir = root.root_dir.handle.openDir(sub_path, .{ .iterate = true }) catch |err| {
3810 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{}': {s}", .{
3811 root, @errorName(err),
3812 });
3813 };
3814 defer mod_dir.close();
3815
3816 var walker = try mod_dir.walk(comp.gpa);
3817 defer walker.deinit();
3818
3819 const padding_buffer = [1]u8{0} ** 512;
3820
3821 while (try walker.next()) |entry| {
3822 switch (entry.kind) {
3823 .file => {
3824 if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue;
3825 if (std.mem.eql(u8, entry.basename, "test.zig")) continue;
3826 if (std.mem.endsWith(u8, entry.basename, "_test.zig")) continue;
3827 },
3828 else => continue,
3829 }
3830
3831 var file = mod_dir.openFile(entry.path, .{}) catch |err| {
3832 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{}{s}': {s}", .{
3833 root, entry.path, @errorName(err),
3834 });
3835 };
3836 defer file.close();
3837
3838 const stat = file.stat() catch |err| {
3839 return comp.lockAndSetMiscFailure(.docs_copy, "unable to stat '{}{s}': {s}", .{
3840 root, entry.path, @errorName(err),
3841 });
3842 };
3843
3844 var file_header = std.tar.output.Header.init();
3845 file_header.typeflag = .regular;
3846 try file_header.setPath(comp.root_name, entry.path);
3847 try file_header.setSize(stat.size);
3848 try file_header.updateChecksum();
3849
3850 const header_bytes = std.mem.asBytes(&file_header);
3851 const padding = p: {
3852 const remainder: u16 = @intCast(stat.size % 512);
3853 const n = if (remainder > 0) 512 - remainder else 0;
3854 break :p padding_buffer[0..n];
3855 };
3856
3857 var header_and_trailer: [2]std.os.iovec_const = .{
3858 .{ .iov_base = header_bytes.ptr, .iov_len = header_bytes.len },
3859 .{ .iov_base = padding.ptr, .iov_len = padding.len },
3860 };
3861
3862 try tar_file.writeFileAll(file, .{
3863 .in_len = stat.size,
3864 .headers_and_trailers = &header_and_trailer,
3865 .header_count = 1,
3866 });
3867 }
3868}
3869
3870fn workerDocsWasm(comp: *Compilation, prog_node: *std.Progress.Node) void {
3871 workerDocsWasmFallible(comp, prog_node) catch |err| {
3872 comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{
3873 @errorName(err),
3874 });
3875 };
3876}
3877
3878fn workerDocsWasmFallible(comp: *Compilation, prog_node: *std.Progress.Node) anyerror!void {
3879 const gpa = comp.gpa;
3880
3881 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
3882 defer arena_allocator.deinit();
3883 const arena = arena_allocator.allocator();
3884
3885 const optimize_mode = std.builtin.OptimizeMode.ReleaseSmall;
3886 const output_mode = std.builtin.OutputMode.Exe;
3887 const resolved_target: Package.Module.ResolvedTarget = .{
3888 .result = std.zig.system.resolveTargetQuery(.{
3889 .cpu_arch = .wasm32,
3890 .os_tag = .freestanding,
3891 .cpu_features_add = std.Target.wasm.featureSet(&.{
3892 .atomics,
3893 .bulk_memory,
3894 // .extended_const, not supported by Safari
3895 .multivalue,
3896 .mutable_globals,
3897 .nontrapping_fptoint,
3898 .reference_types,
3899 //.relaxed_simd, not supported by Firefox or Safari
3900 .sign_ext,
3901 // observed to cause Error occured during wast conversion :
3902 // Unknown operator: 0xfd058 in Firefox 117
3903 //.simd128,
3904 // .tail_call, not supported by Safari
3905 }),
3906 }) catch unreachable,
3907
3908 .is_native_os = false,
3909 .is_native_abi = false,
3910 };
3911
3912 const config = try Config.resolve(.{
3913 .output_mode = output_mode,
3914 .resolved_target = resolved_target,
3915 .is_test = false,
3916 .have_zcu = true,
3917 .emit_bin = true,
3918 .root_optimize_mode = optimize_mode,
3919 .link_libc = false,
3920 .rdynamic = true,
3921 });
3922
3923 const src_basename = "main.zig";
3924 const root_name = std.fs.path.stem(src_basename);
3925
3926 const root_mod = try Package.Module.create(arena, .{
3927 .global_cache_directory = comp.global_cache_directory,
3928 .paths = .{
3929 .root = .{
3930 .root_dir = comp.zig_lib_directory,
3931 .sub_path = "docs/wasm",
3932 },
3933 .root_src_path = src_basename,
3934 },
3935 .fully_qualified_name = root_name,
3936 .inherited = .{
3937 .resolved_target = resolved_target,
3938 .optimize_mode = optimize_mode,
3939 },
3940 .global = config,
3941 .cc_argv = &.{},
3942 .parent = null,
3943 .builtin_mod = null,
3944 .builtin_modules = null, // there is only one module in this compilation
3945 });
3946 const bin_basename = try std.zig.binNameAlloc(arena, .{
3947 .root_name = root_name,
3948 .target = resolved_target.result,
3949 .output_mode = output_mode,
3950 });
3951
3952 const sub_compilation = try Compilation.create(gpa, arena, .{
3953 .global_cache_directory = comp.global_cache_directory,
3954 .local_cache_directory = comp.global_cache_directory,
3955 .zig_lib_directory = comp.zig_lib_directory,
3956 .self_exe_path = comp.self_exe_path,
3957 .config = config,
3958 .root_mod = root_mod,
3959 .entry = .disabled,
3960 .cache_mode = .whole,
3961 .root_name = root_name,
3962 .thread_pool = comp.thread_pool,
3963 .libc_installation = comp.libc_installation,
3964 .emit_bin = .{
3965 .directory = null, // Put it in the cache directory.
3966 .basename = bin_basename,
3967 },
3968 .verbose_cc = comp.verbose_cc,
3969 .verbose_link = comp.verbose_link,
3970 .verbose_air = comp.verbose_air,
3971 .verbose_intern_pool = comp.verbose_intern_pool,
3972 .verbose_generic_instances = comp.verbose_intern_pool,
3973 .verbose_llvm_ir = comp.verbose_llvm_ir,
3974 .verbose_llvm_bc = comp.verbose_llvm_bc,
3975 .verbose_cimport = comp.verbose_cimport,
3976 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
3977 });
3978 defer sub_compilation.destroy();
3979
3980 try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node);
3981
3982 const emit = comp.docs_emit.?;
3983 var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| {
3984 return comp.lockAndSetMiscFailure(
3985 .docs_copy,
3986 "unable to create output directory '{}{s}': {s}",
3987 .{ emit.directory, emit.sub_path, @errorName(err) },
3988 );
3989 };
3990 defer out_dir.close();
3991
3992 sub_compilation.local_cache_directory.handle.copyFile(
3993 sub_compilation.cache_use.whole.bin_sub_path.?,
3994 out_dir,
3995 "main.wasm",
3996 .{},
3997 ) catch |err| {
3998 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{
3999 sub_compilation.local_cache_directory,
4000 sub_compilation.cache_use.whole.bin_sub_path.?,
4001 emit.directory,
4002 emit.sub_path,
4003 @errorName(err),
4004 });
4005 };
4006}
4007
37724008const AstGenSrc = union(enum) {
37734009 root,
37744010 import: struct {
src/autodoc/render_source.zig deleted-435
......@@ -1,435 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const io = std.io;
4const fs = std.fs;
5const process = std.process;
6const ChildProcess = std.ChildProcess;
7const Progress = std.Progress;
8const print = std.debug.print;
9const mem = std.mem;
10const testing = std.testing;
11const Allocator = std.mem.Allocator;
12const Module = @import("../Module.zig");
13
14pub fn genHtml(
15 allocator: Allocator,
16 src: *Module.File,
17 out: anytype,
18) !void {
19 try out.writeAll(
20 \\<!doctype html>
21 \\<html lang="en">
22 \\<head>
23 \\ <meta charset="utf-8">
24 \\ <meta name="viewport" content="width=device-width, initial-scale=1.0">
25 );
26 try out.print(" <title>{s} - source view</title>\n", .{src.sub_file_path});
27 try out.writeAll(
28 \\ <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
29 \\ <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
30 \\ <style>
31 \\ body{
32 \\ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
33 \\ margin: 0;
34 \\ line-height: 1.5;
35 \\ }
36 \\
37 \\ pre > code {
38 \\ display: block;
39 \\ overflow: auto;
40 \\ line-height: normal;
41 \\ margin: 0em;
42 \\ }
43 \\ .tok-kw {
44 \\ color: #333;
45 \\ font-weight: bold;
46 \\ }
47 \\ .tok-str {
48 \\ color: #d14;
49 \\ }
50 \\ .tok-builtin {
51 \\ color: #005C7A;
52 \\ }
53 \\ .tok-comment {
54 \\ color: #545454;
55 \\ font-style: italic;
56 \\ }
57 \\ .tok-fn {
58 \\ color: #900;
59 \\ font-weight: bold;
60 \\ }
61 \\ .tok-null {
62 \\ color: #005C5C;
63 \\ }
64 \\ .tok-number {
65 \\ color: #005C5C;
66 \\ }
67 \\ .tok-type {
68 \\ color: #458;
69 \\ font-weight: bold;
70 \\ }
71 \\ pre {
72 \\ counter-reset: line;
73 \\ }
74 \\ pre .line:before {
75 \\ counter-increment: line;
76 \\ content: counter(line);
77 \\ display: inline-block;
78 \\ padding-right: 1em;
79 \\ width: 2em;
80 \\ text-align: right;
81 \\ color: #999;
82 \\ }
83 \\
84 \\ .line {
85 \\ width: 100%;
86 \\ display: inline-block;
87 \\ }
88 \\ .line:target {
89 \\ border-top: 1px solid #ccc;
90 \\ border-bottom: 1px solid #ccc;
91 \\ background: #fafafa;
92 \\ }
93 \\
94 \\ @media (prefers-color-scheme: dark) {
95 \\ body{
96 \\ background:#222;
97 \\ color: #ccc;
98 \\ }
99 \\ pre > code {
100 \\ color: #ccc;
101 \\ background: #222;
102 \\ border: unset;
103 \\ }
104 \\ .line:target {
105 \\ border-top: 1px solid #444;
106 \\ border-bottom: 1px solid #444;
107 \\ background: #333;
108 \\ }
109 \\ .tok-kw {
110 \\ color: #eee;
111 \\ }
112 \\ .tok-str {
113 \\ color: #2e5;
114 \\ }
115 \\ .tok-builtin {
116 \\ color: #ff894c;
117 \\ }
118 \\ .tok-comment {
119 \\ color: #aa7;
120 \\ }
121 \\ .tok-fn {
122 \\ color: #B1A0F8;
123 \\ }
124 \\ .tok-null {
125 \\ color: #ff8080;
126 \\ }
127 \\ .tok-number {
128 \\ color: #ff8080;
129 \\ }
130 \\ .tok-type {
131 \\ color: #68f;
132 \\ }
133 \\ }
134 \\ </style>
135 \\</head>
136 \\<body>
137 \\
138 );
139
140 const source = try src.getSource(allocator);
141 try tokenizeAndPrintRaw(out, source.bytes);
142 try out.writeAll(
143 \\</body>
144 \\</html>
145 );
146}
147
148const start_line = "<span class=\"line\" id=\"L{d}\">";
149const end_line = "</span>\n";
150
151var line_counter: usize = 1;
152
153pub fn tokenizeAndPrintRaw(
154 out: anytype,
155 src: [:0]const u8,
156) !void {
157 line_counter = 1;
158
159 try out.print("<pre><code>" ++ start_line, .{line_counter});
160 var tokenizer = std.zig.Tokenizer.init(src);
161 var index: usize = 0;
162 var next_tok_is_fn = false;
163 while (true) {
164 const prev_tok_was_fn = next_tok_is_fn;
165 next_tok_is_fn = false;
166
167 const token = tokenizer.next();
168 if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| {
169 // render one comment
170 const comment_start = index + comment_start_off;
171 const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n");
172 const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start;
173
174 try writeEscapedLines(out, src[index..comment_start]);
175 try out.writeAll("<span class=\"tok-comment\">");
176 try writeEscaped(out, src[comment_start..comment_end]);
177 try out.writeAll("</span>\n");
178 index = comment_end;
179 tokenizer.index = index;
180 continue;
181 }
182
183 try writeEscapedLines(out, src[index..token.loc.start]);
184 switch (token.tag) {
185 .eof => break,
186
187 .keyword_addrspace,
188 .keyword_align,
189 .keyword_and,
190 .keyword_asm,
191 .keyword_async,
192 .keyword_await,
193 .keyword_break,
194 .keyword_catch,
195 .keyword_comptime,
196 .keyword_const,
197 .keyword_continue,
198 .keyword_defer,
199 .keyword_else,
200 .keyword_enum,
201 .keyword_errdefer,
202 .keyword_error,
203 .keyword_export,
204 .keyword_extern,
205 .keyword_for,
206 .keyword_if,
207 .keyword_inline,
208 .keyword_noalias,
209 .keyword_noinline,
210 .keyword_nosuspend,
211 .keyword_opaque,
212 .keyword_or,
213 .keyword_orelse,
214 .keyword_packed,
215 .keyword_anyframe,
216 .keyword_pub,
217 .keyword_resume,
218 .keyword_return,
219 .keyword_linksection,
220 .keyword_callconv,
221 .keyword_struct,
222 .keyword_suspend,
223 .keyword_switch,
224 .keyword_test,
225 .keyword_threadlocal,
226 .keyword_try,
227 .keyword_union,
228 .keyword_unreachable,
229 .keyword_usingnamespace,
230 .keyword_var,
231 .keyword_volatile,
232 .keyword_allowzero,
233 .keyword_while,
234 .keyword_anytype,
235 => {
236 try out.writeAll("<span class=\"tok-kw\">");
237 try writeEscaped(out, src[token.loc.start..token.loc.end]);
238 try out.writeAll("</span>");
239 },
240
241 .keyword_fn => {
242 try out.writeAll("<span class=\"tok-kw\">");
243 try writeEscaped(out, src[token.loc.start..token.loc.end]);
244 try out.writeAll("</span>");
245 next_tok_is_fn = true;
246 },
247
248 .string_literal,
249 .char_literal,
250 => {
251 try out.writeAll("<span class=\"tok-str\">");
252 try writeEscaped(out, src[token.loc.start..token.loc.end]);
253 try out.writeAll("</span>");
254 },
255
256 .multiline_string_literal_line => {
257 if (src[token.loc.end - 1] == '\n') {
258 try out.writeAll("<span class=\"tok-str\">");
259 try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]);
260 line_counter += 1;
261 try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter});
262 } else {
263 try out.writeAll("<span class=\"tok-str\">");
264 try writeEscaped(out, src[token.loc.start..token.loc.end]);
265 try out.writeAll("</span>");
266 }
267 },
268
269 .builtin => {
270 try out.writeAll("<span class=\"tok-builtin\">");
271 try writeEscaped(out, src[token.loc.start..token.loc.end]);
272 try out.writeAll("</span>");
273 },
274
275 .doc_comment,
276 .container_doc_comment,
277 => {
278 try out.writeAll("<span class=\"tok-comment\">");
279 try writeEscaped(out, src[token.loc.start..token.loc.end]);
280 try out.writeAll("</span>");
281 },
282
283 .identifier => {
284 const tok_bytes = src[token.loc.start..token.loc.end];
285 if (mem.eql(u8, tok_bytes, "undefined") or
286 mem.eql(u8, tok_bytes, "null") or
287 mem.eql(u8, tok_bytes, "true") or
288 mem.eql(u8, tok_bytes, "false"))
289 {
290 try out.writeAll("<span class=\"tok-null\">");
291 try writeEscaped(out, tok_bytes);
292 try out.writeAll("</span>");
293 } else if (prev_tok_was_fn) {
294 try out.writeAll("<span class=\"tok-fn\">");
295 try writeEscaped(out, tok_bytes);
296 try out.writeAll("</span>");
297 } else {
298 const is_int = blk: {
299 if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u')
300 break :blk false;
301 var i = token.loc.start + 1;
302 if (i == token.loc.end)
303 break :blk false;
304 while (i != token.loc.end) : (i += 1) {
305 if (src[i] < '0' or src[i] > '9')
306 break :blk false;
307 }
308 break :blk true;
309 };
310 if (is_int or isType(tok_bytes)) {
311 try out.writeAll("<span class=\"tok-type\">");
312 try writeEscaped(out, tok_bytes);
313 try out.writeAll("</span>");
314 } else {
315 try writeEscaped(out, tok_bytes);
316 }
317 }
318 },
319
320 .number_literal => {
321 try out.writeAll("<span class=\"tok-number\">");
322 try writeEscaped(out, src[token.loc.start..token.loc.end]);
323 try out.writeAll("</span>");
324 },
325
326 .bang,
327 .pipe,
328 .pipe_pipe,
329 .pipe_equal,
330 .equal,
331 .equal_equal,
332 .equal_angle_bracket_right,
333 .bang_equal,
334 .l_paren,
335 .r_paren,
336 .semicolon,
337 .percent,
338 .percent_equal,
339 .l_brace,
340 .r_brace,
341 .l_bracket,
342 .r_bracket,
343 .period,
344 .period_asterisk,
345 .ellipsis2,
346 .ellipsis3,
347 .caret,
348 .caret_equal,
349 .plus,
350 .plus_plus,
351 .plus_equal,
352 .plus_percent,
353 .plus_percent_equal,
354 .plus_pipe,
355 .plus_pipe_equal,
356 .minus,
357 .minus_equal,
358 .minus_percent,
359 .minus_percent_equal,
360 .minus_pipe,
361 .minus_pipe_equal,
362 .asterisk,
363 .asterisk_equal,
364 .asterisk_asterisk,
365 .asterisk_percent,
366 .asterisk_percent_equal,
367 .asterisk_pipe,
368 .asterisk_pipe_equal,
369 .arrow,
370 .colon,
371 .slash,
372 .slash_equal,
373 .comma,
374 .ampersand,
375 .ampersand_equal,
376 .question_mark,
377 .angle_bracket_left,
378 .angle_bracket_left_equal,
379 .angle_bracket_angle_bracket_left,
380 .angle_bracket_angle_bracket_left_equal,
381 .angle_bracket_angle_bracket_left_pipe,
382 .angle_bracket_angle_bracket_left_pipe_equal,
383 .angle_bracket_right,
384 .angle_bracket_right_equal,
385 .angle_bracket_angle_bracket_right,
386 .angle_bracket_angle_bracket_right_equal,
387 .tilde,
388 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
389
390 .invalid, .invalid_periodasterisks => return error.ParseError,
391 }
392 index = token.loc.end;
393 }
394 try out.writeAll(end_line ++ "</code></pre>");
395}
396
397fn writeEscapedLines(out: anytype, text: []const u8) !void {
398 for (text) |char| {
399 if (char == '\n') {
400 try out.writeAll(end_line);
401 line_counter += 1;
402 try out.print(start_line, .{line_counter});
403 } else {
404 try writeEscaped(out, &[_]u8{char});
405 }
406 }
407}
408
409fn writeEscaped(out: anytype, input: []const u8) !void {
410 for (input) |c| {
411 try switch (c) {
412 '&' => out.writeAll("&amp;"),
413 '<' => out.writeAll("&lt;"),
414 '>' => out.writeAll("&gt;"),
415 '"' => out.writeAll("&quot;"),
416 else => out.writeByte(c),
417 };
418 }
419}
420
421const builtin_types = [_][]const u8{
422 "f16", "f32", "f64", "f80", "f128",
423 "c_longdouble", "c_short", "c_ushort", "c_int", "c_uint",
424 "c_long", "c_ulong", "c_longlong", "c_ulonglong", "c_char",
425 "anyopaque", "void", "bool", "isize", "usize",
426 "noreturn", "type", "anyerror", "comptime_int", "comptime_float",
427};
428
429fn isType(name: []const u8) bool {
430 for (builtin_types) |t| {
431 if (mem.eql(u8, t, name))
432 return true;
433 }
434 return false;
435}
src/main.zig+15
......@@ -98,6 +98,7 @@ const normal_usage =
9898 \\
9999 \\ env Print lib path, std path, cache directory, and version
100100 \\ help Print this help and exit
101 \\ std View standard library documentation in a browser
101102 \\ libc Display native libc paths file or validate one
102103 \\ targets List available compilation targets
103104 \\ version Print version number and exit
......@@ -309,6 +310,14 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
309310 .root_src_path = "libc.zig",
310311 .prepend_zig_lib_dir_path = true,
311312 });
313 } else if (mem.eql(u8, cmd, "std")) {
314 return jitCmd(gpa, arena, cmd_args, .{
315 .cmd_name = "std",
316 .root_src_path = "std-docs.zig",
317 .prepend_zig_lib_dir_path = true,
318 .prepend_zig_exe_path = true,
319 .prepend_global_cache_path = true,
320 });
312321 } else if (mem.eql(u8, cmd, "init")) {
313322 return cmdInit(gpa, arena, cmd_args);
314323 } else if (mem.eql(u8, cmd, "targets")) {
......@@ -5556,6 +5565,8 @@ const JitCmdOptions = struct {
55565565 cmd_name: []const u8,
55575566 root_src_path: []const u8,
55585567 prepend_zig_lib_dir_path: bool = false,
5568 prepend_global_cache_path: bool = false,
5569 prepend_zig_exe_path: bool = false,
55595570 depend_on_aro: bool = false,
55605571 capture: ?*[]u8 = null,
55615572};
......@@ -5714,6 +5725,10 @@ fn jitCmd(
57145725
57155726 if (options.prepend_zig_lib_dir_path)
57165727 child_argv.appendAssumeCapacity(zig_lib_directory.path.?);
5728 if (options.prepend_zig_exe_path)
5729 child_argv.appendAssumeCapacity(self_exe_path);
5730 if (options.prepend_global_cache_path)
5731 child_argv.appendAssumeCapacity(global_cache_directory.path.?);
57175732
57185733 child_argv.appendSliceAssumeCapacity(args);
57195734