agency-lang 0.0.85 → 0.0.86
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.
- package/dist/lib/backends/agencyGenerator.d.ts +2 -1
- package/dist/lib/backends/agencyGenerator.js +52 -16
- package/dist/lib/backends/agencyGenerator.test.js +8 -8
- package/dist/lib/backends/typescriptBuilder.d.ts +6 -0
- package/dist/lib/backends/typescriptBuilder.js +79 -10
- package/dist/lib/cli/commands.d.ts +1 -1
- package/dist/lib/cli/commands.js +10 -9
- package/dist/lib/cli/test.js +24 -11
- package/dist/lib/cli/util.js +6 -3
- package/dist/lib/config.d.ts +2 -1
- package/dist/lib/config.js +1 -35
- package/dist/lib/importPaths.d.ts +34 -0
- package/dist/lib/importPaths.js +71 -0
- package/dist/lib/importPaths.test.d.ts +1 -0
- package/dist/lib/importPaths.test.js +78 -0
- package/dist/lib/parser.d.ts +1 -1
- package/dist/lib/parser.js +11 -7
- package/dist/lib/parser.test.js +3 -68
- package/dist/lib/parsers/access.js +4 -3
- package/dist/lib/parsers/access.test.js +24 -24
- package/dist/lib/parsers/assignment.test.js +2 -2
- package/dist/lib/parsers/binop.js +14 -56
- package/dist/lib/parsers/binop.test.js +20 -20
- package/dist/lib/parsers/body.test.js +1 -1
- package/dist/lib/parsers/comment.js +2 -2
- package/dist/lib/parsers/comment.test.js +1 -1
- package/dist/lib/parsers/dataStructures.js +5 -6
- package/dist/lib/parsers/dataStructures.test.js +3 -3
- package/dist/lib/parsers/debuggerStatement.d.ts +3 -0
- package/dist/lib/parsers/debuggerStatement.js +11 -0
- package/dist/lib/parsers/debuggerStatement.test.d.ts +1 -0
- package/dist/lib/parsers/debuggerStatement.test.js +43 -0
- package/dist/lib/parsers/expression.d.ts +3 -0
- package/dist/lib/parsers/expression.js +121 -0
- package/dist/lib/parsers/expression.test.d.ts +1 -0
- package/dist/lib/parsers/expression.test.js +299 -0
- package/dist/lib/parsers/forLoop.test.js +1 -1
- package/dist/lib/parsers/function.js +21 -17
- package/dist/lib/parsers/function.test.js +8 -8
- package/dist/lib/parsers/functionCall.js +4 -7
- package/dist/lib/parsers/functionCall.test.js +42 -7
- package/dist/lib/parsers/handleBlock.test.js +1 -1
- package/dist/lib/parsers/ifElse.test.js +1 -1
- package/dist/lib/parsers/importStatement.js +22 -8
- package/dist/lib/parsers/importStatement.test.js +27 -27
- package/dist/lib/parsers/keyword.test.js +1 -1
- package/dist/lib/parsers/literals.js +3 -8
- package/dist/lib/parsers/literals.test.js +63 -8
- package/dist/lib/parsers/loc.d.ts +9 -0
- package/dist/lib/parsers/loc.js +25 -0
- package/dist/lib/parsers/matchBlock.d.ts +1 -1
- package/dist/lib/parsers/matchBlock.js +4 -7
- package/dist/lib/parsers/matchBlock.test.js +3 -3
- package/dist/lib/parsers/multiLineComment.test.js +1 -1
- package/dist/lib/parsers/parserUtils.test.js +2 -2
- package/dist/lib/parsers/returnStatement.js +5 -7
- package/dist/lib/parsers/returnStatement.test.js +1 -1
- package/dist/lib/parsers/skill.test.js +1 -1
- package/dist/lib/parsers/specialVar.js +2 -4
- package/dist/lib/parsers/specialVar.test.js +1 -1
- package/dist/lib/parsers/tools.test.js +1 -1
- package/dist/lib/parsers/typeHints.js +2 -2
- package/dist/lib/parsers/typeHints.test.js +15 -15
- package/dist/lib/parsers/utils.d.ts +1 -1
- package/dist/lib/parsers/vitest.setup.d.ts +9 -0
- package/dist/lib/parsers/vitest.setup.js +53 -0
- package/dist/lib/parsers/whileLoop.test.js +1 -1
- package/dist/lib/preprocessors/importResolver.js +14 -5
- package/dist/lib/preprocessors/importResolver.test.js +3 -3
- package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +1 -0
- package/dist/lib/preprocessors/typescriptPreprocessor.js +70 -3
- package/dist/lib/programInfo.js +5 -0
- package/dist/lib/programInfo.test.js +1 -1
- package/dist/lib/runtime/audit.d.ts +12 -1
- package/dist/lib/runtime/builtinTools.d.ts +0 -90
- package/dist/lib/runtime/builtinTools.js +0 -65
- package/dist/lib/runtime/builtins.d.ts +0 -15
- package/dist/lib/runtime/builtins.js +0 -55
- package/dist/lib/runtime/hooks.d.ts +2 -0
- package/dist/lib/runtime/index.d.ts +5 -3
- package/dist/lib/runtime/index.js +4 -3
- package/dist/lib/runtime/interrupts.d.ts +11 -4
- package/dist/lib/runtime/interrupts.js +20 -4
- package/dist/lib/runtime/isDebugger.test.d.ts +1 -0
- package/dist/lib/runtime/isDebugger.test.js +24 -0
- package/dist/lib/runtime/rewind.d.ts +20 -0
- package/dist/lib/runtime/rewind.js +67 -0
- package/dist/lib/runtime/rewind.test.d.ts +1 -0
- package/dist/lib/runtime/rewind.test.js +80 -0
- package/dist/lib/runtime/state/context.d.ts +1 -0
- package/dist/lib/runtime/state/context.js +6 -0
- package/dist/lib/runtime/state/stateStack.d.ts +7 -0
- package/dist/lib/runtime/state/stateStack.js +16 -0
- package/dist/lib/symbolTable.d.ts +1 -0
- package/dist/lib/symbolTable.js +8 -6
- package/dist/lib/symbolTable.test.js +1 -1
- package/dist/lib/templates/backends/agency/template.d.ts +6 -0
- package/dist/lib/templates/backends/agency/template.js +11 -0
- package/dist/lib/templates/backends/typescriptGenerator/debugger.d.ts +7 -0
- package/dist/lib/templates/backends/typescriptGenerator/debugger.js +25 -0
- package/dist/lib/templates/backends/typescriptGenerator/forSteps.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/forSteps.js +1 -4
- package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/imports.js +13 -50
- package/dist/lib/templates/backends/typescriptGenerator/rewindCheckpoint.d.ts +8 -0
- package/dist/lib/templates/backends/typescriptGenerator/rewindCheckpoint.js +32 -0
- package/dist/lib/templates/backends/typescriptGenerator/whileSteps.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/whileSteps.js +1 -4
- package/dist/lib/types/access.d.ts +4 -3
- package/dist/lib/types/awaitPending.d.ts +2 -1
- package/dist/lib/types/base.d.ts +9 -0
- package/dist/lib/types/base.js +1 -0
- package/dist/lib/types/binop.d.ts +7 -9
- package/dist/lib/types/binop.js +1 -0
- package/dist/lib/types/dataStructures.d.ts +7 -8
- package/dist/lib/types/debuggerStatement.d.ts +5 -0
- package/dist/lib/types/debuggerStatement.js +1 -0
- package/dist/lib/types/forLoop.d.ts +4 -4
- package/dist/lib/types/function.d.ts +5 -7
- package/dist/lib/types/graphNode.d.ts +2 -1
- package/dist/lib/types/handleBlock.d.ts +2 -1
- package/dist/lib/types/ifElse.d.ts +4 -5
- package/dist/lib/types/importStatement.d.ts +7 -4
- package/dist/lib/types/importStatement.js +6 -0
- package/dist/lib/types/keyword.d.ts +2 -1
- package/dist/lib/types/literals.d.ts +9 -9
- package/dist/lib/types/matchBlock.d.ts +6 -10
- package/dist/lib/types/messageThread.d.ts +2 -1
- package/dist/lib/types/returnStatement.d.ts +4 -6
- package/dist/lib/types/sentinel.d.ts +11 -0
- package/dist/lib/types/sentinel.js +1 -0
- package/dist/lib/types/skill.d.ts +2 -1
- package/dist/lib/types/specialVar.d.ts +4 -6
- package/dist/lib/types/tools.d.ts +2 -1
- package/dist/lib/types/typeHints.d.ts +3 -2
- package/dist/lib/types/whileLoop.d.ts +4 -5
- package/dist/lib/types.d.ts +14 -6
- package/dist/lib/types.js +4 -0
- package/dist/lib/utils/node.d.ts +7 -5
- package/dist/lib/utils/node.js +54 -29
- package/package.json +4 -2
- package/stdlib/_builtins.js +97 -0
- package/stdlib/_math.js +9 -0
- package/stdlib/_utils.js +51 -0
- package/stdlib/index.agency +115 -0
- package/stdlib/index.js +1303 -0
- package/stdlib/lib/test.js +3 -0
- package/stdlib/math.agency +13 -0
- package/stdlib/math.js +383 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SpecialVar } from "../types/specialVar.js";
|
|
2
|
-
import { AgencyComment, AgencyMultiLineComment, AgencyNode, AgencyProgram, Assignment, Literal, NewLine, Scope, TypeAlias, TypeHint, TypeHintMap, VariableType } from "../types.js";
|
|
2
|
+
import { AgencyComment, AgencyMultiLineComment, AgencyNode, AgencyProgram, Assignment, DebuggerStatement, Literal, NewLine, Scope, TypeAlias, TypeHint, TypeHintMap, VariableType } from "../types.js";
|
|
3
3
|
import { AccessChainElement, ValueAccess } from "../types/access.js";
|
|
4
4
|
import { AgencyArray, AgencyObject } from "../types/dataStructures.js";
|
|
5
5
|
import { FunctionCall, FunctionDefinition } from "../types/function.js";
|
|
@@ -80,6 +80,7 @@ export declare class AgencyGenerator {
|
|
|
80
80
|
protected processWhileLoop(node: WhileLoop): string;
|
|
81
81
|
protected processIfElse(node: IfElse): string;
|
|
82
82
|
protected processReturnStatement(node: ReturnStatement): string;
|
|
83
|
+
protected processDebuggerStatement(node: DebuggerStatement): string;
|
|
83
84
|
protected processComment(node: AgencyComment): string;
|
|
84
85
|
protected processMultiLineComment(node: AgencyMultiLineComment): string;
|
|
85
86
|
protected processImportStatement(node: ImportStatement): string;
|
|
@@ -64,10 +64,33 @@ export class AgencyGenerator {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
this.preprocessAST();
|
|
67
|
+
// Types that should have a blank line before/after them at the top level
|
|
68
|
+
const BLOCK_TYPES = new Set([
|
|
69
|
+
"graphNode", "function", "typeAlias",
|
|
70
|
+
]);
|
|
71
|
+
const NO_SPACE_TYPES = new Set([
|
|
72
|
+
"comment", "multiLineComment"
|
|
73
|
+
]);
|
|
67
74
|
// Pass 7: Process all nodes and generate code
|
|
75
|
+
const stmtPairs = [];
|
|
68
76
|
for (const node of program.nodes) {
|
|
69
77
|
const result = this.processNode(node);
|
|
70
|
-
|
|
78
|
+
if (result !== "") {
|
|
79
|
+
stmtPairs.push({ type: node.type, code: result });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Join top-level statements: blank line between block declarations,
|
|
83
|
+
// single newline between simple statements
|
|
84
|
+
const stmtLines = [];
|
|
85
|
+
for (let i = 0; i < stmtPairs.length; i++) {
|
|
86
|
+
if (i > 0) {
|
|
87
|
+
const prev = stmtPairs[i - 1];
|
|
88
|
+
const curr = stmtPairs[i];
|
|
89
|
+
if (BLOCK_TYPES.has(prev.type) || (BLOCK_TYPES.has(curr.type) && !NO_SPACE_TYPES.has(prev.type))) {
|
|
90
|
+
stmtLines.push(""); // blank line
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
stmtLines.push(stmtPairs[i].code);
|
|
71
94
|
}
|
|
72
95
|
const output = [];
|
|
73
96
|
this.addIfNonEmpty(this.preprocess(), output);
|
|
@@ -75,7 +98,7 @@ export class AgencyGenerator {
|
|
|
75
98
|
this.addIfNonEmpty(this.generateImports(), output);
|
|
76
99
|
this.addIfNonEmpty(this.generateBuiltins(), output);
|
|
77
100
|
output.push(...this.generatedTypeAliases);
|
|
78
|
-
output.push(
|
|
101
|
+
output.push(stmtLines.join("\n"));
|
|
79
102
|
this.addIfNonEmpty(this.postprocess(), output);
|
|
80
103
|
return {
|
|
81
104
|
output: output.join("\n"),
|
|
@@ -131,6 +154,8 @@ export class AgencyGenerator {
|
|
|
131
154
|
return this.generateLiteral(node);
|
|
132
155
|
case "returnStatement":
|
|
133
156
|
return this.processReturnStatement(node);
|
|
157
|
+
case "debuggerStatement":
|
|
158
|
+
return this.processDebuggerStatement(node);
|
|
134
159
|
case "agencyArray":
|
|
135
160
|
return this.processAgencyArray(node);
|
|
136
161
|
case "agencyObject":
|
|
@@ -195,8 +220,8 @@ export class AgencyGenerator {
|
|
|
195
220
|
}
|
|
196
221
|
isImportedTool(functionName) {
|
|
197
222
|
return this.importedTools
|
|
198
|
-
.
|
|
199
|
-
.
|
|
223
|
+
.flatMap((node) => node.importedTools)
|
|
224
|
+
.flatMap((n) => n.importedNames)
|
|
200
225
|
.includes(functionName);
|
|
201
226
|
}
|
|
202
227
|
isAgencyFunction(functionName, context) {
|
|
@@ -359,7 +384,7 @@ export class AgencyGenerator {
|
|
|
359
384
|
for (const stmt of body) {
|
|
360
385
|
lines.push(this.processNode(stmt));
|
|
361
386
|
}
|
|
362
|
-
const bodyCode = lines.join("").trimEnd() + "\n";
|
|
387
|
+
const bodyCode = lines.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
363
388
|
result += bodyCode;
|
|
364
389
|
this.decreaseIndent();
|
|
365
390
|
result += this.indentStr(`}`);
|
|
@@ -459,9 +484,11 @@ export class AgencyGenerator {
|
|
|
459
484
|
: node.itemVar;
|
|
460
485
|
let result = this.indentStr(`for (${vars} in ${iterableCode}) {\n`);
|
|
461
486
|
this.increaseIndent();
|
|
487
|
+
const lines = [];
|
|
462
488
|
for (const stmt of node.body) {
|
|
463
|
-
|
|
489
|
+
lines.push(this.processNode(stmt));
|
|
464
490
|
}
|
|
491
|
+
result += lines.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
465
492
|
this.decreaseIndent();
|
|
466
493
|
result += this.indentStr(`}`);
|
|
467
494
|
return result;
|
|
@@ -470,9 +497,11 @@ export class AgencyGenerator {
|
|
|
470
497
|
const conditionCode = this.processNode(node.condition).trim();
|
|
471
498
|
let result = this.indentStr(`while (${conditionCode}) {\n`);
|
|
472
499
|
this.increaseIndent();
|
|
500
|
+
const lines = [];
|
|
473
501
|
for (const stmt of node.body) {
|
|
474
|
-
|
|
502
|
+
lines.push(this.processNode(stmt));
|
|
475
503
|
}
|
|
504
|
+
result += lines.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
476
505
|
this.decreaseIndent();
|
|
477
506
|
result += this.indentStr(`}`);
|
|
478
507
|
return result;
|
|
@@ -487,7 +516,7 @@ export class AgencyGenerator {
|
|
|
487
516
|
bodyLines.push(this.processNode(stmt));
|
|
488
517
|
}
|
|
489
518
|
this.decreaseIndent();
|
|
490
|
-
lines.push(bodyLines.join("").trimEnd() + "\n");
|
|
519
|
+
lines.push(bodyLines.filter(s => s !== "").join("\n").trimEnd() + "\n");
|
|
491
520
|
if (node.elseBody && node.elseBody.length > 0) {
|
|
492
521
|
if (node.elseBody.length === 1 && node.elseBody[0].type === "ifElse") {
|
|
493
522
|
const elseIfCode = this.processIfElse(node.elseBody[0]);
|
|
@@ -502,7 +531,7 @@ export class AgencyGenerator {
|
|
|
502
531
|
elseBodyLines.push(this.processNode(stmt));
|
|
503
532
|
}
|
|
504
533
|
this.decreaseIndent();
|
|
505
|
-
lines.push(elseBodyLines.join("").trimEnd() + "\n");
|
|
534
|
+
lines.push(elseBodyLines.filter(s => s !== "").join("\n").trimEnd() + "\n");
|
|
506
535
|
}
|
|
507
536
|
}
|
|
508
537
|
lines.push(this.indentStr(`}`));
|
|
@@ -512,6 +541,9 @@ export class AgencyGenerator {
|
|
|
512
541
|
const valueCode = this.processNode(node.value).trim();
|
|
513
542
|
return this.indentStr(`return ${valueCode}`);
|
|
514
543
|
}
|
|
544
|
+
processDebuggerStatement(node) {
|
|
545
|
+
return this.indentStr(node.label ? `debugger(${JSON.stringify(node.label)})` : "debugger()");
|
|
546
|
+
}
|
|
515
547
|
// Utility methods
|
|
516
548
|
processComment(node) {
|
|
517
549
|
return this.indentStr(`//${node.content}`);
|
|
@@ -521,7 +553,10 @@ export class AgencyGenerator {
|
|
|
521
553
|
}
|
|
522
554
|
processImportStatement(node) {
|
|
523
555
|
const importedNames = node.importedNames.map((name) => this.processImportNameType(name));
|
|
524
|
-
const
|
|
556
|
+
const modulePath = node.modulePath.startsWith("std::")
|
|
557
|
+
? node.modulePath.replace(/\.agency$/, "")
|
|
558
|
+
: node.modulePath;
|
|
559
|
+
const str = this.indentStr(`import ${importedNames.join(", ")} from "${modulePath}"`);
|
|
525
560
|
return str;
|
|
526
561
|
}
|
|
527
562
|
processImportNameType(node) {
|
|
@@ -540,7 +575,8 @@ export class AgencyGenerator {
|
|
|
540
575
|
return `import node { ${node.importedNodes.join(", ")} } from "${node.agencyFile}"`;
|
|
541
576
|
}
|
|
542
577
|
processImportToolStatement(node) {
|
|
543
|
-
|
|
578
|
+
const toolNames = node.importedTools.flatMap((n) => n.importedNames);
|
|
579
|
+
return `import tool { ${toolNames.join(", ")} } from "${node.agencyFile}"`;
|
|
544
580
|
}
|
|
545
581
|
visibilityToString(vis) {
|
|
546
582
|
switch (vis) {
|
|
@@ -569,7 +605,7 @@ export class AgencyGenerator {
|
|
|
569
605
|
for (const stmt of body) {
|
|
570
606
|
lines.push(this.processNode(stmt));
|
|
571
607
|
}
|
|
572
|
-
const bodyCode = lines.join("").trimEnd() + "\n";
|
|
608
|
+
const bodyCode = lines.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
573
609
|
result += bodyCode;
|
|
574
610
|
this.decreaseIndent();
|
|
575
611
|
result += this.indentStr(`}`);
|
|
@@ -585,7 +621,7 @@ export class AgencyGenerator {
|
|
|
585
621
|
return this.indentStr(`@${node.name} = ${this.processNode(node.value).trim()}`);
|
|
586
622
|
}
|
|
587
623
|
processNewLine(_node) {
|
|
588
|
-
return "
|
|
624
|
+
return "";
|
|
589
625
|
}
|
|
590
626
|
processMessageThread(node) {
|
|
591
627
|
this.increaseIndent();
|
|
@@ -594,7 +630,7 @@ export class AgencyGenerator {
|
|
|
594
630
|
bodyCodes.push(this.processNode(stmt));
|
|
595
631
|
}
|
|
596
632
|
this.decreaseIndent();
|
|
597
|
-
const bodyCodeStr = bodyCodes.join("");
|
|
633
|
+
const bodyCodeStr = bodyCodes.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
598
634
|
const threadType = node.threadType;
|
|
599
635
|
return this.indentStr(`${threadType} {\n${bodyCodeStr}${this.indentStr("}")}`);
|
|
600
636
|
}
|
|
@@ -605,7 +641,7 @@ export class AgencyGenerator {
|
|
|
605
641
|
bodyCodes.push(this.processNode(stmt));
|
|
606
642
|
}
|
|
607
643
|
this.decreaseIndent();
|
|
608
|
-
const bodyCodeStr = bodyCodes.join("");
|
|
644
|
+
const bodyCodeStr = bodyCodes.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
609
645
|
let handlerStr;
|
|
610
646
|
if (node.handler.kind === "inline") {
|
|
611
647
|
const paramStr = node.handler.param.typeHint
|
|
@@ -617,7 +653,7 @@ export class AgencyGenerator {
|
|
|
617
653
|
handlerBodyCodes.push(this.processNode(stmt));
|
|
618
654
|
}
|
|
619
655
|
this.decreaseIndent();
|
|
620
|
-
const handlerBodyStr = handlerBodyCodes.join("");
|
|
656
|
+
const handlerBodyStr = handlerBodyCodes.filter(s => s !== "").join("\n").trimEnd() + "\n";
|
|
621
657
|
handlerStr = `(${paramStr}) {\n${handlerBodyStr}${this.indentStr("}")}`;
|
|
622
658
|
}
|
|
623
659
|
else {
|
|
@@ -57,7 +57,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
57
57
|
];
|
|
58
58
|
testCases.forEach(({ description, input, expectedOutput }) => {
|
|
59
59
|
it(`should correctly generate ${description}`, () => {
|
|
60
|
-
const parseResult = parseAgency(input);
|
|
60
|
+
const parseResult = parseAgency(input, {}, false);
|
|
61
61
|
expect(parseResult.success).toBe(true);
|
|
62
62
|
if (!parseResult.success)
|
|
63
63
|
return;
|
|
@@ -73,7 +73,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
73
73
|
describe("Type preservation", () => {
|
|
74
74
|
it("should preserve primitive types", () => {
|
|
75
75
|
const input = "def test(n: number, s: string, b: boolean) { n }";
|
|
76
|
-
const parseResult = parseAgency(input);
|
|
76
|
+
const parseResult = parseAgency(input, {}, false);
|
|
77
77
|
expect(parseResult.success).toBe(true);
|
|
78
78
|
if (!parseResult.success)
|
|
79
79
|
return;
|
|
@@ -85,7 +85,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
85
85
|
});
|
|
86
86
|
it("should preserve array types", () => {
|
|
87
87
|
const input = "def test(nums: number[], strs: string[]) { nums }";
|
|
88
|
-
const parseResult = parseAgency(input);
|
|
88
|
+
const parseResult = parseAgency(input, {}, false);
|
|
89
89
|
expect(parseResult.success).toBe(true);
|
|
90
90
|
if (!parseResult.success)
|
|
91
91
|
return;
|
|
@@ -96,7 +96,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
96
96
|
});
|
|
97
97
|
it("should preserve union types", () => {
|
|
98
98
|
const input = "def test(val: string | number | boolean) { val }";
|
|
99
|
-
const parseResult = parseAgency(input);
|
|
99
|
+
const parseResult = parseAgency(input, {}, false);
|
|
100
100
|
expect(parseResult.success).toBe(true);
|
|
101
101
|
if (!parseResult.success)
|
|
102
102
|
return;
|
|
@@ -106,7 +106,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
106
106
|
});
|
|
107
107
|
it("should preserve nested array types", () => {
|
|
108
108
|
const input = "def test(matrix: number[][]) { matrix }";
|
|
109
|
-
const parseResult = parseAgency(input);
|
|
109
|
+
const parseResult = parseAgency(input, {}, false);
|
|
110
110
|
expect(parseResult.success).toBe(true);
|
|
111
111
|
if (!parseResult.success)
|
|
112
112
|
return;
|
|
@@ -118,7 +118,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
118
118
|
describe("Mixed typed and untyped parameters", () => {
|
|
119
119
|
it("should handle first parameter typed, second untyped", () => {
|
|
120
120
|
const input = "def test(x: number, y) { x }";
|
|
121
|
-
const parseResult = parseAgency(input);
|
|
121
|
+
const parseResult = parseAgency(input, {}, false);
|
|
122
122
|
expect(parseResult.success).toBe(true);
|
|
123
123
|
if (!parseResult.success)
|
|
124
124
|
return;
|
|
@@ -130,7 +130,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
130
130
|
});
|
|
131
131
|
it("should handle first parameter untyped, second typed", () => {
|
|
132
132
|
const input = "def test(x, y: string) { x }";
|
|
133
|
-
const parseResult = parseAgency(input);
|
|
133
|
+
const parseResult = parseAgency(input, {}, false);
|
|
134
134
|
expect(parseResult.success).toBe(true);
|
|
135
135
|
if (!parseResult.success)
|
|
136
136
|
return;
|
|
@@ -142,7 +142,7 @@ describe("AgencyGenerator - Function Parameter Type Hints", () => {
|
|
|
142
142
|
});
|
|
143
143
|
it("should handle alternating typed and untyped parameters", () => {
|
|
144
144
|
const input = "def test(a, b: number, c, d: string) { a }";
|
|
145
|
-
const parseResult = parseAgency(input);
|
|
145
|
+
const parseResult = parseAgency(input, {}, false);
|
|
146
146
|
expect(parseResult.success).toBe(true);
|
|
147
147
|
if (!parseResult.success)
|
|
148
148
|
return;
|
|
@@ -15,6 +15,9 @@ export declare class TypeScriptBuilder {
|
|
|
15
15
|
private loopVars;
|
|
16
16
|
private insideMessageThread;
|
|
17
17
|
private insideHandlerBody;
|
|
18
|
+
/** Stack of loop subKeys for generating break/continue cleanup code.
|
|
19
|
+
* Pushed when entering a stepped loop, popped when leaving. */
|
|
20
|
+
private _loopContextStack;
|
|
18
21
|
private _asyncBranchCheckNeeded;
|
|
19
22
|
/** Tracks the current substep nesting path. Empty when at the top level
|
|
20
23
|
* of a stepped body. Non-empty when inside a block (if/else, etc.) that
|
|
@@ -60,6 +63,7 @@ export declare class TypeScriptBuilder {
|
|
|
60
63
|
private needsParensRight;
|
|
61
64
|
build(program: AgencyProgram): TsNode;
|
|
62
65
|
private processNode;
|
|
66
|
+
private processKeyword;
|
|
63
67
|
private processTypeAlias;
|
|
64
68
|
private processTypeHint;
|
|
65
69
|
private processComment;
|
|
@@ -101,6 +105,8 @@ export declare class TypeScriptBuilder {
|
|
|
101
105
|
* response format from type hints, and tools from config object.
|
|
102
106
|
*/
|
|
103
107
|
private processLlmCall;
|
|
108
|
+
private processSentinel;
|
|
109
|
+
private processDebuggerStatement;
|
|
104
110
|
private buildPromptString;
|
|
105
111
|
private processSpecialVar;
|
|
106
112
|
private processMessageThread;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { formatTypeHint } from "../cli/util.js";
|
|
2
|
+
import { toCompiledImportPath } from "../importPaths.js";
|
|
2
3
|
import { BUILTIN_FUNCTIONS, BUILTIN_TOOLS, BUILTIN_VARIABLES, TYPES_THAT_DONT_TRIGGER_NEW_PART, } from "../config.js";
|
|
3
4
|
import * as renderImports from "../templates/backends/typescriptGenerator/imports.js";
|
|
4
5
|
import * as renderInterruptAssignment from "../templates/backends/typescriptGenerator/interruptAssignment.js";
|
|
5
6
|
import * as renderInterruptReturn from "../templates/backends/typescriptGenerator/interruptReturn.js";
|
|
7
|
+
import * as renderRewindCheckpoint from "../templates/backends/typescriptGenerator/rewindCheckpoint.js";
|
|
8
|
+
import * as renderDebugger from "../templates/backends/typescriptGenerator/debugger.js";
|
|
6
9
|
import { PRECEDENCE, } from "../types/binop.js";
|
|
7
10
|
import { expressionToString, getBaseVarName, walkNodesArray, } from "../utils/node.js";
|
|
8
11
|
import path from "path";
|
|
@@ -34,6 +37,9 @@ export class TypeScriptBuilder {
|
|
|
34
37
|
loopVars = [];
|
|
35
38
|
insideMessageThread = false;
|
|
36
39
|
insideHandlerBody = false;
|
|
40
|
+
/** Stack of loop subKeys for generating break/continue cleanup code.
|
|
41
|
+
* Pushed when entering a stepped loop, popped when leaving. */
|
|
42
|
+
_loopContextStack = [];
|
|
37
43
|
/*
|
|
38
44
|
We break up every function and node body into steps,
|
|
39
45
|
and wrap each statement in an if statement. If that statement
|
|
@@ -138,8 +144,8 @@ export class TypeScriptBuilder {
|
|
|
138
144
|
}
|
|
139
145
|
isImportedTool(functionName) {
|
|
140
146
|
return this.programInfo.importedTools
|
|
141
|
-
.
|
|
142
|
-
.
|
|
147
|
+
.flatMap((node) => node.importedTools)
|
|
148
|
+
.flatMap((n) => n.importedNames)
|
|
143
149
|
.includes(functionName);
|
|
144
150
|
}
|
|
145
151
|
// Runtime functions that need __state (ctx injection) like user-defined agency functions.
|
|
@@ -360,11 +366,37 @@ export class TypeScriptBuilder {
|
|
|
360
366
|
case "binOpExpression":
|
|
361
367
|
return this.processBinOpExpression(node);
|
|
362
368
|
case "keyword":
|
|
363
|
-
return
|
|
369
|
+
return this.processKeyword(node);
|
|
370
|
+
case "sentinel":
|
|
371
|
+
return this.processSentinel(node);
|
|
372
|
+
case "debuggerStatement":
|
|
373
|
+
return this.processDebuggerStatement(node);
|
|
364
374
|
default:
|
|
365
375
|
throw new Error(`Unhandled Agency node type: ${node.type}`);
|
|
366
376
|
}
|
|
367
377
|
}
|
|
378
|
+
processKeyword(node) {
|
|
379
|
+
const keyword = node.value === "break" ? ts.break() : ts.continue();
|
|
380
|
+
// Inside a handler body or not inside a stepped loop: emit bare keyword
|
|
381
|
+
const loopSubKey = this._loopContextStack[this._loopContextStack.length - 1];
|
|
382
|
+
if (this.insideHandlerBody || loopSubKey === undefined) {
|
|
383
|
+
return keyword;
|
|
384
|
+
}
|
|
385
|
+
// Inside a stepped loop: emit cleanup before the keyword.
|
|
386
|
+
// For continue, we also need to increment the iteration counters
|
|
387
|
+
// so the next iteration doesn't replay the current one.
|
|
388
|
+
const iterStore = `__stack.locals.__iteration_${loopSubKey}`;
|
|
389
|
+
const currentIterVar = `__currentIter_${loopSubKey}`;
|
|
390
|
+
const stmts = [
|
|
391
|
+
ts.raw(`__stack.resetLoopIteration("${loopSubKey}")`),
|
|
392
|
+
];
|
|
393
|
+
if (node.value === "continue") {
|
|
394
|
+
stmts.push(ts.raw(`${iterStore}++`));
|
|
395
|
+
stmts.push(ts.raw(`${currentIterVar}++`));
|
|
396
|
+
}
|
|
397
|
+
stmts.push(keyword);
|
|
398
|
+
return ts.statements(stmts);
|
|
399
|
+
}
|
|
368
400
|
// ------- Type system (side effects only) -------
|
|
369
401
|
processTypeAlias(node) {
|
|
370
402
|
return ts.raw(`type ${node.aliasName} = ${formatTypeHint(node.aliasedType)};`);
|
|
@@ -535,12 +567,14 @@ export class TypeScriptBuilder {
|
|
|
535
567
|
}
|
|
536
568
|
const subStepPath = [...this._subStepPath];
|
|
537
569
|
const subKey = subStepPath.join("_");
|
|
570
|
+
this._loopContextStack.push(subKey);
|
|
538
571
|
const bodyNodes = node.body.map((stmt, i) => {
|
|
539
572
|
this._subStepPath.push(i);
|
|
540
573
|
const result = this.processStatement(stmt);
|
|
541
574
|
this._subStepPath.pop();
|
|
542
575
|
return result;
|
|
543
576
|
});
|
|
577
|
+
this._loopContextStack.pop();
|
|
544
578
|
// Unregister loop variables
|
|
545
579
|
this.loopVars = this.loopVars.filter((v) => v !== node.itemVar && v !== node.indexVar);
|
|
546
580
|
// Range form: for (i in range(start, end))
|
|
@@ -584,13 +618,16 @@ export class TypeScriptBuilder {
|
|
|
584
618
|
}
|
|
585
619
|
processWhileLoopWithSteps(node) {
|
|
586
620
|
const subStepPath = [...this._subStepPath];
|
|
621
|
+
const subKey = subStepPath.join("_");
|
|
587
622
|
const condition = this.processNode(node.condition);
|
|
623
|
+
this._loopContextStack.push(subKey);
|
|
588
624
|
const bodyNodes = node.body.map((stmt, i) => {
|
|
589
625
|
this._subStepPath.push(i);
|
|
590
626
|
const result = this.processStatement(stmt);
|
|
591
627
|
this._subStepPath.pop();
|
|
592
628
|
return result;
|
|
593
629
|
});
|
|
630
|
+
this._loopContextStack.pop();
|
|
594
631
|
return ts.whileSteps(subStepPath, condition, bodyNodes);
|
|
595
632
|
}
|
|
596
633
|
processMatchBlockWithSteps(node) {
|
|
@@ -614,7 +651,7 @@ export class TypeScriptBuilder {
|
|
|
614
651
|
return ts.ifSteps(subStepPath, branches, elseBranch);
|
|
615
652
|
}
|
|
616
653
|
processImportStatement(node) {
|
|
617
|
-
const from = node.modulePath
|
|
654
|
+
const from = toCompiledImportPath(node.modulePath);
|
|
618
655
|
const imports = node.importedNames.map((nameType) => {
|
|
619
656
|
switch (nameType.type) {
|
|
620
657
|
case "namedImport":
|
|
@@ -643,17 +680,17 @@ export class TypeScriptBuilder {
|
|
|
643
680
|
return ts.empty(); // handled in preprocess
|
|
644
681
|
}
|
|
645
682
|
processImportToolStatement(node) {
|
|
646
|
-
const
|
|
647
|
-
|
|
683
|
+
const toolNames = node.importedTools.flatMap((n) => n.importedNames);
|
|
684
|
+
const importNames = toolNames
|
|
685
|
+
.flatMap((toolName) => [
|
|
648
686
|
toolName,
|
|
649
687
|
`__${toolName}Tool`,
|
|
650
688
|
`__${toolName}ToolParams`,
|
|
651
|
-
])
|
|
652
|
-
.flat();
|
|
689
|
+
]);
|
|
653
690
|
return ts.importDecl({
|
|
654
691
|
importKind: "named",
|
|
655
692
|
names: importNames,
|
|
656
|
-
from: node.agencyFile
|
|
693
|
+
from: toCompiledImportPath(node.agencyFile),
|
|
657
694
|
});
|
|
658
695
|
}
|
|
659
696
|
// ------- TsRaw wrapper methods (template-heavy) -------
|
|
@@ -720,7 +757,9 @@ export class TypeScriptBuilder {
|
|
|
720
757
|
entries[def.functionName] = this.buildToolRegistryEntry(def.functionName, def.functionName, false);
|
|
721
758
|
}
|
|
722
759
|
// Add imported tools (they import __toolNameTool and __toolNameToolParams)
|
|
723
|
-
const importedToolNames = this.programInfo.importedTools
|
|
760
|
+
const importedToolNames = this.programInfo.importedTools
|
|
761
|
+
.flatMap((node) => node.importedTools)
|
|
762
|
+
.flatMap((n) => n.importedNames);
|
|
724
763
|
for (const toolName of importedToolNames) {
|
|
725
764
|
entries[toolName] = this.buildToolRegistryEntry(toolName, toolName, false);
|
|
726
765
|
}
|
|
@@ -1316,6 +1355,25 @@ export class TypeScriptBuilder {
|
|
|
1316
1355
|
}
|
|
1317
1356
|
return ts.statements(stmts);
|
|
1318
1357
|
}
|
|
1358
|
+
processSentinel(node) {
|
|
1359
|
+
if (node.value === "checkpoint") {
|
|
1360
|
+
const promptNode = this.processNode(node.data.prompt);
|
|
1361
|
+
const varRef = ts.scopedVar(node.data.targetVariable, node.data.scope, this.moduleId);
|
|
1362
|
+
return ts.raw(renderRewindCheckpoint.default({
|
|
1363
|
+
targetVariable: node.data.targetVariable,
|
|
1364
|
+
prompt: printTs(promptNode),
|
|
1365
|
+
response: printTs(varRef),
|
|
1366
|
+
}));
|
|
1367
|
+
}
|
|
1368
|
+
return ts.empty();
|
|
1369
|
+
}
|
|
1370
|
+
processDebuggerStatement(node) {
|
|
1371
|
+
const code = renderDebugger.default({
|
|
1372
|
+
label: node.label !== undefined ? JSON.stringify(node.label) : "undefined",
|
|
1373
|
+
nodeContext: this.isInsideGraphNode,
|
|
1374
|
+
});
|
|
1375
|
+
return ts.raw(code);
|
|
1376
|
+
}
|
|
1319
1377
|
buildPromptString({ segments, typeHints, skills, }) {
|
|
1320
1378
|
const promptParts = [];
|
|
1321
1379
|
for (const segment of segments) {
|
|
@@ -1481,6 +1539,17 @@ export class TypeScriptBuilder {
|
|
|
1481
1539
|
return ts.handleSteps(subStepPath, handler, bodyNodes);
|
|
1482
1540
|
}
|
|
1483
1541
|
processBodyAsParts(body, opts = {}) {
|
|
1542
|
+
// Debugger mode: insert breakpoints before each step-triggering statement
|
|
1543
|
+
if (this.agencyConfig?.debugger) {
|
|
1544
|
+
const expanded = [];
|
|
1545
|
+
for (const stmt of body) {
|
|
1546
|
+
if (!TYPES_THAT_DONT_TRIGGER_NEW_PART.includes(stmt.type) && stmt.type !== "debuggerStatement") {
|
|
1547
|
+
expanded.push({ type: "debuggerStatement" });
|
|
1548
|
+
}
|
|
1549
|
+
expanded.push(stmt);
|
|
1550
|
+
}
|
|
1551
|
+
body = expanded;
|
|
1552
|
+
}
|
|
1484
1553
|
const parts = [[]];
|
|
1485
1554
|
// Maps step index to the branch key (subStepPath) captured at processing time
|
|
1486
1555
|
const branchKeys = {};
|
|
@@ -3,7 +3,7 @@ import { AgencyProgram } from "../index.js";
|
|
|
3
3
|
import { type SymbolTable } from "../symbolTable.js";
|
|
4
4
|
export declare function loadConfig(configPath?: string, verbose?: boolean): AgencyConfig;
|
|
5
5
|
export declare function readStdin(): Promise<string>;
|
|
6
|
-
export declare function parse(contents: string, config: AgencyConfig): AgencyProgram;
|
|
6
|
+
export declare function parse(contents: string, config: AgencyConfig, applyTemplate?: boolean): AgencyProgram;
|
|
7
7
|
export declare function readFile(inputFile: string): string;
|
|
8
8
|
export declare function renderGraph(contents: string, config: AgencyConfig): void;
|
|
9
9
|
export declare function resetCompilationCache(): void;
|
package/dist/lib/cli/commands.js
CHANGED
|
@@ -6,6 +6,7 @@ import { collectProgramInfo } from "../programInfo.js";
|
|
|
6
6
|
import { typeCheck, formatErrors } from "../typeChecker.js";
|
|
7
7
|
import { buildSymbolTable } from "../symbolTable.js";
|
|
8
8
|
import { resolveImports } from "../preprocessors/importResolver.js";
|
|
9
|
+
import { resolveAgencyImportPath, isStdlibImport, getStdlibDir, } from "../importPaths.js";
|
|
9
10
|
import { renderMermaidAscii } from "beautiful-mermaid";
|
|
10
11
|
import { spawn } from "child_process";
|
|
11
12
|
import * as fs from "fs";
|
|
@@ -52,14 +53,14 @@ export function readStdin() {
|
|
|
52
53
|
});
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
|
-
export function parse(contents, config) {
|
|
56
|
+
export function parse(contents, config, applyTemplate = true) {
|
|
56
57
|
const verbose = config.verbose ?? false;
|
|
57
|
-
const parseResult = parseAgency(contents, config);
|
|
58
|
+
const parseResult = parseAgency(contents, config, applyTemplate);
|
|
58
59
|
// Check if parsing was successful
|
|
59
60
|
if (!parseResult.success) {
|
|
60
61
|
console.error("Parse error:");
|
|
61
62
|
console.error(parseResult);
|
|
62
|
-
|
|
63
|
+
throw new Error("Failed to parse Agency program");
|
|
63
64
|
}
|
|
64
65
|
return parseResult.result;
|
|
65
66
|
}
|
|
@@ -120,7 +121,8 @@ export function compile(config, inputFile, _outputFile, options) {
|
|
|
120
121
|
}
|
|
121
122
|
compiledFiles.add(absoluteInputFile);
|
|
122
123
|
const contents = readFile(inputFile);
|
|
123
|
-
const
|
|
124
|
+
const isStdlibFile = absoluteInputFile.startsWith(getStdlibDir());
|
|
125
|
+
const parsedProgram = parse(contents, config, !isStdlibFile);
|
|
124
126
|
// Build symbol table once at the top level, reuse for recursive calls
|
|
125
127
|
const symbolTable = options?.symbolTable ?? buildSymbolTable(absoluteInputFile, config);
|
|
126
128
|
// Resolve unified imports into specialized AST nodes
|
|
@@ -140,10 +142,9 @@ export function compile(config, inputFile, _outputFile, options) {
|
|
|
140
142
|
}
|
|
141
143
|
}
|
|
142
144
|
const imports = getImports(resolvedProgram);
|
|
143
|
-
const inputDir = path.dirname(absoluteInputFile);
|
|
144
145
|
for (const importPath of imports) {
|
|
145
|
-
const absPath =
|
|
146
|
-
if (config.restrictImports) {
|
|
146
|
+
const absPath = resolveAgencyImportPath(importPath, absoluteInputFile);
|
|
147
|
+
if (config.restrictImports && !isStdlibImport(importPath)) {
|
|
147
148
|
const projectRoot = process.cwd();
|
|
148
149
|
if (!absPath.startsWith(projectRoot + path.sep) &&
|
|
149
150
|
absPath !== projectRoot) {
|
|
@@ -154,7 +155,7 @@ export function compile(config, inputFile, _outputFile, options) {
|
|
|
154
155
|
}
|
|
155
156
|
// Update the import path in the AST to reference the new .ts file
|
|
156
157
|
resolvedProgram.nodes.forEach((node) => {
|
|
157
|
-
if (node.type === "importStatement") {
|
|
158
|
+
if (node.type === "importStatement" && !isStdlibImport(node.modulePath)) {
|
|
158
159
|
node.modulePath = node.modulePath.replace(".agency", ext);
|
|
159
160
|
}
|
|
160
161
|
});
|
|
@@ -204,7 +205,7 @@ export function run(config, inputFile, outputFile, resumeFile) {
|
|
|
204
205
|
});
|
|
205
206
|
}
|
|
206
207
|
export async function format(contents, config) {
|
|
207
|
-
const parsedProgram = parse(contents, config);
|
|
208
|
+
const parsedProgram = parse(contents, config, false);
|
|
208
209
|
const generatedCode = generateAgency(parsedProgram);
|
|
209
210
|
return generatedCode;
|
|
210
211
|
}
|
package/dist/lib/cli/test.js
CHANGED
|
@@ -5,7 +5,7 @@ import prompts from "prompts";
|
|
|
5
5
|
import { executeJudge, executeNode, findRecursively, parseTarget, pickANode, promptForArgs, promptForTarget, } from "./util.js";
|
|
6
6
|
import { color } from "../utils/termcolors.js";
|
|
7
7
|
import path from "path";
|
|
8
|
-
import { compile } from "./commands.js";
|
|
8
|
+
import { compile, loadConfig } from "./commands.js";
|
|
9
9
|
import { execFileSync } from "child_process";
|
|
10
10
|
function readFile(filename) {
|
|
11
11
|
console.log("Trying to read file", filename, "...");
|
|
@@ -231,14 +231,22 @@ export function mergeStats(a, b) {
|
|
|
231
231
|
function runSingleTest(config, testFile, tests, testCase) {
|
|
232
232
|
const hasArgs = testCase.input !== "";
|
|
233
233
|
const relativeSourceFilePath = path.join(path.dirname(testFile), tests.sourceFile);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
234
|
+
let result;
|
|
235
|
+
try {
|
|
236
|
+
result = executeNode({
|
|
237
|
+
config,
|
|
238
|
+
agencyFile: relativeSourceFilePath,
|
|
239
|
+
nodeName: testCase.nodeName,
|
|
240
|
+
hasArgs,
|
|
241
|
+
argsString: testCase.input,
|
|
242
|
+
interruptHandlers: testCase.interruptHandlers,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch (e) {
|
|
246
|
+
exitIfSignal(e);
|
|
247
|
+
console.log(color.red(` ✗ Test execution error: ${e}`));
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
242
250
|
let testPassed = true;
|
|
243
251
|
for (const criterion of testCase.evaluationCriteria) {
|
|
244
252
|
if (criterion.type === "exact") {
|
|
@@ -383,10 +391,15 @@ export async function testTs(config, inputPaths) {
|
|
|
383
391
|
failures.push(dir);
|
|
384
392
|
continue;
|
|
385
393
|
}
|
|
386
|
-
// Compile the .agency file
|
|
394
|
+
// Compile the .agency file, merging any local agency.json config
|
|
387
395
|
const agencyPath = path.join(dir, agencyFile);
|
|
396
|
+
const localConfigPath = path.join(dir, "agency.json");
|
|
397
|
+
let mergedConfig = config;
|
|
398
|
+
if (fs.existsSync(localConfigPath)) {
|
|
399
|
+
mergedConfig = { ...config, ...loadConfig(localConfigPath) };
|
|
400
|
+
}
|
|
388
401
|
try {
|
|
389
|
-
compile(
|
|
402
|
+
compile(mergedConfig, agencyPath);
|
|
390
403
|
}
|
|
391
404
|
catch (e) {
|
|
392
405
|
console.log(color.red(` ✗ Compilation failed: ${e}`));
|
package/dist/lib/cli/util.js
CHANGED
|
@@ -5,6 +5,7 @@ const onCancel = () => {
|
|
|
5
5
|
import fs, { readFileSync } from "fs";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import { execFileSync } from "child_process";
|
|
8
|
+
import { isStdlibImport, resolveAgencyImportPath, getStdlibDir } from "../importPaths.js";
|
|
8
9
|
import renderEvaluate from "../templates/cli/evaluate.js";
|
|
9
10
|
import renderJudgeEvaluate from "../templates/cli/judgeEvaluate.js";
|
|
10
11
|
import { compile } from "./commands.js";
|
|
@@ -201,7 +202,8 @@ export function getImportsRecursively(filename, visited = new Set()) {
|
|
|
201
202
|
}
|
|
202
203
|
visited.add(filename);
|
|
203
204
|
const contents = fs.readFileSync(filename, "utf-8");
|
|
204
|
-
const
|
|
205
|
+
const isStdlibFile = filename.startsWith(getStdlibDir());
|
|
206
|
+
const parsed = parseAgency(contents, { verbose: false }, !isStdlibFile);
|
|
205
207
|
if (!parsed.success) {
|
|
206
208
|
console.error(`Error parsing ${filename}:`, parsed);
|
|
207
209
|
return [];
|
|
@@ -209,7 +211,7 @@ export function getImportsRecursively(filename, visited = new Set()) {
|
|
|
209
211
|
const program = parsed.result;
|
|
210
212
|
const imports = getImports(program);
|
|
211
213
|
for (const imp of imports) {
|
|
212
|
-
const importedFile =
|
|
214
|
+
const importedFile = resolveAgencyImportPath(imp, filename);
|
|
213
215
|
if (fs.existsSync(importedFile)) {
|
|
214
216
|
imports.push(...getImportsRecursively(importedFile, visited));
|
|
215
217
|
}
|
|
@@ -226,7 +228,8 @@ export function getImports(program) {
|
|
|
226
228
|
.map((node) => node.agencyFile.trim());
|
|
227
229
|
// this makes compile() try to parse non-agency files
|
|
228
230
|
const importStatements = program.nodes
|
|
229
|
-
.filter((node) => node.type === "importStatement" &&
|
|
231
|
+
.filter((node) => node.type === "importStatement" &&
|
|
232
|
+
(node.modulePath.endsWith(".agency") || isStdlibImport(node.modulePath)))
|
|
230
233
|
.map((node) => node.modulePath.trim());
|
|
231
234
|
return [...toolAndNodeImports, ...importStatements];
|
|
232
235
|
}
|