@erml/parser
Version:
Parser implementation of ERML
98 lines (97 loc) • 4.98 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.testables = exports.walkPipeline = exports.processBody = exports.processIdentifier = exports.processStringLiteral = exports.processNumber = exports.assertToken = void 0;
var identifiers_1 = require("./identifiers");
var lexer_1 = require("../lexer");
var _1 = require(".");
function assertToken(token, expectedValues, callback) {
var matchedIndex = expectedValues.indexOf(token.value);
if (matchedIndex < 0) {
throw new SyntaxError("Expected to find " + expectedValues
.map(function (value) { return "'" + value + "'"; })
.join(", ") + " at position " + token.position + ", line " + token.line + ". Instead found '" + token.value + "'");
}
if (callback) {
callback(matchedIndex);
}
}
exports.assertToken = assertToken;
function processNumber(token, range, callback) {
var numberValue = Number(token.value);
if (isNaN(numberValue)) {
throw new TypeError("'" + token.value + "' at position " + token.position + ", line " + token.line + " is not a valid number");
}
else if (numberValue < range[0] || numberValue > range[1]) {
throw new RangeError("'" + token.value + "' at position " + token.position + ", line " + token.line + " doesn't fall in the range of [" + range[0] + ", " + range[1] + "]");
}
callback(numberValue);
}
exports.processNumber = processNumber;
function processStringLiteral(token, callback) {
var match = lexer_1.stringLiteralRegexp.exec(token.value);
if (match === null) {
throw new TypeError("'" + token.value + "' at position " + token.position + ", line " + token.line + " is not a valid string");
}
var stringValue = match[1].replace(/\\\\|\\/g, function (match) {
return match === "\\\\" ? "\\" : "";
});
callback(stringValue);
}
exports.processStringLiteral = processStringLiteral;
function processIdentifier(token, isReference, callback) {
if ((0, identifiers_1.isValidIdentifier)(token.value) === false) {
throw new SyntaxError("'" + token.value + "' at position " + token.position + ", line " + token.line + " is not a valid identifier");
}
else if (isReference && (0, identifiers_1.isValidReference)(token.value) === false) {
throw new ReferenceError("'" + token.value + "' at position " + token.position + ", line " + token.line + " is not defined before");
}
else if (isReference === false && (0, identifiers_1.isDuplicateIdentifier)(token.value)) {
throw new SyntaxError("'" + token.value + "' at position " + token.position + ", line " + token.line + " is already defined");
}
callback();
}
exports.processIdentifier = processIdentifier;
function processBody(tokens, tokenIndex, callback) {
assertToken(tokens[tokenIndex], [_1.Delimiters.OPENING_BRACE]);
var closingBracePosition = bracesMatchAt(tokens, tokenIndex);
if (closingBracePosition === null) {
throw new SyntaxError("Grouping symbols (\"" + _1.Delimiters.OPENING_BRACE + "\" and \"" + _1.Delimiters.CLOSING_BRACE + "\") don't match after \"" + _1.Delimiters.OPENING_BRACE + "\" at position " + tokens[tokenIndex].position + ", line " + tokens[tokenIndex].line);
}
var bodyStart = tokenIndex + 1;
var bodyEnd = closingBracePosition - 1;
if (bodyStart > bodyEnd) {
throw new SyntaxError("Body can't be empty at position " + tokens[tokenIndex].position + ", line " + tokens[tokenIndex].line);
}
callback(bodyStart, bodyEnd);
return closingBracePosition;
}
exports.processBody = processBody;
function walkPipeline(parsingPipeline, tokens, currentTokenIndex) {
for (var _i = 0, parsingPipeline_1 = parsingPipeline; _i < parsingPipeline_1.length; _i++) {
var process_1 = parsingPipeline_1[_i];
if (tokens[currentTokenIndex] === undefined) {
var previousToken = tokens[currentTokenIndex - 1];
throw new SyntaxError("Didn't expect to reach the end after token '" + previousToken.value + "' at position " + previousToken.position + ", line " + previousToken.line);
}
var bodyEnd = process_1(tokens[currentTokenIndex], currentTokenIndex);
currentTokenIndex = (bodyEnd ? bodyEnd : currentTokenIndex) + 1;
}
return currentTokenIndex;
}
exports.walkPipeline = walkPipeline;
function bracesMatchAt(tokens, currentPosition) {
var scales = 0;
do {
scales +=
tokens[currentPosition].value === _1.Delimiters.OPENING_BRACE
? 1
: tokens[currentPosition].value === _1.Delimiters.CLOSING_BRACE
? -1
: 0;
if (scales === 0) {
return currentPosition;
}
} while (++currentPosition < tokens.length);
return null;
}
exports.testables = { bracesMatchAt: bracesMatchAt };
;