11/**
22 * WGSL shader preprocessor implementation
33 */
4- import { fetchInclude , parseUint32 , WGSLError } from './utils' ;
4+ import { evalMathExpression , fetchInclude , parseUint32 , WGSLError } from './utils' ;
55
66// Regular expressions for preprocessing
77const RE_COMMENT = / ( \/ \/ .* | \/ \* [ \s \S ] * ?\* \/ ) / g;
8- const RE_WORD = / [ a - z A - Z _ ] [ a - z A - Z 0 - 9 _ ] * / g;
8+ const RE_WORD = / \b \w + \b / g;
99
1010const STRING_MAX_LEN = 20 ;
1111
@@ -35,15 +35,17 @@ export class SourceMap {
3535 * Handles WGSL preprocessing including includes, defines, etc.
3636 */
3737export class Preprocessor {
38+ private overrides : Map < string , string > ;
3839 private defines : Map < string , string > ;
3940 private source : SourceMap ;
4041 private storageCount : number ;
4142 // private assertCount: number;
4243 private specialStrings : boolean ;
4344
44- constructor ( defines : Map < string , string > ) {
45- this . defines = new Map ( defines ) ;
46- this . defines . set ( 'STRING_MAX_LEN' , STRING_MAX_LEN . toString ( ) ) ;
45+ constructor ( overrides : Map < string , string > ) {
46+ this . overrides = new Map ( overrides ) ;
47+ this . overrides . set ( 'STRING_MAX_LEN' , STRING_MAX_LEN . toString ( ) ) ;
48+ this . defines = new Map ( ) ;
4749 this . source = new SourceMap ( ) ;
4850 this . storageCount = 0 ;
4951 // this.assertCount = 0;
@@ -57,20 +59,14 @@ export class Preprocessor {
5759 return source . replace ( RE_COMMENT , '' ) ;
5860 }
5961
60- /**
61- * Substitute defines in source text
62- */
63- private substDefines ( source : string ) : string {
64- return source . replace ( RE_WORD , match => {
65- return this . defines . get ( match ) ?? match ;
66- } ) ;
67- }
68-
6962 /**
7063 * Process a single line of shader source
7164 */
7265 private async processLine ( lineOrig : string , lineNum : number ) : Promise < void > {
73- let line = this . substDefines ( lineOrig ) ;
66+ // Substitute overrides and defines
67+ let line = lineOrig
68+ . replace ( RE_WORD , match => this . overrides . get ( match ) ?? match )
69+ . replace ( RE_WORD , match => this . defines . get ( match ) ?? match ) ;
7470
7571 // Handle enable directives
7672 if ( line . trimStart ( ) . startsWith ( 'enable' ) ) {
@@ -79,6 +75,14 @@ export class Preprocessor {
7975 return ;
8076 }
8177
78+ // Handle override in one line and evaluate to number
79+ if ( line . trimStart ( ) . startsWith ( 'override' ) ) {
80+ line = line . replace ( RE_COMMENT , '' ) ;
81+ const tokens = line . trim ( ) . replace ( '=' , ' = ' ) . replace ( / \s + / g, ' ' ) . split ( ' ' ) ;
82+ this . handleOverride ( tokens , lineNum ) ;
83+ return ;
84+ }
85+
8286 // Handle preprocessor directives
8387 if ( line . trimStart ( ) . startsWith ( '#' ) ) {
8488 line = line . replace ( RE_COMMENT , '' ) ;
@@ -103,7 +107,7 @@ export class Preprocessor {
103107 break ;
104108
105109 case '#define' :
106- this . handleDefine ( lineOrig , tokens , lineNum ) ;
110+ this . handleDefine ( tokens , lineNum ) ;
107111 break ;
108112
109113 case '#storage' :
@@ -232,20 +236,41 @@ export class Preprocessor {
232236 /**
233237 * Handle #define directive
234238 */
235- private handleDefine ( lineOrig : string , tokens : string [ ] , lineNum : number ) : void {
236- const name = lineOrig . trim ( ) . split ( ' ' ) [ 1 ] ;
239+ private handleDefine ( tokens : string [ ] , lineNum : number ) : void {
240+ const name = tokens [ 1 ] ;
237241 if ( ! name ) {
238242 throw new WGSLError ( 'Invalid #define syntax' , lineNum ) ;
239243 }
240244
241245 const value = tokens . slice ( 2 ) . join ( ' ' ) ;
242- if ( this . defines . has ( name ) ) {
246+ if ( value . includes ( name ) ) {
243247 throw new WGSLError ( `Cannot redefine ${ name } ` , lineNum ) ;
244248 }
245249
246250 this . defines . set ( name , value ) ;
247251 }
248252
253+ // /**
254+ // * Handle override in one line and evaluate to number
255+ // */
256+ private handleOverride ( tokens : string [ ] , lineNum : number ) : void {
257+ const name = tokens [ 1 ] ;
258+ let expression = tokens . slice ( 3 ) . join ( '' ) ;
259+ if ( ! name || ! expression . endsWith ( ';' ) ) {
260+ throw new WGSLError (
261+ `Please write override in single line ${ lineNum } and terminated!` ,
262+ lineNum
263+ ) ;
264+ }
265+ if ( expression . includes ( name ) ) {
266+ throw new WGSLError ( `Cannot redefine ${ name } ` , lineNum ) ;
267+ }
268+
269+ expression = expression . slice ( 0 , - 1 ) ;
270+ expression = evalMathExpression ( expression , lineNum ) ;
271+ this . defines . set ( name , expression ) ;
272+ }
273+
249274 /**
250275 * Handle #storage directive
251276 */
0 commit comments