@vibe-lang/runtime 0.2.5

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 (250) hide show
  1. package/package.json +46 -0
  2. package/src/ast/index.ts +375 -0
  3. package/src/ast.ts +2 -0
  4. package/src/debug/advanced-features.ts +482 -0
  5. package/src/debug/bun-inspector.ts +424 -0
  6. package/src/debug/handoff-manager.ts +283 -0
  7. package/src/debug/index.ts +150 -0
  8. package/src/debug/runner.ts +365 -0
  9. package/src/debug/server.ts +565 -0
  10. package/src/debug/stack-merger.ts +267 -0
  11. package/src/debug/state.ts +581 -0
  12. package/src/debug/test/advanced-features.test.ts +300 -0
  13. package/src/debug/test/e2e.test.ts +218 -0
  14. package/src/debug/test/handoff-manager.test.ts +256 -0
  15. package/src/debug/test/runner.test.ts +256 -0
  16. package/src/debug/test/stack-merger.test.ts +163 -0
  17. package/src/debug/test/state.test.ts +400 -0
  18. package/src/debug/test/ts-debug-integration.test.ts +374 -0
  19. package/src/debug/test/ts-import-tracker.test.ts +125 -0
  20. package/src/debug/test/ts-source-map.test.ts +169 -0
  21. package/src/debug/ts-import-tracker.ts +151 -0
  22. package/src/debug/ts-source-map.ts +171 -0
  23. package/src/errors/index.ts +124 -0
  24. package/src/index.ts +358 -0
  25. package/src/lexer/index.ts +348 -0
  26. package/src/lexer.ts +2 -0
  27. package/src/parser/index.ts +792 -0
  28. package/src/parser/parse.ts +45 -0
  29. package/src/parser/test/async.test.ts +248 -0
  30. package/src/parser/test/destructuring.test.ts +167 -0
  31. package/src/parser/test/do-expression.test.ts +486 -0
  32. package/src/parser/test/errors/do-expression.test.ts +95 -0
  33. package/src/parser/test/errors/error-locations.test.ts +230 -0
  34. package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
  35. package/src/parser/test/errors/missing-tokens.test.ts +126 -0
  36. package/src/parser/test/errors/model-declaration.test.ts +185 -0
  37. package/src/parser/test/errors/nested-blocks.test.ts +226 -0
  38. package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
  39. package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
  40. package/src/parser/test/import-export.test.ts +143 -0
  41. package/src/parser/test/literals.test.ts +404 -0
  42. package/src/parser/test/model-declaration.test.ts +161 -0
  43. package/src/parser/test/nested-blocks.test.ts +402 -0
  44. package/src/parser/test/parser.test.ts +743 -0
  45. package/src/parser/test/private.test.ts +136 -0
  46. package/src/parser/test/template-literal.test.ts +127 -0
  47. package/src/parser/test/tool-declaration.test.ts +302 -0
  48. package/src/parser/test/ts-block.test.ts +252 -0
  49. package/src/parser/test/type-annotations.test.ts +254 -0
  50. package/src/parser/visitor/helpers.ts +330 -0
  51. package/src/parser/visitor.ts +794 -0
  52. package/src/parser.ts +2 -0
  53. package/src/runtime/ai/cache-chunking.test.ts +69 -0
  54. package/src/runtime/ai/cache-chunking.ts +73 -0
  55. package/src/runtime/ai/client.ts +109 -0
  56. package/src/runtime/ai/context.ts +168 -0
  57. package/src/runtime/ai/formatters.ts +316 -0
  58. package/src/runtime/ai/index.ts +38 -0
  59. package/src/runtime/ai/language-ref.ts +38 -0
  60. package/src/runtime/ai/providers/anthropic.ts +253 -0
  61. package/src/runtime/ai/providers/google.ts +201 -0
  62. package/src/runtime/ai/providers/openai.ts +156 -0
  63. package/src/runtime/ai/retry.ts +100 -0
  64. package/src/runtime/ai/return-tools.ts +301 -0
  65. package/src/runtime/ai/test/client.test.ts +83 -0
  66. package/src/runtime/ai/test/formatters.test.ts +485 -0
  67. package/src/runtime/ai/test/retry.test.ts +137 -0
  68. package/src/runtime/ai/test/return-tools.test.ts +450 -0
  69. package/src/runtime/ai/test/tool-loop.test.ts +319 -0
  70. package/src/runtime/ai/test/tool-schema.test.ts +241 -0
  71. package/src/runtime/ai/tool-loop.ts +203 -0
  72. package/src/runtime/ai/tool-schema.ts +151 -0
  73. package/src/runtime/ai/types.ts +113 -0
  74. package/src/runtime/ai-logger.ts +255 -0
  75. package/src/runtime/ai-provider.ts +347 -0
  76. package/src/runtime/async/dependencies.ts +276 -0
  77. package/src/runtime/async/executor.ts +293 -0
  78. package/src/runtime/async/index.ts +43 -0
  79. package/src/runtime/async/scheduling.ts +163 -0
  80. package/src/runtime/async/test/dependencies.test.ts +284 -0
  81. package/src/runtime/async/test/executor.test.ts +388 -0
  82. package/src/runtime/context.ts +357 -0
  83. package/src/runtime/exec/ai.ts +139 -0
  84. package/src/runtime/exec/expressions.ts +475 -0
  85. package/src/runtime/exec/frames.ts +26 -0
  86. package/src/runtime/exec/functions.ts +305 -0
  87. package/src/runtime/exec/interpolation.ts +312 -0
  88. package/src/runtime/exec/statements.ts +604 -0
  89. package/src/runtime/exec/tools.ts +129 -0
  90. package/src/runtime/exec/typescript.ts +215 -0
  91. package/src/runtime/exec/variables.ts +279 -0
  92. package/src/runtime/index.ts +975 -0
  93. package/src/runtime/modules.ts +452 -0
  94. package/src/runtime/serialize.ts +103 -0
  95. package/src/runtime/state.ts +489 -0
  96. package/src/runtime/stdlib/core.ts +45 -0
  97. package/src/runtime/stdlib/directory.test.ts +156 -0
  98. package/src/runtime/stdlib/edit.test.ts +154 -0
  99. package/src/runtime/stdlib/fastEdit.test.ts +201 -0
  100. package/src/runtime/stdlib/glob.test.ts +106 -0
  101. package/src/runtime/stdlib/grep.test.ts +144 -0
  102. package/src/runtime/stdlib/index.ts +16 -0
  103. package/src/runtime/stdlib/readFile.test.ts +123 -0
  104. package/src/runtime/stdlib/tools/index.ts +707 -0
  105. package/src/runtime/stdlib/writeFile.test.ts +157 -0
  106. package/src/runtime/step.ts +969 -0
  107. package/src/runtime/test/ai-context.test.ts +1086 -0
  108. package/src/runtime/test/ai-result-object.test.ts +419 -0
  109. package/src/runtime/test/ai-tool-flow.test.ts +859 -0
  110. package/src/runtime/test/async-execution-order.test.ts +618 -0
  111. package/src/runtime/test/async-execution.test.ts +344 -0
  112. package/src/runtime/test/async-nested.test.ts +660 -0
  113. package/src/runtime/test/async-parallel-timing.test.ts +546 -0
  114. package/src/runtime/test/basic1.test.ts +154 -0
  115. package/src/runtime/test/binary-operators.test.ts +431 -0
  116. package/src/runtime/test/break-statement.test.ts +257 -0
  117. package/src/runtime/test/context-modes.test.ts +650 -0
  118. package/src/runtime/test/context.test.ts +466 -0
  119. package/src/runtime/test/core-functions.test.ts +228 -0
  120. package/src/runtime/test/e2e.test.ts +88 -0
  121. package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
  122. package/src/runtime/test/error-locations/main-error.vibe +4 -0
  123. package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
  124. package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
  125. package/src/runtime/test/for-in.test.ts +312 -0
  126. package/src/runtime/test/helpers.ts +69 -0
  127. package/src/runtime/test/imports.test.ts +334 -0
  128. package/src/runtime/test/json-expressions.test.ts +232 -0
  129. package/src/runtime/test/literals.test.ts +372 -0
  130. package/src/runtime/test/logical-indexing.test.ts +478 -0
  131. package/src/runtime/test/member-methods.test.ts +324 -0
  132. package/src/runtime/test/model-config.test.ts +338 -0
  133. package/src/runtime/test/null-handling.test.ts +342 -0
  134. package/src/runtime/test/private-visibility.test.ts +332 -0
  135. package/src/runtime/test/runtime-state.test.ts +514 -0
  136. package/src/runtime/test/scoping.test.ts +370 -0
  137. package/src/runtime/test/string-interpolation.test.ts +354 -0
  138. package/src/runtime/test/template-literal.test.ts +181 -0
  139. package/src/runtime/test/tool-execution.test.ts +467 -0
  140. package/src/runtime/test/tool-schema-generation.test.ts +477 -0
  141. package/src/runtime/test/tostring.test.ts +210 -0
  142. package/src/runtime/test/ts-block.test.ts +594 -0
  143. package/src/runtime/test/ts-error-location.test.ts +231 -0
  144. package/src/runtime/test/types.test.ts +732 -0
  145. package/src/runtime/test/verbose-logger.test.ts +710 -0
  146. package/src/runtime/test/vibe-expression.test.ts +54 -0
  147. package/src/runtime/test/vibe-value-errors.test.ts +541 -0
  148. package/src/runtime/test/while.test.ts +232 -0
  149. package/src/runtime/tools/builtin.ts +30 -0
  150. package/src/runtime/tools/directory-tools.ts +70 -0
  151. package/src/runtime/tools/file-tools.ts +228 -0
  152. package/src/runtime/tools/index.ts +5 -0
  153. package/src/runtime/tools/registry.ts +48 -0
  154. package/src/runtime/tools/search-tools.ts +134 -0
  155. package/src/runtime/tools/security.ts +36 -0
  156. package/src/runtime/tools/system-tools.ts +312 -0
  157. package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
  158. package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
  159. package/src/runtime/tools/test/registry.test.ts +713 -0
  160. package/src/runtime/tools/test/security.test.ts +86 -0
  161. package/src/runtime/tools/test/system-tools.test.ts +679 -0
  162. package/src/runtime/tools/test/ts-schema.test.ts +357 -0
  163. package/src/runtime/tools/ts-schema.ts +341 -0
  164. package/src/runtime/tools/types.ts +89 -0
  165. package/src/runtime/tools/utility-tools.ts +198 -0
  166. package/src/runtime/ts-eval.ts +126 -0
  167. package/src/runtime/types.ts +797 -0
  168. package/src/runtime/validation.ts +160 -0
  169. package/src/runtime/verbose-logger.ts +459 -0
  170. package/src/runtime.ts +2 -0
  171. package/src/semantic/analyzer-context.ts +62 -0
  172. package/src/semantic/analyzer-validators.ts +575 -0
  173. package/src/semantic/analyzer-visitors.ts +534 -0
  174. package/src/semantic/analyzer.ts +83 -0
  175. package/src/semantic/index.ts +11 -0
  176. package/src/semantic/symbol-table.ts +58 -0
  177. package/src/semantic/test/async-validation.test.ts +301 -0
  178. package/src/semantic/test/compress-validation.test.ts +179 -0
  179. package/src/semantic/test/const-reassignment.test.ts +111 -0
  180. package/src/semantic/test/control-flow.test.ts +346 -0
  181. package/src/semantic/test/destructuring.test.ts +185 -0
  182. package/src/semantic/test/duplicate-declarations.test.ts +168 -0
  183. package/src/semantic/test/export-validation.test.ts +111 -0
  184. package/src/semantic/test/fixtures/math.ts +31 -0
  185. package/src/semantic/test/imports.test.ts +148 -0
  186. package/src/semantic/test/json-type.test.ts +68 -0
  187. package/src/semantic/test/literals.test.ts +127 -0
  188. package/src/semantic/test/model-validation.test.ts +179 -0
  189. package/src/semantic/test/prompt-validation.test.ts +343 -0
  190. package/src/semantic/test/scoping.test.ts +312 -0
  191. package/src/semantic/test/tool-validation.test.ts +306 -0
  192. package/src/semantic/test/ts-type-checking.test.ts +563 -0
  193. package/src/semantic/test/type-constraints.test.ts +111 -0
  194. package/src/semantic/test/type-inference.test.ts +87 -0
  195. package/src/semantic/test/type-validation.test.ts +552 -0
  196. package/src/semantic/test/undefined-variables.test.ts +163 -0
  197. package/src/semantic/ts-block-checker.ts +204 -0
  198. package/src/semantic/ts-signatures.ts +194 -0
  199. package/src/semantic/ts-types.ts +170 -0
  200. package/src/semantic/types.ts +58 -0
  201. package/tests/fixtures/conditional-logic.vibe +14 -0
  202. package/tests/fixtures/function-call.vibe +16 -0
  203. package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
  204. package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
  205. package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
  206. package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
  207. package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
  208. package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
  209. package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
  210. package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
  211. package/tests/fixtures/imports/nested-import/main.vibe +3 -0
  212. package/tests/fixtures/imports/nested-import/utils.ts +3 -0
  213. package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
  214. package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
  215. package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
  216. package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
  217. package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
  218. package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
  219. package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
  220. package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
  221. package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
  222. package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
  223. package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
  224. package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
  225. package/tests/fixtures/imports/ts-import/main.vibe +4 -0
  226. package/tests/fixtures/imports/ts-import/math.ts +9 -0
  227. package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
  228. package/tests/fixtures/imports/ts-variables/data.ts +10 -0
  229. package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
  230. package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
  231. package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
  232. package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
  233. package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
  234. package/tests/fixtures/multiple-ai-calls.vibe +10 -0
  235. package/tests/fixtures/simple-greeting.vibe +6 -0
  236. package/tests/fixtures/template-literals.vibe +11 -0
  237. package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
  238. package/tests/integration/basic-ai/basic-ai.vibe +12 -0
  239. package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
  240. package/tests/integration/bug-fix/buggy-code.ts +22 -0
  241. package/tests/integration/bug-fix/fix-bug.vibe +21 -0
  242. package/tests/integration/compress/compress.integration.test.ts +206 -0
  243. package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
  244. package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
  245. package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
  246. package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
  247. package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
  248. package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
  249. package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
  250. package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
