diff --git a/lib/docs/index.html b/lib/docs/index.html index d5148e3aab..5db9a2c694 100644 --- a/lib/docs/index.html +++ b/lib/docs/index.html @@ -297,6 +297,13 @@ overflow-x: auto; } + .docs pre.inline { + background-color: var(--bg-color); + padding: 0; + display: inline; + } + + .docs code { font-family: var(--mono); font-size: 1em; @@ -685,15 +692,23 @@ diff --git a/lib/docs/main.js b/lib/docs/main.js index 725fe145ee..dec6bf85cc 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -7,7 +7,7 @@ const NAV_MODES = { GUIDES: "#G;", }; -(function () { +(function() { const domBanner = document.getElementById("banner"); const domMain = document.getElementById("main"); const domStatus = document.getElementById("status"); @@ -59,7 +59,7 @@ const NAV_MODES = { const domDocs = document.getElementById("docs"); const domGuidesSection = document.getElementById("guides"); const domActiveGuide = document.getElementById("activeGuide"); - + const domListSearchResults = document.getElementById("listSearchResults"); const domSectSearchNoResults = document.getElementById("sectSearchNoResults"); const domSectInfo = document.getElementById("sectInfo"); @@ -133,7 +133,7 @@ const NAV_MODES = { // map of decl index to list of comptime fn calls // let nodesToCallsMap = indexNodesToCalls(); - let guidesSearchIndex = {}; + let guidesSearchIndex = {}; window.guideSearch = guidesSearchIndex; parseGuides(); @@ -248,7 +248,7 @@ const NAV_MODES = { } else if (type.kind === typeKinds.Union) { name = "union"; } else { - console.log("TODO: unhalndled case in typeShortName"); + console.log("TODO: unhandled case in typeShortName"); return null; } @@ -313,8 +313,8 @@ const NAV_MODES = { function resolveGenericRet(genericFunc) { if (genericFunc.generic_ret == null) return null; - let result = resolveValue({expr: genericFunc.generic_ret}); - + let result = resolveValue({ expr: genericFunc.generic_ret }); + let i = 0; while (true) { i += 1; @@ -437,32 +437,32 @@ const NAV_MODES = { const section_list = zigAnalysis.guide_sections; resizeDomList(domGuidesList, section_list.length, '

'); for (let j = 0; j < section_list.length; j += 1) { - const section = section_list[j]; - const domSectionName = domGuidesList.children[j].children[0].children[0]; - const domGuides = domGuidesList.children[j].children[1]; - domSectionName.textContent = section.name; - resizeDomList(domGuides, section.guides.length, '
  • '); - for (let i = 0; i < section.guides.length; i += 1) { - const guide = section.guides[i]; - let liDom = domGuides.children[i]; - let aDom = liDom.children[0]; - aDom.textContent = guide.title; - aDom.setAttribute("href", NAV_MODES.GUIDES + guide.name); - if (guide.name === curNav.activeGuide) { - aDom.classList.add("active"); - } else { - aDom.classList.remove("active"); - } + const section = section_list[j]; + const domSectionName = domGuidesList.children[j].children[0].children[0]; + const domGuides = domGuidesList.children[j].children[1]; + domSectionName.textContent = section.name; + resizeDomList(domGuides, section.guides.length, '
  • '); + for (let i = 0; i < section.guides.length; i += 1) { + const guide = section.guides[i]; + let liDom = domGuides.children[i]; + let aDom = liDom.children[0]; + aDom.textContent = guide.title; + aDom.setAttribute("href", NAV_MODES.GUIDES + guide.name); + if (guide.name === curNav.activeGuide) { + aDom.classList.add("active"); + } else { + aDom.classList.remove("active"); } + } } - + if (section_list.length > 0) { domGuidesMenu.classList.remove("hidden"); } - + if (curNavSearch !== "") { - return renderSearchGuides(); + return renderSearchGuides(); } // main content @@ -476,8 +476,8 @@ const NAV_MODES = { break outer; } } - } - + } + if (activeGuide == undefined) { const root_file_idx = zigAnalysis.modules[zigAnalysis.rootMod].file; const root_file_name = getFile(root_file_idx).name; @@ -564,7 +564,7 @@ Happy writing! renderModList(); if (curNavSearch !== "") { - return renderSearchAPI(); + return renderSearchAPI(); } let rootMod = zigAnalysis.modules[zigAnalysis.rootMod]; @@ -660,7 +660,8 @@ Happy writing! if (!decl.decltest) return; const astNode = getAstNode(decl.decltest); domSectDocTests.classList.remove("hidden"); - domDocTestsCode.innerHTML = generate_html_for_src(astNode.code); + domDocTestsCode.innerHTML = renderTokens( + DecoratedTokenizer(astNode.code, decl)); } function renderUnknownDecl(decl) { @@ -707,11 +708,7 @@ Happy writing! console.assert("type" in value.expr); let typeObj = getType(value.expr.type); - domFnProtoCode.innerHTML = exprName(value.expr, { - wantHtml: true, - wantLink: true, - fnDecl, - }); + domFnProtoCode.innerHTML = renderTokens(ex(value.expr, { fnDecl: fnDecl })); domFnSourceLink.innerHTML = "[src]"; @@ -840,15 +837,21 @@ Happy writing! let value = typeObj.params[i]; let preClass = docsNonEmpty ? ' class="fieldHasDocs"' : ""; - let html = "" + escapeHtml(fieldNode.name) + ": "; - if (isVarArgs && i === typeObj.params.length - 1) { - html += "..."; - } else { - let name = exprName(value, { wantHtml: false, wantLink: false }); - html += '' + name + ""; - } + let html = "" + renderTokens((function*() { + yield Tok.identifier(fieldNode.name); + yield Tok.colon; + yield Tok.space; + if (isVarArgs && i === typeObj.params.length - 1) { + yield Tok.period; + yield Tok.period; + yield Tok.period; + } else { + yield* ex(value, {}); + } + yield Tok.comma; + }())); - html += ","; + html += ""; if (docsNonEmpty) { html += '
    ' + markdown(docs) + "
    "; @@ -932,7 +935,7 @@ Happy writing! domSectMainMod.classList.remove("hidden"); } - list.sort(function (a, b) { + list.sort(function(a, b) { return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase()); }); @@ -1054,823 +1057,578 @@ Happy writing! return walkResultTypeRef(resolved); } - function exprName(expr, opts) { + function* DecoratedTokenizer(src, context) { + let tok_it = Tokenizer(src); + for (let t of tok_it) { + if (t.tag == Tag.identifier) { + const link = detectDeclPath(t.src, context); + if (link) { + t.link = link; + } + } + + yield t; + } + } + + + function renderSingleToken(t) { + + if (t.tag == Tag.whitespace) { + return t.src; + } + + let src = t.src; + // if (t.tag == Tag.identifier) { + // src = escapeHtml(src); + // } + let result = ""; + if (t.tag == Tag.identifier && isSimpleType(t.src)) { + result = `${src}`; + } else if (t.tag == Tag.identifier && isSpecialIndentifier(t.src)) { + result = `${src}`; + } else if (t.tag == Tag.identifier && t.fnDecl) { + result = `${src}`; + } else { + result = `${src}`; + } + + if (t.link) { + result = `` + result + ""; + } + + return result; + } + + function renderTokens(tok_it) { + var html = []; + + const max_iter = 100000; + let i = 0; + for (const t of tok_it) { + i += 1; + if (i > max_iter) + throw "too many iterations"; + + if (t.tag == Tag.eof) + break; + + html.push(renderSingleToken(t)); + } + + return html.join(""); + } + + function* ex(expr, opts) { switch (Object.keys(expr)[0]) { default: - throw "this expression is not implemented yet"; - case "bool": { - if (expr.bool) { - return "true"; + throw "this expression is not implemented yet: " + Object.keys(expr)[0]; + case "comptimeExpr": { + const src = zigAnalysis.comptimeExprs[expr.comptimeExpr].code; + yield* DecoratedTokenizer(src); + return; + } + case "declName": { + yield { src: expr.declName, tag: Tag.identifier }; + return; + } + case "declRef": { + const name = getDecl(expr.declRef).name; + const canonPath = getCanonDeclPath(expr.declRef); + if (canonPath) { + const link = navLink(canonPath.modNames, canonPath.declNames); + yield { src: name, tag: Tag.identifier, link }; + } else { + yield { src: name, tag: Tag.identifier }; } - return "false"; + return; } - case "&": { - return "&" + exprName(zigAnalysis.exprs[expr["&"]], opts); - } - case "compileError": { - let compileError = expr.compileError; - return "@compileError(" + exprName(zigAnalysis.exprs[compileError], opts) + ")"; - } - case "enumLiteral": { - let literal = expr.enumLiteral; - return "." + literal; - } - case "void": { - return "void"; - } - case "unreachable": { - return "unreachable"; - } - case "slice": { - let payloadHtml = ""; - const lhsExpr = zigAnalysis.exprs[expr.slice.lhs]; - const startExpr = zigAnalysis.exprs[expr.slice.start]; - let decl = exprName(lhsExpr, opts); - let start = exprName(startExpr, opts); - let end = ""; - let sentinel = ""; - if (expr.slice["end"]) { - const endExpr = zigAnalysis.exprs[expr.slice.end]; - let end_ = exprName(endExpr, opts); - end += end_; + case "refPath": { + for (let i = 0; i < expr.refPath.length; i += 1) { + if (i > 0) yield Tok.period; + yield* ex(expr.refPath[i]); } - if (expr.slice["sentinel"]) { - const sentinelExpr = zigAnalysis.exprs[expr.slice.sentinel]; - let sentinel_ = exprName(sentinelExpr, opts); - sentinel += " :" + sentinel_; - } - payloadHtml += decl + "[" + start + ".." + end + sentinel + "]"; - return payloadHtml; - } - case "sliceLength": { - let payloadHtml = ""; - const lhsExpr = zigAnalysis.exprs[expr.sliceLength.lhs]; - const startExpr = zigAnalysis.exprs[expr.sliceLength.start]; - const lenExpr = zigAnalysis.exprs[expr.sliceLength.len]; - let decl = exprName(lhsExpr, opts); - let start = exprName(startExpr, opts); - let len = exprName(lenExpr, opts); - let sentinel = ""; - if (expr.sliceLength["sentinel"]) { - const sentinelExpr = zigAnalysis.exprs[expr.sliceLength.sentinel]; - let sentinel_ = exprName(sentinelExpr, options); - sentinel += " :" + sentinel_; - } - payloadHtml += decl + "[" + start + "..][0.." + len + sentinel + "]"; - return payloadHtml; - } - case "sliceIndex": { - const sliceIndex = zigAnalysis.exprs[expr.sliceIndex]; - return exprName(sliceIndex, opts, opts); - } - case "cmpxchg": { - const typeIndex = zigAnalysis.exprs[expr.cmpxchg.type]; - const ptrIndex = zigAnalysis.exprs[expr.cmpxchg.ptr]; - const expectedValueIndex = - zigAnalysis.exprs[expr.cmpxchg.expected_value]; - const newValueIndex = zigAnalysis.exprs[expr.cmpxchg.new_value]; - const successOrderIndex = zigAnalysis.exprs[expr.cmpxchg.success_order]; - const failureOrderIndex = zigAnalysis.exprs[expr.cmpxchg.failure_order]; - - const type = exprName(typeIndex, opts); - const ptr = exprName(ptrIndex, opts); - const expectedValue = exprName(expectedValueIndex, opts); - const newValue = exprName(newValueIndex, opts); - const successOrder = exprName(successOrderIndex, opts); - const failureOrder = exprName(failureOrderIndex, opts); - - let fnName = "@"; - - switch (expr.cmpxchg.name) { - case "cmpxchg_strong": { - fnName += "cmpxchgStrong"; - break; - } - case "cmpxchg_weak": { - fnName += "cmpxchgWeak"; - break; - } - default: { - console.log("There's only cmpxchg_strong and cmpxchg_weak"); - } - } - - return ( - fnName + - "(" + - type + - ", " + - ptr + - ", " + - expectedValue + - ", " + - newValue + - ", " + - "." + - successOrder + - ", " + - "." + - failureOrder + - ")" - ); - } - case "cmpxchgIndex": { - const cmpxchgIndex = zigAnalysis.exprs[expr.cmpxchgIndex]; - return exprName(cmpxchgIndex, opts); - } - case "switchOp": { - let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index]; - let ast = getAstNode(expr.switchOp.src); - let file_name = expr.switchOp.file_name; - let outer_decl_index = expr.switchOp.outer_decl; - let outer_decl = getType(outer_decl_index); - let line = 0; - // console.log(expr.switchOp) - // console.log(outer_decl) - while (outer_decl_index !== 0 && outer_decl.line_number > 0) { - line += outer_decl.line_number; - outer_decl_index = outer_decl.outer_decl; - outer_decl = getType(outer_decl_index); - // console.log(outer_decl) - } - line += ast.line + 1; - let payloadHtml = ""; - let cond = exprName(condExpr, opts); - - payloadHtml += - "
    " + - "node_name: " + - ast.name + - "
    " + - "file: " + - file_name + - "
    " + - "line: " + - line + - "
    "; - payloadHtml += - "switch(" + - cond + - ") {" + - '' + - "..." + - "}"; - return payloadHtml; - } - case "switchIndex": { - const switchIndex = zigAnalysis.exprs[expr.switchIndex]; - return exprName(switchIndex, opts); + return; } case "fieldRef": { const field_idx = expr.fieldRef.index; const type = getType(expr.fieldRef.type); const field = getAstNode(type.src).fields[field_idx]; const name = getAstNode(field).name; - return name; + yield { src: name, tag: Tag.identifier }; + return; } - case "intFromEnum": { - const intFromEnum = zigAnalysis.exprs[expr.intFromEnum]; - return "@intFromEnum(" + exprName(intFromEnum, opts) + ")"; - } - case "bitSizeOf": { - const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf]; - return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")"; - } - case "sizeOf": { - const sizeOf = zigAnalysis.exprs[expr.sizeOf]; - return "@sizeOf(" + exprName(sizeOf, opts) + ")"; - } - case "builtinIndex": { - const builtinIndex = zigAnalysis.exprs[expr.builtinIndex]; - return exprName(builtinIndex, opts); - } - case "builtin": { - const param_expr = zigAnalysis.exprs[expr.builtin.param]; - let param = exprName(param_expr, opts); - - let payloadHtml = "@"; - switch (expr.builtin.name) { - case "align_of": { - payloadHtml += "alignOf"; - break; - } - case "int_from_bool": { - payloadHtml += "intFromBool"; - break; - } - case "embed_file": { - payloadHtml += "embedFile"; - break; - } - case "error_name": { - payloadHtml += "errorName"; - break; - } - case "panic": { - payloadHtml += "panic"; - break; - } - case "set_runtime_safety": { - payloadHtml += "setRuntimeSafety"; - break; - } - case "sqrt": { - payloadHtml += "sqrt"; - break; - } - case "sin": { - payloadHtml += "sin"; - break; - } - case "cos": { - payloadHtml += "cos"; - break; - } - case "tan": { - payloadHtml += "tan"; - break; - } - case "exp": { - payloadHtml += "exp"; - break; - } - case "exp2": { - payloadHtml += "exp2"; - break; - } - case "log": { - payloadHtml += "log"; - break; - } - case "log2": { - payloadHtml += "log2"; - break; - } - case "log10": { - payloadHtml += "log10"; - break; - } - case "fabs": { - payloadHtml += "fabs"; - break; - } - case "floor": { - payloadHtml += "floor"; - break; - } - case "ceil": { - payloadHtml += "ceil"; - break; - } - case "trunc": { - payloadHtml += "trunc"; - break; - } - case "round": { - payloadHtml += "round"; - break; - } - case "tag_name": { - payloadHtml += "tagName"; - break; - } - case "reify": { - payloadHtml += "Type"; - break; - } - case "type_name": { - payloadHtml += "typeName"; - break; - } - case "frame_type": { - payloadHtml += "Frame"; - break; - } - case "frame_size": { - payloadHtml += "frameSize"; - break; - } - case "work_item_id": { - payloadHtml += "workItemId"; - break; - } - case "work_group_size": { - payloadHtml += "workGroupSize"; - break; - } - case "work_group_id": { - payloadHtml += "workGroupId"; - break; - } - case "int_from_ptr": { - payloadHtml += "intFromPtr"; - break; - } - case "int_from_error": { - payloadHtml += "intFromError"; - break; - } - case "error_to_int": { - payloadHtml += "errorFromInt"; - break; - } - case "max": { - payloadHtml += "max"; - break; - } - case "min": { - payloadHtml += "min"; - break; - } - case "bit_not": { - return "~" + param; - } - case "bool_not": { - return "!" + param; - } - case "clz": { - return "@clz(T" + ", " + param + ")"; - } - case "ctz": { - return "@ctz(T" + ", " + param + ")"; - } - case "pop_count": { - return "@popCount(T" + ", " + param + ")"; - } - case "byte_swap": { - return "@byteSwap(T" + ", " + param + ")"; - } - case "bit_reverse": { - return "@bitReverse(T" + ", " + param + ")"; - } - case "truncate": { - return "@truncate(" + param + ")"; - } - default: - console.log("builtin function not handled yet or doesn't exist!"); + case "bool": { + if (expr.bool) { + yield { src: "true", tag: Tag.identifier }; + return; } - return payloadHtml + "(" + param + ")"; + yield { src: "false", tag: Tag.identifier }; + return; } - case "builtinBinIndex": { - const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex]; - return exprName(builtinBinIndex, opts); - } - case "builtinBin": { - const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs]; - const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs]; - let lhs = exprName(lhsOp, opts); - let rhs = exprName(rhsOp, opts); - - let payloadHtml = "@"; - switch (expr.builtinBin.name) { - case "int_from_float": { - payloadHtml += "intFromFloat"; - break; - } - case "float_from_int": { - payloadHtml += "floatFromInt"; - break; - } - case "ptr_from_int": { - payloadHtml += "ptrFromInt"; - break; - } - case "enum_from_int": { - payloadHtml += "enumFromInt"; - break; - } - case "float_cast": { - payloadHtml += "floatCast"; - break; - } - case "int_cast": { - payloadHtml += "intCast"; - break; - } - case "ptr_cast": { - payloadHtml += "ptrCast"; - break; - } - case "const_cast": { - payloadHtml += "constCast"; - break; - } - case "volatile_cast": { - payloadHtml += "volatileCast"; - break; - } - case "truncate": { - payloadHtml += "truncate"; - break; - } - case "has_decl": { - payloadHtml += "hasDecl"; - break; - } - case "has_field": { - payloadHtml += "hasField"; - break; - } - case "bit_reverse": { - payloadHtml += "bitReverse"; - break; - } - case "div_exact": { - payloadHtml += "divExact"; - break; - } - case "div_floor": { - payloadHtml += "divFloor"; - break; - } - case "div_trunc": { - payloadHtml += "divTrunc"; - break; - } - case "mod": { - payloadHtml += "mod"; - break; - } - case "rem": { - payloadHtml += "rem"; - break; - } - case "mod_rem": { - payloadHtml += "rem"; - break; - } - case "shl_exact": { - payloadHtml += "shlExact"; - break; - } - case "shr_exact": { - payloadHtml += "shrExact"; - break; - } - case "bitcast": { - payloadHtml += "bitCast"; - break; - } - case "align_cast": { - payloadHtml += "alignCast"; - break; - } - case "vector_type": { - payloadHtml += "Vector"; - break; - } - case "reduce": { - payloadHtml += "reduce"; - break; - } - case "splat": { - payloadHtml += "splat"; - break; - } - case "offset_of": { - payloadHtml += "offsetOf"; - break; - } - case "bit_offset_of": { - payloadHtml += "bitOffsetOf"; - break; - } - default: - console.log("builtin function not handled yet or doesn't exist!"); - } - return payloadHtml + "(" + lhs + ", " + rhs + ")"; - } - case "binOpIndex": { - const binOpIndex = zigAnalysis.exprs[expr.binOpIndex]; - return exprName(binOpIndex, opts); - } - case "binOp": { - const lhsOp = zigAnalysis.exprs[expr.binOp.lhs]; - const rhsOp = zigAnalysis.exprs[expr.binOp.rhs]; - let lhs = exprName(lhsOp, opts); - let rhs = exprName(rhsOp, opts); - - let print_lhs = ""; - let print_rhs = ""; - - if (lhsOp["binOpIndex"]) { - print_lhs = "(" + lhs + ")"; - } else { - print_lhs = lhs; - } - if (rhsOp["binOpIndex"]) { - print_rhs = "(" + rhs + ")"; - } else { - print_rhs = rhs; - } - - let operator = ""; - - switch (expr.binOp.name) { - case "add": { - operator += "+"; - break; - } - case "addwrap": { - operator += "+%"; - break; - } - case "add_sat": { - operator += "+|"; - break; - } - case "sub": { - operator += "-"; - break; - } - case "subwrap": { - operator += "-%"; - break; - } - case "sub_sat": { - operator += "-|"; - break; - } - case "mul": { - operator += "*"; - break; - } - case "mulwrap": { - operator += "*%"; - break; - } - case "mul_sat": { - operator += "*|"; - break; - } - case "div": { - operator += "/"; - break; - } - case "shl": { - operator += "<<"; - break; - } - case "shl_sat": { - operator += "<<|"; - break; - } - case "shr": { - operator += ">>"; - break; - } - case "bit_or": { - operator += "|"; - break; - } - case "bit_and": { - operator += "&"; - break; - } - case "array_cat": { - operator += "++"; - break; - } - case "array_mul": { - operator += "**"; - break; - } - case "cmp_eq": { - operator += "=="; - break; - } - case "cmp_neq": { - operator += "!="; - break; - } - case "cmp_gt": { - operator += ">"; - break; - } - case "cmp_gte": { - operator += ">="; - break; - } - case "cmp_lt": { - operator += "<"; - break; - } - case "cmp_lte": { - operator += "<="; - break; - } - case "bool_br_and": { - operator += "and"; - break; - } - case "bool_br_or": { - operator += "or"; - break; - } - default: - console.log("operator not handled yet or doesn't exist!"); - } - - return print_lhs + " " + operator + " " + print_rhs; - } - case "errorSets": { - const errUnionObj = getType(expr.errorSets); - let lhs = exprName(errUnionObj.lhs, opts); - let rhs = exprName(errUnionObj.rhs, opts); - return lhs + " || " + rhs; - } - case "errorUnion": { - const errUnionObj = getType(expr.errorUnion); - let lhs = exprName(errUnionObj.lhs, opts); - let rhs = exprName(errUnionObj.rhs, opts); - return lhs + "!" + rhs; - } - case "struct": { - // const struct_name = - // zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name; - const struct_name = "."; - let struct_body = ""; - struct_body += struct_name + "{ "; - for (let i = 0; i < expr.struct.length; i++) { - const fv = expr.struct[i]; - const field_name = fv.name; - const field_value = exprName(fv.val.expr, opts); - // TODO: commented out because it seems not needed. if it deals - // with a corner case, please add a comment when re-enabling it. - // let field_value = exprArg[Object.keys(exprArg)[0]]; - // if (field_value instanceof Object) { - // value_field = exprName(value_field) - // zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef] - // .name; - // } - struct_body += "." + field_name + " = " + field_value; - if (i !== expr.struct.length - 1) { - struct_body += ", "; - } else { - struct_body += " "; - } - } - struct_body += "}"; - return struct_body; - } - case "typeOf_peer": { - let payloadHtml = "@TypeOf("; - for (let i = 0; i < expr.typeOf_peer.length; i++) { - let elem = zigAnalysis.exprs[expr.typeOf_peer[i]]; - payloadHtml += exprName(elem, { wantHtml: true, wantLink: true }); - if (i !== expr.typeOf_peer.length - 1) { - payloadHtml += ", "; - } - } - payloadHtml += ")"; - return payloadHtml; - } - case "alignOf": { - const alignRefArg = zigAnalysis.exprs[expr.alignOf]; - let payloadHtml = - "@alignOf(" + - exprName(alignRefArg, { wantHtml: true, wantLink: true }) + - ")"; - return payloadHtml; - } - case "typeOf": { - const typeRefArg = zigAnalysis.exprs[expr.typeOf]; - let payloadHtml = - "@TypeOf(" + - exprName(typeRefArg, { wantHtml: true, wantLink: true }) + - ")"; - return payloadHtml; - } - case "typeInfo": { - const typeRefArg = zigAnalysis.exprs[expr.typeInfo]; - let payloadHtml = - "@typeInfo(" + - exprName(typeRefArg, { wantHtml: true, wantLink: true }) + - ")"; - return payloadHtml; - } - case "null": { - if (opts.wantHtml) { - return 'null'; - } else { - return "null"; - } - } - case "array": { - let payloadHtml = ".{"; - for (let i = 0; i < expr.array.length; i++) { - if (i != 0) payloadHtml += ", "; - let elem = zigAnalysis.exprs[expr.array[i]]; - payloadHtml += exprName(elem, opts); - } - return payloadHtml + "}"; - } - case "comptimeExpr": { - return generate_html_for_src(zigAnalysis.comptimeExprs[expr.comptimeExpr].code); + case "&": { + yield { src: "&", tag: Tag.ampersand }; + yield* ex(zigAnalysis.exprs[expr["&"]], opts); + return; } case "call": { + let call = zigAnalysis.calls[expr.call]; - let payloadHtml = ""; switch (Object.keys(call.func)[0]) { default: throw "TODO"; case "declRef": case "refPath": { - payloadHtml += exprName(call.func, opts); + yield* ex(call.func, opts); break; } } - payloadHtml += "("; + yield Tok.l_paren; for (let i = 0; i < call.args.length; i++) { - if (i != 0) payloadHtml += ", "; - payloadHtml += exprName(call.args[i], opts); + if (i != 0) { + yield Tok.comma; + yield Tok.space; + } + yield* ex(call.args[i], opts); } - payloadHtml += ")"; - return payloadHtml; + yield Tok.r_paren; + return; } + case "sizeOf": { + const sizeOf = zigAnalysis.exprs[expr.sizeOf]; + yield { src: "@sizeOf", tag: Tag.builtin }; + yield { src: "(", tag: Tag.l_paren }; + yield* ex(sizeOf, opts); + yield { src: ")", tag: Tag.r_paren }; + return; + } + case "as": { - // @Check : this should be done in backend because there are legit @as() calls - // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg]; const exprArg = zigAnalysis.exprs[expr.as.exprArg]; - // return "@as(" + exprName(typeRefArg, opts) + - // ", " + exprName(exprArg, opts) + ")"; - return exprName(exprArg, opts); + yield* ex(exprArg, opts); + return; } - case "declRef": { - const name = getDecl(expr.declRef).name; - if (opts.wantHtml) { - let payloadHtml = ""; - if (opts.wantLink) { - payloadHtml += ''; - } - payloadHtml += - '' + - name + - ""; - if (opts.wantLink) payloadHtml += ""; - return payloadHtml; - } else { - return name; - } - } - case "refPath": { - let firstComponent = expr.refPath[0]; - let name = exprName(firstComponent, opts); - let url = undefined; - if (opts.wantLink && "declRef" in firstComponent) { - url = findDeclNavLink(getDecl(firstComponent.declRef).name); - } - for (let i = 1; i < expr.refPath.length; i++) { - let component = undefined; - if ("string" in expr.refPath[i]) { - component = expr.refPath[i].string; - } else { - component = exprName(expr.refPath[i], { ...opts, wantLink: false }); - if (opts.wantLink && "declRef" in expr.refPath[i]) { - url += "." + getDecl(expr.refPath[i].declRef).name; - component = '' + - component + - ""; - } - } - name += "." + component; - } - return name; - } case "int": { - return "" + expr.int; - } - case "float": { - return "" + expr.float.toFixed(2); - } - case "float128": { - return "" + expr.float128.toFixed(2); - } - case "undefined": { - return "undefined"; - } - case "string": { - return '"' + escapeHtml(expr.string) + '"'; + yield { src: expr.int, tag: Tag.number_literal }; + return; } case "int_big": { - return (expr.int_big.negated ? "-" : "") + expr.int_big.value; + if (expr.int_big.negated) { + yield { src: "-", tag: Tag.minus }; + } + yield { src: expr.int_big.value, tag: Tag.number_literal }; + return; + } + + case "float": { + yield { src: expr.float, tag: Tag.number_literal }; + return; + } + + case "float128": { + yield { src: expr.float128, tag: Tag.number_literal }; + return; + } + + case "array": { + yield { src: ".", tag: Tag.period }; + yield Tok.l_brace; + for (let i = 0; i < expr.array.length; i++) { + if (i != 0) { + yield { src: ",", tag: Tag.comma }; + yield Tok.space; + } + let elem = zigAnalysis.exprs[expr.array[i]]; + yield* ex(elem, opts); + } + yield Tok.r_brace; + return; + } + + case "compileError": { + yield { src: "@compileError", tag: Tag.builtin }; + yield Tok.l_paren; + yield* ex(zigAnalysis.exprs[expr.compileError], opts); + yield Tok.r_paren; + return; + } + + case "string": { + yield { src: '"' + expr.string + '"', tag: Tag.string_literal }; + return; + } + + case "struct": { + yield Tok.period; + yield Tok.l_brace; + yield Tok.space; + + for (let i = 0; i < expr.struct.length; i++) { + const fv = expr.struct[i]; + const field_name = fv.name; + const field_value = ex(fv.val.expr, opts); + yield Tok.period; + yield { src: field_name, tag: Tag.identifier }; + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* field_value; + if (i !== expr.struct.length - 1) { + yield Tok.comma; + yield Tok.space; + } else { + yield Tok.space; + } + } + yield Tok.r_brace; + return; + } + + case "binOpIndex": { + const binOp = zigAnalysis.exprs[expr.binOpIndex]; + yield* ex(binOp, opts); + return; + } + + case "binOp": { + const lhsOp = zigAnalysis.exprs[expr.binOp.lhs]; + const rhsOp = zigAnalysis.exprs[expr.binOp.rhs]; + + if (lhsOp["binOpIndex"] !== undefined) { + yield Tok.l_paren; + yield* ex(lhsOp, opts); + yield Tok.r_paren; + } else { + yield* ex(lhsOp, opts); + } + + yield Tok.space; + + switch (expr.binOp.name) { + case "add": { + yield { src: "+", tag: Tag.plus }; + break; + } + case "addwrap": { + yield { src: "+%", tag: Tag.plus_percent }; + break; + } + case "add_sat": { + yield { src: "+|", tag: Tag.plus_pipe }; + break; + } + case "sub": { + yield { src: "-", tag: Tag.minus }; + break; + } + case "subwrap": { + yield { src: "-%", tag: Tag.minus_percent }; + break; + } + case "sub_sat": { + yield { src: "-|", tag: Tag.minus_pipe }; + break; + } + case "mul": { + yield { src: "*", tag: Tag.asterisk }; + break; + } + case "mulwrap": { + yield { src: "*%", tag: Tag.asterisk_percent }; + break; + } + case "mul_sat": { + yield { src: "*|", tag: Tag.asterisk_pipe }; + break; + } + case "div": { + yield { src: "/", tag: Tag.slash }; + break; + } + case "shl": { + yield { src: "<<", tag: Tag.angle_bracket_angle_bracket_left }; + break; + } + case "shl_sat": { + yield { src: "<<|", tag: Tag.angle_bracket_angle_bracket_left_pipe }; + break; + } + case "shr": { + yield { src: ">>", tag: Tag.angle_bracket_angle_bracket_right }; + break; + } + case "bit_or": { + yield { src: "|", tag: Tag.pipe }; + break; + } + case "bit_and": { + yield { src: "&", tag: Tag.ampersand }; + break; + } + case "array_cat": { + yield { src: "++", tag: Tag.plus_plus }; + break; + } + case "array_mul": { + yield { src: "**", tag: Tag.asterisk_asterisk }; + break; + } + case "cmp_eq": { + yield { src: "==", tag: Tag.equal_equal }; + break; + } + case "cmp_neq": { + yield { src: "!=", tag: Tag.bang_equal }; + break; + } + case "cmp_gt": { + yield { src: ">", tag: Tag.angle_bracket_right }; + break; + } + case "cmp_gte": { + yield { src: ">=", tag: Tag.angle_bracket_right_equal }; + break; + } + case "cmp_lt": { + yield { src: "<", tag: Tag.angle_bracket_left }; + break; + } + case "cmp_lte": { + yield { src: "<=", tag: Tag.angle_bracket_left_equal }; + break; + } + case "bool_br_and": { + yield { src: "and", tag: Tag.keyword_and }; + break; + } + case "bool_br_or": { + yield { src: "or", tag: Tag.keyword_or }; + break; + } + default: + console.log("operator not handled yet or doesn't exist!"); + } + + yield Tok.space; + + if (rhsOp["binOpIndex"] !== undefined) { + yield Tok.l_paren; + yield* ex(rhsOp, opts); + yield Tok.r_paren; + } else { + yield* ex(rhsOp, opts); + } + return; + } + + case "builtinBinIndex": { + const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex]; + yield* ex(builtinBinIndex, opts); + return; + } + + case "builtinBin": { + const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs]; + const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs]; + + let builtinName = "@"; + switch (expr.builtinBin.name) { + case "int_from_float": { + builtinName += "intFromFloat"; + break; + } + case "float_from_int": { + builtinName += "floatFromInt"; + break; + } + case "ptr_from_int": { + builtinName += "ptrFromInt"; + break; + } + case "enum_from_int": { + builtinName += "enumFromInt"; + break; + } + case "float_cast": { + builtinName += "floatCast"; + break; + } + case "int_cast": { + builtinName += "intCast"; + break; + } + case "ptr_cast": { + builtinName += "ptrCast"; + break; + } + case "const_cast": { + builtinName += "constCast"; + break; + } + case "volatile_cast": { + builtinName += "volatileCast"; + break; + } + case "truncate": { + builtinName += "truncate"; + break; + } + case "has_decl": { + builtinName += "hasDecl"; + break; + } + case "has_field": { + builtinName += "hasField"; + break; + } + case "bit_reverse": { + builtinName += "bitReverse"; + break; + } + case "div_exact": { + builtinName += "divExact"; + break; + } + case "div_floor": { + builtinName += "divFloor"; + break; + } + case "div_trunc": { + builtinName += "divTrunc"; + break; + } + case "mod": { + builtinName += "mod"; + break; + } + case "rem": { + builtinName += "rem"; + break; + } + case "mod_rem": { + builtinName += "rem"; + break; + } + case "shl_exact": { + builtinName += "shlExact"; + break; + } + case "shr_exact": { + builtinName += "shrExact"; + break; + } + case "bitcast": { + builtinName += "bitCast"; + break; + } + case "align_cast": { + builtinName += "alignCast"; + break; + } + case "vector_type": { + builtinName += "Vector"; + break; + } + case "reduce": { + builtinName += "reduce"; + break; + } + case "splat": { + builtinName += "splat"; + break; + } + case "offset_of": { + builtinName += "offsetOf"; + break; + } + case "bit_offset_of": { + builtinName += "bitOffsetOf"; + break; + } + default: + console.log("builtin function not handled yet or doesn't exist!"); + } + + yield { src: builtinName, tag: Tag.builtin }; + yield Tok.l_paren; + yield* ex(lhsOp, opts); + yield Tok.comma; + yield Tok.space; + yield* ex(rhsOp, opts); + yield Tok.r_paren; + return; + } + + case "enumLiteral": { + let literal = expr.enumLiteral; + yield Tok.period; + yield { src: literal, tag: Tag.identifier }; + return; + } + + case "void": { + yield { src: "void", tag: Tag.identifier }; + return; + } + + case "null": { + yield { src: "null", tag: Tag.identifier }; + return; + } + + case "undefined": { + yield { src: "undefined", tag: Tag.identifier }; + return; } case "anytype": { - return "anytype"; + yield { src: "anytype", tag: Tag.keyword_anytype }; + return; } case "this": { - return "@This()"; + yield { src: "@This", tag: Tag.builtin }; + yield Tok.l_paren; + yield Tok.r_paren; + return; + } + + case "typeInfo": { + const arg = zigAnalysis.exprs[expr.typeInfo]; + yield { src: "@typeInfo", tag: Tag.builtin }; + yield Tok.l_paren; + yield* ex(arg, opts); + yield Tok.r_paren; + return; + } + + case "switchIndex": { + const switchIndex = zigAnalysis.exprs[expr.switchIndex]; + yield* ex(switchIndex, opts); + return; + } + + case "errorSets": { + const errSetsObj = getType(expr.errorSets); + yield* ex(errSetsObj.lhs, opts); + yield Tok.space; + yield { src: "||", tag: Tag.pipe_pipe }; + yield Tok.space; + yield* ex(errSetsObj.rhs, opts); + return; + } + + case "errorUnion": { + const errUnionObj = getType(expr.errorUnion); + yield* ex(errUnionObj.lhs, opts); + yield { src: "!", tag: Tag.bang }; + yield* ex(errUnionObj.rhs, opts); + return; } case "type": { @@ -1880,416 +1638,389 @@ Happy writing! if (typeof typeObj === "number") typeObj = getType(typeObj); switch (typeObj.kind) { default: - throw "TODO"; + throw "TODO: " + typeObj.kind; + case typeKinds.Type: { + yield { src: typeObj.name, tag: Tag.identifier }; + return; + } + case typeKinds.Void: { + yield { src: "void", tag: Tag.identifier }; + return; + } + case typeKinds.NoReturn: { + yield { src: "noreturn", tag: Tag.identifier }; + return; + } + case typeKinds.ComptimeExpr: { + yield { src: "anyopaque", tag: Tag.identifier }; + return; + } + case typeKinds.Bool: { + yield { src: "bool", tag: Tag.identifier }; + return; + } + case typeKinds.ComptimeInt: { + yield { src: "comptime_int", tag: Tag.identifier }; + return; + } + case typeKinds.ComptimeFloat: { + yield { src: "comptime_float", tag: Tag.identifier }; + return; + } + case typeKinds.Int: { + yield { src: typeObj.name, tag: Tag.identifier }; + return; + } + case typeKinds.Float: { + yield { src: typeObj.name, tag: Tag.identifier }; + return; + } + case typeKinds.Array: { + yield Tok.l_bracket; + yield* ex(typeObj.len, opts); + if (typeObj.sentinel) { + yield Tok.colon; + yield* ex(typeObj.sentinel, opts); + } + yield Tok.r_bracket; + yield* ex(typeObj.child, opts); + return; + } + case typeKinds.Optional: { + yield { src: "?", tag: Tag.question_mark }; + yield* ex(typeObj.child, opts); + return; + } + case typeKinds.Pointer: { + let ptrObj = typeObj; + switch (ptrObj.size) { + default: + console.log("TODO: implement unhandled pointer size case"); + case pointerSizeEnum.One: + yield { src: "*", tag: Tag.asterisk }; + break; + case pointerSizeEnum.Many: + yield Tok.l_bracket; + yield { src: "*", tag: Tag.asterisk }; + if (ptrObj.sentinel !== null) { + yield Tok.colon; + yield* ex(ptrObj.sentinel, opts); + } + yield Tok.r_bracket; + break; + case pointerSizeEnum.Slice: + if (ptrObj.is_ref) { + yield { src: "*", tag: Tag.asterisk }; + } + yield Tok.l_bracket; + if (ptrObj.sentinel !== null) { + yield Tok.colon; + yield* ex(ptrObj.sentinel, opts); + } + yield Tok.r_bracket; + break; + case pointerSizeEnum.C: + yield Tok.l_bracket; + yield { src: "*", tag: Tag.asterisk }; + yield { src: "c", tag: Tag.identifier }; + if (typeObj.sentinel !== null) { + yield Tok.colon; + yield* ex(ptrObj.sentinel, opts); + } + yield Tok.r_bracket; + break; + } + if (!ptrObj.is_mutable) { + yield Tok.const; + yield Tok.space; + } + if (ptrObj.is_allowzero) { + yield { src: "allowzero", tag: Tag.keyword_allowzero }; + yield Tok.space; + } + if (ptrObj.is_volatile) { + yield { src: "volatile", tag: Tag.keyword_volatile }; + } + if (ptrObj.has_addrspace) { + yield { src: "addrspace", tag: Tag.keyword_addrspace }; + yield Tok.l_paren; + yield Tok.period; + yield Tok.r_paren; + } + if (ptrObj.has_align) { + yield { src: "align", tag: Tag.keyword_align }; + yield Tok.l_paren; + yield* ex(ptrObj.align, opts); + if (ptrObj.hostIntBytes !== undefined && ptrObj.hostIntBytes !== null) { + yield Tok.colon; + yield* ex(ptrObj.bitOffsetInHost, opts); + yield Tok.colon; + yield* ex(ptrObj.hostIntBytes, opts); + } + yield Tok.r_paren; + yield Tok.space; + } + yield* ex(ptrObj.child, opts); + return; + } case typeKinds.Struct: { let structObj = typeObj; - let name = ""; - let layout = ""; if (structObj.layout !== null) { switch (structObj.layout.enumLiteral) { case "Packed": { - layout = "packed "; + yield { src: "packed", tag: Tag.keyword_packed }; break; } case "Extern": { - layout = "extern "; + yield { src: "extern", tag: Tag.keyword_extern }; break; } } + yield Tok.space; } - if (opts.wantHtml) { - name = "" + layout + "struct"; - } else { - name = layout + "struct"; - } + yield { src: "struct", tag: Tag.keyword_struct }; if (structObj.backing_int !== null) { - name += "(" + exprName(structObj.backing_int, opts) + ")"; + yield Tok.l_paren; + yield* ex(structObj.backing_int, opts); + yield Tok.r_paren; } - name += " { "; - if (structObj.field_types.length > 1 && opts.wantHtml) { name += "
    "; } - let indent = ""; - if (structObj.field_types.length > 1 && opts.wantHtml) { - indent = "    " - } - if (opts.indent && structObj.field_types.length > 1) { - indent = opts.indent + indent; - } - let structNode = getAstNode(structObj.src); - let field_end = ","; - if (structObj.field_types.length > 1 && opts.wantHtml) { - field_end += "
    "; + yield Tok.space; + yield Tok.l_brace; + + if (structObj.field_types.length > 1) { + yield Tok.enter; } else { - field_end += " "; + yield Tok.space; } + let indent = 0; + if (structObj.field_types.length > 1) { + indent = 1; + } + if (opts.indent && structObj.field_types.length > 1) { + indent += opts.ident; + } + + let structNode = getAstNode(structObj.src); for (let i = 0; i < structObj.field_types.length; i += 1) { let fieldNode = getAstNode(structNode.fields[i]); let fieldName = fieldNode.name; - let html = indent; - if (!structObj.is_tuple) { - html += escapeHtml(fieldName); + + for (let j = 0; j < indent; j += 1) { + yield Tok.tab; + } + + if (!typeObj.is_tuple) { + yield { src: fieldName, tag: Tag.identifier }; } let fieldTypeExpr = structObj.field_types[i]; - if (!structObj.is_tuple) { - html += ": "; + if (!typeObj.is_tuple) { + yield Tok.colon; + yield Tok.space; } - - html += exprName(fieldTypeExpr, { ...opts, indent: indent }); + yield* ex(fieldTypeExpr, { ...opts, indent: indent }); if (structObj.field_defaults[i] !== null) { - html += " = " + exprName(structObj.field_defaults[i], opts); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(structObj.field_defaults[i], opts); } - html += field_end; - - name += html; + if (structObj.field_types.length > 1) { + yield Tok.comma; + yield Tok.enter; + } else { + yield Tok.space; + } } - if (opts.indent && structObj.field_types.length > 1) { - name += opts.indent; - } - name += "}"; - return name; + yield Tok.r_brace; + return; } case typeKinds.Enum: { let enumObj = typeObj; - let name = ""; - if (opts.wantHtml) { - name = "enum"; - } else { - name = "enum"; - } + yield { src: "enum", tag: Tag.keyword_enum }; if (enumObj.tag) { - name += "(" + exprName(enumObj.tag, opts) + ")"; + yield Tok.l_paren; + yield* ex(enumObj.tag, opts); + yield Tok.r_paren; } - name += " { "; + yield Tok.space; + yield Tok.l_brace; + let enumNode = getAstNode(enumObj.src); let fields_len = enumNode.fields.length; if (enumObj.nonexhaustive) { fields_len += 1; } - if (fields_len > 1 && opts.wantHtml) { name += "
    "; } - let indent = ""; + if (fields_len > 1) { - if (opts.wantHtml) { - indent = "    "; - } else { - indent = " "; - } + yield Tok.enter; + } else { + yield Tok.space; + } + + let indent = 0; + if (fields_len > 1) { + indent = 1; } if (opts.indent) { - indent = opts.indent + indent; - } - let field_end = ","; - if (fields_len > 1 && opts.wantHtml) { - field_end += "
    "; - } else { - field_end += " "; + indent += opts.indent; } + for (let i = 0; i < enumNode.fields.length; i += 1) { let fieldNode = getAstNode(enumNode.fields[i]); let fieldName = fieldNode.name; - let html = indent + escapeHtml(fieldName); + + for (let j = 0; j < indent; j += 1) yield Tok.tab; + yield { src: fieldName, tag: Tag.identifier }; if (enumObj.values[i] !== null) { - html += " = " + exprName(enumObj.values[i], opts); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(enumObj.values[i], opts); } - html += field_end; - - name += html; + if (fields_len > 1) { + yield Tok.comma; + yield Tok.enter; + } } - if (enumObj.nonexhaustive) { - name += indent + "_" + field_end; + for (let j = 0; j < indent; j += 1) yield Tok.tab; + yield { src: "_", tag: Tag.identifier }; + if (fields_len > 1) { + yield Tok.comma; + yield Tok.enter; } if (opts.indent) { - name += opts.indent; + for (let j = 0; j < opts.indent; j += 1) yield Tok.tab; } - name += "}"; - return name; + yield Tok.r_brace; + return; } case typeKinds.Union: { let unionObj = typeObj; - let name = ""; - let layout = ""; if (unionObj.layout !== null) { switch (unionObj.layout.enumLiteral) { case "Packed": { - layout = "packed "; + yield { src: "packed", tag: Tag.keyword_packed }; break; } case "Extern": { - layout = "extern "; + yield { src: "extern", tag: Tag.keyword_extern }; break; } } + yield Tok.space; } - if (opts.wantHtml) { - name = "" + layout + "union"; - } else { - name = layout + "union"; - } + yield { src: "union", tag: Tag.keyword_union }; if (unionObj.auto_tag) { - if (opts.wantHtml) { - name += "(enum"; - } else { - name += "(enum"; - } + yield Tok.l_paren; + yield { src: "enum", tag: Tag.keyword_enum }; if (unionObj.tag) { - name += "(" + exprName(unionObj.tag, opts) + "))"; + yield Tok.l_paren; + yield* ex(unionObj.tag, opts); + yield Tok.r_paren; + yield Tok.r_paren; } else { - name += ")"; + yield Tok.r_paren; } } else if (unionObj.tag) { - name += "(" + exprName(unionObj.tag, opts) + ")"; + yield Tok.l_paren; + yield* ex(unionObj.tag, opts); + yield Tok.r_paren; } - name += " { "; - if (unionObj.field_types.length > 1 && opts.wantHtml) { - name += "
    "; + yield Tok.space; + yield Tok.l_brace; + if (unionObj.field_types.length > 1) { + yield Tok.enter; + } else { + yield Tok.space; } - let indent = ""; - if (unionObj.field_types.length > 1 && opts.wantHtml) { - indent = "    " + let indent = 0; + if (unionObj.field_types.length > 1) { + indent = 1; } if (opts.indent) { - indent = opts.indent + indent; + indent += opts.indent; } let unionNode = getAstNode(unionObj.src); - let field_end = ","; - if (unionObj.field_types.length > 1 && opts.wantHtml) { - field_end += "
    "; - } else { - field_end += " "; - } for (let i = 0; i < unionObj.field_types.length; i += 1) { let fieldNode = getAstNode(unionNode.fields[i]); let fieldName = fieldNode.name; - let html = indent + escapeHtml(fieldName); + for (let j = 0; j < indent; j += 1) yield Tok.tab; + yield { src: fieldName, tag: Tag.identifier }; let fieldTypeExpr = unionObj.field_types[i]; - html += ": "; + yield Tok.colon; + yield Tok.space; - html += exprName(fieldTypeExpr, { ...opts, indent: indent }); + yield* ex(fieldTypeExpr, { ...opts, indent: indent }); - html += field_end; - - name += html; + if (unionObj.field_types.length > 1) { + yield Tok.comma; + yield Tok.enter; + } else { + yield Tok.space; + } } if (opts.indent) { - name += opts.indent; + for (let j = 0; j < opts.indent; j += 1) yield Tok.tab; } - name += "}"; - return name; + yield Tok.r_brace; + return; } case typeKinds.Opaque: { - let opaqueObj = typeObj; - return opaqueObj; + yield { src: "opaque", tag: Tag.keyword_opaque }; + yield Tok.space; + yield Tok.l_brace; + yield Tok.r_brace; + return; } - case typeKinds.ComptimeExpr: { - return "anyopaque"; + case typeKinds.EnumLiteral: { + yield { src: "(enum literal)", tag: Tag.identifier }; + return; } - case typeKinds.Array: { - let arrayObj = typeObj; - let name = "["; - let lenName = exprName(arrayObj.len, opts); - let sentinel = arrayObj.sentinel - ? ":" + exprName(arrayObj.sentinel, opts) - : ""; - // let is_mutable = arrayObj.is_multable ? "const " : ""; - - if (opts.wantHtml) { - name += - '' + lenName + sentinel + ""; - } else { - name += lenName + sentinel; - } - name += "]"; - // name += is_mutable; - name += exprName(arrayObj.child, opts); - return name; - } - case typeKinds.Optional: - return "?" + exprName(typeObj.child, opts); - case typeKinds.Pointer: { - let ptrObj = typeObj; - let sentinel = ptrObj.sentinel - ? ":" + exprName(ptrObj.sentinel, opts) - : ""; - let is_mutable = !ptrObj.is_mutable ? "const " : ""; - let name = ""; - switch (ptrObj.size) { - default: - console.log("TODO: implement unhandled pointer size case"); - case pointerSizeEnum.One: - name += "*"; - name += is_mutable; - break; - case pointerSizeEnum.Many: - name += "[*"; - name += sentinel; - name += "]"; - name += is_mutable; - break; - case pointerSizeEnum.Slice: - if (ptrObj.is_ref) { - name += "*"; - } - name += "["; - name += sentinel; - name += "]"; - name += is_mutable; - break; - case pointerSizeEnum.C: - name += "[*c"; - name += sentinel; - name += "]"; - name += is_mutable; - break; - } - // @check: after the major changes in arrays the consts are came from switch above - // if (!ptrObj.is_mutable) { - // if (opts.wantHtml) { - // name += 'const '; - // } else { - // name += "const "; - // } - // } - if (ptrObj.is_allowzero) { - name += "allowzero "; - } - if (ptrObj.is_volatile) { - name += "volatile "; - } - if (ptrObj.has_addrspace) { - name += "addrspace("; - name += "." + ""; - name += ") "; - } - if (ptrObj.has_align) { - let align = exprName(ptrObj.align, opts); - if (opts.wantHtml) { - name += 'align('; - } else { - name += "align("; - } - if (opts.wantHtml) { - name += '' + align + ""; - } else { - name += align; - } - if (ptrObj.hostIntBytes != null) { - name += ":"; - if (opts.wantHtml) { - name += - '' + - ptrObj.bitOffsetInHost + - ""; - } else { - name += ptrObj.bitOffsetInHost; - } - name += ":"; - if (opts.wantHtml) { - name += - '' + - ptrObj.hostIntBytes + - ""; - } else { - name += ptrObj.hostIntBytes; - } - } - name += ") "; - } - //name += typeValueName(ptrObj.child, wantHtml, wantSubLink, null); - name += exprName(ptrObj.child, opts); - return name; - } - case typeKinds.Float: { - let floatObj = typeObj; - - if (opts.wantHtml) { - return '' + floatObj.name + ""; - } else { - return floatObj.name; - } - } - case typeKinds.Int: { - let intObj = typeObj; - let name = intObj.name; - if (opts.wantHtml) { - return '' + name + ""; - } else { - return name; - } - } - case typeKinds.ComptimeInt: - if (opts.wantHtml) { - return 'comptime_int'; - } else { - return "comptime_int"; - } - case typeKinds.ComptimeFloat: - if (opts.wantHtml) { - return 'comptime_float'; - } else { - return "comptime_float"; - } - case typeKinds.Type: - if (opts.wantHtml) { - return 'type'; - } else { - return "type"; - } - case typeKinds.Bool: - if (opts.wantHtml) { - return 'bool'; - } else { - return "bool"; - } - case typeKinds.Void: - if (opts.wantHtml) { - return 'void'; - } else { - return "void"; - } - case typeKinds.EnumLiteral: - if (opts.wantHtml) { - return '(enum literal)'; - } else { - return "(enum literal)"; - } - case typeKinds.NoReturn: - if (opts.wantHtml) { - return 'noreturn'; - } else { - return "noreturn"; - } case typeKinds.ErrorSet: { let errSetObj = typeObj; - if (errSetObj.fields == null) { - return 'anyerror'; + if (errSetObj.fields === null) { + yield { src: "anyerror", tag: Tag.identifier }; } else if (errSetObj.fields.length == 0) { - return "error{}"; + yield { src: "error", tag: Tag.keyword_error }; + yield Tok.l_brace; + yield Tok.r_brace; } else if (errSetObj.fields.length == 1) { - return "error{" + errSetObj.fields[0].name + "}"; + yield { src: "error", tag: Tag.keyword_error }; + yield Tok.l_brace; + yield { src: errSetObj.fields[0].name, tag: Tag.identifier }; + yield Tok.r_brace; } else { - // throw "TODO"; - let html = "error{ " + errSetObj.fields[0].name; - for (let i = 1; i < errSetObj.fields.length; i++) html += ", " + errSetObj.fields[i].name; - html += " }"; - return html; + yield { src: "error", tag: Tag.keyword_error }; + yield Tok.l_brace; + yield { src: errSetObj.fields[0].name, tag: Tag.identifier }; + for (let i = 1; i < errSetObj.fields.length; i++) { + yield Tok.comma; + yield Tok.space; + yield { src: errSetObj.fields[i].name, tag: Tag.identifier }; + } + yield Tok.r_brace; } + return; } - case typeKinds.ErrorUnion: { let errUnionObj = typeObj; - let lhs = exprName(errUnionObj.lhs, opts); - let rhs = exprName(errUnionObj.rhs, opts); - return lhs + "!" + rhs; + yield* ex(errUnionObj.lhs, opts); + yield { src: "!", tag: Tag.bang }; + yield* ex(errUnionObj.rhs, opts); + return; } case typeKinds.InferredErrorUnion: { let errUnionObj = typeObj; - let payload = exprName(errUnionObj.payload, opts); - return "!" + payload; + yield { src: "!", tag: Tag.bang }; + yield* ex(errUnionObj.payload, opts); + return; } case typeKinds.Fn: { let fnObj = typeObj; @@ -2299,45 +2030,32 @@ Happy writing! opts.linkFnNameDecl = null; let payloadHtml = ""; if (opts.addParensIfFnSignature && fnObj.src == 0) { - payloadHtml += "("; + yield Tok.l_paren; } if (fnObj.is_extern) { - if (opts.wantHtml) { - payloadHtml += 'extern '; - } else { - payloadHtml += "extern "; - } + yield { src: "extern", tag: Tag.keyword_extern }; + yield Tok.space; } else if (fnObj.has_cc) { let cc_expr = zigAnalysis.exprs[fnObj.cc]; if (cc_expr.enumLiteral === "Inline") { - if(opts.wantHtml) { - payloadHtml += 'inline ' - } else { - payloadHtml += "inline " - } + yield { src: "inline", tag: Tag.keyword_inline }; + yield Tok.space; } } if (fnObj.has_lib_name) { - payloadHtml += '"' + fnObj.lib_name + '" '; + yield { src: '"' + fnObj.lib_name + '"', tag: Tag.string_literal }; + yield Tok.space; } - if (opts.wantHtml) { - payloadHtml += 'fn '; - if (fnDecl) { - payloadHtml += ''; - if (linkFnNameDecl) { - payloadHtml += - '' + - escapeHtml(fnDecl.name) + - ""; - } else { - payloadHtml += escapeHtml(fnDecl.name); - } - payloadHtml += ""; + yield { src: "fn", tag: Tag.keyword_fn }; + yield Tok.space; + if (fnDecl) { + if (linkFnNameDecl) { + yield { src: fnDecl.name, tag: Tag.identifier, link: linkFnNameDecl, fnDecl: false }; + } else { + yield { src: fnDecl.name, tag: Tag.identifier, fnDecl: true }; } - } else { - payloadHtml += "fn "; } - payloadHtml += "("; + yield Tok.l_paren; if (fnObj.params) { let fields = null; let isVarArgs = false; @@ -2349,13 +2067,10 @@ Happy writing! for (let i = 0; i < fnObj.params.length; i += 1) { if (i != 0) { - payloadHtml += ", "; + yield Tok.comma; + yield Tok.space; } - if (opts.wantHtml) { - payloadHtml += - "
        
    "; - } let value = fnObj.params[i]; let paramValue = resolveValue({ expr: value }); @@ -2363,24 +2078,20 @@ Happy writing! let paramNode = getAstNode(fields[i]); if (paramNode.varArgs) { - payloadHtml += "..."; + yield Tok.period; + yield Tok.period; + yield Tok.period; continue; } if (paramNode.noalias) { - if (opts.wantHtml) { - payloadHtml += 'noalias '; - } else { - payloadHtml += "noalias "; - } + yield { src: "noalias", tag: Tag.keyword_noalias }; + yield Tok.space; } if (paramNode.comptime) { - if (opts.wantHtml) { - payloadHtml += 'comptime '; - } else { - payloadHtml += "comptime "; - } + yield { src: "comptime", tag: Tag.keyword_comptime }; + yield Tok.space; } let paramName = paramNode.name; @@ -2390,94 +2101,102 @@ Happy writing! if (paramName === "") { paramName = "_"; } - payloadHtml += paramName + ": "; + yield { src: paramName, tag: Tag.identifier }; + yield Tok.colon; + yield Tok.space; } } } if (isVarArgs && i === fnObj.params.length - 1) { - payloadHtml += "..."; + yield Tok.period; + yield Tok.period; + yield Tok.period; } else if ("alignOf" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("typeOf" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("typeOf_peer" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("declRef" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("call" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("refPath" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("type" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); //payloadHtml += '' + name + ""; } else if ("binOpIndex" in value) { - payloadHtml += exprName(value, opts); + yield* ex(value, opts); } else if ("comptimeExpr" in value) { let comptimeExpr = zigAnalysis.comptimeExprs[value.comptimeExpr].code; - if (opts.wantHtml) { - payloadHtml += - '' + comptimeExpr + ""; - } else { - payloadHtml += comptimeExpr; - } - } else if (opts.wantHtml) { - payloadHtml += 'anytype'; + yield* Tokenizer(comptimeExpr); } else { - payloadHtml += "anytype"; + yield { src: "anytype", tag: Tag.keyword_anytype }; } } } - if (opts.wantHtml) { - payloadHtml += ",
    "; - } - payloadHtml += ") "; + yield Tok.r_paren; + yield Tok.space; if (fnObj.has_align) { let align = zigAnalysis.exprs[fnObj.align]; - payloadHtml += "align(" + exprName(align, opts) + ") "; + yield { src: "align", tag: Tag.keyword_align }; + yield Tok.l_paren; + yield* ex(align, opts); + yield Tok.r_paren; + yield Tok.space; } if (fnObj.has_cc) { let cc = zigAnalysis.exprs[fnObj.cc]; if (cc) { if (cc.enumLiteral !== "Inline") { - payloadHtml += "callconv(" + exprName(cc, opts) + ") "; + yield { src: "collconv", tag: Tag.keyword_callconv }; + yield Tok.l_paren; + yield* ex(cc, opts); + yield Tok.r_paren; + yield Tok.space; } } } if (fnObj.is_inferred_error) { - payloadHtml += "!"; + yield { src: "!", tag: Tag.bang }; } if (fnObj.ret != null) { - payloadHtml += exprName(fnObj.ret, { + yield* ex(fnObj.ret, { ...opts, addParensIfFnSignature: true, }); - } else if (opts.wantHtml) { - payloadHtml += 'anytype'; } else { - payloadHtml += "anytype"; + yield { src: "anytype", tag: Tag.keyword_anytype }; } if (opts.addParensIfFnSignature && fnObj.src == 0) { - payloadHtml += ")"; + yield Tok.r_paren; } - return payloadHtml; + return; } - // if (wantHtml) { - // return escapeHtml(typeObj.name); - // } else { - // return typeObj.name; - // } } } + case "typeOf": { + const typeRefArg = zigAnalysis.exprs[expr.typeOf]; + yield { src: "@TypeOf", tag: Tag.builtin }; + yield Tok.l_paren; + yield* ex(typeRefArg, opts); + yield Tok.r_paren; + return; + } } + + } + + function shouldSkipParamName(typeRef, paramName) { let resolvedTypeRef = resolveValue({ expr: typeRef }); if ("type" in resolvedTypeRef) { @@ -2504,13 +2223,13 @@ Happy writing! typeObj === getType(zigAnalysis.modules[zigAnalysis.rootMod].main) ) { - name = "std"; + name = renderSingleToken(Tok.identifier("std")); } else { - name = exprName({ type: typeObj }, { wantHtml: false, wantLink: false }); + name = renderTokens(ex({ type: typeObj })); } if (name != null && name != "") { - domHdrName.innerText = - name + " (" + zigAnalysis.typeKinds[typeObj.kind] + ")"; + domHdrName.innerHTML = "
    " + name + "
    (" + + zigAnalysis.typeKinds[typeObj.kind] + ")"; domHdrName.classList.remove("hidden"); } if (typeObj.kind == typeKinds.ErrorSet) { @@ -2528,7 +2247,7 @@ Happy writing! //let srcObj = zigAnalysis.astNodes[errObj.src]; errorList.push(errObj); } - errorList.sort(function (a, b) { + errorList.sort(function(a, b) { return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase()); }); @@ -2624,55 +2343,80 @@ Happy writing! if (resolvedValue.expr.fieldRef) { const declRef = decl.value.expr.refPath[0].declRef; const type = getDecl(declRef); - domFnProtoCode.innerHTML = - 'const ' + - escapeHtml(decl.name) + - ": " + - type.name + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.const; + yield Tok.space; + yield Tok.identifier(decl.name); + yield Tok.colon; + yield Tok.space; + yield Tok.identifier(type.name); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } else if ( resolvedValue.expr.string !== undefined || resolvedValue.expr.call !== undefined || resolvedValue.expr.comptimeExpr !== undefined ) { - let typeRef = null; - if (resolvedValue.typeRef !== undefined) { - typeRef = resolvedValue.typeRef; - } - domFnProtoCode.innerHTML = - 'const ' + - escapeHtml(decl.name) + - ": " + - exprName(typeRef !== null ? typeRef : resolvedValue.expr, { wantHtml: true, wantLink: true }) + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.const; + yield Tok.space; + yield Tok.identifier(decl.name); + if (decl.value.typeRef) { + yield Tok.colon; + yield Tok.space; + yield* ex(decl.value.typeRef, {}); + } + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } else if (resolvedValue.expr.compileError) { - domFnProtoCode.innerHTML = - 'const ' + - escapeHtml(decl.name) + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.const; + yield Tok.space; + yield Tok.identifier(decl.name); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } else { - domFnProtoCode.innerHTML = - 'const ' + - escapeHtml(decl.name) + - ": " + - exprName(resolvedValue.typeRef, { wantHtml: true, wantLink: true }) + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + const parent = getType(decl.parent_container); + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.const; + yield Tok.space; + yield Tok.identifier(decl.name); + if (decl.value.typeRef !== null) { + yield Tok.colon; + yield Tok.space; + yield* ex(decl.value.typeRef, {}); + } + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } let docs = getAstNode(decl.src).docs; if (docs != null) { // TODO: it shouldn't just be decl.parent_container, but rather // the type that the decl holds (if the value is a type) - domTldDocs.innerHTML = markdown(docs, getType(decl.parent_container)); - + domTldDocs.innerHTML = markdown(docs, decl); + domTldDocs.classList.remove("hidden"); } @@ -2685,43 +2429,68 @@ Happy writing! if (resolvedVar.expr.fieldRef) { const declRef = decl.value.expr.refPath[0].declRef; const type = getDecl(declRef); - domFnProtoCode.innerHTML = - 'var ' + - escapeHtml(decl.name) + - ": " + - type.name + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.var; + yield Tok.space; + yield Tok.identifier(decl.name); + yield Tok.colon; + yield Tok.space; + yield Tok.identifier(type.name); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } else if ( resolvedVar.expr.string !== undefined || resolvedVar.expr.call !== undefined || resolvedVar.expr.comptimeExpr !== undefined ) { - domFnProtoCode.innerHTML = - 'var ' + - escapeHtml(decl.name) + - ": " + - exprName(resolvedVar.typeRef !== null ? resolvedVar.typeRef : resolvedVar.expr, { wantHtml: true, wantLink: true }) + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.var; + yield Tok.space; + yield Tok.identifier(decl.name); + if (decl.value.typeRef) { + yield Tok.colon; + yield Tok.space; + yield* ex(decl.value.typeRef, {}); + } + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } else if (resolvedVar.expr.compileError) { - domFnProtoCode.innerHTML = - 'var ' + - escapeHtml(decl.name) + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.var; + yield Tok.space; + yield Tok.identifier(decl.name); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } else { - domFnProtoCode.innerHTML = - 'var ' + - escapeHtml(decl.name) + - ": " + - exprName(resolvedVar.typeRef, { wantHtml: true, wantLink: true }) + - " = " + - exprName(decl.value.expr, { wantHtml: true, wantLink: true }) + - ";"; + domFnProtoCode.innerHTML = renderTokens( + (function*() { + yield Tok.var; + yield Tok.space; + yield Tok.identifier(decl.name); + yield Tok.colon; + yield Tok.space; + yield* ex(resolvedVar.typeRef, {}); + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(decl.value.expr, {}); + yield Tok.semi; + })()); } let docs = getAstNode(decl.src).docs; @@ -2955,7 +2724,7 @@ Happy writing! resizeDomList( domListFns, fnsList.length, - "
    " + '
    ' ); for (let i = 0; i < fnsList.length; i += 1) { @@ -2968,12 +2737,10 @@ Happy writing! let declType = resolveValue(decl.value); console.assert("type" in declType.expr); - tdFnSignature.innerHTML = exprName(declType.expr, { - wantHtml: true, - wantLink: true, + tdFnSignature.innerHTML = renderTokens(ex(declType.expr, { fnDecl: decl, linkFnNameDecl: navLinkDecl(decl.name), - }); + })); tdFnSrc.innerHTML = "[src]"; @@ -3018,14 +2785,22 @@ Happy writing! if (container.kind === typeKinds.Enum) { let value = container.values[i]; if (value !== null) { - html += " = " + exprName(value, { wantHtml: true, wantLink: true }); + html += renderTokens((function*() { + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(value, {}); + })()); } } else { let fieldTypeExpr = container.field_types[i]; if (container.kind !== typeKinds.Struct || !container.is_tuple) { - html += ": "; + html += renderTokens((function*() { + yield Tok.colon; + yield Tok.space; + })()); } - html += exprName(fieldTypeExpr, { wantHtml: true, wantLink: true }); + html += renderTokens(ex(fieldTypeExpr, {})); let tsn = typeShorthandName(fieldTypeExpr); if (tsn) { html += " (" + tsn + ")"; @@ -3033,7 +2808,12 @@ Happy writing! if (container.kind === typeKinds.Struct && !container.is_tuple) { let defaultInitExpr = container.field_defaults[i]; if (defaultInitExpr !== null) { - html += " = " + exprName(defaultInitExpr, { wantHtml: true, wantLink: true }); + html += renderTokens((function*() { + yield Tok.space; + yield Tok.eql; + yield Tok.space; + yield* ex(defaultInitExpr, {}); + })()); } } } @@ -3052,7 +2832,7 @@ Happy writing! resizeDomList( domListGlobalVars, varsList.length, - '' + '
    '
           );
           for (let i = 0; i < varsList.length; i += 1) {
             let decl = varsList[i];
    @@ -3061,15 +2841,13 @@ Happy writing!
             let tdName = trDom.children[0];
             let tdNameA = tdName.children[0];
             let tdType = trDom.children[1];
    +        let preType = tdType.children[0];
             let tdDesc = trDom.children[2];
     
             tdNameA.setAttribute("href", navLinkDecl(decl.name));
             tdNameA.textContent = decl.name;
     
    -        tdType.innerHTML = exprName(walkResultTypeRef(decl.value), {
    -          wantHtml: true,
    -          wantLink: true,
    -        });
    +        preType.innerHTML = renderTokens(ex(walkResultTypeRef(decl.value), {}));
     
             let docs = getAstNode(decl.src).docs;
             if (docs != null) {
    @@ -3085,7 +2863,7 @@ Happy writing!
           resizeDomList(
             domListValues,
             valsList.length,
    -        ''
    +        '
    '
           );
           for (let i = 0; i < valsList.length; i += 1) {
             let decl = valsList[i];
    @@ -3094,15 +2872,13 @@ Happy writing!
             let tdName = trDom.children[0];
             let tdNameA = tdName.children[0];
             let tdType = trDom.children[1];
    +        let preType = tdType.children[0];
             let tdDesc = trDom.children[2];
     
             tdNameA.setAttribute("href", navLinkDecl(decl.name));
             tdNameA.textContent = decl.name;
     
    -        tdType.innerHTML = exprName(walkResultTypeRef(decl.value), {
    -          wantHtml: true,
    -          wantLink: true,
    -        });
    +        preType.innerHTML = renderTokens(ex(walkResultTypeRef(decl.value), {}));
     
             let docs = getAstNode(decl.src).docs;
             if (docs != null) {
    @@ -3118,24 +2894,21 @@ Happy writing!
           resizeDomList(
             domListTests,
             testsList.length,
    -        ''
    +        '
    '
           );
           for (let i = 0; i < testsList.length; i += 1) {
             let decl = testsList[i];
             let trDom = domListTests.children[i];
     
             let tdName = trDom.children[0];
    -        let tdNameA = tdName.children[0];
    +        let tdNamePre = tdName.children[0];
             let tdType = trDom.children[1];
    +        let tdTypePre = tdType.children[0];
             let tdDesc = trDom.children[2];
     
    -        tdNameA.setAttribute("href", navLinkDecl(decl.name));
    -        tdNameA.textContent = decl.name;
    +        tdNamePre.innerHTML = renderSingleToken(Tok.identifier(decl.name));
     
    -        tdType.innerHTML = exprName(walkResultTypeRef(decl.value), {
    -          wantHtml: true,
    -          wantLink: true,
    -        });
    +        tdTypePre.innerHTML = ex(walkResultTypeRef(decl.value), {});
     
             let docs = getAstNode(decl.src).docs;
             if (docs != null) {
    @@ -3260,7 +3033,7 @@ Happy writing!
     
             return;
           case NAV_MODES.GUIDES:
    -        
    +
             const sections = zigAnalysis.guide_sections;
             if (sections.length != 0 && sections[0].guides.length != 0 && nonSearchPart == "") {
               location.hash = NAV_MODES.GUIDES + sections[0].guides[0].name;
    @@ -3428,10 +3201,10 @@ Happy writing!
                 if (list[declIndex] != null) continue;
     
                 let decl = getDecl(declIndex);
    -              
    +
                 if (decl.is_uns) {
                   let unsDeclList = [decl];
    -              while(unsDeclList.length != 0) {
    +              while (unsDeclList.length != 0) {
                     let unsDecl = unsDeclList.pop();
                     let unsDeclVal = resolveValue(unsDecl.value);
                     if (!("type" in unsDeclVal.expr)) continue;
    @@ -3441,7 +3214,7 @@ Happy writing!
                     for (let unsDeclI = 0; unsDeclI < unsPubDeclLen; unsDeclI += 1) {
                       let childDeclIndex = unsType.pubDecls[unsDeclI];
                       let childDecl = getDecl(childDeclIndex);
    -                  
    +
                       if (childDecl.is_uns) {
                         unsDeclList.push(childDecl);
                       } else {
    @@ -3460,54 +3233,54 @@ Happy writing!
         return list;
       }
     
    -function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
    -  let declVal = resolveValue(decl.value);
    -  let declNames = item.declNames.concat([decl.name]);
    -  let declIndexes = item.declIndexes.concat([declIndex]);
    +  function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
    +    let declVal = resolveValue(decl.value);
    +    let declNames = item.declNames.concat([decl.name]);
    +    let declIndexes = item.declIndexes.concat([declIndex]);
     
    -  if (list[declIndex] != null) return;
    -  list[declIndex] = {
    -    modNames: modNames,
    -    declNames: declNames,
    -    declIndexes: declIndexes,
    -  };
    +    if (list[declIndex] != null) return;
    +    list[declIndex] = {
    +      modNames: modNames,
    +      declNames: declNames,
    +      declIndexes: declIndexes,
    +    };
     
    -  // add to search index
    -  {
    -    declSearchIndex.add(decl.name, {declIndex});
    -  }
    -  
    -  
    -  if ("type" in declVal.expr) {
    -    let value = getType(declVal.expr.type);
    -    if (declCanRepresentTypeKind(value.kind)) {
    -      canonTypeDecls[declVal.type] = declIndex;
    +    // add to search index
    +    {
    +      declSearchIndex.add(decl.name, { declIndex });
         }
     
    -    if (isContainerType(value)) {
    -      stack.push({
    -        declNames: declNames,
    -        declIndexes: declIndexes,
    -        type: value,
    -      });
    -    }
     
    -    // Generic function
    -    if (typeIsGenericFn(declVal.expr.type)) {
    -      let ret = resolveGenericRet(value);
    -      if (ret != null && "type" in ret.expr) {
    -        let generic_type = getType(ret.expr.type);
    -        if (isContainerType(generic_type)) {
    -          stack.push({
    -            declNames: declNames,
    -            declIndexes: declIndexes,
    -            type: generic_type,
    -          });
    +    if ("type" in declVal.expr) {
    +      let value = getType(declVal.expr.type);
    +      if (declCanRepresentTypeKind(value.kind)) {
    +        canonTypeDecls[declVal.type] = declIndex;
    +      }
    +
    +      if (isContainerType(value)) {
    +        stack.push({
    +          declNames: declNames,
    +          declIndexes: declIndexes,
    +          type: value,
    +        });
    +      }
    +
    +      // Generic function
    +      if (typeIsGenericFn(declVal.expr.type)) {
    +        let ret = resolveGenericRet(value);
    +        if (ret != null && "type" in ret.expr) {
    +          let generic_type = getType(ret.expr.type);
    +          if (isContainerType(generic_type)) {
    +            stack.push({
    +              declNames: declNames,
    +              declIndexes: declIndexes,
    +              type: generic_type,
    +            });
    +          }
             }
           }
         }
       }
    -}
     
       function getCanonDeclPath(index) {
         if (canonDeclPaths == null) {
    @@ -3524,7 +3297,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
       }
     
       function escapeHtml(text) {
    -    return text.replace(/[&"<>]/g, function (m) {
    +    return text.replace(/[&"<>]/g, function(m) {
           return escapeHtmlReplacements[m];
         });
       }
    @@ -3553,13 +3326,13 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
       }
     
       function parseGuides() {
    -    for (let j = 0; j < zigAnalysis.guide_sections.length; j+=1){
    +    for (let j = 0; j < zigAnalysis.guide_sections.length; j += 1) {
           const section = zigAnalysis.guide_sections[j];
    -      for (let i = 0; i < section.guides.length; i+=1){
    -        let reader = new commonmark.Parser({smart: true});
    +      for (let i = 0; i < section.guides.length; i += 1) {
    +        let reader = new commonmark.Parser({ smart: true });
             const guide = section.guides[i];
    -        const ast = reader.parse(guide.body);        
    -        
    +        const ast = reader.parse(guide.body);
    +
             // Find the first text thing to use as a sidebar title
             guide.title = "[empty guide]";
             {
    @@ -3571,7 +3344,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
                   guide.title = node.literal;
                   break;
                 }
    -          }        
    +          }
             }
             // Index this guide
             {
    @@ -3580,24 +3353,24 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
               while ((event = walker.next())) {
                 node = event.node;
                 if (event.entering == true && node.type === 'text') {
    -                indexTextForGuide(j, i, node);          
    +              indexTextForGuide(j, i, node);
                 }
    -          }        
    +          }
             }
    -      }  
    +      }
         }
       }
     
    -  function indexTextForGuide(section_idx, guide_idx, node){
    +  function indexTextForGuide(section_idx, guide_idx, node) {
         const terms = node.literal.split(" ");
    -    for (let i = 0; i < terms.length; i += 1){
    +    for (let i = 0; i < terms.length; i += 1) {
           const t = terms[i];
           if (!guidesSearchIndex[t]) guidesSearchIndex[t] = new Set();
    -      node.guide = {section_idx, guide_idx};
    +      node.guide = { section_idx, guide_idx };
           guidesSearchIndex[t].add(node);
    -    }  
    +    }
       }
    -  
    +
     
       function markdown(input, contextType) {
         const parsed = new commonmark.Parser({ smart: true }).parse(input);
    @@ -3620,70 +3393,71 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
     
         return new commonmark.HtmlRenderer({ safe: true }).render(parsed);
     
    -    function detectDeclPath(text, context) {
    -      let result = "";
    -      let separator = ":";
    -      const components = text.split(".");
    -      let curDeclOrType = undefined;
    -      
    -      let curContext = context;
    -      let limit = 10000;
    -      while (curContext) {
    -        limit -= 1;
    -        
    -        if (limit == 0) {
    -          throw "too many iterations";
    -        }
    -        
    -        curDeclOrType = findSubDecl(curContext, components[0]);
    -        
    -        if (!curDeclOrType) {
    -          if (curContext.parent_container == null) break;
    -          curContext = getType(curContext.parent_container);
    -          continue;
    -        }
    +  }
     
    -        if (curContext == context) {
    -          separator = '.';
    -          result = location.hash + separator + components[0];
    -        } else {
    -          // We had to go up, which means we need a new path!
    -          const canonPath = getCanonDeclPath(curDeclOrType.find_subdecl_idx);
    -          if (!canonPath) return;
    -          
    -          let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
    -          let fullPath = lastModName + ":" + canonPath.declNames.join(".");
    -        
    -          separator = '.';
    -          result = "#A;" + fullPath;
    -        }
    +  function detectDeclPath(text, context) {
    +    let result = "";
    +    let separator = ":";
    +    const components = text.split(".");
    +    let curDeclOrType = undefined;
     
    -        break;
    -      } 
    +    let curContext = context;
    +    let limit = 10000;
    +    while (curContext) {
    +      limit -= 1;
    +
    +      if (limit == 0) {
    +        throw "too many iterations";
    +      }
    +
    +      curDeclOrType = findSubDecl(curContext, components[0]);
     
           if (!curDeclOrType) {
    -        for (let i = 0; i < zigAnalysis.modules.length; i += 1){
    -          const p = zigAnalysis.modules[i];
    -          if (p.name == components[0]) {
    -            curDeclOrType = getType(p.main);
    -            result += "#A;" + components[0];
    -            break;
    -          }
    +        if (curContext.parent_container == null) break;
    +        curContext = getType(curContext.parent_container);
    +        continue;
    +      }
    +
    +      if (curContext == context) {
    +        separator = '.';
    +        result = location.hash + separator + components[0];
    +      } else {
    +        // We had to go up, which means we need a new path!
    +        const canonPath = getCanonDeclPath(curDeclOrType.find_subdecl_idx);
    +        if (!canonPath) return;
    +
    +        let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
    +        let fullPath = lastModName + ":" + canonPath.declNames.join(".");
    +
    +        separator = '.';
    +        result = "#A;" + fullPath;
    +      }
    +
    +      break;
    +    }
    +
    +    if (!curDeclOrType) {
    +      for (let i = 0; i < zigAnalysis.modules.length; i += 1) {
    +        const p = zigAnalysis.modules[i];
    +        if (p.name == components[0]) {
    +          curDeclOrType = getType(p.main);
    +          result += "#A;" + components[0];
    +          break;
             }
           }
    -
    -      if (!curDeclOrType) return null;
    -      
    -      for (let i = 1; i < components.length; i += 1) {
    -        curDeclOrType = findSubDecl(curDeclOrType, components[i]);
    -        if (!curDeclOrType) return null;
    -        result += separator + components[i];
    -        separator = '.';
    -      }
    -
    -      return result;
    -      
         }
    +
    +    if (!curDeclOrType) return null;
    +
    +    for (let i = 1; i < components.length; i += 1) {
    +      curDeclOrType = findSubDecl(curDeclOrType, components[i]);
    +      if (!curDeclOrType) return null;
    +      result += separator + components[i];
    +      separator = '.';
    +    }
    +
    +    return result;
    +
       }
     
       function activateSelectedResult() {
    @@ -3723,7 +3497,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
           startSearch();
         }
       }
    -  
    +
     
       function onSearchKeyDown(ev) {
         switch (getKeyString(ev)) {
    @@ -3824,7 +3598,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
             break;
           case "/":
             if (!getPrefSlashSearch()) break;
    -        // fallthrough
    +      // fallthrough
           case "s":
             if (!isModalVisible(domHelpModal) && !isModalVisible(domPrefsModal)) {
               if (ev.target == domSearch) break;
    @@ -3846,9 +3620,9 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
     
             // toggle the help modal
             if (isModalVisible(domHelpModal)) {
    -            hideModal(domHelpModal);
    +          hideModal(domHelpModal);
             } else {
    -            showModal(domHelpModal);
    +          showModal(domHelpModal);
             }
             ev.preventDefault();
             ev.stopPropagation();
    @@ -3927,21 +3701,21 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
       function renderSearchGuides() {
         const searchTrimmed = false;
         let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
    -    
    +
         let terms = getSearchTerms();
         let matchedItems = new Set();
     
         for (let i = 0; i < terms.length; i += 1) {
           const nodes = guidesSearchIndex[terms[i]];
           if (nodes) {
    -        for (const n of nodes) {      
    +        for (const n of nodes) {
               matchedItems.add(n);
             }
           }
         }
     
    -    
    -    
    +
    +
         if (matchedItems.size !== 0) {
           // Build up the list of search results
           let matchedItemsHTML = "";
    @@ -3966,14 +3740,14 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
         }
       }
     
    -  function renderSearchAPI(){
    +  function renderSearchAPI() {
         if (canonDeclPaths == null) {
           canonDeclPaths = computeCanonDeclPaths();
         }
         let declSet = new Set();
         let otherDeclSet = new Set(); // for low quality results
         let declScores = {};
    -    
    +
         let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
         let term_list = getSearchTerms();
         for (let i = 0; i < term_list.length; i += 1) {
    @@ -4004,7 +3778,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
                   if (declSet.has(p)) {
                     found = true;
                     break;
    -              }   
    +              }
                 }
                 if (!found) {
                   otherDeclSet.add(d);
    @@ -4012,9 +3786,9 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
                   termSet.add(d);
                 }
               }
    -          
    +
               if (declScores[d] == undefined) declScores[d] = 0;
    -        
    +
               // scores (lower is better)
               let decl_name = decl.name;
               if (ignoreCase) decl_name = decl_name.toLowerCase();
    @@ -4022,21 +3796,21 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
               // shallow path are preferable
               const path_depth = canonPath.declNames.length * 50;
               // matching the start of a decl name is good
    -          const match_from_start = decl_name.startsWith(term) ? -term.length * (2 -ignoreCase) : (decl_name.length - term.length) + 1; 
    +          const match_from_start = decl_name.startsWith(term) ? -term.length * (2 - ignoreCase) : (decl_name.length - term.length) + 1;
               // being a perfect match is good
               const is_full_match = (decl_name === term) ? -decl_name.length * (1 - ignoreCase) : Math.abs(decl_name.length - term.length);
               // matching the end of a decl name is good
               const matches_the_end = decl_name.endsWith(term) ? -term.length * (1 - ignoreCase) : (decl_name.length - term.length) + 1;
               // explicitly penalizing scream case decls
    -          const decl_is_scream_case = decl.name.toUpperCase() != decl.name ? 0 : decl.name.length;  
    -        
    -          const score =  path_depth 
    -            + match_from_start 
    -            + is_full_match 
    -            + matches_the_end 
    +          const decl_is_scream_case = decl.name.toUpperCase() != decl.name ? 0 : decl.name.length;
    +
    +          const score = path_depth
    +            + match_from_start
    +            + is_full_match
    +            + matches_the_end
                 + decl_is_scream_case;
     
    -          declScores[d] += score;        
    +          declScores[d] += score;
             }
           }
           if (i != 0) {
    @@ -4047,19 +3821,19 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
                 if (termSet.has(p) || otherDeclSet.has(p)) {
                   found = true;
                   break;
    -            }   
    +            }
               }
               if (found) {
                 declScores[d] = declScores[d] / term_list.length;
               }
    -          
    +
               termOtherSet.add(d);
             }
             declSet = termSet;
             for (let d of termOtherSet) {
               otherDeclSet.add(d);
             }
    -        
    +
           }
         }
     
    @@ -4068,21 +3842,21 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
           low_quality: [],
         };
         for (let idx of declSet) {
    -      matchedItems.high_quality.push({points: declScores[idx], declIndex: idx})
    +      matchedItems.high_quality.push({ points: declScores[idx], declIndex: idx })
         }
         for (let idx of otherDeclSet) {
    -      matchedItems.low_quality.push({points: declScores[idx], declIndex: idx})
    +      matchedItems.low_quality.push({ points: declScores[idx], declIndex: idx })
         }
    -    
    -    matchedItems.high_quality.sort(function (a, b) {
    +
    +    matchedItems.high_quality.sort(function(a, b) {
           let cmp = operatorCompare(a.points, b.points);
           return cmp;
         });
    -    matchedItems.low_quality.sort(function (a, b) {
    +    matchedItems.low_quality.sort(function(a, b) {
           let cmp = operatorCompare(a.points, b.points);
           return cmp;
         });
    -    
    +
         // Build up the list of search results
         let matchedItemsHTML = "";
     
    @@ -4099,7 +3873,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
     
             let lastModName = canonPath.modNames[canonPath.modNames.length - 1];
             let text = lastModName + "." + canonPath.declNames.join(".");
    -      
    +
     
             const href = navLink(canonPath.modNames, canonPath.declNames);
     
    @@ -4113,7 +3887,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
     
         domSectSearchResults.classList.remove("hidden");
       }
    -   
    +
       function renderSearchAPIOld() {
         let matchedItems = [];
         let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
    @@ -4179,7 +3953,7 @@ function addDeclToSearchResults(decl, declIndex, modNames, item, list, stack) {
         }
     
         if (matchedItems.length !== 0) {
    -      matchedItems.sort(function (a, b) {
    +      matchedItems.sort(function(a, b) {
             let cmp = operatorCompare(b.points, a.points);
             if (cmp != 0) return cmp;
             return operatorCompare(a.decl.name, b.decl.name);
    @@ -4485,12 +4259,12 @@ function toggleExpand(event) {
     function RadixTree() {
       this.root = null;
     
    -  RadixTree.prototype.search = function (query) {
    +  RadixTree.prototype.search = function(query) {
         return this.root.search(query);
    -    
    +
       }
     
    -  RadixTree.prototype.add = function (declName, value) {
    +  RadixTree.prototype.add = function(declName, value) {
         if (this.root == null) {
           this.root = new Node(declName.toLowerCase(), null, [value]);
         } else {
    @@ -4499,7 +4273,7 @@ function RadixTree() {
     
         const not_scream_case = declName.toUpperCase() != declName;
         let found_separator = false;
    -    for (let i = 1; i < declName.length; i +=1) {
    +    for (let i = 1; i < declName.length; i += 1) {
           if (declName[i] == '_' || declName[i] == '.') {
             found_separator = true;
             continue;
    @@ -4507,42 +4281,42 @@ function RadixTree() {
     
     
           if (found_separator || (declName[i].toLowerCase() !== declName[i])) {
    -        if (declName.length > i+1 
    -          && declName[i+1].toLowerCase() != declName[i+1]) continue;
    +        if (declName.length > i + 1
    +          && declName[i + 1].toLowerCase() != declName[i + 1]) continue;
             let suffix = declName.slice(i);
             this.root.add(suffix.toLowerCase(), value);
             found_separator = false;
           }
         }
       }
    -  
    +
       function Node(labels, next, values) {
    -    this.labels = labels; 
    +    this.labels = labels;
         this.next = next;
         this.values = values;
       }
     
    -  Node.prototype.isCompressed = function () {
    +  Node.prototype.isCompressed = function() {
         return !Array.isArray(this.next);
       }
     
    -  Node.prototype.search = function (word) {
    +  Node.prototype.search = function(word) {
         let full_matches = [];
         let partial_matches = [];
         let subtree_root = null;
    -    
    +
         let cn = this;
         char_loop: for (let i = 0; i < word.length;) {
           if (cn.isCompressed()) {
             for (let j = 0; j < cn.labels.length; j += 1) {
    -          let current_idx = i+j;
    +          let current_idx = i + j;
     
               if (current_idx == word.length) {
                 partial_matches = cn.values;
                 subtree_root = cn.next;
    -            break char_loop; 
    +            break char_loop;
               }
    -          
    +
               if (word[current_idx] != cn.labels[j]) return null;
             }
     
    @@ -4553,33 +4327,33 @@ function RadixTree() {
               subtree_root = cn.next;
               break char_loop;
             }
    -        
    -        
    +
    +
             i = new_idx;
             cn = cn.next;
             continue;
           } else {
             for (let j = 0; j < cn.labels.length; j += 1) {
               if (word[i] == cn.labels[j]) {
    -            if (i == word.length - 1) { 
    +            if (i == word.length - 1) {
                   full_matches = cn.values[j];
                   subtree_root = cn.next[j];
                   break char_loop;
                 }
    -              
    +
                 let next = cn.next[j];
                 if (next == null) return null;
                 cn = next;
                 i += 1;
    -            continue char_loop; 
    -          } 
    +            continue char_loop;
    +          }
             }
    -        
    +
             // didn't find a match
             return null;
           }
         }
    -    
    +
         // Match was found, let's collect all other 
         // partial matches from the subtree
         let stack = [subtree_root];
    @@ -4594,22 +4368,22 @@ function RadixTree() {
             for (let v of node.values) {
               partial_matches = partial_matches.concat(v);
             }
    -        
    +
             for (let n of node.next) {
               if (n != null) stack.push(n);
             }
           }
         }
     
    -    return {full: full_matches, partial: partial_matches};
    +    return { full: full_matches, partial: partial_matches };
       }
     
    -  Node.prototype.add = function (word, value) {
    +  Node.prototype.add = function(word, value) {
         let cn = this;
         char_loop: for (let i = 0; i < word.length;) {
           if (cn.isCompressed()) {
    -        for(let j = 0; j < cn.labels.length; j += 1) {
    -          let current_idx = i+j;
    +        for (let j = 0; j < cn.labels.length; j += 1) {
    +          let current_idx = i + j;
     
               if (current_idx == word.length) {
                 if (j < cn.labels.length - 1) {
    @@ -4621,13 +4395,13 @@ function RadixTree() {
                 cn.values.push(value);
                 return;
               }
    -          
    +
               if (word[current_idx] == cn.labels[j]) continue;
    -          
    +
               // if we're here, a mismatch was found
               if (j != cn.labels.length - 1) {
                 // create a suffix node
    -            const label_suffix = cn.labels.slice(j+1);
    +            const label_suffix = cn.labels.slice(j + 1);
                 let node = new Node(label_suffix, cn.next, [...cn.values]);
                 cn.next = node;
                 cn.values = [];
    @@ -4641,11 +4415,11 @@ function RadixTree() {
                 // meaning that the current node should hold its value
                 word_values.push(value);
               } else {
    -             node = new Node(word.slice(current_idx+1), null, [value]);
    +            node = new Node(word.slice(current_idx + 1), null, [value]);
               }
    -        
    +
               cn.labels = cn.labels[j] + word[current_idx];
    -          cn.next = [cn.next, node];          
    +          cn.next = [cn.next, node];
               cn.values = [cn.values, word_values];
     
               if (j != 0) {
    @@ -4657,7 +4431,7 @@ function RadixTree() {
               }
     
               return;
    -        }        
    +        }
             // label matched fully with word, are there any more chars?
             const new_idx = i + cn.labels.length;
             if (new_idx == word.length) {
    @@ -4673,7 +4447,7 @@ function RadixTree() {
                 i = new_idx;
                 continue;
               }
    -        } 
    +        }
           } else { // node is not compressed
             let letter = word[i];
             for (let j = 0; j < cn.labels.length; j += 1) {
    @@ -4683,7 +4457,7 @@ function RadixTree() {
                   return;
                 }
                 if (cn.next[j] == null) {
    -              let node = new Node(word.slice(i+1), null, [value]);
    +              let node = new Node(word.slice(i + 1), null, [value]);
                   cn.next[j] = node;
                   return;
                 } else {
    @@ -4700,7 +4474,7 @@ function RadixTree() {
               cn.next.push(null);
               cn.values.push([value]);
             } else {
    -          let node = new Node(word.slice(i+1), null, [value]);
    +          let node = new Node(word.slice(i + 1), null, [value]);
               cn.next.push(node);
               cn.values.push([]);
             }
    diff --git a/lib/docs/ziglexer.js b/lib/docs/ziglexer.js
    index 06a37dfb97..e049657cbf 100644
    --- a/lib/docs/ziglexer.js
    +++ b/lib/docs/ziglexer.js
    @@ -1,6 +1,7 @@
     'use strict';
     
     const Tag = {
    +    whitespace: "whitespace",
         invalid: "invalid",
         identifier: "identifier",
         string_literal: "string_literal",
    @@ -125,6 +126,27 @@ const Tag = {
         keyword_while: "keyword_while"
     }
     
    +const Tok = {
    +    const: { src: "const", tag: Tag.keyword_const },
    +    var: { src: "var", tag: Tag.keyword_var },
    +    colon: { src: ":", tag: Tag.colon },
    +    eql: { src: "=", tag: Tag.equals },
    +    space: { src: " ", tag: Tag.whitespace },
    +    tab: { src: "    ", tag: Tag.whitespace },
    +    enter: { src: "\n", tag: Tag.whitespace },
    +    semi: { src: ";", tag: Tag.semicolon },
    +    l_bracket: { src: "[", tag: Tag.l_bracket },
    +    r_bracket: { src: "]", tag: Tag.r_bracket },
    +    l_brace: { src: "{", tag: Tag.l_brace },
    +    r_brace: { src: "}", tag: Tag.r_brace },
    +    l_paren: { src: "(", tag: Tag.l_paren },
    +    r_paren: { src: ")", tag: Tag.r_paren },
    +    period: { src: ".", tag: Tag.period },
    +    comma: { src: ",", tag: Tag.comma },
    +    identifier: (name) => { return { src: name, tag: Tag.identifier } },
    +};
    +
    +
     const State = {
         start: 0,
         identifier: 1,
    @@ -175,6 +197,7 @@ const State = {
         period_2: 46,
         period_asterisk: 47,
         saw_at_sign: 48,
    +    whitespace: 49,
     }
     
     const keywords = {
    @@ -256,25 +279,36 @@ function dump_tokens(tokens, raw_source) {
         }
     }
     
    +function* Tokenizer(raw_source) {
    +    let tokenizer = new InnerTokenizer(raw_source);
    +    while (true) {
    +        let t = tokenizer.next(); 
    +        if (t.tag == Tag.eof) 
    +            return;
    +        
    +        t.src = raw_source.slice(t.loc.start, t.loc.end);
    +        
    +        yield t;
    +    }
     
    +}
    +function InnerTokenizer(raw_source) {
    +    this.index = 0;
    +    this.flag = false;
     
    -function tokenize_zig_source(raw_source) {
    +    this.seen_escape_digits = undefined;
    +    this.remaining_code_units = undefined;
     
    -    var index = 0;
    -    var flag = false;
    -
    -    let seen_escape_digits = undefined;
    -    let remaining_code_units = undefined;
    -
    -    const next = () => {
    +    this.next = () => {
             let state = State.start;
     
             var result = {
                 tag: -1,
                 loc: {
    -                start: index,
    +                start: this.index,
                     end: undefined,
                 },
    +            src: undefined,
             };
     
             //having a while (true) loop seems like a bad idea the loop should never
    @@ -284,37 +318,39 @@ function tokenize_zig_source(raw_source) {
     
             while (iterations <= MAX_ITERATIONS) {
     
    -            if (flag) {
    -                return make_token(Tag.eof, index - 2, index - 2);
    +            if (this.flag) {
    +                return make_token(Tag.eof, this.index - 2, this.index - 2);
                 }
                 iterations += 1; // avoid death loops
     
    -            var c = raw_source[index];
    +            var c = raw_source[this.index];
     
                 if (c === undefined) {
                     c = ' '; // push the last token
    -                flag = true;
    +                this.flag = true;
                 }
     
                 switch (state) {
                     case State.start:
                         switch (c) {
                             case 0: {
    -                            if (index != raw_source.length) {
    +                            if (this.index != raw_source.length) {
                                     result.tag = Tag.invalid;
    -                                result.loc.start = index;
    -                                index += 1;
    -                                result.loc.end = index;
    +                                result.loc.start = this.index;
    +                                this.index += 1;
    +                                result.loc.end = this.index;
                                     return result;
                                 }
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case ' ':
                             case '\n':
                             case '\t':
                             case '\r': {
    -                            result.loc.start = index + 1;
    +                            state = State.whitespace;
    +                            result.tag = Tag.whitespace;
    +                            result.loc.start = this.index;
                                 break;
                             }
                             case '"': {
    @@ -401,51 +437,51 @@ function tokenize_zig_source(raw_source) {
                             }
                             case '(': {
                                 result.tag = Tag.l_paren;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
     
                                 return result;
                                 
                             }
                             case ')': {
                                 result.tag = Tag.r_paren;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case '[': {
                                 result.tag = Tag.l_bracket;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case ']': {
                                 result.tag = Tag.r_bracket;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case ';': {
                                 result.tag = Tag.semicolon;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case ',': {
                                 result.tag = Tag.comma;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case '?': {
                                 result.tag = Tag.question_mark;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case ':': {
                                 result.tag = Tag.colon;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
    @@ -473,19 +509,19 @@ function tokenize_zig_source(raw_source) {
                             }
                             case '{': {
                                 result.tag = Tag.l_brace;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case '}': {
                                 result.tag = Tag.r_brace;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
                             case '~': {
                                 result.tag = Tag.tilde;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                                 
                             }
    @@ -517,8 +553,8 @@ function tokenize_zig_source(raw_source) {
                                 }
                             default: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    -                            index += 1;
    +                            result.loc.end = this.index;
    +                            this.index += 1;
                                 return result;
                             }
                         }
    @@ -588,7 +624,7 @@ function tokenize_zig_source(raw_source) {
                             }
                             default: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -597,11 +633,11 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.ampersand_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
    -                            result.tag = Tag.ampersand; result.loc.end = index;
    +                            result.tag = Tag.ampersand; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -609,12 +645,12 @@ function tokenize_zig_source(raw_source) {
                     case State.asterisk: switch (c) {
                         case '=': {
                             result.tag = Tag.asterisk_equal;
    -                        index += 1; result.loc.end = index;
    +                        this.index += 1; result.loc.end = this.index;
                             return result;
                         }
                         case '*': {
                             result.tag = Tag.asterisk_asterisk;
    -                        index += 1; result.loc.end = index;
    +                        this.index += 1; result.loc.end = this.index;
                             return result;
                         }
                         case '%': {
    @@ -625,7 +661,7 @@ function tokenize_zig_source(raw_source) {
                         }
                         default: {
                             result.tag = Tag.asterisk;
    -                        result.loc.end = index;
    +                        result.loc.end = this.index;
                             return result;
                         }
                     }
    @@ -634,12 +670,12 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.asterisk_percent_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.asterisk_percent;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                         }
    @@ -648,11 +684,11 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.asterisk_pipe_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
    -                            result.tag = Tag.asterisk_pipe; result.loc.end = index;
    +                            result.tag = Tag.asterisk_pipe; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -661,11 +697,11 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.percent_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
    -                            result.tag = Tag.percent; result.loc.end = index;
    +                            result.tag = Tag.percent; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -674,12 +710,12 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.plus_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             case '+': {
                                 result.tag = Tag.plus_plus;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             case '%': {
    @@ -689,7 +725,7 @@ function tokenize_zig_source(raw_source) {
                                 state = State.plus_pipe; break;
                             }
                             default: {
    -                            result.tag = Tag.plus; result.loc.end = index;
    +                            result.tag = Tag.plus; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -698,11 +734,11 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.plus_percent_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
    -                            result.tag = Tag.plus_percent; result.loc.end = index;
    +                            result.tag = Tag.plus_percent; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -711,11 +747,11 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.plus_pipe_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
    -                            result.tag = Tag.plus_pipe; result.loc.end = index;
    +                            result.tag = Tag.plus_pipe; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -724,11 +760,11 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.caret_equal;
    -                            index += 1; result.loc.end = index;
    +                            this.index += 1; result.loc.end = this.index;
                                 return result;
                             }
                             default: {
    -                            result.tag = Tag.caret; result.loc.end = index;
    +                            result.tag = Tag.caret; result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -799,12 +835,12 @@ function tokenize_zig_source(raw_source) {
                             case '8':
                             case '9': break;
                             default: {
    -                            // if (Token.getKeyword(buffer[result.loc.start..index])) | tag | {
    -                            const z = raw_source.substring(result.loc.start, index);
    +                            // if (Token.getKeyword(buffer[result.loc.start..this.index])) | tag | {
    +                            const z = raw_source.substring(result.loc.start, this.index);
                                 if (z in keywords) {
                                     result.tag = keywords[z];
                                 }
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
     
    @@ -875,7 +911,7 @@ function tokenize_zig_source(raw_source) {
                         case '7':
                         case '8':
                         case '9': break;
    -                    default: result.loc.end = index;
    +                    default: result.loc.end = this.index;
                             return result;
                     }
                         break;
    @@ -887,7 +923,7 @@ function tokenize_zig_source(raw_source) {
                             }
                             default: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -898,25 +934,25 @@ function tokenize_zig_source(raw_source) {
                                 state = State.string_literal_backslash; break;
                             }
                             case '"': {
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
     
                                 return result; 
                             }
                             case 0: {
                                 //TODO: PORT
    -                            // if (index == buffer.len) {
    +                            // if (this.index == buffer.len) {
                                 //     result.tag = .invalid;
                                 //     break;
                                 // } else {
                                 //     checkLiteralCharacter();
                                 // }
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                             case '\n': {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                             //TODO: PORT
    @@ -928,7 +964,7 @@ function tokenize_zig_source(raw_source) {
                             case 0:
                             case '\n': {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                             default: {
    @@ -939,7 +975,7 @@ function tokenize_zig_source(raw_source) {
                     case State.char_literal: switch (c) {
                         case 0: {
                             result.tag = Tag.invalid;
    -                        result.loc.end = index;
    +                        result.loc.end = this.index;
                             return result; 
                         }
                         case '\\': {
    @@ -952,15 +988,15 @@ function tokenize_zig_source(raw_source) {
                         //     break;
                         // },
                         // 0xc0...0xdf => { // 110xxxxx
    -                    //     remaining_code_units = 1;
    +                    //     this.remaining_code_units = 1;
                         //     state = .char_literal_unicode;
                         // },
                         // 0xe0...0xef => { // 1110xxxx
    -                    //     remaining_code_units = 2;
    +                    //     this.remaining_code_units = 2;
                         //     state = .char_literal_unicode;
                         // },
                         // 0xf0...0xf7 => { // 11110xxx
    -                    //     remaining_code_units = 3;
    +                    //     this.remaining_code_units = 3;
                         //     state = .char_literal_unicode;
                         // },
     
    @@ -1070,7 +1106,7 @@ function tokenize_zig_source(raw_source) {
                         // case 0xdd:
                         // case 0xde:
                         // case 0xdf:
    -                    //     remaining_code_units = 1;
    +                    //     this.remaining_code_units = 1;
                         //     state = .char_literal_unicode;
                         // case 0xe0:
                         // case 0xe1:
    @@ -1088,7 +1124,7 @@ function tokenize_zig_source(raw_source) {
                         // case 0xed:
                         // case 0xee:
                         // case 0xef:
    -                    //     remaining_code_units = 2;
    +                    //     this.remaining_code_units = 2;
                         //     state = .char_literal_unicode;
                         // case 0xf0:
                         // case 0xf1:
    @@ -1098,12 +1134,12 @@ function tokenize_zig_source(raw_source) {
                         // case 0xf5:
                         // case 0xf6:
                         // case 0xf7:
    -                    //     remaining_code_units = 3;
    +                    //     this.remaining_code_units = 3;
                         //     state = .char_literal_unicode;
     
                         case '\n': {
                             result.tag = Tag.invalid;
    -                        result.loc.end = index;
    +                        result.loc.end = this.index;
                             return result; 
                         }
                         default: {
    @@ -1116,12 +1152,12 @@ function tokenize_zig_source(raw_source) {
                             case 0:
                             case '\n': {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                             case 'x': {
                                 state = State.char_literal_hex_escape;
    -                            seen_escape_digits = 0; break;
    +                            this.seen_escape_digits = 0; break;
                             }
                             case 'u': {
                                 state = State.char_literal_unicode_escape_saw_u; break;
    @@ -1155,14 +1191,14 @@ function tokenize_zig_source(raw_source) {
                             case 'D':
                             case 'E':
                             case 'F': {
    -                            seen_escape_digits += 1;
    -                            if (seen_escape_digits == 2) {
    +                            this.seen_escape_digits += 1;
    +                            if (this.seen_escape_digits == 2) {
                                     state = State.char_literal_end;
                                 } break;
                             }
                             default: {
                                 result.tag = Tag.invalid;
    -                            esult.loc.end = index;
    +                            esult.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1171,7 +1207,7 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case 0: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '{': {
    @@ -1187,7 +1223,7 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case 0: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '0':
    @@ -1297,13 +1333,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '\'': {
                                 result.tag = Tag.char_literal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                             default: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                         }
    @@ -1311,14 +1347,14 @@ function tokenize_zig_source(raw_source) {
                     case State.char_literal_unicode:
                         switch (c) {
                             // 0x80...0xbf => {
    -                        //         remaining_code_units -= 1;
    -                        //         if (remaining_code_units == 0) {
    +                        //         this.remaining_code_units -= 1;
    +                        //         if (this.remaining_code_units == 0) {
                             //             state = .char_literal_end;
                             //         }
                             //     },
                             default: {
                                 result.tag = Tag.invalid;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result; 
                             }
                         }
    @@ -1326,12 +1362,12 @@ function tokenize_zig_source(raw_source) {
                     case State.multiline_string_literal_line:
                         switch (c) {
                             case 0:
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             case '\n': {
     
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '\t': break;
    @@ -1344,13 +1380,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.bang_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.bang;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1359,19 +1395,19 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.pipe_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '|': {
                                 result.tag = Tag.pipe_pipe;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.pipe;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1379,19 +1415,19 @@ function tokenize_zig_source(raw_source) {
                     case State.equal: switch (c) {
                         case '=': {
                             result.tag = Tag.equal_equal;
    -                        index += 1;
    -                        result.loc.end = index;
    +                        this.index += 1;
    +                        result.loc.end = this.index;
                             return result;
                         }
                         case '>': {
                             result.tag = Tag.equal_angle_bracket_right;
    -                        index += 1;
    -                        result.loc.end = index;
    +                        this.index += 1;
    +                        result.loc.end = this.index;
                             return result;
                         }
                         default: {
                             result.tag = Tag.equal;
    -                        result.loc.end = index;
    +                        result.loc.end = this.index;
                             return result;
                         }
                     }
    @@ -1399,14 +1435,14 @@ function tokenize_zig_source(raw_source) {
                     case State.minus: switch (c) {
                         case '>': {
                             result.tag = Tag.arrow;
    -                        index += 1;
    -                        result.loc.end = index;
    +                        this.index += 1;
    +                        result.loc.end = this.index;
                             return result;
                         }
                         case '=': {
                             result.tag = Tag.minus_equal;
    -                        index += 1;
    -                        result.loc.end = index;
    +                        this.index += 1;
    +                        result.loc.end = this.index;
                             return result;
                         }
                         case '%': {
    @@ -1417,7 +1453,7 @@ function tokenize_zig_source(raw_source) {
                         }
                         default: {
                             result.tag = Tag.minus;
    -                        result.loc.end = index;
    +                        result.loc.end = this.index;
                             return result;
                         }
                     }
    @@ -1426,13 +1462,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.minus_percent_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.minus_percent;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1441,13 +1477,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.minus_pipe_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.minus_pipe;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1459,13 +1495,13 @@ function tokenize_zig_source(raw_source) {
                             }
                             case '=': {
                                 result.tag = Tag.angle_bracket_left_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.angle_bracket_left;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1474,8 +1510,8 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.angle_bracket_angle_bracket_left_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '|': {
    @@ -1483,7 +1519,7 @@ function tokenize_zig_source(raw_source) {
                             }
                             default: {
                                 result.tag = Tag.angle_bracket_angle_bracket_left;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1492,13 +1528,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.angle_bracket_angle_bracket_left_pipe_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.angle_bracket_angle_bracket_left_pipe;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1510,13 +1546,13 @@ function tokenize_zig_source(raw_source) {
                             }
                             case '=': {
                                 result.tag = Tag.angle_bracket_right_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.angle_bracket_right;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1525,13 +1561,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '=': {
                                 result.tag = Tag.angle_bracket_angle_bracket_right_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.angle_bracket_angle_bracket_right;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1546,7 +1582,7 @@ function tokenize_zig_source(raw_source) {
                             }
                             default: {
                                 result.tag = Tag.period;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1555,13 +1591,13 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '.': {
                                 result.tag = Tag.ellipsis3;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.ellipsis2;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1570,12 +1606,12 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case '*': {
                                 result.tag = Tag.invalid_periodasterisks;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.period_asterisk;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         }
    @@ -1588,24 +1624,24 @@ function tokenize_zig_source(raw_source) {
                             }
                             case '=': {
                                 result.tag = Tag.slash_equal;
    -                            index += 1;
    -                            result.loc.end = index;
    +                            this.index += 1;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             default: {
                                 result.tag = Tag.slash;
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                         } break;
                     case State.line_comment_start:
                         switch (c) {
                             case 0: {
    -                            if (index != raw_source.length) {
    +                            if (this.index != raw_source.length) {
                                     result.tag = Tag.invalid;
    -                                index += 1;
    +                                this.index += 1;
                                 }
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '/': {
    @@ -1617,7 +1653,7 @@ function tokenize_zig_source(raw_source) {
                             }
                             case '\n': {
                                 state = State.start;
    -                            result.loc.start = index + 1; break;
    +                            result.loc.start = this.index + 1; break;
                             }
                             case '\t':
                                 state = State.line_comment; break;
    @@ -1637,7 +1673,7 @@ function tokenize_zig_source(raw_source) {
                             case '\n':
                                 {
                                     result.tag = Tag.doc_comment;
    -                                result.loc.end = index;
    +                                result.loc.end = this.index;
                                     return result;
                                 }
                             case '\t': {
    @@ -1655,16 +1691,16 @@ function tokenize_zig_source(raw_source) {
                     case State.line_comment:
                         switch (c) {
                             case 0: {
    -                            if (index != raw_source.length) {
    +                            if (this.index != raw_source.length) {
                                     result.tag = Tag.invalid;
    -                                index += 1;
    +                                this.index += 1;
                                 }
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             }
                             case '\n': {
                                 state = State.start;
    -                            result.loc.start = index + 1;
    +                            result.loc.start = this.index + 1;
                                 break;
                             }
                             case '\t': break;
    @@ -1675,7 +1711,7 @@ function tokenize_zig_source(raw_source) {
                         switch (c) {
                             case 0://
                             case '\n':
    -                            result.loc.end = index;
    +                            result.loc.end = this.index;
                                 return result;
                             case '\t': break;
                             //TODOL PORT
    @@ -1754,7 +1790,7 @@ function tokenize_zig_source(raw_source) {
                             case 'P':
                                 state = State.int_exponent;
                                 break;
    -                        default: result.loc.end = index;
    +                        default: result.loc.end = this.index;
                                 return result;
                         } break;
                     case State.int_exponent:
    @@ -1766,7 +1802,7 @@ function tokenize_zig_source(raw_source) {
                                     state = State.float; break;
                                 }
                             default: {
    -                            index -= 1;
    +                            this.index -= 1;
                                 state = State.int; break;
                             }
                         } break;
    @@ -1838,8 +1874,8 @@ function tokenize_zig_source(raw_source) {
                         case 'P':
                             state = State.float_exponent; break;
                         default: {
    -                        index -= 1;
    -                        result.loc.end = index;
    +                        this.index -= 1;
    +                        result.loc.end = this.index;
                             return result;
                         }
                     } break;
    @@ -1911,7 +1947,7 @@ function tokenize_zig_source(raw_source) {
                             case 'p':
                             case 'P':
                                 state = State.float_exponent; break;
    -                        default: result.loc.end = index;
    +                        default: result.loc.end = this.index;
                                 return result;
                         } break;
                     case State.float_exponent:
    @@ -1920,13 +1956,27 @@ function tokenize_zig_source(raw_source) {
                             case '+':
                                 state = State.float; break;
                             default: {
    -                            index -= 1;
    +                            this.index -= 1;
                                 state = State.float; break;
                             }
                         }
                         break;
    +
    +                case State.whitespace:
    +                    switch(c) {
    +                        case ' ':
    +                        case '\n':
    +                        case '\t':
    +                        case '\r': {
    +                            break;
    +                        }
    +                        default: {
    +                            result.loc.end = this.index;
    +                            return result;
    +                        }
    +                   }
                 }
    -            index += 1;
    +            this.index += 1;
             }
     
             //TODO: PORT
    @@ -1938,52 +1988,37 @@ function tokenize_zig_source(raw_source) {
             //     result.loc.start = sindex;
             // }
     
    -        result.loc.end = index;
    +        result.loc.end = this.index;
             return result;
     
         }
    -
    -    let toks = []
    -
    -    for (let i = 0; i < raw_source.length * 2; i++) {
    -        const tok = next();
    -        toks.push(tok);
    -
    -        if (tok.tag == Tag.eof) {
    -            break;
    -        }
    -    }
    -
    -    return toks;
     }
     
     
    -function generate_html_for_src(src) {
    -    var toks = tokenize_zig_source(src);
    -    var html = [];
    +const builtin_types = [
    +    "f16",          "f32",     "f64",        "f80",          "f128",
    +    "c_longdouble", "c_short", "c_ushort",   "c_int",        "c_uint",
    +    "c_long",       "c_ulong", "c_longlong", "c_ulonglong",  "c_char",
    +    "anyopaque",    "void",    "bool",       "isize",        "usize",
    +    "noreturn",     "type",    "anyerror",   "comptime_int", "comptime_float",
    +];
     
    -    let offset = 0;
    -    for (let z = 0; z < toks.length; z++) {
    -        const t = toks[z];
    +function isSimpleType(typeName) {
    +    return builtin_types.includes(typeName) || isIntType(typeName);
    +}
     
    -        if(t.tag == Tag.eof)
    -            break;
    -
    -        const spanStart = ``
    -        const spanEnd = ``
    -
    -        src = `${src.slice(0, t.loc.start + offset)}` + spanStart + `${src.slice(t.loc.start + offset)}`;
    -        offset += spanStart.length;
    -
    -        src = `${src.slice(0, t.loc.end + offset)}` + spanEnd + `${src.slice(t.loc.end + offset)}`;
    -        offset += spanEnd.length;
    +function isIntType(typeName) {
    +    if (typeName[0] != 'u' && typeName[0] != 'i') return false;
    +    let i = 1;
    +    if (i == typeName.length) return false;
    +    for (; i < typeName.length; i += 1) {
    +        if (typeName[i] < '0' || typeName[i] > '9') return false;
         }
    +    return true;
    +}
     
    -
    -    html.push(src);
    -
    -    return html.join("");
    -
    +function isSpecialIndentifier(identifier) {
    +    return ["null", "true", "false", ,"undefined"].includes(identifier);
     }
     
     //const fs = require('fs');
    diff --git a/src/Autodoc.zig b/src/Autodoc.zig
    index fd1e064625..3c6d8f8f60 100644
    --- a/src/Autodoc.zig
    +++ b/src/Autodoc.zig
    @@ -814,6 +814,7 @@ const DocData = struct {
             this: usize, // index in `types`
             declRef: *Scope.DeclStatus,
             declIndex: usize, // index into `decls`, alternative repr for `declRef`
    +        declName: []const u8, // unresolved decl name
             builtinField: enum { len, ptr },
             fieldRef: FieldRef,
             refPath: []Expr,
    @@ -2282,7 +2283,7 @@ fn walkInstruction(
     
                 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
                 try path.append(self.arena, .{
    -                .string = file.zir.nullTerminatedString(extra.data.field_name_start),
    +                .declName = file.zir.nullTerminatedString(extra.data.field_name_start),
                 });
     
                 // Put inside path the starting index of each decl name that
    @@ -2304,7 +2305,7 @@ fn walkInstruction(
                         );
     
                         try path.append(self.arena, .{
    -                        .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
    +                        .declName = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
                         });
                     }
                 };
    @@ -3665,7 +3666,7 @@ fn tryResolveRefPath(
         var i: usize = 0;
         outer: while (i < path.len - 1) : (i += 1) {
             const parent = path[i];
    -        const child_string = path[i + 1].string; // we expect to find a string union case
    +        const child_string = path[i + 1].declName; // we expect to find an unsolved decl
     
             var resolved_parent = parent;
             var j: usize = 0;
    @@ -3738,14 +3739,14 @@ fn tryResolveRefPath(
                             return;
                         }
     
    -                    // If the last element is a string or a CTE, then we give up,
    +                    // If the last element is a declName or a CTE, then we give up,
                         // otherwise we resovle the parent to it and loop again.
                         // NOTE: we assume that if we find a string, it's because of
                         // a CTE component somewhere in the path. We know that the path
                         // is not pending futher evaluation because we just checked!
                         const last = rp[rp.len - 1];
                         switch (last) {
    -                        .comptimeExpr, .string => break :outer,
    +                        .comptimeExpr, .declName => break :outer,
                             else => {
                                 resolved_parent = last;
                                 continue;
    @@ -3772,7 +3773,7 @@ fn tryResolveRefPath(
                         "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
                         .{ @tagName(resolved_parent), resolved_parent },
                     );
    -                path[i + 1] = (try self.cteTodo("")).expr;
    +                // path[i + 1] = (try self.cteTodo("")).expr;
                     continue :outer;
                 },
                 .comptimeExpr, .call, .typeOf => {