agency-lang 0.0.4 → 0.0.6
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/README.md +27 -0
- package/dist/lib/backends/agencyGenerator.d.ts +48 -0
- package/dist/lib/backends/agencyGenerator.js +228 -0
- package/dist/lib/parser.d.ts +1 -1
- package/dist/lib/parser.js +10 -1
- package/dist/lib/parsers/importStatement.test.js +4 -4
- package/dist/lib/parsers/typeHints.d.ts +1 -1
- package/dist/lib/parsers/typeHints.js +3 -3
- package/dist/lib/parsers/typeHints.test.js +20 -2
- package/dist/scripts/agency.js +56 -13
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
# Agency
|
|
2
2
|
Agent Definition Language
|
|
3
3
|
|
|
4
|
+
## Usage
|
|
5
|
+
|
|
6
|
+
Add agency to a project:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add agency-lang
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
You can then start using the agency script on your files:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# to compile
|
|
16
|
+
agency compile infile.agency outfile.ts
|
|
17
|
+
|
|
18
|
+
# to compile and run
|
|
19
|
+
agency run infile.agency
|
|
20
|
+
|
|
21
|
+
# or simply
|
|
22
|
+
agency infile.agency
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Note that the generated files use several other libraries that you will need to install as well:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm i nanoid openai egonSchiele/simplemachine statelog-client zod
|
|
29
|
+
```
|
|
30
|
+
|
|
4
31
|
## troubleshooting
|
|
5
32
|
### Weird undefined error
|
|
6
33
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AgencyComment, AgencyProgram, Assignment, Literal, PromptLiteral, TypeAlias, TypeHint } from "../types.js";
|
|
2
|
+
import { AccessExpression, DotFunctionCall, DotProperty, IndexAccess } from "../types/access.js";
|
|
3
|
+
import { AgencyArray, AgencyObject } from "../types/dataStructures.js";
|
|
4
|
+
import { FunctionCall, FunctionDefinition } from "../types/function.js";
|
|
5
|
+
import { GraphNodeDefinition } from "../types/graphNode.js";
|
|
6
|
+
import { ImportStatement } from "../types/importStatement.js";
|
|
7
|
+
import { MatchBlock } from "../types/matchBlock.js";
|
|
8
|
+
import { ReturnStatement } from "../types/returnStatement.js";
|
|
9
|
+
import { UsesTool } from "../types/tools.js";
|
|
10
|
+
import { WhileLoop } from "../types/whileLoop.js";
|
|
11
|
+
import { BaseGenerator } from "./baseGenerator.js";
|
|
12
|
+
export declare class AgencyGenerator extends BaseGenerator {
|
|
13
|
+
private indentLevel;
|
|
14
|
+
private indentSize;
|
|
15
|
+
constructor();
|
|
16
|
+
private indent;
|
|
17
|
+
private increaseIndent;
|
|
18
|
+
private decreaseIndent;
|
|
19
|
+
protected generateBuiltins(): string;
|
|
20
|
+
protected generateImports(): string;
|
|
21
|
+
protected preprocess(): string;
|
|
22
|
+
protected postprocess(): string;
|
|
23
|
+
protected processTypeAlias(node: TypeAlias): string;
|
|
24
|
+
protected processTypeHint(node: TypeHint): string;
|
|
25
|
+
protected processAssignment(node: Assignment): string;
|
|
26
|
+
protected generateLiteral(literal: Literal): string;
|
|
27
|
+
private generatePromptLiteral;
|
|
28
|
+
protected processPromptLiteral(variableName: string, node: PromptLiteral): string;
|
|
29
|
+
protected processFunctionDefinition(node: FunctionDefinition): string;
|
|
30
|
+
protected processFunctionCall(node: FunctionCall): string;
|
|
31
|
+
protected generateFunctionCallExpression(node: FunctionCall): string;
|
|
32
|
+
protected processAgencyArray(node: AgencyArray): string;
|
|
33
|
+
protected processAgencyObject(node: AgencyObject): string;
|
|
34
|
+
protected processAccessExpression(node: AccessExpression): string;
|
|
35
|
+
protected processDotProperty(node: DotProperty): string;
|
|
36
|
+
protected processIndexAccess(node: IndexAccess): string;
|
|
37
|
+
protected processDotFunctionCall(node: DotFunctionCall): string;
|
|
38
|
+
protected processMatchBlock(node: MatchBlock): string;
|
|
39
|
+
protected processWhileLoop(node: WhileLoop): string;
|
|
40
|
+
protected processReturnStatement(node: ReturnStatement): string;
|
|
41
|
+
protected processComment(node: AgencyComment): string;
|
|
42
|
+
protected processImportStatement(node: ImportStatement): string;
|
|
43
|
+
protected processGraphNode(node: GraphNodeDefinition): string;
|
|
44
|
+
protected processTool(node: FunctionDefinition): string;
|
|
45
|
+
protected processUsesTool(node: UsesTool): string;
|
|
46
|
+
private indentStr;
|
|
47
|
+
}
|
|
48
|
+
export declare function generateAgency(program: AgencyProgram): string;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { BaseGenerator } from "./baseGenerator.js";
|
|
2
|
+
import { variableTypeToString } from "./typescriptGenerator/typeToString.js";
|
|
3
|
+
export class AgencyGenerator extends BaseGenerator {
|
|
4
|
+
indentLevel = 0;
|
|
5
|
+
indentSize = 2;
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
}
|
|
9
|
+
indent() {
|
|
10
|
+
return " ".repeat(this.indentLevel * this.indentSize);
|
|
11
|
+
}
|
|
12
|
+
increaseIndent() {
|
|
13
|
+
this.indentLevel++;
|
|
14
|
+
}
|
|
15
|
+
decreaseIndent() {
|
|
16
|
+
this.indentLevel--;
|
|
17
|
+
}
|
|
18
|
+
// Lifecycle methods
|
|
19
|
+
generateBuiltins() {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
generateImports() {
|
|
23
|
+
return "";
|
|
24
|
+
}
|
|
25
|
+
preprocess() {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
postprocess() {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
// Type system methods
|
|
32
|
+
processTypeAlias(node) {
|
|
33
|
+
this.typeAliases[node.aliasName] = node.aliasedType;
|
|
34
|
+
const aliasedTypeStr = variableTypeToString(node.aliasedType, this.typeAliases);
|
|
35
|
+
return this.indentStr(`type ${node.aliasName} = ${aliasedTypeStr}\n`);
|
|
36
|
+
}
|
|
37
|
+
processTypeHint(node) {
|
|
38
|
+
this.typeHints[node.variableName] = node.variableType;
|
|
39
|
+
const typeStr = variableTypeToString(node.variableType, this.typeAliases);
|
|
40
|
+
return this.indentStr(`${node.variableName} :: ${typeStr}\n`);
|
|
41
|
+
}
|
|
42
|
+
// Assignment and literals
|
|
43
|
+
processAssignment(node) {
|
|
44
|
+
const valueCode = this.processNode(node.value).trim();
|
|
45
|
+
return this.indentStr(`${node.variableName} = ${valueCode}\n\n`);
|
|
46
|
+
}
|
|
47
|
+
generateLiteral(literal) {
|
|
48
|
+
switch (literal.type) {
|
|
49
|
+
case "number":
|
|
50
|
+
return literal.value;
|
|
51
|
+
case "string":
|
|
52
|
+
// Escape backslashes and quotes
|
|
53
|
+
const escaped = literal.value
|
|
54
|
+
.replace(/\\/g, "\\\\")
|
|
55
|
+
.replace(/"/g, '\\"');
|
|
56
|
+
return `"${escaped}"`;
|
|
57
|
+
case "variableName":
|
|
58
|
+
return literal.value;
|
|
59
|
+
case "prompt":
|
|
60
|
+
return this.generatePromptLiteral(literal);
|
|
61
|
+
default:
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
generatePromptLiteral(node) {
|
|
66
|
+
let result = "`";
|
|
67
|
+
for (const segment of node.segments) {
|
|
68
|
+
if (segment.type === "text") {
|
|
69
|
+
result += segment.value;
|
|
70
|
+
}
|
|
71
|
+
else if (segment.type === "interpolation") {
|
|
72
|
+
result += `\${${segment.variableName}}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
result += "`";
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
processPromptLiteral(variableName, node) {
|
|
79
|
+
// For agency code, prompts are just part of assignments
|
|
80
|
+
// This shouldn't be called directly, but return empty string
|
|
81
|
+
return "";
|
|
82
|
+
}
|
|
83
|
+
// Function methods
|
|
84
|
+
processFunctionDefinition(node) {
|
|
85
|
+
const { functionName, body, parameters } = node;
|
|
86
|
+
// Build parameter list
|
|
87
|
+
const params = parameters.join(", ");
|
|
88
|
+
// Start function definition
|
|
89
|
+
let result = this.indentStr(`def ${functionName}(${params}) {\n`);
|
|
90
|
+
// Process body with increased indentation
|
|
91
|
+
this.increaseIndent();
|
|
92
|
+
this.functionScopedVariables = [...parameters];
|
|
93
|
+
for (const stmt of body) {
|
|
94
|
+
result += this.processNode(stmt);
|
|
95
|
+
}
|
|
96
|
+
this.functionScopedVariables = [];
|
|
97
|
+
this.decreaseIndent();
|
|
98
|
+
// Close function
|
|
99
|
+
result += this.indentStr(`}\n\n`);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
processFunctionCall(node) {
|
|
103
|
+
const expr = this.generateFunctionCallExpression(node);
|
|
104
|
+
return this.indentStr(`${expr}\n`);
|
|
105
|
+
}
|
|
106
|
+
generateFunctionCallExpression(node) {
|
|
107
|
+
const args = node.arguments.map((arg) => {
|
|
108
|
+
return this.processNode(arg).trim();
|
|
109
|
+
});
|
|
110
|
+
return `${node.functionName}(${args.join(", ")})`;
|
|
111
|
+
}
|
|
112
|
+
// Data structures
|
|
113
|
+
processAgencyArray(node) {
|
|
114
|
+
const items = node.items.map((item) => {
|
|
115
|
+
return this.processNode(item).trim();
|
|
116
|
+
});
|
|
117
|
+
return `[${items.join(", ")}]`;
|
|
118
|
+
}
|
|
119
|
+
processAgencyObject(node) {
|
|
120
|
+
const entries = node.entries.map((entry) => {
|
|
121
|
+
const valueCode = this.processNode(entry.value).trim();
|
|
122
|
+
return `${entry.key}: ${valueCode}`;
|
|
123
|
+
});
|
|
124
|
+
return `{${entries.join(", ")}}`;
|
|
125
|
+
}
|
|
126
|
+
// Access expressions
|
|
127
|
+
processAccessExpression(node) {
|
|
128
|
+
switch (node.expression.type) {
|
|
129
|
+
case "dotProperty":
|
|
130
|
+
return this.processDotProperty(node.expression);
|
|
131
|
+
case "indexAccess":
|
|
132
|
+
return this.processIndexAccess(node.expression);
|
|
133
|
+
case "dotFunctionCall":
|
|
134
|
+
return this.processDotFunctionCall(node.expression);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
processDotProperty(node) {
|
|
138
|
+
const objectCode = this.processNode(node.object).trim();
|
|
139
|
+
return `${objectCode}.${node.propertyName}`;
|
|
140
|
+
}
|
|
141
|
+
processIndexAccess(node) {
|
|
142
|
+
const arrayCode = this.processNode(node.array).trim();
|
|
143
|
+
const indexCode = this.processNode(node.index).trim();
|
|
144
|
+
return `${arrayCode}[${indexCode}]`;
|
|
145
|
+
}
|
|
146
|
+
processDotFunctionCall(node) {
|
|
147
|
+
const objectCode = this.processNode(node.object).trim();
|
|
148
|
+
const functionCallCode = this.generateFunctionCallExpression(node.functionCall);
|
|
149
|
+
return `${objectCode}.${functionCallCode}`;
|
|
150
|
+
}
|
|
151
|
+
// Control flow
|
|
152
|
+
processMatchBlock(node) {
|
|
153
|
+
const exprCode = this.processNode(node.expression).trim();
|
|
154
|
+
let result = this.indentStr(`match(${exprCode}) {\n`);
|
|
155
|
+
this.increaseIndent();
|
|
156
|
+
for (const caseNode of node.cases) {
|
|
157
|
+
// Handle comments within cases
|
|
158
|
+
if (caseNode.type === "comment") {
|
|
159
|
+
result += this.processComment(caseNode);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// Format case value (pattern)
|
|
163
|
+
const pattern = caseNode.caseValue === "_"
|
|
164
|
+
? "_"
|
|
165
|
+
: this.processNode(caseNode.caseValue).trim();
|
|
166
|
+
// Format body (action)
|
|
167
|
+
const bodyCode = this.processNode(caseNode.body).trim();
|
|
168
|
+
result += this.indentStr(`${pattern} => ${bodyCode}\n`);
|
|
169
|
+
}
|
|
170
|
+
this.decreaseIndent();
|
|
171
|
+
result += this.indentStr(`}\n`);
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
processWhileLoop(node) {
|
|
175
|
+
const conditionCode = this.processNode(node.condition).trim();
|
|
176
|
+
let result = this.indentStr(`while (${conditionCode}) {\n`);
|
|
177
|
+
this.increaseIndent();
|
|
178
|
+
for (const stmt of node.body) {
|
|
179
|
+
result += this.processNode(stmt);
|
|
180
|
+
}
|
|
181
|
+
this.decreaseIndent();
|
|
182
|
+
result += this.indentStr(`}\n`);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
processReturnStatement(node) {
|
|
186
|
+
const valueCode = this.processNode(node.value).trim();
|
|
187
|
+
return this.indentStr(`return ${valueCode}\n`);
|
|
188
|
+
}
|
|
189
|
+
// Utility methods
|
|
190
|
+
processComment(node) {
|
|
191
|
+
return this.indentStr(`// ${node.content}\n`);
|
|
192
|
+
}
|
|
193
|
+
processImportStatement(node) {
|
|
194
|
+
return this.indentStr(`import {${node.importedNames}} from "${node.modulePath}"\n`);
|
|
195
|
+
}
|
|
196
|
+
processGraphNode(node) {
|
|
197
|
+
// Graph nodes use similar syntax to functions
|
|
198
|
+
const { nodeName, body, parameters } = node;
|
|
199
|
+
const params = parameters.join(", ");
|
|
200
|
+
let result = this.indentStr(`node ${nodeName}(${params}) {\n`);
|
|
201
|
+
this.increaseIndent();
|
|
202
|
+
this.functionScopedVariables = [...parameters];
|
|
203
|
+
for (const stmt of body) {
|
|
204
|
+
result += this.processNode(stmt);
|
|
205
|
+
}
|
|
206
|
+
this.functionScopedVariables = [];
|
|
207
|
+
this.decreaseIndent();
|
|
208
|
+
result += this.indentStr(`}\n`);
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
processTool(node) {
|
|
212
|
+
// For agency code, tools are just functions
|
|
213
|
+
// No special formatting needed
|
|
214
|
+
return "";
|
|
215
|
+
}
|
|
216
|
+
processUsesTool(node) {
|
|
217
|
+
// Track tool usage but don't generate code
|
|
218
|
+
this.toolsUsed.push(node.toolName);
|
|
219
|
+
return this.indentStr(`+${node.toolName}\n`);
|
|
220
|
+
}
|
|
221
|
+
indentStr(str) {
|
|
222
|
+
return `${this.indent()}${str}`;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
export function generateAgency(program) {
|
|
226
|
+
const generator = new AgencyGenerator();
|
|
227
|
+
return generator.generate(program).output.trim();
|
|
228
|
+
}
|
package/dist/lib/parser.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export declare const agencyNode: Parser<AgencyNode[]>;
|
|
|
4
4
|
export declare const agencyParser: Parser<AgencyProgram>;
|
|
5
5
|
export declare const _multilineCommentParser: Parser<string[]>;
|
|
6
6
|
export declare const multilineCommentParser: Parser<string[][]>;
|
|
7
|
-
export declare function parseAgency(input: string): ParserResult<AgencyProgram>;
|
|
7
|
+
export declare function parseAgency(input: string, verbose?: boolean): ParserResult<AgencyProgram>;
|
package/dist/lib/parser.js
CHANGED
|
@@ -9,6 +9,7 @@ import { importStatmentParser } from "./parsers/importStatement.js";
|
|
|
9
9
|
import { matchBlockParser } from "./parsers/matchBlock.js";
|
|
10
10
|
import { returnStatementParser } from "./parsers/returnStatement.js";
|
|
11
11
|
import { usesToolParser } from "./parsers/tools.js";
|
|
12
|
+
import { EgonLog } from "egonlog";
|
|
12
13
|
export const agencyNode = (input) => {
|
|
13
14
|
const parser = sepBy(spaces, trace("agencyParser", or(usesToolParser, importStatmentParser, graphNodeParser, typeAliasParser, whileLoopParser, typeHintParser, matchBlockParser, functionParser, returnStatementParser, accessExpressionParser, assignmentParser, functionCallParser, commentParser)));
|
|
14
15
|
return parser(input);
|
|
@@ -16,9 +17,15 @@ export const agencyNode = (input) => {
|
|
|
16
17
|
export const agencyParser = seqC(set("type", "agencyProgram"), capture(agencyNode, "nodes"), eof);
|
|
17
18
|
export const _multilineCommentParser = between(str("/*"), str("*/"), anyChar);
|
|
18
19
|
export const multilineCommentParser = search(_multilineCommentParser);
|
|
19
|
-
export function parseAgency(input) {
|
|
20
|
+
export function parseAgency(input, verbose = false) {
|
|
21
|
+
const logger = new EgonLog({ level: verbose ? "debug" : "warn" });
|
|
20
22
|
let normalized = input;
|
|
23
|
+
logger.debug("Starting to parse agency program");
|
|
24
|
+
logger.debug(`Input: ${input}`);
|
|
25
|
+
logger.debug("================================");
|
|
21
26
|
const comments = multilineCommentParser(normalized);
|
|
27
|
+
logger.debug(`Multiline comments: ${JSON.stringify(comments)}`);
|
|
28
|
+
logger.debug("================================");
|
|
22
29
|
// get rid of all multiline comments
|
|
23
30
|
normalized = comments.rest
|
|
24
31
|
.split("\n")
|
|
@@ -33,6 +40,8 @@ export function parseAgency(input) {
|
|
|
33
40
|
nodes: [],
|
|
34
41
|
}, "");
|
|
35
42
|
}
|
|
43
|
+
logger.debug(`Normalized input: ${normalized}`);
|
|
44
|
+
logger.debug("================================");
|
|
36
45
|
const result = agencyParser(normalized);
|
|
37
46
|
return result;
|
|
38
47
|
}
|
|
@@ -44,7 +44,7 @@ describe("importStatmentParser", () => {
|
|
|
44
44
|
result: {
|
|
45
45
|
type: "importStatement",
|
|
46
46
|
importedNames: "foo ",
|
|
47
|
-
modulePath: '"./local/path"',
|
|
47
|
+
modulePath: '"./local/path.js"',
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
},
|
|
@@ -55,7 +55,7 @@ describe("importStatmentParser", () => {
|
|
|
55
55
|
result: {
|
|
56
56
|
type: "importStatement",
|
|
57
57
|
importedNames: "bar ",
|
|
58
|
-
modulePath: '"
|
|
58
|
+
modulePath: '"../utils/helper.js"',
|
|
59
59
|
},
|
|
60
60
|
},
|
|
61
61
|
},
|
|
@@ -89,7 +89,7 @@ describe("importStatmentParser", () => {
|
|
|
89
89
|
result: {
|
|
90
90
|
type: "importStatement",
|
|
91
91
|
importedNames: "test ",
|
|
92
|
-
modulePath: "'./module'",
|
|
92
|
+
modulePath: "'./module.js'",
|
|
93
93
|
},
|
|
94
94
|
},
|
|
95
95
|
},
|
|
@@ -240,7 +240,7 @@ describe("importStatmentParser", () => {
|
|
|
240
240
|
result: {
|
|
241
241
|
type: "importStatement",
|
|
242
242
|
importedNames: "foo ",
|
|
243
|
-
modulePath: '"../../../utils/helpers"',
|
|
243
|
+
modulePath: '"../../../utils/helpers.js"',
|
|
244
244
|
},
|
|
245
245
|
},
|
|
246
246
|
},
|
|
@@ -7,7 +7,7 @@ export declare const angleBracketsArrayTypeParser: Parser<ArrayType>;
|
|
|
7
7
|
export declare const stringLiteralTypeParser: Parser<StringLiteralType>;
|
|
8
8
|
export declare const numberLiteralTypeParser: Parser<NumberLiteralType>;
|
|
9
9
|
export declare const booleanLiteralTypeParser: Parser<BooleanLiteralType>;
|
|
10
|
-
export declare const objectPropertyDelimiter: Parser<(string
|
|
10
|
+
export declare const objectPropertyDelimiter: Parser<"\n" | (string | string[])[]>;
|
|
11
11
|
export declare const objectPropertyParser: Parser<ObjectProperty>;
|
|
12
12
|
export declare const objectPropertyDescriptionParser: Parser<{
|
|
13
13
|
description: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { optionalSpaces, varNameChar } from "./utils.js";
|
|
2
|
-
import { capture, captureCaptures, char, count, digit, many1Till, many1WithJoin, or, sepBy, seqC, seqR, set, space, spaces, str, trace, } from "tarsec";
|
|
2
|
+
import { capture, captureCaptures, char, count, digit, many1Till, many1WithJoin, oneOf, or, sepBy, seqC, seqR, set, space, spaces, str, trace, } from "tarsec";
|
|
3
3
|
import { optionalSemicolon } from "./parserUtils.js";
|
|
4
4
|
export const primitiveTypeParser = trace("primitiveTypeParser", seqC(set("type", "primitiveType"), capture(or(str("number"), str("string"), str("boolean")), "value")));
|
|
5
5
|
export const typeAliasVariableParser = trace("typeAliasVariableParser", seqC(set("type", "typeAliasVariable"), capture(many1WithJoin(varNameChar), "aliasName")));
|
|
@@ -27,12 +27,12 @@ export const angleBracketsArrayTypeParser = trace("angleBracketsArrayTypeParser"
|
|
|
27
27
|
export const stringLiteralTypeParser = trace("stringLiteralTypeParser", seqC(set("type", "stringLiteralType"), char('"'), capture(many1Till(char('"')), "value"), char('"')));
|
|
28
28
|
export const numberLiteralTypeParser = trace("numberLiteralTypeParser", seqC(set("type", "numberLiteralType"), capture(many1WithJoin(or(char("-"), char("."), digit)), "value")));
|
|
29
29
|
export const booleanLiteralTypeParser = trace("booleanLiteralTypeParser", seqC(set("type", "booleanLiteralType"), capture(or(str("true"), str("false")), "value")));
|
|
30
|
-
export const objectPropertyDelimiter = seqR(optionalSpaces,
|
|
30
|
+
export const objectPropertyDelimiter = or(char("\n"), seqR(optionalSpaces, oneOf(",;"), optionalSpaces));
|
|
31
31
|
export const objectPropertyParser = trace("objectPropertyParser", (input) => {
|
|
32
32
|
const parser = seqC(capture(many1WithJoin(varNameChar), "key"), optionalSpaces, char(":"), optionalSpaces, capture(variableTypeParser, "value"));
|
|
33
33
|
return parser(input);
|
|
34
34
|
});
|
|
35
|
-
export const objectPropertyDescriptionParser = seqC(char("#"), optionalSpaces, capture(many1Till(
|
|
35
|
+
export const objectPropertyDescriptionParser = seqC(char("#"), optionalSpaces, capture(many1Till(oneOf(",;\n")), "description"));
|
|
36
36
|
export const objectPropertyWithDescriptionParser = trace("objectPropertyWithDescriptionParser", seqC(captureCaptures(objectPropertyParser), spaces, captureCaptures(objectPropertyDescriptionParser)));
|
|
37
37
|
export const objectTypeParser = trace("objectTypeParser", (input) => {
|
|
38
38
|
const parser = seqC(set("type", "objectType"), char("{"), optionalSpaces, capture(sepBy(objectPropertyDelimiter, or(objectPropertyWithDescriptionParser, objectPropertyParser)), "properties"), optionalSpaces, char("}"));
|
|
@@ -1012,6 +1012,24 @@ describe("objectPropertyDescriptionParser", () => {
|
|
|
1012
1012
|
},
|
|
1013
1013
|
},
|
|
1014
1014
|
},
|
|
1015
|
+
{
|
|
1016
|
+
input: "# comma,",
|
|
1017
|
+
expected: {
|
|
1018
|
+
success: true,
|
|
1019
|
+
result: {
|
|
1020
|
+
description: "comma",
|
|
1021
|
+
},
|
|
1022
|
+
},
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
input: "# newline",
|
|
1026
|
+
expected: {
|
|
1027
|
+
success: true,
|
|
1028
|
+
result: {
|
|
1029
|
+
description: "newline",
|
|
1030
|
+
},
|
|
1031
|
+
},
|
|
1032
|
+
},
|
|
1015
1033
|
{
|
|
1016
1034
|
input: "# with extra spaces ;",
|
|
1017
1035
|
expected: {
|
|
@@ -1022,11 +1040,11 @@ describe("objectPropertyDescriptionParser", () => {
|
|
|
1022
1040
|
},
|
|
1023
1041
|
},
|
|
1024
1042
|
{
|
|
1025
|
-
input: "# description with
|
|
1043
|
+
input: "# description with punctuation!;",
|
|
1026
1044
|
expected: {
|
|
1027
1045
|
success: true,
|
|
1028
1046
|
result: {
|
|
1029
|
-
description: "description with
|
|
1047
|
+
description: "description with punctuation!",
|
|
1030
1048
|
},
|
|
1031
1049
|
},
|
|
1032
1050
|
},
|
package/dist/scripts/agency.js
CHANGED
|
@@ -3,6 +3,7 @@ import { spawn } from "child_process";
|
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import { parseAgency } from "../lib/parser.js";
|
|
5
5
|
import { generateGraph } from "../lib/index.js";
|
|
6
|
+
import { generateAgency } from "../lib/backends/agencyGenerator.js";
|
|
6
7
|
function help() {
|
|
7
8
|
console.log(`
|
|
8
9
|
Agency Language CLI
|
|
@@ -11,6 +12,8 @@ Usage:
|
|
|
11
12
|
agency help Show this help message
|
|
12
13
|
agency compile <input> [output] Compile .agency file to TypeScript
|
|
13
14
|
agency run <input> [output] Compile and run .agency file
|
|
15
|
+
agency format <input> Format .agency file in place
|
|
16
|
+
agency parse <input> Parse .agency file and show AST
|
|
14
17
|
agency <input> Compile and run .agency file (shorthand)
|
|
15
18
|
|
|
16
19
|
Arguments:
|
|
@@ -18,32 +21,39 @@ Arguments:
|
|
|
18
21
|
output Path to output .ts file (optional)
|
|
19
22
|
Default: <input-name>.ts
|
|
20
23
|
|
|
24
|
+
Flags:
|
|
25
|
+
-v, --verbose Enable verbose logging during parsing
|
|
26
|
+
|
|
21
27
|
Examples:
|
|
22
28
|
agency help Show help
|
|
23
29
|
agency compile script.agency Compile to script.ts
|
|
24
30
|
agency compile script.agency out.ts Compile to out.ts
|
|
25
31
|
agency run script.agency Compile and run script.agency
|
|
32
|
+
agency -v parse script.agency Parse with verbose logging
|
|
26
33
|
agency script.agency Compile and run (shorthand)
|
|
27
34
|
`);
|
|
28
35
|
}
|
|
29
|
-
function
|
|
36
|
+
function parse(inputFile, verbose = false) {
|
|
30
37
|
// Validate input file
|
|
31
38
|
if (!fs.existsSync(inputFile)) {
|
|
32
39
|
console.error(`Error: Input file '${inputFile}' not found`);
|
|
33
40
|
process.exit(1);
|
|
34
41
|
}
|
|
35
|
-
// Determine output file name
|
|
36
|
-
const output = outputFile || inputFile.replace(".agency", ".ts");
|
|
37
42
|
// Read and parse the Agency file
|
|
38
43
|
const contents = fs.readFileSync(inputFile, "utf-8");
|
|
39
|
-
const parseResult = parseAgency(contents);
|
|
44
|
+
const parseResult = parseAgency(contents, verbose);
|
|
40
45
|
// Check if parsing was successful
|
|
41
46
|
if (!parseResult.success) {
|
|
42
47
|
console.error("Parse error:");
|
|
43
48
|
console.error(parseResult);
|
|
44
49
|
process.exit(1);
|
|
45
50
|
}
|
|
46
|
-
|
|
51
|
+
return parseResult.result;
|
|
52
|
+
}
|
|
53
|
+
function compile(inputFile, outputFile, verbose = false) {
|
|
54
|
+
// Determine output file name
|
|
55
|
+
const output = outputFile || inputFile.replace(".agency", ".ts");
|
|
56
|
+
const parsedProgram = parse(inputFile, verbose);
|
|
47
57
|
// Generate TypeScript code
|
|
48
58
|
const generatedCode = generateGraph(parsedProgram);
|
|
49
59
|
// Write to output file
|
|
@@ -51,9 +61,9 @@ function compile(inputFile, outputFile) {
|
|
|
51
61
|
console.log(`Generated ${output} from ${inputFile}`);
|
|
52
62
|
return output;
|
|
53
63
|
}
|
|
54
|
-
function run(inputFile, outputFile) {
|
|
64
|
+
function run(inputFile, outputFile, verbose = false) {
|
|
55
65
|
// Compile the file
|
|
56
|
-
const output = compile(inputFile, outputFile);
|
|
66
|
+
const output = compile(inputFile, outputFile, verbose);
|
|
57
67
|
// Run the generated TypeScript file with Node.js
|
|
58
68
|
console.log(`Running ${output}...`);
|
|
59
69
|
console.log("---");
|
|
@@ -71,6 +81,16 @@ function run(inputFile, outputFile) {
|
|
|
71
81
|
}
|
|
72
82
|
});
|
|
73
83
|
}
|
|
84
|
+
function format(inputFile, verbose = false) {
|
|
85
|
+
const parsedProgram = parse(inputFile, verbose);
|
|
86
|
+
// Generate TypeScript code
|
|
87
|
+
const generatedCode = generateAgency(parsedProgram);
|
|
88
|
+
// Write to output file
|
|
89
|
+
//fs.writeFileSync(inputFile, generatedCode, "utf-8");
|
|
90
|
+
// console.log(`Generated ${output} from ${inputFile}`);
|
|
91
|
+
console.log(generatedCode);
|
|
92
|
+
return generatedCode;
|
|
93
|
+
}
|
|
74
94
|
// Main CLI logic
|
|
75
95
|
function main() {
|
|
76
96
|
const args = process.argv.slice(2);
|
|
@@ -79,7 +99,12 @@ function main() {
|
|
|
79
99
|
help();
|
|
80
100
|
return;
|
|
81
101
|
}
|
|
82
|
-
|
|
102
|
+
// Extract verbose flag
|
|
103
|
+
const verboseIndex = args.findIndex((arg) => arg === "-v" || arg === "--verbose");
|
|
104
|
+
const verbose = verboseIndex !== -1;
|
|
105
|
+
// Remove verbose flag from args
|
|
106
|
+
const filteredArgs = args.filter((arg) => arg !== "-v" && arg !== "--verbose");
|
|
107
|
+
const command = filteredArgs[0];
|
|
83
108
|
switch (command) {
|
|
84
109
|
case "help":
|
|
85
110
|
case "--help":
|
|
@@ -87,25 +112,43 @@ function main() {
|
|
|
87
112
|
help();
|
|
88
113
|
break;
|
|
89
114
|
case "compile":
|
|
90
|
-
if (
|
|
115
|
+
if (filteredArgs.length < 2) {
|
|
91
116
|
console.error("Error: 'compile' command requires an input file");
|
|
92
117
|
console.error("Usage: agency compile <input> [output]");
|
|
93
118
|
process.exit(1);
|
|
94
119
|
}
|
|
95
|
-
compile(
|
|
120
|
+
compile(filteredArgs[1], filteredArgs[2], verbose);
|
|
96
121
|
break;
|
|
97
122
|
case "run":
|
|
98
|
-
if (
|
|
123
|
+
if (filteredArgs.length < 2) {
|
|
99
124
|
console.error("Error: 'run' command requires an input file");
|
|
100
125
|
console.error("Usage: agency run <input> [output]");
|
|
101
126
|
process.exit(1);
|
|
102
127
|
}
|
|
103
|
-
run(
|
|
128
|
+
run(filteredArgs[1], filteredArgs[2], verbose);
|
|
129
|
+
break;
|
|
130
|
+
case "fmt":
|
|
131
|
+
case "format":
|
|
132
|
+
if (filteredArgs.length < 1) {
|
|
133
|
+
console.error("Error: 'format' command requires an input file");
|
|
134
|
+
console.error("Usage: agency format <input>");
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
format(filteredArgs[1], verbose);
|
|
138
|
+
break;
|
|
139
|
+
case "parse":
|
|
140
|
+
if (filteredArgs.length < 1) {
|
|
141
|
+
console.error("Error: 'parse' command requires an input file");
|
|
142
|
+
console.error("Usage: agency parse <input>");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
const result = parse(filteredArgs[1], verbose);
|
|
146
|
+
console.log(JSON.stringify(result, null, 2));
|
|
104
147
|
break;
|
|
105
148
|
default:
|
|
106
149
|
// If first arg is not a recognized command, treat it as a file to run
|
|
107
150
|
if (command.endsWith(".agency") || fs.existsSync(command)) {
|
|
108
|
-
run(command,
|
|
151
|
+
run(command, filteredArgs[1], verbose);
|
|
109
152
|
}
|
|
110
153
|
else {
|
|
111
154
|
console.error(`Error: Unknown command '${command}'`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agency-lang",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "The Agency language",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"build": "rm -rf dist/ && tsc && tsc-alias",
|
|
10
10
|
"start": "node dist/lib/index.js",
|
|
11
11
|
"templates": "typestache ./lib/templates",
|
|
12
|
-
"typecheck": "tsc --noEmit"
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"agency": "node ./dist/scripts/agency.js"
|
|
13
14
|
},
|
|
14
15
|
"bin": {
|
|
15
16
|
"agency": "./dist/scripts/agency.js"
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
},
|
|
39
40
|
"homepage": "https://github.com/egonSchiele/agency-lang#readme",
|
|
40
41
|
"dependencies": {
|
|
42
|
+
"egonlog": "^0.0.2",
|
|
41
43
|
"nanoid": "^5.1.6",
|
|
42
44
|
"openai": "^6.15.0",
|
|
43
45
|
"simplemachine": "github:egonSchiele/simplemachine",
|