agency-lang 0.0.15 → 0.0.16

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 (38) hide show
  1. package/dist/lib/backends/agencyGenerator.js +20 -3
  2. package/dist/lib/backends/agencyGenerator.test.d.ts +1 -0
  3. package/dist/lib/backends/agencyGenerator.test.js +205 -0
  4. package/dist/lib/backends/baseGenerator.js +3 -1
  5. package/dist/lib/backends/graphGenerator.js +7 -5
  6. package/dist/lib/backends/typescriptGenerator.d.ts +3 -3
  7. package/dist/lib/backends/typescriptGenerator.js +14 -12
  8. package/dist/lib/parsers/access.d.ts +3 -5
  9. package/dist/lib/parsers/access.js +54 -13
  10. package/dist/lib/parsers/access.test.js +40 -500
  11. package/dist/lib/parsers/assignment.js +2 -2
  12. package/dist/lib/parsers/assignment.test.d.ts +1 -0
  13. package/dist/lib/parsers/assignment.test.js +279 -0
  14. package/dist/lib/parsers/dataStructures.js +3 -3
  15. package/dist/lib/parsers/function.d.ts +3 -1
  16. package/dist/lib/parsers/function.js +6 -4
  17. package/dist/lib/parsers/function.test.js +653 -8
  18. package/dist/lib/parsers/functionCall.js +3 -2
  19. package/dist/lib/parsers/functionCall.test.js +310 -0
  20. package/dist/lib/parsers/literals.js +11 -2
  21. package/dist/lib/parsers/literals.test.js +7 -7
  22. package/dist/lib/parsers/matchBlock.js +2 -2
  23. package/dist/lib/parsers/parserUtils.test.d.ts +1 -0
  24. package/dist/lib/parsers/parserUtils.test.js +46 -0
  25. package/dist/lib/parsers/returnStatement.js +2 -2
  26. package/dist/lib/parsers/returnStatement.test.d.ts +1 -0
  27. package/dist/lib/parsers/returnStatement.test.js +268 -0
  28. package/dist/lib/parsers/specialVar.test.d.ts +1 -0
  29. package/dist/lib/parsers/specialVar.test.js +219 -0
  30. package/dist/lib/types/access.d.ts +5 -5
  31. package/dist/lib/types/access.js +6 -1
  32. package/dist/lib/types/dataStructures.d.ts +3 -3
  33. package/dist/lib/types/function.d.ts +10 -4
  34. package/dist/lib/types/matchBlock.d.ts +2 -2
  35. package/dist/lib/types/returnStatement.d.ts +2 -2
  36. package/dist/lib/types/whileLoop.d.ts +2 -2
  37. package/dist/lib/types.d.ts +3 -3
  38. package/package.json +3 -3
@@ -1,10 +1,11 @@
1
1
  import { capture, char, many1WithJoin, or, sepBy, seqC, seqR, set, } from "tarsec";
2
- import { accessExpressionParser } from "./access.js";
2
+ import { accessExpressionParser, indexAccessParser } from "./access.js";
3
3
  import { literalParser } from "./literals.js";
4
4
  import { optionalSemicolon } from "./parserUtils.js";
5
5
  import { optionalSpaces, varNameChar } from "./utils.js";
6
+ import { agencyArrayParser, agencyObjectParser } from "./dataStructures.js";
6
7
  const comma = seqR(optionalSpaces, char(","), optionalSpaces);
7
8
  export const functionCallParser = (input) => {
8
- const parser = seqC(set("type", "functionCall"), capture(many1WithJoin(varNameChar), "functionName"), char("("), optionalSpaces, capture(sepBy(comma, or(functionCallParser, accessExpressionParser, literalParser)), "arguments"), optionalSpaces, char(")"), optionalSemicolon);
9
+ const parser = seqC(set("type", "functionCall"), capture(many1WithJoin(varNameChar), "functionName"), char("("), optionalSpaces, capture(sepBy(comma, or(agencyArrayParser, agencyObjectParser, indexAccessParser, functionCallParser, accessExpressionParser, literalParser)), "arguments"), optionalSpaces, char(")"), optionalSemicolon);
9
10
  return parser(input);
10
11
  };
