You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

353 lines
13 KiB

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var chunker_1 = tslib_1.__importDefault(require("./chunker"));
exports.default = (function () {
var // Less input string
input;
var // current chunk
j;
var // holds state for backtracking
saveStack = [];
var // furthest index the parser has gone to
furthest;
var // if this is furthest we got to, this is the probably cause
furthestPossibleErrorMessage;
var // chunkified input
chunks;
var // current chunk
current;
var // index of current chunk, in `input`
currentPos;
var parserInput = {};
var CHARCODE_SPACE = 32;
var CHARCODE_TAB = 9;
var CHARCODE_LF = 10;
var CHARCODE_CR = 13;
var CHARCODE_PLUS = 43;
var CHARCODE_COMMA = 44;
var CHARCODE_FORWARD_SLASH = 47;
var CHARCODE_9 = 57;
function skipWhitespace(length) {
var oldi = parserInput.i;
var oldj = j;
var curr = parserInput.i - currentPos;
var endIndex = parserInput.i + current.length - curr;
var mem = (parserInput.i += length);
var inp = input;
var c;
var nextChar;
var comment;
for (; parserInput.i < endIndex; parserInput.i++) {
c = inp.charCodeAt(parserInput.i);
if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) {
nextChar = inp.charAt(parserInput.i + 1);
if (nextChar === '/') {
comment = { index: parserInput.i, isLineComment: true };
var nextNewLine = inp.indexOf('\n', parserInput.i + 2);
if (nextNewLine < 0) {
nextNewLine = endIndex;
}
parserInput.i = nextNewLine;
comment.text = inp.substr(comment.index, parserInput.i - comment.index);
parserInput.commentStore.push(comment);
continue;
}
else if (nextChar === '*') {
var nextStarSlash = inp.indexOf('*/', parserInput.i + 2);
if (nextStarSlash >= 0) {
comment = {
index: parserInput.i,
text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i),
isLineComment: false
};
parserInput.i += comment.text.length - 1;
parserInput.commentStore.push(comment);
continue;
}
}
break;
}
if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) {
break;
}
}
current = current.slice(length + parserInput.i - mem + curr);
currentPos = parserInput.i;
if (!current.length) {
if (j < chunks.length - 1) {
current = chunks[++j];
skipWhitespace(0); // skip space at the beginning of a chunk
return true; // things changed
}
parserInput.finished = true;
}
return oldi !== parserInput.i || oldj !== j;
}
parserInput.save = function () {
currentPos = parserInput.i;
saveStack.push({ current: current, i: parserInput.i, j: j });
};
parserInput.restore = function (possibleErrorMessage) {
if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) {
furthest = parserInput.i;
furthestPossibleErrorMessage = possibleErrorMessage;
}
var state = saveStack.pop();
current = state.current;
currentPos = parserInput.i = state.i;
j = state.j;
};
parserInput.forget = function () {
saveStack.pop();
};
parserInput.isWhitespace = function (offset) {
var pos = parserInput.i + (offset || 0);
var code = input.charCodeAt(pos);
return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF);
};
// Specialization of $(tok)
parserInput.$re = function (tok) {
if (parserInput.i > currentPos) {
current = current.slice(parserInput.i - currentPos);
currentPos = parserInput.i;
}
var m = tok.exec(current);
if (!m) {
return null;
}
skipWhitespace(m[0].length);
if (typeof m === 'string') {
return m;
}
return m.length === 1 ? m[0] : m;
};
parserInput.$char = function (tok) {
if (input.charAt(parserInput.i) !== tok) {
return null;
}
skipWhitespace(1);
return tok;
};
parserInput.$str = function (tok) {
var tokLength = tok.length;
// https://jsperf.com/string-startswith/21
for (var i = 0; i < tokLength; i++) {
if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
return null;
}
}
skipWhitespace(tokLength);
return tok;
};
parserInput.$quoted = function (loc) {
var pos = loc || parserInput.i;
var startChar = input.charAt(pos);
if (startChar !== '\'' && startChar !== '"') {
return;
}
var length = input.length;
var currentPosition = pos;
for (var i = 1; i + currentPosition < length; i++) {
var nextChar = input.charAt(i + currentPosition);
switch (nextChar) {
case '\\':
i++;
continue;
case '\r':
case '\n':
break;
case startChar:
var str = input.substr(currentPosition, i + 1);
if (!loc && loc !== 0) {
skipWhitespace(i + 1);
return str;
}
return [startChar, str];
default:
}
}
return null;
};
/**
* Permissive parsing. Ignores everything except matching {} [] () and quotes
* until matching token (outside of blocks)
*/
parserInput.$parseUntil = function (tok) {
var quote = '';
var returnVal = null;
var inComment = false;
var blockDepth = 0;
var blockStack = [];
var parseGroups = [];
var length = input.length;
var startPos = parserInput.i;
var lastPos = parserInput.i;
var i = parserInput.i;
var loop = true;
var testChar;
if (typeof tok === 'string') {
testChar = function (char) { return char === tok; };
}
else {
testChar = function (char) { return tok.test(char); };
}
do {
var prevChar = void 0;
var nextChar = input.charAt(i);
if (blockDepth === 0 && testChar(nextChar)) {
returnVal = input.substr(lastPos, i - lastPos);
if (returnVal) {
parseGroups.push(returnVal);
}
else {
parseGroups.push(' ');
}
returnVal = parseGroups;
skipWhitespace(i - startPos);
loop = false;
}
else {
if (inComment) {
if (nextChar === '*' &&
input.charAt(i + 1) === '/') {
i++;
blockDepth--;
inComment = false;
}
i++;
continue;
}
switch (nextChar) {
case '\\':
i++;
nextChar = input.charAt(i);
parseGroups.push(input.substr(lastPos, i - lastPos + 1));
lastPos = i + 1;
break;
case '/':
if (input.charAt(i + 1) === '*') {
i++;
inComment = true;
blockDepth++;
}
break;
case '\'':
case '"':
quote = parserInput.$quoted(i);
if (quote) {
parseGroups.push(input.substr(lastPos, i - lastPos), quote);
i += quote[1].length - 1;
lastPos = i + 1;
}
else {
skipWhitespace(i - startPos);
returnVal = nextChar;
loop = false;
}
break;
case '{':
blockStack.push('}');
blockDepth++;
break;
case '(':
blockStack.push(')');
blockDepth++;
break;
case '[':
blockStack.push(']');
blockDepth++;
break;
case '}':
case ')':
case ']':
var expected = blockStack.pop();
if (nextChar === expected) {
blockDepth--;
}
else {
// move the parser to the error and return expected
skipWhitespace(i - startPos);
returnVal = expected;
loop = false;
}
}
i++;
if (i > length) {
loop = false;
}
}
prevChar = nextChar;
} while (loop);
return returnVal ? returnVal : null;
};
parserInput.autoCommentAbsorb = true;
parserInput.commentStore = [];
parserInput.finished = false;
// Same as $(), but don't change the state of the parser,
// just return the match.
parserInput.peek = function (tok) {
if (typeof tok === 'string') {
// https://jsperf.com/string-startswith/21
for (var i = 0; i < tok.length; i++) {
if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
return false;
}
}
return true;
}
else {
return tok.test(current);
}
};
// Specialization of peek()
// TODO remove or change some currentChar calls to peekChar
parserInput.peekChar = function (tok) { return input.charAt(parserInput.i) === tok; };
parserInput.currentChar = function () { return input.charAt(parserInput.i); };
parserInput.prevChar = function () { return input.charAt(parserInput.i - 1); };
parserInput.getInput = function () { return input; };
parserInput.peekNotNumeric = function () {
var c = input.charCodeAt(parserInput.i);
// Is the first char of the dimension 0-9, '.', '+' or '-'
return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
};
parserInput.start = function (str, chunkInput, failFunction) {
input = str;
parserInput.i = j = currentPos = furthest = 0;
// chunking apparently makes things quicker (but my tests indicate
// it might actually make things slower in node at least)
// and it is a non-perfect parse - it can't recognise
// unquoted urls, meaning it can't distinguish comments
// meaning comments with quotes or {}() in them get 'counted'
// and then lead to parse errors.
// In addition if the chunking chunks in the wrong place we might
// not be able to parse a parser statement in one go
// this is officially deprecated but can be switched on via an option
// in the case it causes too much performance issues.
if (chunkInput) {
chunks = chunker_1.default(str, failFunction);
}
else {
chunks = [str];
}
current = chunks[0];
skipWhitespace(0);
};
parserInput.end = function () {
var message;
var isFinished = parserInput.i >= input.length;
if (parserInput.i < furthest) {
message = furthestPossibleErrorMessage;
parserInput.i = furthest;
}
return {
isFinished: isFinished,
furthest: parserInput.i,
furthestPossibleErrorMessage: message,
furthestReachedEnd: parserInput.i >= input.length - 1,
furthestChar: input[parserInput.i]
};
};
return parserInput;
});
//# sourceMappingURL=parser-input.js.map