192 lines
10 KiB
JavaScript
192 lines
10 KiB
JavaScript
|
|
import { getPreparedOptions } from './getPreparedOptions.js';
|
||
|
|
/**
|
||
|
|
* Creates parse function by comments and statements.
|
||
|
|
*/
|
||
|
|
export const createParseFunction = (options) => {
|
||
|
|
var { commentsKeys, nextStatementRegExp, onError: onGlobalError, preparedComments, preparedStatements, statementsKeys, } = getPreparedOptions(options);
|
||
|
|
const parse = (context, source) => {
|
||
|
|
var _a, _b, _c, _d, _e, _f;
|
||
|
|
var index = 0;
|
||
|
|
var parsedComments;
|
||
|
|
var previousIndex;
|
||
|
|
findNextStatement: while (index < source.length) {
|
||
|
|
if (index === previousIndex) {
|
||
|
|
index += 1;
|
||
|
|
continue findNextStatement;
|
||
|
|
}
|
||
|
|
previousIndex = index;
|
||
|
|
nextStatementRegExp.lastIndex = index;
|
||
|
|
const nextStatementMatch = nextStatementRegExp.exec(source);
|
||
|
|
if (nextStatementMatch === null) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (const key of statementsKeys) {
|
||
|
|
const token = (_a = nextStatementMatch.groups) === null || _a === void 0 ? void 0 : _a[key];
|
||
|
|
if (token === undefined) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const parsedTokens = [];
|
||
|
|
const { onError, onParse, tokens } = preparedStatements[key];
|
||
|
|
index = nextStatementRegExp.lastIndex;
|
||
|
|
let lastParsedToken = {
|
||
|
|
start: nextStatementMatch.index,
|
||
|
|
end: index,
|
||
|
|
match: nextStatementMatch,
|
||
|
|
token,
|
||
|
|
};
|
||
|
|
parsedTokens.push(lastParsedToken);
|
||
|
|
for (const { nextTokenRegExp, nextTokenKey } of tokens) {
|
||
|
|
let previousTokensIndex;
|
||
|
|
let tokensIndex = index;
|
||
|
|
findNextToken: while (tokensIndex < source.length) {
|
||
|
|
if (tokensIndex === previousTokensIndex) {
|
||
|
|
tokensIndex += 1;
|
||
|
|
continue findNextToken;
|
||
|
|
}
|
||
|
|
previousTokensIndex = tokensIndex;
|
||
|
|
nextTokenRegExp.lastIndex = tokensIndex;
|
||
|
|
const nextTokenMatch = nextTokenRegExp.exec(source);
|
||
|
|
if (nextTokenMatch === null) {
|
||
|
|
if (parsedComments === undefined) {
|
||
|
|
parsedComments = {};
|
||
|
|
for (const commentPair of lastParsedToken.comments || emptyComments) {
|
||
|
|
parsedComments[commentPair[0].start] = commentPair;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
delete lastParsedToken.comments;
|
||
|
|
const maybeIndex = onError === null || onError === void 0 ? void 0 : onError(context, source, ...parsedTokens);
|
||
|
|
if (maybeIndex !== undefined) {
|
||
|
|
index = maybeIndex;
|
||
|
|
}
|
||
|
|
continue findNextStatement;
|
||
|
|
}
|
||
|
|
const nextToken = (_b = nextTokenMatch.groups) === null || _b === void 0 ? void 0 : _b[nextTokenKey];
|
||
|
|
if (nextToken !== undefined) {
|
||
|
|
index = nextTokenRegExp.lastIndex;
|
||
|
|
lastParsedToken = {
|
||
|
|
start: nextTokenMatch.index,
|
||
|
|
end: index,
|
||
|
|
match: nextTokenMatch,
|
||
|
|
token: nextToken,
|
||
|
|
};
|
||
|
|
parsedTokens.push(lastParsedToken);
|
||
|
|
break findNextToken;
|
||
|
|
}
|
||
|
|
for (const commentKey of commentsKeys) {
|
||
|
|
const commentToken = (_c = nextTokenMatch.groups) === null || _c === void 0 ? void 0 : _c[commentKey];
|
||
|
|
if (commentToken === undefined) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (parsedComments !== undefined) {
|
||
|
|
const commentPair = parsedComments[nextTokenMatch.index];
|
||
|
|
if (commentPair === undefined) {
|
||
|
|
onGlobalError === null || onGlobalError === void 0 ? void 0 : onGlobalError(context, source, `Cannot find already parsed comment in statement ${token} with token ${commentToken}`, nextTokenMatch.index);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
tokensIndex = commentPair[1].end;
|
||
|
|
(_d = lastParsedToken.comments) !== null && _d !== void 0 ? _d : (lastParsedToken.comments = []);
|
||
|
|
lastParsedToken.comments.push(commentPair);
|
||
|
|
continue findNextToken;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const { closeRegExp, onError: onCommentError, onParse: onCommentParse, } = preparedComments[commentKey];
|
||
|
|
tokensIndex = nextTokenRegExp.lastIndex;
|
||
|
|
const openToken = {
|
||
|
|
start: nextTokenMatch.index,
|
||
|
|
end: tokensIndex,
|
||
|
|
match: nextTokenMatch,
|
||
|
|
token: commentToken,
|
||
|
|
};
|
||
|
|
closeRegExp.lastIndex = tokensIndex;
|
||
|
|
const closeMatch = closeRegExp.exec(source);
|
||
|
|
if (closeMatch === null) {
|
||
|
|
onCommentError === null || onCommentError === void 0 ? void 0 : onCommentError(context, source, openToken);
|
||
|
|
onError === null || onError === void 0 ? void 0 : onError(context, source, ...parsedTokens);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
tokensIndex = closeRegExp.lastIndex;
|
||
|
|
const closeToken = {
|
||
|
|
start: closeMatch.index,
|
||
|
|
end: tokensIndex,
|
||
|
|
match: closeMatch,
|
||
|
|
token: closeMatch[0],
|
||
|
|
};
|
||
|
|
(_e = lastParsedToken.comments) !== null && _e !== void 0 ? _e : (lastParsedToken.comments = []);
|
||
|
|
lastParsedToken.comments.push([openToken, closeToken]);
|
||
|
|
onCommentParse === null || onCommentParse === void 0 ? void 0 : onCommentParse(context, source, openToken, closeToken);
|
||
|
|
continue findNextToken;
|
||
|
|
}
|
||
|
|
onGlobalError === null || onGlobalError === void 0 ? void 0 : onGlobalError(context, source, `Cannot find next part of statement ${token} or comments by regexp ${nextTokenRegExp}`, tokensIndex);
|
||
|
|
tokensIndex = nextTokenRegExp.lastIndex;
|
||
|
|
}
|
||
|
|
if (tokensIndex >= source.length) {
|
||
|
|
if (parsedComments === undefined) {
|
||
|
|
parsedComments = {};
|
||
|
|
for (const commentPair of lastParsedToken.comments || emptyComments) {
|
||
|
|
parsedComments[commentPair[0].start] = commentPair;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
delete lastParsedToken.comments;
|
||
|
|
const maybeIndex = onError === null || onError === void 0 ? void 0 : onError(context, source, ...parsedTokens);
|
||
|
|
if (maybeIndex !== undefined) {
|
||
|
|
index = maybeIndex;
|
||
|
|
}
|
||
|
|
continue findNextStatement;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const maybeIndex = onParse === null || onParse === void 0 ? void 0 : onParse(context, source, ...parsedTokens);
|
||
|
|
if (maybeIndex !== undefined) {
|
||
|
|
index = maybeIndex;
|
||
|
|
}
|
||
|
|
continue findNextStatement;
|
||
|
|
}
|
||
|
|
for (const key of commentsKeys) {
|
||
|
|
const token = (_f = nextStatementMatch.groups) === null || _f === void 0 ? void 0 : _f[key];
|
||
|
|
if (token === undefined) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (parsedComments !== undefined) {
|
||
|
|
const commentPair = parsedComments[nextStatementMatch.index];
|
||
|
|
if (commentPair === undefined) {
|
||
|
|
onGlobalError === null || onGlobalError === void 0 ? void 0 : onGlobalError(context, source, `Cannot find already parsed comment with token ${token}`, nextStatementMatch.index);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
index = commentPair[1].end;
|
||
|
|
continue findNextStatement;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const { closeRegExp, onError, onParse } = preparedComments[key];
|
||
|
|
index = nextStatementRegExp.lastIndex;
|
||
|
|
const openToken = {
|
||
|
|
start: nextStatementMatch.index,
|
||
|
|
end: index,
|
||
|
|
match: nextStatementMatch,
|
||
|
|
token,
|
||
|
|
};
|
||
|
|
closeRegExp.lastIndex = index;
|
||
|
|
const closeMatch = closeRegExp.exec(source);
|
||
|
|
if (closeMatch === null) {
|
||
|
|
onError === null || onError === void 0 ? void 0 : onError(context, source, openToken);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
index = closeRegExp.lastIndex;
|
||
|
|
const closeToken = {
|
||
|
|
start: closeMatch.index,
|
||
|
|
end: index,
|
||
|
|
match: closeMatch,
|
||
|
|
token: closeMatch[0],
|
||
|
|
};
|
||
|
|
onParse === null || onParse === void 0 ? void 0 : onParse(context, source, openToken, closeToken);
|
||
|
|
continue findNextStatement;
|
||
|
|
}
|
||
|
|
onGlobalError === null || onGlobalError === void 0 ? void 0 : onGlobalError(context, source, `Cannot find statements or comments by regexp ${nextStatementRegExp}`, index);
|
||
|
|
index = nextStatementRegExp.lastIndex;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
return parse;
|
||
|
|
};
|
||
|
|
/**
|
||
|
|
* Empty comments array to skip `for-or` cycle.
|
||
|
|
*/
|
||
|
|
const emptyComments = [];
|