syntax-cli-prog
Version:
Syntactic analysis toolkit, language agnostic parsers generator.
190 lines (145 loc) • 5.34 kB
JavaScript
;
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;