glayzzle / php-parser

:herb: NodeJS PHP Parser - extract AST or tokens
https://php-parser.glayzzle.com/
BSD 3-Clause "New" or "Revised" License
537 stars 71 forks source link

How to turn ast into PHP code #969

Open Yuri2 opened 2 years ago

Yuri2 commented 2 years ago

const parser = new engine({ // some options : parser: { extractDoc: true, php7: true, }, ast: { withPositions: true, }, });

// Load a static file (Note: this file should exist on your computer) const phpcode = fs.readFileSync("./1.php", { encoding: "utf-8" });

let ast=parser.parseCode(phpcode);


now: How to turn ast into PHP code?

dominic-p commented 2 years ago

I'm new to this project, but I believe you will want to use something like php-writer for that.

loilo commented 1 year ago

Possibly helpful: It's not exactly turning an AST into code, but if you just want to make changes to some PHP code based on the php-parser AST, I just made a library for that. 🙂

yaegassy commented 1 year ago

@loilo Hi, do you have a code example for traversing or visitors with php-parser?

loilo commented 1 year ago

@yaegassy Sure. You basically have to recursively check all properties of a node to find descendant nodes, where a node is defined by having a kind property.

Here's some code defining a walk function which you can feed a callback and an AST:

/**
 * Check whether a value resembles a php-parser AST node
 *
 * @param value The value to check
 */
function isNode(value) {
  return (
    typeof value === 'object' &&
    value !== null &&
    typeof value.kind === 'string'
  )
}

/**
 * Collect the child nodes of an AST node
 *
 * @param node The node to search for child nodes
 */
function collectChildNodes(node) {
  const childNodes = []

  // Walk all AST node properties, performing a recursive `walk`
  // on everything that looks like another AST node
  for (const key of Object.keys(node)) {
    const property = node[key]

    if (Array.isArray(property)) {
      // Step into arrays and walk their items
      for (const propertyElement of property) {
        if (isNode(propertyElement)) {
          childNodes.push(propertyElement)
        }
      }
    } else if (isNode(property)) {
      childNodes.push(property)
    }
  }

  return childNodes
}

/**
 * Walk an AST recursively
 *
 * @param callback  A function to invoke for every node
 * @param node      The tree to visit
 * @param parent    The parent of the (sub)tree node
 */
function walk(callback, node, parent = undefined) {
  const children = collectChildNodes(node)
  for (const child of children) {
    walk(callback, child, node)
  }
  callback(node, parent)
}
yaegassy commented 1 year ago

@loilo Thanks, I will refer to it. 🙇