mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 14:55:25 +00:00
parent
47dfaf3d17
commit
1014cfdf3b
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@ -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);
|
||||
|
||||
jw_object_field(jw, "fn");
|
||||
ZigFn *fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry;
|
||||
anal_dump_fn_ref(&ctx, fn);
|
||||
|
||||
ConstExprValue *result = entry->value;
|
||||
jw_object_field(jw, "result");
|
||||
jw_begin_object(jw);
|
||||
jw_object_field(jw, "type");
|
||||
anal_dump_type_ref(&ctx, result->type);
|
||||
jw_object_field(jw, "value");
|
||||
anal_dump_value(&ctx, scope->source_node, result->type, result);
|
||||
jw_end_object(jw);
|
||||
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);
|
||||
|
||||
while (var_stack.length != 0) {
|
||||
ZigVar *var = var_stack.pop();
|
||||
|
||||
jw_array_elem(jw);
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
||||
@ -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| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user