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