UNPKG

syntax-cli-prog

Version:

Syntactic analysis toolkit, language agnostic parsers generator.

334 lines (270 loc) 7.28 kB
/** * LR parser generated by the Syntax tool. * * https://www.npmjs.com/package/syntax-cli * * npm install -g syntax-cli * * syntax-cli --help * * To regenerate run: * * syntax-cli \ * --grammar ~/path-to-grammar-file \ * --mode <parsing-mode> \ * --output ~/path-to-output-parser-file.js */ 'use strict'; /** * Matched token text. */ let yytext; /** * Length of the matched token text. */ let yyleng; /** * Storage object. */ let yy = {}; /** * Result of semantic action. */ let __; /** * Result location object. */ let __loc; function yyloc(start, end) { if (!yy.options.captureLocations) { return null; } // Epsilon doesn't produce location. if (!start || !end) { return start || end; } return { startOffset: start.startOffset, endOffset: end.endOffset, startLine: start.startLine, endLine: end.endLine, startColumn: start.startColumn, endColumn: end.endColumn, }; } const EOF = '$'; /** * List of productions (generated by Syntax tool). */ const productions = {{{PRODUCTIONS}}}; /** * Encoded tokens map. */ const tokens = {{{TOKENS}}}; /** * Parsing table (generated by Syntax tool). */ const table = {{{TABLE}}}; /** * Parsing stack. */ const stack = []; /** * Tokenizer instance. */ let tokenizer; {{{TOKENIZER}}} /** * Expose tokenizer so it can be accessed in semantic actions. */ yy.lexer = tokenizer; yy.tokenizer = tokenizer; /** * Global parsing options. Some options can be shadowed per * each `parse` call, if the optations are passed. * * Initalized to the `captureLocations` which is passed * from the generator. Other options can be added at runtime. */ yy.options = { captureLocations: {{{CAPTURE_LOCATIONS}}}, }; /** * Parsing module. */ const yyparse = { /** * Sets global parsing options. */ setOptions(options) { yy.options = options; return this; }, /** * Returns parsing options. */ getOptions() { return yy.options; }, /** * Parses a string. */ parse(string, parseOptions) { if (!tokenizer) { throw new Error(`Tokenizer instance wasn't specified.`); } tokenizer.initString(string); /** * If parse options are passed, override global parse options for * this call, and later restore global options. */ let globalOptions = yy.options; if (parseOptions) { yy.options = Object.assign({}, yy.options, parseOptions); } /** * Allow callers to do setup work based on the * parsing string, and passed options. */ yyparse.onParseBegin(string, tokenizer, yy.options); stack.length = 0; stack.push(0); let token = tokenizer.getNextToken(); let shiftedToken = null; do { if (!token) { // Restore options. yy.options = globalOptions; unexpectedEndOfInput(); } let state = stack[stack.length - 1]; let column = tokens[token.type]; if (!table[state].hasOwnProperty(column)) { yy.options = globalOptions; unexpectedToken(token); } let entry = table[state][column]; // Shift action. if (entry[0] === 's') { let loc = null; if (yy.options.captureLocations) { loc = { startOffset: token.startOffset, endOffset: token.endOffset, startLine: token.startLine, endLine: token.endLine, startColumn: token.startColumn, endColumn: token.endColumn, }; } shiftedToken = this.onShift(token); stack.push( {symbol: tokens[shiftedToken.type], semanticValue: shiftedToken.value, loc}, Number(entry.slice(1)) ); token = tokenizer.getNextToken(); } // Reduce action. else if (entry[0] === 'r') { let productionNumber = entry.slice(1); let production = productions[productionNumber]; let hasSemanticAction = typeof production[2] === 'function'; let semanticValueArgs = hasSemanticAction ? [] : null; const locationArgs = ( hasSemanticAction && yy.options.captureLocations ? [] : null ); if (production[1] !== 0) { let rhsLength = production[1]; while (rhsLength-- > 0) { stack.pop(); let stackEntry = stack.pop(); if (hasSemanticAction) { semanticValueArgs.unshift(stackEntry.semanticValue); if (locationArgs) { locationArgs.unshift(stackEntry.loc); } } } } const reduceStackEntry = {symbol: production[0]}; if (hasSemanticAction) { yytext = shiftedToken ? shiftedToken.value : null; yyleng = shiftedToken ? shiftedToken.value.length : null; const semanticActionArgs = ( locationArgs !== null ? semanticValueArgs.concat(locationArgs) : semanticValueArgs ); production[2](...semanticActionArgs); reduceStackEntry.semanticValue = __; if (locationArgs) { reduceStackEntry.loc = __loc; } } const nextState = stack[stack.length - 1]; const symbolToReduceWith = production[0]; stack.push( reduceStackEntry, table[nextState][symbolToReduceWith] ); } // Accept. else if (entry === 'acc') { stack.pop(); let parsed = stack.pop(); if (stack.length !== 1 || stack[0] !== 0 || tokenizer.hasMoreTokens()) { // Restore options. yy.options = globalOptions; unexpectedToken(token); } if (parsed.hasOwnProperty('semanticValue')) { yy.options = globalOptions; yyparse.onParseEnd(parsed.semanticValue); return parsed.semanticValue; } yyparse.onParseEnd(); // Restore options. yy.options = globalOptions; return true; } } while (tokenizer.hasMoreTokens() || stack.length > 1); }, setTokenizer(customTokenizer) { tokenizer = customTokenizer; return yyparse; }, getTokenizer() { return tokenizer; }, onParseBegin(string, tokenizer, options) {}, onParseEnd(parsed) {}, /** * Allows analyzing, and transforming shifted token. Default implementation * just passes the token through. */ onShift(token) { return token; }, }; {{{MODULE_INCLUDE}}} function unexpectedToken(token) { if (token.type === EOF) { unexpectedEndOfInput(); } tokenizer.throwUnexpectedToken( token.value, token.startLine, token.startColumn ); } function unexpectedEndOfInput() { parseError(`Unexpected end of input.`); } function parseError(message) { throw new SyntaxError(message); } module.exports = yyparse;