@@ -68,12 +68,14 @@ module.exports = grammar({
6868 $ . _preproc_unary_operator ,
6969 $ . hollerith_constant ,
7070 $ . macro_identifier ,
71+ $ . whitespace ,
7172 ] ,
7273
7374 extras : $ => [
7475 // This allows escaping newlines everywhere, although this is only valid in
7576 // preprocessor statements
7677 / \s | \\ \r ? \n / ,
78+ $ . whitespace ,
7779 $ . comment ,
7880 $ . multiline_preproc_comment ,
7981 '&' ,
@@ -153,22 +155,32 @@ module.exports = grammar({
153155 $ . system_lib_string ,
154156 alias ( $ . preproc_call_expression , $ . call_expression ) ,
155157 ) ) ,
156- / \r ? \n / ,
158+ $ . _external_end_of_statement ,
157159 ) ,
158160
159161 preproc_def : $ => seq (
160162 preprocessor ( 'define' ) ,
161163 field ( 'name' , $ . identifier ) ,
164+ // HACK: This `optional($.whitespace)` is a workaround to prevent
165+ // `tree-sitter` from misinterpreting `#define FOO (bar * baz)` as a
166+ // `preproc_function_def`. For reasons related to how `token.immediate()`
167+ // detects adjacent tokens, explicitly naming the whitespace rule causes
168+ // the parser to think the opening parenthesis after `FOO` is immediately
169+ // following it, which makes it match the function-like form instead of
170+ // the object-like one. Adding an optional `whitespace` node here breaks
171+ // that ambiguity and forces `tree-sitter` to correctly parse it as a
172+ // regular `preproc_def`
173+ optional ( $ . whitespace ) ,
162174 field ( 'value' , optional ( $ . preproc_arg ) ) ,
163- token ( prec ( 1 , / \r ? \n / ) ) , // force newline to win over preproc_arg
175+ $ . _external_end_of_statement ,
164176 ) ,
165177
166178 preproc_function_def : $ => seq (
167179 preprocessor ( 'define' ) ,
168180 field ( 'name' , $ . identifier ) ,
169181 field ( 'parameters' , $ . preproc_params ) ,
170182 field ( 'value' , optional ( $ . preproc_arg ) ) ,
171- token . immediate ( / \r ? \n / ) ,
183+ $ . _external_end_of_statement ,
172184 ) ,
173185
174186 preproc_params : $ => seq (
@@ -178,7 +190,7 @@ module.exports = grammar({
178190 preproc_call : $ => seq (
179191 field ( 'directive' , $ . preproc_directive ) ,
180192 field ( 'argument' , optional ( $ . preproc_arg ) ) ,
181- token . immediate ( / \r ? \n / ) ,
193+ $ . _external_end_of_statement ,
182194 ) ,
183195
184196 ...preprocIf ( '' , $ => repeat ( $ . _top_level_item ) ) ,
0 commit comments