All files / src/compiler/utils compile_diagnostic.js

91.91% Statements 91/99
100% Branches 13/13
100% Functions 6/6
91.83% Lines 90/98

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 992x 2x 2x 2x 2x 2x 2x 2x 8633x 8633x 8633x 2x 2x 2x 2x 2x 2x 1583x 1583x 1583x 1583x 1583x 1583x 1583x 1583x 7050x 7050x 7050x 1583x 1583x 1583x 1583x 5467x 1583x 1583x 1583x 2x 2x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1588x 1583x 1583x 1583x 1583x 1583x 1583x 1588x 1588x 1588x 1x 1x 1x             1x 1x     1x 1x 1x 1588x 1588x 803x 803x 803x 803x 803x 803x 803x 803x 803x 803x 1588x  
/** @import { Location } from 'locate-character' */
import * as state from '../state.js';
 
const regex_tabs = /^\t+/;
 
/**
 * @param {string} str
 */
function tabs_to_spaces(str) {
	return str.replace(regex_tabs, (match) => match.split('\t').join('  '));
}
 
/**
 * @param {string} source
 * @param {number} line
 * @param {number} column
 */
function get_code_frame(source, line, column) {
	const lines = source.split('\n');
	const frame_start = Math.max(0, line - 2);
	const frame_end = Math.min(line + 3, lines.length);
	const digits = String(frame_end + 1).length;
	return lines
		.slice(frame_start, frame_end)
		.map((str, i) => {
			const is_error_line = frame_start + i === line;
			const line_num = String(i + frame_start + 1).padStart(digits, ' ');
			if (is_error_line) {
				const indicator =
					' '.repeat(digits + 2 + tabs_to_spaces(str.slice(0, column)).length) + '^';
				return `${line_num}: ${tabs_to_spaces(str)}\n${indicator}`;
			}
			return `${line_num}: ${tabs_to_spaces(str)}`;
		})
		.join('\n');
}
 
export class CompileDiagnostic extends Error {
	name = 'CompileDiagnostic';
	filename = state.filename;
	/** @type {[number, number] | undefined} */
	position = undefined;
	/** @type {Location | undefined} */
	start = undefined;
	/** @type {Location | undefined} */
	end = undefined;
	/** @type {string | undefined} */
	frame = undefined;
 
	/**
	 * @param {string} code
	 * @param {string} message
	 * @param {[number, number] | undefined} position
	 */
	constructor(code, message, position) {
		super(message);
		this.code = code;
		this.position = position;
 
		if (position) {
			this.start = state.locator(position[0]);
			this.end = state.locator(position[1]);
			if (this.start && this.end) {
				this.frame = get_code_frame(state.source, this.start.line - 1, this.end.column);
			}
		}
	}
 
	toString() {
		let out = `${this.code}: ${this.message}`;
 
		if (this.filename) {
			out += `\n${this.filename}`;

			if (this.start) {
				out += `:${this.start.line}:${this.start.column}`;
			}
		}
 
		if (this.frame) {
			out += `\n${this.frame}`;
		}
 
		return out;
	}
 
	toJSON() {
		return {
			code: this.code,
			message: this.message,
			filename: this.filename,
			start: this.start,
			end: this.end,
			position: this.position,
			frame: this.frame
		};
	}
}