@@ -6,7 +6,8 @@ const { resolve } = require('path');
66const { parseArgs } = require ( 'util' )
77const { createInterface } = require ( 'readline' ) ;
88const { inspect } = require ( 'util' ) ;
9- const { runClang } = require ( './clang-utils' ) ;
9+ const { runClang } = require ( '../lib/clang-utils' ) ;
10+ const { evaluate } = require ( '../lib/parse-utils' ) ;
1011
1112/**
1213 * @returns {Promise<string> } Version string, eg. `'v19.6.0'`.
@@ -32,8 +33,11 @@ function removeExperimentals(stream, destination, verbose = false) {
3233 } ;
3334 const rl = createInterface ( stream ) ;
3435
35- /** @type {Array<'write' | 'ignore'> } */
36- let mode = [ 'write' ] ;
36+ /** @type {Array<'write' | 'ignore' | 'preprocessor'> } */
37+ const mode = [ 'write' ] ;
38+
39+ /** @type {Array<string> } */
40+ const preprocessor = [ ] ;
3741
3842 /** @type {Array<string> } */
3943 const macroStack = [ ] ;
@@ -44,6 +48,22 @@ function removeExperimentals(stream, destination, verbose = false) {
4448 let lineNumber = 0 ;
4549 let toWrite = '' ;
4650
51+ const handlePreprocessor = ( expression ) => {
52+ const result = evaluate ( expression ) ;
53+
54+ macroStack . push ( expression ) ;
55+
56+ if ( result === false ) {
57+ debug ( `Line ${ lineNumber } Ignored '${ expression } '` ) ;
58+ mode . push ( 'ignore' ) ;
59+ return false ;
60+ } else {
61+ debug ( `Line ${ lineNumber } Pushed '${ expression } '` ) ;
62+ mode . push ( 'write' ) ;
63+ return true ;
64+ }
65+ } ;
66+
4767 rl . on ( 'line' , function lineHandler ( line ) {
4868 ++ lineNumber ;
4969 if ( matches = line . match ( / ^ \s * # i f ( n ) ? d e f \s + ( [ A - Z a - z _ ] [ A - Z a - z 0 - 9 _ ] * ) / ) ) {
@@ -63,14 +83,23 @@ function removeExperimentals(stream, destination, verbose = false) {
6383 } else {
6484 mode . push ( 'write' ) ;
6585 }
66-
6786 }
6887 else if ( matches = line . match ( / ^ \s * # i f \s + ( .+ ) $ / ) ) {
69- const identifier = matches [ 1 ] ;
70- macroStack . push ( identifier ) ;
71- mode . push ( 'write' ) ;
88+ const expression = matches [ 1 ] ;
89+ if ( expression . endsWith ( '\\' ) ) {
90+ if ( preprocessor . length ) {
91+ reject ( new Error ( `Unexpected preprocessor continuation on line ${ lineNumber } ` ) ) ;
92+ return ;
93+ }
94+ preprocessor . push ( expression . substring ( 0 , expression . length - 1 ) ) ;
7295
73- debug ( `Line ${ lineNumber } Pushed ${ identifier } ` ) ;
96+ mode . push ( 'preprocessor' ) ;
97+ return ;
98+ } else {
99+ if ( ! handlePreprocessor ( expression ) ) {
100+ return ;
101+ }
102+ }
74103 }
75104 else if ( line . match ( / ^ # e l s e (?: \s + | $ ) / ) ) {
76105 const identifier = macroStack [ macroStack . length - 1 ] ;
@@ -83,7 +112,7 @@ function removeExperimentals(stream, destination, verbose = false) {
83112 return ;
84113 }
85114
86- if ( identifier === 'NAPI_EXPERIMENTAL' ) {
115+ if ( identifier . indexOf ( 'NAPI_EXPERIMENTAL' ) > - 1 ) {
87116 const lastMode = mode [ mode . length - 1 ] ;
88117 mode [ mode . length - 1 ] = ( lastMode === 'ignore' ) ? 'write' : 'ignore' ;
89118 return ;
@@ -98,9 +127,10 @@ function removeExperimentals(stream, destination, verbose = false) {
98127 if ( ! identifier ) {
99128 rl . off ( 'line' , lineHandler ) ;
100129 reject ( new Error ( `Macro stack is empty handling #endif on line ${ lineNumber } ` ) ) ;
130+ return ;
101131 }
102132
103- if ( identifier === 'NAPI_EXPERIMENTAL' ) {
133+ if ( identifier . indexOf ( 'NAPI_EXPERIMENTAL' ) > - 1 ) {
104134 return ;
105135 }
106136 }
@@ -113,7 +143,28 @@ function removeExperimentals(stream, destination, verbose = false) {
113143
114144 if ( mode [ mode . length - 1 ] === 'write' ) {
115145 toWrite += `${ line } \n` ;
146+ } else if ( mode [ mode . length - 1 ] === 'preprocessor' ) {
147+ if ( ! preprocessor ) {
148+ reject ( new Error ( `Preprocessor mode without preprocessor on line ${ lineNumber } ` ) ) ;
149+ return ;
150+ }
151+
152+ if ( line . endsWith ( '\\' ) ) {
153+ preprocessor . push ( line . substring ( 0 , line . length - 1 ) ) ;
154+ return ;
155+ }
156+
157+ preprocessor . push ( line ) ;
158+
159+ const expression = preprocessor . join ( '' ) ;
160+ preprocessor . length = 0 ;
161+ mode . pop ( ) ;
162+
163+ if ( ! handlePreprocessor ( expression ) ) {
164+ return ;
165+ }
116166 }
167+
117168 } ) ;
118169
119170 rl . on ( 'close' , ( ) => {
@@ -138,7 +189,7 @@ function removeExperimentals(stream, destination, verbose = false) {
138189 * @param {string } path Path for file to validate with clang.
139190 */
140191async function validateSyntax ( path ) {
141- try {
192+ try {
142193 await runClang ( [ '-fsyntax-only' , path ] ) ;
143194 } catch ( e ) {
144195 throw new Error ( `Syntax validation failed for ${ path } : ${ e } ` ) ;
0 commit comments