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