agency-lang 0.0.64 → 0.0.66

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 (52) hide show
  1. package/README.md +7 -0
  2. package/dist/lib/backends/agencyGenerator.d.ts +2 -0
  3. package/dist/lib/backends/agencyGenerator.js +5 -0
  4. package/dist/lib/backends/baseGenerator.d.ts +2 -0
  5. package/dist/lib/backends/baseGenerator.js +6 -0
  6. package/dist/lib/backends/graphGenerator.js +15 -5
  7. package/dist/lib/backends/typescriptGenerator.d.ts +2 -0
  8. package/dist/lib/backends/typescriptGenerator.js +7 -2
  9. package/dist/lib/cli/evaluate.js +8 -5
  10. package/dist/lib/cli/remoteRun.js +12 -0
  11. package/dist/lib/cli/test.js +9 -6
  12. package/dist/lib/cli/util.js +8 -5
  13. package/dist/lib/config.d.ts +3 -0
  14. package/dist/lib/parser.js +2 -1
  15. package/dist/lib/parsers/assignment.test.js +2 -2
  16. package/dist/lib/parsers/binop.d.ts +3 -0
  17. package/dist/lib/parsers/binop.js +8 -0
  18. package/dist/lib/parsers/binop.test.d.ts +1 -0
  19. package/dist/lib/parsers/binop.test.js +321 -0
  20. package/dist/lib/parsers/dataStructures.test.js +1 -1
  21. package/dist/lib/parsers/function.js +4 -3
  22. package/dist/lib/parsers/function.test.js +2 -2
  23. package/dist/lib/parsers/ifElse.test.js +3 -3
  24. package/dist/lib/parsers/literals.d.ts +4 -1
  25. package/dist/lib/parsers/literals.js +12 -2
  26. package/dist/lib/parsers/literals.test.js +48 -1
  27. package/dist/lib/parsers/matchBlock.d.ts +1 -1
  28. package/dist/lib/parsers/matchBlock.js +8 -7
  29. package/dist/lib/parsers/returnStatement.js +2 -1
  30. package/dist/lib/parsers/whileLoop.test.js +3 -3
  31. package/dist/lib/preprocessors/typescriptPreprocessor.js +13 -0
  32. package/dist/lib/templates/backends/graphGenerator/builtinTools.d.ts +1 -1
  33. package/dist/lib/templates/backends/graphGenerator/builtinTools.js +2 -2
  34. package/dist/lib/templates/backends/graphGenerator/imports.d.ts +5 -1
  35. package/dist/lib/templates/backends/graphGenerator/imports.js +15 -3
  36. package/dist/lib/templates/backends/graphGenerator/startNode.d.ts +2 -4
  37. package/dist/lib/templates/backends/graphGenerator/startNode.js +2 -2
  38. package/dist/lib/templates/backends/typescriptGenerator/internalFunctionCall.d.ts +1 -1
  39. package/dist/lib/templates/backends/typescriptGenerator/internalFunctionCall.js +2 -1
  40. package/dist/lib/templates/cli/evaluate.d.ts +1 -1
  41. package/dist/lib/templates/cli/evaluate.js +0 -1
  42. package/dist/lib/types/binop.d.ts +12 -0
  43. package/dist/lib/types/binop.js +1 -0
  44. package/dist/lib/types/ifElse.d.ts +2 -1
  45. package/dist/lib/types/literals.d.ts +5 -1
  46. package/dist/lib/types/matchBlock.d.ts +2 -1
  47. package/dist/lib/types/returnStatement.d.ts +2 -1
  48. package/dist/lib/types/whileLoop.d.ts +2 -1
  49. package/dist/lib/types.d.ts +3 -2
  50. package/dist/lib/utils/node.js +4 -0
  51. package/dist/lib/utils.js +11 -1
  52. package/package.json +5 -4
package/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Agency
2
2
  Agent Definition Language
3
3
 
4
+ ```ts
5
+ node main() {
6
+ result = llm("Say hello to world")
7
+ return result
8
+ }
9
+ ```
10
+
4
11
  ## Usage
5
12
 
6
13
  Add agency to a project:
@@ -16,6 +16,7 @@ import { BaseGenerator } from "./baseGenerator.js";
16
16
  import { AgencyConfig } from "../config.js";
17
17
  import { MessageThread } from "../types/messageThread.js";
18
18
  import { Skill } from "../types/skill.js";
