Skip to content

Commit f8aa228

Browse files
committed
comments
1 parent ccd9bb3 commit f8aa228

1 file changed

Lines changed: 17 additions & 8 deletions

File tree

src/preprocessor/preprocessor.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ export type NodeEvaluators = Partial<
139139
}
140140
>;
141141

142+
// Use the same parser, but starting from the expression entry point, to parse
143+
// expression strings on the fly after macro expansion
142144
const expressionParser = (src: string): PreprocessorAstNode =>
143145
formatError(parser)(src, {
144146
grammarSource: 'expression',
@@ -488,23 +490,30 @@ export type PreprocessorOptions = {
488490
startRule?: 'constant_expression' | 'program';
489491
};
490492

491-
// Evaluate a raw #if / #elif expression string against the current macros.
492-
// Handles defined() before macro expansion (spec-correct order), then
493-
// parses the result as a constant_expression AST and evaluates it.
493+
// Expressions are stored as strings in the AST, since their contents may be
494+
// affected by macro expansion. This function performs macro expansion, then
495+
// parses and evaluates the expanded string. It uses the same grammar, but
496+
// starting from the "constant expression" rule to parse, aka the rule for the
497+
// expression of an if / elif
494498
const evaluateExpressionString = (expr: string, macros: Macros): any => {
495499
// Strip inline comments so "defined/**/A" is treated as "defined A"
496500
const stripped = preprocessComments(expr);
497-
// Step 1: evaluate defined(X) / defined X before any macro expansion
498-
const withDefined = stripped
501+
502+
// In the input
503+
// #define A
504+
// #if !defined(A)
505+
// If we expand macros then evaluate the expression it will break. The spec
506+
// says that identifiers inside defined() are not eligible for expansion. So
507+
// hacky way to evaluate them first before macro expansion and parsing
508+
const defined = stripped
499509
.replace(/defined\s*\(\s*([A-Za-z_][A-Za-z_0-9]*)\s*\)/g, (_, id) =>
500510
id in macros ? '1' : '0'
501511
)
502512
.replace(/defined\s+([A-Za-z_][A-Za-z_0-9]*)/g, (_, id) =>
503513
id in macros ? '1' : '0'
504514
);
505-
// Step 2: expand all macros in the resulting string
506-
const expanded = expandMacros(withDefined, macros);
507-
// Step 3: parse the expanded string as a constant_expression and evaluate
515+
516+
const expanded = expandMacros(defined, macros);
508517
return evaluteExpression(expressionParser(expanded.trim()), macros);
509518
};
510519

0 commit comments

Comments
 (0)