token-goat 2.9.10 → 2.9.11

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.
Files changed (27) hide show
  1. package/README.md +54 -11
  2. package/SECURITY.md +17 -19
  3. package/THIRD_PARTY_NOTICES.md +667 -0
  4. package/dist/token-goat-chunk-2ZUPQYLO.mjs +3728 -0
  5. package/dist/{token-goat-chunk-DCYHAUW3.mjs → token-goat-chunk-3ZALKJ23.mjs} +69 -37
  6. package/dist/{token-goat-chunk-JS44SRAX.mjs → token-goat-chunk-4NZUXC4F.mjs} +3 -2
  7. package/dist/{token-goat-chunk-VCEK77ED.mjs → token-goat-chunk-AAEYU2U2.mjs} +5307 -6350
  8. package/dist/{token-goat-chunk-ATVQ6IIT.mjs → token-goat-chunk-FDURVZQD.mjs} +10 -2
  9. package/dist/{token-goat-chunk-DSHYDU53.mjs → token-goat-chunk-HDL77BN3.mjs} +11 -7
  10. package/dist/{token-goat-chunk-LYWIRYCF.mjs → token-goat-chunk-LHLQFGWQ.mjs} +1 -1
  11. package/dist/{token-goat-chunk-YFXFUG3L.mjs → token-goat-chunk-LKOYKSID.mjs} +1275 -655
  12. package/dist/{token-goat-chunk-ZQODJQTP.mjs → token-goat-chunk-MKITQ5RY.mjs} +354 -180
  13. package/dist/{token-goat-chunk-7ALFFPJW.mjs → token-goat-chunk-MRZ555B3.mjs} +2699 -2175
  14. package/dist/{token-goat-chunk-2TJBY5RD.mjs → token-goat-chunk-PJPFOOGM.mjs} +6 -5
  15. package/dist/{token-goat-chunk-FQD3OB5W.mjs → token-goat-chunk-QCQUIPIP.mjs} +6068 -1687
  16. package/dist/{token-goat-chunk-PA5UXNOT.mjs → token-goat-chunk-SY7WTZMW.mjs} +5053 -7735
  17. package/dist/{token-goat-chunk-PXWBHSFB.mjs → token-goat-chunk-T6M7DAW3.mjs} +31 -4
  18. package/dist/{token-goat-chunk-SLGOIXKF.mjs → token-goat-chunk-V53Z47ZH.mjs} +85 -328
  19. package/dist/token-goat-chunk-Y5VKNLVD.mjs +5942 -0
  20. package/dist/token-goat-chunk-YCKCFYTM.mjs +3564 -0
  21. package/dist/token-goat-hook.mjs +6 -5
  22. package/dist/token-goat.core.mjs +8 -6
  23. package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
  24. package/docs/cli.md +4 -1
  25. package/docs/install.md +131 -11
  26. package/docs/security.md +2 -0
  27. package/package.json +8 -3
