Skip to content

Commit 95eaa13

Browse files
committed
feat: expand public API exports and improve comment annotation
- Add CI triggers for feature branch - Export commonly used Stmt, Expr, and Scalar node types from index - Replace naive comment assignment with position-based annotation using binary search to attach comments to their nearest following node
1 parent 09db5a3 commit 95eaa13

3 files changed

Lines changed: 107 additions & 8 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI
22

33
on:
44
push:
5-
branches: [main]
5+
branches: [main, feature/pure-typescript-port-of-php-parser]
66
pull_request:
77
branches: [main]
88

src/index.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,48 @@ export { CloningVisitor } from './node-visitor/cloning-visitor';
4040
// Token constants
4141
export * from './php-token';
4242

43-
// Node types
43+
// Node types - base classes
4444
export { Expr } from './node/expr';
4545
export { Stmt } from './node/stmt';
4646
export { Scalar } from './node/scalar';
4747
export { Name, FullyQualified, Relative } from './node/name';
48+
49+
// Stmt node types
50+
export { Namespace_ } from './node/stmt/namespace';
51+
export { Class_ } from './node/stmt/class';
52+
export { ClassLike } from './node/stmt/class-like';
53+
export { Interface_ } from './node/stmt/interface';
54+
export { Trait_ } from './node/stmt/trait';
55+
export { Enum_ } from './node/stmt/enum';
56+
export { ClassMethod } from './node/stmt/class-method';
57+
export { Property } from './node/stmt/property';
58+
export { ClassConst } from './node/stmt/class-const';
59+
export { Use_ } from './node/stmt/use';
60+
export { EnumCase } from './node/stmt/enum-case';
61+
export { TraitUse } from './node/stmt/trait-use';
62+
export { Function_ } from './node/stmt/function';
63+
export { Return_ } from './node/stmt/return';
64+
export { Expression } from './node/stmt/expression';
65+
66+
// Expr node types
67+
export { Variable } from './node/expr/variable';
68+
export { Assign } from './node/expr/assign';
69+
export { FuncCall } from './node/expr/func-call';
70+
export { MethodCall } from './node/expr/method-call';
71+
export { StaticCall } from './node/expr/static-call';
72+
export { ClassConstFetch } from './node/expr/class-const-fetch';
73+
export { Array_ } from './node/expr/array';
74+
export { ArrayDimFetch } from './node/expr/array-dim-fetch';
75+
export { BinaryOp } from './node/expr/binary-op';
76+
export { Concat as BinaryOpConcat } from './node/expr/binary-op/concat';
77+
export { New_ } from './node/expr/new';
78+
export { Closure } from './node/expr/closure';
79+
export { ArrowFunction } from './node/expr/arrow-function';
80+
81+
// Scalar node types
82+
export { String_ } from './node/scalar/string';
83+
export { Int_ } from './node/scalar/int';
84+
export { Float_ } from './node/scalar/float';
4885
export { Identifier, VarLikeIdentifier } from './node/identifier';
4986
export { Param } from './node/param';
5087
export { Arg } from './node/arg';

src/parser/php8.ts

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ export class Php8Parser implements Parser {
328328
// ─── Comment annotation ────────────────────────────────────────
329329

330330
private annotateComments(stmts: Node[]): void {
331-
// Collect all comments from the token stream and assign them to adjacent nodes
331+
// Collect all comments from the token stream
332332
const comments: Comment[] = [];
333333
for (const token of this.tokens) {
334334
if (token.id === T.T_COMMENT) {
@@ -339,11 +339,73 @@ export class Php8Parser implements Parser {
339339
token.getEndLine(), token.getEndPos() - 1, 0));
340340
}
341341
}
342-
// Simple approach: assign comments to the first statement
343-
if (comments.length > 0 && stmts.length > 0) {
344-
const firstNode = stmts[0];
345-
if (firstNode && typeof firstNode.setAttribute === 'function') {
346-
firstNode.setAttribute('comments', comments);
342+
343+
if (comments.length === 0) return;
344+
345+
// Collect all nodes in the AST with their file positions
346+
const allNodes: Node[] = [];
347+
this.collectAllNodes(stmts, allNodes);
348+
349+
// Sort nodes by startFilePos ascending
350+
allNodes.sort((a, b) => a.getStartFilePos() - b.getStartFilePos());
351+
352+
// For each comment, find the node whose startFilePos comes after the comment ends
353+
// and attach the comment to that node
354+
const nodeComments = new Map<Node, Comment[]>();
355+
356+
for (const comment of comments) {
357+
const commentEndPos = comment.getEndFilePos();
358+
// Binary search for the first node with startFilePos > commentEndPos
359+
let lo = 0;
360+
let hi = allNodes.length;
361+
while (lo < hi) {
362+
const mid = (lo + hi) >>> 1;
363+
if (allNodes[mid].getStartFilePos() <= commentEndPos) {
364+
lo = mid + 1;
365+
} else {
366+
hi = mid;
367+
}
368+
}
369+
if (lo < allNodes.length) {
370+
const targetNode = allNodes[lo];
371+
if (!nodeComments.has(targetNode)) {
372+
nodeComments.set(targetNode, []);
373+
}
374+
nodeComments.get(targetNode)!.push(comment);
375+
}
376+
}
377+
378+
// Assign collected comments to their respective nodes
379+
for (const [node, nodeCommentList] of nodeComments) {
380+
node.setAttribute('comments', nodeCommentList);
381+
}
382+
}
383+
384+
private collectAllNodes(nodes: Node | Node[], result: Node[]): void {
385+
if (Array.isArray(nodes)) {
386+
for (const node of nodes) {
387+
this.collectAllNodes(node, result);
388+
}
389+
return;
390+
}
391+
392+
const node = nodes;
393+
if (!node || typeof node.getType !== 'function') return;
394+
395+
result.push(node);
396+
397+
for (const rawName of node.getSubNodeNames()) {
398+
const name = (node as any)[rawName] !== undefined ? rawName : rawName + '_';
399+
const subNode = (node as any)[name];
400+
if (subNode === null || subNode === undefined) continue;
401+
if (Array.isArray(subNode)) {
402+
for (const item of subNode) {
403+
if (item && typeof item === 'object' && typeof item.getType === 'function') {
404+
this.collectAllNodes(item, result);
405+
}
406+
}
407+
} else if (typeof subNode === 'object' && typeof subNode.getType === 'function') {
408+
this.collectAllNodes(subNode, result);
347409
}
348410
}
349411
}

0 commit comments

Comments
 (0)