glayzzle / php-parser

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

Modifying the AST #1006

Open deakjahn opened 2 years ago

deakjahn commented 2 years ago

Was the AST ever intended to be modified externally? I've just written an AST->PHP writer (yes, I'm aware of php-writer, it's very old and dated, I needed the full support up to the latest PHP 8.1). It's in TypeScript, actually, not JavaScript. I didn't yet have time to test it at all but I'm more than willing to share it as soon as it's reasonably error free.

However, this leads to the current question. I'd need to modify the AST so that I can export it in full or partly back to PHP. Was php-parser ever intended to support this scenario? The various AST classes don't seem to have constructors and there seems to be no easy way to build or modify an AST tree (except for assembling PHP strings and parsing them eval-style but that's not what would really be needed).

deakjahn commented 2 years ago

Addendum: I could actually create some nodes like this:

let newExpression: php.Bin = {
  kind: 'bin',
  left: node.left,
  right: node.right,
  type: '+',
  setTrailingComments: (docs: any) => { },
  destroy: () => { },
  includeToken: (parser: any) => { },
  loc: null,
  trailingComments: null,
  leadingComments: null,
};

but it just doesn't feel right. But I have to override those functions in the middle because the compiler doesn't accept a partial class, leaving out some fields.

deakjahn commented 2 years ago

I finally came up with this solution and it works but adding real constructors would be very welcome down the line:

import * as php from "php-parser";

export function binary(left: php.Expression, right: php.Expression, operator: string): php.Bin {
  return {
    kind: 'bin',
    left: left,
    right: right,
    type: operator,
  } as php.Bin;
}
czosel commented 2 years ago

Hi @deakjahn, thanks for bringing this up. As far as I can tell, a public API for this use-case has not been a focus yet. If I'm not mistaken, the functions in the src/ast directory are node constructors, though. The parser itself creates them like this: https://github.com/glayzzle/php-parser/blob/main/src/ast.js#L393 - you're looking for something typed though, right?

deakjahn commented 2 years ago

Yes, they look like constructors, but there's no way to pass them the required parameters. So, I need to create one for each and every one of the node types, of course.

The ATS->PHP writer is practically done, I listed the small problems I found along the route in the other issue.