UNPKG

syntax-cli-prog

Version:

Syntactic analysis toolkit, language agnostic parsers generator.

218 lines (167 loc) 6.04 kB
'use strict'; var _codeUnit = require('../../code-unit'); var _codeUnit2 = _interopRequireDefault(_codeUnit); var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Python tokenizer template. */ /** * The MIT License (MIT) * Copyright (c) 2015-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com> */ var PY_TOKENIZER_TEMPLATE = _fs2.default.readFileSync(__dirname + '/templates/tokenizer.template.py', 'utf-8'); /** * Standard Python's indentation. */ var STANDARD_SPACES = ' '.repeat(4); /** * The trait is used by parser generators (LL/LR) for Python. */ var PythonParserGeneratorTrait = { /** * Module include code. */ generateModuleInclude: function generateModuleInclude() { this.writeData('MODULE_INCLUDE', this._formatIndent(this._grammar.getModuleInclude(), /* no ident */'')); }, /** * Whether locations should be captured, and propagated. */ generateCaptureLocations: function generateCaptureLocations() { this.writeData('CAPTURE_LOCATIONS', this._grammar.shouldCaptureLocations() ? 'True' : 'False'); }, /** * Creates handler prologue for locations. Use default implementation * from CodeUnit, plugins may implement custom logic. */ createLocationPrologue: function createLocationPrologue(production) { if (production.isEpsilon()) { return '__loc = None;'; } return _codeUnit2.default.createLocationPrologue(production); }, /** * Since Python's lambdas are one-liners, we use normal `def` * functiona declarations, and put a reference it them in the table. */ buildSemanticAction: function buildSemanticAction(production) { var action = this.getSemanticActionCode(production); if (!action) { return null; } var args = 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', PY_TOKENIZER_TEMPLATE); }, /** * Generates rules for tokenizer. */ generateLexRules: function generateLexRules() { var _this = this; var lexRules = this._grammar.getLexGrammar().getRules().map(function (lexRule) { var action = lexRule.getRawHandler(); _this._lexHandlers.push({ args: 'self', action: action }); var flags = []; if (lexRule.isCaseInsensitive()) { flags.push('i'); } if (flags.length > 0) { flags = '(?' + flags.join('') + ')'; } else { flags = ''; } return '[\'' + flags + lexRule.getRawMatcher() + '\', ' + ('_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', '' + JSON.stringify(result)); }, /** * Python-specific lex rules handler declarations. */ generateLexHandlers: function generateLexHandlers() { var handlers = this._generateHandlers(this._lexHandlers, '_lex_rule'); this.writeData('LEX_RULE_HANDLERS', handlers.join('\n\n')); }, /** * Python-specific handler declarations. */ generateProductionHandlers: function generateProductionHandlers() { var handlers = this._generateHandlers(this._productionHandlers, '_handler'); this.writeData('PRODUCTION_HANDLERS', handlers.join('\n\n')); }, /** * Generates Python's `def` function declarations for handlers. */ _generateHandlers: function _generateHandlers(handlers, name) { var _this2 = this; return handlers.map(function (_ref, index) { var args = _ref.args, action = _ref.action; var formatted = _this2._formatIndent(action); return 'def ' + name + (index + 1) + '(' + args + '):\n' + (STANDARD_SPACES + 'global __, __loc, yytext, yyleng\n') + formatted; }); }, /** * Formats Python's indentation. */ _formatIndent: function _formatIndent(code) { var indent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : STANDARD_SPACES; var lines = code.split('\n'); var firstNonEmptyLine = void 0; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = lines[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var line = _step.value; if (line.trim() !== '') { firstNonEmptyLine = line; break; } } // First line defines indentation. } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var spaceMatch = (firstNonEmptyLine || '').match(/^\s+/); var spacesCount = spaceMatch ? spaceMatch[0].length : 0; var formatted = lines.map(function (line) { return indent + line.substring(spacesCount); }); if (formatted.length === 0) { formatted.push(STANDARD_SPACES + 'pass'); } return formatted.join('\n'); } }; module.exports = PythonParserGeneratorTrait;