import * as common from './common.js';
function padNumbersToEqualLength(arr) { let maxLen = 0; const strings = arr.map(n => { const str = n.toString(); maxLen = Math.max(maxLen, str.length); return str; }); return strings.map(s => common.padLeft(s, maxLen));}
function strcpy(dest, src, offset) { const origDestLen = dest.length; const start = dest.slice(0, offset); const end = dest.slice(offset + src.length); return (start + src + end).substr(0, origDestLen);}
function lineAndColumnToMessage(...ranges) { const lineAndCol = this; const {offset} = lineAndCol; const {repeatStr} = common;
const sb = new common.StringBuffer(); sb.append('Line ' + lineAndCol.lineNum + ', col ' + lineAndCol.colNum + ':\n');
const lineNumbers = padNumbersToEqualLength([ lineAndCol.prevLine == null ? 0 : lineAndCol.lineNum - 1, lineAndCol.lineNum, lineAndCol.nextLine == null ? 0 : lineAndCol.lineNum + 1, ]);
const appendLine = (num, content, prefix) => { sb.append(prefix + lineNumbers[num] + ' | ' + content + '\n'); };
if (lineAndCol.prevLine != null) { appendLine(0, lineAndCol.prevLine, ' '); } appendLine(1, lineAndCol.line, '> ');
const lineLen = lineAndCol.line.length; let indicationLine = repeatStr(' ', lineLen + 1); for (let i = 0; i < ranges.length; ++i) { let startIdx = ranges[i][0]; let endIdx = ranges[i][1]; common.assert(startIdx >= 0 && startIdx <= endIdx, 'range start must be >= 0 and <= end');
const lineStartOffset = offset - lineAndCol.colNum + 1; startIdx = Math.max(0, startIdx - lineStartOffset); endIdx = Math.min(endIdx - lineStartOffset, lineLen);
indicationLine = strcpy(indicationLine, repeatStr('~', endIdx - startIdx), startIdx); } const gutterWidth = 2 + lineNumbers[1].length + 3; sb.append(repeatStr(' ', gutterWidth)); indicationLine = strcpy(indicationLine, '^', lineAndCol.colNum - 1); sb.append(indicationLine.replace(/ +$/, '') + '\n');
if (lineAndCol.nextLine != null) { appendLine(2, lineAndCol.nextLine, ' '); } return sb.contents();}
let builtInRulesCallbacks = [];
export function awaitBuiltInRules(cb) { builtInRulesCallbacks.push(cb);}
export function announceBuiltInRules(grammar) { builtInRulesCallbacks.forEach(cb => { cb(grammar); }); builtInRulesCallbacks = null;}
export function getLineAndColumn(str, offset) { let lineNum = 1; let colNum = 1;
let currOffset = 0; let lineStartOffset = 0;
let nextLine = null; let prevLine = null; let prevLineStartOffset = -1;
while (currOffset < offset) { const c = str.charAt(currOffset++); if (c === '\n') { lineNum++; colNum = 1; prevLineStartOffset = lineStartOffset; lineStartOffset = currOffset; } else if (c !== '\r') { colNum++; } }
let lineEndOffset = str.indexOf('\n', lineStartOffset); if (lineEndOffset === -1) { lineEndOffset = str.length; } else { const nextLineEndOffset = str.indexOf('\n', lineEndOffset + 1); nextLine = nextLineEndOffset === -1 ? str.slice(lineEndOffset) : str.slice(lineEndOffset, nextLineEndOffset); nextLine = nextLine.replace(/^\r?\n/, '').replace(/\r$/, ''); }
if (prevLineStartOffset >= 0) { prevLine = str.slice(prevLineStartOffset, lineStartOffset).replace(/\r?\n$/, ''); }
const line = str.slice(lineStartOffset, lineEndOffset).replace(/\r$/, '');
return { offset, lineNum, colNum, line, prevLine, nextLine, toString: lineAndColumnToMessage, };}
export function getLineAndColumnMessage(str, offset, ...ranges) { return getLineAndColumn(str, offset).toString(...ranges);}
export const uniqueId = (() => { let idCounter = 0; return prefix => '' + prefix + idCounter++;})();