/** Dumps abstract syntax tree */ function ast_dump($ast, int $options = 0) : string { if ($ast instanceof ast\Node) { $result = ast\get_kind_name($ast->kind); if ($options & AST_DUMP_LINENOS) { $result .= " @ {$ast->lineno}"; if (isset($ast->endLineno)) { $result .= "-{$ast->endLineno}"; } } if (ast\kind_uses_flags($ast->kind)) { $result .= "\n flags: " . format_flags($ast->kind, $ast->flags); } if (isset($ast->name)) { $result .= "\n name: {$ast->name}"; } if (isset($ast->docComment)) { $result .= "\n docComment: {$ast->docComment}"; } foreach ($ast->children as $i => $child) { $result .= "\n {$i}: " . str_replace("\n", "\n ", ast_dump($child, $options)); } return $result; } else { if ($ast === null) { return 'null'; } else { if (is_string($ast)) { return "\"{$ast}\""; } else { return (string) $ast; } } } }
function ast_dump($ast, $children = true) { if ($ast instanceof \ast\Node) { $result = \ast\get_kind_name($ast->kind); $result .= " @ {$ast->lineno}"; if (isset($ast->endLineno)) { $result .= "-{$ast->endLineno}"; } if (\ast\kind_uses_flags($ast->kind)) { $result .= "\n flags: {$ast->flags}"; } if (isset($ast->name)) { $result .= "\n name: {$ast->name}"; } if (isset($ast->docComment)) { $result .= "\n docComment: {$ast->docComment}"; } if ($children) { foreach ($ast->children as $i => $child) { $result .= "\n {$i}: " . str_replace("\n", "\n ", ast_dump($child)); } } return $result; } else { if ($ast === null) { return 'null'; } else { if (is_string($ast)) { return "\"{$ast}\""; } else { return (string) $ast; } } } }
/** * Exports a syntax tree into two CSV files as * described in https://github.com/jexp/batch-import/ * * @param $ast The AST to export. * @param $nodeline Indicates the nodeline of the parent node. This * is necessary when $ast is a plain value, since * we cannot get back from a plain value to the * parent node to learn the line number. * @param $childnum Indicates that this node is the $childnum'th * child of its parent node (starting at 0). * @param $funcid If the AST to be exported is part of a function, * the node id of that function. * * @return The root node index of the exported AST (i.e., the value * of $this->nodecount at the point in time where this * function was called.) */ public function export($ast, $nodeline = 0, $childnum = 0, $funcid = null) : int { // (1) if $ast is an AST node, print info and recurse // An instance of ast\Node declares: // $kind (integer, name can be retrieved using ast\get_kind_name()) // $flags (integer, corresponding to a set of flags for the current node) // $lineno (integer, starting line number) // $children (array of child nodes) // Additionally, an instance of the subclass ast\Node\Decl declares: // $endLineno (integer, end line number of the declaration) // $name (string, the name of the declared function/class) // $docComment (string, the preceding doc comment) if ($ast instanceof ast\Node) { $nodetype = ast\get_kind_name($ast->kind); $nodeline = $ast->lineno; $nodeflags = ""; if (ast\kind_uses_flags($ast->kind)) { $nodeflags = $this->csv_format_flags($ast->kind, $ast->flags); } // for decl nodes: if (isset($ast->endLineno)) { $nodeendline = $ast->endLineno; } if (isset($ast->name)) { $nodename = $ast->name; } if (isset($ast->docComment)) { $nodedoccomment = $this->quote_and_escape($ast->docComment); } // store node, export all children and store the relationships $rootnode = $this->store_node($nodetype, $nodeflags, $nodeline, null, $childnum, $funcid, $nodeendline, $nodename, $nodedoccomment); // If this node is a function/method/closure declaration, set $funcid. // Note that in particular, the decl node *itself* does not have $funcid set to its own id; // this is intentional. The *declaration* of a function/method/closure itself is part of the // control flow of the outer scope: e.g., a closure declaration is part of the control flow // of the function it is declared in, or a function/method declaration is part of the control flow // of the pseudo-function representing the top-level code it is declared in. if ($ast->kind === ast\AST_FUNC_DECL || $ast->kind === ast\AST_METHOD || $ast->kind === ast\AST_CLOSURE) { $funcid = $rootnode; } foreach ($ast->children as $i => $child) { $childnode = $this->export($child, $nodeline, $i, $funcid); $this->store_rel($rootnode, $childnode, "PARENT_OF"); } } else { if (is_string($ast)) { $nodetype = gettype($ast); // should be string $rootnode = $this->store_node($nodetype, null, $nodeline, $this->quote_and_escape($ast), $childnum, $funcid); } else { if ($ast === null) { $nodetype = gettype($ast); // should be the string "NULL" $rootnode = $this->store_node($nodetype, null, $nodeline, null, $childnum, $funcid); } else { $nodetype = gettype($ast); $nodecode = (string) $ast; $rootnode = $this->store_node($nodetype, null, $nodeline, $nodecode, $childnum, $funcid); } } } return $rootnode; }