Commit 1014cfdf3b
Changed files (6)
lib
std
tools
lib/std/special/docs/index.html
@@ -104,6 +104,16 @@
background-color: #FFBB4D;
color: #000;
}
+ #listFnExamples {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ }
+ #listFnExamples li {
+ padding: 0.5em 0;
+ white-space: nowrap;
+ overflow-x: auto;
+ }
#logo {
width: 8em;
padding: 0.5em 1em;
@@ -289,7 +299,6 @@
<pre id="fnProtoCode"></pre>
</div>
<h1 id="hdrName" class="hidden"></h1>
- <div id="fnExamples" class="hidden"></div>
<div id="fnNoExamples" class="hidden">
<p>This function is not tested or referenced.</p>
</div>
@@ -357,6 +366,10 @@
<ul id="listErrSets">
</ul>
</div>
+ <div id="fnExamples" class="hidden">
+ <h2>Examples</h2>
+ <ul id="listFnExamples"></ul>
+ </div>
</section>
<div id="helpDialog" class="hidden">
<h1>Keyboard Shortcuts</h1>
lib/std/special/docs/main.js
@@ -26,6 +26,7 @@
var domTableFnErrors = document.getElementById("tableFnErrors");
var domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
var domFnExamples = document.getElementById("fnExamples");
+ var domListFnExamples = document.getElementById("listFnExamples");
var domFnNoExamples = document.getElementById("fnNoExamples");
var domDeclNoRef = document.getElementById("declNoRef");
var domSearch = document.getElementById("search");
@@ -64,6 +65,9 @@
declNames: [],
// these will be all types, except the last one may be a type or a decl
declObjs: [],
+
+ // (a, b, c, d) comptime call; result is the value the docs refer to
+ callName: null,
};
var curNavSearch = "";
var curSearchIndex = -1;
@@ -237,20 +241,29 @@
renderErrorSet(errSetType);
}
- var protoSrcIndex;
+ var fnObj = zigAnalysis.fns[fnDecl.value];
+ var protoSrcIndex = fnObj.src;
if (typeIsGenericFn(fnDecl.type)) {
- protoSrcIndex = fnDecl.value;
-
var instantiations = nodesToFnsMap[protoSrcIndex];
var calls = nodesToCallsMap[protoSrcIndex];
if (instantiations == null && calls == null) {
domFnNoExamples.classList.remove("hidden");
- } else {
- // TODO show examples
+ } else if (calls != null) {
+ if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
+ if (fnObj.combined != null) renderContainer(fnObj.combined);
+
+ resizeDomList(domListFnExamples, calls.length, '<li></li>');
+
+ for (var callI = 0; callI < calls.length; callI += 1) {
+ var liDom = domListFnExamples.children[callI];
+ liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
+ }
+
domFnExamples.classList.remove("hidden");
+ } else if (instantiations != null) {
+ // TODO
}
} else {
- protoSrcIndex = zigAnalysis.fns[fnDecl.value].src;
domFnExamples.classList.add("hidden");
domFnNoExamples.classList.add("hidden");
@@ -349,13 +362,15 @@
}
}
- function navLink(pkgNames, declNames) {
+ function navLink(pkgNames, declNames, callName) {
if (pkgNames.length === 0 && declNames.length === 0) {
return '#';
- } else if (declNames.length === 0) {
+ } else if (declNames.length === 0 && callName == null) {
return '#' + pkgNames.join('.');
- } else {
+ } else if (callName == null) {
return '#' + pkgNames.join('.') + ';' + declNames.join('.');
+ } else {
+ return '#' + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;
}
}
@@ -367,6 +382,22 @@
return navLink(curNav.pkgNames, curNav.declNames.concat([childName]));
}
+ function navLinkCall(callObj) {
+ var declNamesCopy = curNav.declNames.concat([]);
+ var callName = declNamesCopy.pop();
+
+ callName += '(';
+ for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
+ if (arg_i !== 0) callName += ',';
+ var argObj = callObj.args[arg_i];
+ callName += getValueText(argObj.type, argObj.value, false, false);
+ }
+ callName += ')';
+
+ declNamesCopy.push(callName);
+ return navLink(curNav.pkgNames, declNamesCopy);
+ }
+
function resizeDomListDl(dlDom, desiredLen) {
// add the missing dom entries
var i, ev;
@@ -426,6 +457,40 @@
return (typeObj.len == null) ? pointerSizeEnum.One : typeObj.len;
}
+ function getCallHtml(fnDecl, callIndex) {
+ var callObj = zigAnalysis.calls[callIndex];
+
+ // TODO make these links work
+ //var html = '<a href="' + navLinkCall(callObj) + '">' + escapeHtml(fnDecl.name) + '</a>(';
+ var html = escapeHtml(fnDecl.name) + '(';
+ for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
+ if (arg_i !== 0) html += ', ';
+ var argObj = callObj.args[arg_i];
+ html += getValueText(argObj.type, argObj.value, true, true);
+ }
+ html += ')';
+ return html;
+ }
+
+ function getValueText(typeIndex, value, wantHtml, wantLink) {
+ var typeObj = zigAnalysis.types[typeIndex];
+ switch (typeObj.kind) {
+ case typeKinds.Type:
+ return typeIndexName(value, wantHtml, wantLink);
+ case typeKinds.Fn:
+ var fnObj = zigAnalysis.fns[value];
+ return typeIndexName(fnObj.type, wantHtml, wantLink);
+ case typeKinds.Int:
+ if (wantHtml) {
+ return '<span class="tok-number">' + value + '</span>';
+ } else {
+ return value + "";
+ }
+ default:
+ throw new Error("TODO implement getValueText for this type");
+ }
+ }
+
function typeName(typeObj, wantHtml, wantSubLink, fnDecl, linkFnNameDecl) {
switch (typeObj.kind) {
case typeKinds.Array:
@@ -544,6 +609,12 @@
} else {
return "void";
}
+ case typeKinds.EnumLiteral:
+ if (wantHtml) {
+ return '<span class="tok-type">(enum literal)</span>';
+ } else {
+ return "(enum literal)";
+ }
case typeKinds.NoReturn:
if (wantHtml) {
return '<span class="tok-type">noreturn</span>';
@@ -592,6 +663,15 @@
}
payloadHtml += '(';
if (typeObj.args != null) {
+ var fields = null;
+ var isVarArgs = false;
+ if (fnDecl != null) {
+ var fnObj = zigAnalysis.fns[fnDecl.value];
+ var fnNode = zigAnalysis.astNodes[fnObj.src];
+ fields = fnNode.fields;
+ isVarArgs = fnNode.varArgs;
+ }
+
for (var i = 0; i < typeObj.args.length; i += 1) {
if (i != 0) {
payloadHtml += ', ';
@@ -599,10 +679,31 @@
var argTypeIndex = typeObj.args[i];
- if (fnDecl != null && zigAnalysis.astNodes[fnDecl.src].fields != null) {
- var paramDeclIndex = zigAnalysis.astNodes[fnDecl.src].fields[i];
- var paramName = zigAnalysis.astNodes[paramDeclIndex].name;
+ if (fields != null) {
+ var paramNode = zigAnalysis.astNodes[fields[i]];
+
+ if (paramNode.varArgs) {
+ payloadHtml += '...';
+ continue;
+ }
+
+ if (paramNode.noalias) {
+ if (wantHtml) {
+ payloadHtml += '<span class="tok-kw">noalias</span> ';
+ } else {
+ payloadHtml += 'noalias ';
+ }
+ }
+
+ if (paramNode.comptime) {
+ if (wantHtml) {
+ payloadHtml += '<span class="tok-kw">comptime</span> ';
+ } else {
+ payloadHtml += 'comptime ';
+ }
+ }
+ var paramName = paramNode.name;
if (paramName != null) {
// skip if it matches the type name
if (argTypeIndex == null || !shouldSkipParamName(argTypeIndex, paramName)) {
@@ -611,7 +712,9 @@
}
}
- if (argTypeIndex != null) {
+ if (isVarArgs && i === typeObj.args.length - 1) {
+ payloadHtml += '...';
+ } else if (argTypeIndex != null) {
payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink);
} else if (wantHtml) {
payloadHtml += '<span class="tok-kw">var</span>';
@@ -690,7 +793,7 @@
}
function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
- var srcIndex = typeIsGenericFn(typeIndex) ? value : zigAnalysis.fns[value].src;
+ var srcIndex = zigAnalysis.fns[value].src;
var calls = nodesToCallsMap[srcIndex];
if (calls == null) return false;
for (var i = 0; i < calls.length; i += 1) {
@@ -700,6 +803,90 @@
return true;
}
+ function allCompTimeFnCallsResult(calls) {
+ var firstTypeObj = null;
+ var containerObj = {
+ privDecls: [],
+ };
+ for (var callI = 0; callI < calls.length; callI += 1) {
+ var call = zigAnalysis.calls[calls[callI]];
+ if (call.result.type !== typeTypeId) return null;
+ var typeObj = zigAnalysis.types[call.result.value];
+ if (!typeKindIsContainer(typeObj.kind)) return null;
+ if (firstTypeObj == null) {
+ firstTypeObj = typeObj;
+ containerObj.src = typeObj.src;
+ } else if (firstTypeObj.src !== typeObj.src) {
+ return null;
+ }
+
+ if (containerObj.fields == null) {
+ containerObj.fields = (typeObj.fields || []).concat([]);
+ } else for (var fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
+ var prev = containerObj.fields[fieldI];
+ var next = typeObj.fields[fieldI];
+ if (prev === next) continue;
+ if (typeof(prev) === 'object') {
+ if (prev[next] == null) prev[next] = typeObj;
+ } else {
+ containerObj.fields[fieldI] = {};
+ containerObj.fields[fieldI][prev] = firstTypeObj;
+ containerObj.fields[fieldI][next] = typeObj;
+ }
+ }
+
+ if (containerObj.pubDecls == null) {
+ containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
+ } else for (var declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
+ var prev = containerObj.pubDecls[declI];
+ var next = typeObj.pubDecls[declI];
+ if (prev === next) continue;
+ // TODO instead of showing "examples" as the public declarations,
+ // do logic like this:
+ //if (typeof(prev) !== 'object') {
+ // var newDeclId = zigAnalysis.decls.length;
+ // prev = clone(zigAnalysis.decls[prev]);
+ // prev.id = newDeclId;
+ // zigAnalysis.decls.push(prev);
+ // containerObj.pubDecls[declI] = prev;
+ //}
+ //mergeDecls(prev, next, firstTypeObj, typeObj);
+ }
+ }
+ for (var declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
+ var decl = containerObj.pubDecls[declI];
+ if (typeof(decl) === 'object') {
+ containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
+ }
+ }
+ return containerObj;
+ }
+
+ function mergeDecls(declObj, nextDeclIndex, firstTypeObj, typeObj) {
+ var nextDeclObj = zigAnalysis.decls[nextDeclIndex];
+ if (declObj.type != null && nextDeclObj.type != null && declObj.type !== nextDeclObj.type) {
+ if (typeof(declObj.type) !== 'object') {
+ var prevType = declObj.type;
+ declObj.type = {};
+ declObj.type[prevType] = firstTypeObj;
+ declObj.value = null;
+ }
+ declObj.type[nextDeclObj.type] = typeObj;
+ } else if (declObj.type == null && nextDeclObj != null) {
+ declObj.type = nextDeclObj.type;
+ }
+ if (declObj.value != null && nextDeclObj.value != null && declObj.value !== nextDeclObj.value) {
+ if (typeof(declObj.value) !== 'object') {
+ var prevValue = declObj.value;
+ declObj.value = {};
+ declObj.value[prevValue] = firstTypeObj;
+ }
+ declObj.value[nextDeclObj.value] = typeObj;
+ } else if (declObj.value == null && nextDeclObj.value != null) {
+ declObj.value = nextDeclObj.value;
+ }
+ }
+
function renderValue(decl) {
domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true);
@@ -733,13 +920,15 @@
var fnsList = [];
var varsList = [];
var valsList = [];
+
for (var i = 0; i < container.pubDecls.length; i += 1) {
var decl = zigAnalysis.decls[container.pubDecls[i]];
+
if (decl.kind === 'var') {
varsList.push(decl);
continue;
} else if (decl.kind === 'const' && decl.type != null) {
- if (decl.type == typeTypeId) {
+ if (decl.type === typeTypeId) {
if (typeIsErrSet(decl.value)) {
errSetsList.push(decl);
} else if (typeIsStructWithNoFields(decl.value)) {
@@ -838,7 +1027,12 @@
if (container.kind === typeKinds.Enum) {
html += ' = <span class="tok-number">' + field + '</span>';
} else {
- html += ": " + typeIndexName(field, true, true);
+ html += ": ";
+ if (typeof(field) === 'object') {
+ html += '<span class="tok-kw">var</span>';
+ } else {
+ html += typeIndexName(field, true, true);
+ }
}
html += ',</pre>';
@@ -1042,13 +1236,16 @@
return list;
}
- function declCanRepresentTypeKind(typeKind) {
- return typeKind === typeKinds.ErrorSet ||
- typeKind === typeKinds.Struct ||
+ function typeKindIsContainer(typeKind) {
+ return typeKind === typeKinds.Struct ||
typeKind === typeKinds.Union ||
typeKind === typeKinds.Enum;
}
+ function declCanRepresentTypeKind(typeKind) {
+ return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
+ }
+
function computeCanonDeclPaths() {
var list = new Array(zigAnalysis.decls.length);
canonTypeDecls = new Array(zigAnalysis.types.length);
@@ -1406,4 +1603,18 @@
function byNameProperty(a, b) {
return operatorCompare(a.name, b.name);
}
+
+ function clone(obj) {
+ var res = {};
+ for (var key in obj) {
+ res[key] = obj[key];
+ }
+ return res;
+ }
+
+ function firstObjectKey(obj) {
+ for (var key in obj) {
+ return key;
+ }
+ }
})();
lib/std/hash_map.zig
@@ -36,7 +36,8 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
size: usize,
max_distance_from_start_index: usize,
allocator: *Allocator,
- // this is used to detect bugs where a hashtable is edited while an iterator is running.
+
+ /// This is used to detect bugs where a hashtable is edited while an iterator is running.
modification_count: debug_u32,
const Self = @This();
lib/std/meta.zig
@@ -542,3 +542,13 @@ pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag {
}
return error.InvalidEnumTag;
}
+
+/// Given a type and a name, return the field index according to source order.
+/// Returns `null` if the field is not found.
+pub fn fieldIndex(comptime T: type, comptime name: []const u8) ?comptime_int {
+ inline for (fields(T)) |field, i| {
+ if (mem.eql(u8, field.name, name))
+ return comptime_int(i);
+ }
+ return null;
+}
src/dump_analysis.cpp
@@ -456,6 +456,10 @@ static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) {
auto existing_entry = ctx->fn_map.put_unique(fn, fn_id);
if (existing_entry == nullptr) {
ctx->fn_list.append(fn);
+
+ // poke the fn
+ (void)anal_dump_get_type_id(ctx, fn->type_entry);
+ (void)anal_dump_get_node_id(ctx, fn->proto_node);
} else {
fn_id = existing_entry->value;
}
@@ -700,11 +704,7 @@ static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty,
case ZigTypeIdFn: {
if (value->data.x_ptr.special == ConstPtrSpecialFunction) {
ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry;
- if (val_fn->type_entry->data.fn.is_generic) {
- anal_dump_node_ref(ctx, val_fn->proto_node);
- } else {
- anal_dump_fn_ref(ctx, val_fn);
- }
+ anal_dump_fn_ref(ctx, val_fn);
} else {
jw_null(&ctx->jw);
}
@@ -758,6 +758,7 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
switch (ty->id) {
case ZigTypeIdMetaType:
case ZigTypeIdBool:
+ case ZigTypeIdEnumLiteral:
break;
case ZigTypeIdStruct: {
if (ty->data.structure.is_slice) {
@@ -1072,13 +1073,25 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
jw_object_field(jw, "col");
jw_int(jw, node->column);
- const Buf *doc_comments_buf;
+ const Buf *doc_comments_buf = nullptr;
+ const Buf *name_buf = nullptr;
+ const ZigList<AstNode *> *field_nodes = nullptr;
+ bool is_var_args = false;
+ bool is_noalias = false;
+ bool is_comptime = false;
+
switch (node->type) {
case NodeTypeParamDecl:
doc_comments_buf = &node->data.param_decl.doc_comments;
+ name_buf = node->data.param_decl.name;
+ is_var_args = node->data.param_decl.is_var_args;
+ is_noalias = node->data.param_decl.is_noalias;
+ is_comptime = node->data.param_decl.is_comptime;
break;
case NodeTypeFnProto:
doc_comments_buf = &node->data.fn_proto.doc_comments;
+ field_nodes = &node->data.fn_proto.params;
+ is_var_args = node->data.fn_proto.is_var_args;
break;
case NodeTypeVariableDeclaration:
doc_comments_buf = &node->data.variable_declaration.doc_comments;
@@ -1088,55 +1101,50 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
break;
case NodeTypeStructField:
doc_comments_buf = &node->data.struct_field.doc_comments;
+ name_buf = node->data.struct_field.name;
+ break;
+ case NodeTypeContainerDecl:
+ field_nodes = &node->data.container_decl.fields;
break;
default:
- doc_comments_buf = nullptr;
break;
}
+
if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) {
jw_object_field(jw, "docs");
jw_string(jw, buf_ptr(doc_comments_buf));
}
- const Buf *name_buf;
- switch (node->type) {
- case NodeTypeStructField:
- name_buf = node->data.struct_field.name;
- break;
- case NodeTypeParamDecl:
- name_buf = node->data.param_decl.name;
- break;
- default:
- name_buf = nullptr;
- break;
- }
if (name_buf != nullptr) {
jw_object_field(jw, "name");
jw_string(jw, buf_ptr(name_buf));
}
- const ZigList<AstNode *> *fieldNodes;
- switch (node->type) {
- case NodeTypeContainerDecl:
- fieldNodes = &node->data.container_decl.fields;
- break;
- case NodeTypeFnProto:
- fieldNodes = &node->data.fn_proto.params;
- break;
- default:
- fieldNodes = nullptr;
- break;
- }
- if (fieldNodes != nullptr) {
+ if (field_nodes != nullptr) {
jw_object_field(jw, "fields");
jw_begin_array(jw);
- for (size_t i = 0; i < fieldNodes->length; i += 1) {
+ for (size_t i = 0; i < field_nodes->length; i += 1) {
jw_array_elem(jw);
- anal_dump_node_ref(ctx, fieldNodes->at(i));
+ anal_dump_node_ref(ctx, field_nodes->at(i));
}
jw_end_array(jw);
}
+ if (is_var_args) {
+ jw_object_field(jw, "varArgs");
+ jw_bool(jw, true);
+ }
+
+ if (is_comptime) {
+ jw_object_field(jw, "comptime");
+ jw_bool(jw, true);
+ }
+
+ if (is_noalias) {
+ jw_object_field(jw, "noalias");
+ jw_bool(jw, true);
+ }
+
jw_end_object(jw);
}
@@ -1235,59 +1243,76 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
jw_object_field(jw, "calls");
jw_begin_array(jw);
{
+ ZigList<ZigVar *> var_stack = {};
+
auto it = g->memoized_fn_eval_table.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
break;
- jw_array_elem(jw);
- jw_begin_object(jw);
-
- jw_object_field(jw, "args");
- jw_begin_object(jw);
+ var_stack.resize(0);
+ ZigFn *fn = nullptr;
Scope *scope = entry->key;
while (scope != nullptr) {
if (scope->id == ScopeIdVarDecl) {
ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
- jw_object_field(jw, var->name);
- jw_begin_object(jw);
- jw_object_field(jw, "type");
- anal_dump_type_ref(&ctx, var->var_type);
- jw_object_field(jw, "value");
- anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value);
- jw_end_object(jw);
+ var_stack.append(var);
} else if (scope->id == ScopeIdFnDef) {
- jw_end_object(jw);
+ fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry;
+ break;
+ }
+ scope = scope->parent;
+ }
+ ConstExprValue *result = entry->value;
+
+ assert(fn != nullptr);
+
+ jw_array_elem(jw);
+ jw_begin_object(jw);
+
+ jw_object_field(jw, "fn");
+ anal_dump_fn_ref(&ctx, fn);
+
+ jw_object_field(jw, "result");
+ {
+ jw_begin_object(jw);
+
+ jw_object_field(jw, "type");
+ anal_dump_type_ref(&ctx, result->type);
+
+ jw_object_field(jw, "value");
+ anal_dump_value(&ctx, scope->source_node, result->type, result);
+
+ jw_end_object(jw);
+ }
+
+ if (var_stack.length != 0) {
+ jw_object_field(jw, "args");
+ jw_begin_array(jw);
- jw_object_field(jw, "fn");
- ZigFn *fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry;
- anal_dump_fn_ref(&ctx, fn);
+ while (var_stack.length != 0) {
+ ZigVar *var = var_stack.pop();
- ConstExprValue *result = entry->value;
- jw_object_field(jw, "result");
+ jw_array_elem(jw);
jw_begin_object(jw);
+
jw_object_field(jw, "type");
- anal_dump_type_ref(&ctx, result->type);
+ anal_dump_type_ref(&ctx, var->var_type);
+
jw_object_field(jw, "value");
- anal_dump_value(&ctx, scope->source_node, result->type, result);
+ anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value);
+
jw_end_object(jw);
- break;
}
- scope = scope->parent;
+ jw_end_array(jw);
}
+
jw_end_object(jw);
}
- }
- jw_end_array(jw);
- jw_object_field(jw, "fns");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) {
- ZigFn *fn = ctx.fn_list.at(i);
- jw_array_elem(jw);
- anal_dump_fn(&ctx, fn);
+ var_stack.deinit();
}
jw_end_array(jw);
@@ -1315,6 +1340,15 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
}
jw_end_array(jw);
+ jw_object_field(jw, "fns");
+ jw_begin_array(jw);
+ for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) {
+ ZigFn *fn = ctx.fn_list.at(i);
+ jw_array_elem(jw);
+ anal_dump_fn(&ctx, fn);
+ }
+ jw_end_array(jw);
+
jw_object_field(jw, "errors");
jw_begin_array(jw);
for (uint32_t i = 0; i < ctx.err_list.length; i += 1) {
tools/merge_anal_dumps.zig
@@ -2,6 +2,8 @@ const builtin = @import("builtin");
const std = @import("std");
const json = std.json;
const mem = std.mem;
+const fieldIndex = std.meta.fieldIndex;
+const TypeId = builtin.TypeId;
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator);
@@ -61,6 +63,81 @@ const Error = struct {
}
};
+const simple_types = [_][]const u8{
+ "Type",
+ "Void",
+ "Bool",
+ "NoReturn",
+ "ComptimeFloat",
+ "ComptimeInt",
+ "Undefined",
+ "Null",
+ "AnyFrame",
+ "EnumLiteral",
+};
+
+const Type = union(builtin.TypeId) {
+ Type,
+ Void,
+ Bool,
+ NoReturn,
+ ComptimeFloat,
+ ComptimeInt,
+ Undefined,
+ Null,
+ AnyFrame,
+ EnumLiteral,
+
+ Int: Int,
+ Float: usize, // bits
+
+ Vector: Array,
+ Optional: usize, // payload type index
+ Pointer: Pointer,
+ Array: Array,
+
+ Struct, // TODO
+ ErrorUnion, // TODO
+ ErrorSet, // TODO
+ Enum, // TODO
+ Union, // TODO
+ Fn, // TODO
+ BoundFn, // TODO
+ ArgTuple, // TODO
+ Opaque, // TODO
+ Frame, // TODO
+
+ const Int = struct {
+ bits: usize,
+ signed: bool,
+ };
+
+ const Pointer = struct {
+ elem: usize,
+ alignment: usize,
+ is_const: bool,
+ is_volatile: bool,
+ allow_zero: bool,
+ host_int_bytes: usize,
+ bit_offset_in_host: usize,
+ };
+
+ const Array = struct {
+ elem: usize,
+ len: usize,
+ };
+
+ fn hash(t: Type) u32 {
+ var hasher = std.hash.Wyhash.init(0);
+ std.hash.autoHash(&hasher, builtin.TypeId(t));
+ return @truncate(u32, hasher.final());
+ }
+
+ fn eql(a: Type, b: Type) bool {
+ return std.meta.eql(a, b);
+ }
+};
+
const Dump = struct {
zig_id: ?[]const u8 = null,
zig_version: ?[]const u8 = null,
@@ -79,6 +156,10 @@ const Dump = struct {
error_list: std.ArrayList(Error),
error_map: ErrorMap,
+ const TypeMap = std.HashMap(Type, usize, Type.hash, Type.eql);
+ type_list: std.ArrayList(Type),
+ type_map: TypeMap,
+
fn init(allocator: *mem.Allocator) Dump {
return Dump{
.targets = std.ArrayList([]const u8).init(allocator),
@@ -88,6 +169,8 @@ const Dump = struct {
.node_map = NodeMap.init(allocator),
.error_list = std.ArrayList(Error).init(allocator),
.error_map = ErrorMap.init(allocator),
+ .type_list = std.ArrayList(Type).init(allocator),
+ .type_map = TypeMap.init(allocator),
};
}
@@ -165,6 +248,66 @@ const Dump = struct {
}
try other_error_to_mine.putNoClobber(i, gop.kv.value);
}
+
+ // Merge types. Now it starts to get advanced.
+ // First we identify all the simple types and merge those.
+ // Example: void, type, noreturn
+ // We can also do integers and floats.
+ const other_types = root.Object.get("types").?.value.Array.toSliceConst();
+ var other_types_to_mine = std.AutoHashMap(usize, usize).init(self.a());
+ for (other_types) |other_type_json, i| {
+ const type_kind = jsonObjInt(other_type_json, "kind");
+ switch (type_kind) {
+ fieldIndex(TypeId, "Int").? => {
+ var signed: bool = undefined;
+ var bits: usize = undefined;
+ if (other_type_json.Object.get("i")) |kv| {
+ signed = true;
+ bits = @intCast(usize, kv.value.Integer);
+ } else if (other_type_json.Object.get("u")) |kv| {
+ signed = false;
+ bits = @intCast(usize, kv.value.Integer);
+ } else {
+ unreachable;
+ }
+ const other_type = Type{
+ .Int = Type.Int{
+ .bits = bits,
+ .signed = signed,
+ },
+ };
+ try self.mergeOtherType(other_type, i, &other_types_to_mine);
+ },
+ fieldIndex(TypeId, "Float").? => {
+ const other_type = Type{
+ .Float = jsonObjInt(other_type_json, "bits"),
+ };
+ try self.mergeOtherType(other_type, i, &other_types_to_mine);
+ },
+ else => {},
+ }
+
+ inline for (simple_types) |simple_type_name| {
+ if (type_kind == std.meta.fieldIndex(builtin.TypeId, simple_type_name).?) {
+ const other_type = @unionInit(Type, simple_type_name, {});
+ try self.mergeOtherType(other_type, i, &other_types_to_mine);
+ }
+ }
+ }
+ }
+
+ fn mergeOtherType(
+ self: *Dump,
+ other_type: Type,
+ other_type_index: usize,
+ other_types_to_mine: *std.AutoHashMap(usize, usize),
+ ) !void {
+ const gop = try self.type_map.getOrPut(other_type);
+ if (!gop.found_existing) {
+ gop.kv.value = self.type_list.len;
+ try self.type_list.append(other_type);
+ }
+ try other_types_to_mine.putNoClobber(other_type_index, gop.kv.value);
}
fn render(self: *Dump, stream: var) !void {
@@ -204,6 +347,36 @@ const Dump = struct {
try jw.endObject();
+ try jw.objectField("types");
+ try jw.beginArray();
+ for (self.type_list.toSliceConst()) |t| {
+ try jw.arrayElem();
+ try jw.beginObject();
+
+ try jw.objectField("kind");
+ try jw.emitNumber(@enumToInt(builtin.TypeId(t)));
+
+ switch (t) {
+ .Int => |int| {
+ if (int.signed) {
+ try jw.objectField("i");
+ } else {
+ try jw.objectField("u");
+ }
+ try jw.emitNumber(int.bits);
+ },
+ .Float => |bits| {
+ try jw.objectField("bits");
+ try jw.emitNumber(bits);
+ },
+
+ else => {},
+ }
+
+ try jw.endObject();
+ }
+ try jw.endArray();
+
try jw.objectField("errors");
try jw.beginArray();
for (self.error_list.toSliceConst()) |zig_error| {