@@ -98,6 +98,316 @@ describe("functionCallParser", () => {
98
98
  input: "",
99
99
  expected: { success: false },
100
100
  },
101
+ // Function calls with array arguments
102
+ {
103
+ input: "processArray([1, 2, 3])",
104
+ expected: {
105
+ success: true,
106
+ result: {
107
+ type: "functionCall",
108
+ functionName: "processArray",
109
+ arguments: [
110
+ {
111
+ type: "agencyArray",
112
+ items: [
113
+ { type: "number", value: "1" },
114
+ { type: "number", value: "2" },
115
+ { type: "number", value: "3" },
116
+ ],
117
+ },
118
+ ],
119
+ },
120
+ },
121
+ },
122
+ {
123
+ input: "processArray([1, 2, 3, 4, 5])",
124
+ expected: {
125
+ success: true,
126
+ result: {
127
+ type: "functionCall",
128
+ functionName: "processArray",
129
+ arguments: [
130
+ {
131
+ type: "agencyArray",
132
+ items: [
133
+ { type: "number", value: "1" },
134
+ { type: "number", value: "2" },
135
+ { type: "number", value: "3" },
136
+ { type: "number", value: "4" },
137
+ { type: "number", value: "5" },
138
+ ],
139
+ },
140
+ ],
141
+ },
142
+ },
143
+ },
144
+ {
145
+ input: "handleStrings([\"hello\", \"world\"])",
146
+ expected: {
147
+ success: true,
148
+ result: {
149
+ type: "functionCall",
150
+ functionName: "handleStrings",
151
+ arguments: [
152
+ {
153
+ type: "agencyArray",
154
+ items: [
155
+ { type: "string", value: "hello" },
156
+ { type: "string", value: "world" },
157
+ ],
158
+ },
159
+ ],
160
+ },
161
+ },
162
+ },
163
+ {
164
+ input: "processEmpty([])",
165
+ expected: {
166
+ success: true,
167
+ result: {
168
+ type: "functionCall",
169
+ functionName: "processEmpty",
170
+ arguments: [
171
+ {
172
+ type: "agencyArray",
173
+ items: [],
174
+ },
175
+ ],
176
+ },
177
+ },
178
+ },
179
+ {
180
+ input: "processNested([[1, 2], [3, 4]])",
181
+ expected: {
182
+ success: true,
183
+ result: {
184
+ type: "functionCall",
185
+ functionName: "processNested",
186
+ arguments: [
187
+ {
188
+ type: "agencyArray",
189
+ items: [
190
+ {
191
+ type: "agencyArray",
192
+ items: [
193
+ { type: "number", value: "1" },
194
+ { type: "number", value: "2" },
195
+ ],
196
+ },
197
+ {
198
+ type: "agencyArray",
199
+ items: [
200
+ { type: "number", value: "3" },
201
+ { type: "number", value: "4" },
202
+ ],
203
+ },
204
+ ],
205
+ },
206
+ ],
207
+ },
208
+ },
209
+ },
210
+ // Function calls with object arguments
211
+ {
212
+ input: "configure({key: \"value\"})",
213
+ expected: {
214
+ success: true,
215
+ result: {
216
+ type: "functionCall",
217
+ functionName: "configure",
218
+ arguments: [
219
+ {
220
+ type: "agencyObject",
221
+ entries: [
222
+ {
223
+ key: "key",
224
+ value: { type: "string", value: "value" },
225
+ },
226
+ ],
227
+ },
228
+ ],
229
+ },
230
+ },
231
+ },
232
+ {
233
+ input: "createUser({name: \"Alice\", age: 30})",
234
+ expected: {
235
+ success: true,
236
+ result: {
237
+ type: "functionCall",
238
+ functionName: "createUser",
239
+ arguments: [
240
+ {
241
+ type: "agencyObject",
242
+ entries: [
243
+ {
244
+ key: "name",
245
+ value: { type: "string", value: "Alice" },
246
+ },
247
+ {
248
+ key: "age",
249
+ value: { type: "number", value: "30" },
250
+ },
251
+ ],
252
+ },
253
+ ],
254
+ },
255
+ },
256
+ },
257
+ {
258
+ input: "initialize({})",
259
+ expected: {
260
+ success: true,
261
+ result: {
262
+ type: "functionCall",
263
+ functionName: "initialize",
264
+ arguments: [
265
+ {
266
+ type: "agencyObject",
267
+ entries: [],
268
+ },
269
+ ],
270
+ },
271
+ },
272
+ },
273
+ {
274
+ input: "processData({items: [1, 2, 3]})",
275
+ expected: {
276
+ success: true,
277
+ result: {
278
+ type: "functionCall",
279
+ functionName: "processData",
280
+ arguments: [
281
+ {
282
+ type: "agencyObject",
283
+ entries: [
284
+ {
285
+ key: "items",
286
+ value: {
287
+ type: "agencyArray",
288
+ items: [
289
+ { type: "number", value: "1" },
290
+ { type: "number", value: "2" },
291
+ { type: "number", value: "3" },
292
+ ],
293
+ },
294
+ },
295
+ ],
296
+ },
297
+ ],
298
+ },
299
+ },
300
+ },
301
+ {
302
+ input: "nestedConfig({outer: {inner: 42}})",
303
+ expected: {
304
+ success: true,
305
+ result: {
306
+ type: "functionCall",
307
+ functionName: "nestedConfig",
308
+ arguments: [
309
+ {
310
+ type: "agencyObject",
311
+ entries: [
312
+ {
313
+ key: "outer",
314
+ value: {
315
+ type: "agencyObject",
316
+ entries: [
317
+ {
318
+ key: "inner",
319
+ value: { type: "number", value: "42" },
320
+ },
321
+ ],
322
+ },
323
+ },
324
+ ],
325
+ },
326
+ ],
327
+ },
328
+ },
329
+ },
330
+ // Function calls with mixed arguments
331
+ {
332
+ input: "mixed(42, [1, 2], {key: \"value\"})",
333
+ expected: {
334
+ success: true,
335
+ result: {
336
+ type: "functionCall",
337
+ functionName: "mixed",
338
+ arguments: [
339
+ { type: "number", value: "42" },
340
+ {
341
+ type: "agencyArray",
342
+ items: [
343
+ { type: "number", value: "1" },
344
+ { type: "number", value: "2" },
345
+ ],
346
+ },
347
+ {
348
+ type: "agencyObject",
349
+ entries: [
350
+ {
351
+ key: "key",
352
+ value: { type: "string", value: "value" },
353
+ },
354
+ ],
355
+ },
356
+ ],
357
+ },
358
+ },
359
+ },
360
+ {
361
+ input: "complexCall(\"test\", [], {}, 100)",
362
+ expected: {
363
+ success: true,
364
+ result: {
365
+ type: "functionCall",
366
+ functionName: "complexCall",
367
+ arguments: [
368
+ { type: "string", value: "test" },
369
+ {
370
+ type: "agencyArray",
371
+ items: [],
372
+ },
373
+ {
374
+ type: "agencyObject",
375
+ entries: [],
376
+ },
377
+ { type: "number", value: "100" },
378
+ ],
379
+ },
380
+ },
381
+ },
382
+ {
383
+ input: "withVariables(x, [y, z], {key: value})",
384
+ expected: {
385
+ success: true,
386
+ result: {
387
+ type: "functionCall",
388
+ functionName: "withVariables",
389
+ arguments: [
390
+ { type: "variableName", value: "x" },
391
+ {
392
+ type: "agencyArray",
393
+ items: [
394
+ { type: "variableName", value: "y" },
395
+ { type: "variableName", value: "z" },
396
+ ],
397
+ },
398
+ {
399
+ type: "agencyObject",
400
+ entries: [
401
+ {
402
+ key: "key",
403
+ value: { type: "variableName", value: "value" },
404
+ },
405
+ ],
406
+ },
407
+ ],
408
+ },
409
+ },
410
+ },
101
411
  ];
