@wgslx/wgslx
Version:
Extended WebGPU shading language tools
199 lines (198 loc) • 7.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.discoverTemplates = exports.stripComments = exports.preprocess = void 0;
const patterns_1 = require("./patterns");
const util_1 = require("./util");
function preprocess(text) {
text = stripComments(text);
const templateLists = discoverTemplates(text);
text = text.replaceAll(/[<>]/g, (character, offset) => {
switch (character) {
case '<':
return templateLists.some((t) => t.startPosition === offset)
? util_1.TEMPLATE_START
: '<';
case '>':
return templateLists.some((t) => t.endPosition === offset)
? util_1.TEMPLATE_END
: '>';
}
throw new Error('Unidentified character.');
});
return text;
}
exports.preprocess = preprocess;
function firstIndexOf(text, position, ...values) {
let minIndex = Number.MAX_SAFE_INTEGER;
let minChar = '';
for (let value of values) {
const index = text.indexOf(value, position);
if (index !== -1 && index < minIndex) {
minIndex = index;
minChar = value;
}
}
if (minIndex === Number.MAX_SAFE_INTEGER) {
return [-1, ''];
}
return [minIndex, minChar];
}
function stripComments(text) {
const lines = text.split(patterns_1.LINE_BREAK_REGEX);
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const [firstCommentIndex, firstCommentType] = firstIndexOf(lines[lineIndex], 0, '//', '/*', '*/');
if (firstCommentIndex === -1) {
lines[lineIndex] = lines[lineIndex].trimEnd();
continue;
}
if (firstCommentType === '*/') {
throw new Error(`Line ${lineIndex + 1}: Unexpected block comment close.`);
}
if (firstCommentType === '//') {
lines[lineIndex] = lines[lineIndex].substring(0, firstCommentIndex);
continue;
}
let depth = 1;
let startLine = lineIndex;
let column = firstCommentIndex + 2;
while (depth !== 0) {
const [nextBlockIndex, nextBlockType] = firstIndexOf(lines[lineIndex], column, '/*', '*/');
if (nextBlockIndex === -1) {
if (lineIndex === lines.length - 1) {
throw new Error(`Line ${startLine}: Unclosed block comment.`);
}
lineIndex += 1;
column = 0;
continue;
}
if (nextBlockType === '/*') {
depth += 1;
column = nextBlockIndex + 2;
continue;
}
if (nextBlockType === '*/') {
depth -= 1;
column = nextBlockIndex + 2;
continue;
}
throw new Error('Unreachable code.');
}
if (startLine == lineIndex) {
lines[lineIndex] =
lines[lineIndex].substring(0, firstCommentIndex) +
' '.repeat(column - firstCommentIndex) +
lines[lineIndex].substring(column);
lineIndex -= 1;
continue;
}
lines[startLine] = lines[startLine].substring(0, firstCommentIndex);
for (let j = startLine + 1; j < lineIndex; j++) {
lines[j] = '';
}
lines[lineIndex] = ' '.repeat(column) + lines[lineIndex].substring(column);
lineIndex -= 1;
}
return lines.join('\n');
}
exports.stripComments = stripComments;
function discoverTemplates(text) {
const discoveredTemplateLists = [];
const pendingCandidatesStack = [];
let currentPosition = 0;
let nestingDepth = 0;
function matchAdvance(...matchers) {
const startPosition = currentPosition;
let matched = false;
rematch: do {
for (let matcher of matchers) {
const match = matcher(text, currentPosition);
if (match) {
currentPosition += match.length;
matched = true;
continue rematch;
}
}
matched = false;
} while (matched === true && matchers.length > 1);
return startPosition === currentPosition
? undefined
: text.substring(startPosition, currentPosition);
}
function startsWithAdvance(...consts) {
const rest = text.substring(currentPosition);
for (const str of consts) {
if (rest.startsWith(str)) {
currentPosition += str.length;
return true;
}
}
return false;
}
while (currentPosition < text.length) {
matchAdvance(patterns_1.matchBlankspace, patterns_1.matchLiteral, patterns_1.matchLineEndingComment, patterns_1.matchBlockComment);
if (matchAdvance(patterns_1.matchIdentPatternToken)) {
matchAdvance(patterns_1.matchBlankspace, patterns_1.matchLineEndingComment, patterns_1.matchBlockComment);
if (startsWithAdvance('<')) {
pendingCandidatesStack.push({
position: currentPosition - 1,
depth: nestingDepth,
});
if (startsWithAdvance('<') || startsWithAdvance('=')) {
pendingCandidatesStack.pop();
}
}
continue;
}
if (startsWithAdvance('>')) {
if (pendingCandidatesStack.length > 0 &&
pendingCandidatesStack[pendingCandidatesStack.length - 1].depth ===
nestingDepth) {
const pending = pendingCandidatesStack.pop();
discoveredTemplateLists.push({
startPosition: pending.position,
endPosition: currentPosition - 1,
});
}
else {
startsWithAdvance('=');
}
continue;
}
if (startsWithAdvance('(', '[')) {
nestingDepth++;
continue;
}
if (startsWithAdvance(')', ']')) {
nestingDepth--;
continue;
}
if (startsWithAdvance('!')) {
startsWithAdvance('=');
continue;
}
if (startsWithAdvance('=')) {
if (startsWithAdvance('=')) {
continue;
}
nestingDepth = 0;
pendingCandidatesStack.length = 0;
continue;
}
if (startsWithAdvance(';', '{', ':')) {
nestingDepth = 0;
pendingCandidatesStack.length = 0;
continue;
}
if (startsWithAdvance('&&', '||')) {
while (pendingCandidatesStack.length &&
pendingCandidatesStack[pendingCandidatesStack.length - 1].depth >=
nestingDepth) {
pendingCandidatesStack.pop();
}
continue;
}
currentPosition += 1;
}
return discoveredTemplateLists;
}
exports.discoverTemplates = discoverTemplates;