Skip to content

Commit 6d89efd

Browse files
committed
Registree
1 parent 1d1f421 commit 6d89efd

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

src/languagePlugins/php/registree/index.test.ts

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type Parser from "tree-sitter";
2+
import { PHPRegistry, PHPTree } from "./types.ts";
3+
4+
export class PHPRegistree {
5+
registry: PHPRegistry;
6+
tree: PHPTree;
7+
8+
constructor(
9+
files: Map<string, { path: string; rootNode: Parser.SyntaxNode }>,
10+
) {
11+
this.registry = new PHPRegistry(files);
12+
this.tree = new PHPTree(files);
13+
}
14+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import type Parser from "tree-sitter";
2+
import type {
3+
ExportedNamespace,
4+
ExportedSymbol,
5+
} from "../exportResolver/types.ts";
6+
import { PHPExportResolver } from "../exportResolver/index.ts";
7+
8+
export interface PHPNode {
9+
name: string;
10+
children: Map<string, PHPNode>;
11+
}
12+
13+
export class NamespaceNode implements PHPNode {
14+
name: string;
15+
children: Map<string, PHPNode>;
16+
17+
constructor(name: string) {
18+
this.name = name;
19+
this.children = new Map();
20+
}
21+
}
22+
23+
export class SymbolNode implements PHPNode {
24+
name: string;
25+
children: Map<string, PHPNode>;
26+
symbols: ExportedSymbol[];
27+
constructor(symbol: ExportedSymbol) {
28+
this.name = symbol.name;
29+
this.children = new Map();
30+
this.symbols = [symbol];
31+
}
32+
}
33+
34+
export class PHPTree extends NamespaceNode {
35+
constructor(
36+
files: Map<string, { path: string; rootNode: Parser.SyntaxNode }>,
37+
) {
38+
super("");
39+
const resolver = new PHPExportResolver();
40+
for (const [, file] of files) {
41+
this.addNamespaces(Array.from(resolver.resolveFile(file).values()));
42+
}
43+
}
44+
45+
addNamespaces(namespaces: ExportedNamespace[]) {
46+
for (const ns of namespaces) {
47+
const nsparts = ns.name.split("\\");
48+
let current = this.children;
49+
for (const p of nsparts) {
50+
if (!current.has(p)) {
51+
current.set(p, new NamespaceNode(p));
52+
}
53+
current = current.get(p)!.children;
54+
}
55+
for (const s of ns.symbols) {
56+
if (!current.has(s.name)) {
57+
current.set(s.name, new SymbolNode(s));
58+
} else {
59+
const snode = current.get(s.name)!;
60+
if (!(snode instanceof SymbolNode)) {
61+
throw Error(
62+
`${s.name} is used both for a namespace and a symbol in ${ns.name}`,
63+
);
64+
} else {
65+
snode.symbols.push(s);
66+
}
67+
}
68+
}
69+
}
70+
}
71+
}
72+
73+
export interface PHPFile {
74+
path: string;
75+
rootNode: Parser.SyntaxNode;
76+
symbols: Map<string, ExportedSymbol[]>;
77+
}
78+
79+
export class PHPRegistry {
80+
files: Map<string, PHPFile>;
81+
resolver: PHPExportResolver;
82+
constructor(
83+
files: Map<string, { path: string; rootNode: Parser.SyntaxNode }>,
84+
) {
85+
this.resolver = new PHPExportResolver();
86+
this.files = new Map();
87+
for (const [, file] of files) {
88+
this.addFile(file);
89+
}
90+
}
91+
92+
addFile(file: { path: string; rootNode: Parser.SyntaxNode }) {
93+
const exported = this.resolver.resolveFile(file);
94+
const symbols: Map<string, ExportedSymbol[]> = new Map();
95+
for (const [, ns] of exported) {
96+
for (const s of ns.symbols) {
97+
if (!symbols.has(s.name)) {
98+
symbols.set(s.name, []);
99+
}
100+
symbols.get(s.name)!.push(s);
101+
}
102+
}
103+
this.files.set(file.path, {
104+
path: file.path,
105+
rootNode: file.rootNode,
106+
symbols,
107+
});
108+
}
109+
}

0 commit comments

Comments
 (0)