blob: bd116d0af8f5d610807d5e0ad914c66710a77edb [file] [log] [blame]
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ import { assert } from './util/util.js'; // The state of the preprocessor is a stack of States.
var State;
(function (State) {
State[(State['Seeking'] = 0)] = 'Seeking';
State[(State['Passing'] = 1)] = 'Passing';
State[(State['Skipping'] = 2)] = 'Skipping';
})(State || (State = {}));
// The transitions in the state space are the following preprocessor directives:
// - Sibling elif
// - Sibling else
// - Sibling endif
// - Child if
class Directive {
constructor(depth) {
this.depth = depth;
}
checkDepth(stack) {
assert(
stack.length === this.depth,
`Number of "$"s must match nesting depth, currently ${stack.length} (e.g. $if $$if $$endif $endif)`
);
}
}
class If extends Directive {
constructor(depth, predicate) {
super(depth);
this.predicate = predicate;
}
applyTo(stack) {
this.checkDepth(stack);
const parentState = stack[stack.length - 1].state;
stack.push({
allowsFollowingElse: true,
state:
parentState !== State.Passing
? State.Skipping
: this.predicate
? State.Passing
: State.Seeking,
});
}
}
class ElseIf extends If {
applyTo(stack) {
assert(stack.length >= 1);
const { allowsFollowingElse, state: siblingState } = stack.pop();
this.checkDepth(stack);
assert(allowsFollowingElse, 'pp.elif after pp.else');
if (siblingState !== State.Seeking) {
stack.push({ allowsFollowingElse: true, state: State.Skipping });
} else {
super.applyTo(stack);
}
}
}
class Else extends Directive {
applyTo(stack) {
assert(stack.length >= 1);
const { allowsFollowingElse, state: siblingState } = stack.pop();
this.checkDepth(stack);
assert(allowsFollowingElse, 'pp.else after pp.else');
stack.push({
allowsFollowingElse: false,
state: siblingState === State.Seeking ? State.Passing : State.Skipping,
});
}
}
class EndIf extends Directive {
applyTo(stack) {
stack.pop();
this.checkDepth(stack);
}
}
/**
* A simple template-based, non-line-based preprocessor implementing if/elif/else/endif.
*
* @example
* const shader = pp`
* ${pp._if(expr)}
* const x: ${type} = ${value};
* ${pp._elif(expr)}
* ${pp.__if(expr)}
* ...
* ${pp.__else}
* ...
* ${pp.__endif}
* ${pp._endif}`;
*
* @param strings - The array of constant string chunks of the template string.
* @param ...values - The array of interpolated ${} values within the template string.
*/
export function pp(strings, ...values) {
let result = '';
const stateStack = [{ allowsFollowingElse: false, state: State.Passing }];
for (let i = 0; i < values.length; ++i) {
const passing = stateStack[stateStack.length - 1].state === State.Passing;
if (passing) {
result += strings[i];
}
const value = values[i];
if (value instanceof Directive) {
value.applyTo(stateStack);
} else {
if (passing) {
result += value;
}
}
}
assert(stateStack.length === 1, 'Unterminated preprocessor condition at end of file');
result += strings[values.length];
return result;
}
pp._if = predicate => new If(1, predicate);
pp._elif = predicate => new ElseIf(1, predicate);
pp._else = new Else(1);
pp._endif = new EndIf(1);
pp.__if = predicate => new If(2, predicate);
pp.__elif = predicate => new ElseIf(2, predicate);
pp.__else = new Else(2);
pp.__endif = new EndIf(2);
pp.___if = predicate => new If(3, predicate);
pp.___elif = predicate => new ElseIf(3, predicate);
pp.___else = new Else(3);
pp.___endif = new EndIf(3);
// Add more if needed.