diff --git a/src/preprocessor/index.ts b/src/preprocessor/index.ts index 4c1a89c..f416c42 100644 --- a/src/preprocessor/index.ts +++ b/src/preprocessor/index.ts @@ -3,6 +3,7 @@ import { preprocessAst, preprocessComments, PreprocessorOptions, + visitPreprocessedAst, } from './preprocessor.js'; // This index file is currently only for package publishing, where the whole @@ -20,4 +21,4 @@ const preprocess = (src: string, options: PreprocessorOptions) => export default preprocess; -export { preprocessAst, preprocessComments, generate, preprocess, parser }; +export { preprocessAst, preprocessComments, generate, preprocess, parser, visitPreprocessedAst }; diff --git a/src/preprocessor/preprocessor-grammar.pegjs b/src/preprocessor/preprocessor-grammar.pegjs index 326d601..fca70f3 100644 --- a/src/preprocessor/preprocessor-grammar.pegjs +++ b/src/preprocessor/preprocessor-grammar.pegjs @@ -77,6 +77,7 @@ UNDEF = wsStart:_? token:"#undef" wsEnd:_? { return node('literal', { literal: t ERROR = wsStart:_? token:"#error" wsEnd:_? { return node('literal', { literal: token, wsStart, wsEnd }); } PRAGMA = wsStart:_? token:"#pragma" wsEnd:_? { return node('literal', { literal: token, wsStart, wsEnd }); } DEFINED = wsStart:_? token:"defined" wsEnd:_? { return node('literal', { literal: token, wsStart, wsEnd }); } +DEFINED_WITH_END_WS = wsStart:_? token:"defined" wsEnd:__ { return node('literal', { literal: token, wsStart, wsEnd }); } IF = wsStart:_? token:"#if" wsEnd:_? { return node('literal', { literal: token, wsStart, wsEnd }); } IFDEF = wsStart:_? token:"#ifdef" wsEnd:_? { return node('literal', { literal: token, wsStart, wsEnd }); } IFNDEF = wsStart:_? token:"#ifndef" wsEnd:_? { return node('literal', { literal: token, wsStart, wsEnd }); } @@ -224,6 +225,9 @@ unary_expression "unary expression" = operator:DEFINED lp:LEFT_PAREN identifier:IDENTIFIER rp:RIGHT_PAREN { return node('unary_defined', { operator, lp, identifier, rp, }); } + / operator:DEFINED_WITH_END_WS identifier:IDENTIFIER { + return node('unary_defined', { operator, identifier}); + } / operator:(PLUS / DASH / BANG / TILDE) expression:unary_expression { return node('unary', { operator, expression }); @@ -323,10 +327,18 @@ logical_or_expression "logical or expression" // I added this as a maybe entry point to expressions constant_expression "constant expression" = logical_or_expression +// Must have a space or a comment +__ "whitespace or comment" = w:whitespace rest:(comment whitespace?)* { + return collapse(w, rest); +} +/ c:comment rest:(whitespace comment?)* { + return collapse(c, rest); +} + // The whitespace is optional so that we can put comments immediately after // terminals, like void/* comment */ // The ending whitespace is so that linebreaks can happen after comments -_ "whitespace or comment" = w:whitespace? rest:(comment whitespace?)* { +_ "whitespace or comment or null" = w:whitespace? rest:(comment whitespace?)* { return collapse(w, rest); } diff --git a/src/preprocessor/preprocessor.test.ts b/src/preprocessor/preprocessor.test.ts index d9be523..910f98c 100644 --- a/src/preprocessor/preprocessor.test.ts +++ b/src/preprocessor/preprocessor.test.ts @@ -477,6 +477,25 @@ test('generate #ifdef & #ifndef & #else', () => { `); }); + +test('parse defined && defined() && definedXXX', () => { + const program = ` +#if defined AAA && defined/**/BBB && defined/**/ CCC && definedXXX && defined(DDD) +#endif +`; + const ast = parse(program); + const astStr = JSON.stringify(ast); + expect(astStr.includes('"identifier":"definedXXX"')).toBeTruthy(); + expect(astStr.includes('"identifier":"AAA"')).toBeTruthy(); + expect(astStr.includes('"identifier":"BBB"')).toBeTruthy(); + expect(astStr.includes('"identifier":"CCC"')).toBeTruthy(); + expect(astStr.includes('"identifier":"DDD"')).toBeTruthy(); + expect(astStr.includes('"identifier":"XXX"')).toBeFalsy(); + expect(astStr.match(/unary_defined/g)?.length).toBe(4); + + expectParsedProgram(program); +}); + /* test('debug', () => { const program = ` diff --git a/src/preprocessor/preprocessor.ts b/src/preprocessor/preprocessor.ts index a07ed47..04e8b14 100644 --- a/src/preprocessor/preprocessor.ts +++ b/src/preprocessor/preprocessor.ts @@ -434,7 +434,7 @@ type VisitorOverride = ( ) => void; // @ts-ignore -const visitPreprocessedAst = visit as VisitorOverride; +export const visitPreprocessedAst = visit as VisitorOverride; type PathOverride = { node: NodeType;