UNPKG

syntax-cli-prog

Version:

Syntactic analysis toolkit, language agnostic parsers generator.

190 lines (145 loc) 5.34 kB
'use strict'; var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Python tokenizer template. */ var PHP_TOKENIZER_TEMPLATE = _fs2.default.readFileSync(__dirname + '/templates/tokenizer.template.php', 'utf-8'); /** * The trait is used by parser generators (LL/LR) for PHP. */ /** * The MIT License (MIT) * Copyright (c) 2015-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com> */ var PHPParserGeneratorTrait = { /** * Generates parser class name. */ generateParserClassName: function generateParserClassName(className) { this.writeData('PARSER_CLASS_NAME', className); }, /** * Generates namespace. */ generateNamespace: function generateNamespace() { var ns = this.getOptions().namespace; var nsString = ''; if (ns && ns !== '') { nsString = 'namespace ' + ns + ';'; } this.writeData('NAMESPACE', nsString); }, /** * Generates parsing table in PHP arrays format. */ generateParseTable: function generateParseTable() { this.writeData('TABLE', this._toPHPArray(this.generateParseTableData())); }, /** * Generates tokens table in PHP arrays format. */ generateTokensTable: function generateTokensTable() { this.writeData('TOKENS', this._toPHPArray(this._tokens)); }, /** * Production handlers are implemented as private methods * on the `yyparse` class. */ buildSemanticAction: function buildSemanticAction(production) { var action = this.getSemanticActionCode(production); if (!action) { return null; } action = this._scopeVars(action) + ';'; var args = this._scopeVars(this.getSemanticActionParams(production).join(',')); // Save the action, they are injected later. this._productionHandlers.push({ args: args, action: action }); return '\'_handler' + this._productionHandlers.length + '\''; }, /** * Generates built-in tokenizer instance. */ generateBuiltInTokenizer: function generateBuiltInTokenizer() { this.writeData('TOKENIZER', PHP_TOKENIZER_TEMPLATE.replace(/<\?php/g, '')); }, /** * Generates rules for tokenizer. */ generateLexRules: function generateLexRules() { var _this = this; var lexRules = this._grammar.getLexGrammar().getRules().map(function (lexRule) { var action = _this._scopeVars(lexRule.getRawHandler()) + ';'; _this._lexHandlers.push({ args: '', action: action }); var flags = []; if (lexRule.isCaseInsensitive()) { flags.push('i'); } return '[\'/' + lexRule.getRawMatcher() + '/' + flags.join('') + '\', ' + ('\'_lex_rule' + _this._lexHandlers.length + '\']'); }); this.writeData('LEX_RULES', '[' + lexRules.join(',\n') + ']'); }, generateLexRulesByStartConditions: function generateLexRulesByStartConditions() { var lexGrammar = this._grammar.getLexGrammar(); var lexRulesByConditions = lexGrammar.getRulesByStartConditions(); var result = {}; for (var condition in lexRulesByConditions) { result[condition] = lexRulesByConditions[condition].map(function (lexRule) { return lexGrammar.getRuleIndex(lexRule); }); } this.writeData('LEX_RULES_BY_START_CONDITIONS', '' + this._toPHPArray(result)); }, /** * Replaces global vars like `yytext`, `$$`, etc. to be * referred from `yyparse`. */ _scopeVars: function _scopeVars(code) { return code.replace(/\$?yytext/g, 'yyparse::$yytext').replace(/\$?yyleng/g, 'yyparse::$yyleng').replace(/\b__\b/g, 'yyparse::$__').replace(/\b__loc\b/g, 'yyparse::$__loc').replace(/yyloc/g, 'yyparse::yyloc').replace(/\b_(\d+)/g, '$_$1'); }, /** * Converts JS object to PHP's array representation. */ _toPHPArray: function _toPHPArray(object) { if (typeof object !== 'object') { return JSON.stringify(object); } var result = []; for (var k in object) { var value = object[k]; if (Array.isArray(object)) { result.push(this._toPHPArray(value)); } else { var key = k.replace(/'/g, "\\'"); result.push("'" + key + "' => " + this._toPHPArray(value)); } } return 'array(' + result.join(', ') + ')'; }, /** * Python-specific lex rules handler declarations. */ generateLexHandlers: function generateLexHandlers() { var handlers = this._generateHandlers(this._lexHandlers, '_lex_rule', false); this.writeData('LEX_RULE_HANDLERS', handlers.join('\n\n')); }, /** * Python-specific handler declarations. */ generateProductionHandlers: function generateProductionHandlers() { var handlers = this._generateHandlers(this._productionHandlers, '_handler', true); this.writeData('PRODUCTION_HANDLERS', handlers.join('\n\n')); }, /** * Generates Python's `def` function declarations for handlers. */ _generateHandlers: function _generateHandlers(handlers, name, isStatic) { return handlers.map(function (_ref, index) { var args = _ref.args, action = _ref.action; return 'private ' + (isStatic ? 'static ' : '') + 'function ' + name + (index + 1) + ('(' + args + ') {\n' + action + '\n}'); }); } }; module.exports = PHPParserGeneratorTrait;