@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.
- package/package.json +46 -0
- package/src/ast/index.ts +375 -0
- package/src/ast.ts +2 -0
- package/src/debug/advanced-features.ts +482 -0
- package/src/debug/bun-inspector.ts +424 -0
- package/src/debug/handoff-manager.ts +283 -0
- package/src/debug/index.ts +150 -0
- package/src/debug/runner.ts +365 -0
- package/src/debug/server.ts +565 -0
- package/src/debug/stack-merger.ts +267 -0
- package/src/debug/state.ts +581 -0
- package/src/debug/test/advanced-features.test.ts +300 -0
- package/src/debug/test/e2e.test.ts +218 -0
- package/src/debug/test/handoff-manager.test.ts +256 -0
- package/src/debug/test/runner.test.ts +256 -0
- package/src/debug/test/stack-merger.test.ts +163 -0
- package/src/debug/test/state.test.ts +400 -0
- package/src/debug/test/ts-debug-integration.test.ts +374 -0
- package/src/debug/test/ts-import-tracker.test.ts +125 -0
- package/src/debug/test/ts-source-map.test.ts +169 -0
- package/src/debug/ts-import-tracker.ts +151 -0
- package/src/debug/ts-source-map.ts +171 -0
- package/src/errors/index.ts +124 -0
- package/src/index.ts +358 -0
- package/src/lexer/index.ts +348 -0
- package/src/lexer.ts +2 -0
- package/src/parser/index.ts +792 -0
- package/src/parser/parse.ts +45 -0
- package/src/parser/test/async.test.ts +248 -0
- package/src/parser/test/destructuring.test.ts +167 -0
- package/src/parser/test/do-expression.test.ts +486 -0
- package/src/parser/test/errors/do-expression.test.ts +95 -0
- package/src/parser/test/errors/error-locations.test.ts +230 -0
- package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
- package/src/parser/test/errors/missing-tokens.test.ts +126 -0
- package/src/parser/test/errors/model-declaration.test.ts +185 -0
- package/src/parser/test/errors/nested-blocks.test.ts +226 -0
- package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
- package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
- package/src/parser/test/import-export.test.ts +143 -0
- package/src/parser/test/literals.test.ts +404 -0
- package/src/parser/test/model-declaration.test.ts +161 -0
- package/src/parser/test/nested-blocks.test.ts +402 -0
- package/src/parser/test/parser.test.ts +743 -0
- package/src/parser/test/private.test.ts +136 -0
- package/src/parser/test/template-literal.test.ts +127 -0
- package/src/parser/test/tool-declaration.test.ts +302 -0
- package/src/parser/test/ts-block.test.ts +252 -0
- package/src/parser/test/type-annotations.test.ts +254 -0
- package/src/parser/visitor/helpers.ts +330 -0
- package/src/parser/visitor.ts +794 -0
- package/src/parser.ts +2 -0
- package/src/runtime/ai/cache-chunking.test.ts +69 -0
- package/src/runtime/ai/cache-chunking.ts +73 -0
- package/src/runtime/ai/client.ts +109 -0
- package/src/runtime/ai/context.ts +168 -0
- package/src/runtime/ai/formatters.ts +316 -0
- package/src/runtime/ai/index.ts +38 -0
- package/src/runtime/ai/language-ref.ts +38 -0
- package/src/runtime/ai/providers/anthropic.ts +253 -0
- package/src/runtime/ai/providers/google.ts +201 -0
- package/src/runtime/ai/providers/openai.ts +156 -0
- package/src/runtime/ai/retry.ts +100 -0
- package/src/runtime/ai/return-tools.ts +301 -0
- package/src/runtime/ai/test/client.test.ts +83 -0
- package/src/runtime/ai/test/formatters.test.ts +485 -0
- package/src/runtime/ai/test/retry.test.ts +137 -0
- package/src/runtime/ai/test/return-tools.test.ts +450 -0
- package/src/runtime/ai/test/tool-loop.test.ts +319 -0
- package/src/runtime/ai/test/tool-schema.test.ts +241 -0
- package/src/runtime/ai/tool-loop.ts +203 -0
- package/src/runtime/ai/tool-schema.ts +151 -0
- package/src/runtime/ai/types.ts +113 -0
- package/src/runtime/ai-logger.ts +255 -0
- package/src/runtime/ai-provider.ts +347 -0
- package/src/runtime/async/dependencies.ts +276 -0
- package/src/runtime/async/executor.ts +293 -0
- package/src/runtime/async/index.ts +43 -0
- package/src/runtime/async/scheduling.ts +163 -0
- package/src/runtime/async/test/dependencies.test.ts +284 -0
- package/src/runtime/async/test/executor.test.ts +388 -0
- package/src/runtime/context.ts +357 -0
- package/src/runtime/exec/ai.ts +139 -0
- package/src/runtime/exec/expressions.ts +475 -0
- package/src/runtime/exec/frames.ts +26 -0
- package/src/runtime/exec/functions.ts +305 -0
- package/src/runtime/exec/interpolation.ts +312 -0
- package/src/runtime/exec/statements.ts +604 -0
- package/src/runtime/exec/tools.ts +129 -0
- package/src/runtime/exec/typescript.ts +215 -0
- package/src/runtime/exec/variables.ts +279 -0
- package/src/runtime/index.ts +975 -0
- package/src/runtime/modules.ts +452 -0
- package/src/runtime/serialize.ts +103 -0
- package/src/runtime/state.ts +489 -0
- package/src/runtime/stdlib/core.ts +45 -0
- package/src/runtime/stdlib/directory.test.ts +156 -0
- package/src/runtime/stdlib/edit.test.ts +154 -0
- package/src/runtime/stdlib/fastEdit.test.ts +201 -0
- package/src/runtime/stdlib/glob.test.ts +106 -0
- package/src/runtime/stdlib/grep.test.ts +144 -0
- package/src/runtime/stdlib/index.ts +16 -0
- package/src/runtime/stdlib/readFile.test.ts +123 -0
- package/src/runtime/stdlib/tools/index.ts +707 -0
- package/src/runtime/stdlib/writeFile.test.ts +157 -0
- package/src/runtime/step.ts +969 -0
- package/src/runtime/test/ai-context.test.ts +1086 -0
- package/src/runtime/test/ai-result-object.test.ts +419 -0
- package/src/runtime/test/ai-tool-flow.test.ts +859 -0
- package/src/runtime/test/async-execution-order.test.ts +618 -0
- package/src/runtime/test/async-execution.test.ts +344 -0
- package/src/runtime/test/async-nested.test.ts +660 -0
- package/src/runtime/test/async-parallel-timing.test.ts +546 -0
- package/src/runtime/test/basic1.test.ts +154 -0
- package/src/runtime/test/binary-operators.test.ts +431 -0
- package/src/runtime/test/break-statement.test.ts +257 -0
- package/src/runtime/test/context-modes.test.ts +650 -0
- package/src/runtime/test/context.test.ts +466 -0
- package/src/runtime/test/core-functions.test.ts +228 -0
- package/src/runtime/test/e2e.test.ts +88 -0
- package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
- package/src/runtime/test/error-locations/main-error.vibe +4 -0
- package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
- package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
- package/src/runtime/test/for-in.test.ts +312 -0
- package/src/runtime/test/helpers.ts +69 -0
- package/src/runtime/test/imports.test.ts +334 -0
- package/src/runtime/test/json-expressions.test.ts +232 -0
- package/src/runtime/test/literals.test.ts +372 -0
- package/src/runtime/test/logical-indexing.test.ts +478 -0
- package/src/runtime/test/member-methods.test.ts +324 -0
- package/src/runtime/test/model-config.test.ts +338 -0
- package/src/runtime/test/null-handling.test.ts +342 -0
- package/src/runtime/test/private-visibility.test.ts +332 -0
- package/src/runtime/test/runtime-state.test.ts +514 -0
- package/src/runtime/test/scoping.test.ts +370 -0
- package/src/runtime/test/string-interpolation.test.ts +354 -0
- package/src/runtime/test/template-literal.test.ts +181 -0
- package/src/runtime/test/tool-execution.test.ts +467 -0
- package/src/runtime/test/tool-schema-generation.test.ts +477 -0
- package/src/runtime/test/tostring.test.ts +210 -0
- package/src/runtime/test/ts-block.test.ts +594 -0
- package/src/runtime/test/ts-error-location.test.ts +231 -0
- package/src/runtime/test/types.test.ts +732 -0
- package/src/runtime/test/verbose-logger.test.ts +710 -0
- package/src/runtime/test/vibe-expression.test.ts +54 -0
- package/src/runtime/test/vibe-value-errors.test.ts +541 -0
- package/src/runtime/test/while.test.ts +232 -0
- package/src/runtime/tools/builtin.ts +30 -0
- package/src/runtime/tools/directory-tools.ts +70 -0
- package/src/runtime/tools/file-tools.ts +228 -0
- package/src/runtime/tools/index.ts +5 -0
- package/src/runtime/tools/registry.ts +48 -0
- package/src/runtime/tools/search-tools.ts +134 -0
- package/src/runtime/tools/security.ts +36 -0
- package/src/runtime/tools/system-tools.ts +312 -0
- package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
- package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
- package/src/runtime/tools/test/registry.test.ts +713 -0
- package/src/runtime/tools/test/security.test.ts +86 -0
- package/src/runtime/tools/test/system-tools.test.ts +679 -0
- package/src/runtime/tools/test/ts-schema.test.ts +357 -0
- package/src/runtime/tools/ts-schema.ts +341 -0
- package/src/runtime/tools/types.ts +89 -0
- package/src/runtime/tools/utility-tools.ts +198 -0
- package/src/runtime/ts-eval.ts +126 -0
- package/src/runtime/types.ts +797 -0
- package/src/runtime/validation.ts +160 -0
- package/src/runtime/verbose-logger.ts +459 -0
- package/src/runtime.ts +2 -0
- package/src/semantic/analyzer-context.ts +62 -0
- package/src/semantic/analyzer-validators.ts +575 -0
- package/src/semantic/analyzer-visitors.ts +534 -0
- package/src/semantic/analyzer.ts +83 -0
- package/src/semantic/index.ts +11 -0
- package/src/semantic/symbol-table.ts +58 -0
- package/src/semantic/test/async-validation.test.ts +301 -0
- package/src/semantic/test/compress-validation.test.ts +179 -0
- package/src/semantic/test/const-reassignment.test.ts +111 -0
- package/src/semantic/test/control-flow.test.ts +346 -0
- package/src/semantic/test/destructuring.test.ts +185 -0
- package/src/semantic/test/duplicate-declarations.test.ts +168 -0
- package/src/semantic/test/export-validation.test.ts +111 -0
- package/src/semantic/test/fixtures/math.ts +31 -0
- package/src/semantic/test/imports.test.ts +148 -0
- package/src/semantic/test/json-type.test.ts +68 -0
- package/src/semantic/test/literals.test.ts +127 -0
- package/src/semantic/test/model-validation.test.ts +179 -0
- package/src/semantic/test/prompt-validation.test.ts +343 -0
- package/src/semantic/test/scoping.test.ts +312 -0
- package/src/semantic/test/tool-validation.test.ts +306 -0
- package/src/semantic/test/ts-type-checking.test.ts +563 -0
- package/src/semantic/test/type-constraints.test.ts +111 -0
- package/src/semantic/test/type-inference.test.ts +87 -0
- package/src/semantic/test/type-validation.test.ts +552 -0
- package/src/semantic/test/undefined-variables.test.ts +163 -0
- package/src/semantic/ts-block-checker.ts +204 -0
- package/src/semantic/ts-signatures.ts +194 -0
- package/src/semantic/ts-types.ts +170 -0
- package/src/semantic/types.ts +58 -0
- package/tests/fixtures/conditional-logic.vibe +14 -0
- package/tests/fixtures/function-call.vibe +16 -0
- package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
- package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
- package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
- package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
- package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
- package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
- package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
- package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
- package/tests/fixtures/imports/nested-import/main.vibe +3 -0
- package/tests/fixtures/imports/nested-import/utils.ts +3 -0
- package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
- package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
- package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
- package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
- package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
- package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
- package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
- package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
- package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
- package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
- package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
- package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
- package/tests/fixtures/imports/ts-import/main.vibe +4 -0
- package/tests/fixtures/imports/ts-import/math.ts +9 -0
- package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/data.ts +10 -0
- package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
- package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
- package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
- package/tests/fixtures/multiple-ai-calls.vibe +10 -0
- package/tests/fixtures/simple-greeting.vibe +6 -0
- package/tests/fixtures/template-literals.vibe +11 -0
- package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
- package/tests/integration/basic-ai/basic-ai.vibe +12 -0
- package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
- package/tests/integration/bug-fix/buggy-code.ts +22 -0
- package/tests/integration/bug-fix/fix-bug.vibe +21 -0
- package/tests/integration/compress/compress.integration.test.ts +206 -0
- package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
- package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
- package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
- package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
- package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
- package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
- package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
- 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
|
+
}
|