@@ -0,0 +1,475 @@
1
+ // Expression execution: literals, identifiers, value building
2
+
3
+ import * as AST from '../../ast';
4
+ import type { RuntimeState } from '../types';
5
+ import { isVibeValue, resolveValue } from '../types';
6
+ import {
7
+ getImportedValue,
8
+ isImportedTsFunction,
9
+ isImportedVibeFunction,
10
+ } from '../modules';
11
+ import { isCoreFunction } from '../stdlib/core';
12
+ import { lookupVariable } from './variables';
13
+ import { execVibeExpression } from './ai';
14
+ import { execTsBlock } from './typescript';
15
+
16
+ /**
17
+ * Identifier - get variable VibeValue.
18
+ * Returns the VibeValue so member access can see .err and .toolCalls.
19
+ * Expressions use resolveValue() to auto-unwrap when needed.
20
+ *
21
+ * If the variable is pending async (has asyncOperationId and operation is still pending),
22
+ * triggers awaiting_async status to wait for the async result.
23
+ */
24
+ export function execIdentifier(state: RuntimeState, expr: AST.Identifier): RuntimeState {
25
+ // Walk the scope chain to find the variable
26
+ const found = lookupVariable(state, expr.name);
27
+ if (found) {
28
+ const variable = found.variable;
29
+
30
+ // Check if this variable is pending async
31
+ if (isVibeValue(variable) && variable.asyncOperationId) {
32
+ const opId = variable.asyncOperationId;
33
+ const operation = state.asyncOperations.get(opId);
34
+
35
+ // If operation is still pending or running, trigger await
36
+ if (operation && (operation.status === 'pending' || operation.status === 'running')) {
37
+ return {
38
+ ...state,
39
+ status: 'awaiting_async',
40
+ awaitingAsyncIds: [opId],
41
+ // Re-add current instruction to retry after await
42
+ instructionStack: [
43
+ { op: 'exec_expression', expr, location: expr.location },
44
+ ...state.instructionStack,
45
+ ],
46
+ };
47
+ }
48
+
49
+ // If operation completed, use the result
50
+ if (operation && operation.status === 'completed' && operation.result) {
51
+ return { ...state, lastResult: operation.result };
52
+ }
53
+
54
+ // If operation failed, return the error
55
+ if (operation && operation.status === 'failed' && operation.error) {
56
+ // Return a VibeValue with the error
57
+ const errorValue: typeof variable = {
58
+ ...variable,
59
+ value: null,
60
+ err: true,
61
+ errDetails: operation.error,
62
+ asyncOperationId: undefined, // Clear the async marker
63
+ };
64
+ return { ...state, lastResult: errorValue };
65
+ }
66
+ }
67
+
68
+ return { ...state, lastResult: variable }; // Return VibeValue, not just value
69
+ }
70
+
71
+ // Check if it's a local function
72
+ if (state.functions[expr.name]) {
73
+ return { ...state, lastResult: { __vibeFunction: true, name: expr.name } };
74
+ }
75
+
76
+ // Check if it's an imported TS function
77
+ if (isImportedTsFunction(state, expr.name)) {
78
+ return { ...state, lastResult: { __vibeImportedTsFunction: true, name: expr.name } };
79
+ }
80
+
81
+ // Check if it's an imported Vibe function
82
+ if (isImportedVibeFunction(state, expr.name)) {
83
+ return { ...state, lastResult: { __vibeImportedVibeFunction: true, name: expr.name } };
84
+ }
85
+
86
+ // Check if it's any other imported value
87
+ const importedValue = getImportedValue(state, expr.name);
88
+ if (importedValue !== undefined) {
89
+ return { ...state, lastResult: importedValue };
90
+ }
91
+
92
+ // Check if it's a core function (auto-imported, available everywhere)
93
+ if (isCoreFunction(expr.name)) {
94
+ return { ...state, lastResult: { __vibeCoreFunction: true, name: expr.name } };
95
+ }
96
+
97
+ throw new Error(`ReferenceError: '${expr.name}' is not defined`);
98
+ }
99
+
100
+ /**
101
+ * Assignment expression - push value and assign instruction.
102
+ */
103
+ export function execAssignmentExpression(state: RuntimeState, expr: AST.AssignmentExpression): RuntimeState {
104
+ return {
105
+ ...state,
106
+ instructionStack: [
107
+ { op: 'exec_expression', expr: expr.value, location: expr.value.location },
108
+ { op: 'assign_var', name: expr.target.name, location: expr.location },
109
+ ...state.instructionStack,
110
+ ],
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Object literal - push properties and build.
116
+ */
117
+ export function execObjectLiteral(state: RuntimeState, expr: AST.ObjectLiteral): RuntimeState {
118
+ if (expr.properties.length === 0) {
119
+ return { ...state, lastResult: {} };
120
+ }
121
+
122
+ // Evaluate properties in order, push to value stack, then build
123
+ const keys = expr.properties.map((p) => p.key);
124
+ const propInstructions = expr.properties.flatMap((p) => [
125
+ { op: 'exec_expression' as const, expr: p.value, location: p.value.location },
126
+ { op: 'push_value' as const, location: p.value.location },
127
+ ]);
128
+
129
+ return {
130
+ ...state,
131
+ instructionStack: [
132
+ ...propInstructions,
133
+ { op: 'build_object', keys, location: expr.location },
134
+ ...state.instructionStack,
135
+ ],
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Array literal - push elements and build.
141
+ */
142
+ export function execArrayLiteral(state: RuntimeState, expr: AST.ArrayLiteral): RuntimeState {
143
+ if (expr.elements.length === 0) {
144
+ return { ...state, lastResult: [] };
145
+ }
146
+
147
+ const elemInstructions = expr.elements.flatMap((e) => [
148
+ { op: 'exec_expression' as const, expr: e, location: e.location },
149
+ { op: 'push_value' as const, location: e.location },
150
+ ]);
151
+
152
+ return {
153
+ ...state,
154
+ instructionStack: [
155
+ ...elemInstructions,
156
+ { op: 'build_array', count: expr.elements.length, location: expr.location },
157
+ ...state.instructionStack,
158
+ ],
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Push lastResult to value stack.
164
+ */
165
+ export function execPushValue(state: RuntimeState): RuntimeState {
166
+ return {
167
+ ...state,
168
+ valueStack: [...state.valueStack, state.lastResult],
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Build object from value stack.
174
+ * Unwraps VibeValues to get raw values for object properties.
175
+ */
176
+ export function execBuildObject(state: RuntimeState, keys: string[]): RuntimeState {
177
+ const rawValues = state.valueStack.slice(-keys.length);
178
+ const obj: Record<string, unknown> = {};
179
+
180
+ for (let i = 0; i < keys.length; i++) {
181
+ // Unwrap VibeValue to get raw value for object property
182
+ obj[keys[i]] = resolveValue(rawValues[i]);
183
+ }
184
+
185
+ return {
186
+ ...state,
187
+ valueStack: state.valueStack.slice(0, -keys.length),
188
+ lastResult: obj,
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Build array from value stack.
194
+ * Unwraps VibeValues to get raw values for array elements.
195
+ */
196
+ export function execBuildArray(state: RuntimeState, count: number): RuntimeState {
197
+ const rawElements = state.valueStack.slice(-count);
198
+ // Unwrap VibeValues to get raw values for array elements
199
+ const elements = rawElements.map(el => resolveValue(el));
200
+
201
+ return {
202
+ ...state,
203
+ valueStack: state.valueStack.slice(0, -count),
204
+ lastResult: elements,
205
+ };
206
+ }
207
+
208
+ /**
209
+ * Collect args from value stack for function call.
210
+ */
211
+ export function execCollectArgs(state: RuntimeState, count: number): RuntimeState {
212
+ const args = state.valueStack.slice(-count);
213
+
214
+ return {
215
+ ...state,
216
+ valueStack: state.valueStack.slice(0, -count),
217
+ lastResult: args,
218
+ };
219
+ }
220
+
221
+ /**
222
+ * Binary expression - evaluate left, push, evaluate right, apply operator.
223
+ */
224
+ export function execBinaryExpression(state: RuntimeState, expr: AST.BinaryExpression): RuntimeState {
225
+ return {
226
+ ...state,
227
+ instructionStack: [
228
+ { op: 'exec_expression', expr: expr.left, location: expr.left.location },
229
+ { op: 'push_value', location: expr.left.location },
230
+ { op: 'exec_expression', expr: expr.right, location: expr.right.location },
231
+ { op: 'binary_op', operator: expr.operator, location: expr.location },
232
+ ...state.instructionStack,
233
+ ],
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Unary expression - evaluate operand, apply operator.
239
+ */
240
+ export function execUnaryExpression(state: RuntimeState, expr: AST.UnaryExpression): RuntimeState {
241
+ return {
242
+ ...state,
243
+ instructionStack: [
244
+ { op: 'exec_expression', expr: expr.operand, location: expr.operand.location },
245
+ { op: 'unary_op', operator: expr.operator, location: expr.location },
246
+ ...state.instructionStack,
247
+ ],
248
+ };
249
+ }
250
+
251
+ /**
252
+ * Index expression - evaluate object, push, evaluate index, access element.
253
+ */
254
+ export function execIndexExpression(state: RuntimeState, expr: AST.IndexExpression): RuntimeState {
255
+ return {
256
+ ...state,
257
+ instructionStack: [
258
+ { op: 'exec_expression', expr: expr.object, location: expr.object.location },
259
+ { op: 'push_value', location: expr.object.location },
260
+ { op: 'exec_expression', expr: expr.index, location: expr.index.location },
261
+ { op: 'index_access', location: expr.location },
262
+ ...state.instructionStack,
263
+ ],
264
+ };
265
+ }
266
+
267
+ /**
268
+ * Member expression - evaluate object and access property.
269
+ * For method calls, returns a bound method wrapper.
270
+ * For property access (including AIResultObject.toolCalls), returns the property value.
271
+ */
272
+ export function execMemberExpression(state: RuntimeState, expr: AST.MemberExpression): RuntimeState {
273
+ return {
274
+ ...state,
275
+ instructionStack: [
276
+ { op: 'exec_expression', expr: expr.object, location: expr.object.location },
277
+ { op: 'member_access', property: expr.property, location: expr.location },
278
+ ...state.instructionStack,
279
+ ],
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Slice expression - evaluate object, push, evaluate start/end if present, slice array.
285
+ */
286
+ export function execSliceExpression(state: RuntimeState, expr: AST.SliceExpression): RuntimeState {
287
+ const instructions: RuntimeState['instructionStack'] = [];
288
+
289
+ // Push the object first
290
+ instructions.push({ op: 'exec_expression', expr: expr.object, location: expr.object.location });
291
+ instructions.push({ op: 'push_value', location: expr.object.location });
292
+
293
+ // Push start if present
294
+ if (expr.start) {
295
+ instructions.push({ op: 'exec_expression', expr: expr.start, location: expr.start.location });
296
+ instructions.push({ op: 'push_value', location: expr.start.location });
297
+ }
298
+
299
+ // Push end if present
300
+ if (expr.end) {
301
+ instructions.push({ op: 'exec_expression', expr: expr.end, location: expr.end.location });
302
+ instructions.push({ op: 'push_value', location: expr.end.location });
303
+ }
304
+
305
+ // Slice operation
306
+ instructions.push({ op: 'slice_access', hasStart: !!expr.start, hasEnd: !!expr.end, location: expr.location });
307
+
308
+ return {
309
+ ...state,
310
+ instructionStack: [
311
+ ...instructions,
312
+ ...state.instructionStack,
313
+ ],
314
+ };
315
+ }
316
+
317
+ /**
318
+ * Range expression - evaluate start and end, build inclusive range array.
319
+ */
320
+ export function execRangeExpression(state: RuntimeState, expr: AST.RangeExpression): RuntimeState {
321
+ return {
322
+ ...state,
323
+ instructionStack: [
324
+ { op: 'exec_expression', expr: expr.start, location: expr.start.location },
325
+ { op: 'push_value', location: expr.start.location },
326
+ { op: 'exec_expression', expr: expr.end, location: expr.end.location },
327
+ { op: 'push_value', location: expr.end.location },
328
+ { op: 'build_range', location: expr.location },
329
+ ...state.instructionStack,
330
+ ],
331
+ };
332
+ }
333
+
334
+ /**
335
+ * Build inclusive range array from value stack [start, end].
336
+ */
337
+ export function execBuildRange(state: RuntimeState): RuntimeState {
338
+ const rawEnd = state.valueStack[state.valueStack.length - 1];
339
+ const rawStart = state.valueStack[state.valueStack.length - 2];
340
+ const newStack = state.valueStack.slice(0, -2);
341
+
342
+ // Error propagation: if start or end is a VibeValue with error, propagate it
343
+ if (isVibeValue(rawStart) && rawStart.err) {
344
+ return { ...state, valueStack: newStack, lastResult: rawStart };
345
+ }
346
+ if (isVibeValue(rawEnd) && rawEnd.err) {
347
+ return { ...state, valueStack: newStack, lastResult: rawEnd };
348
+ }
349
+
350
+ // Auto-unwrap VibeValue and AIResultObject
351
+ const start = resolveValue(rawStart);
352
+ const end = resolveValue(rawEnd);
353
+
354
+ if (typeof start !== 'number' || typeof end !== 'number') {
355
+ throw new Error(`Range bounds must be numbers, got ${typeof start} and ${typeof end}`);
356
+ }
357
+
358
+ if (!Number.isInteger(start) || !Number.isInteger(end)) {
359
+ throw new Error(`Range bounds must be integers, got ${start} and ${end}`);
360
+ }
361
+
362
+ const length = end - start + 1;
363
+ const range = length > 0 ? Array.from({ length }, (_, i) => start + i) : [];
364
+
365
+ return {
366
+ ...state,
367
+ valueStack: newStack,
368
+ lastResult: range,
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Call expression - push callee, args, and call instruction.
374
+ */
375
+ export function execCallExpression(state: RuntimeState, expr: AST.CallExpression): RuntimeState {
376
+ // Evaluate callee and all arguments, then call
377
+ const argInstructions = expr.arguments.flatMap((arg) => [
378
+ { op: 'exec_expression' as const, expr: arg, location: arg.location },
379
+ { op: 'push_value' as const, location: arg.location },
380
+ ]);
381
+
382
+ return {
383
+ ...state,
384
+ instructionStack: [
385
+ { op: 'exec_expression', expr: expr.callee, location: expr.callee.location },
386
+ { op: 'push_value', location: expr.callee.location }, // Save callee to value stack
387
+ ...argInstructions,
388
+ { op: 'call_function', funcName: '', argCount: expr.arguments.length, location: expr.location },
389
+ ...state.instructionStack,
390
+ ],
391
+ };
392
+ }
393
+
394
+ /**
395
+ * Expression dispatcher - routes to appropriate expression handler.
396
+ */
397
+ export function execExpression(state: RuntimeState, expr: AST.Expression): RuntimeState {
398
+ switch (expr.type) {
399
+ case 'StringLiteral':
400
+ // Use prompt interpolation if in prompt context (do/vibe, prompt-typed variable)
401
+ return {
402
+ ...state,
403
+ instructionStack: [
404
+ state.inPromptContext
405
+ ? { op: 'interpolate_prompt_string', template: expr.value, location: expr.location }
406
+ : { op: 'interpolate_string', template: expr.value, location: expr.location },
407
+ ...state.instructionStack,
408
+ ],
409
+ };
410
+
411
+ case 'TemplateLiteral':
412
+ // Template literals also use {var} pattern now (unified)
413
+ // Use prompt interpolation if in prompt context
414
+ return {
415
+ ...state,
416
+ instructionStack: [
417
+ state.inPromptContext
418
+ ? { op: 'interpolate_prompt_string', template: expr.value, location: expr.location }
419
+ : { op: 'interpolate_string', template: expr.value, location: expr.location },
420
+ ...state.instructionStack,
421
+ ],
422
+ };
423
+
424
+ case 'BooleanLiteral':
425
+ return { ...state, lastResult: expr.value };
426
+
427
+ case 'NumberLiteral':
428
+ return { ...state, lastResult: expr.value };
429
+
430
+ case 'NullLiteral':
431
+ return { ...state, lastResult: null };
432
+
433
+ case 'ObjectLiteral':
434
+ return execObjectLiteral(state, expr);
435
+
436
+ case 'ArrayLiteral':
437
+ return execArrayLiteral(state, expr);
438
+
439
+ case 'Identifier':
440
+ return execIdentifier(state, expr);
441
+
442
+ case 'AssignmentExpression':
443
+ return execAssignmentExpression(state, expr);
444
+
445
+ case 'CallExpression':
446
+ return execCallExpression(state, expr);
447
+
448
+ case 'VibeExpression':
449
+ return execVibeExpression(state, expr);
450
+
451
+ case 'TsBlock':
452
+ return execTsBlock(state, expr);
453
+
454
+ case 'RangeExpression':
455
+ return execRangeExpression(state, expr);
456
+
457
+ case 'BinaryExpression':
458
+ return execBinaryExpression(state, expr);
459
+
460
+ case 'UnaryExpression':
461
+ return execUnaryExpression(state, expr);
462
+
463
+ case 'IndexExpression':
464
+ return execIndexExpression(state, expr);
465
+
466
+ case 'SliceExpression':
467
+ return execSliceExpression(state, expr);
468
+
469
+ case 'MemberExpression':
470
+ return execMemberExpression(state, expr);
471
+
472
+ default:
473
+ throw new Error(`Unknown expression type: ${(expr as AST.Expression).type}`);
474
+ }
475
+ }
@@ -0,0 +1,26 @@
1
+ // Frame management: push and pop stack frames
2
+
3
+ import type { RuntimeState } from '../types';
4
+ import { createFrame } from '../state';
5
+
6
+ /**
7
+ * Push a new frame onto the call stack.
8
+ */
9
+ export function execPushFrame(state: RuntimeState, name: string): RuntimeState {
10
+ return {
11
+ ...state,
12
+ callStack: [...state.callStack, createFrame(name)],
13
+ };
14
+ }
15
+
16
+ /**
17
+ * Pop the current frame from the call stack.
18
+ * Functions always forget their internal context on return (like traditional callstack).
19
+ * If you want data visible outside a function, return it and assign to a variable.
20
+ */
21
+ export function execPopFrame(state: RuntimeState): RuntimeState {
22
+ return {
23
+ ...state,
24
+ callStack: state.callStack.slice(0, -1),
25
+ };
26
+ }