|
|
|
@ -2,6 +2,41 @@ import { locate } from 'locate-character';
|
|
|
|
|
import fragment from './state/fragment.js';
|
|
|
|
|
import { whitespace } from './patterns.js';
|
|
|
|
|
import { trimStart, trimEnd } from './utils/trim.js';
|
|
|
|
|
import spaces from './utils/spaces.js';
|
|
|
|
|
|
|
|
|
|
function tabsToSpaces ( str ) {
|
|
|
|
|
return str.replace( /^\t+/, match => match.split( '\t' ).join( ' ' ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ParseError ( message, template, index ) {
|
|
|
|
|
const { line, column } = locate( template, index );
|
|
|
|
|
const lines = template.split( '\n' );
|
|
|
|
|
|
|
|
|
|
const frameStart = Math.max( 0, line - 2 );
|
|
|
|
|
const frameEnd = Math.min( line + 3, lines.length );
|
|
|
|
|
|
|
|
|
|
const digits = String( frameEnd + 1 ).length;
|
|
|
|
|
const frame = lines
|
|
|
|
|
.slice( frameStart, frameEnd )
|
|
|
|
|
.map( ( str, i ) => {
|
|
|
|
|
const isErrorLine = frameStart + i === line;
|
|
|
|
|
|
|
|
|
|
let lineNum = String( i + frameStart + 1 );
|
|
|
|
|
while ( lineNum.length < digits ) lineNum = ` ${lineNum}`;
|
|
|
|
|
|
|
|
|
|
if ( isErrorLine ) {
|
|
|
|
|
const indicator = spaces( digits + 2 + tabsToSpaces( str.slice( 0, column ) ).length ) + '^';
|
|
|
|
|
return `${lineNum}: ${tabsToSpaces( str )}\n${indicator}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `${lineNum}: ${tabsToSpaces( str )}`;
|
|
|
|
|
})
|
|
|
|
|
.join( '\n' );
|
|
|
|
|
|
|
|
|
|
this.message = `${message} (${line + 1}:${column})\n${frame}`;
|
|
|
|
|
this.loc = { line, column };
|
|
|
|
|
this.shortMessage = message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function parse ( template ) {
|
|
|
|
|
const parser = {
|
|
|
|
@ -13,9 +48,12 @@ export default function parse ( template ) {
|
|
|
|
|
return this.stack[ this.stack.length - 1 ];
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
acornError ( err ) {
|
|
|
|
|
parser.error( err.message.replace( /\(\d+:\d+\)$/, '' ), err.pos );
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
error ( message, index = this.index ) {
|
|
|
|
|
const { line, column } = locate( this.template, index );
|
|
|
|
|
throw new Error( `${message} (${line}:${column})` );
|
|
|
|
|
throw new ParseError( message, this.template, index );
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
eat ( str, required ) {
|
|
|
|
|