fix invalid free on syntax error
[m6w6/ext-psi] / src / cpp_tokiter.c
1 /*******************************************************************************
2 Copyright (c) 2017, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31
32 #include "cpp.h"
33 #include "parser.h"
34
35 void psi_cpp_tokiter_dump(struct psi_dump *dump, struct psi_cpp *cpp);
36 void psi_cpp_tokiter_dump(struct psi_dump *dump, struct psi_cpp *cpp)
37 {
38 size_t i = cpp->index;
39 struct psi_token *T;
40
41 if (i > 40) {
42 i -= 40;
43 } else {
44 i = 0;
45 }
46 while (psi_plist_get(cpp->tokens.iter, i, &T)) {
47 PSI_DUMP(dump, "PSI: CPP tokens %5zu %c ", i, cpp->index == i ? '*' : ' ');
48 if (T) {
49 psi_token_dump(dump, T);
50 } else {
51 PSI_DUMP(dump, "TOKEN deleted\n");
52 }
53 if (i >= cpp->index + 40) {
54 PSI_DUMP(dump, "PSI: CPP tokens .....\n");
55 break;
56 }
57 ++i;
58 }
59 }
60
61 void psi_cpp_tokiter_reset(struct psi_cpp *cpp)
62 {
63 #if PSI_CPP_DEBUG
64 PSI_DEBUG_PRINT(cpp->parser,
65 "PSI: CPP reset -> iter.count=%zu, next.count=%zu, exec.count=%zu\n",
66 psi_plist_count(cpp->tokens.iter),
67 psi_plist_count(cpp->tokens.next),
68 psi_plist_count(cpp->tokens.exec));
69 # if PSI_CPP_DEBUG > 1
70 PSI_DEBUG_DUMP(cpp->parser, psi_cpp_tokiter_dump, cpp);
71 # endif
72 #endif
73 cpp->index = 0;
74 cpp->expanded = 0;
75 cpp->skip = 0;
76 cpp->seen = 0;
77 cpp->level = 0;
78 cpp->do_cpp = false;
79
80 if (cpp->tokens.next) {
81 psi_plist_free(cpp->tokens.iter);
82 cpp->tokens.iter = cpp->tokens.next;
83 }
84 cpp->tokens.next = psi_plist_init((psi_plist_dtor) psi_token_free);
85 if (cpp->tokens.exec) {
86 assert(!psi_plist_count(cpp->tokens.exec));
87 psi_plist_clean(cpp->tokens.exec);
88 } else {
89 cpp->tokens.exec = psi_plist_init((psi_plist_dtor) psi_token_free);
90 }
91 }
92
93 bool psi_cpp_tokiter_seek(struct psi_cpp *cpp, size_t index)
94 {
95 if (index < psi_plist_count(cpp->tokens.iter)) {
96 cpp->index = index;
97 return true;
98 }
99 return false;
100 }
101
102 struct psi_token *psi_cpp_tokiter_current(struct psi_cpp *cpp)
103 {
104 struct psi_token *current = NULL;
105 bool found = psi_plist_get(cpp->tokens.iter, cpp->index, &current);
106
107 assert(found);
108
109 return current;
110 }
111
112 size_t psi_cpp_tokiter_index(struct psi_cpp *cpp)
113 {
114 return cpp->index;
115 }
116
117 bool psi_cpp_tokiter_add_cur(struct psi_cpp *cpp)
118 {
119 struct psi_token *cur = NULL;
120
121 if (psi_plist_get(cpp->tokens.iter, cpp->index, &cur)) {
122 psi_plist_unset(cpp->tokens.iter, cpp->index);
123 if (cpp->do_cpp) {
124 cpp->tokens.exec = psi_plist_add(cpp->tokens.exec, &cur);
125 } else {
126 cpp->tokens.next = psi_plist_add(cpp->tokens.next, &cur);
127 }
128
129 #if PSI_CPP_DEBUG
130 PSI_DEBUG_PRINT(cpp->parser,
131 "PSI: CPP add_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
132 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
133 psi_plist_count(cpp->tokens.exec));
134 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, cur);
135 #endif
136
137 return true;
138 }
139
140 return false;
141 }
142
143 bool psi_cpp_tokiter_add(struct psi_cpp *cpp, struct psi_token *tok)
144 {
145 if (cpp->do_cpp) {
146 cpp->tokens.exec = psi_plist_add(cpp->tokens.exec, &tok);
147 } else {
148 cpp->tokens.next = psi_plist_add(cpp->tokens.next, &tok);
149 }
150
151 #if PSI_CPP_DEBUG
152 PSI_DEBUG_PRINT(cpp->parser,
153 "PSI: CPP add -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
154 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
155 psi_plist_count(cpp->tokens.exec));
156 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, tok);
157 #endif
158
159 return true;
160 }
161
162
163 bool psi_cpp_tokiter_add_range(struct psi_cpp *cpp, size_t num_eles, void **eles)
164 {
165 if (!num_eles) {
166 return true;
167 }
168
169 if (cpp->do_cpp) {
170 cpp->tokens.exec = psi_plist_add_r(cpp->tokens.exec, num_eles, eles);
171 } else {
172 cpp->tokens.next = psi_plist_add_r(cpp->tokens.next, num_eles, eles);
173 }
174
175 #if PSI_CPP_DEBUG
176 PSI_DEBUG_PRINT(cpp->parser,
177 "PSI: CPP add_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
178 cpp->index, num_eles, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
179 psi_plist_count(cpp->tokens.exec));
180 #endif
181
182 return true;
183 }
184
185
186 void psi_cpp_tokiter_next(struct psi_cpp *cpp)
187 {
188 #if 0 && PSI_CPP_DEBUG
189 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP next -> index=%zu -> index=%zu\n",
190 cpp->index, cpp->index+1);
191 #endif
192 ++cpp->index;
193 }
194
195 bool psi_cpp_tokiter_valid(struct psi_cpp *cpp)
196 {
197 #if 0 && PSI_CPP_DEBUG
198 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP valid -> index=%zu -> %d\n",
199 cpp->index, cpp->index < psi_plist_count(cpp->tokens.iter));
200 #endif
201 return cpp->index < psi_plist_count(cpp->tokens.iter);
202 }
203
204 bool psi_cpp_tokiter_del_prev(struct psi_cpp *cpp, bool free_token)
205 {
206 struct psi_token *cur = NULL;
207
208 #if PSI_CPP_DEBUG
209 PSI_DEBUG_PRINT(cpp->parser,
210 "PSI: CPP del_prev -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
211 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
212 psi_plist_count(cpp->tokens.exec));
213 #endif
214
215 if (cpp->do_cpp) {
216 if (!psi_plist_pop(cpp->tokens.exec, &cur)) {
217 return false;
218 }
219 } else if (!psi_plist_pop(cpp->tokens.next, &cur)) {
220 return false;
221 }
222 if (free_token && cur) {
223 psi_token_free(&cur);
224 }
225 return true;
226 }
227
228 bool psi_cpp_tokiter_del_cur(struct psi_cpp *cpp, bool free_token)
229 {
230 struct psi_token *cur = NULL;
231
232 #if PSI_CPP_DEBUG
233 PSI_DEBUG_PRINT(cpp->parser,
234 "PSI: CPP del_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
235 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
236 psi_plist_count(cpp->tokens.exec));
237 #endif
238
239 if (psi_plist_get(cpp->tokens.iter, cpp->index, &cur)) {
240 #if PSI_CPP_DEBUG
241 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, cur);
242 #endif
243 if (cpp->index == psi_plist_count(cpp->tokens.iter) - 1) {
244 psi_plist_pop(cpp->tokens.iter, NULL);
245 } else {
246 psi_plist_unset(cpp->tokens.iter, cpp->index);
247 }
248 if (free_token && cur) {
249 psi_token_free(&cur);
250 }
251 ++cpp->index;
252 return true;
253 }
254
255 return false;
256 }
257
258 bool psi_cpp_tokiter_del_range(struct psi_cpp *cpp, size_t offset, size_t num_eles, bool free_tokens)
259 {
260 struct psi_token *ptr;
261 size_t i;
262
263 #if PSI_CPP_DEBUG
264 PSI_DEBUG_PRINT(cpp->parser,
265 "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
266 cpp->index, offset, num_eles, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
267 psi_plist_count(cpp->tokens.exec));
268 #endif
269
270 for (i = offset; i < offset + num_eles; ++i) {
271 if (!psi_plist_get(cpp->tokens.iter, i, &ptr)) {
272 return false;
273 }
274 #if PSI_CPP_DEBUG
275 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP del_range -> ");
276 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, ptr);
277 #endif
278 psi_plist_unset(cpp->tokens.iter, i);
279 if (free_tokens && ptr) {
280 psi_token_free(&ptr);
281 }
282 }
283
284 cpp->index = i;
285 return true;
286 }
287
288 bool psi_cpp_tokiter_defined(struct psi_cpp *cpp)
289 {
290 if (psi_cpp_tokiter_valid(cpp)) {
291 struct psi_token *current = psi_cpp_tokiter_current(cpp);
292
293 return psi_cpp_defined(cpp, current);
294 }
295
296 return false;
297 }
298
299 static inline size_t psi_cpp_tokiter_expand_tokens(struct psi_cpp *cpp,
300 struct psi_token *target, struct psi_plist *tokens)
301 {
302 size_t i = 0, n = 0;
303 bool stringify = false, paste = false;
304 struct psi_token *tok;
305 struct psi_plist *exp;
306
307 if (!psi_plist_count(tokens)) {
308 return 0;
309 }
310
311 exp = psi_plist_init(NULL);
312 while (psi_plist_get(tokens, i++, &tok)) {
313 struct psi_token *new_tok;
314
315 if (tok->type == PSI_T_EOL) {
316 continue;
317 }
318 if (tok->type == PSI_T_HASH) {
319 stringify = true;
320 continue;
321 }
322 if (tok->type == PSI_T_CPP_PASTE) {
323 paste = true;
324 continue;
325 }
326
327 if (paste && psi_plist_count(exp)) {
328 struct psi_token *old_tok;
329 struct psi_parser_input *toscan;
330
331 psi_plist_pop(exp, &old_tok);
332 new_tok = psi_token_cat(NULL, 2, old_tok, tok);
333
334 /* reclassify token(s) */
335 if ((toscan = psi_parser_open_string(cpp->parser, new_tok->text->val, new_tok->text->len))) {
336 struct psi_plist *scanned;
337
338 scanned = psi_parser_scan(cpp->parser, toscan);
339 if (psi_plist_count(scanned)) {
340 size_t i = 0;
341 struct psi_token *tmp_tok;
342
343 exp = psi_plist_add_r(exp, psi_plist_count(scanned), psi_plist_eles(scanned));
344
345 /* fix meta info */
346 while (psi_plist_get(scanned, i++, &tmp_tok)) {
347 zend_string_release(tmp_tok->file);
348 tmp_tok->file = zend_string_copy(new_tok->file);
349 tmp_tok->line = new_tok->line;
350 tmp_tok->col = new_tok->col;
351 }
352
353 psi_token_free(&new_tok);
354 psi_plist_top(scanned, &new_tok);
355 } else {
356 exp = psi_plist_add(exp, &new_tok);
357 }
358 if (scanned) {
359 free(scanned);
360 }
361 psi_parser_input_free(&toscan);
362 } else {
363 exp = psi_plist_add(exp, &new_tok);
364 }
365
366 psi_token_free(&old_tok);
367 } else {
368 new_tok = psi_token_init(stringify ? PSI_T_QUOTED_STRING : tok->type,
369 tok->text->val, tok->text->len, target->col, target->line,
370 target->file ?: zend_empty_string);
371
372 exp = psi_plist_add(exp, &new_tok);
373 }
374
375 #if PSI_CPP_DEBUG
376 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand > ");
377 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, new_tok);
378 #endif
379
380 paste = false;
381 stringify = false;
382 }
383
384 bool processed = psi_cpp_process(cpp, &exp, target);
385 assert(processed);
386
387 n = psi_plist_count(exp);
388 psi_cpp_tokiter_add_range(cpp, n, psi_plist_eles(exp));
389 free(exp);
390
391 return n;
392 }
393
394 static inline void psi_cpp_tokiter_free_call_tokens(
395 struct psi_plist **arg_tokens_list, size_t arg_count, bool free_tokens)
396 {
397 size_t i;
398
399 for (i = 0; i < arg_count; ++i) {
400 if (arg_tokens_list[i]) {
401 if (free_tokens) {
402 struct psi_token *tok;
403
404 while (psi_plist_pop(arg_tokens_list[i], &tok)) {
405 psi_token_free(&tok);
406 }
407 }
408 psi_plist_free(arg_tokens_list[i]);
409 }
410 }
411 free(arg_tokens_list);
412 }
413
414 static inline struct psi_plist **psi_cpp_tokiter_read_call_tokens(
415 struct psi_cpp *cpp, size_t arg_count)
416 {
417 size_t arg_index = 0, lparens = 1, rparens = 0, start = psi_cpp_tokiter_index(cpp);
418 struct psi_plist **arg_tokens = pecalloc(arg_count, sizeof(*arg_tokens), 1);
419 struct psi_plist *free_tokens = psi_plist_init((psi_plist_dtor) psi_token_free);
420 struct psi_token *tok;
421
422 arg_tokens[0] = psi_plist_init(NULL);
423
424 /* next token must be a LPAREN for a macro call */
425 psi_cpp_tokiter_next(cpp);
426 tok = psi_cpp_tokiter_current(cpp);
427 if (!psi_cpp_tokiter_valid(cpp) || tok->type != PSI_T_LPAREN) {
428 goto fail;
429 }
430
431 /* free LPAREN on success */
432 free_tokens = psi_plist_add(free_tokens, &tok);
433
434 while (lparens > rparens) {
435 psi_cpp_tokiter_next(cpp);
436 if (!psi_cpp_tokiter_valid(cpp)) {
437 goto fail;
438 }
439 tok = psi_cpp_tokiter_current(cpp);
440
441 switch (tok->type) {
442 case PSI_T_LPAREN:
443 ++lparens;
444 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
445 break;
446 case PSI_T_RPAREN:
447 if (++rparens == lparens) {
448 /* closing RPAREN */
449 if (arg_index + 1 < arg_count) {
450 goto fail;
451 }
452 free_tokens = psi_plist_add(free_tokens, &tok);
453 } else {
454 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
455 }
456 break;
457 case PSI_T_COMMA:
458 if (1 == (lparens - rparens)) {
459 /* too many commas? */
460 if (++arg_index >= arg_count) {
461 goto fail;
462 }
463 free_tokens = psi_plist_add(free_tokens, &tok);
464 /* next arg */
465 arg_tokens[arg_index] = psi_plist_init(NULL);
466 } else {
467 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
468 }
469 break;
470 default:
471 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
472 }
473 }
474
475 /* ditch arg tokens */
476 psi_cpp_tokiter_del_range(cpp, start, psi_cpp_tokiter_index(cpp) - start + 1, false);
477 psi_plist_free(free_tokens);
478
479 return arg_tokens;
480
481 fail:
482 psi_cpp_tokiter_free_call_tokens(arg_tokens, arg_count, false);
483 return NULL;
484 }
485
486 static inline void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp *cpp,
487 struct psi_token *target, struct psi_cpp_macro_decl *macro,
488 struct psi_plist **arg_tokens_list)
489 {
490 size_t i;
491 struct psi_token *tok;
492 struct psi_plist *tokens = psi_plist_init(NULL);
493 bool prescan = true;
494
495 for (i = 0; psi_plist_get(macro->tokens, i, &tok); ++i) {
496 struct psi_plist *arg_tokens = NULL;
497
498 if (tok->type == PSI_T_HASH || tok->type == PSI_T_CPP_PASTE) {
499 prescan = false;
500 } else if (tok->type == PSI_T_NAME) {
501 size_t s;
502 struct psi_token *arg_name;
503
504 for (s = 0; psi_plist_get(macro->sig, s, &arg_name); ++s) {
505 if (zend_string_equals(arg_name->text, tok->text)) {
506 if (prescan) {
507 bool processed = psi_cpp_process(cpp,
508 &arg_tokens_list[s], target);
509
510 assert(processed);
511 }
512 arg_tokens = arg_tokens_list[s];
513 break;
514 }
515 }
516 }
517
518 if (arg_tokens) {
519 tokens = psi_plist_add_r(tokens, psi_plist_count(arg_tokens), psi_plist_eles(arg_tokens));
520 } else {
521 tokens = psi_plist_add(tokens, &tok);
522 }
523 }
524
525 psi_cpp_tokiter_expand_tokens(cpp, target, tokens);
526 psi_plist_free(tokens);
527 }
528
529 static inline bool psi_cpp_tokiter_expand_call(struct psi_cpp *cpp,
530 struct psi_token *target, struct psi_cpp_macro_decl *macro)
531 {
532 /* function-like macro
533 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
534 * # if FOO(1,2) // expands to if 1 > 2
535 */
536 size_t start = psi_cpp_tokiter_index(cpp), argc = psi_plist_count(macro->sig);
537 struct psi_plist **arg_tokens_list;
538
539
540 /* read in tokens, until we have balanced parens */
541 arg_tokens_list = psi_cpp_tokiter_read_call_tokens(cpp, argc);
542 if (!arg_tokens_list) {
543 psi_cpp_tokiter_seek(cpp, start);
544 return false;
545 }
546
547 /* insert and expand macro tokens */
548 psi_cpp_tokiter_expand_call_tokens(cpp, target, macro, arg_tokens_list);
549 psi_cpp_tokiter_free_call_tokens(arg_tokens_list, argc, true);
550
551 psi_token_free(&target);
552 ++cpp->expanded;
553 return true;
554 }
555
556 static inline void psi_cpp_tokiter_expand_builtin_tokens(struct psi_cpp *cpp,
557 struct psi_token *target, struct psi_builtin *builtin,
558 struct psi_plist **arg_tokens_list)
559 {
560 size_t s;
561 struct psi_plist *res = NULL;
562 size_t argc = psi_plist_count(builtin->decl->sig);
563
564 /* prescan */
565 for (s = 0; s < argc; ++s) {
566 bool processed = psi_cpp_process(cpp, &arg_tokens_list[s],
567 target);
568 assert(processed);
569 }
570
571 /* insert and expand macro tokens */
572 if (!builtin->func(cpp, target, arg_tokens_list, &res)) {
573 struct psi_token *zero = psi_token_init(PSI_T_NUMBER, "0", 1,
574 target->col, target->line, target->file);
575 psi_cpp_tokiter_add(cpp, zero);
576 } else if (!res) {
577 struct psi_token *one = psi_token_init(PSI_T_NUMBER, "1", 1,
578 target->col, target->line, target->file);
579 psi_cpp_tokiter_add(cpp, one);
580 } else {
581 psi_cpp_tokiter_expand_tokens(cpp, target, res);
582 psi_plist_free(res);
583 }
584 }
585
586 static inline bool psi_cpp_tokiter_expand_builtin(struct psi_cpp *cpp,
587 struct psi_token *target, struct psi_builtin *builtin)
588 {
589 size_t start = psi_cpp_tokiter_index(cpp), argc = 0;
590 struct psi_plist **arg_tokens_list = NULL;
591
592 if (builtin->decl->sig) {
593 argc = psi_plist_count(builtin->decl->sig);
594 /* read in tokens, until we have balanced parens */
595 arg_tokens_list = psi_cpp_tokiter_read_call_tokens(cpp, argc);
596 if (!arg_tokens_list) {
597 psi_cpp_tokiter_seek(cpp, start);
598 return false;
599 }
600 } else {
601 psi_cpp_tokiter_next(cpp);
602 }
603
604 psi_cpp_tokiter_expand_builtin_tokens(cpp, target, builtin, arg_tokens_list);
605 if (arg_tokens_list) {
606 psi_cpp_tokiter_free_call_tokens(arg_tokens_list, argc, true);
607 }
608
609 psi_token_free(&target);
610 ++cpp->expanded;
611 return true;
612 }
613
614
615 static inline bool psi_cpp_tokiter_expand_def(struct psi_cpp *cpp,
616 struct psi_token *target, struct psi_cpp_macro_decl *macro)
617 {
618 /* delete current token from stream */
619 psi_cpp_tokiter_del_cur(cpp, false);
620
621 if (macro->tokens) {
622 struct psi_plist *tokens = psi_plist_copy(macro->tokens,
623 (void (*)(void *)) psi_token_copy_ctor);
624 bool processed = psi_cpp_process(cpp, &tokens, target);
625
626 if (processed) {
627 /* replace with tokens from macro */
628 psi_cpp_tokiter_expand_tokens(cpp, target, tokens);
629 }
630 psi_plist_free(tokens);
631 ++cpp->expanded;
632 }
633
634 psi_token_free(&target);
635 return true;
636 }
637
638 static inline int psi_cpp_tokiter_expand_cmp(struct psi_token *t,
639 struct psi_cpp_macro_decl *m)
640 {
641 if (psi_plist_count(m->tokens) == 1) {
642 struct psi_token *r;
643
644 if (psi_plist_get(m->tokens, 0, &r) && r->text) {
645 return !zend_string_equals(r->text, t->text);
646 }
647 }
648 return -1;
649 }
650
651 static inline bool psi_cpp_tokiter_expand_decl(struct psi_cpp *cpp,
652 struct psi_token *target, struct psi_cpp_macro_decl *macro)
653 {
654 if (!macro) {
655 return false;
656 }
657
658 /* don't expand itself */
659 // if (zend_string_equals(macro->token->text, target->text)) {
660 // PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand ~ skipping self token\n");
661 // return false;
662 // }
663
664 if (macro->sig) {
665 return psi_cpp_tokiter_expand_call(cpp, target, macro);
666 } else if (psi_cpp_tokiter_expand_cmp(target, macro)) {
667 return psi_cpp_tokiter_expand_def(cpp, target, macro);
668 } else {
669 return false;
670 }
671 }
672
673 bool psi_cpp_tokiter_expand(struct psi_cpp *cpp)
674 {
675 struct psi_token *current;
676
677 if (!psi_cpp_tokiter_valid(cpp)) {
678 return false;
679 }
680
681 current = psi_cpp_tokiter_current(cpp);
682 if (!current) {
683 return false;
684 }
685 #if PSI_CPP_DEBUG
686 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand < ");
687 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, current);
688 #endif
689
690 if (psi_builtin_exists(current->text)) {
691 return psi_cpp_tokiter_expand_builtin(cpp, current,
692 psi_builtin_get(current->text));
693 } else {
694 return psi_cpp_tokiter_expand_decl(cpp, current,
695 zend_hash_find_ptr(&cpp->defs, current->text));
696 }
697 }