@@ -6,7 +6,8 @@ const { resolve } = require('path');
6
6
const { parseArgs } = require ( 'util' )
7
7
const { createInterface } = require ( 'readline' ) ;
8
8
const { inspect } = require ( 'util' ) ;
9
- const { runClang } = require ( './clang-utils' ) ;
9
+ const { runClang } = require ( '../lib/clang-utils' ) ;
10
+ const { evaluate } = require ( '../lib/parse-utils' ) ;
10
11
11
12
/**
12
13
* @returns {Promise<string> } Version string, eg. `'v19.6.0'`.
@@ -32,8 +33,11 @@ function removeExperimentals(stream, destination, verbose = false) {
32
33
} ;
33
34
const rl = createInterface ( stream ) ;
34
35
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 = [ ] ;
37
41
38
42
/** @type {Array<string> } */
39
43
const macroStack = [ ] ;
@@ -44,6 +48,22 @@ function removeExperimentals(stream, destination, verbose = false) {
44
48
let lineNumber = 0 ;
45
49
let toWrite = '' ;
46
50
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
+
47
67
rl . on ( 'line' , function lineHandler ( line ) {
48
68
++ lineNumber ;
49
69
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) {
63
83
} else {
64
84
mode . push ( 'write' ) ;
65
85
}
66
-
67
86
}
68
87
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 ) ) ;
72
95
73
- debug ( `Line ${ lineNumber } Pushed ${ identifier } ` ) ;
96
+ mode . push ( 'preprocessor' ) ;
97
+ return ;
98
+ } else {
99
+ if ( ! handlePreprocessor ( expression ) ) {
100
+ return ;
101
+ }
102
+ }
74
103
}
75
104
else if ( line . match ( / ^ # e l s e (?: \s + | $ ) / ) ) {
76
105
const identifier = macroStack [ macroStack . length - 1 ] ;
@@ -83,7 +112,7 @@ function removeExperimentals(stream, destination, verbose = false) {
83
112
return ;
84
113
}
85
114
86
- if ( identifier === 'NAPI_EXPERIMENTAL' ) {
115
+ if ( identifier . indexOf ( 'NAPI_EXPERIMENTAL' ) > - 1 ) {
87
116
const lastMode = mode [ mode . length - 1 ] ;
88
117
mode [ mode . length - 1 ] = ( lastMode === 'ignore' ) ? 'write' : 'ignore' ;
89
118
return ;
@@ -98,9 +127,10 @@ function removeExperimentals(stream, destination, verbose = false) {
98
127
if ( ! identifier ) {
99
128
rl . off ( 'line' , lineHandler ) ;
100
129
reject ( new Error ( `Macro stack is empty handling #endif on line ${ lineNumber } ` ) ) ;
130
+ return ;
101
131
}
102
132
103
- if ( identifier === 'NAPI_EXPERIMENTAL' ) {
133
+ if ( identifier . indexOf ( 'NAPI_EXPERIMENTAL' ) > - 1 ) {
104
134
return ;
105
135
}
106
136
}
@@ -113,7 +143,28 @@ function removeExperimentals(stream, destination, verbose = false) {
113
143
114
144
if ( mode [ mode . length - 1 ] === 'write' ) {
115
145
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
+ }
116
166
}
167
+
117
168
} ) ;
118
169
119
170
rl . on ( 'close' , ( ) => {
@@ -138,7 +189,7 @@ function removeExperimentals(stream, destination, verbose = false) {
138
189
* @param {string } path Path for file to validate with clang.
139
190
*/
140
191
async function validateSyntax ( path ) {
141
- try {
192
+ try {
142
193
await runClang ( [ '-fsyntax-only' , path ] ) ;
143
194
} catch ( e ) {
144
195
throw new Error ( `Syntax validation failed for ${ path } : ${ e } ` ) ;
0 commit comments