@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,370 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { parse } from '../../parser/parse';
|
|
3
|
+
import { createInitialState, runUntilPause } from '../index';
|
|
4
|
+
|
|
5
|
+
describe('Runtime Lexical Scoping', () => {
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Function access to global scope
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
test('function can read global variable', () => {
|
|
11
|
+
const ast = parse(`
|
|
12
|
+
let globalVar = "global_value"
|
|
13
|
+
function readGlobal() {
|
|
14
|
+
return globalVar
|
|
15
|
+
}
|
|
16
|
+
let result = readGlobal()
|
|
17
|
+
`);
|
|
18
|
+
let state = createInitialState(ast);
|
|
19
|
+
state = runUntilPause(state);
|
|
20
|
+
|
|
21
|
+
expect(state.status).toBe('completed');
|
|
22
|
+
expect(state.callStack[0].locals['result'].value).toBe('global_value');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('function can modify global variable', () => {
|
|
26
|
+
const ast = parse(`
|
|
27
|
+
let counter = "before"
|
|
28
|
+
function updateCounter() {
|
|
29
|
+
counter = "after"
|
|
30
|
+
return counter
|
|
31
|
+
}
|
|
32
|
+
updateCounter()
|
|
33
|
+
`);
|
|
34
|
+
let state = createInitialState(ast);
|
|
35
|
+
state = runUntilPause(state);
|
|
36
|
+
|
|
37
|
+
expect(state.status).toBe('completed');
|
|
38
|
+
expect(state.callStack[0].locals['counter'].value).toBe('after');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('function can access global constant', () => {
|
|
42
|
+
const ast = parse(`
|
|
43
|
+
const CONFIG = "config_value"
|
|
44
|
+
function useConfig() {
|
|
45
|
+
return CONFIG
|
|
46
|
+
}
|
|
47
|
+
let result = useConfig()
|
|
48
|
+
`);
|
|
49
|
+
let state = createInitialState(ast);
|
|
50
|
+
state = runUntilPause(state);
|
|
51
|
+
|
|
52
|
+
expect(state.status).toBe('completed');
|
|
53
|
+
expect(state.callStack[0].locals['result'].value).toBe('config_value');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('function can call other global function', () => {
|
|
57
|
+
const ast = parse(`
|
|
58
|
+
function helper() {
|
|
59
|
+
return "helped"
|
|
60
|
+
}
|
|
61
|
+
function main() {
|
|
62
|
+
return helper()
|
|
63
|
+
}
|
|
64
|
+
let result = main()
|
|
65
|
+
`);
|
|
66
|
+
let state = createInitialState(ast);
|
|
67
|
+
state = runUntilPause(state);
|
|
68
|
+
|
|
69
|
+
expect(state.status).toBe('completed');
|
|
70
|
+
expect(state.callStack[0].locals['result'].value).toBe('helped');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('recursion works', () => {
|
|
74
|
+
const ast = parse(`
|
|
75
|
+
let depth = "0"
|
|
76
|
+
function recurse(shouldRecurse: boolean): text {
|
|
77
|
+
if shouldRecurse {
|
|
78
|
+
depth = "reached"
|
|
79
|
+
return recurse(false)
|
|
80
|
+
}
|
|
81
|
+
return depth
|
|
82
|
+
}
|
|
83
|
+
let result = recurse(true)
|
|
84
|
+
`);
|
|
85
|
+
let state = createInitialState(ast);
|
|
86
|
+
state = runUntilPause(state);
|
|
87
|
+
|
|
88
|
+
expect(state.status).toBe('completed');
|
|
89
|
+
expect(state.callStack[0].locals['result'].value).toBe('reached');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// Shadowing
|
|
94
|
+
// ============================================================================
|
|
95
|
+
|
|
96
|
+
test('local variable shadows global', () => {
|
|
97
|
+
const ast = parse(`
|
|
98
|
+
let x = "global"
|
|
99
|
+
function shadow() {
|
|
100
|
+
let x = "local"
|
|
101
|
+
return x
|
|
102
|
+
}
|
|
103
|
+
let result = shadow()
|
|
104
|
+
`);
|
|
105
|
+
let state = createInitialState(ast);
|
|
106
|
+
state = runUntilPause(state);
|
|
107
|
+
|
|
108
|
+
expect(state.status).toBe('completed');
|
|
109
|
+
expect(state.callStack[0].locals['result'].value).toBe('local');
|
|
110
|
+
// Global x unchanged
|
|
111
|
+
expect(state.callStack[0].locals['x'].value).toBe('global');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('parameter shadows global', () => {
|
|
115
|
+
const ast = parse(`
|
|
116
|
+
let name = "global_name"
|
|
117
|
+
function greet(name: text): text {
|
|
118
|
+
return name
|
|
119
|
+
}
|
|
120
|
+
let result = greet("param_name")
|
|
121
|
+
`);
|
|
122
|
+
let state = createInitialState(ast);
|
|
123
|
+
state = runUntilPause(state);
|
|
124
|
+
|
|
125
|
+
expect(state.status).toBe('completed');
|
|
126
|
+
expect(state.callStack[0].locals['result'].value).toBe('param_name');
|
|
127
|
+
// Global name unchanged
|
|
128
|
+
expect(state.callStack[0].locals['name'].value).toBe('global_name');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// String interpolation with scope chain
|
|
133
|
+
// ============================================================================
|
|
134
|
+
|
|
135
|
+
test('string interpolation can access global variables from function', () => {
|
|
136
|
+
const ast = parse(`
|
|
137
|
+
let name = "World"
|
|
138
|
+
function greet() {
|
|
139
|
+
return "Hello, {name}!"
|
|
140
|
+
}
|
|
141
|
+
let result = greet()
|
|
142
|
+
`);
|
|
143
|
+
let state = createInitialState(ast);
|
|
144
|
+
state = runUntilPause(state);
|
|
145
|
+
|
|
146
|
+
expect(state.status).toBe('completed');
|
|
147
|
+
expect(state.callStack[0].locals['result'].value).toBe('Hello, World!');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('string interpolation prefers local over global (shadowing)', () => {
|
|
151
|
+
const ast = parse(`
|
|
152
|
+
let name = "Global"
|
|
153
|
+
function greet() {
|
|
154
|
+
let name = "Local"
|
|
155
|
+
return "Hello, {name}!"
|
|
156
|
+
}
|
|
157
|
+
let result = greet()
|
|
158
|
+
`);
|
|
159
|
+
let state = createInitialState(ast);
|
|
160
|
+
state = runUntilPause(state);
|
|
161
|
+
|
|
162
|
+
expect(state.status).toBe('completed');
|
|
163
|
+
expect(state.callStack[0].locals['result'].value).toBe('Hello, Local!');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Model access from functions
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
test('function can access global model', () => {
|
|
171
|
+
const ast = parse(`
|
|
172
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
173
|
+
function useModel() {
|
|
174
|
+
return myModel
|
|
175
|
+
}
|
|
176
|
+
let result = useModel()
|
|
177
|
+
`);
|
|
178
|
+
let state = createInitialState(ast);
|
|
179
|
+
state = runUntilPause(state);
|
|
180
|
+
|
|
181
|
+
expect(state.status).toBe('completed');
|
|
182
|
+
const result = state.callStack[0].locals['result'].value as any;
|
|
183
|
+
// Model is accessible from function - just verify it's a model object
|
|
184
|
+
expect(result.__vibeModel).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('cannot assign to global model from function', () => {
|
|
188
|
+
const ast = parse(`
|
|
189
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
190
|
+
function tryModify() {
|
|
191
|
+
myModel = "something else"
|
|
192
|
+
return myModel
|
|
193
|
+
}
|
|
194
|
+
tryModify()
|
|
195
|
+
`);
|
|
196
|
+
let state = createInitialState(ast);
|
|
197
|
+
state = runUntilPause(state);
|
|
198
|
+
|
|
199
|
+
expect(state.status).toBe('error');
|
|
200
|
+
expect(state.error).toContain("Cannot assign to constant 'myModel'");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('local variable can shadow global model', () => {
|
|
204
|
+
const ast = parse(`
|
|
205
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
206
|
+
function shadowModel() {
|
|
207
|
+
let myModel = "shadowed"
|
|
208
|
+
return myModel
|
|
209
|
+
}
|
|
210
|
+
let result = shadowModel()
|
|
211
|
+
`);
|
|
212
|
+
let state = createInitialState(ast);
|
|
213
|
+
state = runUntilPause(state);
|
|
214
|
+
|
|
215
|
+
expect(state.status).toBe('completed');
|
|
216
|
+
expect(state.callStack[0].locals['result'].value).toBe('shadowed');
|
|
217
|
+
// Global model unchanged
|
|
218
|
+
const globalModel = state.callStack[0].locals['myModel'].value as any;
|
|
219
|
+
expect(globalModel.__vibeModel).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Block scope within functions
|
|
224
|
+
// ============================================================================
|
|
225
|
+
|
|
226
|
+
test('block in function can access function locals', () => {
|
|
227
|
+
const ast = parse(`
|
|
228
|
+
function test() {
|
|
229
|
+
let funcVar = "func_value"
|
|
230
|
+
if true {
|
|
231
|
+
return funcVar
|
|
232
|
+
}
|
|
233
|
+
return "not reached"
|
|
234
|
+
}
|
|
235
|
+
let result = test()
|
|
236
|
+
`);
|
|
237
|
+
let state = createInitialState(ast);
|
|
238
|
+
state = runUntilPause(state);
|
|
239
|
+
|
|
240
|
+
expect(state.status).toBe('completed');
|
|
241
|
+
expect(state.callStack[0].locals['result'].value).toBe('func_value');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('block in function can access function parameters', () => {
|
|
245
|
+
const ast = parse(`
|
|
246
|
+
function test(param: text): text {
|
|
247
|
+
if true {
|
|
248
|
+
return param
|
|
249
|
+
}
|
|
250
|
+
return "not reached"
|
|
251
|
+
}
|
|
252
|
+
let result = test("param_value")
|
|
253
|
+
`);
|
|
254
|
+
let state = createInitialState(ast);
|
|
255
|
+
state = runUntilPause(state);
|
|
256
|
+
|
|
257
|
+
expect(state.status).toBe('completed');
|
|
258
|
+
expect(state.callStack[0].locals['result'].value).toBe('param_value');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('block in function can access global scope', () => {
|
|
262
|
+
const ast = parse(`
|
|
263
|
+
let globalVar = "global"
|
|
264
|
+
function test() {
|
|
265
|
+
if true {
|
|
266
|
+
return globalVar
|
|
267
|
+
}
|
|
268
|
+
return "not reached"
|
|
269
|
+
}
|
|
270
|
+
let result = test()
|
|
271
|
+
`);
|
|
272
|
+
let state = createInitialState(ast);
|
|
273
|
+
state = runUntilPause(state);
|
|
274
|
+
|
|
275
|
+
expect(state.status).toBe('completed');
|
|
276
|
+
expect(state.callStack[0].locals['result'].value).toBe('global');
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// ============================================================================
|
|
280
|
+
// Nested blocks
|
|
281
|
+
// ============================================================================
|
|
282
|
+
|
|
283
|
+
test('nested blocks can access all outer scopes', () => {
|
|
284
|
+
const ast = parse(`
|
|
285
|
+
let a = "level0"
|
|
286
|
+
if true {
|
|
287
|
+
let b = "level1"
|
|
288
|
+
if true {
|
|
289
|
+
let c = "level2"
|
|
290
|
+
if true {
|
|
291
|
+
a = b
|
|
292
|
+
b = c
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
`);
|
|
297
|
+
let state = createInitialState(ast);
|
|
298
|
+
state = runUntilPause(state);
|
|
299
|
+
|
|
300
|
+
expect(state.status).toBe('completed');
|
|
301
|
+
expect(state.callStack[0].locals['a'].value).toBe('level1');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// ============================================================================
|
|
305
|
+
// Const protection across scopes
|
|
306
|
+
// ============================================================================
|
|
307
|
+
|
|
308
|
+
test('cannot assign to global const from function', () => {
|
|
309
|
+
const ast = parse(`
|
|
310
|
+
const CONFIG = "original"
|
|
311
|
+
function tryModify() {
|
|
312
|
+
CONFIG = "modified"
|
|
313
|
+
return CONFIG
|
|
314
|
+
}
|
|
315
|
+
tryModify()
|
|
316
|
+
`);
|
|
317
|
+
let state = createInitialState(ast);
|
|
318
|
+
state = runUntilPause(state);
|
|
319
|
+
|
|
320
|
+
expect(state.status).toBe('error');
|
|
321
|
+
expect(state.error).toContain("Cannot assign to constant 'CONFIG'");
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// ============================================================================
|
|
325
|
+
// Complex scenarios
|
|
326
|
+
// ============================================================================
|
|
327
|
+
|
|
328
|
+
test('multiple functions sharing global state', () => {
|
|
329
|
+
const ast = parse(`
|
|
330
|
+
let state = "initial"
|
|
331
|
+
function setState(val: text): text {
|
|
332
|
+
state = val
|
|
333
|
+
return state
|
|
334
|
+
}
|
|
335
|
+
function getState() {
|
|
336
|
+
return state
|
|
337
|
+
}
|
|
338
|
+
setState("updated")
|
|
339
|
+
let result = getState()
|
|
340
|
+
`);
|
|
341
|
+
let state = createInitialState(ast);
|
|
342
|
+
state = runUntilPause(state);
|
|
343
|
+
|
|
344
|
+
expect(state.status).toBe('completed');
|
|
345
|
+
expect(state.callStack[0].locals['result'].value).toBe('updated');
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test('function chain using global variables', () => {
|
|
349
|
+
const ast = parse(`
|
|
350
|
+
let prefix = "Hello"
|
|
351
|
+
let suffix = "!"
|
|
352
|
+
function addPrefix(msg: text): text {
|
|
353
|
+
return "{prefix}, {msg}"
|
|
354
|
+
}
|
|
355
|
+
function addSuffix(msg: text): text {
|
|
356
|
+
return "{msg}{suffix}"
|
|
357
|
+
}
|
|
358
|
+
function greet(name: text): text {
|
|
359
|
+
let withPrefix = addPrefix(name)
|
|
360
|
+
return addSuffix(withPrefix)
|
|
361
|
+
}
|
|
362
|
+
let result = greet("World")
|
|
363
|
+
`);
|
|
364
|
+
let state = createInitialState(ast);
|
|
365
|
+
state = runUntilPause(state);
|
|
366
|
+
|
|
367
|
+
expect(state.status).toBe('completed');
|
|
368
|
+
expect(state.callStack[0].locals['result'].value).toBe('Hello, World!');
|
|
369
|
+
});
|
|
370
|
+
});
|