php-parser-py 1.2.6__py3-none-win_amd64.whl → 2.0.3__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- php_parser_py/__init__.py +5 -1
- php_parser_py/_graph/_ast.py +29 -5
- php_parser_py/_mapping/_build.py +16 -5
- php_parser_py/_mapping/_serialize.py +4 -1
- php_parser_py/_parser.py +36 -10
- php_parser_py/_printer.py +17 -0
- php_parser_py/_resources/parse.php +6 -4
- php_parser_py/_resources/print.php +15 -6
- php_parser_py/_resources/transport.php +19 -1
- php_parser_py/_runtime/_runner.py +16 -5
- php_parser_py/_types.py +5 -0
- php_parser_py/_version.py +51 -0
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/METADATA +9 -7
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/RECORD +19 -19
- php_parser_py/_resources/php +0 -0
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/WHEEL +0 -0
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/licenses/LICENSE +0 -0
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/licenses/PHP-LICENSE +0 -0
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/licenses/PHP-Parser-LICENSE +0 -0
- {php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/licenses/Zend-Engine-LICENSE +0 -0
php_parser_py/__init__.py
CHANGED
|
@@ -6,13 +6,16 @@ and manipulation of PHP code.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
from importlib.metadata import version as _distribution_version
|
|
10
|
+
|
|
11
|
+
__version__ = _distribution_version("php-parser-py")
|
|
10
12
|
__all__ = [
|
|
11
13
|
"AST",
|
|
12
14
|
"Edge",
|
|
13
15
|
"Modifier",
|
|
14
16
|
"Node",
|
|
15
17
|
"Parser",
|
|
18
|
+
"PHPVersion",
|
|
16
19
|
"Printer",
|
|
17
20
|
"StandardPrinter",
|
|
18
21
|
"ExtendedPrinter",
|
|
@@ -31,3 +34,4 @@ from ._graph import AST, Edge, Modifier, Node
|
|
|
31
34
|
from ._parser import Parser, parse_code, parse_file, parse_project
|
|
32
35
|
from ._printer import ExtendedPrinter, Printer, StandardPrinter
|
|
33
36
|
from ._types import PrintMode, PrintRequest
|
|
37
|
+
from ._version import PHPVersion
|
php_parser_py/_graph/_ast.py
CHANGED
|
@@ -8,6 +8,7 @@ from cpg2py import AbcGraphQuerier, Storage
|
|
|
8
8
|
|
|
9
9
|
from .._exceptions import NodeNotInFileError
|
|
10
10
|
from .._types import PARENT_OF_EDGE, PROJECT_ROOT_ID
|
|
11
|
+
from .._version import PHPVersion
|
|
11
12
|
from ._edge import Edge
|
|
12
13
|
from ._node import Node
|
|
13
14
|
from ._node_id import NodeId
|
|
@@ -31,17 +32,27 @@ class AST(AbcGraphQuerier[Node, Edge]):
|
|
|
31
32
|
|
|
32
33
|
Attributes:
|
|
33
34
|
_root_node_id: ID of the root project node (always "project").
|
|
35
|
+
_target_php: Target PHP version the parser parsed the source under;
|
|
36
|
+
None when no parser produced this graph.
|
|
34
37
|
"""
|
|
35
38
|
|
|
36
|
-
def __init__(
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
storage: Storage,
|
|
42
|
+
root_node_id: str = PROJECT_ROOT_ID,
|
|
43
|
+
target_php: PHPVersion | None = None,
|
|
44
|
+
) -> None:
|
|
37
45
|
"""Initialize AST with populated storage.
|
|
38
46
|
|
|
39
47
|
Args:
|
|
40
48
|
storage: cpg2py Storage containing AST nodes and edges.
|
|
41
49
|
root_node_id: ID of the root node. Defaults to "project".
|
|
50
|
+
target_php: Target PHP version of the parse that produced the
|
|
51
|
+
graph. Default None marks the provenance unknown.
|
|
42
52
|
"""
|
|
43
53
|
super().__init__(storage)
|
|
44
54
|
self._root_node_id = root_node_id
|
|
55
|
+
self._target_php = target_php
|
|
45
56
|
|
|
46
57
|
@property
|
|
47
58
|
def storage(self) -> Storage:
|
|
@@ -68,13 +79,24 @@ class AST(AbcGraphQuerier[Node, Edge]):
|
|
|
68
79
|
"""Return the root node ID of this AST."""
|
|
69
80
|
return self._root_node_id
|
|
70
81
|
|
|
82
|
+
@property
|
|
83
|
+
def target_php(self) -> PHPVersion | None:
|
|
84
|
+
"""Return the target PHP version the source was parsed under.
|
|
85
|
+
|
|
86
|
+
Parse provenance, not a PHP node field: serialization and printing
|
|
87
|
+
never emit it as part of the PHP-Parser JSON. Always known on a graph
|
|
88
|
+
a parser produced; None on a graph built without a parse.
|
|
89
|
+
"""
|
|
90
|
+
return self._target_php
|
|
91
|
+
|
|
71
92
|
def copy(self) -> AST:
|
|
72
93
|
"""Return a new AST backed by a deep copy of this graph.
|
|
73
94
|
|
|
74
95
|
Node IDs, the edge set, and all node/edge properties are duplicated
|
|
75
|
-
verbatim, preserving the ``{file_hash}_{counter}`` ID namespace
|
|
76
|
-
root node ID. The returned AST shares no
|
|
77
|
-
mutating either graph leaves the other
|
|
96
|
+
verbatim, preserving the ``{file_hash}_{counter}`` ID namespace, the
|
|
97
|
+
root node ID and the target PHP version. The returned AST shares no
|
|
98
|
+
mutable state with this one: mutating either graph leaves the other
|
|
99
|
+
unchanged.
|
|
78
100
|
|
|
79
101
|
Returns:
|
|
80
102
|
A new AST whose storage is an independent copy of this graph.
|
|
@@ -82,7 +104,9 @@ class AST(AbcGraphQuerier[Node, Edge]):
|
|
|
82
104
|
storage = Storage()
|
|
83
105
|
self._copy_nodes_into(storage)
|
|
84
106
|
self._copy_edges_into(storage)
|
|
85
|
-
return AST(
|
|
107
|
+
return AST(
|
|
108
|
+
storage, root_node_id=self._root_node_id, target_php=self._target_php
|
|
109
|
+
)
|
|
86
110
|
|
|
87
111
|
def _copy_nodes_into(self, storage: Storage) -> None:
|
|
88
112
|
"""Duplicate every node and its properties into ``storage``."""
|
php_parser_py/_mapping/_build.py
CHANGED
|
@@ -12,6 +12,7 @@ from cpg2py import Storage
|
|
|
12
12
|
|
|
13
13
|
from .._graph import AST, Modifier, NodeId
|
|
14
14
|
from .._types import PROJECT_ROOT_ID, FileRecord, ProjectLayout
|
|
15
|
+
from .._version import PHPVersion
|
|
15
16
|
from ._contract import (
|
|
16
17
|
ATTRIBUTE_KEYS_PROPERTY,
|
|
17
18
|
LIST_LENGTHS_PROPERTY,
|
|
@@ -26,7 +27,11 @@ _FILE_END_DEFAULTS: dict[str, int] = {"endLine": 1, "endFilePos": 0, "endTokenPo
|
|
|
26
27
|
_CODE_ROOT_ID = "__code_root__"
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def build(
|
|
30
|
+
def build(
|
|
31
|
+
json_trees: list[dict[str, object]],
|
|
32
|
+
layout: ProjectLayout,
|
|
33
|
+
target_php: PHPVersion,
|
|
34
|
+
) -> AST:
|
|
30
35
|
"""Populate a fresh ``AST`` from PHP-Parser JSON trees.
|
|
31
36
|
|
|
32
37
|
Forward entry of the mapping package; inverse of ``serialize``.
|
|
@@ -34,6 +39,8 @@ def build(json_trees: list[dict[str, object]], layout: ProjectLayout) -> AST:
|
|
|
34
39
|
Args:
|
|
35
40
|
json_trees: Normalized list of root node dicts (code-only mode).
|
|
36
41
|
layout: Project/file structure and per-file hashes.
|
|
42
|
+
target_php: Target PHP version the trees were parsed under; recorded
|
|
43
|
+
as the AST's provenance, never as a node field.
|
|
37
44
|
|
|
38
45
|
Returns:
|
|
39
46
|
AST with project -> file -> statement hierarchy, or a flat statement
|
|
@@ -42,7 +49,7 @@ def build(json_trees: list[dict[str, object]], layout: ProjectLayout) -> AST:
|
|
|
42
49
|
Raises:
|
|
43
50
|
ValueError: From ``Modifier.add_node`` on a duplicate ID.
|
|
44
51
|
"""
|
|
45
|
-
builder = _Builder()
|
|
52
|
+
builder = _Builder(target_php)
|
|
46
53
|
if layout.project_path is None:
|
|
47
54
|
return builder.build_code(json_trees)
|
|
48
55
|
return builder.build_project(layout)
|
|
@@ -52,18 +59,22 @@ class _Builder:
|
|
|
52
59
|
"""Stateful JSON->graph builder with a per-file ID allocator.
|
|
53
60
|
|
|
54
61
|
Attributes:
|
|
62
|
+
_target_php: Target PHP version stamped on the built AST.
|
|
55
63
|
_next_index: Stateful per-file ID allocator counter.
|
|
56
64
|
_prefix: Current file-hash prefix; empty string for code-only parsing.
|
|
57
65
|
"""
|
|
58
66
|
|
|
59
|
-
def __init__(self) -> None:
|
|
67
|
+
def __init__(self, target_php: PHPVersion) -> None:
|
|
60
68
|
"""Initialize a builder with a fresh allocator state."""
|
|
69
|
+
self._target_php = target_php
|
|
61
70
|
self._next_index = 1
|
|
62
71
|
self._prefix = ""
|
|
63
72
|
|
|
64
73
|
def build_code(self, json_trees: list[dict[str, object]]) -> AST:
|
|
65
74
|
"""Build statements anchored under a synthetic code-root node."""
|
|
66
|
-
modifier = Modifier(
|
|
75
|
+
modifier = Modifier(
|
|
76
|
+
AST(Storage(), root_node_id=_CODE_ROOT_ID, target_php=self._target_php)
|
|
77
|
+
)
|
|
67
78
|
# A real anchor node makes top-level membership explicit: serialize
|
|
68
79
|
# exports the anchor's stmts edges. Inferring roots from missing
|
|
69
80
|
# parent edges would promote subtrees orphaned by remove_node.
|
|
@@ -78,7 +89,7 @@ class _Builder:
|
|
|
78
89
|
project_path = layout.project_path
|
|
79
90
|
if project_path is None:
|
|
80
91
|
raise ValueError("ProjectLayout.project_path is required for build")
|
|
81
|
-
modifier = Modifier(AST(Storage()))
|
|
92
|
+
modifier = Modifier(AST(Storage(), target_php=self._target_php))
|
|
82
93
|
modifier.add_node(
|
|
83
94
|
PROJECT_ROOT_ID,
|
|
84
95
|
"Project",
|
|
@@ -139,6 +139,10 @@ def _node_result(ast: AST, nid: str) -> dict[str, Any]:
|
|
|
139
139
|
result: dict[str, Any] = {"nodeType": node.node_type}
|
|
140
140
|
result["attributes"] = {k: props[k] for k in attr_keys}
|
|
141
141
|
_add_scalar_props(result, props, attr_keys)
|
|
142
|
+
# A recorded attributes bundle marks an original JSON node; only
|
|
143
|
+
# nodes created without that record need declaration defaults.
|
|
144
|
+
if ATTRIBUTE_KEYS_PROPERTY not in props:
|
|
145
|
+
_add_default_attrs(result, node.node_type)
|
|
142
146
|
return result
|
|
143
147
|
|
|
144
148
|
|
|
@@ -183,7 +187,6 @@ def _reconstruct_children(
|
|
|
183
187
|
else:
|
|
184
188
|
arrays.setdefault(field_name, {})[index] = child_json
|
|
185
189
|
_fill_arrays(result, arrays, node.all_properties.get(LIST_LENGTHS_PROPERTY, {}))
|
|
186
|
-
_add_default_attrs(result, node.node_type)
|
|
187
190
|
return descend
|
|
188
191
|
|
|
189
192
|
|
php_parser_py/_parser.py
CHANGED
|
@@ -15,6 +15,7 @@ from ._graph import AST, Node
|
|
|
15
15
|
from ._mapping import build, statement_ids
|
|
16
16
|
from ._runtime import Runner
|
|
17
17
|
from ._types import FileRecord, ProjectLayout
|
|
18
|
+
from ._version import PHPVersion
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
20
21
|
|
|
@@ -67,21 +68,35 @@ class Parser:
|
|
|
67
68
|
|
|
68
69
|
Attributes:
|
|
69
70
|
_runner: Runner instance for PHP-Parser invocation.
|
|
71
|
+
_target_php: PHP version every parse targets.
|
|
70
72
|
"""
|
|
71
73
|
|
|
72
74
|
def __init__(
|
|
73
75
|
self,
|
|
74
76
|
php: PHP | None = None,
|
|
75
77
|
ini_settings: Mapping[str, str] | None = None,
|
|
78
|
+
*,
|
|
79
|
+
target_php: PHPVersion,
|
|
76
80
|
) -> None:
|
|
77
81
|
"""Initialize Parser with Runner.
|
|
78
82
|
|
|
79
83
|
Args:
|
|
80
84
|
php: Optional PHP instance. If not provided, uses bundled PHP.
|
|
85
|
+
It runs PHP-Parser and is independent of ``target_php``.
|
|
81
86
|
ini_settings: Optional PHP ini overrides forwarded to the Runner.
|
|
82
87
|
Default None inherits the binary's environment.
|
|
88
|
+
target_php: PHP version the parsed source targets; selects the
|
|
89
|
+
PHP-Parser grammar and is recorded on every AST produced.
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
TypeError: If ``target_php`` is not a ``PHPVersion``.
|
|
83
93
|
"""
|
|
94
|
+
if not isinstance(target_php, PHPVersion):
|
|
95
|
+
raise TypeError(
|
|
96
|
+
f"target_php must be a PHPVersion, got {type(target_php).__name__}"
|
|
97
|
+
)
|
|
84
98
|
self._runner = Runner(php=php, ini_settings=ini_settings)
|
|
99
|
+
self._target_php = target_php
|
|
85
100
|
|
|
86
101
|
def parse_code(self, code: str) -> list[Node]:
|
|
87
102
|
"""Parse PHP code string into a list of top-level statement nodes.
|
|
@@ -100,8 +115,9 @@ class Parser:
|
|
|
100
115
|
ParseError: If code has syntax errors.
|
|
101
116
|
RunnerError: If PHP execution fails.
|
|
102
117
|
"""
|
|
103
|
-
node_list = self._runner.parse(code)
|
|
104
|
-
|
|
118
|
+
node_list = self._runner.parse(code, self._target_php)
|
|
119
|
+
layout = ProjectLayout(project_path=None)
|
|
120
|
+
ast = build(node_list, layout, self._target_php)
|
|
105
121
|
return [ast.node(nid) for nid in statement_ids(ast, ast.project_root_id)]
|
|
106
122
|
|
|
107
123
|
def parse_file(self, path: str, encoding: str | None = None) -> AST:
|
|
@@ -136,7 +152,7 @@ class Parser:
|
|
|
136
152
|
|
|
137
153
|
record = self._read_file(file_path, encoding)
|
|
138
154
|
layout = ProjectLayout(project_path=file_path.parent, files=[record])
|
|
139
|
-
return build([], layout)
|
|
155
|
+
return build([], layout, self._target_php)
|
|
140
156
|
|
|
141
157
|
def parse_project(
|
|
142
158
|
self,
|
|
@@ -185,7 +201,7 @@ class Parser:
|
|
|
185
201
|
|
|
186
202
|
records = self._read_files(php_files, encoding)
|
|
187
203
|
layout = ProjectLayout(project_path=project_path_obj, files=records)
|
|
188
|
-
return build([], layout)
|
|
204
|
+
return build([], layout, self._target_php)
|
|
189
205
|
|
|
190
206
|
# -- Internal helpers --
|
|
191
207
|
|
|
@@ -219,11 +235,11 @@ class Parser:
|
|
|
219
235
|
code = path.read_bytes().decode("utf-8", "surrogateescape")
|
|
220
236
|
else:
|
|
221
237
|
code = path.read_bytes().decode(encoding)
|
|
222
|
-
statements = self._runner.parse(code)
|
|
238
|
+
statements = self._runner.parse(code, self._target_php)
|
|
223
239
|
return FileRecord(path=path, file_hash=_file_id(path), statements=statements)
|
|
224
240
|
|
|
225
241
|
|
|
226
|
-
def parse_code(code: str) -> list[Node]:
|
|
242
|
+
def parse_code(code: str, *, target_php: PHPVersion) -> list[Node]:
|
|
227
243
|
"""Parse PHP code string into a list of top-level statement nodes.
|
|
228
244
|
|
|
229
245
|
Does not create file nodes; statements are anchored under a synthetic
|
|
@@ -231,18 +247,22 @@ def parse_code(code: str) -> list[Node]:
|
|
|
231
247
|
|
|
232
248
|
Args:
|
|
233
249
|
code: PHP source code string.
|
|
250
|
+
target_php: PHP version the source targets.
|
|
234
251
|
|
|
235
252
|
Returns:
|
|
236
253
|
List of Node instances representing top-level statements.
|
|
237
254
|
|
|
238
255
|
Raises:
|
|
239
256
|
ParseError: If PHP-Parser reports syntax error.
|
|
257
|
+
TypeError: If ``target_php`` is not a ``PHPVersion``.
|
|
240
258
|
"""
|
|
241
|
-
parser = Parser()
|
|
259
|
+
parser = Parser(target_php=target_php)
|
|
242
260
|
return parser.parse_code(code)
|
|
243
261
|
|
|
244
262
|
|
|
245
|
-
def parse_file(
|
|
263
|
+
def parse_file(
|
|
264
|
+
path: str, encoding: str | None = None, *, target_php: PHPVersion
|
|
265
|
+
) -> AST:
|
|
246
266
|
"""Read and parse a single PHP file into an AST.
|
|
247
267
|
|
|
248
268
|
Creates a project node and a file node. The file node contains
|
|
@@ -253,6 +273,7 @@ def parse_file(path: str, encoding: str | None = None) -> AST:
|
|
|
253
273
|
encoding: Optional Python codec name declaring the file's byte
|
|
254
274
|
encoding; the file is transcoded before parsing. Default None
|
|
255
275
|
passes source bytes through unchanged.
|
|
276
|
+
target_php: PHP version the source targets; recorded on the AST.
|
|
256
277
|
|
|
257
278
|
Returns:
|
|
258
279
|
AST instance with project -> file -> statements hierarchy.
|
|
@@ -264,8 +285,9 @@ def parse_file(path: str, encoding: str | None = None) -> AST:
|
|
|
264
285
|
LookupError: If ``encoding`` names no Python codec.
|
|
265
286
|
UnicodeDecodeError: If the file's bytes do not decode under the
|
|
266
287
|
declared ``encoding``.
|
|
288
|
+
TypeError: If ``target_php`` is not a ``PHPVersion``.
|
|
267
289
|
"""
|
|
268
|
-
parser = Parser()
|
|
290
|
+
parser = Parser(target_php=target_php)
|
|
269
291
|
return parser.parse_file(path, encoding=encoding)
|
|
270
292
|
|
|
271
293
|
|
|
@@ -274,6 +296,8 @@ def parse_project(
|
|
|
274
296
|
file_filter: Callable[[Path], bool] | None = None,
|
|
275
297
|
ini_settings: Mapping[str, str] | None = None,
|
|
276
298
|
encoding: str | None = None,
|
|
299
|
+
*,
|
|
300
|
+
target_php: PHPVersion,
|
|
277
301
|
) -> AST:
|
|
278
302
|
"""Parse all PHP files in a project directory into an AST.
|
|
279
303
|
|
|
@@ -293,6 +317,7 @@ def parse_project(
|
|
|
293
317
|
encoding; each file is transcoded before parsing. A file that
|
|
294
318
|
does not decode is skipped with a warning. Default None passes
|
|
295
319
|
source bytes through unchanged.
|
|
320
|
+
target_php: PHP version every file targets; recorded on the AST.
|
|
296
321
|
|
|
297
322
|
Returns:
|
|
298
323
|
AST instance with project -> files -> statements hierarchy.
|
|
@@ -302,10 +327,11 @@ def parse_project(
|
|
|
302
327
|
ValueError: If project_path is not a directory, or if two files
|
|
303
328
|
hash to the same file ID.
|
|
304
329
|
LookupError: If ``encoding`` names no Python codec.
|
|
330
|
+
TypeError: If ``target_php`` is not a ``PHPVersion``.
|
|
305
331
|
"""
|
|
306
332
|
if file_filter is None:
|
|
307
333
|
file_filter = _default_file_filter
|
|
308
|
-
parser = Parser(ini_settings=ini_settings)
|
|
334
|
+
parser = Parser(ini_settings=ini_settings, target_php=target_php)
|
|
309
335
|
return parser.parse_project(
|
|
310
336
|
project_path, file_filter=file_filter, encoding=encoding
|
|
311
337
|
)
|
php_parser_py/_printer.py
CHANGED
|
@@ -12,6 +12,7 @@ from ._graph import AST, Node
|
|
|
12
12
|
from ._mapping import serialize
|
|
13
13
|
from ._runtime import Runner
|
|
14
14
|
from ._types import PrintMode, PrintRequest
|
|
15
|
+
from ._version import PHPVersion
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
@@ -35,6 +36,7 @@ class Printer(Protocol):
|
|
|
35
36
|
|
|
36
37
|
Raises:
|
|
37
38
|
RunnerError: On PHP-Parser failure.
|
|
39
|
+
ValueError: If the AST has no known parse target version.
|
|
38
40
|
"""
|
|
39
41
|
|
|
40
42
|
def print_preserving(
|
|
@@ -52,6 +54,7 @@ class Printer(Protocol):
|
|
|
52
54
|
Raises:
|
|
53
55
|
RunnerError: On PHP-Parser failure.
|
|
54
56
|
KeyError: If an AST file key is absent from origin_source.
|
|
57
|
+
ValueError: If the AST has no known parse target version.
|
|
55
58
|
"""
|
|
56
59
|
|
|
57
60
|
|
|
@@ -76,12 +79,14 @@ class _PrinterBase:
|
|
|
76
79
|
|
|
77
80
|
def print(self, ast: AST) -> dict[str, str]:
|
|
78
81
|
"""Full-rewrite print of every file in the AST."""
|
|
82
|
+
target = self._target_of(ast)
|
|
79
83
|
return {
|
|
80
84
|
key: self._runner.print(
|
|
81
85
|
PrintRequest(
|
|
82
86
|
php_class=self._php_class,
|
|
83
87
|
mode=PrintMode.FULL_REWRITE,
|
|
84
88
|
stmts_json=json_str,
|
|
89
|
+
target_php=target,
|
|
85
90
|
)
|
|
86
91
|
)
|
|
87
92
|
for key, json_str in self._file_statements(ast).items()
|
|
@@ -91,6 +96,7 @@ class _PrinterBase:
|
|
|
91
96
|
self, ast: AST, origin_source: Mapping[str, str]
|
|
92
97
|
) -> dict[str, str]:
|
|
93
98
|
"""Format-preserving print; reprint only changed or new nodes."""
|
|
99
|
+
target = self._target_of(ast)
|
|
94
100
|
result: dict[str, str] = {}
|
|
95
101
|
for key, json_str in self._file_statements(ast).items():
|
|
96
102
|
if key not in origin_source:
|
|
@@ -100,11 +106,22 @@ class _PrinterBase:
|
|
|
100
106
|
php_class=self._php_class,
|
|
101
107
|
mode=PrintMode.FORMAT_PRESERVING,
|
|
102
108
|
stmts_json=json_str,
|
|
109
|
+
target_php=target,
|
|
103
110
|
orig_source=origin_source[key],
|
|
104
111
|
)
|
|
105
112
|
)
|
|
106
113
|
return result
|
|
107
114
|
|
|
115
|
+
@staticmethod
|
|
116
|
+
def _target_of(ast: AST) -> PHPVersion:
|
|
117
|
+
"""Return the AST's parse target, rejecting unknown provenance."""
|
|
118
|
+
if ast.target_php is None:
|
|
119
|
+
raise ValueError(
|
|
120
|
+
"Cannot print an AST of unknown parse provenance: "
|
|
121
|
+
"target_php is None."
|
|
122
|
+
)
|
|
123
|
+
return ast.target_php
|
|
124
|
+
|
|
108
125
|
@staticmethod
|
|
109
126
|
def _file_statements(ast: AST) -> dict[str, str]:
|
|
110
127
|
"""Map each file key to its statement JSON.
|
|
@@ -5,10 +5,12 @@ declare(strict_types=1);
|
|
|
5
5
|
/**
|
|
6
6
|
* Parse PHP source into a JSON AST.
|
|
7
7
|
*
|
|
8
|
-
* Reads one JSON object from stdin:
|
|
8
|
+
* Reads one JSON object from stdin:
|
|
9
|
+
* {"phar_path": string, "code": string, "target_major": int, "target_minor": int}.
|
|
9
10
|
* The code field is base64: JSON cannot carry the raw non-UTF-8 bytes a
|
|
10
|
-
* PHP source file may legally contain.
|
|
11
|
-
*
|
|
11
|
+
* PHP source file may legally contain. The target version selects the
|
|
12
|
+
* PHP-Parser grammar the code is accepted under. Emits {"errors": [...]}
|
|
13
|
+
* with exit 0 on syntax errors, the serialized statements on success, or
|
|
12
14
|
* {"error": ...} with exit 1 on any other failure.
|
|
13
15
|
*/
|
|
14
16
|
|
|
@@ -90,9 +92,9 @@ if ($code === false) {
|
|
|
90
92
|
exit(2);
|
|
91
93
|
}
|
|
92
94
|
$errorHandler = new Collecting();
|
|
93
|
-
$parser = (new ParserFactory())->createForNewestSupportedVersion();
|
|
94
95
|
|
|
95
96
|
try {
|
|
97
|
+
$parser = (new ParserFactory())->createForVersion(pppy_target_version($payload));
|
|
96
98
|
$stmts = $parser->parse($code, $errorHandler);
|
|
97
99
|
if ($errorHandler->hasErrors()) {
|
|
98
100
|
$errors = array_map(fn($e) => [
|
|
@@ -12,11 +12,15 @@ declare(strict_types=1);
|
|
|
12
12
|
* "printer_class": string, // FQCN to instantiate (read as data)
|
|
13
13
|
* "mode": string, // "full_rewrite" | "format_preserving"
|
|
14
14
|
* "stmts": string, // JSON of the (modified) statements
|
|
15
|
+
* "target_major": int, // target PHP version, read as data
|
|
16
|
+
* "target_minor": int,
|
|
15
17
|
* "orig_source": string // original source (format_preserving only)
|
|
16
18
|
* }
|
|
17
19
|
*
|
|
18
20
|
* The printer class name is read from the payload and instantiated via a
|
|
19
|
-
* variable class expression; it is never spliced into source.
|
|
21
|
+
* variable class expression; it is never spliced into source. The target
|
|
22
|
+
* version sets the printer's phpVersion option and the version the original
|
|
23
|
+
* source is reparsed under. Emits the
|
|
20
24
|
* generated PHP on success, or {"error": ...} with exit 1 on failure.
|
|
21
25
|
*/
|
|
22
26
|
|
|
@@ -44,13 +48,14 @@ try {
|
|
|
44
48
|
|
|
45
49
|
// Normalize the FQCN and instantiate by name (class name travels as data).
|
|
46
50
|
$printerClass = '\\' . ltrim($payload['printer_class'], '\\');
|
|
47
|
-
$
|
|
51
|
+
$version = pppy_target_version($payload);
|
|
52
|
+
$printer = new $printerClass(['phpVersion' => $version]);
|
|
48
53
|
|
|
49
54
|
// Output is base64-encoded so non-UTF-8 source bytes survive the text
|
|
50
55
|
// stdout channel back to the caller (mirrors the base64 orig_source input).
|
|
51
56
|
if ($payload['mode'] === 'format_preserving') {
|
|
52
57
|
$origSource = base64_decode($payload['orig_source']);
|
|
53
|
-
echo base64_encode(render_format_preserving($printer, $stmts, $origSource));
|
|
58
|
+
echo base64_encode(render_format_preserving($printer, $stmts, $origSource, $version));
|
|
54
59
|
} else {
|
|
55
60
|
echo base64_encode($printer->prettyPrintFile($stmts));
|
|
56
61
|
}
|
|
@@ -93,9 +98,13 @@ function pppy_decode_stmts(string $stmtsJson): array
|
|
|
93
98
|
* Re-parse the original source, link unchanged decoded nodes to their original
|
|
94
99
|
* objects by token position, then reprint preserving original formatting.
|
|
95
100
|
*/
|
|
96
|
-
function render_format_preserving(
|
|
97
|
-
|
|
98
|
-
$
|
|
101
|
+
function render_format_preserving(
|
|
102
|
+
$printer,
|
|
103
|
+
array $stmts,
|
|
104
|
+
string $origSource,
|
|
105
|
+
PhpParser\PhpVersion $version
|
|
106
|
+
): string {
|
|
107
|
+
$parser = (new ParserFactory())->createForVersion($version);
|
|
99
108
|
$origStmts = $parser->parse($origSource);
|
|
100
109
|
$origTokens = $parser->getTokens();
|
|
101
110
|
|
|
@@ -10,7 +10,8 @@ declare(strict_types=1);
|
|
|
10
10
|
* value that cannot travel as strict JSON is wrapped in a NUL-prefixed
|
|
11
11
|
* marker string; the Python side (_transport.py) applies the same
|
|
12
12
|
* codec. parse.php encodes before emitting; print.php decodes after
|
|
13
|
-
* JsonDecoder.
|
|
13
|
+
* JsonDecoder. Both scripts also read the target PHP version from the
|
|
14
|
+
* payload through pppy_target_version.
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
// json_encode/json_decode default to a 512-level nesting cap, rejecting
|
|
@@ -193,3 +194,20 @@ function pppy_decode_comment(PhpParser\Comment $comment)
|
|
|
193
194
|
$comment->getEndTokenPos()
|
|
194
195
|
);
|
|
195
196
|
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Read the target PHP version a payload carries as two integer fields,
|
|
200
|
+
* target_major and target_minor. Python validates the series before it
|
|
201
|
+
* sends the payload, so a missing or mistyped field is a channel fault.
|
|
202
|
+
*/
|
|
203
|
+
function pppy_target_version(array $payload): PhpParser\PhpVersion
|
|
204
|
+
{
|
|
205
|
+
$major = $payload['target_major'] ?? null;
|
|
206
|
+
$minor = $payload['target_minor'] ?? null;
|
|
207
|
+
if (!is_int($major) || !is_int($minor)) {
|
|
208
|
+
throw new RuntimeException(
|
|
209
|
+
'payload target_major and target_minor must be integers'
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return PhpParser\PhpVersion::fromComponents($major, $minor);
|
|
213
|
+
}
|
|
@@ -13,6 +13,7 @@ from static_php_py import PHP, ExecutionError, ExecutionResult
|
|
|
13
13
|
from .._exceptions import ParseError, RunnerError
|
|
14
14
|
from .._transport import decode_values
|
|
15
15
|
from .._types import PrintMode, PrintRequest
|
|
16
|
+
from .._version import PHPVersion
|
|
16
17
|
from ._binary import resolve_php
|
|
17
18
|
from ._bundle import ensure_php_parser_extracted, get_resources_path
|
|
18
19
|
|
|
@@ -21,6 +22,11 @@ from ._bundle import ensure_php_parser_extracted, get_resources_path
|
|
|
21
22
|
_BASE_INI = {"display_errors": "stderr"}
|
|
22
23
|
|
|
23
24
|
|
|
25
|
+
def _target_fields(target_php: PHPVersion) -> dict[str, int]:
|
|
26
|
+
# The target travels as two integers read as data by the PHP scripts.
|
|
27
|
+
return {"target_major": target_php.major, "target_minor": target_php.minor}
|
|
28
|
+
|
|
29
|
+
|
|
24
30
|
def _failure_message(result: ExecutionResult) -> str:
|
|
25
31
|
# Assemble the RunnerError message carrying the process's full output.
|
|
26
32
|
message = f"PHP execution failed with exit code {result.return_code}"
|
|
@@ -114,11 +120,12 @@ class Runner:
|
|
|
114
120
|
)
|
|
115
121
|
return result.stdout
|
|
116
122
|
|
|
117
|
-
def parse(self, code: str) -> list[dict[str, Any]]:
|
|
123
|
+
def parse(self, code: str, target_php: PHPVersion) -> list[dict[str, Any]]:
|
|
118
124
|
"""Invoke PHP-Parser parse + JsonSerializer.
|
|
119
125
|
|
|
120
126
|
Args:
|
|
121
127
|
code: PHP source code to parse.
|
|
128
|
+
target_php: PHP version whose grammar the parser accepts.
|
|
122
129
|
|
|
123
130
|
Returns:
|
|
124
131
|
Parsed statements as a list of PHP-Parser JSON node dicts.
|
|
@@ -127,7 +134,7 @@ class Runner:
|
|
|
127
134
|
ParseError: If PHP-Parser reports syntax error.
|
|
128
135
|
RunnerError: If PHP execution fails or emits a malformed payload.
|
|
129
136
|
"""
|
|
130
|
-
stdin = self._build_parse_stdin(code)
|
|
137
|
+
stdin = self._build_parse_stdin(code, target_php)
|
|
131
138
|
|
|
132
139
|
try:
|
|
133
140
|
output = self._execute_script_file("parse.php", stdin)
|
|
@@ -186,7 +193,8 @@ class Runner:
|
|
|
186
193
|
"""Render and run the print script for one file.
|
|
187
194
|
|
|
188
195
|
Args:
|
|
189
|
-
request: Print inputs (printer class, mode, statements,
|
|
196
|
+
request: Print inputs (printer class, mode, statements, target
|
|
197
|
+
version, origin).
|
|
190
198
|
|
|
191
199
|
Returns:
|
|
192
200
|
Generated PHP source code.
|
|
@@ -200,7 +208,7 @@ class Runner:
|
|
|
200
208
|
# the text stdout channel; recover the exact bytes back to a str.
|
|
201
209
|
return base64.b64decode(output).decode("utf-8", "surrogateescape")
|
|
202
210
|
|
|
203
|
-
def _build_parse_stdin(self, code: str) -> str:
|
|
211
|
+
def _build_parse_stdin(self, code: str, target_php: PHPVersion) -> str:
|
|
204
212
|
"""Pack the parse inputs into a single JSON stdin payload.
|
|
205
213
|
|
|
206
214
|
The code field travels as base64: PHP source may legally hold raw
|
|
@@ -211,6 +219,7 @@ class Runner:
|
|
|
211
219
|
payload = {
|
|
212
220
|
"phar_path": str(self._phar_path()),
|
|
213
221
|
"code": base64.b64encode(raw).decode("ascii"),
|
|
222
|
+
**_target_fields(target_php),
|
|
214
223
|
}
|
|
215
224
|
return json.dumps(payload)
|
|
216
225
|
|
|
@@ -219,13 +228,15 @@ class Runner:
|
|
|
219
228
|
|
|
220
229
|
The printer class name travels as the ``printer_class`` field; it is
|
|
221
230
|
read as data by ``print.php`` and never interpolated into PHP source.
|
|
231
|
+
The target version travels as two integers.
|
|
222
232
|
"""
|
|
223
|
-
payload: dict[str, str] = {
|
|
233
|
+
payload: dict[str, str | int] = {
|
|
224
234
|
"phar_path": str(self._phar_path()),
|
|
225
235
|
"extended_path": str(get_resources_path() / "ExtendedPrinter.php"),
|
|
226
236
|
"printer_class": request.php_class,
|
|
227
237
|
"mode": request.mode.value,
|
|
228
238
|
"stmts": request.stmts_json,
|
|
239
|
+
**_target_fields(request.target_php),
|
|
229
240
|
}
|
|
230
241
|
if request.mode is PrintMode.FORMAT_PRESERVING:
|
|
231
242
|
# Original source may hold non-UTF-8 bytes (e.g. Latin-1 literals).
|
php_parser_py/_types.py
CHANGED
|
@@ -6,6 +6,8 @@ from dataclasses import dataclass, field
|
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
from ._version import PHPVersion
|
|
10
|
+
|
|
9
11
|
# The AST hierarchy edge type; fixed by the JSON<->graph mapping contract.
|
|
10
12
|
PARENT_OF_EDGE = "PARENT_OF"
|
|
11
13
|
|
|
@@ -36,6 +38,8 @@ class PrintRequest:
|
|
|
36
38
|
php_class: Fully-qualified printer class to instantiate.
|
|
37
39
|
mode: Entry-point selector.
|
|
38
40
|
stmts_json: JSON of the (modified) statements.
|
|
41
|
+
target_php: PHP version the printer options and the original-source
|
|
42
|
+
reparse follow; the parse provenance of the printed AST.
|
|
39
43
|
orig_source: Original PHP source, re-parsed in-process to recover
|
|
40
44
|
original objects and tokens. Required when ``mode`` is
|
|
41
45
|
FORMAT_PRESERVING; None otherwise.
|
|
@@ -48,6 +52,7 @@ class PrintRequest:
|
|
|
48
52
|
php_class: str
|
|
49
53
|
mode: PrintMode
|
|
50
54
|
stmts_json: str
|
|
55
|
+
target_php: PHPVersion
|
|
51
56
|
orig_source: str | None = None
|
|
52
57
|
|
|
53
58
|
def __post_init__(self) -> None:
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""PHP target version: the (major, minor) series a parse or print targets."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
# Newest minor accepted per supported major series. Project policy, not an
|
|
8
|
+
# upstream boundary: PHP-Parser takes arbitrary components and treats the
|
|
9
|
+
# target as best-effort.
|
|
10
|
+
_NEWEST_MINOR_BY_MAJOR = {7: 4, 8: 5}
|
|
11
|
+
_SUPPORTED_SERIES = " and ".join(
|
|
12
|
+
f"{major}.0-{major}.{newest}" for major, newest in _NEWEST_MINOR_BY_MAJOR.items()
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _require_int(name: str, value: object) -> None:
|
|
17
|
+
# bool is an int subtype but never a version component.
|
|
18
|
+
if isinstance(value, bool) or not isinstance(value, int):
|
|
19
|
+
raise TypeError(
|
|
20
|
+
f"PHPVersion {name} must be an int, got {type(value).__name__}: {value!r}"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class PHPVersion:
|
|
26
|
+
"""A target PHP series: major and minor version, without a patch level.
|
|
27
|
+
|
|
28
|
+
Accepted series are 7.0 to 7.4 and 8.0 to 8.5. The patch level is not
|
|
29
|
+
part of the target: PHP-Parser distinguishes series only.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
major: PHP major version, 7 or 8.
|
|
33
|
+
minor: PHP minor version within the major series.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
TypeError: If a component is not an ``int`` (``bool`` included).
|
|
37
|
+
ValueError: If the pair is not an accepted series.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
major: int
|
|
41
|
+
minor: int
|
|
42
|
+
|
|
43
|
+
def __post_init__(self) -> None:
|
|
44
|
+
_require_int("major", self.major)
|
|
45
|
+
_require_int("minor", self.minor)
|
|
46
|
+
newest = _NEWEST_MINOR_BY_MAJOR.get(self.major)
|
|
47
|
+
if newest is None or not 0 <= self.minor <= newest:
|
|
48
|
+
raise ValueError(
|
|
49
|
+
f"Unsupported target PHP version {self.major}.{self.minor}; "
|
|
50
|
+
f"supported series are {_SUPPORTED_SERIES}"
|
|
51
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: php-parser-py
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: Python wrapper for PHP-Parser using cpg2py
|
|
5
5
|
License-Expression: GPL-2.0-only
|
|
6
6
|
License-File: LICENSE
|
|
@@ -37,10 +37,10 @@ Requires Python >= 3.10.
|
|
|
37
37
|
## Usage
|
|
38
38
|
|
|
39
39
|
```python
|
|
40
|
-
from php_parser_py import parse_file, Modifier
|
|
40
|
+
from php_parser_py import parse_file, Modifier, PHPVersion
|
|
41
41
|
|
|
42
|
-
# Parse
|
|
43
|
-
ast = parse_file("src/User.php")
|
|
42
|
+
# Parse (the target PHP version is required)
|
|
43
|
+
ast = parse_file("src/User.php", target_php=PHPVersion(8, 3))
|
|
44
44
|
|
|
45
45
|
# Query
|
|
46
46
|
functions = ast.nodes(lambda n: n.node_type == "Stmt_Function")
|
|
@@ -58,9 +58,11 @@ modified = modifier.ast
|
|
|
58
58
|
|
|
59
59
|
| Function / Class | Signature | Description |
|
|
60
60
|
|-----------------|-----------|-------------|
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
61
|
+
| `PHPVersion` | `(major: int, minor: int)` | Target PHP version, 7.0 to 7.4 and 8.0 to 8.5 |
|
|
62
|
+
| `parse_code` | `(code: str, *, target_php: PHPVersion) -> list[Node]` | Parse PHP string into statement nodes |
|
|
63
|
+
| `parse_file` | `(path: str, *, target_php: PHPVersion) -> AST` | Parse single file with project/file structure |
|
|
64
|
+
| `parse_project` | `(project_path: str, file_filter?, *, target_php: PHPVersion) -> AST` | Parse all PHP files in a directory |
|
|
65
|
+
| `AST.target_php` | `-> PHPVersion \| None` | Version the graph was parsed under (read-only) |
|
|
64
66
|
| `Modifier` | `(ast: AST)` | Copy-on-write graph mutation; read result from `modifier.ast` |
|
|
65
67
|
| `AST.nodes` | `(predicate?) -> Generator[Node]` | Iterate/filter nodes |
|
|
66
68
|
| `AST.succ` | `(node) -> Generator[Node]` | Get children |
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
php_parser_py/__init__.py,sha256=
|
|
1
|
+
php_parser_py/__init__.py,sha256=BkOXmqdi1q3YG3MZljPP9Aa43VoMUtc8gdyVyFVta-Q,968
|
|
2
2
|
php_parser_py/_exceptions.py,sha256=lWGngHWCrOEGL3ILwPMFnU0mlha6e5U6SYxz7n1oLY8,1824
|
|
3
3
|
php_parser_py/_graph/__init__.py,sha256=GAOtPcGGMQCbif86vdQgk9GgTkOJPee6_NA-wewN3g8,396
|
|
4
|
-
php_parser_py/_graph/_ast.py,sha256=
|
|
4
|
+
php_parser_py/_graph/_ast.py,sha256=HHlqm7-Et1T2aMRtILTrlXElPGo_15FB4DS--x_NEyg,8856
|
|
5
5
|
php_parser_py/_graph/_edge.py,sha256=WzimZf6WB6inHACrFHsQOyFgrhdzyfGhv8UboEPOQjE,2995
|
|
6
6
|
php_parser_py/_graph/_modifier.py,sha256=VLJruL0260_VbXoXYWZdGmrXO-oXgiWIWS6v3MRmsaM,4829
|
|
7
7
|
php_parser_py/_graph/_node.py,sha256=hA4eRQx4PWAakHkehC5SbpS12FvtlGDf2UnT4RuFZQ4,8276
|
|
8
8
|
php_parser_py/_graph/_node_id.py,sha256=YvtpkOO1DiT-yHyOED0pSsDqzuYFUiNRGtGvCNKvArY,1597
|
|
9
9
|
php_parser_py/_mapping/__init__.py,sha256=XzQuME5jXu_GBiwFpXZyhM9EevRJaNyrH_vAu7jFNos,469
|
|
10
|
-
php_parser_py/_mapping/_build.py,sha256=
|
|
10
|
+
php_parser_py/_mapping/_build.py,sha256=C9gCBJKS3q5VYVNbqWdrI5gC3DD5X9dSJBBfOUDyVes,9271
|
|
11
11
|
php_parser_py/_mapping/_contract.py,sha256=Czfspg4FbU_FZOJLV0AtAmEl6-Pjuo_RLOyOBH8NtYw,2451
|
|
12
|
-
php_parser_py/_mapping/_serialize.py,sha256=
|
|
13
|
-
php_parser_py/_parser.py,sha256=
|
|
14
|
-
php_parser_py/_printer.py,sha256=
|
|
12
|
+
php_parser_py/_mapping/_serialize.py,sha256=EP3A5_wXD72a0-drb62j_N-hJ-JGJoUZ6qqFNWdYZOs,8670
|
|
13
|
+
php_parser_py/_parser.py,sha256=juoRV9sxQJi7odimmm3s27s3l4aHUbBZ4toODEKc3PM,13012
|
|
14
|
+
php_parser_py/_printer.py,sha256=SEr1ivOJnoDUxzDaKY0Hkiu5kNQOfAuqiwH10QtH6tI,5241
|
|
15
15
|
php_parser_py/_resources/ExtendedPrinter.php,sha256=hv2wKJ7QzK6epkevlwmlWrOiFncClTetiqR8kriKsCY,6333
|
|
16
|
-
php_parser_py/_resources/parse.php,sha256=
|
|
17
|
-
php_parser_py/_resources/php,sha256=vvXi2Cj0AtYVxcNp-Iaa2u-A8jR-znyvIZhDUM_-0bw,8918288
|
|
16
|
+
php_parser_py/_resources/parse.php,sha256=g0pDrC1h1Lv85nqIbhOdZcuGgByjz4lJTEivNZAu6NY,3768
|
|
18
17
|
php_parser_py/_resources/php-parser-5.7.0.tar.gz,sha256=CeU5G4YHMA__oybtkqM3dNW07VlcSLOUl2eQWpLklFs,143662
|
|
19
|
-
php_parser_py/_resources/print.php,sha256=
|
|
20
|
-
php_parser_py/_resources/transport.php,sha256=
|
|
18
|
+
php_parser_py/_resources/print.php,sha256=2YDlnK3XPJkqulabrpItAA3HlUDXMgjiO8G3vcrLT7k,5987
|
|
19
|
+
php_parser_py/_resources/transport.php,sha256=WTkEf85Lx8rQ9gojqWC1aGo7tp3XR148M1o8B1OR2K4,6767
|
|
21
20
|
php_parser_py/_runtime/__init__.py,sha256=gKauz8DvQxNUQyNMLfPgy08tEoyIxXsmWb_96bHheJE,223
|
|
22
21
|
php_parser_py/_runtime/_binary.py,sha256=OrldT-rcPjA7P8PeDPNd717BPNfN2hXgwoUe63YWzl0,4145
|
|
23
22
|
php_parser_py/_runtime/_bundle.py,sha256=tIWRCmDuIVGmmSYjtUD-i04rIFJcBIzIjpRM5dpIu7Y,5567
|
|
24
|
-
php_parser_py/_runtime/_runner.py,sha256
|
|
23
|
+
php_parser_py/_runtime/_runner.py,sha256=MDvHIrBfeCq5Lw4qlYx2_W1Yj9mzG5vxUunNvqtVtNI,10044
|
|
25
24
|
php_parser_py/_transport.py,sha256=J4qo0c8gBEGv05Vww59QnkDZ1R0Bjzrjtr8mV2xbCjo,3873
|
|
26
|
-
php_parser_py/_types.py,sha256=
|
|
25
|
+
php_parser_py/_types.py,sha256=70aTz0AbMsJjQb_5w_t8yVYVqg8GZonXi_2HHGDoF5o,2925
|
|
26
|
+
php_parser_py/_version.py,sha256=ZFkpcL_cP2MZyPOwMy4QX68MTVNhYw77F3MNa41dXuo,1760
|
|
27
27
|
php_parser_py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
php_parser_py/_resources/php.exe,sha256=yv_KdAxqo8Pc_xrwnCjdBA2_jn24PL1V4TB1Aey34vY,9529856
|
|
29
|
-
php_parser_py-
|
|
30
|
-
php_parser_py-
|
|
31
|
-
php_parser_py-
|
|
32
|
-
php_parser_py-
|
|
33
|
-
php_parser_py-
|
|
34
|
-
php_parser_py-
|
|
35
|
-
php_parser_py-
|
|
29
|
+
php_parser_py-2.0.3.dist-info/METADATA,sha256=JC0zDNsthV9OCG-fCpYYG3KQYJiADU7-6jRNKt5Lxp8,3893
|
|
30
|
+
php_parser_py-2.0.3.dist-info/WHEEL,sha256=eOph205RIaepfK4qdVVjtNnzanETS7NC0N2C0Ks5Yc8,104
|
|
31
|
+
php_parser_py-2.0.3.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
|
|
32
|
+
php_parser_py-2.0.3.dist-info/licenses/PHP-LICENSE,sha256=tC5N9eUObs2hBH1QPW2R1xAy0J7RAnuh7ynu0m-JDFo,3204
|
|
33
|
+
php_parser_py-2.0.3.dist-info/licenses/PHP-Parser-LICENSE,sha256=3YWeEH-sn4ekQTq4w8lvDxYRoX9Zai21YqWk9JBMHpc,1520
|
|
34
|
+
php_parser_py-2.0.3.dist-info/licenses/Zend-Engine-LICENSE,sha256=UJrrO-ZOQo1-AATOIkYgqwG_lK2qzvu0SWEZOd9WvFs,2803
|
|
35
|
+
php_parser_py-2.0.3.dist-info/RECORD,,
|
php_parser_py/_resources/php
DELETED
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{php_parser_py-1.2.6.dist-info → php_parser_py-2.0.3.dist-info}/licenses/Zend-Engine-LICENSE
RENAMED
|
File without changes
|