2a8fc398398cc2a780df8b40282cfc9bf3fff01f
[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, "PSI: CPP reset -> iter.count=%zu, next.count=%zu\n",
65 psi_plist_count(cpp->tokens.iter),
66 psi_plist_count(cpp->tokens.next));
67 # if PSI_CPP_DEBUG > 1
68 PSI_DEBUG_DUMP(cpp->parser, psi_cpp_tokiter_dump, cpp);
69 # endif
70 #endif
71 cpp->index = 0;
72 cpp->expanded = 0;
73 cpp->skip = 0;
74 cpp->seen = 0;
75 cpp->level = 0;
76 cpp->do_cpp = false;
77
78 if (cpp->tokens.next) {
79 free(cpp->tokens.iter);
80 cpp->tokens.iter = cpp->tokens.next;
81 }
82 cpp->tokens.next = psi_plist_init((psi_plist_dtor) psi_token_free);
83 cpp->tokens.exec = psi_plist_init((psi_plist_dtor) psi_token_free);
84 }
85
86 bool psi_cpp_tokiter_seek(struct psi_cpp *cpp, size_t index)
87 {
88 if (index < psi_plist_count(cpp->tokens.iter)) {
89 cpp->index = index;
90 return true;
91 }
92 return false;
93 }
94
95 struct psi_token *psi_cpp_tokiter_current(struct psi_cpp *cpp)
96 {
97 struct psi_token *current = NULL;
98 bool found = psi_plist_get(cpp->tokens.iter, cpp->index, &current);
99
100 assert(found);
101
102 return current;
103 }
104
105 size_t psi_cpp_tokiter_index(struct psi_cpp *cpp)
106 {
107 return cpp->index;
108 }
109
110 bool psi_cpp_tokiter_add_cur(struct psi_cpp *cpp)
111 {
112 struct psi_token *cur = NULL;
113
114 if (psi_plist_get(cpp->tokens.iter, cpp->index, &cur)) {
115 if (cpp->do_cpp) {
116 cpp->tokens.exec = psi_plist_add(cpp->tokens.exec, &cur);
117 } else {
118 cpp->tokens.next = psi_plist_add(cpp->tokens.next, &cur);
119 }
120
121 #if PSI_CPP_DEBUG
122 PSI_DEBUG_PRINT(cpp->parser,
123 "PSI: CPP add_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
124 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
125 psi_plist_count(cpp->tokens.exec));
126 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, cur);
127 #endif
128
129 return true;
130 }
131
132 return false;
133 }
134
135 bool psi_cpp_tokiter_add(struct psi_cpp *cpp, struct psi_token *tok)
136 {
137 if (cpp->do_cpp) {
138 cpp->tokens.exec = psi_plist_add(cpp->tokens.exec, &tok);
139 } else {
140 cpp->tokens.next = psi_plist_add(cpp->tokens.next, &tok);
141 }
142
143 #if PSI_CPP_DEBUG
144 PSI_DEBUG_PRINT(cpp->parser,
145 "PSI: CPP add -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
146 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
147 psi_plist_count(cpp->tokens.exec));
148 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, tok);
149 #endif
150
151 return true;
152 }
153
154
155 bool psi_cpp_tokiter_add_range(struct psi_cpp *cpp, size_t num_eles, void **eles)
156 {
157 struct psi_plist *tokens;
158
159 if (!num_eles) {
160 return true;
161 }
162
163 if (cpp->do_cpp) {
164 cpp->tokens.exec = psi_plist_add_r(cpp->tokens.exec, num_eles, eles);
165 } else {
166 cpp->tokens.next = psi_plist_add_r(cpp->tokens.next, num_eles, eles);
167 }
168
169 #if PSI_CPP_DEBUG
170 PSI_DEBUG_PRINT(cpp->parser,
171 "PSI: CPP add_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
172 cpp->index, num_eles, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
173 psi_plist_count(cpp->tokens.exec));
174 #endif
175
176 return true;
177 }
178
179
180 void psi_cpp_tokiter_next(struct psi_cpp *cpp)
181 {
182 #if 0 && PSI_CPP_DEBUG
183 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP next -> index=%zu -> index=%zu\n",
184 cpp->index, cpp->index+1);
185 #endif
186 ++cpp->index;
187 }
188
189 bool psi_cpp_tokiter_valid(struct psi_cpp *cpp)
190 {
191 #if 0 && PSI_CPP_DEBUG
192 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP valid -> index=%zu -> %d\n",
193 cpp->index, cpp->index < psi_plist_count(cpp->tokens.iter));
194 #endif
195 return cpp->index < psi_plist_count(cpp->tokens.iter);
196 }
197
198 bool psi_cpp_tokiter_del_prev(struct psi_cpp *cpp, bool free_token)
199 {
200 struct psi_token *cur = NULL;
201
202 #if PSI_CPP_DEBUG
203 PSI_DEBUG_PRINT(cpp->parser,
204 "PSI: CPP del_prev -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
205 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
206 psi_plist_count(cpp->tokens.exec));
207 #endif
208
209 if (cpp->do_cpp) {
210 if (!psi_plist_pop(cpp->tokens.exec, NULL)) {
211 return false;
212 }
213 } else if (!psi_plist_pop(cpp->tokens.next, NULL)) {
214 return false;
215 }
216
217 if (!psi_plist_get(cpp->tokens.iter, cpp->index - 1, &cur)) {
218 return false;
219 }
220 psi_plist_unset(cpp->tokens.iter, cpp->index - 1);
221 if (free_token && cur) {
222 psi_token_free(&cur);
223 }
224 return true;
225 }
226
227 bool psi_cpp_tokiter_del_cur(struct psi_cpp *cpp, bool free_token)
228 {
229 struct psi_token *cur = NULL;
230
231 #if PSI_CPP_DEBUG
232 PSI_DEBUG_PRINT(cpp->parser,
233 "PSI: CPP del_cur -> index=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu ",
234 cpp->index, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
235 psi_plist_count(cpp->tokens.exec));
236 #endif
237
238 if (psi_plist_get(cpp->tokens.iter, cpp->index, &cur)) {
239 #if PSI_CPP_DEBUG
240 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, cur);
241 #endif
242 psi_plist_unset(cpp->tokens.iter, cpp->index);
243 if (free_token && cur) {
244 psi_token_free(&cur);
245 }
246 ++cpp->index;
247 return true;
248 }
249
250 return false;
251 }
252
253 bool psi_cpp_tokiter_del_range(struct psi_cpp *cpp, size_t offset, size_t num_eles, bool free_tokens)
254 {
255 struct psi_token *ptr;
256 size_t i;
257
258 #if PSI_CPP_DEBUG
259 PSI_DEBUG_PRINT(cpp->parser,
260 "PSI: CPP del_range -> index=%zu, offset=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
261 cpp->index, offset, num_eles, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
262 psi_plist_count(cpp->tokens.exec));
263 #endif
264
265 for (i = offset; i < offset + num_eles; ++i) {
266 if (!psi_plist_get(cpp->tokens.iter, i, &ptr)) {
267 return false;
268 }
269 #if PSI_CPP_DEBUG
270 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP del_range -> ");
271 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, ptr);
272 #endif
273 psi_plist_unset(cpp->tokens.iter, i);
274 if (free_tokens && ptr) {
275 psi_token_free(&ptr);
276 }
277 }
278
279 cpp->index = i;
280 return true;
281 }
282
283 bool psi_cpp_tokiter_ins_range(struct psi_cpp *cpp, size_t num_eles, void **eles)
284 {
285 struct psi_plist *tokens;
286
287 if (!num_eles) {
288 return true;
289 }
290
291 cpp->tokens.iter = psi_plist_ins_r(cpp->tokens.iter, cpp->index, num_eles, eles);
292
293 #if PSI_CPP_DEBUG
294 PSI_DEBUG_PRINT(cpp->parser,
295 "PSI: CPP ins_range -> index=%zu, num_eles=%zu, iter.count=%zu, next.count=%zu, exec.count=%zu\n",
296 cpp->index, num_eles, psi_plist_count(cpp->tokens.iter), psi_plist_count(cpp->tokens.next),
297 psi_plist_count(cpp->tokens.exec));
298 #endif
299
300 return true;
301 }
302
303 bool psi_cpp_tokiter_defined(struct psi_cpp *cpp)
304 {
305 if (psi_cpp_tokiter_valid(cpp)) {
306 struct psi_token *current = psi_cpp_tokiter_current(cpp);
307
308 return psi_cpp_defined(cpp, current);
309 }
310
311 return false;
312 }
313
314 static inline size_t psi_cpp_tokiter_expand_tokens(struct psi_cpp *cpp,
315 struct psi_token *target, struct psi_plist *tokens)
316 {
317 size_t i = 0, n = 0;
318 bool stringify = false, paste = false;
319 struct psi_token *tok;
320 struct psi_plist *exp;
321
322 if (!psi_plist_count(tokens)) {
323 return 0;
324 }
325
326 exp = psi_plist_init(NULL);
327 while (psi_plist_get(tokens, i++, &tok)) {
328 struct psi_token *new_tok;
329
330 if (tok->type == PSI_T_EOL) {
331 continue;
332 }
333 if (tok->type == PSI_T_HASH) {
334 stringify = true;
335 continue;
336 }
337 if (tok->type == PSI_T_CPP_PASTE) {
338 paste = true;
339 continue;
340 }
341
342 if (paste && psi_plist_count(exp)) {
343 struct psi_token *old_tok;
344 struct psi_parser_input *toscan;
345
346 psi_plist_pop(exp, &old_tok);
347 new_tok = psi_token_cat(NULL, 2, old_tok, tok);
348
349 /* reclassify token(s) */
350 if ((toscan = psi_parser_open_string(cpp->parser, new_tok->text->val, new_tok->text->len))) {
351 struct psi_plist *scanned;
352
353 scanned = psi_parser_scan(cpp->parser, toscan);
354 if (psi_plist_count(scanned)) {
355 size_t i = 0;
356 struct psi_token *tmp_tok;
357
358 exp = psi_plist_add_r(exp, psi_plist_count(scanned), psi_plist_eles(scanned));
359
360 /* fix meta info */
361 while (psi_plist_get(scanned, i++, &tmp_tok)) {
362 zend_string_release(tmp_tok->file);
363 tmp_tok->file = zend_string_copy(new_tok->file);
364 tmp_tok->line = new_tok->line;
365 tmp_tok->col = new_tok->col;
366 }
367
368 psi_token_free(&new_tok);
369 psi_plist_top(scanned, &new_tok);
370 } else {
371 exp = psi_plist_add(exp, &new_tok);
372 }
373 if (scanned) {
374 free(scanned);
375 }
376 psi_parser_input_free(&toscan);
377 } else {
378 exp = psi_plist_add(exp, &new_tok);
379 }
380
381 psi_token_free(&old_tok);
382 } else {
383 new_tok = psi_token_init(stringify ? PSI_T_QUOTED_STRING : tok->type,
384 tok->text->val, tok->text->len, target->col, target->line,
385 target->file ?: zend_empty_string);
386
387 exp = psi_plist_add(exp, &new_tok);
388 }
389
390 #if PSI_CPP_DEBUG
391 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand > ");
392 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, new_tok);
393 #endif
394
395 paste = false;
396 stringify = false;
397 }
398
399 bool processed = psi_cpp_process(cpp, &exp, target);
400 assert(processed);
401
402 n = psi_plist_count(exp);
403 psi_cpp_tokiter_add_range(cpp, n, psi_plist_eles(exp));
404 free(exp);
405
406 return n;
407 }
408
409 static inline void psi_cpp_tokiter_free_call_tokens(
410 struct psi_plist **arg_tokens_list, size_t arg_count, bool free_tokens)
411 {
412 size_t i;
413
414 for (i = 0; i < arg_count; ++i) {
415 if (arg_tokens_list[i]) {
416 if (free_tokens) {
417 struct psi_token *tok;
418
419 while (psi_plist_pop(arg_tokens_list[i], &tok)) {
420 psi_token_free(&tok);
421 }
422 }
423 psi_plist_free(arg_tokens_list[i]);
424 }
425 }
426 free(arg_tokens_list);
427 }
428
429 static inline struct psi_plist **psi_cpp_tokiter_read_call_tokens(
430 struct psi_cpp *cpp, size_t arg_count)
431 {
432 size_t arg_index = 0, lparens = 1, rparens = 0, start = psi_cpp_tokiter_index(cpp);
433 struct psi_plist **arg_tokens = pecalloc(arg_count, sizeof(*arg_tokens), 1);
434 struct psi_plist *free_tokens = psi_plist_init((psi_plist_dtor) psi_token_free);
435 struct psi_token *tok;
436
437 arg_tokens[0] = psi_plist_init(NULL);
438
439 /* next token must be a LPAREN for a macro call */
440 psi_cpp_tokiter_next(cpp);
441 tok = psi_cpp_tokiter_current(cpp);
442 if (!psi_cpp_tokiter_valid(cpp) || tok->type != PSI_T_LPAREN) {
443 goto fail;
444 }
445
446 /* free LPAREN on success */
447 free_tokens = psi_plist_add(free_tokens, &tok);
448
449 while (lparens > rparens) {
450 psi_cpp_tokiter_next(cpp);
451 if (!psi_cpp_tokiter_valid(cpp)) {
452 goto fail;
453 }
454 tok = psi_cpp_tokiter_current(cpp);
455
456 switch (tok->type) {
457 case PSI_T_LPAREN:
458 ++lparens;
459 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
460 break;
461 case PSI_T_RPAREN:
462 if (++rparens == lparens) {
463 /* closing RPAREN */
464 if (arg_index + 1 < arg_count) {
465 goto fail;
466 }
467 free_tokens = psi_plist_add(free_tokens, &tok);
468 } else {
469 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
470 }
471 break;
472 case PSI_T_COMMA:
473 if (1 == (lparens - rparens)) {
474 /* too many commas? */
475 if (++arg_index >= arg_count) {
476 goto fail;
477 }
478 free_tokens = psi_plist_add(free_tokens, &tok);
479 /* next arg */
480 arg_tokens[arg_index] = psi_plist_init(NULL);
481 } else {
482 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
483 }
484 break;
485 default:
486 arg_tokens[arg_index] = psi_plist_add(arg_tokens[arg_index], &tok);
487 }
488 }
489
490 /* ditch arg tokens */
491 psi_cpp_tokiter_del_range(cpp, start, psi_cpp_tokiter_index(cpp) - start + 1, false);
492 psi_plist_free(free_tokens);
493
494 return arg_tokens;
495
496 fail:
497 psi_cpp_tokiter_free_call_tokens(arg_tokens, arg_count, false);
498 return NULL;
499 }
500
501 static inline void psi_cpp_tokiter_expand_call_tokens(struct psi_cpp *cpp,
502 struct psi_token *target, struct psi_cpp_macro_decl *macro,
503 struct psi_plist **arg_tokens_list)
504 {
505 size_t i;
506 struct psi_token *tok;
507 struct psi_plist *tokens = psi_plist_init(NULL);
508 bool prescan = true;
509
510 for (i = 0; psi_plist_get(macro->tokens, i, &tok); ++i) {
511 struct psi_plist *arg_tokens = NULL;
512
513 if (tok->type == PSI_T_HASH || tok->type == PSI_T_CPP_PASTE) {
514 prescan = false;
515 } else if (tok->type == PSI_T_NAME) {
516 size_t s;
517 struct psi_token *arg_name;
518
519 for (s = 0; psi_plist_get(macro->sig, s, &arg_name); ++s) {
520 if (zend_string_equals(arg_name->text, tok->text)) {
521 if (prescan) {
522 bool processed = psi_cpp_process(cpp,
523 &arg_tokens_list[s], target);
524
525 assert(processed);
526 }
527 arg_tokens = arg_tokens_list[s];
528 break;
529 }
530 }
531 }
532
533 if (arg_tokens) {
534 tokens = psi_plist_add_r(tokens, psi_plist_count(arg_tokens), psi_plist_eles(arg_tokens));
535 } else {
536 tokens = psi_plist_add(tokens, &tok);
537 }
538 }
539
540 psi_cpp_tokiter_expand_tokens(cpp, target, tokens);
541 psi_plist_free(tokens);
542 }
543
544 static inline bool psi_cpp_tokiter_expand_call(struct psi_cpp *cpp,
545 struct psi_token *target, struct psi_cpp_macro_decl *macro)
546 {
547 /* function-like macro
548 * #define FOO(a,b) a>b // macro->sig == {a, b}, macro->tokens = {a, >, b}
549 * # if FOO(1,2) // expands to if 1 > 2
550 */
551 size_t start = psi_cpp_tokiter_index(cpp), argc = psi_plist_count(macro->sig);
552 struct psi_plist **arg_tokens_list;
553
554
555 /* read in tokens, until we have balanced parens */
556 arg_tokens_list = psi_cpp_tokiter_read_call_tokens(cpp, argc);
557 if (!arg_tokens_list) {
558 psi_cpp_tokiter_seek(cpp, start);
559 return false;
560 }
561
562 /* insert and expand macro tokens */
563 psi_cpp_tokiter_expand_call_tokens(cpp, target, macro, arg_tokens_list);
564 psi_cpp_tokiter_free_call_tokens(arg_tokens_list, argc, true);
565
566 psi_token_free(&target);
567 ++cpp->expanded;
568 return true;
569 }
570
571 static inline void psi_cpp_tokiter_expand_builtin_tokens(struct psi_cpp *cpp,
572 struct psi_token *target, struct psi_builtin *builtin,
573 struct psi_plist **arg_tokens_list)
574 {
575 size_t s;
576 struct psi_plist *res = NULL;
577 size_t argc = psi_plist_count(builtin->decl->sig);
578
579 /* prescan */
580 for (s = 0; s < argc; ++s) {
581 bool processed = psi_cpp_process(cpp, &arg_tokens_list[s],
582 target);
583 assert(processed);
584 }
585
586 /* insert and expand macro tokens */
587 if (!builtin->func(cpp, target, arg_tokens_list, &res)) {
588 struct psi_token *zero = psi_token_init(PSI_T_NUMBER, "0", 1,
589 target->col, target->line, target->file);
590 psi_cpp_tokiter_add(cpp, zero);
591 } else if (!res) {
592 struct psi_token *one = psi_token_init(PSI_T_NUMBER, "1", 1,
593 target->col, target->line, target->file);
594 psi_cpp_tokiter_add(cpp, one);
595 } else {
596 psi_cpp_tokiter_expand_tokens(cpp, target, res);
597 psi_plist_free(res);
598 }
599 }
600
601 static inline bool psi_cpp_tokiter_expand_builtin(struct psi_cpp *cpp,
602 struct psi_token *target, struct psi_builtin *builtin)
603 {
604 size_t start = psi_cpp_tokiter_index(cpp), argc = 0;
605 struct psi_plist **arg_tokens_list = NULL;
606
607 if (builtin->decl->sig) {
608 argc = psi_plist_count(builtin->decl->sig);
609 /* read in tokens, until we have balanced parens */
610 arg_tokens_list = psi_cpp_tokiter_read_call_tokens(cpp, argc);
611 if (!arg_tokens_list) {
612 psi_cpp_tokiter_seek(cpp, start);
613 return false;
614 }
615 } else {
616 psi_cpp_tokiter_next(cpp);
617 }
618
619 psi_cpp_tokiter_expand_builtin_tokens(cpp, target, builtin, arg_tokens_list);
620 if (arg_tokens_list) {
621 psi_cpp_tokiter_free_call_tokens(arg_tokens_list, argc, true);
622 }
623
624 psi_token_free(&target);
625 ++cpp->expanded;
626 return true;
627 }
628
629
630 static inline bool psi_cpp_tokiter_expand_def(struct psi_cpp *cpp,
631 struct psi_token *target, struct psi_cpp_macro_decl *macro)
632 {
633 /* delete current token from stream */
634 psi_cpp_tokiter_del_cur(cpp, false);
635
636 if (macro->tokens) {
637 struct psi_plist *tokens = psi_plist_copy(macro->tokens,
638 (void (*)(void *)) psi_token_copy_ctor);
639 bool processed = psi_cpp_process(cpp, &tokens, target);
640
641 if (processed) {
642 /* replace with tokens from macro */
643 psi_cpp_tokiter_expand_tokens(cpp, target, tokens);
644 }
645 ++cpp->expanded;
646 }
647
648 psi_token_free(&target);
649 return true;
650 }
651
652 static inline int psi_cpp_tokiter_expand_cmp(struct psi_token *t,
653 struct psi_cpp_macro_decl *m)
654 {
655 if (psi_plist_count(m->tokens) == 1) {
656 struct psi_token *r;
657
658 if (psi_plist_get(m->tokens, 0, &r) && r->text) {
659 return !zend_string_equals(r->text, t->text);
660 }
661 }
662 return -1;
663 }
664
665 static inline bool psi_cpp_tokiter_expand_decl(struct psi_cpp *cpp,
666 struct psi_token *target, struct psi_cpp_macro_decl *macro)
667 {
668 if (!macro) {
669 return false;
670 }
671
672 /* don't expand itself */
673 // if (zend_string_equals(macro->token->text, target->text)) {
674 // PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand ~ skipping self token\n");
675 // return false;
676 // }
677
678 if (macro->sig) {
679 return psi_cpp_tokiter_expand_call(cpp, target, macro);
680 } else if (psi_cpp_tokiter_expand_cmp(target, macro)) {
681 return psi_cpp_tokiter_expand_def(cpp, target, macro);
682 } else {
683 return false;
684 }
685 }
686
687 bool psi_cpp_tokiter_expand(struct psi_cpp *cpp)
688 {
689 struct psi_token *current;
690
691 if (!psi_cpp_tokiter_valid(cpp)) {
692 return false;
693 }
694
695 current = psi_cpp_tokiter_current(cpp);
696 if (!current) {
697 return false;
698 }
699 #if PSI_CPP_DEBUG
700 PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP expand < ");
701 PSI_DEBUG_DUMP(cpp->parser, psi_token_dump, current);
702 #endif
703
704 if (psi_builtin_exists(current->text)) {
705 return psi_cpp_tokiter_expand_builtin(cpp, current,
706 psi_builtin_get(current->text));
707 } else {
708 return psi_cpp_tokiter_expand_decl(cpp, current,
709 zend_hash_find_ptr(&cpp->defs, current->text));
710 }
711 }