102
412
  testCases.forEach(({ input, expected }) => {
103
413
  if (expected.success) {
@@ -1,5 +1,5 @@
1
1
  import { backtick, varNameChar } from "./utils.js";
2
- import { capture, char, digit, many, many1Till, many1WithJoin, manyTill, map, or, seqC, set, } from "tarsec";
2
+ import { capture, char, digit, letter, many, many1Till, many1WithJoin, manyTill, manyWithJoin, map, or, seq, seqC, set, } from "tarsec";
3
3
  export const textSegmentParser = map(many1Till(or(backtick, char("$"))), (text) => ({
4
4
  type: "text",
5
5
  value: text,
@@ -8,5 +8,14 @@ export const interpolationSegmentParser = seqC(set("type", "interpolation"), cha
8
8
  export const promptParser = seqC(set("type", "prompt"), backtick, capture(many(or(textSegmentParser, interpolationSegmentParser)), "segments"), backtick);
9
9
  export const numberParser = seqC(set("type", "number"), capture(many1WithJoin(or(char("-"), char("."), digit)), "value"));
10
10
  export const stringParser = seqC(set("type", "string"), char('"'), capture(manyTill(char('"')), "value"), char('"'));
11
- export const variableNameParser = seqC(set("type", "variableName"), capture(many1WithJoin(varNameChar), "value"));
11
+ export const variableNameParser = seq([
12
+ set("type", "variableName"),
13
+ capture(letter, "init"),
14
+ capture(manyWithJoin(varNameChar), "value"),
15
+ ], (_, captures) => {
16
+ return {
17
+ type: "variableName",
18
+ value: `${captures.init}${captures.value}`,
19
+ };
20
+ });
12
21
  export const literalParser = or(promptParser, numberParser, stringParser, variableNameParser);
@@ -497,13 +497,6 @@ describe("literals parsers", () => {
497
497
  result: { type: "variableName", value: "var2test" },
498
498
  },
499
499
  },
500
- {
501
- input: "123",
502
- expected: {
503
- success: true,
504
- result: { type: "variableName", value: "123" },
505
- },
506
- },
507
500
  // Mixed case
508
501
  {
509
502
  input: "camelCase",
@@ -528,6 +521,13 @@ describe("literals parsers", () => {
528
521
  },
529
522
  // Failure cases
530
523
  { input: "", expected: { success: false } },
524
+ // cannot start with number
525
+ {
526
+ input: "1a",
527
+ expected: {
528
+ success: false,
529
+ },
530
+ },
531
531
  ];
532
532
  testCases.forEach(({ input, expected }) => {
533
533
  if (expected.success) {
@@ -13,12 +13,12 @@ import { optionalSpaces } from "./utils.js";
13
13
  import { literalParser } from "./literals.js";
14
14
  import { assignmentParser } from "./assignment.js";
15
15
  import { functionCallParser } from "./functionCall.js";
16
- import { accessExpressionParser } from "./access.js";
16
+ import { accessExpressionParser, indexAccessParser } from "./access.js";
17
17
  import { optionalSemicolon } from "./parserUtils.js";
18
18
  import { agencyArrayParser, agencyObjectParser } from "./dataStructures.js";
19
19
  import { commentParser } from "./comment.js";
20
20
  import { returnStatementParser } from "./returnStatement.js";
21
21
  export const defaultCaseParser = char("_");
22
- export const matchBlockParserCase = seqC(set("type", "matchBlockCase"), optionalSpaces, capture(or(defaultCaseParser, accessExpressionParser, literalParser), "caseValue"), optionalSpaces, str("=>"), optionalSpaces, capture(or(returnStatementParser, agencyArrayParser, agencyObjectParser, accessExpressionParser, assignmentParser, functionCallParser, literalParser), "body"));
22
+ export const matchBlockParserCase = seqC(set("type", "matchBlockCase"), optionalSpaces, capture(or(defaultCaseParser, indexAccessParser, accessExpressionParser, literalParser), "caseValue"), optionalSpaces, str("=>"), optionalSpaces, capture(or(returnStatementParser, agencyArrayParser, agencyObjectParser, accessExpressionParser, assignmentParser, functionCallParser, literalParser), "body"));
23
23
  const semicolon = seqC(optionalSpaces, char(";"), optionalSpaces);
24
24
  export const matchBlockParser = seqC(set("type", "matchBlock"), str("match"), optionalSpaces, char("("), capture(literalParser, "expression"), char(")"), optionalSpaces, char("{"), optionalSpaces, capture(sepBy(or(semicolon, newline), or(commentParser, matchBlockParserCase)), "cases"), optionalSpaces, char("}"), optionalSemicolon);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { optionalSemicolon } from "./parserUtils.js";
3
+ describe("parserUtils", () => {
4
+ describe("optionalSemicolon", () => {
5
+ const testCases = [
6
+ // Happy path - semicolon present
7
+ {
8
+ input: ";",
9
+ expected: { success: true, result: ";" },
10
+ },
11
+ {
12
+ input: ";rest",
13
+ expected: { success: true, result: ";", rest: "rest" },
14
+ },
15
+ // Happy path - no semicolon (optional means success even without match)
16
+ {
17
+ input: "",
18
+ expected: { success: true, result: null },
19
+ },
20
+ {
21
+ input: "other",
22
+ expected: { success: true, result: null, rest: "other" },
23
+ },
24
+ {
25
+ input: " ;",
26
+ expected: { success: true, result: null, rest: " ;" },
27
+ },
28
+ {
29
+ input: ";;",
30
+ expected: { success: true, result: ";", rest: ";" },
31
+ },
32
+ ];
33
+ testCases.forEach(({ input, expected }) => {
34
+ it(`should parse "${input}" successfully`, () => {
35
+ const result = optionalSemicolon(input);
36
+ expect(result.success).toBe(true);
37
+ if (result.success) {
38
+ expect(result.result).toEqual(expected.result);
39
+ if (expected.rest !== undefined) {
40
+ expect(result.rest).toEqual(expected.rest);
41
+ }
42
+ }
43
+ });
44
+ });
45
+ });
46
+ });
@@ -1,8 +1,8 @@
1
1
  import { seqC, set, str, capture, or } from "tarsec";
2
- import { accessExpressionParser } from "./access.js";
2
+ import { accessExpressionParser, indexAccessParser } from "./access.js";
3
3
  import { functionCallParser } from "./functionCall.js";
4
4
  import { optionalSemicolon } from "./parserUtils.js";
5
5
  import { optionalSpaces } from "./utils.js";
6
6
  import { literalParser } from "./literals.js";
7
7
  import { agencyArrayParser, agencyObjectParser } from "./dataStructures.js";
8
- export const returnStatementParser = seqC(set("type", "returnStatement"), str("return"), optionalSpaces, capture(or(accessExpressionParser, functionCallParser, literalParser, agencyObjectParser, agencyArrayParser), "value"), optionalSemicolon);
8
+ export const returnStatementParser = seqC(set("type", "returnStatement"), str("return"), optionalSpaces, capture(or(indexAccessParser, accessExpressionParser, functionCallParser, literalParser, agencyObjectParser, agencyArrayParser), "value"), optionalSemicolon);
@@ -0,0 +1 @@
1
+ export {};