@@ -0,0 +1,3728 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ lastContentLine,
5
+ makeLineSymbol,
6
+ matchGroovySlashy,
7
+ precedingDocComment,
8
+ stripLineComment,
9
+ stripMultilineStringSpan,
10
+ stripNestedBlockCommentSpan,
11
+ stripStringLiterals
12
+ } from "./token-goat-chunk-YCKCFYTM.mjs";
13
+ import {
14
+ init_define_import_meta_env
15
+ } from "./token-goat-chunk-A37V4PBF.mjs";
16
+
17
+ // src/languages/swift.ts
18
+ init_define_import_meta_env();
19
+ var IDENT_START = "A-Za-z_\\u00C0-\\uFFFF";
20
+ var IDENT_CONT = "A-Za-z0-9_\\u00C0-\\uFFFF";
21
+ var IDENT = `(?:\`[^\`]+\`|[${IDENT_START}][${IDENT_CONT}]*)`;
22
+ function unquoteIdent(name) {
23
+ return name.startsWith("`") && name.endsWith("`") ? name.slice(1, -1) : name;
24
+ }
25
+ var GENERIC = "(?:<(?:[^<>]|<[^<>]*>)*>)?";
26
+ var LEADING_ATTRIBUTE_RE = /^\s*(?:@[A-Za-z_][A-Za-z0-9_.]*(?:\((?:[^()]|\([^()]*\))*\))?\s+)+/;
27
+ function stripLeadingAttributes(s) {
28
+ return s.replace(LEADING_ATTRIBUTE_RE, "");
29
+ }
30
+ var IMPORT_RE = new RegExp(
31
+ `^(?:(?:public|package|internal|fileprivate|private)\\s+)?import\\s+(?:(?:class|struct|enum|protocol|func|var|let|typealias)\\s+)?(${IDENT}(?:\\.${IDENT})*)`
32
+ );
33
+ var MODIFIER_ALT = "(?:(?:public|private|fileprivate|internal|open|package)(?:\\(set\\))?|(?:nonisolated|unowned)(?:\\([A-Za-z]+\\))?|static|final|class|override|required|convenience|mutating|nonmutating|dynamic|async|lazy|weak|indirect|distributed|prefix|postfix|infix|optional|consuming|borrowing|isolated)";
34
+ var FUNC_RE = new RegExp(
35
+ "^\\s*(?:" + MODIFIER_ALT + `\\s+)*func\\s+(${IDENT}|[+\\-*/%=!<>&|^~]+)\\s*` + GENERIC + "\\s*(?:\\(|$)"
36
+ );
37
+ var INIT_RE = new RegExp(
38
+ "^\\s*(?:" + MODIFIER_ALT + "\\s+)*(init)[?!]?\\s*" + GENERIC + "\\s*(?:\\(|$)"
39
+ );
40
+ var DEINIT_RE = /^\s*deinit\s*\{/;
41
+ var SUBSCRIPT_RE = new RegExp(
42
+ "^\\s*(?:" + MODIFIER_ALT + "\\s+)*(subscript)\\s*" + GENERIC + "\\s*(?:\\(|$)"
43
+ );
44
+ var PROPERTY_RE = new RegExp(
45
+ "^\\s*(?:" + MODIFIER_ALT + `\\s+)*(?:var|let)\\s+(${IDENT}[^\\n]*)`
46
+ );
47
+ function splitDeclaratorNames(tail) {
48
+ const names = [];
49
+ let depth = 0;
50
+ let start = 0;
51
+ const parts = [];
52
+ for (let i = 0; i < tail.length; i++) {
53
+ const c = tail[i];
54
+ if (c === "(" || c === "[" || c === "{" || c === "<") depth++;
55
+ else if (c === ")" || c === "]" || c === "}") depth = Math.max(0, depth - 1);
56
+ else if (c === ">" && tail[i - 1] !== "-") depth = Math.max(0, depth - 1);
57
+ else if (c === "," && depth === 0) {
58
+ parts.push(tail.slice(start, i));
59
+ start = i + 1;
60
+ }
61
+ }
62
+ parts.push(tail.slice(start));
63
+ const leadRe = new RegExp(`^\\s*(${IDENT})`);
64
+ for (const part of parts) {
65
+ const m = leadRe.exec(part);
66
+ if (m) names.push(unquoteIdent(m[1] ?? ""));
67
+ }
68
+ return names;
69
+ }
70
+ var TYPE_HEADER_RE = new RegExp(
71
+ `^(?:(?:public|private|fileprivate|internal|open|package|final|indirect|distributed|nonisolated)\\s+)*(class|struct|enum|protocol|extension|actor)\\s+(?!(?:func|var|let|subscript)\\b)(${IDENT}(?:\\.${IDENT})*)`
72
+ );
73
+ function stripRegexLiterals(line) {
74
+ return line.replace(/([=(,[:]|^|\breturn\b)(\s*)\/(?![\s/*])(?:\\.|[^\\/\n])*\//g, "$1$2");
75
+ }
76
+ var ALIAS_RE = new RegExp(
77
+ "^(?:" + MODIFIER_ALT + "\\s+)*(typealias|associatedtype|macro)\\s+(" + IDENT + ")"
78
+ );
79
+ function typeKindFor(keyword2) {
80
+ return keyword2 === "struct" ? "struct" : keyword2 === "enum" ? "enum" : keyword2 === "protocol" ? "protocol" : keyword2 === "extension" ? "extension" : keyword2 === "actor" ? "actor" : "class";
81
+ }
82
+ function extractSwift(content, filePath) {
83
+ const symbols = [];
84
+ const imports = [];
85
+ const lines = content.split(/\r?\n/);
86
+ const typeStack = [];
87
+ let braceDepth = 0;
88
+ let commentDepth = 0;
89
+ let mlState = null;
90
+ function pushMembers(text, parent, lineNum, sig) {
91
+ const noAttr = stripLeadingAttributes(text);
92
+ const kind = parent === void 0 ? "function" : "method";
93
+ const initM = INIT_RE.exec(noAttr);
94
+ if (initM) {
95
+ symbols.push(makeLineSymbol(filePath, initM[1] ?? "init", "method", lineNum, sig, parent, lines, "c"));
96
+ return true;
97
+ }
98
+ if (DEINIT_RE.exec(noAttr)) {
99
+ symbols.push(makeLineSymbol(filePath, "deinit", "method", lineNum, sig, parent, lines, "c"));
100
+ return true;
101
+ }
102
+ const subscriptM = SUBSCRIPT_RE.exec(noAttr);
103
+ if (subscriptM) {
104
+ symbols.push(makeLineSymbol(filePath, subscriptM[1] ?? "subscript", "method", lineNum, sig, parent, lines, "c"));
105
+ return true;
106
+ }
107
+ const fm = FUNC_RE.exec(noAttr);
108
+ if (fm) {
109
+ symbols.push(makeLineSymbol(filePath, unquoteIdent(fm[1] ?? ""), kind, lineNum, sig, parent, lines, "c"));
110
+ return true;
111
+ }
112
+ const propM = PROPERTY_RE.exec(noAttr);
113
+ if (propM) {
114
+ const names = splitDeclaratorNames(propM[1] ?? "");
115
+ for (const name of names) {
116
+ symbols.push(makeLineSymbol(filePath, name, "var", lineNum, sig, parent, lines, "c"));
117
+ }
118
+ return names.length > 0;
119
+ }
120
+ return false;
121
+ }
122
+ for (let i = 0; i < lines.length; i++) {
123
+ const rawLine = lines[i] ?? "";
124
+ const lineNum = i + 1;
125
+ let mlLine = rawLine;
126
+ if (mlState !== null || commentDepth === 0) {
127
+ const masked = stripMultilineStringSpan(rawLine, mlState, "swift");
128
+ mlLine = masked.code;
129
+ mlState = masked.state;
130
+ }
131
+ const { code: blockStripped, depth: nextCommentDepth } = stripNestedBlockCommentSpan(mlLine, commentDepth);
132
+ commentDepth = nextCommentDepth;
133
+ const line = stripLineComment(blockStripped).trimEnd();
134
+ const stripped = line.trim();
135
+ if (!stripped) {
136
+ const braceLine2 = stripRegexLiterals(stripStringLiterals(line));
137
+ braceDepth += (braceLine2.match(/\{/g) ?? []).length - (braceLine2.match(/\}/g) ?? []).length;
138
+ continue;
139
+ }
140
+ const strippedNoAttr = stripLeadingAttributes(stripped);
141
+ const importM = IMPORT_RE.exec(strippedNoAttr);
142
+ if (importM) {
143
+ imports.push({ kind: "import", target: unquoteIdent(importM[1] ?? ""), line: lineNum });
144
+ }
145
+ const outerFrame = typeStack.length > 0 ? typeStack[typeStack.length - 1] : null;
146
+ const outerDepthInType = outerFrame !== null ? braceDepth - outerFrame.startDepth : 0;
147
+ const typeDetectionGateOk = typeStack.length === 0 || outerDepthInType === 1;
148
+ const tm = typeDetectionGateOk && (braceDepth === 0 || typeStack.length > 0) ? TYPE_HEADER_RE.exec(strippedNoAttr) : null;
149
+ if (tm) {
150
+ const tname = unquoteIdent(tm[2] ?? "");
151
+ const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
152
+ symbols.push(makeLineSymbol(filePath, tname, typeKindFor(tm[1] ?? "class"), lineNum, stripped.slice(0, 200), parent, lines, "c"));
153
+ typeStack.push({ name: tname, startDepth: braceDepth, bodyEntered: false });
154
+ const open = strippedNoAttr.indexOf("{");
155
+ if (open !== -1) {
156
+ const tail = strippedNoAttr.slice(open + 1).replace(/\}\s*$/, "").trim();
157
+ if (tail) pushMembers(tail, tname, lineNum, tail.slice(0, 200));
158
+ }
159
+ }
160
+ const am = tm === null && typeDetectionGateOk && (braceDepth === 0 || typeStack.length > 0) ? ALIAS_RE.exec(strippedNoAttr) : null;
161
+ if (am) {
162
+ const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
163
+ symbols.push(makeLineSymbol(filePath, unquoteIdent(am[2] ?? ""), am[1] === "macro" ? "macro" : "type", lineNum, stripped.slice(0, 200), parent, lines, "c"));
164
+ }
165
+ const frame = typeStack.length > 0 ? typeStack[typeStack.length - 1] : null;
166
+ if (frame !== null && tm === null) {
167
+ const depthInType = braceDepth - frame.startDepth;
168
+ if (depthInType === 1) {
169
+ pushMembers(line, frame.name, lineNum, stripped.slice(0, 200));
170
+ }
171
+ } else if (frame === null && braceDepth === 0) {
172
+ pushMembers(line, void 0, lineNum, stripped.slice(0, 200));
173
+ }
174
+ const braceLine = stripRegexLiterals(stripStringLiterals(line));
175
+ for (const ch of braceLine) {
176
+ if (ch === "{") {
177
+ braceDepth++;
178
+ const top = typeStack.length > 0 ? typeStack[typeStack.length - 1] : null;
179
+ if (top !== null && braceDepth > top.startDepth) {
180
+ top.bodyEntered = true;
181
+ }
182
+ } else if (ch === "}") {
183
+ braceDepth--;
184
+ }
185
+ }
186
+ while (typeStack.length > 0) {
187
+ const top = typeStack[typeStack.length - 1];
188
+ if (top.bodyEntered && braceDepth <= top.startDepth) {
189
+ typeStack.pop();
190
+ } else {
191
+ break;
192
+ }
193
+ }
194
+ }
195
+ return { symbols, imports };
196
+ }
197
+
198
+ // src/languages/cobol.ts
199
+ init_define_import_meta_env();
200
+ var MAX_SYMBOLS = 1e4;
201
+ var NAME = String.raw`[A-Za-z0-9][A-Za-z0-9_-]*`;
202
+ var SOURCE_DIRECTIVE_RE = /^\s*>>\s*SOURCE\s+(?:FORMAT\s+)?(?:IS\s+)?(FREE|FIXED)\b/i;
203
+ var DIVISION_RE = /^(IDENTIFICATION|ID|ENVIRONMENT|DATA|PROCEDURE)\s+DIVISION\b/i;
204
+ var ID_PARAGRAPH_RE = /^(PROGRAM|FUNCTION)-ID\b/i;
205
+ var END_UNIT_RE = new RegExp(String.raw`^END\s+(PROGRAM|FUNCTION)\s+(?:"([^"]+)"|'([^']+)'|(${NAME}))`, "i");
206
+ var SECTION_RE = new RegExp(String.raw`^(${NAME})\s+SECTION(?:\s+\d+)?\s*\.`, "i");
207
+ var PARAGRAPH_RE = new RegExp(String.raw`^(${NAME})\s*\.(?:\s|$)`);
208
+ var LEVEL_RE = new RegExp(String.raw`^(\d{1,2})\s+(${NAME})(?=[\s.]|$)`);
209
+ var FILE_DESCRIPTION_RE = new RegExp(String.raw`^(FD|SD)\s+(${NAME})`, "i");
210
+ var NOT_A_PARAGRAPH = /^(?:EXIT|GOBACK|CONTINUE|ELSE|EJECT|SKIP[123]|DECLARATIVES|END-[A-Z-]+)$/i;
211
+ var PERFORM_NOT_A_TARGET = /^(?:UNTIL|VARYING|WITH|TEST|FOREVER|TIMES)$/i;
212
+ function startsFree(rawLines) {
213
+ for (const raw of rawLines) {
214
+ const directive = SOURCE_DIRECTIVE_RE.exec(raw);
215
+ if (directive) return directive[1].toUpperCase() === "FREE";
216
+ if (DIVISION_RE.test(raw) || raw.startsWith("*>")) return true;
217
+ }
218
+ return false;
219
+ }
220
+ function stripFloatingComment(text) {
221
+ let quote = "";
222
+ for (let i = 0; i < text.length; i++) {
223
+ const ch = text[i];
224
+ if (quote !== "") {
225
+ if (ch === quote) quote = "";
226
+ } else if (ch === '"' || ch === "'") quote = ch;
227
+ else if (ch === "*" && text[i + 1] === ">") return text.slice(0, i);
228
+ }
229
+ return text;
230
+ }
231
+ function blankStrings(text) {
232
+ let out = "";
233
+ let quote = "";
234
+ for (const ch of text) {
235
+ if (quote !== "") {
236
+ if (ch === quote) {
237
+ quote = "";
238
+ out += ch;
239
+ } else out += " ";
240
+ } else {
241
+ if (ch === '"' || ch === "'") quote = ch;
242
+ out += ch;
243
+ }
244
+ }
245
+ return out;
246
+ }
247
+ function joinContinuation(out, areaB) {
248
+ const prev = out[out.length - 1];
249
+ const rest = areaB.trimStart();
250
+ if (prev === void 0 || rest === "") return;
251
+ const opensLiteral = (prev.code.match(/["']/g) ?? []).length % 2 === 1;
252
+ const piece = (opensLiteral && (rest[0] === '"' || rest[0] === "'") ? rest.slice(1) : rest).trimEnd();
253
+ const text = stripFloatingComment(prev.text + piece).trimEnd();
254
+ out[out.length - 1] = { ...prev, text, code: blankStrings(text) };
255
+ }
256
+ function toLines(rawLines) {
257
+ const out = [];
258
+ let free = startsFree(rawLines);
259
+ for (let i = 0; i < rawLines.length; i++) {
260
+ const raw = rawLines[i];
261
+ const directive = SOURCE_DIRECTIVE_RE.exec(free ? raw : raw.slice(7));
262
+ if (directive) {
263
+ free = directive[1].toUpperCase() === "FREE";
264
+ continue;
265
+ }
266
+ let text;
267
+ let offset;
268
+ let areaA;
269
+ if (free) {
270
+ if (/^\s*>>/.test(raw)) continue;
271
+ text = raw;
272
+ offset = 0;
273
+ areaA = true;
274
+ } else {
275
+ if (raw.length <= 7) continue;
276
+ const indicator = raw[6];
277
+ if (indicator === "*" || indicator === "/" || indicator === "D" || indicator === "d") continue;
278
+ if (indicator === "-") {
279
+ joinContinuation(out, raw.slice(7, 72));
280
+ continue;
281
+ }
282
+ text = raw.slice(7, 72);
283
+ offset = 7;
284
+ areaA = text.slice(0, 4).trim() !== "";
285
+ }
286
+ text = stripFloatingComment(text).trimEnd();
287
+ if (text.trim() === "") continue;
288
+ const lead = text.length - text.trimStart().length;
289
+ out.push({ line: i + 1, text: text.trimStart(), code: blankStrings(text.trimStart()), offset: offset + lead, areaA, raw });
290
+ }
291
+ return out;
292
+ }
293
+ function unitName(rest, next) {
294
+ const source = rest.trim() !== "" ? rest : next?.text ?? "";
295
+ const m = new RegExp(String.raw`^(?:"([^"]+)"|'([^']+)'|(${NAME}))`).exec(source.trim());
296
+ return m ? m[1] ?? m[2] ?? m[3] : void 0;
297
+ }
298
+ function copyTarget(text, index) {
299
+ const m = new RegExp(String.raw`^COPY\s+(?:"([^"]+)"|'([^']+)'|(${NAME}))`, "i").exec(text.slice(index));
300
+ return m ? m[1] ?? m[2] ?? m[3] : void 0;
301
+ }
302
+ function extractCobol(content, filePath) {
303
+ const symbols = [];
304
+ const refs = [];
305
+ const imports = [];
306
+ if (content.includes("\0")) return { symbols, refs, imports };
307
+ const rawLines = (content.charCodeAt(0) === 65279 ? content.slice(1) : content).split(/\r?\n/);
308
+ const lines = toLines(rawLines);
309
+ const isCopybook = /\.cpy$/i.test(filePath);
310
+ const units = [];
311
+ let section;
312
+ let paragraph;
313
+ let fileDescription;
314
+ let record;
315
+ let division = "";
316
+ let lastLine = 0;
317
+ let idDivisionLine;
318
+ let recordLevel = 1;
319
+ if (isCopybook && !lines.some((l) => DIVISION_RE.test(l.code))) {
320
+ const levels = lines.map((l) => LEVEL_RE.exec(l.code)).filter((m) => m !== null).map((m) => Number(m[1]));
321
+ const first = lines[0];
322
+ division = first !== void 0 && LEVEL_RE.test(first.code) ? "DATA" : "PROCEDURE";
323
+ const structural = levels.filter((n) => n >= 1 && n <= 49);
324
+ if (structural.length > 0) recordLevel = structural.reduce((a, b) => b < a ? b : a, structural[0]);
325
+ }
326
+ const emit = (name, kind, line, parent) => {
327
+ if (symbols.length >= MAX_SYMBOLS) return void 0;
328
+ symbols.push({ filePath, name, kind, lineStart: line, lineEnd: line, body: "", docstring: "", parent });
329
+ return symbols.length - 1;
330
+ };
331
+ const close = (index, end) => {
332
+ if (index === void 0) return;
333
+ const sym = symbols[index];
334
+ symbols[index] = { ...sym, lineEnd: Math.max(sym.lineStart, end) };
335
+ };
336
+ const unitParent = () => {
337
+ const top = units[units.length - 1];
338
+ return top === void 0 ? "" : symbols[top].name;
339
+ };
340
+ const closeProcedure = (end) => {
341
+ close(paragraph, end);
342
+ paragraph = void 0;
343
+ close(section, end);
344
+ section = void 0;
345
+ };
346
+ const closeData = (end) => {
347
+ close(record, end);
348
+ record = void 0;
349
+ close(fileDescription, end);
350
+ fileDescription = void 0;
351
+ };
352
+ for (let i = 0; i < lines.length; i++) {
353
+ const l = lines[i];
354
+ const code = l.code.trim();
355
+ for (const m of l.code.matchAll(/\bCOPY\s+/gi)) {
356
+ const target = copyTarget(l.text, m.index);
357
+ if (target !== void 0) imports.push({ kind: "import", target, line: l.line });
358
+ }
359
+ const include = /\bEXEC\s+SQL\s+INCLUDE\s+([A-Za-z0-9_-]+)/i.exec(l.code);
360
+ if (include) imports.push({ kind: "import", target: include[1], line: l.line });
361
+ const id = ID_PARAGRAPH_RE.exec(code);
362
+ if (id) {
363
+ const name = unitName(l.text.slice(l.text.search(/-ID/i) + 3).replace(/^\s*\.?/, ""), lines[i + 1]);
364
+ closeProcedure(lastLine);
365
+ closeData(lastLine);
366
+ if (name !== void 0) {
367
+ const start = idDivisionLine !== void 0 && idDivisionLine === lastLine ? idDivisionLine : l.line;
368
+ const index = emit(name, id[1].toUpperCase() === "FUNCTION" ? "function" : "program", start, unitParent());
369
+ if (index !== void 0) units.push(index);
370
+ }
371
+ division = "IDENTIFICATION";
372
+ lastLine = l.line;
373
+ continue;
374
+ }
375
+ const end = END_UNIT_RE.exec(code);
376
+ if (end) {
377
+ const name = (end[2] ?? end[3] ?? end[4]).toUpperCase();
378
+ closeProcedure(lastLine);
379
+ closeData(lastLine);
380
+ let at = units.length - 1;
381
+ while (at >= 0 && symbols[units[at]].name.toUpperCase() !== name) at--;
382
+ if (at >= 0) {
383
+ for (const u of units.splice(at)) close(u, l.line);
384
+ }
385
+ division = "";
386
+ lastLine = l.line;
387
+ continue;
388
+ }
389
+ const div = DIVISION_RE.exec(code);
390
+ if (div) {
391
+ closeProcedure(lastLine);
392
+ closeData(lastLine);
393
+ division = div[1].toUpperCase() === "ID" ? "IDENTIFICATION" : div[1].toUpperCase();
394
+ if (division === "IDENTIFICATION") idDivisionLine = l.line;
395
+ lastLine = l.line;
396
+ continue;
397
+ }
398
+ if (division === "DATA") {
399
+ if (/^[A-Za-z0-9-]+\s+SECTION\s*\./i.test(code)) {
400
+ closeData(lastLine);
401
+ } else if (FILE_DESCRIPTION_RE.test(code)) {
402
+ const m = FILE_DESCRIPTION_RE.exec(code);
403
+ closeData(lastLine);
404
+ fileDescription = emit(m[2], "file", l.line, unitParent());
405
+ } else {
406
+ const m = LEVEL_RE.exec(code);
407
+ const level = m ? Number(m[1]) : -1;
408
+ if (m && (level === recordLevel || level === 77)) {
409
+ close(record, lastLine);
410
+ record = void 0;
411
+ if (level === 77) {
412
+ close(fileDescription, lastLine);
413
+ fileDescription = void 0;
414
+ }
415
+ if (m[2].toUpperCase() !== "FILLER") {
416
+ const owner = fileDescription !== void 0 ? symbols[fileDescription].name : unitParent();
417
+ record = emit(m[2], "variable", l.line, owner);
418
+ }
419
+ }
420
+ }
421
+ } else if (division === "PROCEDURE") {
422
+ const sec = l.areaA ? SECTION_RE.exec(code) : null;
423
+ const para = l.areaA && !sec ? PARAGRAPH_RE.exec(code) : null;
424
+ if (sec) {
425
+ closeProcedure(lastLine);
426
+ section = emit(sec[1], "section", l.line, unitParent());
427
+ } else if (para && !NOT_A_PARAGRAPH.test(para[1])) {
428
+ close(paragraph, lastLine);
429
+ paragraph = emit(para[1], "paragraph", l.line, section !== void 0 ? symbols[section].name : unitParent());
430
+ }
431
+ for (const m of l.code.matchAll(new RegExp(String.raw`\bPERFORM\s+(${NAME})(?:\s+(?:THRU|THROUGH)\s+(${NAME}))?(\s+TIMES\b)?`, "gi"))) {
432
+ if (m[3] !== void 0 || PERFORM_NOT_A_TARGET.test(m[1]) || /^\d+$/.test(m[1])) continue;
433
+ refs.push({ filePath, name: m[1], line: l.line, col: l.offset + m.index, context: l.raw.trim() });
434
+ if (m[2] !== void 0) refs.push({ filePath, name: m[2], line: l.line, col: l.offset + m.index, context: l.raw.trim() });
435
+ }
436
+ for (const m of l.code.matchAll(new RegExp(String.raw`\bGO\s+(?:TO\s+)?(${NAME})`, "gi"))) {
437
+ if (/^DEPENDING$/i.test(m[1])) continue;
438
+ refs.push({ filePath, name: m[1], line: l.line, col: l.offset + m.index, context: l.raw.trim() });
439
+ }
440
+ for (const m of l.code.matchAll(/\bCALL\s+(["'])/gi)) {
441
+ const quote = m.index + m[0].length - 1;
442
+ const close2 = l.text.indexOf(m[1], quote + 1);
443
+ const name = close2 > quote ? l.text.slice(quote + 1, close2).trim() : "";
444
+ if (name !== "") refs.push({ filePath, name, line: l.line, col: l.offset + m.index, context: l.raw.trim() });
445
+ }
446
+ }
447
+ lastLine = l.line;
448
+ }
449
+ closeProcedure(lastLine);
450
+ closeData(lastLine);
451
+ for (const u of units) close(u, lastLine);
452
+ for (let k = 0; k < symbols.length; k++) {
453
+ const sym = symbols[k];
454
+ symbols[k] = { ...sym, body: rawLines.slice(sym.lineStart - 1, sym.lineEnd).join("\n") };
455
+ }
456
+ return { symbols, refs, imports };
457
+ }
458
+
459
+ // src/languages/natural.ts
460
+ init_define_import_meta_env();
461
+ import * as path from "node:path";
462
+ var MAX_SYMBOLS2 = 1e4;
463
+ var OBJECT_KINDS = /* @__PURE__ */ new Map([
464
+ [".nsp", "program"],
465
+ [".nsn", "subprogram"],
466
+ [".nss", "subroutine"],
467
+ [".nsh", "helproutine"],
468
+ [".nsc", "copycode"],
469
+ [".nsa", "data_area"],
470
+ [".nsl", "data_area"],
471
+ [".nsg", "data_area"]
472
+ ]);
473
+ var DATA_AREA_EXTS = /* @__PURE__ */ new Set([".nsa", ".nsl", ".nsg"]);
474
+ var NAME2 = String.raw`[A-Za-z#&@$_][A-Za-z0-9#&@$_-]*`;
475
+ var DEFINE_SUBROUTINE_RE = new RegExp(String.raw`^DEFINE\s+(?:SUBROUTINE\s+)?(${NAME2})\s*$|^DEFINE\s+SUBROUTINE\s+(${NAME2})\b`, "i");
476
+ var NOT_A_SUBROUTINE = /^(?:DATA|WINDOW|PRINTER|WORK|CLASS|PROTOTYPE|FUNCTION|SUBROUTINE)$/i;
477
+ var DEFINE_DATA_RE = /^DEFINE\s+DATA\b/i;
478
+ var END_DEFINE_RE = /^END-DEFINE\b/i;
479
+ var END_SUBROUTINE_RE = /^END-SUBROUTINE\b/i;
480
+ var LEVEL_ONE_RE = new RegExp(String.raw`^0?1\s+(${NAME2})(?:\s+VIEW\s+(?:OF\s+)?(${NAME2}))?`, "i");
481
+ var USING_RE = new RegExp(String.raw`\b(?:LOCAL|PARAMETER|GLOBAL|CONTEXT|OBJECT)\s+USING\s+(${NAME2})`, "gi");
482
+ var INCLUDE_RE = new RegExp(String.raw`^INCLUDE\s+(${NAME2})`, "i");
483
+ var LINE_NUMBER_RE = /^\d{4}(?: |$)/;
484
+ function isCommentLine(text) {
485
+ return /^(?:\*(?:[ *]|$)|\/\*)/.test(text);
486
+ }
487
+ function codeOf(text) {
488
+ let quote = "";
489
+ let code = "";
490
+ for (let i = 0; i < text.length; i++) {
491
+ const ch = text[i];
492
+ if (quote !== "") {
493
+ if (ch === quote) {
494
+ quote = "";
495
+ code += ch;
496
+ } else code += " ";
497
+ continue;
498
+ }
499
+ if (ch === "/" && text[i + 1] === "*" && (i === 0 || text[i - 1] === " ")) return { text: text.slice(0, i).trimEnd(), code: code.trimEnd() };
500
+ if (ch === "'" || ch === '"') quote = ch;
501
+ code += ch;
502
+ }
503
+ return { text, code };
504
+ }
505
+ function toLines2(rawLines) {
506
+ const nonBlank = rawLines.filter((l) => l.trim() !== "");
507
+ const numbered = nonBlank.length > 0 && nonBlank.filter((l) => LINE_NUMBER_RE.test(l)).length / nonBlank.length >= 0.8;
508
+ const out = [];
509
+ for (let i = 0; i < rawLines.length; i++) {
510
+ const raw = rawLines[i];
511
+ let offset = numbered && LINE_NUMBER_RE.test(raw) ? 5 : 0;
512
+ const body = raw.slice(offset);
513
+ const lead = body.length - body.trimStart().length;
514
+ offset += lead;
515
+ const trimmed = body.trim();
516
+ if (trimmed === "" || isCommentLine(trimmed)) continue;
517
+ const { text, code } = codeOf(trimmed);
518
+ if (text === "") continue;
519
+ out.push({ line: i + 1, text, code, offset, raw });
520
+ }
521
+ return out;
522
+ }
523
+ function literalAt(text, index) {
524
+ const m = /^(['"])([^'"]+)\1/.exec(text.slice(index));
525
+ return m ? m[2].trim() : void 0;
526
+ }
527
+ function extractNatural(content, filePath) {
528
+ const symbols = [];
529
+ const refs = [];
530
+ const imports = [];
531
+ if (content.includes("\0")) return { symbols, refs, imports };
532
+ const rawLines = (content.charCodeAt(0) === 65279 ? content.slice(1) : content).split(/\r?\n/);
533
+ const lines = toLines2(rawLines);
534
+ const ext = path.extname(filePath).toLowerCase();
535
+ const objectName = path.basename(filePath, path.extname(filePath));
536
+ const isDataArea = DATA_AREA_EXTS.has(ext);
537
+ const emit = (name, kind, line, parent) => {
538
+ if (symbols.length >= MAX_SYMBOLS2) return void 0;
539
+ symbols.push({ filePath, name, kind, lineStart: line, lineEnd: line, body: "", docstring: "", parent });
540
+ return symbols.length - 1;
541
+ };
542
+ const close = (index, end) => {
543
+ if (index === void 0) return;
544
+ const sym = symbols[index];
545
+ symbols[index] = { ...sym, lineEnd: Math.max(sym.lineStart, end) };
546
+ };
547
+ const lastLine = lines.length > 0 ? lines[lines.length - 1].line : 1;
548
+ const objectKind = OBJECT_KINDS.get(ext);
549
+ if (objectKind !== void 0 && lines.length > 0) {
550
+ const index = emit(objectName, objectKind, lines[0].line, "");
551
+ close(index, lastLine);
552
+ }
553
+ let inData = isDataArea;
554
+ let dataBlock;
555
+ let field;
556
+ let subroutine;
557
+ let previous = 0;
558
+ for (const l of lines) {
559
+ const code = l.code.trim();
560
+ if (DEFINE_DATA_RE.test(code)) {
561
+ inData = true;
562
+ dataBlock = emit("DEFINE DATA", "data", l.line, objectName);
563
+ } else if (inData && END_DEFINE_RE.test(code)) {
564
+ close(field, previous);
565
+ field = void 0;
566
+ close(dataBlock, l.line);
567
+ dataBlock = void 0;
568
+ inData = false;
569
+ } else if (inData) {
570
+ for (const m2 of l.code.matchAll(USING_RE)) imports.push({ kind: "import", target: m2[1], line: l.line });
571
+ const m = LEVEL_ONE_RE.exec(code);
572
+ if (m) {
573
+ close(field, previous);
574
+ field = emit(m[1], m[2] !== void 0 ? "view" : "variable", l.line, objectName);
575
+ } else if (/^(?:LOCAL|PARAMETER|GLOBAL|INDEPENDENT|CONTEXT|OBJECT)\b/i.test(code)) {
576
+ close(field, previous);
577
+ field = void 0;
578
+ }
579
+ } else {
580
+ const def = DEFINE_SUBROUTINE_RE.exec(code);
581
+ const name = def ? def[1] ?? def[2] : void 0;
582
+ if (name !== void 0 && !NOT_A_SUBROUTINE.test(name)) {
583
+ close(subroutine, previous);
584
+ subroutine = emit(name, "subroutine", l.line, objectName);
585
+ } else if (END_SUBROUTINE_RE.test(code)) {
586
+ close(subroutine, l.line);
587
+ subroutine = void 0;
588
+ } else if (/^END\s*\.?$/i.test(code)) {
589
+ close(subroutine, previous);
590
+ subroutine = void 0;
591
+ }
592
+ const include = INCLUDE_RE.exec(code);
593
+ if (include) imports.push({ kind: "import", target: include[1], line: l.line });
594
+ for (const m of l.code.matchAll(new RegExp(String.raw`\bPERFORM\s+(${NAME2})`, "gi"))) {
595
+ refs.push({ filePath, name: m[1], line: l.line, col: l.offset + m.index, context: l.raw.trim() });
596
+ }
597
+ for (const m of l.code.matchAll(/\b(?:CALLNAT|FETCH(?:\s+(?:RETURN|REPEAT))*)\s+(?=['"])/gi)) {
598
+ const name2 = literalAt(l.text, m.index + m[0].length);
599
+ if (name2 !== void 0) refs.push({ filePath, name: name2, line: l.line, col: l.offset + m.index, context: l.raw.trim() });
600
+ }
601
+ }
602
+ previous = l.line;
603
+ }
604
+ close(field, previous);
605
+ close(dataBlock, previous);
606
+ close(subroutine, previous);
607
+ for (let k = 0; k < symbols.length; k++) {
608
+ const sym = symbols[k];
609
+ symbols[k] = { ...sym, body: rawLines.slice(sym.lineStart - 1, sym.lineEnd).join("\n") };
610
+ }
611
+ return { symbols, refs, imports };
612
+ }
613
+
614
+ // src/languages/abap.ts
615
+ init_define_import_meta_env();
616
+
617
+ // src/languages/span_collector.ts
618
+ init_define_import_meta_env();
619
+ var MAX_SYMBOLS3 = 1e4;
620
+ var MAX_NAME_LENGTH = 120;
621
+ var SpanCollector = class {
622
+ constructor(filePath) {
623
+ this.filePath = filePath;
624
+ }
625
+ filePath;
626
+ items = [];
627
+ /** Record a symbol that starts and, until {@link close} says otherwise, ends on `line`; undefined when the name is unusable or the cap is reached. */
628
+ open(name, kind, line, parent = "") {
629
+ if (name === "" || name.length > MAX_NAME_LENGTH || this.items.length >= MAX_SYMBOLS3) return void 0;
630
+ this.items.push({ filePath: this.filePath, name, kind, lineStart: line, lineEnd: line, body: "", docstring: "", parent });
631
+ return this.items.length - 1;
632
+ }
633
+ close(index, end) {
634
+ if (index === void 0) return;
635
+ const sym = this.items[index];
636
+ this.items[index] = { ...sym, lineEnd: Math.max(sym.lineStart, end) };
637
+ }
638
+ name(index) {
639
+ return index === void 0 ? "" : this.items[index].name;
640
+ }
641
+ /** The collected symbols, each with its body sliced from `rawLines`. */
642
+ finish(rawLines) {
643
+ return this.items.map((s) => ({ ...s, body: rawLines.slice(s.lineStart - 1, s.lineEnd).join("\n") }));
644
+ }
645
+ };
646
+ function topLevelWords(text, isWordChar3) {
647
+ const out = [];
648
+ let depth = 0;
649
+ let word = "";
650
+ for (const ch of text) {
651
+ if (ch === "(") depth++;
652
+ else if (ch === ")") depth = Math.max(0, depth - 1);
653
+ if (depth === 0 && isWordChar3(ch)) {
654
+ word += ch;
655
+ continue;
656
+ }
657
+ if (word !== "") out.push(word);
658
+ word = "";
659
+ }
660
+ if (word !== "") out.push(word);
661
+ return out;
662
+ }
663
+ function wordBeforeParen(text, isWordChar3) {
664
+ const paren = text.indexOf("(");
665
+ if (paren < 0) return "";
666
+ let end = paren;
667
+ while (end > 0 && /\s/.test(text[end - 1])) end--;
668
+ let start = end;
669
+ while (start > 0 && isWordChar3(text[start - 1])) start--;
670
+ return text.slice(start, end);
671
+ }
672
+
673
+ // src/languages/abap.ts
674
+ function abapStatements(rawLines) {
675
+ const out = [];
676
+ let buf = "";
677
+ let start = 0;
678
+ for (let i = 0; i < rawLines.length; i++) {
679
+ const raw = rawLines[i];
680
+ if (raw.startsWith("*")) continue;
681
+ let quote = "";
682
+ for (let j = 0; j < raw.length; j++) {
683
+ const ch = raw[j];
684
+ if (quote !== "") {
685
+ if (quote === "|" && ch === "\\") {
686
+ buf += " ";
687
+ j++;
688
+ } else if (ch === quote && quote !== "|" && raw[j + 1] === quote) {
689
+ buf += " ";
690
+ j++;
691
+ } else if (ch === quote) {
692
+ quote = "";
693
+ buf += ch;
694
+ } else buf += " ";
695
+ continue;
696
+ }
697
+ if (ch === '"') break;
698
+ if (ch === "'" || ch === "`" || ch === "|") quote = ch;
699
+ if (ch === ".") {
700
+ if (buf.trim() !== "") out.push({ text: buf.trim(), line: start, endLine: i + 1 });
701
+ buf = "";
702
+ start = 0;
703
+ continue;
704
+ }
705
+ if (start === 0 && !/\s/.test(ch)) start = i + 1;
706
+ buf += ch === ":" ? " " : ch;
707
+ }
708
+ buf += " ";
709
+ }
710
+ return out;
711
+ }
712
+ var CLOSERS = /* @__PURE__ */ new Map([
713
+ ["ENDCLASS", "CLASS"],
714
+ ["ENDINTERFACE", "INTERFACE"],
715
+ ["ENDMETHOD", "METHOD"],
716
+ ["ENDFORM", "FORM"],
717
+ ["ENDFUNCTION", "FUNCTION"],
718
+ ["ENDMODULE", "MODULE"],
719
+ ["END-OF-DEFINITION", "DEFINE"]
720
+ ]);
721
+ var BLOCK_KINDS = /* @__PURE__ */ new Map([
722
+ ["FORM", "form"],
723
+ ["FUNCTION", "function"],
724
+ ["MODULE", "module"],
725
+ ["DEFINE", "macro"]
726
+ ]);
727
+ function extractAbap(content, filePath) {
728
+ const imports = [];
729
+ const spans = new SpanCollector(filePath);
730
+ if (content.includes("\0")) return { symbols: [], imports };
731
+ const rawLines = content.split(/\r?\n/);
732
+ const statements = abapStatements(rawLines);
733
+ const lastLine = statements.length > 0 ? statements[statements.length - 1].endLine : 1;
734
+ const stack = [];
735
+ let program = false;
736
+ for (const st of statements) {
737
+ const words = st.text.split(/\s+/);
738
+ const w0 = words[0].toUpperCase();
739
+ const name = words[1] ?? "";
740
+ const rest = words.slice(2).map((w) => w.toUpperCase());
741
+ const inMacro = stack.length > 0 && stack[stack.length - 1].opener === "DEFINE";
742
+ const closes = CLOSERS.get(w0);
743
+ if (closes !== void 0) {
744
+ const at = stack.map((o) => o.opener).lastIndexOf(closes);
745
+ if (at < 0) continue;
746
+ for (const o of stack.splice(at)) spans.close(o.index, st.endLine);
747
+ continue;
748
+ }
749
+ if (inMacro || name === "") continue;
750
+ if (!program && (w0 === "REPORT" || w0 === "PROGRAM" || w0 === "FUNCTION-POOL")) {
751
+ program = true;
752
+ spans.close(spans.open(name, "program", st.line), lastLine);
753
+ } else if (w0 === "CLASS" && (rest[0] === "DEFINITION" || rest[0] === "IMPLEMENTATION")) {
754
+ if (rest.includes("DEFERRED") || rest.includes("LOAD") || rest.includes("LOCAL") && rest.includes("FRIENDS")) continue;
755
+ const kind = rest[0] === "DEFINITION" ? "class" : "implementation";
756
+ stack.push({ opener: "CLASS", index: spans.open(name, kind, st.line), owner: name });
757
+ } else if (w0 === "INTERFACE" && !rest.includes("DEFERRED") && !rest.includes("LOAD")) {
758
+ stack.push({ opener: "INTERFACE", index: spans.open(name, "interface", st.line), owner: name });
759
+ } else if (w0 === "METHOD") {
760
+ const owner = [...stack].reverse().find((o) => o.owner !== "")?.owner ?? "";
761
+ stack.push({ opener: "METHOD", index: spans.open(name, "method", st.line, owner), owner: "" });
762
+ } else if (BLOCK_KINDS.has(w0)) {
763
+ stack.push({ opener: w0, index: spans.open(name, BLOCK_KINDS.get(w0), st.line), owner: "" });
764
+ } else if (w0 === "INCLUDE") {
765
+ const target = name.toUpperCase();
766
+ if (target !== "TYPE" && target !== "STRUCTURE") imports.push({ kind: "include", target: name, line: st.line });
767
+ }
768
+ }
769
+ for (const o of stack) spans.close(o.index, lastLine);
770
+ return { symbols: spans.finish(rawLines), imports };
771
+ }
772
+
773
+ // src/languages/abl.ts
774
+ init_define_import_meta_env();
775
+ function isSpace(ch) {
776
+ return ch === void 0 || ch === " " || ch === " " || ch === "\r" || ch === "\f";
777
+ }
778
+ function ablStatements(rawLines) {
779
+ const statements = [];
780
+ const includes = [];
781
+ let text = "";
782
+ let start = 0;
783
+ let quote = "";
784
+ let comment = 0;
785
+ let brace = 0;
786
+ let braceText = "";
787
+ let braceLine = 0;
788
+ for (let i = 0; i < rawLines.length; i++) {
789
+ const line = rawLines[i];
790
+ if (comment === 0 && quote === "" && brace === 0 && text.trim() === "" && line.trimStart().startsWith("&")) continue;
791
+ for (let j = 0; j < line.length; j++) {
792
+ const ch = line[j];
793
+ if (comment > 0) {
794
+ if (ch === "/" && line[j + 1] === "*") {
795
+ comment++;
796
+ j++;
797
+ } else if (ch === "*" && line[j + 1] === "/") {
798
+ comment--;
799
+ j++;
800
+ }
801
+ continue;
802
+ }
803
+ if (brace > 0) {
804
+ if (ch === "{") brace++;
805
+ else if (ch === "}") brace--;
806
+ if (brace === 0) {
807
+ const target = braceText.trim().split(/\s+/)[0] ?? "";
808
+ if (target !== "" && !/^[&\d*]/.test(target)) includes.push({ kind: "include", target, line: braceLine });
809
+ text += " ";
810
+ } else braceText += ch;
811
+ continue;
812
+ }
813
+ if (quote !== "") {
814
+ if (ch === "~") {
815
+ text += " ";
816
+ j++;
817
+ } else if (ch === quote) {
818
+ quote = "";
819
+ text += ch;
820
+ } else text += " ";
821
+ continue;
822
+ }
823
+ if (ch === "/" && line[j + 1] === "*") {
824
+ comment = 1;
825
+ j++;
826
+ continue;
827
+ }
828
+ if (ch === "/" && line[j + 1] === "/") break;
829
+ if (ch === "{") {
830
+ brace = 1;
831
+ braceText = "";
832
+ braceLine = i + 1;
833
+ continue;
834
+ }
835
+ if ((ch === "." || ch === ":") && isSpace(line[j + 1])) {
836
+ const t = text.trim();
837
+ if (t !== "") statements.push({ text: t, line: start, endLine: i + 1, terminator: ch });
838
+ text = "";
839
+ start = 0;
840
+ continue;
841
+ }
842
+ if (ch === '"' || ch === "'") quote = ch;
843
+ if (start === 0 && !isSpace(ch)) start = i + 1;
844
+ text += ch;
845
+ }
846
+ text += " ";
847
+ }
848
+ return { statements, includes };
849
+ }
850
+ var isWordChar = (ch) => /[\w#$%&-]/.test(ch);
851
+ function keyword(word, full, min) {
852
+ return word.length >= min && full.startsWith(word);
853
+ }
854
+ var LONE_BLOCK_WORDS = /* @__PURE__ */ new Set(["DO", "REPEAT", "FINALLY", "GET", "SET"]);
855
+ var TYPE_KINDS = /* @__PURE__ */ new Map([
856
+ ["CLASS", "class"],
857
+ ["INTERFACE", "interface"],
858
+ ["ENUM", "enum"]
859
+ ]);
860
+ var MEMBER_KINDS = /* @__PURE__ */ new Map([
861
+ ["METHOD", "method"],
862
+ ["CONSTRUCTOR", "constructor"],
863
+ ["DESTRUCTOR", "destructor"]
864
+ ]);
865
+ var DEFINE_MODIFIERS = /* @__PURE__ */ new Set(["NEW", "GLOBAL", "SHARED", "PRIVATE", "PROTECTED", "PACKAGE-PRIVATE", "PACKAGE-PROTECTED", "PUBLIC", "STATIC", "SERIALIZABLE", "NON-SERIALIZABLE"]);
866
+ function typeName(word) {
867
+ const dot = word.lastIndexOf(".");
868
+ return dot >= 0 ? word.slice(dot + 1) : word;
869
+ }
870
+ function extractAbl(content, filePath) {
871
+ const spans = new SpanCollector(filePath);
872
+ if (content.includes("\0")) return { symbols: [], imports: [] };
873
+ const rawLines = content.split(/\r?\n/);
874
+ const { statements, includes } = ablStatements(rawLines);
875
+ const imports = [...includes];
876
+ const stack = [];
877
+ let previous = 0;
878
+ const owner = () => {
879
+ for (let k = stack.length - 1; k >= 0; k--) if (stack[k].role === "type") return spans.name(stack[k].index);
880
+ return "";
881
+ };
882
+ const inRoutine = () => stack.some((o) => o.role === "routine");
883
+ for (const st of statements) {
884
+ const words = st.text.split(/\s+/);
885
+ const upper = words.map((w) => w.toUpperCase());
886
+ const w0 = upper[0];
887
+ if (st.terminator === ":") {
888
+ if (words.length === 1 && !LONE_BLOCK_WORDS.has(w0.replace(/\(.*$/, ""))) continue;
889
+ if (keyword(w0, "PROCEDURE", 5)) {
890
+ stack.push({ index: spans.open(words[1] ?? "", "procedure", st.line), role: "routine" });
891
+ } else if (w0 === "FUNCTION") {
892
+ stack.push({ index: spans.open(wordBeforeParen(words[1] ?? "", isWordChar) || (words[1] ?? ""), "function", st.line), role: "routine" });
893
+ } else if (TYPE_KINDS.has(w0)) {
894
+ stack.push({ index: spans.open(typeName(words[1] ?? ""), TYPE_KINDS.get(w0), st.line), role: "type" });
895
+ } else if (MEMBER_KINDS.has(w0)) {
896
+ stack.push({ index: spans.open(wordBeforeParen(st.text, isWordChar), MEMBER_KINDS.get(w0), st.line, owner()), role: "routine" });
897
+ } else {
898
+ stack.push({ index: void 0, role: "block" });
899
+ }
900
+ } else if (w0 === "END") {
901
+ const o = stack.pop();
902
+ if (o) spans.close(o.index, st.endLine);
903
+ } else if (MEMBER_KINDS.has(w0) && owner() !== "" && !inRoutine()) {
904
+ spans.open(wordBeforeParen(st.text, isWordChar), MEMBER_KINDS.get(w0), st.line, owner());
905
+ } else if (keyword(w0, "DEFINE", 3) && !inRoutine()) {
906
+ let k = 1;
907
+ while (k < upper.length && DEFINE_MODIFIERS.has(upper[k])) k++;
908
+ if (upper[k] === "TEMP-TABLE" && words[k + 1] !== void 0) spans.close(spans.open(words[k + 1], "temp_table", st.line, owner()), st.endLine);
909
+ } else if (w0 === "USING" && words[1] !== void 0) {
910
+ imports.push({ kind: "import", target: words[1], line: st.line });
911
+ }
912
+ previous = st.endLine;
913
+ }
914
+ for (const o of stack) spans.close(o.index, previous);
915
+ return { symbols: spans.finish(rawLines), imports };
916
+ }
917
+
918
+ // src/languages/jcl.ts
919
+ init_define_import_meta_env();
920
+ var STATEMENT_RE = /^\/\/(\S*)\s+(\S+)/;
921
+ var DLM_RE = /\bDLM=(?:'([^']{2})'|([^,\s]{2}))/i;
922
+ var MEMBER_RE = /\bMEMBER=([A-Za-z@#$][\w@#$]*)/i;
923
+ function extractJcl(content, filePath) {
924
+ const imports = [];
925
+ const spans = new SpanCollector(filePath);
926
+ if (content.includes("\0")) return { symbols: [], imports };
927
+ const rawLines = content.split(/\r?\n/);
928
+ let job;
929
+ let proc;
930
+ let step;
931
+ let dataDelimiter = "";
932
+ let dataEndsAtStatement = false;
933
+ let previous = 0;
934
+ const endStep = (end) => {
935
+ spans.close(step, end);
936
+ step = void 0;
937
+ };
938
+ const endProc = (end) => {
939
+ endStep(end);
940
+ spans.close(proc, end);
941
+ proc = void 0;
942
+ };
943
+ const endJob = (end) => {
944
+ endProc(end);
945
+ spans.close(job, end);
946
+ job = void 0;
947
+ };
948
+ for (let i = 0; i < rawLines.length; i++) {
949
+ const raw = rawLines[i].slice(0, 72);
950
+ const line = i + 1;
951
+ if (dataDelimiter !== "") {
952
+ if (raw.startsWith(dataDelimiter)) {
953
+ dataDelimiter = "";
954
+ previous = line;
955
+ continue;
956
+ }
957
+ if (!(dataEndsAtStatement && raw.startsWith("//"))) {
958
+ previous = line;
959
+ continue;
960
+ }
961
+ dataDelimiter = "";
962
+ }
963
+ if (!raw.startsWith("//") || raw.startsWith("//*")) continue;
964
+ if (raw.trim() === "//") {
965
+ endJob(previous);
966
+ continue;
967
+ }
968
+ const m = STATEMENT_RE.exec(raw);
969
+ if (!m) continue;
970
+ const name = m[1];
971
+ const op = m[2].toUpperCase();
972
+ const operands = raw.slice(m[0].length).trim();
973
+ if (op === "JOB") {
974
+ endJob(previous);
975
+ job = spans.open(name, "job", line);
976
+ } else if (op === "PROC") {
977
+ endProc(previous);
978
+ proc = spans.open(name, "procedure", line, spans.name(job));
979
+ } else if (op === "PEND") {
980
+ endProc(line);
981
+ } else if (op === "EXEC") {
982
+ endStep(previous);
983
+ if (name !== "") step = spans.open(name, "step", line, spans.name(proc ?? job));
984
+ } else if (op === "INCLUDE") {
985
+ const member = MEMBER_RE.exec(operands);
986
+ if (member) imports.push({ kind: "include", target: member[1], line });
987
+ } else if (op === "DD") {
988
+ const kind = /^(\*|DATA)(?=$|[,\s])/i.exec(operands);
989
+ if (kind) {
990
+ const dlm = DLM_RE.exec(operands);
991
+ dataDelimiter = dlm ? dlm[1] ?? dlm[2] : "/*";
992
+ dataEndsAtStatement = kind[1] === "*" && !dlm;
993
+ }
994
+ }
995
+ previous = line;
996
+ }
997
+ endJob(previous);
998
+ return { symbols: spans.finish(rawLines), imports };
999
+ }
1000
+
1001
+ // src/languages/pli.ts
1002
+ init_define_import_meta_env();
1003
+ var SEQUENCE_FIELD_RE = /^ *\d+ *$/;
1004
+ function hasSequenceField(rawLines) {
1005
+ const long = rawLines.filter((l) => l.length > 72);
1006
+ if (long.length === 0) return false;
1007
+ return long.filter((l) => SEQUENCE_FIELD_RE.test(l.slice(72, 80))).length / long.length >= 0.8;
1008
+ }
1009
+ function pliStatements(rawLines) {
1010
+ const out = [];
1011
+ const margin = hasSequenceField(rawLines);
1012
+ let text = "";
1013
+ let raw = "";
1014
+ let start = 0;
1015
+ let quote = "";
1016
+ let comment = false;
1017
+ for (let i = 0; i < rawLines.length; i++) {
1018
+ const line = margin ? rawLines[i].slice(0, 72) : rawLines[i];
1019
+ for (let j = 0; j < line.length; j++) {
1020
+ const ch = line[j];
1021
+ if (comment) {
1022
+ if (ch === "*" && line[j + 1] === "/") {
1023
+ comment = false;
1024
+ j++;
1025
+ }
1026
+ continue;
1027
+ }
1028
+ if (quote !== "") {
1029
+ raw += ch;
1030
+ if (ch === quote && line[j + 1] === quote) {
1031
+ raw += ch;
1032
+ text += " ";
1033
+ j++;
1034
+ } else if (ch === quote) {
1035
+ quote = "";
1036
+ text += ch;
1037
+ } else text += " ";
1038
+ continue;
1039
+ }
1040
+ if (ch === "/" && line[j + 1] === "*") {
1041
+ comment = true;
1042
+ j++;
1043
+ continue;
1044
+ }
1045
+ if (ch === ";") {
1046
+ const t = text.trim();
1047
+ if (t !== "") out.push({ text: t, raw: raw.trim(), line: start, endLine: i + 1 });
1048
+ text = "";
1049
+ raw = "";
1050
+ start = 0;
1051
+ continue;
1052
+ }
1053
+ if (ch === "'" || ch === '"') quote = ch;
1054
+ if (start === 0 && !/\s/.test(ch)) start = i + 1;
1055
+ text += ch;
1056
+ raw += ch;
1057
+ }
1058
+ text += " ";
1059
+ raw += " ";
1060
+ }
1061
+ return out;
1062
+ }
1063
+ var LABEL_RE = /^(%?)([A-Za-z_@#$][\w@#$]*)\s*:/;
1064
+ var isWordChar2 = (ch) => /[\w@#$%]/.test(ch);
1065
+ var OPENERS = /* @__PURE__ */ new Set(["DO", "BEGIN", "SELECT"]);
1066
+ var INTRODUCERS = /* @__PURE__ */ new Set(["THEN", "ELSE", "OTHERWISE", "WHEN"]);
1067
+ function extractPli(content, filePath) {
1068
+ const imports = [];
1069
+ const spans = new SpanCollector(filePath);
1070
+ if (content.includes("\0")) return { symbols: [], imports };
1071
+ const rawLines = content.split(/\r?\n/);
1072
+ const stack = [];
1073
+ let previous = 0;
1074
+ for (const st of pliStatements(rawLines)) {
1075
+ let rest = st.text;
1076
+ const labels = [];
1077
+ let percent = false;
1078
+ for (let m = LABEL_RE.exec(rest); m !== null; m = LABEL_RE.exec(rest)) {
1079
+ if (m[1] === "%") percent = true;
1080
+ labels.push(m[2]);
1081
+ rest = rest.slice(m[0].length).trimStart();
1082
+ }
1083
+ if (rest.startsWith("%")) percent = true;
1084
+ const words = topLevelWords(rest, isWordChar2).map((w) => w.replace(/^%/, "").toUpperCase());
1085
+ const w0 = words[0] ?? "";
1086
+ const assignment = /^%?[\w@#$]+\s*=/.test(rest);
1087
+ const parent = () => spans.name([...stack].reverse().find((o) => o.named)?.index);
1088
+ if (w0 === "END" && !assignment) {
1089
+ const label = words[1];
1090
+ const at = label === void 0 ? -1 : stack.map((o) => o.labels.some((l) => l.toUpperCase() === label)).lastIndexOf(true);
1091
+ for (const o of stack.splice(at >= 0 ? at : Math.max(0, stack.length - 1))) spans.close(o.index, st.endLine);
1092
+ } else if ((w0 === "PROC" || w0 === "PROCEDURE" || w0 === "PACKAGE") && !assignment) {
1093
+ const index = percent || labels.length === 0 ? void 0 : spans.open(labels[0], w0 === "PACKAGE" ? "package" : "procedure", st.line, parent());
1094
+ stack.push({ labels, index, named: index !== void 0 });
1095
+ } else if (OPENERS.has(w0) && !assignment || words.some((w, k) => INTRODUCERS.has(w) && OPENERS.has(words[k + 1] ?? "")) || w0 === "ON" && words[words.length - 1] === "BEGIN") {
1096
+ stack.push({ labels, index: void 0, named: false });
1097
+ } else if (percent && (w0 === "INCLUDE" || w0 === "XINCLUDE")) {
1098
+ const list = st.raw.replace(/^[^%]*%\s*X?INCLUDE\b/i, "");
1099
+ for (const item of list.split(",")) {
1100
+ const t = item.trim().replace(/^(['"])(.*)\1$/, "$2");
1101
+ const member = /\(([^()]+)\)\s*$/.exec(t);
1102
+ const target = (member ? member[1] : t).trim();
1103
+ if (target !== "") imports.push({ kind: "include", target, line: st.line });
1104
+ }
1105
+ }
1106
+ previous = st.endLine;
1107
+ }
1108
+ for (const o of stack) spans.close(o.index, previous);
1109
+ return { symbols: spans.finish(rawLines), imports };
1110
+ }
1111
+
1112
+ // src/languages/rpg.ts
1113
+ init_define_import_meta_env();
1114
+ var FIXED_SPECS = "HFDICOP";
1115
+ var COMPILE_TIME_DATA_RE = /^\*\*(?:\s|$|CTDATA\b|FTRANS\b|ALTSEQ\b)/i;
1116
+ var DIRECTIVE_RE = /^\/(?:COPY|INCLUDE)\s+(\S+)/i;
1117
+ var NAME_RE = /^[A-Za-z@#$_*][\w@#$]*/;
1118
+ function codeOf2(text) {
1119
+ let out = "";
1120
+ let quote = false;
1121
+ for (let i = 0; i < text.length; i++) {
1122
+ const ch = text[i];
1123
+ if (quote) {
1124
+ if (ch === "'" && text[i + 1] === "'") {
1125
+ out += " ";
1126
+ i++;
1127
+ } else if (ch === "'") {
1128
+ quote = false;
1129
+ out += ch;
1130
+ } else out += " ";
1131
+ continue;
1132
+ }
1133
+ if (ch === "/" && text[i + 1] === "/") break;
1134
+ if (ch === "'") quote = true;
1135
+ out += ch;
1136
+ }
1137
+ return out;
1138
+ }
1139
+ function extractRpg(content, filePath) {
1140
+ const imports = [];
1141
+ const spans = new SpanCollector(filePath);
1142
+ if (content.includes("\0")) return { symbols: [], imports };
1143
+ const rawLines = content.split(/\r?\n/);
1144
+ const fullyFree = /^\*\*FREE\b/i.test(rawLines[0] ?? "");
1145
+ const stack = [];
1146
+ let proc;
1147
+ let longName = "";
1148
+ let text = "";
1149
+ let start = 0;
1150
+ let previous = 0;
1151
+ const closeTo = (end, line) => {
1152
+ const at = stack.map((o) => o.end).lastIndexOf(end);
1153
+ if (at < 0) return;
1154
+ for (const o of stack.splice(at)) spans.close(o.index, line);
1155
+ };
1156
+ const openProc = (name, line) => {
1157
+ closeTo("END-PROC", previous);
1158
+ proc = spans.open(name, "procedure", line);
1159
+ stack.push({ end: "END-PROC", index: proc });
1160
+ };
1161
+ const endProc = (line) => {
1162
+ closeTo("END-PROC", line);
1163
+ proc = void 0;
1164
+ };
1165
+ const inProc = () => stack.some((o) => o.end === "END-PROC");
1166
+ const statement = (t, line, endLine) => {
1167
+ const words = t.split(/\s+/);
1168
+ const w0 = words[0].toUpperCase();
1169
+ const name = NAME_RE.exec(words[1] ?? "")?.[0] ?? "";
1170
+ const upper = words.map((w) => w.toUpperCase());
1171
+ if (w0 === "DCL-PROC") openProc(name, line);
1172
+ else if (w0 === "END-PROC") endProc(endLine);
1173
+ else if (w0 === "BEGSR") stack.push({ end: "ENDSR", index: spans.open(name, "subroutine", line, spans.name(proc)) });
1174
+ else if (w0 === "ENDSR") closeTo("ENDSR", endLine);
1175
+ else if (w0 === "DCL-PR" || w0 === "DCL-DS" || w0 === "DCL-PI") {
1176
+ const end = `END-${w0.slice(4)}`;
1177
+ const single = upper.includes(end) || w0 === "DCL-DS" && upper.some((w) => w.startsWith("LIKEDS") || w.startsWith("LIKEREC"));
1178
+ const emit = w0 === "DCL-PR" || w0 === "DCL-DS" && !inProc();
1179
+ const index = emit && name !== "*N" ? spans.open(name, w0 === "DCL-PR" ? "prototype" : "data_structure", line, "") : void 0;
1180
+ if (single) spans.close(index, endLine);
1181
+ else stack.push({ end, index });
1182
+ } else if (w0 === "END-PR" || w0 === "END-DS" || w0 === "END-PI") closeTo(w0, endLine);
1183
+ else if ((w0 === "DCL-S" || w0 === "DCL-C" || w0 === "DCL-F") && !inProc()) {
1184
+ spans.close(spans.open(name, w0 === "DCL-S" ? "variable" : w0 === "DCL-C" ? "constant" : "file", line), endLine);
1185
+ } else if (w0 === "EXEC" && upper[1] === "SQL" && upper[2] === "INCLUDE" && words[3] !== void 0) {
1186
+ imports.push({ kind: "include", target: words[3].replace(/^['"]|['"]$/g, ""), line });
1187
+ }
1188
+ };
1189
+ const fixed = (raw, line) => {
1190
+ const spec = raw[5].toUpperCase();
1191
+ if (spec === "P") {
1192
+ const field = raw.slice(6, 21).trim();
1193
+ if (field.endsWith("...")) {
1194
+ longName += field.slice(0, -3);
1195
+ return;
1196
+ }
1197
+ const name = longName + field;
1198
+ longName = "";
1199
+ const be = raw.slice(23, 24).toUpperCase();
1200
+ if (be === "B") openProc(name, line);
1201
+ else if (be === "E") endProc(line);
1202
+ } else if (spec === "C") {
1203
+ const opcode = raw.slice(25, 35).trim().toUpperCase().replace(/\(.*$/, "");
1204
+ if (opcode === "BEGSR") stack.push({ end: "ENDSR", index: spans.open(raw.slice(11, 25).trim(), "subroutine", line, spans.name(proc)) });
1205
+ else if (opcode === "ENDSR") closeTo("ENDSR", line);
1206
+ }
1207
+ };
1208
+ for (let i = fullyFree ? 1 : 0; i < rawLines.length; i++) {
1209
+ const raw = rawLines[i];
1210
+ const line = i + 1;
1211
+ let code;
1212
+ if (fullyFree) {
1213
+ if (COMPILE_TIME_DATA_RE.test(raw)) break;
1214
+ code = raw;
1215
+ } else {
1216
+ if (COMPILE_TIME_DATA_RE.test(raw)) break;
1217
+ if (raw.length < 7 || raw[6] === "*") continue;
1218
+ if (FIXED_SPECS.includes(raw[5].toUpperCase())) {
1219
+ fixed(raw, line);
1220
+ previous = line;
1221
+ continue;
1222
+ }
1223
+ code = raw.slice(7, 80);
1224
+ }
1225
+ const trimmed = code.trimStart();
1226
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
1227
+ const d = DIRECTIVE_RE.exec(trimmed);
1228
+ if (d) imports.push({ kind: "include", target: d[1].replace(/^['"]|['"]$/g, ""), line });
1229
+ continue;
1230
+ }
1231
+ const c = codeOf2(code);
1232
+ let from = 0;
1233
+ for (let k = c.indexOf(";"); k >= 0; k = c.indexOf(";", from)) {
1234
+ const part = c.slice(from, k);
1235
+ if (start === 0 && part.trim() !== "") start = line;
1236
+ text += part;
1237
+ const t = text.trim();
1238
+ if (t !== "") statement(t, start, line);
1239
+ text = "";
1240
+ start = 0;
1241
+ from = k + 1;
1242
+ previous = line;
1243
+ }
1244
+ const tail = c.slice(from);
1245
+ if (start === 0 && tail.trim() !== "") start = line;
1246
+ text += `${tail} `;
1247
+ }
1248
+ for (const o of stack) spans.close(o.index, previous);
1249
+ return { symbols: spans.finish(rawLines), imports };
1250
+ }
1251
+
1252
+ // src/languages/sas.ts
1253
+ init_define_import_meta_env();
1254
+ var DATALINES_RE = /^(?:datalines|cards|lines|parmcards)(4?)$/i;
1255
+ function sasStatements(rawLines) {
1256
+ const out = [];
1257
+ let text = "";
1258
+ let raw = "";
1259
+ let start = 0;
1260
+ let quote = "";
1261
+ let blockComment = false;
1262
+ let commentStatement = false;
1263
+ let dataMode = 0;
1264
+ for (let i = 0; i < rawLines.length; i++) {
1265
+ const line = rawLines[i];
1266
+ if (dataMode !== 0) {
1267
+ if (dataMode === 4 ? line.trimStart().startsWith(";;;;") : line.includes(";")) dataMode = 0;
1268
+ continue;
1269
+ }
1270
+ for (let j = 0; j < line.length; j++) {
1271
+ const ch = line[j];
1272
+ if (blockComment) {
1273
+ if (ch === "*" && line[j + 1] === "/") {
1274
+ blockComment = false;
1275
+ j++;
1276
+ }
1277
+ continue;
1278
+ }
1279
+ if (ch === "/" && line[j + 1] === "*" && quote === "") {
1280
+ blockComment = true;
1281
+ j++;
1282
+ continue;
1283
+ }
1284
+ if (commentStatement) {
1285
+ if (ch === ";") commentStatement = false;
1286
+ continue;
1287
+ }
1288
+ if (quote !== "") {
1289
+ raw += ch;
1290
+ if (ch === quote && line[j + 1] === quote) {
1291
+ raw += ch;
1292
+ text += " ";
1293
+ j++;
1294
+ } else if (ch === quote) {
1295
+ quote = "";
1296
+ text += ch;
1297
+ } else text += " ";
1298
+ continue;
1299
+ }
1300
+ if (start === 0 && (ch === "*" || ch === "%" && line[j + 1] === "*")) {
1301
+ commentStatement = true;
1302
+ continue;
1303
+ }
1304
+ if (ch === ";") {
1305
+ const t = text.trim();
1306
+ if (t !== "") {
1307
+ out.push({ text: t, raw: raw.trim(), line: start, endLine: i + 1 });
1308
+ const m = DATALINES_RE.exec(t);
1309
+ if (m) {
1310
+ dataMode = m[1] === "4" ? 4 : 1;
1311
+ break;
1312
+ }
1313
+ }
1314
+ text = "";
1315
+ raw = "";
1316
+ start = 0;
1317
+ continue;
1318
+ }
1319
+ if (ch === "'" || ch === '"') quote = ch;
1320
+ if (start === 0 && !/\s/.test(ch)) start = i + 1;
1321
+ text += ch;
1322
+ raw += ch;
1323
+ }
1324
+ text += " ";
1325
+ raw += " ";
1326
+ }
1327
+ return out;
1328
+ }
1329
+ function nameAfter(text, keywordLength) {
1330
+ const rest = text.slice(keywordLength).trimStart();
1331
+ let end = 0;
1332
+ while (end < rest.length && !/[\s(/;]/.test(rest[end])) end++;
1333
+ return rest.slice(0, end);
1334
+ }
1335
+ function includeTarget(raw) {
1336
+ const rest = raw.replace(/^%inc(?:lude)?\b/i, "").trimStart();
1337
+ const q = rest[0];
1338
+ if (q === "'" || q === '"') {
1339
+ const end2 = rest.indexOf(q, 1);
1340
+ return end2 > 0 ? rest.slice(1, end2) : "";
1341
+ }
1342
+ let end = 0;
1343
+ while (end < rest.length && !/[\s/;]/.test(rest[end])) end++;
1344
+ return rest.slice(0, end);
1345
+ }
1346
+ function extractSas(content, filePath) {
1347
+ const imports = [];
1348
+ const spans = new SpanCollector(filePath);
1349
+ if (content.includes("\0")) return { symbols: [], imports };
1350
+ const rawLines = content.split(/\r?\n/);
1351
+ const statements = sasStatements(rawLines);
1352
+ const macros = [];
1353
+ let step;
1354
+ let previous = 0;
1355
+ const endStep = (end) => {
1356
+ spans.close(step, end);
1357
+ step = void 0;
1358
+ };
1359
+ for (const st of statements) {
1360
+ const keyword2 = (/^%?[A-Za-z_]\w*/.exec(st.text)?.[0] ?? "").toLowerCase();
1361
+ if (keyword2 === "%macro") {
1362
+ endStep(previous);
1363
+ const parent = spans.name(macros[macros.length - 1]);
1364
+ macros.push(spans.open(nameAfter(st.text, keyword2.length), "macro", st.line, parent));
1365
+ } else if (keyword2 === "%mend") {
1366
+ endStep(previous);
1367
+ spans.close(macros.pop(), st.endLine);
1368
+ } else if (keyword2 === "data") {
1369
+ endStep(previous);
1370
+ const name = nameAfter(st.text, keyword2.length);
1371
+ if (name !== "" && name.toLowerCase() !== "_null_") step = spans.open(name, "data_step", st.line, spans.name(macros[macros.length - 1]));
1372
+ } else if (keyword2 === "proc") {
1373
+ endStep(previous);
1374
+ } else if (keyword2 === "run" || keyword2 === "quit") {
1375
+ endStep(st.endLine);
1376
+ } else if (keyword2 === "%include" || keyword2 === "%inc") {
1377
+ const target = includeTarget(st.raw);
1378
+ if (target !== "") imports.push({ kind: "include", target, line: st.line });
1379
+ }
1380
+ previous = st.endLine;
1381
+ }
1382
+ endStep(previous);
1383
+ for (const m of macros) spans.close(m, previous);
1384
+ return { symbols: spans.finish(rawLines), imports };
1385
+ }
1386
+
1387
+ // src/languages/groovy.ts
1388
+ init_define_import_meta_env();
1389
+
1390
+ // src/languages/brace_engine.ts
1391
+ init_define_import_meta_env();
1392
+ var MAX_SYMBOLS4 = 1e4;
1393
+ var MAX_NAME_LENGTH2 = 200;
1394
+ var PENDING_MAX_LINES = 12;
1395
+ var HEADER_MAX_LINES = 12;
1396
+ var HEADER_MAX_CHARS = 2e3;
1397
+ function blankText(s) {
1398
+ return s.replace(/[^\r\n]/g, " ");
1399
+ }
1400
+ function nestedCommentEnd(content, from, open, close) {
1401
+ let depth = 0;
1402
+ let i = from;
1403
+ while (i < content.length) {
1404
+ if (content.startsWith(open, i)) {
1405
+ depth++;
1406
+ i += open.length;
1407
+ } else if (content.startsWith(close, i)) {
1408
+ depth--;
1409
+ i += close.length;
1410
+ if (depth === 0) return i;
1411
+ } else {
1412
+ i++;
1413
+ }
1414
+ }
1415
+ return content.length;
1416
+ }
1417
+ function maskSource(content, opts) {
1418
+ const parts = [];
1419
+ let keepFrom = 0;
1420
+ const blank = (a, b) => {
1421
+ parts.push(content.slice(keepFrom, a), blankText(content.slice(a, b)));
1422
+ keepFrom = b;
1423
+ };
1424
+ const n = content.length;
1425
+ let i = 0;
1426
+ if (opts.shebang === true && content.startsWith("#!")) {
1427
+ const e = content.indexOf("\n");
1428
+ i = e < 0 ? n : e;
1429
+ blank(0, i);
1430
+ }
1431
+ while (i < n) {
1432
+ const c = content[i];
1433
+ if (opts.lineComments.some((p) => content.startsWith(p, i))) {
1434
+ const e = content.indexOf("\n", i);
1435
+ const end = e < 0 ? n : e;
1436
+ blank(i, end);
1437
+ i = end;
1438
+ continue;
1439
+ }
1440
+ const bc = opts.blockComment;
1441
+ if (bc !== null && content.startsWith(bc[0], i)) {
1442
+ let end;
1443
+ if (opts.nestedBlockComments === true) {
1444
+ end = nestedCommentEnd(content, i, bc[0], bc[1]);
1445
+ } else {
1446
+ const e = content.indexOf(bc[1], i + bc[0].length);
1447
+ end = e < 0 ? n : e + bc[1].length;
1448
+ }
1449
+ blank(i, end);
1450
+ i = end;
1451
+ continue;
1452
+ }
1453
+ if (opts.slashyStrings === true) {
1454
+ const slashy = matchGroovySlashy(content, i);
1455
+ if (slashy !== null) {
1456
+ blank(slashy.bodyStart, slashy.bodyEnd);
1457
+ i = slashy.end;
1458
+ continue;
1459
+ }
1460
+ }
1461
+ if (opts.tripleQuotes === true && (content.startsWith('"""', i) || content.startsWith("'''", i))) {
1462
+ const q = content.slice(i, i + 3);
1463
+ let j = i + 3;
1464
+ while (j < n && !content.startsWith(q, j)) j += content[j] === "\\" ? 2 : 1;
1465
+ const closed = j < n;
1466
+ blank(i + 3, Math.min(j, n));
1467
+ i = closed ? j + 3 : n;
1468
+ continue;
1469
+ }
1470
+ if (opts.quotes.includes(c)) {
1471
+ let j = i + 1;
1472
+ while (j < n) {
1473
+ const ch = content[j];
1474
+ if (ch === "\\") {
1475
+ j += 2;
1476
+ continue;
1477
+ }
1478
+ if (ch === c || ch === "\n") break;
1479
+ j++;
1480
+ }
1481
+ const end = Math.min(j, n);
1482
+ blank(i + 1, end);
1483
+ i = end < n && content[end] === c ? end + 1 : end;
1484
+ continue;
1485
+ }
1486
+ i++;
1487
+ }
1488
+ parts.push(content.slice(keepFrom));
1489
+ return parts.join("");
1490
+ }
1491
+ function isIdentChar(ch) {
1492
+ return ch !== void 0 && /[\w$]/.test(ch);
1493
+ }
1494
+ function trailingIdentifier(s) {
1495
+ let start = s.length;
1496
+ while (start > 0 && (isIdentChar(s[start - 1]) || s[start - 1] === ":" || s[start - 1] === "~")) start--;
1497
+ const seg = s.slice(start);
1498
+ const parts = seg.split("::");
1499
+ const name = parts.pop() ?? "";
1500
+ if (!/^~?[A-Za-z_$][\w$]*$/.test(name) || parts.some((p) => !/^[A-Za-z_]\w*$/.test(p))) return null;
1501
+ return { name, qualifier: parts.join("::") };
1502
+ }
1503
+ function trimEndChars(s, chars) {
1504
+ let end = s.length;
1505
+ while (end > 0 && chars.includes(s[end - 1])) end--;
1506
+ return s.slice(0, end);
1507
+ }
1508
+ function withoutTrailingBrace(code) {
1509
+ return code.endsWith("{") ? code.slice(0, -1).trimEnd() : code;
1510
+ }
1511
+ function rawQuoted(ctx, at) {
1512
+ const start = ctx.codeOffset + at;
1513
+ const q = ctx.raw[start];
1514
+ if (q !== '"' && q !== "'") return "";
1515
+ const end = ctx.raw.indexOf(q, start + 1);
1516
+ return end < 0 ? "" : ctx.raw.slice(start + 1, end).trim();
1517
+ }
1518
+ function quotedTarget(raw) {
1519
+ const m = /["'<]([^"'<>]+)["'>]/.exec(raw);
1520
+ return m === null ? null : m[1].trim();
1521
+ }
1522
+ var C_NOT_A_TYPE = /* @__PURE__ */ new Set([
1523
+ "if",
1524
+ "for",
1525
+ "while",
1526
+ "switch",
1527
+ "return",
1528
+ "else",
1529
+ "do",
1530
+ "sizeof",
1531
+ "case",
1532
+ "new",
1533
+ "delete",
1534
+ "throw",
1535
+ "catch",
1536
+ "typedef",
1537
+ "using",
1538
+ "goto",
1539
+ "static_assert",
1540
+ "alignof",
1541
+ "decltype",
1542
+ "defined",
1543
+ "foreach",
1544
+ "synchronized",
1545
+ "assert",
1546
+ "emit",
1547
+ "await",
1548
+ "yield",
1549
+ "in",
1550
+ "not"
1551
+ ]);
1552
+ var C_PREFIX_RE = /^[A-Za-z_][\w\s*&:<>,[\].]*$/;
1553
+ function cFunctionHeader(code) {
1554
+ const paren = code.indexOf("(");
1555
+ if (paren <= 0) return null;
1556
+ const prefix = code.slice(0, paren).trimEnd();
1557
+ if (!C_PREFIX_RE.test(prefix) || prefix.replace(/::/g, "").includes(":")) return null;
1558
+ const id = trailingIdentifier(prefix);
1559
+ if (id === null) return null;
1560
+ const typeText = prefix.slice(0, prefix.length - (id.qualifier === "" ? id.name.length : id.qualifier.length + 2 + id.name.length)).trim();
1561
+ if (typeText === "" || typeText.endsWith(".") || typeText.endsWith(",")) return null;
1562
+ const first = typeText.split(/[\s*&<>,[\]]/, 1)[0];
1563
+ if (C_NOT_A_TYPE.has(first) || C_NOT_A_TYPE.has(id.name)) return null;
1564
+ return { ...id, typeText };
1565
+ }
1566
+ function scanBraceLanguage(content, filePath, lang) {
1567
+ const rawLines = content.split(/\r?\n/);
1568
+ const masked = maskSource(content, lang.lex).split("\n");
1569
+ const items = [];
1570
+ const imports = [];
1571
+ const frames = [];
1572
+ let depth = 0;
1573
+ let pending = null;
1574
+ let continuation = false;
1575
+ const close = (index, line) => {
1576
+ const it = items[index];
1577
+ it.lineEnd = Math.max(it.lineStart, line);
1578
+ };
1579
+ for (let i = 0; i < masked.length; i++) {
1580
+ const code = masked[i];
1581
+ const raw = rawLines[i] ?? "";
1582
+ const trimmed = code.trim();
1583
+ const directive = lang.preprocessor === true && (continuation || trimmed.startsWith("#"));
1584
+ if (directive) {
1585
+ continuation = trimmed.endsWith("\\");
1586
+ const target = lang.importOf?.(trimmed, raw) ?? null;
1587
+ if (target !== null && target !== "") imports.push({ kind: "import", target, line: i + 1 });
1588
+ continue;
1589
+ }
1590
+ if (trimmed !== "") {
1591
+ if (lang.keywordClose?.test(trimmed) === true) {
1592
+ let k = frames.length - 1;
1593
+ while (k >= 0 && !frames[k].keyword) k--;
1594
+ if (k >= 0) {
1595
+ close(frames[k].item, i + 1);
1596
+ frames.length = k;
1597
+ pending = null;
1598
+ }
1599
+ continue;
1600
+ }
1601
+ const target = lang.importOf?.(trimmed, raw) ?? null;
1602
+ if (target !== null && target !== "") imports.push({ kind: "import", target, line: i + 1 });
1603
+ const top = frames[frames.length - 1];
1604
+ const topItem = top !== void 0 && top.item >= 0 ? items[top.item] : void 0;
1605
+ const scope = top === void 0 ? "top" : topItem === void 0 ? "block" : topItem.container ? "container" : "function";
1606
+ let parentIdx = -1;
1607
+ for (let f = frames.length - 1; f >= 0 && parentIdx < 0; f--) {
1608
+ const idx = frames[f].item;
1609
+ if (idx >= 0 && items[idx].container) parentIdx = idx;
1610
+ }
1611
+ const parent = parentIdx >= 0 ? items[parentIdx] : void 0;
1612
+ const ctx = {
1613
+ scope,
1614
+ insideFunction: frames.some((f) => f.item >= 0 && !items[f.item].container),
1615
+ parent: parent?.name ?? "",
1616
+ parentKind: parent?.kind ?? "",
1617
+ raw,
1618
+ codeOffset: code.length - code.trimStart().length,
1619
+ header: () => headerFrom(masked, i)
1620
+ };
1621
+ const inHeader = pending !== null && pending.parens > 0;
1622
+ const d = items.length < MAX_SYMBOLS4 && !inHeader ? lang.match(trimmed, ctx) : null;
1623
+ if (d !== null && d.name.length <= MAX_NAME_LENGTH2 && (d.name !== "" || d.nameAfterClose === true)) {
1624
+ pending = null;
1625
+ items.push({
1626
+ name: d.name,
1627
+ kind: d.kind,
1628
+ lineStart: i + 1,
1629
+ lineEnd: i + 1,
1630
+ parent: d.parent ?? ctx.parent,
1631
+ container: d.container === true,
1632
+ nameAfterClose: d.nameAfterClose === true
1633
+ });
1634
+ const idx = items.length - 1;
1635
+ if (d.end === "brace") pending = { item: idx, depth, line: i, parens: 0, dropPrototype: d.dropPrototype === true };
1636
+ else if (d.end === "keyword") frames.push({ item: idx, keyword: true, depth });
1637
+ }
1638
+ }
1639
+ for (let c = 0; c < code.length; c++) {
1640
+ const ch = code.charCodeAt(c);
1641
+ if (ch === 123) {
1642
+ depth++;
1643
+ if (pending !== null && pending.depth === depth - 1) {
1644
+ frames.push({ item: pending.item, keyword: false, depth });
1645
+ pending = null;
1646
+ } else {
1647
+ frames.push({ item: -1, keyword: false, depth });
1648
+ }
1649
+ } else if (ch === 125) {
1650
+ const top = frames[frames.length - 1];
1651
+ if (top !== void 0 && !top.keyword && top.depth === depth) {
1652
+ frames.pop();
1653
+ if (top.item >= 0) {
1654
+ close(top.item, i + 1);
1655
+ const it = items[top.item];
1656
+ if (it.nameAfterClose && it.name === "") it.name = /^[\s*]*([A-Za-z_]\w*)/.exec(code.slice(c + 1))?.[1] ?? "";
1657
+ }
1658
+ }
1659
+ depth = Math.max(0, depth - 1);
1660
+ if (pending !== null && depth < pending.depth) pending = null;
1661
+ } else if (ch === 40 && pending !== null) {
1662
+ pending.parens++;
1663
+ } else if (ch === 41 && pending !== null) {
1664
+ pending.parens = Math.max(0, pending.parens - 1);
1665
+ } else if (ch === 59 && pending !== null && depth === pending.depth && pending.parens === 0) {
1666
+ close(pending.item, i + 1);
1667
+ if (pending.dropPrototype) items[pending.item].name = "";
1668
+ pending = null;
1669
+ }
1670
+ }
1671
+ if (pending !== null && i - pending.line >= PENDING_MAX_LINES) pending = null;
1672
+ }
1673
+ const symbols = items.filter((it) => it.name !== "").map((it) => ({
1674
+ filePath,
1675
+ name: it.name,
1676
+ kind: it.kind,
1677
+ lineStart: it.lineStart,
1678
+ lineEnd: it.lineEnd,
1679
+ body: rawLines.slice(it.lineStart - 1, it.lineEnd).join("\n"),
1680
+ docstring: lang.docComments === true ? precedingDocComment(rawLines, it.lineStart, "c") : "",
1681
+ parent: it.parent
1682
+ }));
1683
+ return { symbols, imports };
1684
+ }
1685
+ function headerFrom(masked, from) {
1686
+ let s = "";
1687
+ for (let j = from; j < masked.length && j < from + HEADER_MAX_LINES; j++) {
1688
+ const t = masked[j];
1689
+ const cut = t.search(/[{;]/);
1690
+ s += ` ${cut < 0 ? t : t.slice(0, cut)}`;
1691
+ if (cut >= 0 || s.length > HEADER_MAX_CHARS) break;
1692
+ }
1693
+ return s.trim();
1694
+ }
1695
+ function stripLeadingWords(code, words, annotations) {
1696
+ let i = 0;
1697
+ for (; ; ) {
1698
+ while (i < code.length && /\s/.test(code[i])) i++;
1699
+ if (annotations && code[i] === "@" && /[A-Za-z_]/.test(code[i + 1] ?? "") && !code.startsWith("@interface", i)) {
1700
+ i++;
1701
+ while (i < code.length && (isIdentChar(code[i]) || code[i] === ".")) i++;
1702
+ let j2 = i;
1703
+ while (j2 < code.length && code[j2] === " ") j2++;
1704
+ if (code[j2] === "(") {
1705
+ let d = 0;
1706
+ for (; j2 < code.length; j2++) {
1707
+ if (code[j2] === "(") d++;
1708
+ else if (code[j2] === ")" && --d === 0) break;
1709
+ }
1710
+ i = j2 + 1;
1711
+ }
1712
+ continue;
1713
+ }
1714
+ let j = i;
1715
+ while (j < code.length && (isIdentChar(code[j]) || code[j] === "-")) j++;
1716
+ if (j > i && words.has(code.slice(i, j)) && (j === code.length || /\s/.test(code[j]))) {
1717
+ i = j;
1718
+ continue;
1719
+ }
1720
+ return code.slice(i);
1721
+ }
1722
+ }
1723
+
1724
+ // src/languages/groovy.ts
1725
+ var MODIFIERS = /* @__PURE__ */ new Set([
1726
+ "public",
1727
+ "private",
1728
+ "protected",
1729
+ "static",
1730
+ "final",
1731
+ "abstract",
1732
+ "sealed",
1733
+ "non-sealed",
1734
+ "strictfp",
1735
+ "synchronized",
1736
+ "transient",
1737
+ "volatile",
1738
+ "native",
1739
+ "default"
1740
+ ]);
1741
+ var PRIMITIVES = /* @__PURE__ */ new Set(["void", "boolean", "byte", "char", "short", "int", "long", "float", "double", "def", "var"]);
1742
+ var TYPE_DECL_RE = /^(class|interface|trait|enum|record|@interface)\s+([A-Za-z_]\w*)/;
1743
+ var TYPE_KINDS2 = /* @__PURE__ */ new Set(["class", "enum", "record"]);
1744
+ function isReturnType(typeText) {
1745
+ const first = typeText.split(/[\s<[]/, 1)[0];
1746
+ if (PRIMITIVES.has(first)) return true;
1747
+ const last = first.split(".").pop() ?? "";
1748
+ return /^[A-Z]/.test(last);
1749
+ }
1750
+ function matchGroovy(code, ctx) {
1751
+ const s = stripLeadingWords(code, MODIFIERS, true);
1752
+ const at = code.length - s.length;
1753
+ if (ctx.scope === "top" || ctx.scope === "container") {
1754
+ const t = TYPE_DECL_RE.exec(s);
1755
+ if (t !== null) return { name: t[2], kind: t[1] === "@interface" ? "annotation" : t[1], container: true, end: "brace" };
1756
+ const member = ctx.scope === "container" ? "method" : "function";
1757
+ const spock = /^def\s+(?=["'])/.exec(s);
1758
+ if (spock !== null) {
1759
+ const name = rawQuoted(ctx, at + spock[0].length);
1760
+ return name === "" ? null : { name, kind: member, end: "brace" };
1761
+ }
1762
+ if (ctx.scope === "container" && TYPE_KINDS2.has(ctx.parentKind) && s.startsWith(ctx.parent) && /^\s*\(/.test(s.slice(ctx.parent.length))) {
1763
+ return { name: ctx.parent, kind: "constructor", end: "brace" };
1764
+ }
1765
+ const fn = cFunctionHeader(s);
1766
+ if (fn !== null && fn.qualifier === "" && isReturnType(fn.typeText)) return { name: fn.name, kind: member, end: "brace" };
1767
+ }
1768
+ if (ctx.insideFunction) return null;
1769
+ const stage = /^stage\s*\(\s*(?=["'])/.exec(s);
1770
+ if (stage !== null) {
1771
+ const name = rawQuoted(ctx, at + stage[0].length);
1772
+ return name === "" ? null : { name, kind: "stage", container: true, end: "brace" };
1773
+ }
1774
+ const task = /^task\s+([A-Za-z_]\w*)/.exec(s);
1775
+ if (task !== null) return { name: task[1], kind: "task", end: "brace" };
1776
+ const reg = /^tasks\s*\.\s*(?:register|create)\s*\(\s*(?=["'])/.exec(s);
1777
+ if (reg !== null) {
1778
+ const name = rawQuoted(ctx, at + reg[0].length);
1779
+ return name === "" ? null : { name, kind: "task", end: s.includes("{") ? "brace" : "line" };
1780
+ }
1781
+ return null;
1782
+ }
1783
+ var GROOVY = {
1784
+ lex: { lineComments: ["//"], blockComment: ["/*", "*/"], quotes: `"'`, tripleQuotes: true, shebang: true, slashyStrings: true },
1785
+ match: matchGroovy,
1786
+ importOf: (code) => /^import\s+(?:static\s+)?([\w.]+(?:\.\*)?)/.exec(code)?.[1] ?? null,
1787
+ docComments: true
1788
+ };
1789
+ function extractGroovy(content, filePath) {
1790
+ return scanBraceLanguage(content, filePath, GROOVY);
1791
+ }
1792
+
1793
+ // src/languages/objc.ts
1794
+ init_define_import_meta_env();
1795
+ var CONTAINER_RE = /^@(interface|implementation|protocol)\s+([A-Za-z_]\w*)[ \t]*(\([ \t]*(?:([A-Za-z_]\w*)[ \t]*)?\))?/;
1796
+ var NS_ENUM_RE = /^(?:typedef\s+)?NS_(?:ENUM|OPTIONS|CLOSED_ENUM|ERROR_ENUM)\s*\([^,()]*,\s*([A-Za-z_]\w*)\s*\)/;
1797
+ var TYPEDEF_TAG_RE = /^typedef\s+(struct|enum|union)(?:\s+([A-Za-z_]\w*))?$/;
1798
+ var TYPE_RE = /^(struct|union|enum|class|namespace)\s+(?:class\s+)?([A-Za-z_]\w*)(?:\s*:[^;{]*)?$/;
1799
+ function skipParens(s, i) {
1800
+ if (s[i] !== "(") return i;
1801
+ let d = 0;
1802
+ for (; i < s.length; i++) {
1803
+ if (s[i] === "(") d++;
1804
+ else if (s[i] === ")" && --d === 0) return i + 1;
1805
+ }
1806
+ return i;
1807
+ }
1808
+ function skipSpace(s, i) {
1809
+ while (i < s.length && /\s/.test(s[i])) i++;
1810
+ return i;
1811
+ }
1812
+ function readIdent(s, i) {
1813
+ let j = i;
1814
+ while (j < s.length && /\w/.test(s[j])) j++;
1815
+ return /^[A-Za-z_]/.test(s.slice(i, j)) ? s.slice(i, j) : "";
1816
+ }
1817
+ function selectorOf(header) {
1818
+ let i = skipSpace(header, 1);
1819
+ i = skipSpace(header, skipParens(header, i));
1820
+ const parts = [];
1821
+ for (; ; ) {
1822
+ const word = readIdent(header, i);
1823
+ const afterWord = skipSpace(header, i + word.length);
1824
+ if (header[afterWord] === ":") {
1825
+ parts.push(`${word}:`);
1826
+ i = skipSpace(header, skipParens(header, skipSpace(header, afterWord + 1)));
1827
+ i = skipSpace(header, i + readIdent(header, i).length);
1828
+ continue;
1829
+ }
1830
+ if (parts.length === 0) return word;
1831
+ return parts.join("");
1832
+ }
1833
+ }
1834
+ function propertyName(code) {
1835
+ const body = code.slice("@property".length);
1836
+ const afterAttrs = skipParens(body, skipSpace(body, 0));
1837
+ const text = body.slice(afterAttrs, body.includes(";") ? body.indexOf(";") : body.length);
1838
+ const block = /\(\s*\^\s*([A-Za-z_]\w*)\s*\)/.exec(text);
1839
+ if (block !== null) return block[1];
1840
+ const words = text.replace(/\([^()]*\)/g, " ").split(/[\s*]+/).filter((w) => w !== "");
1841
+ while (words.length > 2 && /^[A-Z][A-Z0-9_]+$/.test(words[words.length - 1])) words.pop();
1842
+ return trailingIdentifier(words[words.length - 1] ?? "")?.name ?? "";
1843
+ }
1844
+ function matchObjc(code, ctx) {
1845
+ if (code.startsWith("@property")) {
1846
+ if (ctx.scope !== "container") return null;
1847
+ const name = propertyName(code);
1848
+ return name === "" ? null : { name, kind: "property", end: "line" };
1849
+ }
1850
+ if (code.startsWith("@")) {
1851
+ if (ctx.scope !== "top") return null;
1852
+ const m = CONTAINER_RE.exec(code);
1853
+ if (m === null) return null;
1854
+ if (m[1] === "protocol" && /^[\s\w,]*;/.test(code.slice("@protocol".length))) return null;
1855
+ const kind = m[3] === void 0 ? m[1] : m[4] === void 0 ? "extension" : "category";
1856
+ return { name: m[2], kind, container: true, end: "keyword" };
1857
+ }
1858
+ if (code.startsWith("-") || code.startsWith("+")) {
1859
+ if (ctx.scope !== "container" || !/^[-+]\s*\(/.test(code)) return null;
1860
+ const name = selectorOf(ctx.header());
1861
+ return name === "" ? null : { name, kind: "method", end: "brace" };
1862
+ }
1863
+ if (ctx.scope === "function" || ctx.scope === "block") return null;
1864
+ const ns = NS_ENUM_RE.exec(code);
1865
+ if (ns !== null) return { name: ns[1], kind: "enum", end: "brace" };
1866
+ const head = withoutTrailingBrace(code);
1867
+ const td = TYPEDEF_TAG_RE.exec(head);
1868
+ if (td !== null) return { name: td[2] ?? "", kind: td[1], end: "brace", nameAfterClose: td[2] === void 0 };
1869
+ const t = TYPE_RE.exec(head);
1870
+ if (t !== null) return { name: t[2], kind: t[1], container: t[1] === "class" || t[1] === "struct" || t[1] === "namespace", end: "brace" };
1871
+ const fn = cFunctionHeader(code);
1872
+ if (fn !== null) return { name: fn.name, kind: "function", end: "brace", dropPrototype: true, ...fn.qualifier === "" ? {} : { parent: fn.qualifier } };
1873
+ return null;
1874
+ }
1875
+ function importOf(code, raw) {
1876
+ if (/^#\s*(?:import|include)\b/.test(code)) return quotedTarget(raw);
1877
+ return /^@import\s+([\w.]+)/.exec(code)?.[1] ?? null;
1878
+ }
1879
+ var OBJC = {
1880
+ lex: { lineComments: ["//"], blockComment: ["/*", "*/"], quotes: `"'` },
1881
+ match: matchObjc,
1882
+ keywordClose: /^@end\b/,
1883
+ preprocessor: true,
1884
+ importOf,
1885
+ docComments: true
1886
+ };
1887
+ function extractObjc(content, filePath) {
1888
+ return scanBraceLanguage(content, filePath, OBJC);
1889
+ }
1890
+
1891
+ // src/languages/perl.ts
1892
+ init_define_import_meta_env();
1893
+ var MAX_SYMBOLS5 = 1e4;
1894
+ var SUB_RE = /^\s*sub\s+([A-Za-z_][\w:']*)/;
1895
+ var PACKAGE_RE = /^\s*package\s+([A-Za-z_][\w:]*)/;
1896
+ var HEREDOC_RE = /<<(~?)(?:"([^"\n]*)"|'([^'\n]*)'|([A-Za-z_]\w*))/g;
1897
+ var Q_OPEN_RE = /(?<![\w$@%&])q[qwrx]?\s*([{([<])/g;
1898
+ var CLOSER = { "{": "}", "(": ")", "[": "]", "<": ">" };
1899
+ function stripComment(line) {
1900
+ let quote = "";
1901
+ for (let i = 0; i < line.length; i++) {
1902
+ const c = line[i];
1903
+ if (quote !== "") {
1904
+ if (c === "\\") i++;
1905
+ else if (c === quote) quote = "";
1906
+ } else if (c === '"' || c === "'") {
1907
+ quote = c;
1908
+ } else if (c === "#" && line[i - 1] !== "$") {
1909
+ return line.slice(0, i);
1910
+ }
1911
+ }
1912
+ return line;
1913
+ }
1914
+ function maskStrings(code) {
1915
+ const out = code.split("");
1916
+ let quote = "";
1917
+ for (let i = 0; i < code.length; i++) {
1918
+ const c = code[i];
1919
+ if (quote !== "") {
1920
+ out[i] = " ";
1921
+ if (c === "\\") {
1922
+ if (i + 1 < code.length) out[i + 1] = " ";
1923
+ i++;
1924
+ } else if (c === quote) {
1925
+ out[i] = c;
1926
+ quote = "";
1927
+ }
1928
+ } else if (c === '"' || c === "'") {
1929
+ quote = c;
1930
+ }
1931
+ }
1932
+ return out.join("");
1933
+ }
1934
+ function balance(s, open) {
1935
+ const close = CLOSER[open];
1936
+ let n = 0;
1937
+ for (const c of s) {
1938
+ if (c === open) n++;
1939
+ else if (c === close) n--;
1940
+ }
1941
+ return n;
1942
+ }
1943
+ function extractPerl(content, filePath) {
1944
+ const lines = content.split(/\r?\n/);
1945
+ const cls = new Array(lines.length).fill("skip");
1946
+ const decls = [];
1947
+ const imports = [];
1948
+ let pod = false;
1949
+ let heredocs = [];
1950
+ let qOpen = null;
1951
+ let pkg = "";
1952
+ let last = lines.length;
1953
+ for (let i = 0; i < lines.length; i++) {
1954
+ const line = lines[i];
1955
+ if (heredocs.length > 0) {
1956
+ const h = heredocs[0];
1957
+ if ((h.indented ? line.trim() : line) === h.term) heredocs = heredocs.slice(1);
1958
+ continue;
1959
+ }
1960
+ if (pod) {
1961
+ if (/^=cut\b/.test(line)) pod = false;
1962
+ continue;
1963
+ }
1964
+ if (qOpen !== null) {
1965
+ qOpen.depth += balance(line, qOpen.open);
1966
+ if (qOpen.depth <= 0) qOpen = null;
1967
+ continue;
1968
+ }
1969
+ if (/^=[A-Za-z]/.test(line)) {
1970
+ pod = !/^=cut\b/.test(line);
1971
+ continue;
1972
+ }
1973
+ if (/^__(?:END|DATA)__\s*$/.test(line)) {
1974
+ last = i;
1975
+ break;
1976
+ }
1977
+ const code = stripComment(line);
1978
+ cls[i] = code.trim() === "" ? line.trim() === "" ? "blank" : "comment" : "code";
1979
+ if (cls[i] !== "code") continue;
1980
+ const sub = SUB_RE.exec(code);
1981
+ const p = sub === null ? PACKAGE_RE.exec(code) : null;
1982
+ if (sub !== null && decls.length < MAX_SYMBOLS5) {
1983
+ const rest = code.slice(sub[0].length).replace(/^\s*\([^)]*\)/, "").trimStart();
1984
+ if (!rest.startsWith(";")) {
1985
+ const full = sub[1].replace(/'/g, "::");
1986
+ const cut = full.lastIndexOf("::");
1987
+ const name = cut < 0 ? full : full.slice(cut + 2);
1988
+ const parent = cut < 0 ? pkg === "main" ? "" : pkg : full.slice(0, cut);
1989
+ if (name !== "") decls.push({ name, kind: "sub", line: i, parent });
1990
+ }
1991
+ } else if (p !== null && decls.length < MAX_SYMBOLS5) {
1992
+ pkg = p[1];
1993
+ decls.push({ name: pkg, kind: "package", line: i, parent: "" });
1994
+ } else {
1995
+ const u = /^\s*(?:use|require)\s+([A-Za-z_][\w:]*)/.exec(code);
1996
+ if (u !== null && /[A-Z]|::/.test(u[1])) imports.push({ kind: "import", target: u[1], line: i + 1 });
1997
+ }
1998
+ const scan = maskStrings(code);
1999
+ const insideString = (index) => scan[index] === " " && code[index] !== " ";
2000
+ HEREDOC_RE.lastIndex = 0;
2001
+ for (let m = HEREDOC_RE.exec(code); m !== null; m = HEREDOC_RE.exec(code)) {
2002
+ if (insideString(m.index)) continue;
2003
+ heredocs.push({ term: m[2] ?? m[3] ?? m[4] ?? "", indented: m[1] === "~" });
2004
+ }
2005
+ Q_OPEN_RE.lastIndex = 0;
2006
+ for (let m = Q_OPEN_RE.exec(code); m !== null; m = Q_OPEN_RE.exec(code)) {
2007
+ if (insideString(m.index)) continue;
2008
+ const open = m[1];
2009
+ const depth = balance(scan.slice(m.index + m[0].length - 1), open);
2010
+ if (depth > 0) {
2011
+ qOpen = { open, depth };
2012
+ break;
2013
+ }
2014
+ }
2015
+ }
2016
+ const symbols = decls.map((d, k) => {
2017
+ let next = k + 1;
2018
+ while (d.kind === "package" && next < decls.length && decls[next].kind !== "package") next++;
2019
+ let end = next < decls.length ? decls[next].line - 1 : last - 1;
2020
+ if (d.kind === "sub") {
2021
+ let e = end;
2022
+ while (e > d.line && !(cls[e] === "code" && stripComment(lines[e]).trimEnd().endsWith("}"))) e--;
2023
+ end = e > d.line ? e : d.line;
2024
+ }
2025
+ while (end > d.line && cls[end] !== "code") end--;
2026
+ return {
2027
+ filePath,
2028
+ name: d.name,
2029
+ kind: d.kind,
2030
+ lineStart: d.line + 1,
2031
+ lineEnd: end + 1,
2032
+ body: lines.slice(d.line, end + 1).join("\n"),
2033
+ docstring: precedingDocComment(lines, d.line + 1, "hash"),
2034
+ parent: d.kind === "sub" ? d.parent : ""
2035
+ };
2036
+ });
2037
+ return { symbols, imports };
2038
+ }
2039
+
2040
+ // src/languages/shader.ts
2041
+ init_define_import_meta_env();
2042
+ var TYPE_RE2 = /^(struct|class|namespace|enum)\s+(?:class\s+)?([A-Za-z_]\w*)(?:\s*:[^;{]*)?$/;
2043
+ var CBUFFER_RE = /^(cbuffer|tbuffer)\s+([A-Za-z_]\w*)/;
2044
+ var GLSL_BLOCK_QUALIFIERS = /* @__PURE__ */ new Set(["uniform", "buffer", "in", "out", "shared", "readonly", "writeonly", "coherent", "restrict", "volatile"]);
2045
+ function glslBlockName(code) {
2046
+ let s = code;
2047
+ if (s.startsWith("layout")) {
2048
+ const close = s.indexOf(")");
2049
+ if (close < 0) return "";
2050
+ s = s.slice(close + 1);
2051
+ }
2052
+ const words = s.trim().replace(/\{\s*$/, "").trim().split(/\s+/);
2053
+ let i = 0;
2054
+ while (i < words.length && GLSL_BLOCK_QUALIFIERS.has(words[i])) i++;
2055
+ return i > 0 && i === words.length - 1 && /^[A-Za-z_]\w*$/.test(words[i]) ? words[i] : "";
2056
+ }
2057
+ function matchCShader(code, ctx) {
2058
+ if (ctx.scope !== "top" && ctx.scope !== "container") return null;
2059
+ const t = TYPE_RE2.exec(withoutTrailingBrace(code));
2060
+ if (t !== null) return { name: t[2], kind: t[1], container: t[1] !== "enum", end: "brace" };
2061
+ const cb = CBUFFER_RE.exec(code);
2062
+ if (cb !== null) return { name: cb[2], kind: cb[1], container: true, end: "brace" };
2063
+ if (ctx.scope === "top") {
2064
+ const block = glslBlockName(code);
2065
+ if (block !== "") return { name: block, kind: "block", container: true, end: "brace" };
2066
+ }
2067
+ const fn = cFunctionHeader(code);
2068
+ if (fn !== null) return { name: fn.name, kind: "function", end: "brace", dropPrototype: true, ...fn.qualifier === "" ? {} : { parent: fn.qualifier } };
2069
+ return null;
2070
+ }
2071
+ var C_SHADER = {
2072
+ lex: { lineComments: ["//"], blockComment: ["/*", "*/"], quotes: `"'` },
2073
+ match: matchCShader,
2074
+ preprocessor: true,
2075
+ importOf: (code, raw) => /^#\s*include\b/.test(code) ? quotedTarget(raw) : null,
2076
+ docComments: true
2077
+ };
2078
+ var WGSL_DECL_RE = /^(fn|struct|alias|const|override)\s+([A-Za-z_]\w*)/;
2079
+ var WGSL_VAR_RE = /^var(?:\s*<[^<>]*>)?\s+([A-Za-z_]\w*)/;
2080
+ function matchWgsl(code, ctx) {
2081
+ if (ctx.scope !== "top") return null;
2082
+ const s = stripLeadingWords(code, /* @__PURE__ */ new Set(), true);
2083
+ const d = WGSL_DECL_RE.exec(s);
2084
+ if (d !== null) {
2085
+ const kind = d[1] === "fn" ? "function" : d[1];
2086
+ return { name: d[2], kind, end: d[1] === "fn" || d[1] === "struct" ? "brace" : "line" };
2087
+ }
2088
+ const v = WGSL_VAR_RE.exec(s);
2089
+ return v === null ? null : { name: v[1], kind: "var", end: "line" };
2090
+ }
2091
+ var WGSL = {
2092
+ lex: { lineComments: ["//"], blockComment: ["/*", "*/"], nestedBlockComments: true, quotes: "" },
2093
+ match: matchWgsl,
2094
+ docComments: true
2095
+ };
2096
+ function extractCShader(content, filePath) {
2097
+ return scanBraceLanguage(content, filePath, C_SHADER);
2098
+ }
2099
+ function extractWgsl(content, filePath) {
2100
+ return scanBraceLanguage(content, filePath, WGSL);
2101
+ }
2102
+
2103
+ // src/languages/solidity.ts
2104
+ init_define_import_meta_env();
2105
+ var CONTRACT_RE = /^(?:abstract\s+)?(contract|interface|library)\s+([A-Za-z_$][\w$]*)/;
2106
+ var FUNCTION_RE = /^function\s+([A-Za-z_$][\w$]*)/;
2107
+ var SPECIAL_FUNCTION_RE = /^(constructor|fallback|receive)\s*\(/;
2108
+ var MODIFIER_RE = /^modifier\s+([A-Za-z_$][\w$]*)/;
2109
+ var TYPE_RE3 = /^(struct|enum)\s+([A-Za-z_$][\w$]*)/;
2110
+ var LINE_RE = /^(event|error)\s+([A-Za-z_$][\w$]*)/;
2111
+ var VALUE_TYPE_RE = /^type\s+([A-Za-z_$][\w$]*)\s+is\b/;
2112
+ function matchSolidity(code, ctx) {
2113
+ if (ctx.scope === "top") {
2114
+ const c = CONTRACT_RE.exec(code);
2115
+ if (c !== null) return { name: c[2], kind: c[1], container: true, end: "brace" };
2116
+ }
2117
+ if (ctx.scope !== "top" && ctx.scope !== "container") return null;
2118
+ const f = FUNCTION_RE.exec(code);
2119
+ if (f !== null) return { name: f[1], kind: "function", end: "brace" };
2120
+ const sp = SPECIAL_FUNCTION_RE.exec(code);
2121
+ if (sp !== null) return { name: sp[1], kind: sp[1] === "constructor" ? "constructor" : "function", end: "brace" };
2122
+ const m = MODIFIER_RE.exec(code);
2123
+ if (m !== null) return { name: m[1], kind: "modifier", end: "brace" };
2124
+ const t = TYPE_RE3.exec(code);
2125
+ if (t !== null) return { name: t[2], kind: t[1], end: "brace" };
2126
+ const l = LINE_RE.exec(code);
2127
+ if (l !== null) return { name: l[2], kind: l[1], end: "line" };
2128
+ const v = VALUE_TYPE_RE.exec(code);
2129
+ if (v !== null) return { name: v[1], kind: "type", end: "line" };
2130
+ return null;
2131
+ }
2132
+ var SOLIDITY = {
2133
+ lex: { lineComments: ["//"], blockComment: ["/*", "*/"], quotes: `"'` },
2134
+ match: matchSolidity,
2135
+ importOf: (code, raw) => /^import\b/.test(code) ? quotedTarget(raw) : null,
2136
+ docComments: true
2137
+ };
2138
+ function extractSolidity(content, filePath) {
2139
+ return scanBraceLanguage(content, filePath, SOLIDITY);
2140
+ }
2141
+
2142
+ // src/languages/thrift.ts
2143
+ init_define_import_meta_env();
2144
+ var DEFINITION_RE = /^(struct|union|exception|service|enum|senum)\s+([A-Za-z_][\w.]*)/;
2145
+ function matchThrift(code, ctx) {
2146
+ if (ctx.scope === "top") {
2147
+ const d = DEFINITION_RE.exec(code);
2148
+ if (d !== null) return { name: d[2], kind: d[1], container: true, end: "brace" };
2149
+ if (/^typedef\s/.test(code)) {
2150
+ const name = trailingIdentifier(trimEndChars(code, ";, "))?.name;
2151
+ return name === void 0 ? null : { name, kind: "typedef", end: "line" };
2152
+ }
2153
+ if (/^const\s/.test(code) && code.includes("=")) {
2154
+ const name = trailingIdentifier(code.slice(0, code.indexOf("=")).trimEnd())?.name;
2155
+ return name === void 0 ? null : { name, kind: "const", end: "line" };
2156
+ }
2157
+ return null;
2158
+ }
2159
+ if (ctx.scope === "container" && ctx.parentKind === "service") {
2160
+ const fn = cFunctionHeader(code);
2161
+ if (fn !== null && fn.qualifier === "") return { name: fn.name, kind: "method", end: "line" };
2162
+ }
2163
+ return null;
2164
+ }
2165
+ var THRIFT = {
2166
+ lex: { lineComments: ["//", "#"], blockComment: ["/*", "*/"], quotes: `"'` },
2167
+ match: matchThrift,
2168
+ importOf: (code, raw) => /^include\s/.test(code) ? quotedTarget(raw) : null,
2169
+ docComments: true
2170
+ };
2171
+ function extractThrift(content, filePath) {
2172
+ return scanBraceLanguage(content, filePath, THRIFT);
2173
+ }
2174
+
2175
+ // src/languages/fortran.ts
2176
+ init_define_import_meta_env();
2177
+ import * as path2 from "node:path";
2178
+ var FIXED_FORM_EXTENSIONS = /* @__PURE__ */ new Set([".f", ".for", ".f77"]);
2179
+ var FIXED_TEXT_END = 72;
2180
+ var Buffers = class {
2181
+ text = "";
2182
+ raw = "";
2183
+ add(ch, inString) {
2184
+ this.raw += ch;
2185
+ this.text += inString ? " " : ch;
2186
+ }
2187
+ };
2188
+ function scanCode(body, buf, quote, onSemicolon) {
2189
+ for (let j = 0; j < body.length; j++) {
2190
+ const ch = body[j];
2191
+ if (quote !== "") {
2192
+ if (ch === quote) {
2193
+ if (body[j + 1] === quote) {
2194
+ buf.add(ch, true);
2195
+ buf.add(ch, true);
2196
+ j++;
2197
+ continue;
2198
+ }
2199
+ quote = "";
2200
+ buf.add(ch, false);
2201
+ continue;
2202
+ }
2203
+ buf.add(ch, true);
2204
+ continue;
2205
+ }
2206
+ if (ch === "!") break;
2207
+ if (ch === "'" || ch === '"') {
2208
+ quote = ch;
2209
+ buf.add(ch, false);
2210
+ continue;
2211
+ }
2212
+ if (ch === ";" && onSemicolon !== null) {
2213
+ onSemicolon();
2214
+ continue;
2215
+ }
2216
+ buf.add(ch, false);
2217
+ }
2218
+ return quote;
2219
+ }
2220
+ function preprocessorInclude(line, lineNo, imports) {
2221
+ if (!/^[ \t]*#/.test(line)) return false;
2222
+ const m = /^[ \t]*#[ \t]*include[ \t]*["<]([^">]+)[">]/.exec(line);
2223
+ if (m !== null) imports.push({ kind: "include", target: m[1], line: lineNo });
2224
+ return true;
2225
+ }
2226
+ function freeFormStatements(lines, imports) {
2227
+ const out = [];
2228
+ let buf = new Buffers();
2229
+ let start = 0;
2230
+ let end = 0;
2231
+ let quote = "";
2232
+ let continuing = false;
2233
+ const flush = () => {
2234
+ if (buf.text.trim() !== "") out.push({ text: buf.text.trim(), raw: buf.raw.trim(), line: start, endLine: end });
2235
+ buf = new Buffers();
2236
+ };
2237
+ for (let i = 0; i < lines.length; i++) {
2238
+ const line = lines[i];
2239
+ const lineNo = i + 1;
2240
+ if (!continuing && preprocessorInclude(line, lineNo, imports)) continue;
2241
+ let body = line;
2242
+ if (continuing) {
2243
+ const first = body.search(/\S/);
2244
+ if (first >= 0 && body[first] === "&") body = body.slice(first + 1);
2245
+ } else {
2246
+ start = lineNo;
2247
+ }
2248
+ const before = buf.text.length;
2249
+ quote = scanCode(body, buf, quote, () => {
2250
+ end = lineNo;
2251
+ flush();
2252
+ start = lineNo;
2253
+ });
2254
+ const added = buf.text.slice(before);
2255
+ const trimmed = added.trimEnd();
2256
+ if (trimmed.endsWith("&")) {
2257
+ const cut = added.length - trimmed.length + 1;
2258
+ buf.text = buf.text.slice(0, buf.text.length - cut);
2259
+ buf.raw = buf.raw.slice(0, buf.raw.length - cut);
2260
+ continuing = true;
2261
+ end = lineNo;
2262
+ continue;
2263
+ }
2264
+ if (continuing && added.trim() === "") continue;
2265
+ continuing = false;
2266
+ quote = "";
2267
+ end = lineNo;
2268
+ flush();
2269
+ }
2270
+ flush();
2271
+ return out;
2272
+ }
2273
+ function fixedFormStatements(lines, imports) {
2274
+ const out = [];
2275
+ let buf = new Buffers();
2276
+ let start = 0;
2277
+ let end = 0;
2278
+ const flush = () => {
2279
+ if (buf.text.trim() !== "") out.push({ text: buf.text.trim(), raw: buf.raw.trim(), line: start, endLine: end });
2280
+ buf = new Buffers();
2281
+ };
2282
+ for (let i = 0; i < lines.length; i++) {
2283
+ const line = lines[i];
2284
+ const lineNo = i + 1;
2285
+ const c0 = line[0];
2286
+ if (c0 === "C" || c0 === "c" || c0 === "*" || c0 === "!" || line.trim() === "") continue;
2287
+ if (preprocessorInclude(line, lineNo, imports)) continue;
2288
+ let textStart = 6;
2289
+ let continuation;
2290
+ const tab = line.indexOf(" ");
2291
+ if (tab >= 0 && tab < 6 && /^[ 0-9]*$/.test(line.slice(0, tab))) {
2292
+ textStart = tab + 1;
2293
+ continuation = /[1-9]/.test(line[textStart] ?? "");
2294
+ if (continuation) textStart++;
2295
+ } else {
2296
+ const label = line.slice(0, 5);
2297
+ if (label.includes("!")) continue;
2298
+ continuation = line.length > 5 && line[5] !== " " && line[5] !== "0";
2299
+ }
2300
+ const body = line.slice(textStart, tab >= 0 && tab < 6 ? void 0 : FIXED_TEXT_END);
2301
+ if (!continuation) {
2302
+ flush();
2303
+ start = lineNo;
2304
+ }
2305
+ scanCode(body, buf, "", () => {
2306
+ end = lineNo;
2307
+ flush();
2308
+ start = lineNo;
2309
+ });
2310
+ end = lineNo;
2311
+ }
2312
+ flush();
2313
+ return out;
2314
+ }
2315
+ function hasFreeFormSignal(line) {
2316
+ return /^[A-BD-Za-bd-z_&]/.test(line) || line.includes("::") || /&[ \t]*$/.test(line);
2317
+ }
2318
+ function hasFixedFormSignal(line) {
2319
+ const c0 = line[0];
2320
+ if (c0 === "C" || c0 === "c" || c0 === "*") return true;
2321
+ if (line.length > 72) return true;
2322
+ return line.length > 5 && /^[ \d]{5}$/.test(line.slice(0, 5)) && line[5] !== " " && line[5] !== "0";
2323
+ }
2324
+ function isFixedForm(filePath, lines) {
2325
+ if (!FIXED_FORM_EXTENSIONS.has(path2.extname(filePath).toLowerCase())) return false;
2326
+ if (lines.some(hasFreeFormSignal)) return false;
2327
+ return lines.some(hasFixedFormSignal);
2328
+ }
2329
+ function isIdentStart(ch) {
2330
+ return /[A-Za-z]/.test(ch);
2331
+ }
2332
+ function tokenize(s) {
2333
+ const out = [];
2334
+ let i = 0;
2335
+ while (i < s.length) {
2336
+ const ch = s[i];
2337
+ if (ch === " " || ch === " " || ch === "\r") {
2338
+ i++;
2339
+ continue;
2340
+ }
2341
+ if (isIdentStart(ch)) {
2342
+ let j = i + 1;
2343
+ while (j < s.length && /\w/.test(s[j])) j++;
2344
+ out.push(s.slice(i, j));
2345
+ i = j;
2346
+ continue;
2347
+ }
2348
+ if (/[0-9]/.test(ch)) {
2349
+ let j = i + 1;
2350
+ while (j < s.length && /[0-9]/.test(s[j])) j++;
2351
+ out.push(s.slice(i, j));
2352
+ i = j;
2353
+ continue;
2354
+ }
2355
+ if (ch === ":" && s[i + 1] === ":" || ch === "=" && s[i + 1] === ">") {
2356
+ out.push(s.slice(i, i + 2));
2357
+ i += 2;
2358
+ continue;
2359
+ }
2360
+ out.push(ch);
2361
+ i++;
2362
+ }
2363
+ return out;
2364
+ }
2365
+ function isIdent(tok) {
2366
+ return tok !== void 0 && isIdentStart(tok[0]);
2367
+ }
2368
+ function skipGroup(toks, k) {
2369
+ let depth = 0;
2370
+ for (; k < toks.length; k++) {
2371
+ if (toks[k] === "(") depth++;
2372
+ else if (toks[k] === ")" && --depth === 0) return k + 1;
2373
+ }
2374
+ return k;
2375
+ }
2376
+ function hasTopLevelEquals(toks) {
2377
+ let depth = 0;
2378
+ for (const t of toks) {
2379
+ if (t === "(" || t === "[") depth++;
2380
+ else if (t === ")" || t === "]") depth = Math.max(0, depth - 1);
2381
+ else if (t === "=" && depth === 0) return true;
2382
+ }
2383
+ return false;
2384
+ }
2385
+ var PROCEDURE_PREFIXES = /* @__PURE__ */ new Set(["RECURSIVE", "NON_RECURSIVE", "PURE", "IMPURE", "ELEMENTAL", "MODULE"]);
2386
+ var TYPE_SPECS = /* @__PURE__ */ new Set(["INTEGER", "REAL", "COMPLEX", "LOGICAL", "CHARACTER", "DOUBLEPRECISION", "DOUBLECOMPLEX", "BYTE"]);
2387
+ function skipKind(toks, k) {
2388
+ if (toks[k] === "(") return skipGroup(toks, k);
2389
+ if (toks[k] === "*") return toks[k + 1] === "(" ? skipGroup(toks, k + 1) : k + 2;
2390
+ return k;
2391
+ }
2392
+ function procedureHeader(toks) {
2393
+ let k = 0;
2394
+ while (k < toks.length) {
2395
+ const u = toks[k].toUpperCase();
2396
+ if (PROCEDURE_PREFIXES.has(u)) {
2397
+ k++;
2398
+ } else if (u === "DOUBLE" && /^(?:PRECISION|COMPLEX)$/i.test(toks[k + 1] ?? "")) {
2399
+ k = skipKind(toks, k + 2);
2400
+ } else if (TYPE_SPECS.has(u)) {
2401
+ k = skipKind(toks, k + 1);
2402
+ } else if ((u === "TYPE" || u === "CLASS") && toks[k + 1] === "(") {
2403
+ k = skipGroup(toks, k + 1);
2404
+ } else {
2405
+ break;
2406
+ }
2407
+ }
2408
+ const kw = toks[k]?.toUpperCase();
2409
+ if (kw !== "SUBROUTINE" && kw !== "FUNCTION") return null;
2410
+ const name = toks[k + 1];
2411
+ const after = toks[k + 2]?.toUpperCase();
2412
+ if (!isIdent(name) || after !== void 0 && after !== "(" && after !== "RESULT" && after !== "BIND") return null;
2413
+ return { kind: kw === "SUBROUTINE" ? "subroutine" : "function", name };
2414
+ }
2415
+ function typeDefinitionName(toks) {
2416
+ if (toks[0]?.toUpperCase() !== "TYPE") return null;
2417
+ let k = 1;
2418
+ if (toks[1] === "," || toks[1] === "::") {
2419
+ k = toks.indexOf("::");
2420
+ if (k < 0) return null;
2421
+ k++;
2422
+ } else if (toks[1]?.toUpperCase() === "IS") {
2423
+ return null;
2424
+ }
2425
+ const name = toks[k];
2426
+ if (!isIdent(name)) return null;
2427
+ const after = toks[k + 1];
2428
+ return after === void 0 || after === "(" ? name : null;
2429
+ }
2430
+ var END_KINDS = [
2431
+ ["BLOCKDATA", "block_data"],
2432
+ ["SUBMODULE", "submodule"],
2433
+ ["SUBROUTINE", "subroutine"],
2434
+ ["FUNCTION", "function"],
2435
+ ["PROGRAM", "program"],
2436
+ ["MODULE", "module"],
2437
+ ["PROCEDURE", "procedure"],
2438
+ ["INTERFACE", "interface"],
2439
+ ["TYPE", "type"]
2440
+ ];
2441
+ function extractFortran(content, filePath) {
2442
+ const spans = new SpanCollector(filePath);
2443
+ if (content.includes("\0")) return { symbols: [], imports: [] };
2444
+ const rawLines = content.split(/\r?\n/);
2445
+ const imports = [];
2446
+ const statements = isFixedForm(filePath, rawLines) ? fixedFormStatements(rawLines, imports) : freeFormStatements(rawLines, imports);
2447
+ const stack = [];
2448
+ let previous = 0;
2449
+ const parent = () => {
2450
+ for (let k = stack.length - 1; k >= 0; k--) if (stack[k].index !== void 0) return spans.name(stack[k].index);
2451
+ return "";
2452
+ };
2453
+ const inInterface = () => stack.length > 0 && stack[stack.length - 1].role === "interface";
2454
+ const open = (name, kind, role, line, named = true) => {
2455
+ const index = named && name !== void 0 && !inInterface() ? spans.open(name, kind, line, parent()) : void 0;
2456
+ stack.push({ index, kind, role });
2457
+ };
2458
+ const closeTo = (match, end) => {
2459
+ let k = stack.length - 1;
2460
+ while (k >= 0 && !match(stack[k])) k--;
2461
+ if (k < 0) return;
2462
+ while (stack.length > k) spans.close(stack.pop().index, end);
2463
+ };
2464
+ for (const st of statements) {
2465
+ let toks = tokenize(st.text);
2466
+ if (toks.length > 1 && /^[0-9]+$/.test(toks[0])) toks = toks.slice(1);
2467
+ if (toks.length === 0) continue;
2468
+ const u0 = toks[0].toUpperCase();
2469
+ previous = st.endLine;
2470
+ const compact = toks.join("").toUpperCase();
2471
+ if (/^END\w*$/.test(compact)) {
2472
+ const rest = compact.slice(3);
2473
+ if (rest === "") {
2474
+ closeTo((f) => f.role === "unit", st.endLine);
2475
+ } else {
2476
+ const hit = END_KINDS.find(([kw]) => rest.startsWith(kw));
2477
+ if (hit !== void 0 && !(hit[0] === "TYPE" && rest !== "TYPE" && !isIdent(rest.slice(4)))) closeTo((f) => f.kind === hit[1], st.endLine);
2478
+ }
2479
+ continue;
2480
+ }
2481
+ if (u0 === "USE") {
2482
+ let k = 1;
2483
+ if (toks[k] === ",") k += 2;
2484
+ if (toks[k] === "::") k++;
2485
+ if (isIdent(toks[k])) imports.push({ kind: "import", target: toks[k], line: st.line });
2486
+ continue;
2487
+ }
2488
+ if (u0 === "INCLUDE") {
2489
+ const m = /^include\s*(['"])([^'"]+)\1/i.exec(st.raw);
2490
+ if (m !== null) imports.push({ kind: "include", target: m[2], line: st.line });
2491
+ continue;
2492
+ }
2493
+ if (hasTopLevelEquals(toks)) continue;
2494
+ const u1 = toks[1]?.toUpperCase();
2495
+ if (u0 === "PROGRAM" && isIdent(toks[1]) && toks.length === 2) {
2496
+ open(toks[1], "program", "unit", st.line);
2497
+ } else if (u0 === "MODULE" && u1 === "PROCEDURE") {
2498
+ if (!inInterface() && isIdent(toks[2]) && toks.length === 3) open(toks[2], "procedure", "unit", st.line);
2499
+ } else if (u0 === "MODULE" && isIdent(toks[1]) && toks.length === 2 && u1 !== "FUNCTION" && u1 !== "SUBROUTINE") {
2500
+ open(toks[1], "module", "unit", st.line);
2501
+ } else if (u0 === "SUBMODULE" && toks[1] === "(") {
2502
+ const k = skipGroup(toks, 1);
2503
+ if (isIdent(toks[k]) && toks.length === k + 1) open(toks[k], "submodule", "unit", st.line);
2504
+ } else if (u0 === "BLOCK" && u1 === "DATA" || u0 === "BLOCKDATA") {
2505
+ const name = toks[u0 === "BLOCK" ? 2 : 1];
2506
+ open(name, "block_data", "unit", st.line, isIdent(name));
2507
+ } else if (u0 === "INTERFACE" || u0 === "ABSTRACT" && u1 === "INTERFACE") {
2508
+ const named = u0 === "INTERFACE" && isIdent(toks[1]) && toks.length === 2;
2509
+ open(toks[1], "interface", "interface", st.line, named);
2510
+ } else if (u0 === "TYPE" && typeDefinitionName(toks) !== null) {
2511
+ open(typeDefinitionName(toks), "type", "type", st.line);
2512
+ } else {
2513
+ const header = procedureHeader(toks);
2514
+ if (header !== null) open(header.name, header.kind, "unit", st.line);
2515
+ }
2516
+ }
2517
+ while (stack.length > 0) spans.close(stack.pop().index, previous);
2518
+ return { symbols: spans.finish(rawLines), imports };
2519
+ }
2520
+
2521
+ // src/languages/pascal.ts
2522
+ init_define_import_meta_env();
2523
+ import * as path3 from "node:path";
2524
+ var MAX_DEPTH = 32;
2525
+ function tokenize2(src) {
2526
+ const toks = [];
2527
+ let line = 1;
2528
+ let i = 0;
2529
+ const n = src.length;
2530
+ const push = (type, text, at) => {
2531
+ toks.push({ type, text, upper: text.toUpperCase(), line: at });
2532
+ };
2533
+ const countLines = (from, to) => {
2534
+ for (let k = from; k < to; k++) if (src.charCodeAt(k) === 10) line++;
2535
+ };
2536
+ while (i < n) {
2537
+ const ch = src[i];
2538
+ if (ch === "\n") {
2539
+ line++;
2540
+ i++;
2541
+ continue;
2542
+ }
2543
+ if (ch === " " || ch === " " || ch === "\r" || ch === "\f") {
2544
+ i++;
2545
+ continue;
2546
+ }
2547
+ if (ch === "{") {
2548
+ const end = src.indexOf("}", i + 1);
2549
+ const stop = end < 0 ? n : end + 1;
2550
+ countLines(i, stop);
2551
+ i = stop;
2552
+ continue;
2553
+ }
2554
+ if (ch === "(" && src[i + 1] === "*") {
2555
+ const end = src.indexOf("*)", i + 2);
2556
+ const stop = end < 0 ? n : end + 2;
2557
+ countLines(i, stop);
2558
+ i = stop;
2559
+ continue;
2560
+ }
2561
+ if (ch === "/" && src[i + 1] === "/") {
2562
+ const end = src.indexOf("\n", i);
2563
+ i = end < 0 ? n : end;
2564
+ continue;
2565
+ }
2566
+ if (ch === "'" || ch === "#") {
2567
+ const at = line;
2568
+ while (i < n && (src[i] === "'" || src[i] === "#")) {
2569
+ if (src[i] === "#") {
2570
+ i++;
2571
+ while (i < n && /[$\w]/.test(src[i])) i++;
2572
+ continue;
2573
+ }
2574
+ i++;
2575
+ while (i < n && src[i] !== "\n") {
2576
+ if (src[i] === "'") {
2577
+ if (src[i + 1] === "'") {
2578
+ i += 2;
2579
+ continue;
2580
+ }
2581
+ break;
2582
+ }
2583
+ i++;
2584
+ }
2585
+ if (src[i] === "'") i++;
2586
+ }
2587
+ push("str", "'", at);
2588
+ continue;
2589
+ }
2590
+ if (/[A-Za-z_&]/.test(ch)) {
2591
+ let j = i + 1;
2592
+ while (j < n && /\w/.test(src[j])) j++;
2593
+ const text = src.slice(ch === "&" ? i + 1 : i, j);
2594
+ if (text !== "") push("id", text, line);
2595
+ i = j;
2596
+ continue;
2597
+ }
2598
+ if (/[0-9$%]/.test(ch)) {
2599
+ let j = i + 1;
2600
+ while (j < n && /[\w.]/.test(src[j]) && !(src[j] === "." && src[j + 1] === ".")) j++;
2601
+ push("num", src.slice(i, j), line);
2602
+ i = j;
2603
+ continue;
2604
+ }
2605
+ const two = src.slice(i, i + 2);
2606
+ if (two === ":=" || two === ".." || two === "<=" || two === ">=" || two === "<>") {
2607
+ push("sym", two, line);
2608
+ i += 2;
2609
+ continue;
2610
+ }
2611
+ push("sym", ch, line);
2612
+ i++;
2613
+ }
2614
+ return toks;
2615
+ }
2616
+ var ROUTINE_WORDS = /* @__PURE__ */ new Set(["PROCEDURE", "FUNCTION", "CONSTRUCTOR", "DESTRUCTOR", "OPERATOR"]);
2617
+ var VISIBILITY = /* @__PURE__ */ new Set(["PRIVATE", "PROTECTED", "PUBLIC", "PUBLISHED", "STRICT", "AUTOMATED"]);
2618
+ var SECTION_WORDS = /* @__PURE__ */ new Set([
2619
+ "VAR",
2620
+ "CONST",
2621
+ "RESOURCESTRING",
2622
+ "THREADVAR",
2623
+ "LABEL",
2624
+ "EXPORTS",
2625
+ "IMPLEMENTATION",
2626
+ "INITIALIZATION",
2627
+ "FINALIZATION",
2628
+ "BEGIN",
2629
+ "ASM",
2630
+ "END",
2631
+ "USES",
2632
+ "PROPERTY",
2633
+ "CLASS",
2634
+ ...ROUTINE_WORDS,
2635
+ ...VISIBILITY
2636
+ ]);
2637
+ var DIRECTIVES = /* @__PURE__ */ new Set([
2638
+ "OVERLOAD",
2639
+ "OVERRIDE",
2640
+ "VIRTUAL",
2641
+ "DYNAMIC",
2642
+ "ABSTRACT",
2643
+ "REINTRODUCE",
2644
+ "STATIC",
2645
+ "INLINE",
2646
+ "CDECL",
2647
+ "STDCALL",
2648
+ "REGISTER",
2649
+ "PASCAL",
2650
+ "SAFECALL",
2651
+ "WINAPI",
2652
+ "EXPORT",
2653
+ "FORWARD",
2654
+ "EXTERNAL",
2655
+ "ASSEMBLER",
2656
+ "DEPRECATED",
2657
+ "PLATFORM",
2658
+ "LIBRARY",
2659
+ "EXPERIMENTAL",
2660
+ "FINAL",
2661
+ "VARARGS",
2662
+ "MESSAGE",
2663
+ "DISPID",
2664
+ "FAR",
2665
+ "NEAR",
2666
+ "NOSTACKFRAME",
2667
+ "CPPDECL",
2668
+ "ALIAS",
2669
+ "NORETURN",
2670
+ "UNIMPLEMENTED",
2671
+ "INTERRUPT",
2672
+ "MWPASCAL",
2673
+ "MS_ABI_DEFAULT",
2674
+ "SYSV_ABI_DEFAULT",
2675
+ "VECTORCALL",
2676
+ "DELAYED"
2677
+ ]);
2678
+ var HEADER_WORDS = /* @__PURE__ */ new Set(["PROGRAM", "UNIT", "LIBRARY", "PACKAGE"]);
2679
+ var IMPORT_WORDS = /* @__PURE__ */ new Set(["USES", "REQUIRES", "CONTAINS"]);
2680
+ var MEMBER_KINDS2 = { PROCEDURE: "method", FUNCTION: "method", CONSTRUCTOR: "constructor", DESTRUCTOR: "destructor", OPERATOR: "operator" };
2681
+ var PascalParser = class {
2682
+ constructor(toks, spans) {
2683
+ this.toks = toks;
2684
+ this.spans = spans;
2685
+ }
2686
+ toks;
2687
+ spans;
2688
+ p = 0;
2689
+ imports = [];
2690
+ // Symbols that are declarations inside a class, keyed so an implementation can replace them.
2691
+ declarations = /* @__PURE__ */ new Map();
2692
+ implementations = /* @__PURE__ */ new Set();
2693
+ at(k = 0) {
2694
+ return this.toks[this.p + k];
2695
+ }
2696
+ upper(k = 0) {
2697
+ return this.toks[this.p + k]?.upper ?? "";
2698
+ }
2699
+ isSym(text, k = 0) {
2700
+ const t = this.toks[this.p + k];
2701
+ return t !== void 0 && t.type === "sym" && t.text === text;
2702
+ }
2703
+ lastLine() {
2704
+ return this.toks[Math.min(this.p, this.toks.length) - 1]?.line ?? 1;
2705
+ }
2706
+ /** Advance past the next `;` outside brackets, returning that `;`'s line. */
2707
+ skipStatement() {
2708
+ let depth = 0;
2709
+ while (this.p < this.toks.length) {
2710
+ const t = this.toks[this.p++];
2711
+ if (t.type !== "sym") continue;
2712
+ if (t.text === "(" || t.text === "[") depth++;
2713
+ else if (t.text === ")" || t.text === "]") depth = Math.max(0, depth - 1);
2714
+ else if (t.text === ";" && depth === 0) return t.line;
2715
+ }
2716
+ return this.lastLine();
2717
+ }
2718
+ /** Advance past a balanced `(...)`, `[...]` or `<...>` group starting at the current token. */
2719
+ skipGroup(open, close) {
2720
+ let depth = 0;
2721
+ while (this.p < this.toks.length) {
2722
+ const t = this.toks[this.p++];
2723
+ if (t.type !== "sym") continue;
2724
+ if (t.text === open) depth++;
2725
+ else if (t.text === close && --depth === 0) return;
2726
+ else if (t.text === ";" && open === "<") return;
2727
+ }
2728
+ }
2729
+ /** A dotted name with generic parameters removed: `TList<T>.Add` gives ['TList', 'Add']. */
2730
+ dottedName() {
2731
+ const parts = [];
2732
+ while (this.at()?.type === "id") {
2733
+ parts.push(this.at().text);
2734
+ this.p++;
2735
+ if (this.isSym("<")) this.skipGroup("<", ">");
2736
+ if (this.isSym(".") && this.at(1)?.type === "id") this.p++;
2737
+ else break;
2738
+ }
2739
+ return parts;
2740
+ }
2741
+ /** True when the routine keyword at the current token starts a declaration rather than a procedural type or anonymous method. */
2742
+ isRoutineStart() {
2743
+ let k = this.p - 1;
2744
+ if (this.toks[k]?.upper === "CLASS") k--;
2745
+ const prev = this.toks[k];
2746
+ if (prev === void 0) return true;
2747
+ if (prev.type === "sym") return prev.text === ";" || prev.text === "]";
2748
+ return prev.upper === "IMPLEMENTATION" || prev.upper === "INTERFACE" || VISIBILITY.has(prev.upper);
2749
+ }
2750
+ /** Skip the directives after a routine header; true when one of them says the routine has no body here. */
2751
+ skipDirectives() {
2752
+ let bodiless = false;
2753
+ for (; ; ) {
2754
+ if (this.isSym("[")) {
2755
+ this.skipGroup("[", "]");
2756
+ continue;
2757
+ }
2758
+ const u = this.upper();
2759
+ if (this.at()?.type !== "id" || !DIRECTIVES.has(u)) return bodiless;
2760
+ if (u === "FORWARD" || u === "EXTERNAL") bodiless = true;
2761
+ this.skipStatement();
2762
+ }
2763
+ }
2764
+ /** Parse a routine header at a routine keyword (after any `class`); the cursor ends past its `;`. */
2765
+ routineHeader() {
2766
+ if (this.upper() === "CLASS") this.p++;
2767
+ const word = this.upper();
2768
+ const line = this.at().line;
2769
+ this.p++;
2770
+ let parts = this.dottedName();
2771
+ if (parts.length === 0 && word === "OPERATOR" && this.at()?.type === "sym") parts = [this.toks[this.p++].text];
2772
+ const end = this.skipStatement();
2773
+ return { word, parts, line, end };
2774
+ }
2775
+ /** A routine in a unit's implementation part or a program, with its nested routines, to the `end` that closes its body. */
2776
+ routine(parent, depth) {
2777
+ const h = this.routineHeader();
2778
+ const bodiless = this.skipDirectives();
2779
+ if (bodiless || h.parts.length === 0) return;
2780
+ const name = h.parts[h.parts.length - 1];
2781
+ const qualifier = h.parts.length > 1 ? h.parts[h.parts.length - 2] : "";
2782
+ const kind = qualifier === "" ? h.word.toLowerCase() : MEMBER_KINDS2[h.word];
2783
+ const index = this.spans.open(name, kind, h.line, qualifier === "" ? parent : qualifier);
2784
+ if (qualifier !== "") this.implementations.add(`${qualifier.toUpperCase()}.${name.toUpperCase()}`);
2785
+ if (depth >= MAX_DEPTH) return;
2786
+ while (this.p < this.toks.length) {
2787
+ const u = this.upper();
2788
+ if (u === "BEGIN" || u === "ASM") break;
2789
+ if (this.at().type === "id" && (ROUTINE_WORDS.has(u) || u === "CLASS" && ROUTINE_WORDS.has(this.upper(1))) && this.isRoutineStart()) {
2790
+ this.routine(this.spans.name(index) || parent, depth + 1);
2791
+ continue;
2792
+ }
2793
+ if (u === "TYPE" && this.at().type === "id") {
2794
+ this.typeSection(this.spans.name(index), depth + 1);
2795
+ continue;
2796
+ }
2797
+ this.p++;
2798
+ }
2799
+ this.spans.close(index, this.block());
2800
+ }
2801
+ /** Skip a `begin` or `asm` block to its balancing `end`, returning that line. */
2802
+ block() {
2803
+ let depth = 0;
2804
+ while (this.p < this.toks.length) {
2805
+ const t = this.toks[this.p++];
2806
+ if (t.type !== "id") continue;
2807
+ if (t.upper === "BEGIN" || t.upper === "CASE" || t.upper === "TRY" || t.upper === "ASM") depth++;
2808
+ else if (t.upper === "END" && --depth <= 0) return t.line;
2809
+ }
2810
+ return this.lastLine();
2811
+ }
2812
+ /** A `type` section: each declaration of a class, record, object, interface or enumeration becomes a symbol under `parent`. */
2813
+ typeSection(parent, depth) {
2814
+ this.p++;
2815
+ while (this.p < this.toks.length) {
2816
+ const t = this.at();
2817
+ if (this.isSym("[")) {
2818
+ this.skipGroup("[", "]");
2819
+ continue;
2820
+ }
2821
+ if (t.type === "id" && SECTION_WORDS.has(t.upper)) return;
2822
+ if (t.type === "id" && t.upper === "TYPE") {
2823
+ this.p++;
2824
+ continue;
2825
+ }
2826
+ if (t.type !== "id" || !(this.isSym("=", 1) || this.isSym("<", 1))) {
2827
+ this.p++;
2828
+ continue;
2829
+ }
2830
+ this.p++;
2831
+ if (this.isSym("<")) this.skipGroup("<", ">");
2832
+ if (!this.isSym("=")) continue;
2833
+ this.p++;
2834
+ this.typeDefinition(t, parent, depth);
2835
+ }
2836
+ }
2837
+ typeDefinition(name, parent, depth) {
2838
+ while (this.upper() === "PACKED" || this.upper() === "BITPACKED") this.p++;
2839
+ const u = this.upper();
2840
+ if (u === "CLASS") {
2841
+ this.p++;
2842
+ if (this.isSym(";") || this.upper() === "OF") {
2843
+ this.skipStatement();
2844
+ return;
2845
+ }
2846
+ while (this.upper() === "SEALED" || this.upper() === "ABSTRACT") this.p++;
2847
+ if (this.upper() === "HELPER") {
2848
+ this.p++;
2849
+ if (this.isSym("(")) this.skipGroup("(", ")");
2850
+ if (this.upper() === "FOR") this.p++;
2851
+ this.dottedName();
2852
+ }
2853
+ if (this.isSym("(")) this.skipGroup("(", ")");
2854
+ if (this.isSym(";")) {
2855
+ this.spans.close(this.spans.open(name.text, "class", name.line, parent), this.toks[this.p++].line);
2856
+ return;
2857
+ }
2858
+ this.body(name, "class", parent, depth);
2859
+ return;
2860
+ }
2861
+ if (u === "RECORD" || u === "OBJECT") {
2862
+ this.p++;
2863
+ if (this.upper() === "HELPER") {
2864
+ this.p++;
2865
+ if (this.upper() === "FOR") this.p++;
2866
+ this.dottedName();
2867
+ }
2868
+ if (u === "OBJECT" && this.isSym("(")) this.skipGroup("(", ")");
2869
+ this.body(name, u.toLowerCase(), parent, depth);
2870
+ return;
2871
+ }
2872
+ if (u === "INTERFACE" || u === "DISPINTERFACE") {
2873
+ this.p++;
2874
+ if (this.isSym(";")) {
2875
+ this.p++;
2876
+ return;
2877
+ }
2878
+ if (this.isSym("(")) this.skipGroup("(", ")");
2879
+ this.body(name, "interface", parent, depth);
2880
+ return;
2881
+ }
2882
+ if (this.isSym("(")) {
2883
+ this.skipGroup("(", ")");
2884
+ const end = this.isSym(";") ? this.toks[this.p++].line : this.lastLine();
2885
+ this.spans.close(this.spans.open(name.text, "enum", name.line, parent), end);
2886
+ return;
2887
+ }
2888
+ let records = 0;
2889
+ let brackets = 0;
2890
+ while (this.p < this.toks.length) {
2891
+ const t = this.toks[this.p++];
2892
+ if (t.type === "id" && t.upper === "RECORD") records++;
2893
+ else if (t.type === "id" && t.upper === "END") records = Math.max(0, records - 1);
2894
+ else if (t.type === "sym" && (t.text === "(" || t.text === "[")) brackets++;
2895
+ else if (t.type === "sym" && (t.text === ")" || t.text === "]")) brackets = Math.max(0, brackets - 1);
2896
+ else if (t.type === "sym" && t.text === ";" && records === 0 && brackets === 0) return;
2897
+ }
2898
+ }
2899
+ /** The members of a class, record, object or interface body, up to its `end`. */
2900
+ body(name, kind, parent, depth) {
2901
+ const index = this.spans.open(name.text, kind, name.line, parent);
2902
+ const owner = this.spans.name(index);
2903
+ let records = 0;
2904
+ while (this.p < this.toks.length) {
2905
+ const t = this.at();
2906
+ if (t.type !== "id") {
2907
+ if (this.isSym("[")) this.skipGroup("[", "]");
2908
+ else this.p++;
2909
+ continue;
2910
+ }
2911
+ if (t.upper === "END") {
2912
+ this.p++;
2913
+ if (records > 0) {
2914
+ records--;
2915
+ continue;
2916
+ }
2917
+ this.spans.close(index, t.line);
2918
+ if (this.isSym(";")) this.p++;
2919
+ return;
2920
+ }
2921
+ if (t.upper === "RECORD") {
2922
+ records++;
2923
+ this.p++;
2924
+ continue;
2925
+ }
2926
+ if (records === 0 && (ROUTINE_WORDS.has(t.upper) || t.upper === "CLASS" && ROUTINE_WORDS.has(this.upper(1)))) {
2927
+ this.member(owner);
2928
+ continue;
2929
+ }
2930
+ if (records === 0 && t.upper === "PROPERTY" && this.at(1)?.type === "id") {
2931
+ const prop = this.at(1);
2932
+ this.p += 2;
2933
+ let end = this.skipStatement();
2934
+ if (this.upper() === "DEFAULT" && this.isSym(";", 1)) {
2935
+ end = this.toks[this.p + 1].line;
2936
+ this.p += 2;
2937
+ }
2938
+ this.spans.close(this.spans.open(prop.text, "property", prop.line, owner), end);
2939
+ continue;
2940
+ }
2941
+ if (records === 0 && t.upper === "TYPE" && depth < MAX_DEPTH) {
2942
+ this.typeSection(owner, depth + 1);
2943
+ continue;
2944
+ }
2945
+ this.p++;
2946
+ }
2947
+ this.spans.close(index, this.lastLine());
2948
+ }
2949
+ member(owner) {
2950
+ const h = this.routineHeader();
2951
+ if (h.parts.length !== 1) return;
2952
+ const end = this.skipMemberDirectives(h.end);
2953
+ const index = this.spans.open(h.parts[0], MEMBER_KINDS2[h.word], h.line, owner);
2954
+ this.spans.close(index, end);
2955
+ if (index !== void 0) this.declarations.set(index, `${owner.toUpperCase()}.${h.parts[0].toUpperCase()}`);
2956
+ }
2957
+ /** Like skipDirectives, but returns the line the last directive ended on. */
2958
+ skipMemberDirectives(end) {
2959
+ for (; ; ) {
2960
+ if (this.at()?.type !== "id" || !DIRECTIVES.has(this.upper())) return end;
2961
+ end = this.skipStatement();
2962
+ }
2963
+ }
2964
+ parse() {
2965
+ let header;
2966
+ let inInterface = false;
2967
+ if (this.at()?.type === "id" && HEADER_WORDS.has(this.upper())) {
2968
+ const word = this.upper().toLowerCase();
2969
+ const line = this.at().line;
2970
+ this.p++;
2971
+ const parts = this.dottedName();
2972
+ header = this.spans.open(parts.join("."), word, line);
2973
+ this.skipStatement();
2974
+ }
2975
+ while (this.p < this.toks.length) {
2976
+ const t = this.at();
2977
+ if (t.type !== "id") {
2978
+ this.p++;
2979
+ continue;
2980
+ }
2981
+ const u = t.upper;
2982
+ if (IMPORT_WORDS.has(u) && this.importAllowed()) {
2983
+ this.p++;
2984
+ this.importList(u);
2985
+ continue;
2986
+ }
2987
+ if (u === "INTERFACE") inInterface = true;
2988
+ else if (u === "IMPLEMENTATION") inInterface = false;
2989
+ if (u === "TYPE") {
2990
+ this.typeSection("", 0);
2991
+ continue;
2992
+ }
2993
+ if ((ROUTINE_WORDS.has(u) || u === "CLASS" && ROUTINE_WORDS.has(this.upper(1))) && this.isRoutineStart()) {
2994
+ if (inInterface) {
2995
+ this.routineHeader();
2996
+ this.skipDirectives();
2997
+ } else {
2998
+ this.routine("", 0);
2999
+ }
3000
+ continue;
3001
+ }
3002
+ if (u === "BEGIN" || u === "ASM") {
3003
+ this.block();
3004
+ if (this.isSym(".")) {
3005
+ this.spans.close(header, this.toks[this.p - 1].line);
3006
+ header = void 0;
3007
+ break;
3008
+ }
3009
+ continue;
3010
+ }
3011
+ if (u === "END" && this.isSym(".", 1)) {
3012
+ this.spans.close(header, t.line);
3013
+ header = void 0;
3014
+ break;
3015
+ }
3016
+ this.p++;
3017
+ }
3018
+ this.spans.close(header, this.lastLine());
3019
+ }
3020
+ importAllowed() {
3021
+ const prev = this.toks[this.p - 1];
3022
+ return prev === void 0 || prev.type === "sym" && prev.text === ";" || prev.upper === "INTERFACE" || prev.upper === "IMPLEMENTATION";
3023
+ }
3024
+ importList(word) {
3025
+ while (this.p < this.toks.length) {
3026
+ const line = this.at().line;
3027
+ const parts = this.dottedName();
3028
+ if (parts.length > 0) this.imports.push({ kind: word === "USES" ? "import" : word.toLowerCase(), target: parts.join("."), line });
3029
+ if (this.upper() === "IN") this.p += 2;
3030
+ if (this.isSym(",")) {
3031
+ this.p++;
3032
+ continue;
3033
+ }
3034
+ this.skipStatement();
3035
+ return;
3036
+ }
3037
+ }
3038
+ };
3039
+ var DFM_OBJECT_RE = /^(?:object|inherited|inline)[ \t]+([A-Za-z_]\w*)/i;
3040
+ function extractDfm(content, filePath) {
3041
+ const spans = new SpanCollector(filePath);
3042
+ const text = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
3043
+ if (text.startsWith("TPF0") || text.includes("\0") || text.charCodeAt(0) === 65533 || text.charCodeAt(0) === 255) return { symbols: [], imports: [] };
3044
+ const rawLines = text.split(/\r?\n/);
3045
+ const stack = [];
3046
+ const owner = () => {
3047
+ for (let k = stack.length - 1; k >= 0; k--) if (stack[k] !== void 0) return spans.name(stack[k]);
3048
+ return "";
3049
+ };
3050
+ for (let i = 0; i < rawLines.length; i++) {
3051
+ const line = rawLines[i].trim();
3052
+ const m = DFM_OBJECT_RE.exec(line);
3053
+ if (m !== null) {
3054
+ stack.push(spans.open(m[1], "component", i + 1, owner()));
3055
+ } else if (/^item$/i.test(line)) {
3056
+ stack.push(void 0);
3057
+ } else if (/^end>?$/i.test(line) && stack.length > 0) {
3058
+ spans.close(stack.pop(), i + 1);
3059
+ }
3060
+ }
3061
+ while (stack.length > 0) spans.close(stack.pop(), rawLines.length);
3062
+ return { symbols: spans.finish(rawLines), imports: [] };
3063
+ }
3064
+ function extractPascal(content, filePath) {
3065
+ if (path3.extname(filePath).toLowerCase() === ".dfm") return extractDfm(content, filePath);
3066
+ if (content.includes("\0")) return { symbols: [], imports: [] };
3067
+ const spans = new SpanCollector(filePath);
3068
+ const parser = new PascalParser(tokenize2(content), spans);
3069
+ parser.parse();
3070
+ const rawLines = content.split(/\r?\n/);
3071
+ const symbols = spans.finish(rawLines);
3072
+ const dropped = /* @__PURE__ */ new Set();
3073
+ for (const [index, key] of parser.declarations) if (parser.implementations.has(key)) dropped.add(index);
3074
+ return { symbols: symbols.filter((_, k) => !dropped.has(k)), imports: parser.imports };
3075
+ }
3076
+
3077
+ // src/languages/matlab.ts
3078
+ init_define_import_meta_env();
3079
+ var FUNCTION_RE2 = /^function\b\s*(?:(?:\[[^\]]*\]|[A-Za-z]\w*)\s*=\s*)?([A-Za-z]\w*(?:\.[A-Za-z]\w*)*)/;
3080
+ var CLASSDEF_RE = /^classdef\b\s*(?:\([^)]*\)\s*)?([A-Za-z]\w*)/;
3081
+ var BLOCK_RE = /^(properties|methods|events|enumeration)\s*(?:\(.*\))?$/;
3082
+ var ARGUMENTS_RE = /^arguments\s*(?:\(.*\))?$/;
3083
+ var IMPORT_RE2 = /^import\s+([A-Za-z]\w*(?:\.(?:[A-Za-z]\w*|\*))*)/;
3084
+ var CONTROL_OPENERS = /* @__PURE__ */ new Set(["if", "for", "parfor", "while", "switch", "try", "spmd", "do", "unwind_protect"]);
3085
+ var CLOSERS2 = /* @__PURE__ */ new Set([
3086
+ "end",
3087
+ "endfunction",
3088
+ "endif",
3089
+ "endfor",
3090
+ "endparfor",
3091
+ "endwhile",
3092
+ "endswitch",
3093
+ "end_try_catch",
3094
+ "end_unwind_protect",
3095
+ "endclassdef",
3096
+ "endproperties",
3097
+ "endmethods",
3098
+ "endevents",
3099
+ "endenumeration",
3100
+ "endspmd",
3101
+ "until"
3102
+ ]);
3103
+ function isNameChar(ch) {
3104
+ return ch !== void 0 && /[\w.)\]}']/.test(ch);
3105
+ }
3106
+ function statementsOf(lines) {
3107
+ const out = [];
3108
+ let text = "";
3109
+ let start = 0;
3110
+ let brackets = 0;
3111
+ let parens = 0;
3112
+ let blockComment = 0;
3113
+ const flush = (end) => {
3114
+ const t = text.trim();
3115
+ if (t !== "") out.push({ text: t, line: start, endLine: end });
3116
+ text = "";
3117
+ parens = 0;
3118
+ };
3119
+ for (let i = 0; i < lines.length; i++) {
3120
+ const line = lines[i];
3121
+ const lineNo = i + 1;
3122
+ const trimmed = line.trim();
3123
+ if (trimmed === "%{" || trimmed === "#{") {
3124
+ blockComment++;
3125
+ continue;
3126
+ }
3127
+ if (blockComment > 0) {
3128
+ if (trimmed === "%}" || trimmed === "#}") blockComment--;
3129
+ continue;
3130
+ }
3131
+ if (text === "") start = lineNo;
3132
+ let continued = false;
3133
+ let quote = "";
3134
+ for (let j = 0; j < line.length; j++) {
3135
+ const ch = line[j];
3136
+ if (quote !== "") {
3137
+ if (ch === quote) {
3138
+ if (line[j + 1] === quote) {
3139
+ text += " ";
3140
+ j++;
3141
+ continue;
3142
+ }
3143
+ quote = "";
3144
+ text += ch;
3145
+ continue;
3146
+ }
3147
+ text += " ";
3148
+ continue;
3149
+ }
3150
+ if (ch === "%" || ch === "#") break;
3151
+ if (ch === "." && line.startsWith("...", j)) {
3152
+ continued = true;
3153
+ break;
3154
+ }
3155
+ if (ch === '"' || ch === "'" && !isNameChar(line[j - 1])) {
3156
+ quote = ch;
3157
+ text += ch;
3158
+ continue;
3159
+ }
3160
+ if (ch === "[" || ch === "{") brackets++;
3161
+ else if (ch === "]" || ch === "}") brackets = Math.max(0, brackets - 1);
3162
+ else if (ch === "(") parens++;
3163
+ else if (ch === ")") parens = Math.max(0, parens - 1);
3164
+ else if ((ch === "," || ch === ";") && brackets === 0 && parens === 0) {
3165
+ flush(lineNo);
3166
+ start = lineNo;
3167
+ continue;
3168
+ }
3169
+ text += ch;
3170
+ }
3171
+ if (continued || brackets > 0) {
3172
+ text += " ";
3173
+ continue;
3174
+ }
3175
+ flush(lineNo);
3176
+ }
3177
+ flush(lines.length);
3178
+ return out;
3179
+ }
3180
+ function firstWord(text) {
3181
+ return /^[A-Za-z_]\w*/.exec(text)?.[0] ?? "";
3182
+ }
3183
+ function functionsAreEndless(statements) {
3184
+ let opens = 0;
3185
+ let closes = 0;
3186
+ let functions = 0;
3187
+ for (const st of statements) {
3188
+ const w = firstWord(st.text);
3189
+ if (w === "classdef") return false;
3190
+ if (w === "function" && FUNCTION_RE2.test(st.text)) {
3191
+ functions++;
3192
+ opens++;
3193
+ } else if (CONTROL_OPENERS.has(w) || ARGUMENTS_RE.test(st.text)) {
3194
+ opens++;
3195
+ } else if (CLOSERS2.has(w) && st.text === w) {
3196
+ closes++;
3197
+ }
3198
+ }
3199
+ return functions > 0 && opens - closes >= functions;
3200
+ }
3201
+ function extractMatlab(content, filePath) {
3202
+ const spans = new SpanCollector(filePath);
3203
+ if (content.includes("\0")) return { symbols: [], imports: [] };
3204
+ const rawLines = content.split(/\r?\n/);
3205
+ const statements = statementsOf(rawLines);
3206
+ const endless = functionsAreEndless(statements);
3207
+ const imports = [];
3208
+ const stack = [];
3209
+ let previous = 0;
3210
+ const top = () => stack[stack.length - 1];
3211
+ const nearest = (words) => {
3212
+ for (let k = stack.length - 1; k >= 0; k--) if (words.has(stack[k].word)) return stack[k];
3213
+ return void 0;
3214
+ };
3215
+ const push = (word, index, isEndless = false) => {
3216
+ stack.push({ word, index, endless: isEndless, sawStatement: false });
3217
+ };
3218
+ const OWNERS = /* @__PURE__ */ new Set(["function", "methods"]);
3219
+ const CLASS = /* @__PURE__ */ new Set(["classdef"]);
3220
+ for (const st of statements) {
3221
+ const w = firstWord(st.text);
3222
+ const frame = top();
3223
+ if (CLOSERS2.has(w) && (st.text === w || w === "until")) {
3224
+ if (frame !== void 0 && !frame.endless) spans.close(stack.pop().index, st.endLine);
3225
+ previous = st.endLine;
3226
+ continue;
3227
+ }
3228
+ if (w === "function") {
3229
+ const m = FUNCTION_RE2.exec(st.text);
3230
+ if (m !== null) {
3231
+ if (endless) {
3232
+ while (stack.length > 0) spans.close(stack.pop().index, previous);
3233
+ }
3234
+ const owner = nearest(OWNERS);
3235
+ const isMethod = owner?.word === "methods";
3236
+ const parent = isMethod ? spans.name(nearest(CLASS)?.index) : spans.name(owner?.index);
3237
+ push("function", spans.open(m[1], isMethod ? "method" : "function", st.line, parent), endless);
3238
+ previous = st.endLine;
3239
+ continue;
3240
+ }
3241
+ }
3242
+ if (w === "classdef") {
3243
+ const m = CLASSDEF_RE.exec(st.text);
3244
+ if (m !== null) {
3245
+ push("classdef", spans.open(m[1], "class", st.line));
3246
+ previous = st.endLine;
3247
+ continue;
3248
+ }
3249
+ }
3250
+ if (frame?.word === "classdef" && BLOCK_RE.test(st.text)) {
3251
+ push(w, void 0);
3252
+ } else if (frame?.word === "function" && !frame.sawStatement && ARGUMENTS_RE.test(st.text)) {
3253
+ push("arguments", void 0);
3254
+ } else if (CONTROL_OPENERS.has(w) && !/^\w+\s*=[^=]/.test(st.text)) {
3255
+ push(w, void 0);
3256
+ } else if (frame !== void 0 && (frame.word === "properties" || frame.word === "events" || frame.word === "enumeration") && w !== "") {
3257
+ const kind = frame.word === "properties" ? "property" : frame.word === "events" ? "event" : "enum_member";
3258
+ const cls = spans.name(nearest(CLASS)?.index);
3259
+ spans.close(spans.open(w, kind, st.line, cls), st.endLine);
3260
+ } else if (w === "import") {
3261
+ const m = IMPORT_RE2.exec(st.text);
3262
+ if (m !== null) imports.push({ kind: "import", target: m[1], line: st.line });
3263
+ }
3264
+ if (frame !== void 0 && w !== "arguments") frame.sawStatement = true;
3265
+ previous = st.endLine;
3266
+ }
3267
+ while (stack.length > 0) spans.close(stack.pop().index, previous);
3268
+ return { symbols: spans.finish(rawLines), imports };
3269
+ }
3270
+
3271
+ // src/languages/cmake.ts
3272
+ init_define_import_meta_env();
3273
+ var MAX_ARGS = 2;
3274
+ var TARGET_COMMANDS = /* @__PURE__ */ new Set(["add_library", "add_executable", "add_custom_target"]);
3275
+ var IMPORT_KINDS = { include: "include", add_subdirectory: "subdirectory", find_package: "package" };
3276
+ function bracketClose(src, i) {
3277
+ if (src[i] !== "[") return -1;
3278
+ let j = i + 1;
3279
+ while (src[j] === "=") j++;
3280
+ if (src[j] !== "[") return -1;
3281
+ const close = `]${"=".repeat(j - i - 1)}]`;
3282
+ const end = src.indexOf(close, j + 1);
3283
+ return end < 0 ? src.length : end + close.length;
3284
+ }
3285
+ function commandsOf(src) {
3286
+ const lineStarts = [0];
3287
+ for (let k = 0; k < src.length; k++) if (src.charCodeAt(k) === 10) lineStarts.push(k + 1);
3288
+ const lineAt = (offset) => {
3289
+ let lo = 0;
3290
+ let hi = lineStarts.length - 1;
3291
+ while (lo < hi) {
3292
+ const mid = lo + hi + 1 >> 1;
3293
+ if (lineStarts[mid] <= offset) lo = mid;
3294
+ else hi = mid - 1;
3295
+ }
3296
+ return lo + 1;
3297
+ };
3298
+ const out = [];
3299
+ let i = 0;
3300
+ const n = src.length;
3301
+ const skipComment = (at) => {
3302
+ const b = bracketClose(src, at + 1);
3303
+ if (b >= 0) return b;
3304
+ const nl = src.indexOf("\n", at);
3305
+ return nl < 0 ? n : nl;
3306
+ };
3307
+ while (i < n) {
3308
+ const ch = src[i];
3309
+ if (ch === "#") {
3310
+ i = skipComment(i);
3311
+ continue;
3312
+ }
3313
+ if (!/[A-Za-z_]/.test(ch)) {
3314
+ i++;
3315
+ continue;
3316
+ }
3317
+ const start = i;
3318
+ while (i < n && /\w/.test(src[i])) i++;
3319
+ const name = src.slice(start, i).toLowerCase();
3320
+ while (src[i] === " " || src[i] === " ") i++;
3321
+ if (src[i] !== "(") continue;
3322
+ i++;
3323
+ const args = [];
3324
+ let depth = 1;
3325
+ while (i < n && depth > 0) {
3326
+ const c = src[i];
3327
+ if (c === "(") {
3328
+ depth++;
3329
+ i++;
3330
+ } else if (c === ")") {
3331
+ depth--;
3332
+ i++;
3333
+ } else if (c === "#") {
3334
+ i = skipComment(i);
3335
+ } else if (c === '"') {
3336
+ let j = i + 1;
3337
+ while (j < n && src[j] !== '"') j += src[j] === "\\" ? 2 : 1;
3338
+ if (args.length < MAX_ARGS) args.push(src.slice(i + 1, j));
3339
+ i = j + 1;
3340
+ } else if (c === "[" && bracketClose(src, i) >= 0) {
3341
+ const end = bracketClose(src, i);
3342
+ if (args.length < MAX_ARGS) args.push("");
3343
+ i = end;
3344
+ } else if (/\s/.test(c)) {
3345
+ i++;
3346
+ } else {
3347
+ let j = i;
3348
+ while (j < n && !/[\s()#"]/.test(src[j])) j += src[j] === "\\" ? 2 : 1;
3349
+ if (args.length < MAX_ARGS) args.push(src.slice(i, j));
3350
+ i = j;
3351
+ }
3352
+ }
3353
+ out.push({ name, args, line: lineAt(start), endLine: lineAt(Math.max(start, i - 1)) });
3354
+ }
3355
+ return out;
3356
+ }
3357
+ function extractCmake(content, filePath) {
3358
+ const spans = new SpanCollector(filePath);
3359
+ if (content.includes("\0")) return { symbols: [], imports: [] };
3360
+ const rawLines = content.split(/\r?\n/);
3361
+ const imports = [];
3362
+ const stack = [];
3363
+ let last = 0;
3364
+ const parent = () => {
3365
+ for (let k = stack.length - 1; k >= 0; k--) if (stack[k].index !== void 0) return spans.name(stack[k].index);
3366
+ return "";
3367
+ };
3368
+ for (const cmd of commandsOf(content)) {
3369
+ last = cmd.endLine;
3370
+ const first = cmd.args[0] ?? "";
3371
+ const literal = first !== "" && !first.includes("${");
3372
+ if (cmd.name === "function" || cmd.name === "macro") {
3373
+ stack.push({ kind: cmd.name, index: literal ? spans.open(first, cmd.name, cmd.line, parent()) : void 0 });
3374
+ } else if (cmd.name === "endfunction" || cmd.name === "endmacro") {
3375
+ const kind = cmd.name.slice(3);
3376
+ let k = stack.length - 1;
3377
+ while (k >= 0 && stack[k].kind !== kind) k--;
3378
+ if (k >= 0) while (stack.length > k) spans.close(stack.pop().index, cmd.endLine);
3379
+ } else if (TARGET_COMMANDS.has(cmd.name) || cmd.name === "project") {
3380
+ if (literal) spans.close(spans.open(first, cmd.name === "project" ? "project" : "target", cmd.line, parent()), cmd.endLine);
3381
+ } else if (IMPORT_KINDS[cmd.name] !== void 0 && Object.hasOwn(IMPORT_KINDS, cmd.name)) {
3382
+ if (literal) imports.push({ kind: IMPORT_KINDS[cmd.name], target: first, line: cmd.line });
3383
+ }
3384
+ }
3385
+ while (stack.length > 0) spans.close(stack.pop().index, last);
3386
+ return { symbols: spans.finish(rawLines), imports };
3387
+ }
3388
+
3389
+ // src/languages/asm.ts
3390
+ init_define_import_meta_env();
3391
+ var HLASM_MARKER_RE = /^(?:[A-Z@#$][A-Z0-9@#$_]*)?[ \t]+(?:CSECT|DSECT|RSECT|MACRO|MEND)(?:[ \t]|$)/;
3392
+ var HLASM_STATEMENT_COLUMNS = 71;
3393
+ var LABEL_RE2 = /^[ \t]*([A-Za-z_$?.][A-Za-z0-9_$#@~?.]*):/;
3394
+ var GAS_MACRO_RE = /^[ \t]*\.macro[ \t]+([A-Za-z_$.][A-Za-z0-9_$.]*)/;
3395
+ var GAS_ENDM_RE = /^[ \t]*\.endm\b/;
3396
+ var NASM_MACRO_RE = /^[ \t]*%i?macro[ \t]+([A-Za-z_$?.][A-Za-z0-9_$#@~?.]*)/i;
3397
+ var NASM_ENDMACRO_RE = /^[ \t]*%i?endmacro\b/i;
3398
+ var NASM_STRUC_RE = /^[ \t]*struc[ \t]+([A-Za-z_$?.][A-Za-z0-9_$#@~?.]*)/i;
3399
+ var NASM_ENDSTRUC_RE = /^[ \t]*endstruc\b/i;
3400
+ var INCLUDE_RE2 = /^[ \t]*(?:\.include|%include)[ \t]+"([^"]*)"/i;
3401
+ var HLASM_STATEMENT_RE = /^(\S*)[ \t]+(\S+)/;
3402
+ function isHlasmSource(content) {
3403
+ for (const raw of content.split(/\r?\n/)) {
3404
+ if (raw.startsWith("*")) continue;
3405
+ if (HLASM_MARKER_RE.test(raw.slice(0, HLASM_STATEMENT_COLUMNS))) return true;
3406
+ }
3407
+ return false;
3408
+ }
3409
+ function stripComment2(line, inBlock) {
3410
+ let out = "";
3411
+ let block = inBlock;
3412
+ let i = 0;
3413
+ let quote = "";
3414
+ while (i < line.length) {
3415
+ const ch = line[i];
3416
+ if (block) {
3417
+ if (ch === "*" && line[i + 1] === "/") {
3418
+ block = false;
3419
+ i += 2;
3420
+ continue;
3421
+ }
3422
+ i++;
3423
+ continue;
3424
+ }
3425
+ if (quote !== "") {
3426
+ if (ch === "\\") {
3427
+ out += " ";
3428
+ i += 2;
3429
+ continue;
3430
+ }
3431
+ if (ch === quote) quote = "";
3432
+ out += ch;
3433
+ i++;
3434
+ continue;
3435
+ }
3436
+ if (ch === '"' || ch === "'") {
3437
+ quote = ch;
3438
+ out += ch;
3439
+ i++;
3440
+ continue;
3441
+ }
3442
+ if (ch === "/" && line[i + 1] === "*") {
3443
+ block = true;
3444
+ i += 2;
3445
+ continue;
3446
+ }
3447
+ if (ch === ";" || ch === "#" || ch === "/" && line[i + 1] === "/") break;
3448
+ out += ch;
3449
+ i++;
3450
+ }
3451
+ return { code: out, inBlock: block };
3452
+ }
3453
+ function extractGasNasm(rawLines, spans, imports) {
3454
+ const stack = [];
3455
+ let label;
3456
+ let inBlock = false;
3457
+ const parent = () => stack.length === 0 ? "" : spans.name(stack[stack.length - 1].index);
3458
+ const endLabel = (end) => {
3459
+ spans.close(label, end);
3460
+ label = void 0;
3461
+ };
3462
+ for (let i = 0; i < rawLines.length; i++) {
3463
+ const line = i + 1;
3464
+ const stripped = stripComment2(rawLines[i], inBlock);
3465
+ inBlock = stripped.inBlock;
3466
+ const code = stripped.code;
3467
+ if (code.trim() === "") continue;
3468
+ const include = INCLUDE_RE2.exec(code);
3469
+ if (include) {
3470
+ imports.push({ kind: "include", target: include[1], line });
3471
+ continue;
3472
+ }
3473
+ const open = GAS_MACRO_RE.exec(code) ?? NASM_MACRO_RE.exec(code);
3474
+ if (open) {
3475
+ endLabel(line - 1);
3476
+ stack.push({ index: spans.open(open[1], "macro", line, parent()), kind: "macro" });
3477
+ continue;
3478
+ }
3479
+ const struc = NASM_STRUC_RE.exec(code);
3480
+ if (struc) {
3481
+ endLabel(line - 1);
3482
+ stack.push({ index: spans.open(struc[1], "struct", line, parent()), kind: "struct" });
3483
+ continue;
3484
+ }
3485
+ if (GAS_ENDM_RE.test(code) || NASM_ENDMACRO_RE.test(code) || NASM_ENDSTRUC_RE.test(code)) {
3486
+ endLabel(line - 1);
3487
+ const frame = stack.pop();
3488
+ if (frame !== void 0) spans.close(frame.index, line);
3489
+ continue;
3490
+ }
3491
+ const found = LABEL_RE2.exec(code);
3492
+ if (found) {
3493
+ const name = found[1];
3494
+ if (name.startsWith(".")) continue;
3495
+ endLabel(line - 1);
3496
+ label = spans.open(name, "label", line, parent());
3497
+ }
3498
+ }
3499
+ endLabel(lastContentLine(rawLines));
3500
+ for (const frame of stack) spans.close(frame.index, lastContentLine(rawLines));
3501
+ }
3502
+ function extractHlasm(rawLines, spans) {
3503
+ let section;
3504
+ let macro;
3505
+ let macroStart = 0;
3506
+ let awaitingPrototype = false;
3507
+ let continued = false;
3508
+ for (let i = 0; i < rawLines.length; i++) {
3509
+ const raw = rawLines[i];
3510
+ const line = i + 1;
3511
+ const statement = raw.slice(0, HLASM_STATEMENT_COLUMNS);
3512
+ const continues = raw.length > HLASM_STATEMENT_COLUMNS && raw[HLASM_STATEMENT_COLUMNS].trim() !== "";
3513
+ if (continued) {
3514
+ continued = continues;
3515
+ continue;
3516
+ }
3517
+ continued = continues;
3518
+ if (statement.startsWith("*") || statement.startsWith(".*")) continue;
3519
+ if (statement.trim() === "") continue;
3520
+ const m = HLASM_STATEMENT_RE.exec(statement);
3521
+ if (!m) continue;
3522
+ const name = m[1];
3523
+ const op = m[2].toUpperCase();
3524
+ if (awaitingPrototype) {
3525
+ awaitingPrototype = false;
3526
+ macro = spans.open(op, "macro", macroStart, spans.name(section));
3527
+ continue;
3528
+ }
3529
+ if (op === "MACRO") {
3530
+ awaitingPrototype = true;
3531
+ macroStart = line;
3532
+ continue;
3533
+ }
3534
+ if (op === "MEND") {
3535
+ spans.close(macro, line);
3536
+ macro = void 0;
3537
+ continue;
3538
+ }
3539
+ if (macro !== void 0) continue;
3540
+ if (op === "CSECT" || op === "RSECT" || op === "START" || op === "DSECT") {
3541
+ spans.close(section, line - 1);
3542
+ section = name === "" ? void 0 : spans.open(name, op === "DSECT" ? "dummy section" : "section", line);
3543
+ continue;
3544
+ }
3545
+ if (op === "END") {
3546
+ spans.close(section, line);
3547
+ section = void 0;
3548
+ }
3549
+ }
3550
+ spans.close(macro, lastContentLine(rawLines));
3551
+ spans.close(section, lastContentLine(rawLines));
3552
+ }
3553
+ function extractAsm(content, filePath) {
3554
+ const imports = [];
3555
+ const spans = new SpanCollector(filePath);
3556
+ if (content.includes("\0")) return { symbols: [], imports };
3557
+ const rawLines = content.split(/\r?\n/);
3558
+ if (isHlasmSource(content)) extractHlasm(rawLines, spans);
3559
+ else extractGasNasm(rawLines, spans, imports);
3560
+ return { symbols: spans.finish(rawLines), imports };
3561
+ }
3562
+
3563
+ // src/languages/batch.ts
3564
+ init_define_import_meta_env();
3565
+ var LABEL_RE3 = /^:([A-Za-z0-9_.$#@[\]{}-][^\s;=,]*)/;
3566
+ var REM_RE = /^rem(?:[\s]|$)/i;
3567
+ var CALL_RE = /(?:^|[\s&(])call[\s]+(?:"([^"]+\.(?:bat|cmd))"|([^\s"&|<>]+\.(?:bat|cmd)))/i;
3568
+ function extractBatch(content, filePath) {
3569
+ const imports = [];
3570
+ const spans = new SpanCollector(filePath);
3571
+ if (content.includes("\0")) return { symbols: [], imports };
3572
+ const rawLines = content.split(/\r?\n/);
3573
+ let label;
3574
+ for (let i = 0; i < rawLines.length; i++) {
3575
+ const line = i + 1;
3576
+ const text = rawLines[i].replace(/^[\s@]+/, "");
3577
+ if (text === "") continue;
3578
+ const found = LABEL_RE3.exec(text);
3579
+ if (found) {
3580
+ spans.close(label, line - 1);
3581
+ label = spans.open(found[1], "label", line);
3582
+ continue;
3583
+ }
3584
+ if (text.startsWith(":") || REM_RE.test(text)) continue;
3585
+ const call = CALL_RE.exec(text);
3586
+ if (call) imports.push({ kind: "call", target: call[1] ?? call[2], line });
3587
+ }
3588
+ spans.close(label, lastContentLine(rawLines));
3589
+ return { symbols: spans.finish(rawLines), imports };
3590
+ }
3591
+
3592
+ // src/languages/erlang.ts
3593
+ init_define_import_meta_env();
3594
+ var HEAD_CHARS = 512;
3595
+ var MODULE_RE = /^-\s*module\s*\(\s*(?:'([^'\n]*)'|([a-z][A-Za-z0-9_@]*))/;
3596
+ var RECORD_RE = /^-\s*record\s*\(\s*(?:'([^'\n]*)'|([a-z][A-Za-z0-9_@]*))/;
3597
+ var DEFINE_RE = /^-\s*define\s*\(\s*([A-Za-z_][A-Za-z0-9_@]*)/;
3598
+ var TYPE_RE4 = /^-\s*(?:type|opaque)\s+(?:'([^'\n]*)'|([a-z][A-Za-z0-9_@]*))\s*\(/;
3599
+ var INCLUDE_RE3 = /^-\s*(include_lib|include)\s*\(\s*"([^"\n]*)"/;
3600
+ var IMPORT_RE3 = /^-\s*import\s*\(\s*(?:'([^'\n]*)'|([a-z][A-Za-z0-9_@]*))/;
3601
+ var FUNCTION_RE3 = /^(?:'([^'\n]*)'|([a-z][A-Za-z0-9_@]*))\s*\(/;
3602
+ function formsOf(content) {
3603
+ const out = [];
3604
+ let line = 1;
3605
+ let startOffset = -1;
3606
+ let startLine = 1;
3607
+ let depth = 0;
3608
+ for (let i = 0; i < content.length; i++) {
3609
+ const ch = content[i];
3610
+ if (ch === "\n") {
3611
+ line++;
3612
+ continue;
3613
+ }
3614
+ if (ch === "%") {
3615
+ const nl = content.indexOf("\n", i);
3616
+ i = nl < 0 ? content.length : nl - 1;
3617
+ continue;
3618
+ }
3619
+ if (ch === "$") {
3620
+ i += content[i + 1] === "\\" ? 2 : 1;
3621
+ continue;
3622
+ }
3623
+ if (ch === '"' || ch === "'") {
3624
+ const close = ch;
3625
+ i++;
3626
+ while (i < content.length && content[i] !== close) {
3627
+ if (content[i] === "\n") line++;
3628
+ if (content[i] === "\\") i++;
3629
+ i++;
3630
+ }
3631
+ continue;
3632
+ }
3633
+ if (startOffset < 0 && !/\s/.test(ch)) {
3634
+ startOffset = i;
3635
+ startLine = line;
3636
+ }
3637
+ if (ch === "(" || ch === "[" || ch === "{") depth++;
3638
+ else if (ch === ")" || ch === "]" || ch === "}") depth = Math.max(0, depth - 1);
3639
+ else if (ch === "." && depth === 0) {
3640
+ const next = content[i + 1];
3641
+ if (next === void 0 || /\s/.test(next)) {
3642
+ if (startOffset >= 0) out.push({ head: content.slice(startOffset, startOffset + HEAD_CHARS), line: startLine, endLine: line });
3643
+ startOffset = -1;
3644
+ }
3645
+ }
3646
+ }
3647
+ if (startOffset >= 0) out.push({ head: content.slice(startOffset, startOffset + HEAD_CHARS), line: startLine, endLine: line });
3648
+ return out;
3649
+ }
3650
+ function extractErlang(content, filePath) {
3651
+ const imports = [];
3652
+ const spans = new SpanCollector(filePath);
3653
+ if (content.includes("\0")) return { symbols: [], imports };
3654
+ const rawLines = content.split(/\r?\n/);
3655
+ for (const form of formsOf(content)) {
3656
+ const head = form.head;
3657
+ const emit = (name, kind) => {
3658
+ spans.close(spans.open(name, kind, form.line), form.endLine);
3659
+ };
3660
+ const include = INCLUDE_RE3.exec(head);
3661
+ if (include) {
3662
+ imports.push({ kind: include[1].toLowerCase(), target: include[2], line: form.line });
3663
+ continue;
3664
+ }
3665
+ const imported = IMPORT_RE3.exec(head);
3666
+ if (imported) {
3667
+ imports.push({ kind: "import", target: imported[1] ?? imported[2], line: form.line });
3668
+ continue;
3669
+ }
3670
+ const named = (re) => {
3671
+ const m = re.exec(head);
3672
+ return m === null ? void 0 : m[1] ?? m[2];
3673
+ };
3674
+ const module = named(MODULE_RE);
3675
+ if (module !== void 0) {
3676
+ emit(module, "module");
3677
+ continue;
3678
+ }
3679
+ const record = named(RECORD_RE);
3680
+ if (record !== void 0) {
3681
+ emit(record, "record");
3682
+ continue;
3683
+ }
3684
+ const define = DEFINE_RE.exec(head);
3685
+ if (define) {
3686
+ emit(define[1], "macro");
3687
+ continue;
3688
+ }
3689
+ const type = named(TYPE_RE4);
3690
+ if (type !== void 0) {
3691
+ emit(type, "type");
3692
+ continue;
3693
+ }
3694
+ if (head.startsWith("-")) continue;
3695
+ const fn = named(FUNCTION_RE3);
3696
+ if (fn !== void 0) emit(fn, "function");
3697
+ }
3698
+ return { symbols: spans.finish(rawLines), imports };
3699
+ }
3700
+
3701
+ export {
3702
+ stripLeadingAttributes,
3703
+ IMPORT_RE,
3704
+ extractSwift,
3705
+ extractCobol,
3706
+ extractNatural,
3707
+ SpanCollector,
3708
+ extractAbap,
3709
+ extractAbl,
3710
+ extractJcl,
3711
+ extractPli,
3712
+ extractRpg,
3713
+ extractSas,
3714
+ extractGroovy,
3715
+ extractObjc,
3716
+ extractPerl,
3717
+ extractCShader,
3718
+ extractWgsl,
3719
+ extractSolidity,
3720
+ extractThrift,
3721
+ extractFortran,
3722
+ extractPascal,
3723
+ extractMatlab,
3724
+ extractCmake,
3725
+ extractAsm,
3726
+ extractBatch,
3727
+ extractErlang
3728
+ };