xref: /php-ast/util.php (revision 260678d4)
1<?php declare(strict_types=1);
2
3use ast\flags;
4
5const AST_DUMP_LINENOS = 1;
6const AST_DUMP_EXCLUDE_DOC_COMMENT = 2;
7
8function get_flag_info() : array {
9    static $info;
10    if ($info !== null) {
11        return $info;
12    }
13
14    foreach (ast\get_metadata() as $data) {
15        if (empty($data->flags)) {
16            continue;
17        }
18
19        $flagMap = [];
20        foreach ($data->flags as $fullName) {
21            $shortName = substr($fullName, strrpos($fullName, '\\') + 1);
22            $flagMap[constant($fullName)] = $shortName;
23        }
24
25        $info[(int) $data->flagsCombinable][$data->kind] = $flagMap;
26    }
27
28    return $info;
29}
30function is_combinable_flag(int $kind) : bool {
31    return isset(get_flag_info()[1][$kind]);
32}
33
34function format_flags(int $kind, int $flags) : string {
35    list($exclusive, $combinable) = get_flag_info();
36    if (isset($exclusive[$kind])) {
37        $flagInfo = $exclusive[$kind];
38        if (isset($flagInfo[$flags])) {
39            return "{$flagInfo[$flags]} ($flags)";
40        }
41    } else if (isset($combinable[$kind])) {
42        $flagInfo = $combinable[$kind];
43        $names = [];
44        foreach ($flagInfo as $flag => $name) {
45            if ($flags & $flag) {
46                $names[] = $name;
47            }
48        }
49        if (!empty($names)) {
50            return implode(" | ", $names) . " ($flags)";
51        }
52    }
53    return (string) $flags;
54}
55
56/** Dumps abstract syntax tree */
57function ast_dump($ast, int $options = 0) : string {
58    if ($ast instanceof ast\Node) {
59        $result = ast\get_kind_name($ast->kind);
60
61        if ($options & AST_DUMP_LINENOS) {
62            $result .= " @ $ast->lineno";
63            if (isset($ast->endLineno)) {
64                $result .= "-$ast->endLineno";
65            }
66        }
67
68        if ((ast\kind_uses_flags($ast->kind) && !is_combinable_flag($ast->kind)) || $ast->flags != 0) {
69            $result .= "\n    flags: " . format_flags($ast->kind, $ast->flags);
70        }
71        foreach ($ast->children as $i => $child) {
72            if (($options & AST_DUMP_EXCLUDE_DOC_COMMENT) && $i === 'docComment') {
73                continue;
74            }
75            $result .= "\n    $i: " . str_replace("\n", "\n    ", ast_dump($child, $options));
76        }
77        return $result;
78    } else if ($ast === null) {
79        return 'null';
80    } else if (is_string($ast)) {
81        return "\"$ast\"";
82    } else {
83        return (string) $ast;
84    }
85}
86