in packages-rc/rc-codemirror/src/addon/lint/json/util/parser.ts [125:348]
parse(input: string) {
let stack = [0];
let vStack: (string | null)[] = [null]; // semantic value stack
let lStack = []; // location stack
let yyText = '';
let yyLineNo = 0;
let yyLength = 0;
let recovering = 0;
lexer.setInput(input);
lexer.yy = this.yy;
this.yy.lexer = lexer;
if (_isUndefined(lexer.yylloc)) {
lexer.yylloc = {};
}
let yyloc = lexer.yylloc;
lStack.push(yyloc);
if (_isFunction(this.yy.parseError)) {
this.parseError = this.yy.parseError;
}
function popStack(n: number): void {
stack.length -= 2 * n;
vStack.length -= n;
lStack.length -= n;
}
function lex(): number | 'INVALID' | undefined {
let token;
token = lexer.lex() || EOF; // $end = 1
// if token isn't its numeric value, convert
if (!_isFinite(token)) {
token = PARSER_SYMBOLS[token] || token;
}
return token;
}
const yyVal: IYyVal = {};
let symbol;
let preErrorSymbol;
let state: number;
let action;
let r;
let p;
let len;
let newState;
let expected;
let errStr;
while (true) { // eslint-disable-line
// retrieve state number from top of stack
state = stack[stack.length - 1]!;
// use default actions if available
if (PARSER_DEFAULT_ACTIONS[state]) {
action = PARSER_DEFAULT_ACTIONS[state];
} else {
if (symbol === null || symbol === undefined) {
symbol = lex();
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
action = PARSER_TABLE[state]?.[symbol]; // read action for current state and first input
}
// handle parse error
if (_isUndefined(action) || !action.length || !action[0]) {
if (!recovering) {
// Report error
expected = [];
for (p in PARSER_TABLE[state]) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (PARSER_TERMINALS[p] && p > 2) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
expected.push(`'${PARSER_TERMINALS[p]}'`);
}
}
if (lexer.showPosition) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
errStr = `Parse error on line ${yyLineNo + 1}:\n${lexer.showPosition()}\nExpecting ${expected.join(', ')}, got '${PARSER_TERMINALS[symbol]}'`;
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
errStr = `Parse error on line ${yyLineNo + 1}: Unexpected ${symbol === 1 /* EOF */ ? 'end of input' : `'${PARSER_TERMINALS[symbol] || symbol}'`}`;
}
this.parseError(errStr, {
text: lexer.match,
token: PARSER_TERMINALS[symbol as number] || symbol,
line: lexer.yylineno,
loc: yyloc,
expected
});
}
// just recovered from another error
if (recovering === 3) {
if (symbol === EOF) {
throw new Error(errStr || 'Parsing halted.');
}
// discard current lookahead and grab another
yyLength = lexer.yyleng;
yyText = lexer.yytext;
yyLineNo = lexer.yylineno;
yyloc = lexer.yylloc;
symbol = lex();
}
// try to recover from error
while (true) { // eslint-disable-line no-constant-condition
// check for error recovery rule in this state
if (ERROR.toString() in PARSER_TABLE[state]!) {
break;
}
if (state === 0) {
throw new Error(errStr || 'Parsing halted.');
}
popStack(1);
state = stack[stack.length - 1]!;
}
preErrorSymbol = symbol; // save the lookahead token
symbol = ERROR; // insert generic error symbol as new lookahead
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
state = stack[stack.length - 1];
action = PARSER_TABLE[state]?.[ERROR];
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
}
// this shouldn't happen, unless resolve defaults are off
if (_isArray(action[0]) && action.length > 1) {
throw new Error(`Parse Error: multiple actions possible at state: ${state}, token: ${symbol}`);
}
switch (action[0]) {
case 1: // shift
stack.push(symbol as any);
vStack.push(lexer.yytext);
lStack.push(lexer.yylloc);
stack.push(action[1]); // push state
symbol = null;
if (!preErrorSymbol) { // normal execution/no error
yyLength = lexer.yyleng;
yyText = lexer.yytext;
yyLineNo = lexer.yylineno;
yyloc = lexer.yylloc;
if (recovering > 0) {
recovering -= 1;
}
} else { // error just occurred, resume old lookahead f/ before error
symbol = preErrorSymbol;
preErrorSymbol = null;
}
break;
case 2: // reduce
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
len = PARSER_PRODUCTIONS[action[1]][1];
// perform semantic action
yyVal.$ = vStack[vStack.length - len]; // default to $$ = $1
// default location, uses first token for firsts, last for lasts
yyVal._$ = {
firstLine: lStack[lStack.length - (len || 1)]?.firstLine,
lastLine: lStack[lStack.length - 1]?.lastLine,
firstColumn: lStack[lStack.length - (len || 1)]?.firstColumn,
lastColumn: lStack[lStack.length - 1]?.lastColumn
};
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
r = this.performAction.call(yyVal, yyText, yyLength, yyLineNo, this.yy, action[1], vStack, lStack);
if (!_isUndefined(r)) {
return r;
}
// pop off stack
if (len) {
stack = stack.slice(0, -1 * len * 2);
vStack = vStack.slice(0, -1 * len);
lStack = lStack.slice(0, -1 * len);
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
stack.push(PARSER_PRODUCTIONS[action[1]][0]); // push non-terminal (reduce)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
vStack.push(yyVal.$);
lStack.push(yyVal._$);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
newState = PARSER_TABLE[stack[stack.length - 2]][stack[stack.length - 1]];
stack.push(newState);
break;
case 3: // accept
return true;
default:
break;
}
}
}