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.
Files changed (95) hide show
  1. package/dist/lib/backends/agencyGenerator.d.ts +37 -8
  2. package/dist/lib/backends/agencyGenerator.js +226 -34
  3. package/dist/lib/backends/index.d.ts +0 -1
  4. package/dist/lib/backends/index.js +0 -1
  5. package/dist/lib/backends/typescriptBuilder.d.ts +87 -0
  6. package/dist/lib/backends/typescriptBuilder.integration.test.d.ts +1 -0
  7. package/dist/lib/backends/typescriptBuilder.integration.test.js +95 -0
  8. package/dist/lib/backends/typescriptBuilder.js +1376 -0
  9. package/dist/lib/backends/typescriptBuilder.test.foo.d.ts +1 -0
  10. package/dist/lib/backends/typescriptBuilder.test.foo.js +5 -0
  11. package/dist/lib/backends/typescriptGenerator.d.ts +3 -121
  12. package/dist/lib/backends/typescriptGenerator.js +9 -1008
  13. package/dist/lib/cli/commands.js +6 -3
  14. package/dist/lib/cli/test.js +1 -1
  15. package/dist/lib/config.d.ts +2 -1
  16. package/dist/lib/config.js +10 -9
  17. package/dist/lib/ir/builders.d.ts +126 -0
  18. package/dist/lib/ir/builders.js +341 -0
  19. package/dist/lib/ir/fluent.d.ts +39 -0
  20. package/dist/lib/ir/fluent.js +66 -0
  21. package/dist/lib/ir/prettyPrint.d.ts +2 -0
  22. package/dist/lib/ir/prettyPrint.js +230 -0
  23. package/dist/lib/ir/prettyPrint.test.d.ts +1 -0
  24. package/dist/lib/ir/prettyPrint.test.js +264 -0
  25. package/dist/lib/ir/tsIR.d.ts +213 -0
  26. package/dist/lib/ir/tsIR.js +3 -0
  27. package/dist/lib/parser.js +2 -2
  28. package/dist/lib/parsers/assignment.test.js +41 -1
  29. package/dist/lib/parsers/function.d.ts +1 -0
  30. package/dist/lib/parsers/function.js +4 -0
  31. package/dist/lib/preprocessors/typescriptPreprocessor.d.ts +2 -1
  32. package/dist/lib/preprocessors/typescriptPreprocessor.js +30 -11
  33. package/dist/lib/programInfo.d.ts +12 -0
  34. package/dist/lib/programInfo.js +37 -0
  35. package/dist/lib/programInfo.test.d.ts +1 -0
  36. package/dist/lib/programInfo.test.js +148 -0
  37. package/dist/lib/runtime/index.d.ts +1 -1
  38. package/dist/lib/runtime/interrupts.js +17 -22
  39. package/dist/lib/runtime/node.d.ts +2 -1
  40. package/dist/lib/runtime/node.js +12 -8
  41. package/dist/lib/runtime/prompt.js +0 -2
  42. package/dist/lib/runtime/state/context.d.ts +2 -0
  43. package/dist/lib/runtime/state/context.js +18 -0
  44. package/dist/lib/simplemachine/graph.d.ts +3 -3
  45. package/dist/lib/simplemachine/graph.js +2 -7
  46. package/dist/lib/templates/backends/typescriptGenerator/imports.d.ts +2 -14
  47. package/dist/lib/templates/backends/typescriptGenerator/imports.js +15 -51
  48. package/dist/lib/templates/backends/typescriptGenerator/interruptAssignment.d.ts +1 -1
  49. package/dist/lib/templates/backends/typescriptGenerator/interruptAssignment.js +0 -1
  50. package/dist/lib/templates/backends/typescriptGenerator/interruptReturn.d.ts +1 -1
  51. package/dist/lib/templates/backends/typescriptGenerator/interruptReturn.js +0 -1
  52. package/dist/lib/typeChecker.d.ts +3 -2
  53. package/dist/lib/typeChecker.js +20 -5
  54. package/dist/lib/types.d.ts +5 -1
  55. package/dist/scripts/agency.js +5 -2
  56. package/dist/scripts/regenerate-fixtures.js +37 -1
  57. package/package.json +3 -2
  58. package/dist/lib/backends/baseGenerator.d.ts +0 -89
  59. package/dist/lib/backends/baseGenerator.js +0 -334
  60. package/dist/lib/templates/backends/typescriptGenerator/builtinFunctions/time.d.ts +0 -8
  61. package/dist/lib/templates/backends/typescriptGenerator/builtinFunctions/time.js +0 -16
  62. package/dist/lib/templates/backends/typescriptGenerator/builtinTools.d.ts +0 -4
  63. package/dist/lib/templates/backends/typescriptGenerator/builtinTools.js +0 -21
  64. package/dist/lib/templates/backends/typescriptGenerator/conditionalEdge.d.ts +0 -7
  65. package/dist/lib/templates/backends/typescriptGenerator/conditionalEdge.js +0 -10
  66. package/dist/lib/templates/backends/typescriptGenerator/edge.d.ts +0 -7
  67. package/dist/lib/templates/backends/typescriptGenerator/edge.js +0 -10
  68. package/dist/lib/templates/backends/typescriptGenerator/functionCallAssignment.d.ts +0 -9
  69. package/dist/lib/templates/backends/typescriptGenerator/functionCallAssignment.js +0 -20
  70. package/dist/lib/templates/backends/typescriptGenerator/functionDefinition.d.ts +0 -10
  71. package/dist/lib/templates/backends/typescriptGenerator/functionDefinition.js +0 -36
  72. package/dist/lib/templates/backends/typescriptGenerator/goToNode.d.ts +0 -8
  73. package/dist/lib/templates/backends/typescriptGenerator/goToNode.js +0 -20
  74. package/dist/lib/templates/backends/typescriptGenerator/graphNode.d.ts +0 -9
  75. package/dist/lib/templates/backends/typescriptGenerator/graphNode.js +0 -32
  76. package/dist/lib/templates/backends/typescriptGenerator/initializeMessageThread.d.ts +0 -6
  77. package/dist/lib/templates/backends/typescriptGenerator/initializeMessageThread.js +0 -13
  78. package/dist/lib/templates/backends/typescriptGenerator/internalFunctionCall.d.ts +0 -10
  79. package/dist/lib/templates/backends/typescriptGenerator/internalFunctionCall.js +0 -18
  80. package/dist/lib/templates/backends/typescriptGenerator/messageThread.d.ts +0 -9
  81. package/dist/lib/templates/backends/typescriptGenerator/messageThread.js +0 -26
  82. package/dist/lib/templates/backends/typescriptGenerator/promptFunction.d.ts +0 -18
  83. package/dist/lib/templates/backends/typescriptGenerator/promptFunction.js +0 -47
  84. package/dist/lib/templates/backends/typescriptGenerator/runNodeFunction.d.ts +0 -9
  85. package/dist/lib/templates/backends/typescriptGenerator/runNodeFunction.js +0 -23
  86. package/dist/lib/templates/backends/typescriptGenerator/specialVar.d.ts +0 -7
  87. package/dist/lib/templates/backends/typescriptGenerator/specialVar.js +0 -9
  88. package/dist/lib/templates/backends/typescriptGenerator/startNode.d.ts +0 -4
  89. package/dist/lib/templates/backends/typescriptGenerator/startNode.js +0 -18
  90. package/dist/lib/templates/backends/typescriptGenerator/tool.d.ts +0 -9
  91. package/dist/lib/templates/backends/typescriptGenerator/tool.js +0 -16
  92. package/dist/lib/templates/backends/typescriptGenerator/toolCall.d.ts +0 -8
  93. package/dist/lib/templates/backends/typescriptGenerator/toolCall.js +0 -69
  94. package/dist/lib/templates/prompts/skill.d.ts +0 -6
  95. 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 extends BaseGenerator {
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
- private indent;
28
- private increaseIndent;
29
- private decreaseIndent;
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 extends BaseGenerator {
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
- super(args);
9
- }
10
- indent(level = this.indentLevel) {
11
- return " ".repeat(level * this.indentSize);
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
- decreaseIndent() {
17
- this.indentLevel--;
28
+ configDefaults() {
29
+ return {};
18
30
  }
19
- // Lifecycle methods
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
  }
@@ -1,2 +1 @@
1
- export * from "./baseGenerator.js";
2
1
  export * from "./typescriptGenerator.js";
@@ -1,2 +1 @@
1
- export * from "./baseGenerator.js";
2
1
  export * from "./typescriptGenerator.js";
@@ -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
+ });