import chalk , { ChalkFunction } from 'chalk' ; import { ANTLRErrorListener } from 'antlr4ts' ; import { RecognitionException } from 'antlr4ts/RecognitionException' ; interface CodeInterval { a : number ; b : number ; line : number ; col : number ; } export enum ParseWarningType { ParamNeverUsed } enum ParseErrorType { ParseError } export enum ParseEventType { Info , Warning , Error } export type ParseEvent = { type : ParseEventType . Warning ; message : { text : string ; type : ParseWarningType ; } ; location ? : CodeInterval ; } | { type : ParseEventType . Error ; critical : true ; message : { text : string ; type : ParseErrorType ; } ; location ? : CodeInterval ; } ; function styleIntervals ( str , intervals ) { if ( intervals . length === 0 ) { return str ; } intervals . sort ( ( x , y ) => x . a - y . a ) ; let offset = 0 ; let colored = '' ; for ( const interval of intervals ) { const a = str . slice ( 0 , interval . a + offset ) ; const b = str . slice ( interval . a + offset , interval . b + offset + 1 ) ; const c = str . slice ( interval . b + offset + 1 , str . length ) ; colored = a + interval . style ( b ) + c ; offset += colored . length - str . length ; str = colored ; } return colored ; } export function prettyPrintEvents ( text , parseEvents ) { let msg = chalk . underline . magenta ( 'Parsed file:\n' ) ; const errors = parseEvents . filter ( ( e ) => e . type === ParseEventType . Error ) ; const warnings = parseEvents . filter ( ( e ) => e . type === ParseEventType . Warning ) ; const lineStyle = { } as any ; const locsToColor = parseEvents . filter ( ( w ) => w . location ) . map ( ( w ) => { const style = w . type === ParseEventType . Error ? chalk . underline . red : chalk . underline . yellow ; if ( w . location ?. line ) { lineStyle [ w . location . line ] = style ; } return { ... w . location , style , } ; } ) ; const styledText = styleIntervals ( text , locsToColor as any ) ; let i = 1 ; const numberedText = styledText . replace ( /^/gm , ( ) => { const prefix = lineStyle [ i ] ? lineStyle [ i ] ( '>' ) : '|' ; return `${ i ++ } ${ prefix } ` ; } ) ; msg += numberedText ; if ( errors . length > 0 ) { msg += chalk . underline . red ( '\nErrors:\n' ) ; msg += errors . map ( ( w ) => `- (${ w . location ?. line }:${ w . location ?. col }) ${ w . message . text }` ) . join ( '\n' ) ; } if ( warnings . length > 0 ) { msg += chalk . underline . yellow ( '\nWarnings:\n' ) ; msg += warnings . map ( ( w ) => `- (${ w . location ?. line }:${ w . location ?. col }) ${ w . message . text }` ) . join ( '\n' ) ; } console . log ( msg ) ; } export class Logger implements ANTLRErrorListener < any > { public parseEvents : ParseEvent [ ] = [ ] ; logEvent ( event ) { this . parseEvents . push ( event ) ; } syntaxError ( _recognizer , symbol , line , col , msg , _e ) { this . logEvent ( { type : ParseEventType . Error , critical : true , message : { type : ParseErrorType . ParseError , text : `Parse error: ${ msg }` , } , location : { a : symbol ?. startIndex , b : symbol ?. stopIndex , line , col , } , } ) ; } }