mirror of
https://github.com/ziglang/zig.git
synced 2026-10-14 10:27:43 -04:00
fuzzer web UI: annotated PCs in source view
This commit is contained in:
1 parent
ef4c2193fc
commit
3d48602c99
4 files changed
+108
-5
No files matched your search
@@ -16,6 +16,16 @@ pub const RenderSourceOptions = struct {
|
|||||||
skip_comments: bool = false,
|
skip_comments: bool = false,
|
||||||
collapse_whitespace: bool = false,
|
collapse_whitespace: bool = false,
|
||||||
fn_link: Decl.Index = .none,
|
fn_link: Decl.Index = .none,
|
||||||
|
/// Assumed to be sorted ascending.
|
||||||
|
source_location_annotations: []const Annotation = &.{},
|
||||||
|
/// Concatenated with dom_id.
|
||||||
|
annotation_prefix: []const u8 = "l",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Annotation = struct {
|
||||||
|
file_byte_offset: u32,
|
||||||
|
/// Concatenated with annotation_prefix.
|
||||||
|
dom_id: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn fileSourceHtml(
|
pub fn fileSourceHtml(
|
||||||
@@ -51,6 +61,8 @@ pub fn fileSourceHtml(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var next_annotate_index: usize = 0;
|
||||||
|
|
||||||
for (
|
for (
|
||||||
token_tags[start_token..end_token],
|
token_tags[start_token..end_token],
|
||||||
token_starts[start_token..end_token],
|
token_starts[start_token..end_token],
|
||||||
@@ -74,6 +86,18 @@ pub fn fileSourceHtml(
|
|||||||
if (tag == .eof) break;
|
if (tag == .eof) break;
|
||||||
const slice = ast.tokenSlice(token_index);
|
const slice = ast.tokenSlice(token_index);
|
||||||
cursor = start + slice.len;
|
cursor = start + slice.len;
|
||||||
|
|
||||||
|
// Insert annotations.
|
||||||
|
while (true) {
|
||||||
|
if (next_annotate_index >= options.source_location_annotations.len) break;
|
||||||
|
const next_annotation = options.source_location_annotations[next_annotate_index];
|
||||||
|
if (cursor < next_annotation.file_byte_offset) break;
|
||||||
|
try out.writer(gpa).print("<span id=\"{s}{d}\"></span>", .{
|
||||||
|
options.annotation_prefix, next_annotation.dom_id,
|
||||||
|
});
|
||||||
|
next_annotate_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
.eof => unreachable,
|
.eof => unreachable,
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,14 @@
|
|||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l {
|
||||||
|
display: inline-block;
|
||||||
|
background: white;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.tok-kw {
|
.tok-kw {
|
||||||
color: #333;
|
color: #333;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
+16
-4
@@ -33,7 +33,7 @@
|
|||||||
throw new Error("panic: " + msg);
|
throw new Error("panic: " + msg);
|
||||||
},
|
},
|
||||||
emitSourceIndexChange: onSourceIndexChange,
|
emitSourceIndexChange: onSourceIndexChange,
|
||||||
emitCoverageUpdate: renderStats,
|
emitCoverageUpdate: onCoverageUpdate,
|
||||||
emitEntryPointsUpdate: renderStats,
|
emitEntryPointsUpdate: renderStats,
|
||||||
},
|
},
|
||||||
}).then(function(obj) {
|
}).then(function(obj) {
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onWebSocketOpen() {
|
function onWebSocketOpen() {
|
||||||
console.log("web socket opened");
|
//console.log("web socket opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWebSocketMessage(ev) {
|
function onWebSocketMessage(ev) {
|
||||||
@@ -141,6 +141,11 @@
|
|||||||
if (curNavLocation != null) renderSource(curNavLocation);
|
if (curNavLocation != null) renderSource(curNavLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCoverageUpdate() {
|
||||||
|
renderStats();
|
||||||
|
renderCoverage();
|
||||||
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
domStatus.classList.add("hidden");
|
domStatus.classList.add("hidden");
|
||||||
}
|
}
|
||||||
@@ -166,6 +171,15 @@
|
|||||||
domSectStats.classList.remove("hidden");
|
domSectStats.classList.remove("hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderCoverage() {
|
||||||
|
for (let i = 0; i < domSourceText.children.length; i += 1) {
|
||||||
|
const childDom = domSourceText.children[i];
|
||||||
|
if (childDom.id != null && childDom.id[0] == "l") {
|
||||||
|
childDom.classList.add("l");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function resizeDomList(listDom, desiredLen, templateHtml) {
|
function resizeDomList(listDom, desiredLen, templateHtml) {
|
||||||
for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
|
for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
|
||||||
listDom.insertAdjacentHTML('beforeend', templateHtml);
|
listDom.insertAdjacentHTML('beforeend', templateHtml);
|
||||||
@@ -190,13 +204,11 @@
|
|||||||
domSectSource.classList.remove("hidden");
|
domSectSource.classList.remove("hidden");
|
||||||
|
|
||||||
const slDom = document.getElementById("l" + sourceLocationIndex);
|
const slDom = document.getElementById("l" + sourceLocationIndex);
|
||||||
if (slDom != null) {
|
|
||||||
slDom.scrollIntoView({
|
slDom.scrollIntoView({
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
block: "center",
|
block: "center",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function decodeString(ptr, len) {
|
function decodeString(ptr, len) {
|
||||||
if (len === 0) return "";
|
if (len === 0) return "";
|
||||||
|
|||||||
@@ -280,12 +280,71 @@ const SourceLocationIndex = enum(u32) {
|
|||||||
) error{ OutOfMemory, SourceUnavailable }!void {
|
) error{ OutOfMemory, SourceUnavailable }!void {
|
||||||
const walk_file_index = sli.toWalkFile() orelse return error.SourceUnavailable;
|
const walk_file_index = sli.toWalkFile() orelse return error.SourceUnavailable;
|
||||||
const root_node = walk_file_index.findRootDecl().get().ast_node;
|
const root_node = walk_file_index.findRootDecl().get().ast_node;
|
||||||
html_render.fileSourceHtml(walk_file_index, out, root_node, .{}) catch |err| {
|
var annotations: std.ArrayListUnmanaged(html_render.Annotation) = .{};
|
||||||
|
defer annotations.deinit(gpa);
|
||||||
|
try computeSourceAnnotations(sli.ptr().file, walk_file_index, &annotations, coverage_source_locations.items);
|
||||||
|
html_render.fileSourceHtml(walk_file_index, out, root_node, .{
|
||||||
|
.source_location_annotations = annotations.items,
|
||||||
|
}) catch |err| {
|
||||||
fatal("unable to render source: {s}", .{@errorName(err)});
|
fatal("unable to render source: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn computeSourceAnnotations(
|
||||||
|
cov_file_index: Coverage.File.Index,
|
||||||
|
walk_file_index: Walk.File.Index,
|
||||||
|
annotations: *std.ArrayListUnmanaged(html_render.Annotation),
|
||||||
|
source_locations: []const Coverage.SourceLocation,
|
||||||
|
) !void {
|
||||||
|
// Collect all the source locations from only this file into this array
|
||||||
|
// first, then sort by line, col, so that we can collect annotations with
|
||||||
|
// O(N) time complexity.
|
||||||
|
var locs: std.ArrayListUnmanaged(SourceLocationIndex) = .{};
|
||||||
|
defer locs.deinit(gpa);
|
||||||
|
|
||||||
|
for (source_locations, 0..) |sl, sli_usize| {
|
||||||
|
if (sl.file != cov_file_index) continue;
|
||||||
|
const sli: SourceLocationIndex = @enumFromInt(sli_usize);
|
||||||
|
try locs.append(gpa, sli);
|
||||||
|
}
|
||||||
|
|
||||||
|
std.mem.sortUnstable(SourceLocationIndex, locs.items, {}, struct {
|
||||||
|
pub fn lessThan(context: void, lhs: SourceLocationIndex, rhs: SourceLocationIndex) bool {
|
||||||
|
_ = context;
|
||||||
|
const lhs_ptr = lhs.ptr();
|
||||||
|
const rhs_ptr = rhs.ptr();
|
||||||
|
if (lhs_ptr.line < rhs_ptr.line) return true;
|
||||||
|
if (lhs_ptr.line > rhs_ptr.line) return false;
|
||||||
|
return lhs_ptr.column < rhs_ptr.column;
|
||||||
|
}
|
||||||
|
}.lessThan);
|
||||||
|
|
||||||
|
const source = walk_file_index.get_ast().source;
|
||||||
|
var line: usize = 1;
|
||||||
|
var column: usize = 1;
|
||||||
|
var next_loc_index: usize = 0;
|
||||||
|
for (source, 0..) |byte, offset| {
|
||||||
|
if (byte == '\n') {
|
||||||
|
line += 1;
|
||||||
|
column = 1;
|
||||||
|
} else {
|
||||||
|
column += 1;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
if (next_loc_index >= locs.items.len) return;
|
||||||
|
const next_sli = locs.items[next_loc_index];
|
||||||
|
const next_sl = next_sli.ptr();
|
||||||
|
if (next_sl.line > line or (next_sl.line == line and next_sl.column > column)) break;
|
||||||
|
try annotations.append(gpa, .{
|
||||||
|
.file_byte_offset = offset,
|
||||||
|
.dom_id = @intFromEnum(next_sli),
|
||||||
|
});
|
||||||
|
next_loc_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var coverage = Coverage.init;
|
var coverage = Coverage.init;
|
||||||
/// Index of type `SourceLocationIndex`.
|
/// Index of type `SourceLocationIndex`.
|
||||||
var coverage_source_locations: std.ArrayListUnmanaged(Coverage.SourceLocation) = .{};
|
var coverage_source_locations: std.ArrayListUnmanaged(Coverage.SourceLocation) = .{};
|
||||||
|
|||||||
Reference in new issue
Block a user