11import { NodeVisitor , Path , visit } from '../ast/visit' ;
22import {
33 PreprocessorAstNode ,
4- PreprocessorConditionalNode ,
54 PreprocessorElseIfNode ,
65 PreprocessorIdentifierNode ,
76 PreprocessorIfNode ,
@@ -175,7 +174,6 @@ const expandFunctionMacro = (
175174
176175 while ( ( startMatch = startRegex . exec ( current ) ) ) {
177176 const result = scanFunctionArgs (
178- // current.substr(startMatch.index + startMatch[0].length)
179177 current . substring ( startMatch . index + startMatch [ 0 ] . length )
180178 ) ;
181179 if ( result === null ) {
@@ -188,7 +186,7 @@ const expandFunctionMacro = (
188186 ) ;
189187 const { args, length : argLength } = result ;
190188
191- // The total lenth of the raw text to replace is the macro name in the
189+ // The total length of the raw text to replace is the macro name in the
192190 // text (startMatch), plus the length of the arguments, plus one to
193191 // encompass the closing paren that the scan fn skips
194192 const matchLength = startMatch [ 0 ] . length + argLength + 1 ;
@@ -251,8 +249,13 @@ const expandObjectMacro = (
251249 const regex = new RegExp ( `\\b${ macroName } \\b` , 'g' ) ;
252250 let expanded = text ;
253251 if ( regex . test ( text ) ) {
252+ // Macro definitions like
253+ // #define MACRO
254+ // Have null for the body. Make it empty string if null to avoid 'null' expanded
255+ const replacement = macro . body || '' ;
256+
254257 const firstPass = tokenPaste (
255- text . replace ( new RegExp ( `\\b${ macroName } \\b` , 'g' ) , macro . body )
258+ text . replace ( new RegExp ( `\\b${ macroName } \\b` , 'g' ) , replacement )
256259 ) ;
257260 // Scan expanded text for more expansions. Ignore the expanded macro because
258261 // of the self-reference rule
@@ -278,7 +281,7 @@ const expandInExpressions = (
278281 macros : Macros ,
279282 ...expressions : PreprocessorAstNode [ ]
280283) => {
281- expressions . filter ( identity ) . forEach ( ( expression ) => {
284+ expressions . forEach ( ( expression ) => {
282285 visitPreprocessedAst ( expression , {
283286 unary_defined : {
284287 enter : ( path ) => {
@@ -496,20 +499,28 @@ const preprocessAst = (
496499 return ;
497500 }
498501
499- // Expand macros
502+ // Expand macros in if/else *expressions* only. Macros are expanded in:
503+ // #if X + 1
504+ // #elif Y + 2
505+ // But *not* in
506+ // # ifdef X
507+ // Because X should not be expanded in the ifdef. Note that
508+ // # if defined(X)
509+ // does have an expression, but the skip() in unary_defined prevents
510+ // macro expansion in there. Checking for .expression and filtering out
511+ // any conditionals without expressions is how ifdef is avoided.
512+ // It's not great that ifdef is skipped differentaly than defined().
500513 expandInExpressions (
501514 macros ,
502- // Expression might not exist, since ifPart can be #ifdef which
503- // doesn't have an expression key
504- ( node . ifPart as PreprocessorIfNode ) . expression ,
505- ...node . elseIfParts . map (
506- ( elif : PreprocessorElseIfNode ) => elif . expression
507- ) ,
508- node . elsePart ?. body
515+ ...[
516+ ( node . ifPart as PreprocessorIfNode ) . expression ,
517+ ...node . elseIfParts . map (
518+ ( elif : PreprocessorElseIfNode ) => elif . expression
519+ ) ,
520+ ] . filter ( identity )
509521 ) ;
510522
511523 if ( evaluateIfPart ( macros , node . ifPart ) ) {
512- // Yuck! So much type casting in this file
513524 path . replaceWith ( node . ifPart . body ) ;
514525 // Keeping this commented out block in case I can find a way to
515526 // conditionally evaluate shaders
0 commit comments