'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseOffsets = exports.parseFunctionRanges = exports.emitForestLines = exports.emitForest = void 0;
const compare_1 = require("./compare");
function emitForest(trees) {
return emitForestLines(trees).join("\n");
}
exports.emitForest = emitForest;
function emitForestLines(trees) {
const colMap = getColMap(trees);
const header = emitOffsets(colMap);
return [header, ...trees.map(tree => emitTree(tree, colMap).join("\n"))];
}
exports.emitForestLines = emitForestLines;
function getColMap(trees) {
const eventSet = new Set();
for (const tree of trees) {
const stack = [tree];
while (stack.length > 0) {
const cur = stack.pop();
eventSet.add(cur.start);
eventSet.add(cur.end);
for (const child of cur.children) {
stack.push(child);
}
}
}
const events = [...eventSet];
events.sort((a, b) => a - b);
let maxDigits = 1;
for (const event of events) {
maxDigits = Math.max(maxDigits, event.toString(10).length);
}
const colWidth = maxDigits + 3;
const colMap = new Map();
for (const [i, event] of events.entries()) {
colMap.set(event, i * colWidth);
}
return colMap;
}
function emitTree(tree, colMap) {
const layers = [];
let nextLayer = [tree];
while (nextLayer.length > 0) {
const layer = nextLayer;
layers.push(layer);
nextLayer = [];
for (const node of layer) {
for (const child of node.children) {
nextLayer.push(child);
}
}
}
return layers.map(layer => emitTreeLayer(layer, colMap));
}
function parseFunctionRanges(text, offsetMap) {
const result = [];
for (const line of text.split("\n")) {
for (const range of parseTreeLayer(line, offsetMap)) {
result.push(range);
}
}
result.sort(compare_1.compareRangeCovs);
return result;
}
exports.parseFunctionRanges = parseFunctionRanges;
/**
*
* @param layer Sorted list of disjoint trees.
* @param colMap
*/
function emitTreeLayer(layer, colMap) {
const line = [];
let curIdx = 0;
for (const { start, end, count } of layer) {
const startIdx = colMap.get(start);
const endIdx = colMap.get(end);
if (startIdx > curIdx) {
line.push(" ".repeat(startIdx - curIdx));
}
line.push(emitRange(count, endIdx - startIdx));
curIdx = endIdx;
}
return line.join("");
}
function parseTreeLayer(text, offsetMap) {
const result = [];
const regex = /\[(\d+)-*\)/gs;
while (true) {
const match = regex.exec(text);
if (match === null) {
break;
}
const startIdx = match.index;
const endIdx = startIdx + match[0].length;
const count = parseInt(match[1], 10);
const startOffset = offsetMap.get(startIdx);
const endOffset = offsetMap.get(endIdx);
if (startOffset === undefined || endOffset === undefined) {
throw new Error(`Invalid offsets for: ${JSON.stringify(text)}`);
}
result.push({ startOffset, endOffset, count });
}
return result;
}
function emitRange(count, len) {
const rangeStart = `[${count.toString(10)}`;
const rangeEnd = ")";
const hyphensLen = len - (rangeStart.length + rangeEnd.length);
const hyphens = "-".repeat(Math.max(0, hyphensLen));
return `${rangeStart}${hyphens}${rangeEnd}`;
}
function emitOffsets(colMap) {
let line = "";
for (const [event, col] of colMap) {
if (line.length < col) {
line += " ".repeat(col - line.length);
}
line += event.toString(10);
}
return line;
}
function parseOffsets(text) {
const result = new Map();
const regex = /\d+/gs;
while (true) {
const match = regex.exec(text);
if (match === null) {
break;
}
result.set(match.index, parseInt(match[0], 10));
}
return result;
}
exports.parseOffsets = parseOffsets;
|