rojects/source/components/code-panel/BrowserLexer.ts

65 lines
2.8 KiB
TypeScript

function makeSticky( re: RegExp ): RegExp
{
if ( re.sticky ) return re;
const flags = re.flags.includes( 'y' ) ? re.flags : re.flags + 'y';
return new RegExp( re.source, flags );
}
export class BrowserMatcher
{
readonly type: string;
private _re: RegExp;
constructor( type: string, re: RegExp )
{
this.type = type;
this._re = makeSticky( re );
}
matchLength( source: string, offset: number ): number
{
this._re.lastIndex = offset;
const result = this._re.exec( source );
if ( result && result.index === offset ) return result[ 0 ].length;
return -1;
}
}
export class BrowserLexer
{
readonly modes = new Map<string, BrowserMatcher[]>();
addMatchers( ...matchers: BrowserMatcher[] ): void
{
const list = this.modes.get( 'default' ) ?? [];
list.push( ...matchers );
this.modes.set( 'default', list );
}
}
export function cLikeLexer(): BrowserLexer
{
const l = new BrowserLexer();
l.addMatchers(
new BrowserMatcher( 'SINGLE_LINE_COMMENT', /\/\/.*/ ),
new BrowserMatcher( 'MULTI_LINE_COMMENT', /\/\*[\s\S]*?\*\// ),
new BrowserMatcher( 'DOUBLE_QUOTED_STRING', /"(?:[^"\\]|\\.)*"/ ),
new BrowserMatcher( 'SINGLE_QUOTED_STRING', /'(?:[^'\\]|\\.)*'/ ),
new BrowserMatcher( 'C_INSTRUCTION', /\#.*/ ),
new BrowserMatcher( 'NUMBER', /(?=\.\d|\d)(?:\d+)?(?:\.?\d*)(?:[eE][+-]?\d+)?/ ),
new BrowserMatcher( 'NULL', /\bnull\b/ ),
new BrowserMatcher( 'BOOL', /\b(?:true|false)\b/ ),
new BrowserMatcher( 'BREAK', /\r\n|\r|\n/ ),
new BrowserMatcher( 'WHITESPACE', /\s+/ ),
new BrowserMatcher( 'LOGIC', /\b(?:if|else|switch|do|while|for|break|continue|return|case)\b/ ),
new BrowserMatcher( 'BRACKET', /[()[\]{}]/ ),
new BrowserMatcher( 'ACCESS_MODIFIER', /\b(?:public|protected|private)\b/ ),
new BrowserMatcher( 'CLASS', /\bclass\b/ ),
new BrowserMatcher( 'OPERATOR', /==|\+\+|--|[+\-*\/^|~&%<>=!.:,;]/ ),
new BrowserMatcher( 'CFUNCTION', /[a-zA-Z_]\w*(?=\s*\()/ ),
new BrowserMatcher( 'CWORD', /[a-zA-Z_]\w*/ ),
new BrowserMatcher( 'ANY_SYMBOL', /./ ),
);
return l;
}