agency-lang 0.0.82 → 0.0.84
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 +37 -8
- package/dist/lib/backends/agencyGenerator.js +226 -34
- package/dist/lib/backends/index.d.ts +0 -1
- package/dist/lib/backends/index.js +0 -1
- package/dist/lib/backends/typescriptBuilder.d.ts +87 -0
- package/dist/lib/backends/typescriptBuilder.integration.test.d.ts +1 -0
- package/dist/lib/backends/typescriptBuilder.integration.test.js +95 -0
- package/dist/lib/backends/typescriptBuilder.js +1376 -0
- package/dist/lib/backends/typescriptBuilder.test.foo.d.ts +1 -0
- package/dist/lib/backends/typescriptBuilder.test.foo.js +5 -0
- package/dist/lib/backends/typescriptGenerator.d.ts +3 -121
- package/dist/lib/backends/typescriptGenerator.js +9 -1008
- package/dist/lib/cli/commands.js +6 -3
- package/dist/lib/cli/test.js +1 -1
- package/dist/lib/config.d.ts +2 -1
- package/dist/lib/config.js +10 -9
- package/dist/lib/ir/builders.d.ts +126 -0
- package/dist/lib/ir/builders.js +341 -0
- package/dist/lib/ir/fluent.d.ts +39 -0
- package/dist/lib/ir/fluent.js +66 -0
- package/dist/lib/ir/prettyPrint.d.ts +2 -0
- package/dist/lib/ir/prettyPrint.js +230 -0
- package/dist/lib/ir/prettyPrint.test.d.ts +1 -0
- package/dist/lib/ir/prettyPrint.test.js +264 -0
- package/dist/lib/ir/tsIR.d.ts +213 -0
- package/dist/lib/ir/tsIR.js +3 -0
- package/dist/lib/parser.js +2 -2
- package/dist/lib/parsers/assignment.test.js +41 -1
- package/dist/lib/parsers/function.d.ts +1 -0
- package/dist/lib/parsers/function.js +4 -0
- package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +2 -1
- package/dist/lib/preprocessors/typescriptPreprocessor.js +30 -11
- package/dist/lib/programInfo.d.ts +12 -0
- package/dist/lib/programInfo.js +37 -0
- package/dist/lib/programInfo.test.d.ts +1 -0
- package/dist/lib/programInfo.test.js +148 -0
- package/dist/lib/runtime/index.d.ts +1 -1
- package/dist/lib/runtime/interrupts.js +17 -22
- package/dist/lib/runtime/node.d.ts +2 -1
- package/dist/lib/runtime/node.js +12 -8
- package/dist/lib/runtime/prompt.js +0 -2
- package/dist/lib/runtime/state/context.d.ts +2 -0
- package/dist/lib/runtime/state/context.js +18 -0
- package/dist/lib/simplemachine/graph.d.ts +3 -3
- package/dist/lib/simplemachine/graph.js +2 -7
- package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +2 -14
- package/dist/lib/templates/backends/typescriptGenerator/imports.js +15 -51
- package/dist/lib/templates/backends/typescriptGenerator/interruptAssignment.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/interruptAssignment.js +0 -1
- package/dist/lib/templates/backends/typescriptGenerator/interruptReturn.d.ts +1 -1
- package/dist/lib/templates/backends/typescriptGenerator/interruptReturn.js +0 -1
- package/dist/lib/typeChecker.d.ts +3 -2
- package/dist/lib/typeChecker.js +20 -5
- package/dist/lib/types.d.ts +5 -1
- package/dist/scripts/agency.js +5 -2
- package/dist/scripts/regenerate-fixtures.js +37 -1
- package/package.json +3 -2
- package/dist/lib/backends/baseGenerator.d.ts +0 -89
- package/dist/lib/backends/baseGenerator.js +0 -334
- package/dist/lib/templates/backends/typescriptGenerator/builtinFunctions/time.d.ts +0 -8
- package/dist/lib/templates/backends/typescriptGenerator/builtinFunctions/time.js +0 -16
- package/dist/lib/templates/backends/typescriptGenerator/builtinTools.d.ts +0 -4
- package/dist/lib/templates/backends/typescriptGenerator/builtinTools.js +0 -21
- package/dist/lib/templates/backends/typescriptGenerator/conditionalEdge.d.ts +0 -7
- package/dist/lib/templates/backends/typescriptGenerator/conditionalEdge.js +0 -10
- package/dist/lib/templates/backends/typescriptGenerator/edge.d.ts +0 -7
- package/dist/lib/templates/backends/typescriptGenerator/edge.js +0 -10
- package/dist/lib/templates/backends/typescriptGenerator/functionCallAssignment.d.ts +0 -9
- package/dist/lib/templates/backends/typescriptGenerator/functionCallAssignment.js +0 -20
- package/dist/lib/templates/backends/typescriptGenerator/functionDefinition.d.ts +0 -10
- package/dist/lib/templates/backends/typescriptGenerator/functionDefinition.js +0 -36
- package/dist/lib/templates/backends/typescriptGenerator/goToNode.d.ts +0 -8
- package/dist/lib/templates/backends/typescriptGenerator/goToNode.js +0 -20
- package/dist/lib/templates/backends/typescriptGenerator/graphNode.d.ts +0 -9
- package/dist/lib/templates/backends/typescriptGenerator/graphNode.js +0 -32
- package/dist/lib/templates/backends/typescriptGenerator/initializeMessageThread.d.ts +0 -6
- package/dist/lib/templates/backends/typescriptGenerator/initializeMessageThread.js +0 -13
- package/dist/lib/templates/backends/typescriptGenerator/internalFunctionCall.d.ts +0 -10
- package/dist/lib/templates/backends/typescriptGenerator/internalFunctionCall.js +0 -18
- package/dist/lib/templates/backends/typescriptGenerator/messageThread.d.ts +0 -9
- package/dist/lib/templates/backends/typescriptGenerator/messageThread.js +0 -26
- package/dist/lib/templates/backends/typescriptGenerator/promptFunction.d.ts +0 -18
- package/dist/lib/templates/backends/typescriptGenerator/promptFunction.js +0 -47
- package/dist/lib/templates/backends/typescriptGenerator/runNodeFunction.d.ts +0 -9
- package/dist/lib/templates/backends/typescriptGenerator/runNodeFunction.js +0 -23
- package/dist/lib/templates/backends/typescriptGenerator/specialVar.d.ts +0 -7
- package/dist/lib/templates/backends/typescriptGenerator/specialVar.js +0 -9
- package/dist/lib/templates/backends/typescriptGenerator/startNode.d.ts +0 -4
- package/dist/lib/templates/backends/typescriptGenerator/startNode.js +0 -18
- package/dist/lib/templates/backends/typescriptGenerator/tool.d.ts +0 -9
- package/dist/lib/templates/backends/typescriptGenerator/tool.js +0 -16
- package/dist/lib/templates/backends/typescriptGenerator/toolCall.d.ts +0 -8
- package/dist/lib/templates/backends/typescriptGenerator/toolCall.js +0 -69
- package/dist/lib/templates/prompts/skill.d.ts +0 -6
- package/dist/lib/templates/prompts/skill.js +0 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SpecialVar } from "../types/specialVar.js";
|
|
2
|
-
import { AgencyComment, AgencyMultiLineComment, AgencyProgram, Assignment, Literal, NewLine, PromptLiteral, TypeAlias, TypeHint, VariableType } from "../types.js";
|
|
2
|
+
import { AgencyComment, AgencyMultiLineComment, AgencyNode, AgencyProgram, Assignment, Literal, NewLine, PromptLiteral, Scope, ScopeType, TypeAlias, TypeHint, TypeHintMap, VariableType } from "../types.js";
|
|
3
3
|
import { TimeBlock } from "../types/timeBlock.js";
|
|
4
4
|
import { AccessChainElement, ValueAccess } from "../types/access.js";
|
|
5
5
|
import { AgencyArray, AgencyObject } from "../types/dataStructures.js";
|
|
@@ -12,25 +12,55 @@ import { ReturnStatement } from "../types/returnStatement.js";
|
|
|
12
12
|
import { UsesTool } from "../types/tools.js";
|
|
13
13
|
import { ForLoop } from "../types/forLoop.js";
|
|
14
14
|
import { WhileLoop } from "../types/whileLoop.js";
|
|
15
|
-
import { BaseGenerator } from "./baseGenerator.js";
|
|
16
15
|
import { AgencyConfig } from "../config.js";
|
|
17
16
|
import { MessageThread } from "../types/messageThread.js";
|
|
18
17
|
import { Skill } from "../types/skill.js";
|
|
19
|
-
import { BinOpExpression } from "../types/binop.js";
|
|
18
|
+
import { BinOpArgument, BinOpExpression, Operator } from "../types/binop.js";
|
|
20
19
|
import { Keyword } from "../types/keyword.js";
|
|
21
|
-
export declare class AgencyGenerator
|
|
20
|
+
export declare class AgencyGenerator {
|
|
21
|
+
protected typeHints: TypeHintMap;
|
|
22
|
+
protected graphNodes: GraphNodeDefinition[];
|
|
23
|
+
protected generatedStatements: string[];
|
|
24
|
+
protected generatedTypeAliases: string[];
|
|
25
|
+
protected typeAliases: Record<string, VariableType>;
|
|
26
|
+
protected functionsUsed: Set<string>;
|
|
27
|
+
protected importStatements: string[];
|
|
28
|
+
protected importedNodes: ImportNodeStatement[];
|
|
29
|
+
protected importedTools: ImportToolStatement[];
|
|
30
|
+
protected functionDefinitions: Record<string, FunctionDefinition>;
|
|
31
|
+
protected currentScope: Scope[];
|
|
32
|
+
protected program: AgencyProgram | null;
|
|
33
|
+
protected agencyConfig: AgencyConfig;
|
|
22
34
|
private indentLevel;
|
|
23
35
|
private indentSize;
|
|
24
36
|
constructor(args?: {
|
|
25
37
|
config?: AgencyConfig;
|
|
26
38
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
configDefaults(): Partial<AgencyConfig>;
|
|
40
|
+
generate(program: AgencyProgram): {
|
|
41
|
+
output: string;
|
|
42
|
+
};
|
|
43
|
+
addIfNonEmpty(str: string, lines: string[]): void;
|
|
44
|
+
protected preprocessAST(): void;
|
|
30
45
|
protected generateBuiltins(): string;
|
|
31
46
|
protected generateImports(): string;
|
|
32
47
|
protected preprocess(): string;
|
|
33
48
|
protected postprocess(): string;
|
|
49
|
+
protected collectFunctionSignature(node: FunctionDefinition): void;
|
|
50
|
+
protected processGraphNodeName(node: GraphNodeDefinition): void;
|
|
51
|
+
protected processNode(node: AgencyNode): string;
|
|
52
|
+
protected needsParensLeft(child: BinOpArgument, parentOp: Operator): boolean;
|
|
53
|
+
protected needsParensRight(child: BinOpArgument, parentOp: Operator): boolean;
|
|
54
|
+
protected startScope(scope: Scope): void;
|
|
55
|
+
protected endScope(): void;
|
|
56
|
+
protected getCurrentScope(): Scope;
|
|
57
|
+
protected scopetoString(scope: ScopeType, varName?: string): string;
|
|
58
|
+
protected isImportedTool(functionName: string): boolean;
|
|
59
|
+
protected isAgencyFunction(functionName: string, context: "valueAccess" | "functionArg" | "topLevelStatement"): boolean;
|
|
60
|
+
private indent;
|
|
61
|
+
private increaseIndent;
|
|
62
|
+
private decreaseIndent;
|
|
63
|
+
private indentStr;
|
|
34
64
|
private stringifyProp;
|
|
35
65
|
protected aliasedTypeToString(aliasedType: VariableType): string;
|
|
36
66
|
protected processTypeAlias(node: TypeAlias): string;
|
|
@@ -65,7 +95,6 @@ export declare class AgencyGenerator extends BaseGenerator {
|
|
|
65
95
|
protected processTool(node: FunctionDefinition): string;
|
|
66
96
|
protected processUsesTool(node: UsesTool): string;
|
|
67
97
|
protected processSpecialVar(node: SpecialVar): string;
|
|
68
|
-
private indentStr;
|
|
69
98
|
protected processNewLine(_node: NewLine): string;
|
|
70
99
|
protected processMessageThread(node: MessageThread): string;
|
|
71
100
|
protected processSkill(node: Skill): string;
|
|
@@ -1,22 +1,93 @@
|
|
|
1
|
-
import { BaseGenerator } from "./baseGenerator.js";
|
|
2
1
|
import { variableTypeToString } from "./typescriptGenerator/typeToString.js";
|
|
2
|
+
import { BUILTIN_VARIABLES } from "../config.js";
|
|
3
|
+
import { mergeDeep } from "../utils.js";
|
|
4
|
+
import { PRECEDENCE, } from "../types/binop.js";
|
|
3
5
|
import { expressionToString } from "../utils/node.js";
|
|
4
|
-
export class AgencyGenerator
|
|
6
|
+
export class AgencyGenerator {
|
|
7
|
+
typeHints = {};
|
|
8
|
+
graphNodes = [];
|
|
9
|
+
generatedStatements = [];
|
|
10
|
+
generatedTypeAliases = [];
|
|
11
|
+
typeAliases = {};
|
|
12
|
+
functionsUsed = new Set();
|
|
13
|
+
importStatements = [];
|
|
14
|
+
importedNodes = [];
|
|
15
|
+
importedTools = [];
|
|
16
|
+
functionDefinitions = {};
|
|
17
|
+
currentScope = [{ type: "global" }];
|
|
18
|
+
program = null;
|
|
19
|
+
agencyConfig = {};
|
|
5
20
|
indentLevel = 0;
|
|
6
21
|
indentSize = 2;
|
|
7
22
|
constructor(args = {}) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
increaseIndent() {
|
|
14
|
-
this.indentLevel++;
|
|
23
|
+
this.agencyConfig = mergeDeep(this.configDefaults(), args.config || {});
|
|
24
|
+
if (this.agencyConfig.verbose) {
|
|
25
|
+
console.log("Generator config:", this.agencyConfig);
|
|
26
|
+
}
|
|
15
27
|
}
|
|
16
|
-
|
|
17
|
-
|
|
28
|
+
configDefaults() {
|
|
29
|
+
return {};
|
|
18
30
|
}
|
|
19
|
-
|
|
31
|
+
generate(program) {
|
|
32
|
+
this.program = program;
|
|
33
|
+
// Pass 1: Collect all type aliases
|
|
34
|
+
for (const node of program.nodes) {
|
|
35
|
+
if (node.type === "typeAlias") {
|
|
36
|
+
this.processTypeAlias(node);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Pass 2: Collect all type hints
|
|
40
|
+
for (const node of program.nodes) {
|
|
41
|
+
if (node.type === "typeHint") {
|
|
42
|
+
this.processTypeHint(node);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Pass 3: Collect all node names
|
|
46
|
+
for (const node of program.nodes) {
|
|
47
|
+
if (node.type === "graphNode") {
|
|
48
|
+
this.processGraphNodeName(node);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Pass 4: Collect all node and tool imports
|
|
52
|
+
for (const node of program.nodes) {
|
|
53
|
+
if (node.type === "importNodeStatement") {
|
|
54
|
+
this.importedNodes.push(node);
|
|
55
|
+
}
|
|
56
|
+
else if (node.type === "importToolStatement") {
|
|
57
|
+
this.importedTools.push(node);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Pass 5: Generate code for tools
|
|
61
|
+
for (const node of program.nodes) {
|
|
62
|
+
if (node.type === "function") {
|
|
63
|
+
this.generatedStatements.push(this.processTool(node));
|
|
64
|
+
this.collectFunctionSignature(node);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
this.preprocessAST();
|
|
68
|
+
// Pass 7: Process all nodes and generate code
|
|
69
|
+
for (const node of program.nodes) {
|
|
70
|
+
const result = this.processNode(node);
|
|
71
|
+
this.generatedStatements.push(result);
|
|
72
|
+
}
|
|
73
|
+
const output = [];
|
|
74
|
+
this.addIfNonEmpty(this.preprocess(), output);
|
|
75
|
+
this.addIfNonEmpty(this.importStatements.join("\n"), output);
|
|
76
|
+
this.addIfNonEmpty(this.generateImports(), output);
|
|
77
|
+
this.addIfNonEmpty(this.generateBuiltins(), output);
|
|
78
|
+
output.push(...this.generatedTypeAliases);
|
|
79
|
+
output.push(this.generatedStatements.join(""));
|
|
80
|
+
this.addIfNonEmpty(this.postprocess(), output);
|
|
81
|
+
return {
|
|
82
|
+
output: output.join("\n"),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
addIfNonEmpty(str, lines) {
|
|
86
|
+
if (str.trim() !== "") {
|
|
87
|
+
lines.push(str);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
preprocessAST() { }
|
|
20
91
|
generateBuiltins() {
|
|
21
92
|
return "";
|
|
22
93
|
}
|
|
@@ -29,8 +100,147 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
29
100
|
postprocess() {
|
|
30
101
|
return "";
|
|
31
102
|
}
|
|
103
|
+
collectFunctionSignature(node) {
|
|
104
|
+
this.functionDefinitions[node.functionName] = node;
|
|
105
|
+
}
|
|
106
|
+
processGraphNodeName(node) { }
|
|
107
|
+
processNode(node) {
|
|
108
|
+
switch (node.type) {
|
|
109
|
+
case "typeHint":
|
|
110
|
+
return this.processTypeHint(node);
|
|
111
|
+
case "typeAlias":
|
|
112
|
+
return this.processTypeAlias(node);
|
|
113
|
+
case "assignment":
|
|
114
|
+
return this.processAssignment(node);
|
|
115
|
+
case "function":
|
|
116
|
+
return this.processFunctionDefinition(node);
|
|
117
|
+
case "functionCall":
|
|
118
|
+
return this.processFunctionCall(node);
|
|
119
|
+
case "valueAccess":
|
|
120
|
+
return this.processValueAccess(node);
|
|
121
|
+
case "comment":
|
|
122
|
+
return this.processComment(node);
|
|
123
|
+
case "multiLineComment":
|
|
124
|
+
return this.processMultiLineComment(node);
|
|
125
|
+
case "matchBlock":
|
|
126
|
+
return this.processMatchBlock(node);
|
|
127
|
+
case "number":
|
|
128
|
+
case "multiLineString":
|
|
129
|
+
case "string":
|
|
130
|
+
case "variableName":
|
|
131
|
+
case "prompt":
|
|
132
|
+
case "boolean":
|
|
133
|
+
return this.generateLiteral(node);
|
|
134
|
+
case "returnStatement":
|
|
135
|
+
return this.processReturnStatement(node);
|
|
136
|
+
case "agencyArray":
|
|
137
|
+
return this.processAgencyArray(node);
|
|
138
|
+
case "agencyObject":
|
|
139
|
+
return this.processAgencyObject(node);
|
|
140
|
+
case "graphNode":
|
|
141
|
+
return this.processGraphNode(node);
|
|
142
|
+
case "usesTool":
|
|
143
|
+
return this.processUsesTool(node);
|
|
144
|
+
case "importStatement":
|
|
145
|
+
this.importStatements.push(this.processImportStatement(node));
|
|
146
|
+
return "";
|
|
147
|
+
case "importNodeStatement":
|
|
148
|
+
this.importStatements.push(this.processImportNodeStatement(node));
|
|
149
|
+
return "";
|
|
150
|
+
case "importToolStatement":
|
|
151
|
+
this.importStatements.push(this.processImportToolStatement(node));
|
|
152
|
+
return "";
|
|
153
|
+
case "forLoop":
|
|
154
|
+
return this.processForLoop(node);
|
|
155
|
+
case "whileLoop":
|
|
156
|
+
return this.processWhileLoop(node);
|
|
157
|
+
case "ifElse":
|
|
158
|
+
return this.processIfElse(node);
|
|
159
|
+
case "specialVar":
|
|
160
|
+
return this.processSpecialVar(node);
|
|
161
|
+
case "timeBlock":
|
|
162
|
+
return this.processTimeBlock(node);
|
|
163
|
+
case "newLine":
|
|
164
|
+
return this.processNewLine(node);
|
|
165
|
+
case "rawCode":
|
|
166
|
+
return node.value;
|
|
167
|
+
case "messageThread":
|
|
168
|
+
return this.processMessageThread(node);
|
|
169
|
+
case "skill":
|
|
170
|
+
return this.processSkill(node);
|
|
171
|
+
case "binOpExpression":
|
|
172
|
+
return this.processBinOpExpression(node);
|
|
173
|
+
case "keyword":
|
|
174
|
+
return this.processKeyword(node);
|
|
175
|
+
default:
|
|
176
|
+
throw new Error(`Unhandled Agency node type: ${node.type}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
needsParensLeft(child, parentOp) {
|
|
180
|
+
if (child.type !== "binOpExpression")
|
|
181
|
+
return false;
|
|
182
|
+
return PRECEDENCE[child.operator] < PRECEDENCE[parentOp];
|
|
183
|
+
}
|
|
184
|
+
needsParensRight(child, parentOp) {
|
|
185
|
+
if (child.type !== "binOpExpression")
|
|
186
|
+
return false;
|
|
187
|
+
return PRECEDENCE[child.operator] <= PRECEDENCE[parentOp];
|
|
188
|
+
}
|
|
189
|
+
startScope(scope) {
|
|
190
|
+
this.currentScope.push(scope);
|
|
191
|
+
}
|
|
192
|
+
endScope() {
|
|
193
|
+
this.currentScope.pop();
|
|
194
|
+
}
|
|
195
|
+
getCurrentScope() {
|
|
196
|
+
return this.currentScope[this.currentScope.length - 1];
|
|
197
|
+
}
|
|
198
|
+
scopetoString(scope, varName) {
|
|
199
|
+
if (varName && BUILTIN_VARIABLES.includes(varName)) {
|
|
200
|
+
return "";
|
|
201
|
+
}
|
|
202
|
+
switch (scope) {
|
|
203
|
+
case "global":
|
|
204
|
+
return "__globalCtx.stateStack.globals";
|
|
205
|
+
case "function":
|
|
206
|
+
case "node":
|
|
207
|
+
return "__stack.locals";
|
|
208
|
+
case "args":
|
|
209
|
+
return "__stack.args";
|
|
210
|
+
case "imported":
|
|
211
|
+
return "";
|
|
212
|
+
default:
|
|
213
|
+
throw new Error(`Unknown scope type: ${scope} for varName: ${varName}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
isImportedTool(functionName) {
|
|
217
|
+
return this.importedTools
|
|
218
|
+
.map((node) => node.importedTools)
|
|
219
|
+
.flat()
|
|
220
|
+
.includes(functionName);
|
|
221
|
+
}
|
|
222
|
+
isAgencyFunction(functionName, context) {
|
|
223
|
+
if (context === "valueAccess") {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
return (!!this.functionDefinitions[functionName] ||
|
|
227
|
+
this.isImportedTool(functionName));
|
|
228
|
+
}
|
|
229
|
+
// Indent helpers
|
|
230
|
+
indent(level = this.indentLevel) {
|
|
231
|
+
return " ".repeat(level * this.indentSize);
|
|
232
|
+
}
|
|
233
|
+
increaseIndent() {
|
|
234
|
+
this.indentLevel++;
|
|
235
|
+
}
|
|
236
|
+
decreaseIndent() {
|
|
237
|
+
this.indentLevel--;
|
|
238
|
+
}
|
|
239
|
+
indentStr(str) {
|
|
240
|
+
return `${this.indent()}${str}`;
|
|
241
|
+
}
|
|
242
|
+
// Type system methods
|
|
32
243
|
stringifyProp(prop) {
|
|
33
|
-
// if value is a union containing undefined, render as ?:
|
|
34
244
|
const isUnionWithUndefined = prop.value.type === "unionType" &&
|
|
35
245
|
prop.value.types.some((t) => t.type === "primitiveType" && t.value === "undefined");
|
|
36
246
|
if (isUnionWithUndefined) {
|
|
@@ -66,7 +276,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
66
276
|
}
|
|
67
277
|
return variableTypeToString(aliasedType, this.typeAliases);
|
|
68
278
|
}
|
|
69
|
-
// Type system methods
|
|
70
279
|
processTypeAlias(node) {
|
|
71
280
|
this.typeAliases[node.aliasName] = node.aliasedType;
|
|
72
281
|
const aliasedTypeStr = this.aliasedTypeToString(node.aliasedType);
|
|
@@ -85,12 +294,13 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
85
294
|
const varName = node.typeHint
|
|
86
295
|
? `${node.variableName}${chainStr}: ${variableTypeToString(node.typeHint, this.typeAliases)}`
|
|
87
296
|
: `${node.variableName}${chainStr}`;
|
|
297
|
+
const prefix = node.shared ? "shared " : "";
|
|
88
298
|
if (node.value.type === "timeBlock") {
|
|
89
299
|
const code = this.processTimeBlock(node.value);
|
|
90
|
-
return this.indentStr(`${varName} = ${code.trim()}\n`);
|
|
300
|
+
return this.indentStr(`${prefix}${varName} = ${code.trim()}\n`);
|
|
91
301
|
}
|
|
92
302
|
let valueCode = this.processNode(node.value).trim();
|
|
93
|
-
return this.indentStr(`${varName} = ${valueCode}`);
|
|
303
|
+
return this.indentStr(`${prefix}${varName} = ${valueCode}`);
|
|
94
304
|
}
|
|
95
305
|
processTimeBlock(node) {
|
|
96
306
|
this.increaseIndent();
|
|
@@ -168,21 +378,17 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
168
378
|
}
|
|
169
379
|
}
|
|
170
380
|
result += '"""';
|
|
171
|
-
//console.log(color.green(result));
|
|
172
381
|
return result
|
|
173
382
|
.split("\n")
|
|
174
383
|
.map((line) => this.indentStr(line))
|
|
175
384
|
.join("\n");
|
|
176
385
|
}
|
|
177
386
|
processPromptLiteral(variableName, variableType, node) {
|
|
178
|
-
// For agency code, prompts are just part of assignments
|
|
179
|
-
// This shouldn't be called directly, but return empty string
|
|
180
387
|
return "";
|
|
181
388
|
}
|
|
182
389
|
// Function methods
|
|
183
390
|
processFunctionDefinition(node) {
|
|
184
391
|
const { functionName, body, parameters } = node;
|
|
185
|
-
// Build parameter list
|
|
186
392
|
const params = parameters
|
|
187
393
|
.map((p) => {
|
|
188
394
|
if (p.typeHint) {
|
|
@@ -204,13 +410,10 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
204
410
|
else if (node.async === false) {
|
|
205
411
|
asyncPrefix = "sync ";
|
|
206
412
|
}
|
|
207
|
-
// Start function definition
|
|
208
413
|
let result = this.indentStr(`${asyncPrefix}def ${functionName}(${params})${returnTypeStr} {\n`);
|
|
209
|
-
// Process body with increased indentation
|
|
210
414
|
this.increaseIndent();
|
|
211
415
|
if (node.docString) {
|
|
212
416
|
const docLines = [`"""`, ...node.docString.value.split("\n"), `"""`];
|
|
213
|
-
//console.log(color.red(JSON.stringify(docLines)));
|
|
214
417
|
const docStr = docLines.map((line) => this.indentStr(line)).join("\n");
|
|
215
418
|
result += `${docStr}\n`;
|
|
216
419
|
}
|
|
@@ -221,7 +424,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
221
424
|
const bodyCode = lines.join("").trimEnd() + "\n";
|
|
222
425
|
result += bodyCode;
|
|
223
426
|
this.decreaseIndent();
|
|
224
|
-
// Close function
|
|
225
427
|
result += this.indentStr(`}`);
|
|
226
428
|
return result;
|
|
227
429
|
}
|
|
@@ -298,16 +500,13 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
298
500
|
let result = this.indentStr(`match(${exprCode}) {\n`);
|
|
299
501
|
this.increaseIndent();
|
|
300
502
|
for (const caseNode of node.cases) {
|
|
301
|
-
// Handle comments within cases
|
|
302
503
|
if (caseNode.type === "comment") {
|
|
303
504
|
result += this.processComment(caseNode);
|
|
304
505
|
continue;
|
|
305
506
|
}
|
|
306
|
-
// Format case value (pattern)
|
|
307
507
|
const pattern = caseNode.caseValue === "_"
|
|
308
508
|
? "_"
|
|
309
509
|
: this.processNode(caseNode.caseValue).trim();
|
|
310
|
-
// Format body (action)
|
|
311
510
|
const bodyCode = this.processNode(caseNode.body).trim();
|
|
312
511
|
result += this.indentStr(`${pattern} => ${bodyCode}\n`);
|
|
313
512
|
}
|
|
@@ -353,7 +552,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
353
552
|
lines.push(bodyLines.join("").trimEnd() + "\n");
|
|
354
553
|
if (node.elseBody && node.elseBody.length > 0) {
|
|
355
554
|
if (node.elseBody.length === 1 && node.elseBody[0].type === "ifElse") {
|
|
356
|
-
// Emit "} else if (...)" instead of "} else { if (...) }"
|
|
357
555
|
const elseIfCode = this.processIfElse(node.elseBody[0]);
|
|
358
556
|
lines.push(this.indentStr(`} else ${elseIfCode.trimStart()}`));
|
|
359
557
|
return lines.join("");
|
|
@@ -417,7 +615,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
417
615
|
}
|
|
418
616
|
}
|
|
419
617
|
processGraphNode(node) {
|
|
420
|
-
// Graph nodes use similar syntax to functions
|
|
421
618
|
const { nodeName, body, parameters } = node;
|
|
422
619
|
const params = parameters
|
|
423
620
|
.map((p) => p.typeHint
|
|
@@ -441,8 +638,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
441
638
|
return result;
|
|
442
639
|
}
|
|
443
640
|
processTool(node) {
|
|
444
|
-
// For agency code, tools are just functions
|
|
445
|
-
// No special formatting needed
|
|
446
641
|
return "";
|
|
447
642
|
}
|
|
448
643
|
processUsesTool(node) {
|
|
@@ -451,9 +646,6 @@ export class AgencyGenerator extends BaseGenerator {
|
|
|
451
646
|
processSpecialVar(node) {
|
|
452
647
|
return this.indentStr(`@${node.name} = ${this.processNode(node.value).trim()}`);
|
|
453
648
|
}
|
|
454
|
-
indentStr(str) {
|
|
455
|
-
return `${this.indent()}${str}`;
|
|
456
|
-
}
|
|
457
649
|
processNewLine(_node) {
|
|
458
650
|
return "\n";
|
|
459
651
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { AgencyProgram } from "../types.js";
|
|
2
|
+
import { AgencyConfig } from "../config.js";
|
|
3
|
+
import type { TsNode } from "../ir/tsIR.js";
|
|
4
|
+
import type { ProgramInfo } from "../programInfo.js";
|
|
5
|
+
export declare class TypeScriptBuilder {
|
|
6
|
+
private typeHints;
|
|
7
|
+
private typeAliases;
|
|
8
|
+
private graphNodes;
|
|
9
|
+
private generatedStatements;
|
|
10
|
+
private generatedTypeAliases;
|
|
11
|
+
private importStatements;
|
|
12
|
+
private importedNodes;
|
|
13
|
+
private importedTools;
|
|
14
|
+
private functionDefinitions;
|
|
15
|
+
private functionsUsed;
|
|
16
|
+
private currentScope;
|
|
17
|
+
private agencyConfig;
|
|
18
|
+
private adjacentNodes;
|
|
19
|
+
private currentAdjacentNodes;
|
|
20
|
+
private isInsideGraphNode;
|
|
21
|
+
private parallelThreadVars;
|
|
22
|
+
private loopVars;
|
|
23
|
+
private safeFunctions;
|
|
24
|
+
private importedFunctions;
|
|
25
|
+
private programInfo;
|
|
26
|
+
constructor(config: AgencyConfig | undefined, info: ProgramInfo);
|
|
27
|
+
private configDefaults;
|
|
28
|
+
/** Convert a TsNode to string (for use in template-based methods) */
|
|
29
|
+
private str;
|
|
30
|
+
private startScope;
|
|
31
|
+
private endScope;
|
|
32
|
+
private getCurrentScope;
|
|
33
|
+
private scopetoString;
|
|
34
|
+
private isImportedTool;
|
|
35
|
+
private isAgencyFunction;
|
|
36
|
+
private isGraphNode;
|
|
37
|
+
private isImpureImportedFunction;
|
|
38
|
+
private containsImpureCall;
|
|
39
|
+
private getScopeReturnType;
|
|
40
|
+
private agencyFileToDefaultImportName;
|
|
41
|
+
private needsParensLeft;
|
|
42
|
+
private needsParensRight;
|
|
43
|
+
build(program: AgencyProgram): TsNode;
|
|
44
|
+
private processNode;
|
|
45
|
+
private processTypeAlias;
|
|
46
|
+
private processTypeHint;
|
|
47
|
+
private processComment;
|
|
48
|
+
private processAgencyObject;
|
|
49
|
+
private processAgencyArray;
|
|
50
|
+
private generateLiteral;
|
|
51
|
+
private generateStringLiteralNode;
|
|
52
|
+
private processValueAccess;
|
|
53
|
+
private processBinOpExpression;
|
|
54
|
+
private processIfElse;
|
|
55
|
+
private processForLoop;
|
|
56
|
+
private processWhileLoop;
|
|
57
|
+
private processMatchBlock;
|
|
58
|
+
private processImportStatement;
|
|
59
|
+
private processImportNodeStatement;
|
|
60
|
+
private processImportToolStatement;
|
|
61
|
+
private processUsesTool;
|
|
62
|
+
private processTool;
|
|
63
|
+
private processFunctionDefinition;
|
|
64
|
+
private processStatement;
|
|
65
|
+
private processFunctionCallAsStatement;
|
|
66
|
+
private processFunctionCall;
|
|
67
|
+
private generateFunctionCallExpression;
|
|
68
|
+
private generateNodeCallExpression;
|
|
69
|
+
private processGraphNode;
|
|
70
|
+
private processReturnStatement;
|
|
71
|
+
private processAssignment;
|
|
72
|
+
private renderAccessChain;
|
|
73
|
+
private buildAccessChain;
|
|
74
|
+
private buildAssignmentLhs;
|
|
75
|
+
private processPromptLiteral;
|
|
76
|
+
private generatePromptFunction;
|
|
77
|
+
private buildPromptString;
|
|
78
|
+
private processSpecialVar;
|
|
79
|
+
private processTimeBlock;
|
|
80
|
+
private processMessageThread;
|
|
81
|
+
private processParallelThread;
|
|
82
|
+
private processBodyAsParts;
|
|
83
|
+
private generateBuiltins;
|
|
84
|
+
private generateImports;
|
|
85
|
+
private preprocess;
|
|
86
|
+
private postprocess;
|
|
87
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateWithBuilder(agencySource: string): string;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { parseAgency } from "../parser.js";
|
|
3
|
+
import { TypeScriptBuilder } from "./typescriptBuilder.js";
|
|
4
|
+
import { TypescriptPreprocessor } from "../preprocessors/typescriptPreprocessor.js";
|
|
5
|
+
import { collectProgramInfo } from "../programInfo.js";
|
|
6
|
+
import { printTs } from "../ir/prettyPrint.js";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
function discoverFixtures(fixtureDir) {
|
|
10
|
+
const fixtures = [];
|
|
11
|
+
function scanDirectory(dir, relativePath = "") {
|
|
12
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const fullPath = path.join(dir, entry.name);
|
|
15
|
+
const relPath = relativePath
|
|
16
|
+
? `${relativePath}/${entry.name}`
|
|
17
|
+
: entry.name;
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
scanDirectory(fullPath, relPath);
|
|
20
|
+
}
|
|
21
|
+
else if (entry.isFile() && entry.name.endsWith(".agency")) {
|
|
22
|
+
const baseName = entry.name.replace(".agency", "");
|
|
23
|
+
const mtsPath = path.join(dir, `${baseName}.mjs`);
|
|
24
|
+
if (fs.existsSync(mtsPath)) {
|
|
25
|
+
const nameWithoutExt = relativePath
|
|
26
|
+
? `${relativePath}/${baseName}`
|
|
27
|
+
: baseName;
|
|
28
|
+
try {
|
|
29
|
+
fixtures.push({
|
|
30
|
+
name: nameWithoutExt,
|
|
31
|
+
agencyPath: fullPath,
|
|
32
|
+
mtsPath: mtsPath,
|
|
33
|
+
agencyContent: fs.readFileSync(fullPath, "utf-8"),
|
|
34
|
+
expectedTS: fs.readFileSync(mtsPath, "utf-8"),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`Cannot read fixture ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.warn(`Warning: No corresponding .mjs file for ${fullPath}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
scanDirectory(fixtureDir);
|
|
48
|
+
return fixtures.sort((a, b) => a.name.localeCompare(b.name));
|
|
49
|
+
}
|
|
50
|
+
function normalizeWhitespace(code) {
|
|
51
|
+
return (code
|
|
52
|
+
.replace(/\r\n/g, "\n")
|
|
53
|
+
.split("\n")
|
|
54
|
+
.map((line) => line.trimEnd())
|
|
55
|
+
.join("\n")
|
|
56
|
+
.replace(/\n\n\n+/g, "\n\n")
|
|
57
|
+
.trim()
|
|
58
|
+
.concat("\n"));
|
|
59
|
+
}
|
|
60
|
+
export function generateWithBuilder(agencySource) {
|
|
61
|
+
const parseResult = parseAgency(agencySource);
|
|
62
|
+
if (!parseResult.success) {
|
|
63
|
+
throw new Error(`Failed to parse: ${parseResult.message}`);
|
|
64
|
+
}
|
|
65
|
+
const info = collectProgramInfo(parseResult.result);
|
|
66
|
+
const preprocessor = new TypescriptPreprocessor(parseResult.result, {}, info);
|
|
67
|
+
const preprocessedProgram = preprocessor.preprocess();
|
|
68
|
+
const builder = new TypeScriptBuilder(undefined, info);
|
|
69
|
+
const ir = builder.build(preprocessedProgram);
|
|
70
|
+
return printTs(ir);
|
|
71
|
+
}
|
|
72
|
+
const FIXTURES_DIR = path.resolve(__dirname, "../../tests/typescriptBuilder");
|
|
73
|
+
describe("TypeScript Builder Integration Tests", () => {
|
|
74
|
+
const fixtures = discoverFixtures(FIXTURES_DIR);
|
|
75
|
+
if (fixtures.length === 0) {
|
|
76
|
+
it("should find test fixtures (add .agency + .mjs pairs to tests/typescriptBuilder/)", () => {
|
|
77
|
+
// No fixtures yet — this is expected initially.
|
|
78
|
+
// Add .agency files and run `make builder-fixtures` to generate .mjs files.
|
|
79
|
+
expect(true).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
describe.each(fixtures)("Fixture: $name", ({ name, agencyPath, agencyContent, expectedTS }) => {
|
|
84
|
+
it("should generate correct TypeScript output", () => {
|
|
85
|
+
let generatedTS;
|
|
86
|
+
try {
|
|
87
|
+
generatedTS = generateWithBuilder(agencyContent);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new Error(`Failed to generate TypeScript for fixture: ${name}\nFile: ${agencyPath}\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
+
}
|
|
92
|
+
expect(normalizeWhitespace(generatedTS)).toBe(normalizeWhitespace(expectedTS));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|