19
+ import { BinOpExpression } from "../types/binop.js";
19
20
  export declare class AgencyGenerator extends BaseGenerator {
20
21
  private indentLevel;
21
22
  private indentSize;
@@ -68,5 +69,6 @@ export declare class AgencyGenerator extends BaseGenerator {
68
69
  protected processNewLine(_node: NewLine): string;
69
70
  protected processMessageThread(node: MessageThread): string;
70
71
  protected processSkill(node: Skill): string;
72
+ protected processBinOpExpression(node: BinOpExpression): string;
71
73
  }
72
74
  export declare function generateAgency(program: AgencyProgram): string;
@@ -90,6 +90,8 @@ export class AgencyGenerator extends BaseGenerator {
90
90
  return this.generateMultiLineStringLiteral(literal);
91
91
  case "prompt":
92
92
  return this.indentStr(this.generatePromptLiteral(literal));
93
+ case "boolean":
94
+ return literal.value ? "true" : "false";
93
95
  default:
94
96
  return "";
95
97
  }
@@ -430,6 +432,9 @@ export class AgencyGenerator extends BaseGenerator {
430
432
  processSkill(node) {
431
433
  return this.indentStr(`skill "${node.filepath}"`);
432
434
  }
435
+ processBinOpExpression(node) {
436
+ return `${this.processNode(node.left).trim()} ${node.operator} ${this.processNode(node.right).trim()}`;
437
+ }
433
438
  }
434
439
  export function generateAgency(program) {
435
440
  const generator = new AgencyGenerator();
@@ -15,6 +15,7 @@ import { WhileLoop } from "../types/whileLoop.js";
15
15
  import { AgencyConfig } from "../config.js";
16
16
  import { MessageThread } from "../types/messageThread.js";
17
17
  import { Skill } from "../types/skill.js";
18
+ import { BinOpExpression } from "../types/binop.js";
18
19
  export declare class BaseGenerator {
19
20
  protected typeHints: TypeHintMap;
20
21
  protected graphNodes: GraphNodeDefinition[];
@@ -44,6 +45,7 @@ export declare class BaseGenerator {
44
45
  protected collectFunctionSignature(node: FunctionDefinition): void;
45
46
  protected processGraphNodeName(node: GraphNodeDefinition): void;
46
47
  protected processNode(node: AgencyNode): string;
48
+ protected processBinOpExpression(node: BinOpExpression): string;
47
49
  protected processSkill(node: Skill): string;
48
50
  protected processMessageThread(node: MessageThread): string;
49
51
  protected processNewLine(_node: NewLine): string;
@@ -130,6 +130,7 @@ export class BaseGenerator {
130
130
  case "string":
131
131
  case "variableName":
132
132
  case "prompt":
133
+ case "boolean":
133
134
  // Standalone literals at top level
134
135
  return this.generateLiteral(node);
135
136
  case "returnStatement":
@@ -169,10 +170,15 @@ export class BaseGenerator {
169
170
  return this.processMessageThread(node);
170
171
  case "skill":
171
172
  return this.processSkill(node);
173
+ case "binOpExpression":
174
+ return this.processBinOpExpression(node);
172
175
  default:
173
176
  throw new Error(`Unhandled Agency node type: ${node.type}`);
174
177
  }
175
178
  }
179
+ processBinOpExpression(node) {
180
+ return "processBinOpExpression not implemented";
181
+ }
176
182
  processSkill(node) {
177
183
  return "processSkill not implemented";
178
184
  }
@@ -22,6 +22,9 @@ export class GraphGenerator extends TypeScriptGenerator {
22
22
  }
23
23
  configDefaults() {
24
24
  return {
25
+ log: {
26
+ host: "https://agency-lang.com",
27
+ },
25
28
  client: {
26
29
  logLevel: "warn",
27
30
  defaultModel: "gpt-4o-mini",
@@ -133,6 +136,9 @@ export class GraphGenerator extends TypeScriptGenerator {
133
136
  return "generateLiteral not implemented";
134
137
  } */
135
138
  generateImports() {
139
+ /* if (this.agencyConfig.verbose) {
140
+ console.log("Generating imports with config:", this.agencyConfig);
141
+ } */
136
142
  const args = {
137
143
  logHost: this.agencyConfig.log?.host || "",
138
144
  logProjectId: this.agencyConfig.log?.projectId || "",
@@ -141,6 +147,10 @@ export class GraphGenerator extends TypeScriptGenerator {
141
147
  logDebugMode: this.agencyConfig.log?.debugMode || false,
142
148
  clientLogLevel: this.agencyConfig.client?.logLevel || "warn",
143
149
  clientDefaultModel: this.agencyConfig.client?.defaultModel || "gpt-4o-mini",
150
+ hasOpenAiApiKey: !!this.agencyConfig.client?.openAiApiKey,
151
+ clientOpenAiApiKey: this.agencyConfig.client?.openAiApiKey || undefined,
152
+ hasGoogleApiKey: !!this.agencyConfig.client?.googleApiKey,
153
+ clientGoogleApiKey: this.agencyConfig.client?.googleApiKey || undefined,
144
154
  };
145
155
  const arr = [renderImports.default(args)];
146
156
  arr.push(builtinTools.default({}));
@@ -173,11 +183,6 @@ export class GraphGenerator extends TypeScriptGenerator {
173
183
  const defaultImportName = this.agencyFileToDefaultImportName(importNode.agencyFile);
174
184
  lines.push(`graph.merge(${defaultImportName});`);
175
185
  });
176
- if (this.graphNodes.map((n) => n.nodeName).includes("main")) {
177
- lines.push(renderStartNode.default({
178
- startNode: "main",
179
- }));
180
- }
181
186
  for (const node of this.graphNodes) {
182
187
  const args = node.parameters;
183
188
  const argsStr = args.map((arg) => arg.name).join(", ");
@@ -187,6 +192,11 @@ export class GraphGenerator extends TypeScriptGenerator {
187
192
  argsStr,
188
193
  }));
189
194
  }
195
+ if (this.graphNodes.map((n) => n.nodeName).includes("main")) {
196
+ lines.push(renderStartNode.default({
197
+ startNode: "main",
198
+ }));
199
+ }
190
200
  lines.push("export default graph;");
191
201
  return lines.join("\n");
192
202
  }
@@ -15,6 +15,7 @@ import { BaseGenerator } from "./baseGenerator.js";
15
15
  import { AgencyConfig } from "../config.js";
16
16
  import { MessageThread } from "../types/messageThread.js";
17
17
  import { Skill } from "../types/skill.js";
18
+ import { BinOpExpression } from "../types/binop.js";
18
19
  export declare class TypeScriptGenerator extends BaseGenerator {
19
20
  protected currentMessageThreadNodeId: string[];
20
21
  constructor(args?: {
@@ -78,6 +79,7 @@ export declare class TypeScriptGenerator extends BaseGenerator {
78
79
  protected processAwaitStatement(node: AwaitStatement): string;
79
80
  protected processMessageThread(node: MessageThread, varName?: string): string;
80
81
  protected processSkill(node: Skill): string;
82
+ protected processBinOpExpression(node: BinOpExpression): string;
81
83
  protected processBodyAsParts(body: AgencyNode[]): string[];
82
84
  }
83
85
  export declare function generateTypeScript(program: AgencyProgram, config?: AgencyConfig): string;
@@ -93,7 +93,7 @@ export class TypeScriptGenerator extends BaseGenerator {
93
93
  }
94
94
  }
95
95
  processMatchBlock(node) {
96
- let lines = [`switch (${this.generateLiteral(node.expression)}) {`];
96
+ let lines = [`switch (${this.processNode(node.expression)}) {`];
97
97
  for (const caseItem of node.cases) {
98
98
  if (caseItem.type === "comment") {
99
99
  lines.push(` // ${caseItem.content}`);
@@ -310,6 +310,8 @@ export class TypeScriptGenerator extends BaseGenerator {
310
310
  return `${this.scopetoString(literal.scope)}.${literal.value}`;
311
311
  case "prompt":
312
312
  return this.processPromptLiteral(DEFAULT_PROMPT_NAME, this.getScopeReturnType(), literal);
313
+ case "boolean":
314
+ return literal.value ? "true" : "false";
313
315
  }
314
316
  }
315
317
  getScopeReturnType() {
@@ -452,7 +454,7 @@ export class TypeScriptGenerator extends BaseGenerator {
452
454
  .join("\n");
453
455
  const clientConfig = prompt.config ? this.processNode(prompt.config) : "{}";
454
456
  const metadataObj = `{
455
- messages: __self.messages_${this.currentMessageThreadNodeId.at(-1)}.getMessages(),
457
+ messages: __self.messages_${this.currentMessageThreadNodeId.at(-1)}?.getMessages(),
456
458
  }`;
457
459
  const scopedFunctionArgs = functionArgs.map((arg) => {
458
460
  // Find the scope for this interpolated variable from the prompt segments
@@ -582,6 +584,9 @@ export class TypeScriptGenerator extends BaseGenerator {
582
584
  processSkill(node) {
583
585
  return "";
584
586
  }
587
+ processBinOpExpression(node) {
588
+ return `${this.processNode(node.left).trim()} ${node.operator} ${this.processNode(node.right).trim()}`;
589
+ }
585
590
  /* This generates the body of a node or function separated into multiple parts.
586
591
  You can think of a part as roughly corresponding to a single statement
587
592
  (although some statements don't need their own parts, such as a newlines or type definitions).
@@ -3,6 +3,9 @@ import { getNodesOfType } from "../utils/node.js";
3
3
  import fs from "fs";
4
4
  import { nanoid } from "nanoid";
5
5
  import prompts from "prompts";
6
+ const onCancel = () => {
7
+ process.exit(0);
8
+ };
6
9
  import { executeNode, formatTypeHint, parseTarget, pickANode, promptForTarget, } from "./util.js";
7
10
  function readFile(filename) {
8
11
  const data = fs.readFileSync(filename);
@@ -48,7 +51,7 @@ async function createArgsFileInteractively(filename, selectedNode) {
48
51
  type: "text",
49
52
  name: "name",
50
53
  message: "Case name (optional, press enter to skip):",
51
- });
54
+ }, { onCancel });
52
55
  const args = {};
53
56
  for (const param of selectedNode.parameters) {
54
57
  const typeLabel = param.typeHint
@@ -58,7 +61,7 @@ async function createArgsFileInteractively(filename, selectedNode) {
58
61
  type: "text",
59
62
  name: "value",
60
63
  message: `Value for ${param.name}${typeLabel}:`,
61
- });
64
+ }, { onCancel });
62
65
  if (argResponse.value === undefined)
63
66
  break;
64
67
  args[param.name] = parseArgValue(argResponse.value);
@@ -73,7 +76,7 @@ async function createArgsFileInteractively(filename, selectedNode) {
73
76
  name: "more",
74
77
  message: "Add another case?",
75
78
  initial: true,
76
- });
79
+ }, { onCancel });
77
80
  addMore = moreResponse.more === true;
78
81
  }
79
82
  const argsFile = { cases };
@@ -120,7 +123,7 @@ export async function evaluate(config, target, argsFilePath, resultsFilePath) {
120
123
  name: "filename",
121
124
  message: "Args file name:",
122
125
  initial: defaultFilename,
123
- });
126
+ }, { onCancel });
124
127
  if (!filenameResponse.filename)
125
128
  return;
126
129
  if (fs.existsSync(filenameResponse.filename)) {
@@ -176,7 +179,7 @@ export async function evaluate(config, target, argsFilePath, resultsFilePath) {
176
179
  name: "rating",
177
180
  message: "Rate this output (1-5):",
178
181
  validate: (v) => v >= 1 && v <= 5 ? true : "Rating must be between 1 and 5",
179
- });
182
+ }, { onCancel });
180
183
  if (ratingResponse.rating === undefined) {
181
184
  console.log("\nEvaluation cancelled.");
182
185
  break;
@@ -1,6 +1,8 @@
1
1
  import { getStatelogClient } from "../statelogClient.js";
2
2
  import { getImportsRecursively } from "./util.js";
3
3
  import fs from "fs";
4
+ import { parseAgency } from "../parser.js";
5
+ import { exit } from "process";
4
6
  export async function remoteRun(config, filename) {
5
7
  const client = getStatelogClient({
6
8
  host: config.log?.host || "http://localhost:1065",
@@ -13,6 +15,16 @@ export async function remoteRun(config, filename) {
13
15
  name: file,
14
16
  contents: fs.readFileSync(file, "utf-8"),
15
17
  }));
18
+ const parsed = files.map((file) => {
19
+ return parseAgency(file.contents, config);
20
+ });
21
+ const errors = parsed
22
+ .filter((p) => p.success === false)
23
+ .map((p) => p.message);
24
+ if (errors.length > 0) {
25
+ console.error("Errors parsing agency files:", errors);
26
+ exit(1);
27
+ }
16
28
  const result = await client.remoteRun({
17
29
  files,
18
30
  entrypoint: filename,
@@ -33,6 +33,9 @@ function writeTestCase(agencyFilename, nodeName, input, expectedOutput, evaluati
33
33
  fs.writeFileSync(testFilePath, JSON.stringify(tests, null, 2));
34
34
  return testFilePath;
35
35
  }
36
+ const onCancel = () => {
37
+ process.exit(0);
38
+ };
36
39
  export async function fixtures(config, target) {
37
40
  let { filename, nodeName } = target
38
41
  ? parseTarget(target)
@@ -79,7 +82,7 @@ export async function fixtures(config, target) {
79
82
  { title: "Reject", value: "reject" },
80
83
  { title: "Modify arguments", value: "modify" },
81
84
  ],
82
- });
85
+ }, { onCancel });
83
86
  if (!actionResponse.action) {
84
87
  console.log("Interrupt handling cancelled.");
85
88
  return;
@@ -95,7 +98,7 @@ export async function fixtures(config, target) {
95
98
  type: "text",
96
99
  name: "args",
97
100
  message: "Enter modified arguments as JSON object:",
98
- });
101
+ }, { onCancel });
99
102
  if (!modifyResponse.args) {
100
103
  console.log("Interrupt handling cancelled.");
101
104
  return;
@@ -128,7 +131,7 @@ export async function fixtures(config, target) {
128
131
  name: "correct",
129
132
  message: "Does this output look correct?",
130
133
  initial: true,
131
- });
134
+ }, { onCancel });
132
135
  let expectedOutput;
133
136
  if (correctResponse.correct) {
134
137
  expectedOutput = JSON.stringify(json.data);
@@ -138,7 +141,7 @@ export async function fixtures(config, target) {
138
141
  type: "text",
139
142
  name: "expected",
140
143
  message: "What should the correct output look like?",
141
- });
144
+ }, { onCancel });
142
145
  expectedOutput = expectedResponse.expected;
143
146
  }
144
147
  const criteriaResponse = await prompts({
@@ -149,7 +152,7 @@ export async function fixtures(config, target) {
149
152
  { title: "Exact match", value: "exact" },
150
153
  { title: "LLM Judge", value: "llmJudge" },
151
154
  ],
152
- });
155
+ }, { onCancel });
153
156
  let criteria;
154
157
  if (criteriaResponse.criteria === "exact") {
155
158
  criteria = [{ type: "exact" }];
@@ -167,7 +170,7 @@ export async function fixtures(config, target) {
167
170
  message: "Desired accuracy (0-100):",
168
171
  initial: 80,
169
172
  },
170
- ]);
173
+ ], { onCancel });
171
174
  criteria = [
172
175
  {
173
176
  type: "llmJudge",
@@ -1,4 +1,7 @@
1
1
  import prompts from "prompts";
2
+ const onCancel = () => {
3
+ process.exit(0);
4
+ };
2
5
  import fs, { readFileSync } from "fs";
3
6
  import path from "path";
4
7
  import { execSync } from "child_process";
@@ -35,7 +38,7 @@ export async function promptForTarget() {
35
38
  name: "filename",
36
39
  message: "Select an Agency file to read:",
37
40
  choices: choices,
38
- });
41
+ }, { onCancel });
39
42
  filename = response.filename;
40
43
  // If user chose custom option, prompt for filename
41
44
  if (filename === "__custom__") {
@@ -43,7 +46,7 @@ export async function promptForTarget() {
43
46
  type: "text",
44
47
  name: "filename",
45
48
  message: "Enter the filename to read:",
46
- });
49
+ }, { onCancel });
47
50
  filename = customResponse.filename;
48
51
  }
49
52
  return { filename, nodeName };
@@ -57,7 +60,7 @@ export async function pickANode(nodes) {
57
60
  title: node.nodeName,
58
61
  value: node.nodeName,
59
62
  })),
60
- });
63
+ }, { onCancel });
61
64
  return response.node;
62
65
  }
63
66
  export async function promptForArgs(selectedNode) {
@@ -70,7 +73,7 @@ export async function promptForArgs(selectedNode) {
70
73
  name: "provideArgs",
71
74
  message: `This node has parameters (${paramNames}). Provide arguments?`,
72
75
  initial: true,
73
- });
76
+ }, { onCancel });
74
77
  if (confirmArgs.provideArgs) {
75
78
  const argValues = [];
76
79
  for (const param of selectedNode.parameters) {
@@ -81,7 +84,7 @@ export async function promptForArgs(selectedNode) {
81
84
  type: "text",
82
85
  name: "value",
83
86
  message: `Value for ${param.name}${typeLabel}:`,
84
- });
87
+ }, { onCancel });
85
88
  argValues.push(serializeArgValue(argResponse.value));
86
89
  }
87
90
  argsString = argValues.join(", ");
@@ -47,9 +47,12 @@ export interface AgencyConfig {
47
47
  debugMode: boolean;
48
48
  apiKey: string;
49
49
  }>;
50
+ /** Smoltalk client config */
50
51
  client?: Partial<{
51
52
  logLevel: "error" | "warn" | "info" | "debug";
52
53
  defaultModel: string;
54
+ openAiApiKey: string;
55
+ googleApiKey: string;
53
56
  }>;
54
57
  /**
55
58
  * If true, untyped variables are errors.
@@ -12,8 +12,9 @@ import { usesToolParser } from "./parsers/tools.js";
12
12
  import { typeAliasParser, typeHintParser } from "./parsers/typeHints.js";
13
13
  import { skillParser } from "./parsers/skill.js";
14
14
  import { nanoid } from "nanoid";
15
+ import { binOpParser } from "./parsers/binop.js";
15
16
  export const agencyNode = (input) => {
16
- const parser = many(trace("agencyParser", or(usesToolParser, importNodeStatmentParser, importToolStatmentParser, importStatmentParser, graphNodeParser, typeAliasParser, ifParser, whileLoopParser, typeHintParser, matchBlockParser, timeBlockParser, messageThreadParser, skillParser, streamingPromptLiteralParser, functionParser, returnStatementParser, specialVarParser, accessExpressionParser, assignmentParser, llmPromptFunctionCallParser, functionCallParser, commentParser, newLineParser)));
17
+ const parser = many(trace("agencyParser", or(usesToolParser, importNodeStatmentParser, importToolStatmentParser, importStatmentParser, graphNodeParser, typeAliasParser, ifParser, whileLoopParser, typeHintParser, matchBlockParser, timeBlockParser, messageThreadParser, skillParser, streamingPromptLiteralParser, functionParser, returnStatementParser, specialVarParser, assignmentParser, binOpParser, accessExpressionParser, llmPromptFunctionCallParser, functionCallParser, commentParser, newLineParser)));
17
18
  return parser(input);
18
19
  };
19
20
  export const agencyParser = seqC(set("type", "agencyProgram"), capture(agencyNode, "nodes"), eof);
@@ -107,7 +107,7 @@ describe("assignmentParser", () => {
107
107
  result: {
108
108
  type: "assignment",
109
109
  variableName: "_privateVar",
110
- value: { type: "variableName", value: "true" },
110
+ value: { type: "boolean", value: true },
111
111
  },
112
112
  },
113
113
  },
@@ -312,7 +312,7 @@ describe("assignmentParser", () => {
312
312
  type: "assignment",
313
313
  variableName: "isActive",
314
314
  typeHint: { type: "primitiveType", value: "boolean" },
315
- value: { type: "variableName", value: "true" },
315
+ value: { type: "boolean", value: true },
316
316
  },
317
317
  },
318
318
  },
@@ -0,0 +1,3 @@
1
+ import { BinOpExpression } from "../types/binop.js";
2
+ import { Parser } from "tarsec";
3
+ export declare const binOpParser: Parser<BinOpExpression>;
@@ -0,0 +1,8 @@
1
+ import { capture, oneOf, or, seqC, set, str, trace } from "tarsec";
2
+ import { simpleLiteralParser } from "./literals.js";
3
+ import { optionalSemicolon } from "./parserUtils.js";
4
+ import { optionalSpaces } from "./utils.js";
5
+ export const binOpParser = (input) => {
6
+ const parser = trace("binOpParser", seqC(set("type", "binOpExpression"), capture(simpleLiteralParser, "left"), optionalSpaces, capture(or(str("=="), str("!="), str("<="), str(">="), oneOf("+-*/<>")), "operator"), optionalSpaces, capture(simpleLiteralParser, "right"), optionalSemicolon));
7
+ return parser(input);
8
+ };
@@ -0,0 +1 @@
1
+ export {};