@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,343 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { parse } from '../../parser/parse';
|
|
3
|
+
import { SemanticAnalyzer } from '../analyzer';
|
|
4
|
+
|
|
5
|
+
describe('Semantic Analyzer - Prompt Parameter Validation', () => {
|
|
6
|
+
const analyzer = new SemanticAnalyzer();
|
|
7
|
+
|
|
8
|
+
function getErrors(code: string): string[] {
|
|
9
|
+
const ast = parse(code);
|
|
10
|
+
const errors = analyzer.analyze(ast, code);
|
|
11
|
+
return errors.map((e) => e.message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const modelDecl = 'model m = { name: "test", apiKey: "key", url: "http://test" }';
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Valid prompt parameters - String literals
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
describe('string literals as prompts', () => {
|
|
21
|
+
test('vibe with string literal prompt is valid', () => {
|
|
22
|
+
const errors = getErrors(`
|
|
23
|
+
${modelDecl}
|
|
24
|
+
let x: text = vibe "What is 2+2?" m default
|
|
25
|
+
`);
|
|
26
|
+
expect(errors).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('vibe with question prompt is valid', () => {
|
|
30
|
+
const errors = getErrors(`
|
|
31
|
+
${modelDecl}
|
|
32
|
+
let x: text = vibe "What is your name?" m default
|
|
33
|
+
`);
|
|
34
|
+
expect(errors).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('vibe with string literal prompt is valid', () => {
|
|
38
|
+
const errors = getErrors(`
|
|
39
|
+
${modelDecl}
|
|
40
|
+
let x: text = vibe "Generate a hello function" m default
|
|
41
|
+
`);
|
|
42
|
+
expect(errors).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Valid prompt parameters - Variables with prompt type
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
describe('prompt typed variables as prompts', () => {
|
|
51
|
+
test('vibe with prompt typed variable is valid', () => {
|
|
52
|
+
const errors = getErrors(`
|
|
53
|
+
${modelDecl}
|
|
54
|
+
let question: prompt = "What is 2+2?"
|
|
55
|
+
let x: text = vibe question m default
|
|
56
|
+
`);
|
|
57
|
+
expect(errors).toEqual([]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('vibe with const prompt variable is valid', () => {
|
|
61
|
+
const errors = getErrors(`
|
|
62
|
+
${modelDecl}
|
|
63
|
+
const userPrompt: prompt = "What is your name?"
|
|
64
|
+
let x: text = vibe userPrompt m default
|
|
65
|
+
`);
|
|
66
|
+
expect(errors).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('vibe with prompt typed variable is valid', () => {
|
|
70
|
+
const errors = getErrors(`
|
|
71
|
+
${modelDecl}
|
|
72
|
+
let instruction: prompt = "Generate a hello function"
|
|
73
|
+
let x: text = vibe instruction m default
|
|
74
|
+
`);
|
|
75
|
+
expect(errors).toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Valid prompt parameters - Variables with text type
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
describe('text typed variables as prompts', () => {
|
|
84
|
+
test('vibe with text typed variable is valid', () => {
|
|
85
|
+
const errors = getErrors(`
|
|
86
|
+
${modelDecl}
|
|
87
|
+
let question: text = "What is 2+2?"
|
|
88
|
+
let x: text = vibe question m default
|
|
89
|
+
`);
|
|
90
|
+
expect(errors).toEqual([]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('vibe with const text variable is valid', () => {
|
|
94
|
+
const errors = getErrors(`
|
|
95
|
+
${modelDecl}
|
|
96
|
+
const userInput: text = "What is your name?"
|
|
97
|
+
let x: text = vibe userInput m default
|
|
98
|
+
`);
|
|
99
|
+
expect(errors).toEqual([]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('vibe with text typed variable is valid', () => {
|
|
103
|
+
const errors = getErrors(`
|
|
104
|
+
${modelDecl}
|
|
105
|
+
let instruction: text = "Generate code"
|
|
106
|
+
let x: text = vibe instruction m default
|
|
107
|
+
`);
|
|
108
|
+
expect(errors).toEqual([]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Valid prompt parameters - Variables without type annotation (implicitly text)
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
describe('untyped variables as prompts', () => {
|
|
117
|
+
test('vibe with untyped variable is valid', () => {
|
|
118
|
+
const errors = getErrors(`
|
|
119
|
+
${modelDecl}
|
|
120
|
+
let question = "What is 2+2?"
|
|
121
|
+
let x: text = vibe question m default
|
|
122
|
+
`);
|
|
123
|
+
expect(errors).toEqual([]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('vibe with const untyped variable is valid', () => {
|
|
127
|
+
const errors = getErrors(`
|
|
128
|
+
${modelDecl}
|
|
129
|
+
const userInput = "What is your name?"
|
|
130
|
+
let x: text = vibe userInput m default
|
|
131
|
+
`);
|
|
132
|
+
expect(errors).toEqual([]);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('vibe with untyped variable is valid', () => {
|
|
136
|
+
const errors = getErrors(`
|
|
137
|
+
${modelDecl}
|
|
138
|
+
let instruction = "Generate code"
|
|
139
|
+
let x: text = vibe instruction m default
|
|
140
|
+
`);
|
|
141
|
+
expect(errors).toEqual([]);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// ============================================================================
|
|
146
|
+
// Invalid prompt parameters - JSON typed variables
|
|
147
|
+
// ============================================================================
|
|
148
|
+
|
|
149
|
+
describe('json typed variables as prompts (invalid)', () => {
|
|
150
|
+
test('vibe with json typed variable errors', () => {
|
|
151
|
+
const errors = getErrors(`
|
|
152
|
+
${modelDecl}
|
|
153
|
+
let data: json = "{\\"key\\": \\"value\\"}"
|
|
154
|
+
let x: text = vibe data m default
|
|
155
|
+
`);
|
|
156
|
+
expect(errors).toContain("Cannot use json typed variable 'data' as prompt");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('vibe with const json variable errors', () => {
|
|
160
|
+
const errors = getErrors(`
|
|
161
|
+
${modelDecl}
|
|
162
|
+
const config: json = "[]"
|
|
163
|
+
let x: text = vibe config m default
|
|
164
|
+
`);
|
|
165
|
+
expect(errors).toContain("Cannot use json typed variable 'config' as prompt");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('vibe with json typed variable errors', () => {
|
|
169
|
+
const errors = getErrors(`
|
|
170
|
+
${modelDecl}
|
|
171
|
+
let schema: json = "{}"
|
|
172
|
+
let x: text = vibe schema m default
|
|
173
|
+
`);
|
|
174
|
+
expect(errors).toContain("Cannot use json typed variable 'schema' as prompt");
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Invalid prompt parameters - Model references
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
describe('model references as prompts (invalid)', () => {
|
|
183
|
+
test('vibe with model as prompt errors', () => {
|
|
184
|
+
const errors = getErrors(`
|
|
185
|
+
${modelDecl}
|
|
186
|
+
let x: text = vibe m m default
|
|
187
|
+
`);
|
|
188
|
+
expect(errors).toContain("Cannot use model 'm' as prompt");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('vibe with model as both prompt and model errors', () => {
|
|
192
|
+
const errors = getErrors(`
|
|
193
|
+
${modelDecl}
|
|
194
|
+
let x: text = vibe m m default
|
|
195
|
+
`);
|
|
196
|
+
expect(errors).toContain("Cannot use model 'm' as prompt");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Invalid prompt parameters - Function references
|
|
202
|
+
// ============================================================================
|
|
203
|
+
|
|
204
|
+
describe('function references as prompts (invalid)', () => {
|
|
205
|
+
test('vibe with function as prompt errors', () => {
|
|
206
|
+
const errors = getErrors(`
|
|
207
|
+
${modelDecl}
|
|
208
|
+
function myFunc() {
|
|
209
|
+
return "hello"
|
|
210
|
+
}
|
|
211
|
+
let x: text = vibe myFunc m default
|
|
212
|
+
`);
|
|
213
|
+
expect(errors).toContain("Cannot use function 'myFunc' as prompt");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('vibe with another function as prompt errors', () => {
|
|
217
|
+
const errors = getErrors(`
|
|
218
|
+
${modelDecl}
|
|
219
|
+
function getQuestion() {
|
|
220
|
+
return "question"
|
|
221
|
+
}
|
|
222
|
+
let x: text = vibe getQuestion m default
|
|
223
|
+
`);
|
|
224
|
+
expect(errors).toContain("Cannot use function 'getQuestion' as prompt");
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('vibe with function as prompt errors', () => {
|
|
228
|
+
const errors = getErrors(`
|
|
229
|
+
${modelDecl}
|
|
230
|
+
function generate() {
|
|
231
|
+
return "code"
|
|
232
|
+
}
|
|
233
|
+
let x: text = vibe generate m default
|
|
234
|
+
`);
|
|
235
|
+
expect(errors).toContain("Cannot use function 'generate' as prompt");
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// Undefined variables as prompts
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
describe('undefined variables as prompts', () => {
|
|
244
|
+
test('vibe with undefined variable errors', () => {
|
|
245
|
+
const errors = getErrors(`
|
|
246
|
+
${modelDecl}
|
|
247
|
+
let x: text = vibe undefinedVar m default
|
|
248
|
+
`);
|
|
249
|
+
expect(errors).toContain("'undefinedVar' is not defined");
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('vibe with missing variable errors', () => {
|
|
253
|
+
const errors = getErrors(`
|
|
254
|
+
${modelDecl}
|
|
255
|
+
let x: text = vibe missingQuestion m default
|
|
256
|
+
`);
|
|
257
|
+
expect(errors).toContain("'missingQuestion' is not defined");
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('vibe with undefined variable errors', () => {
|
|
261
|
+
const errors = getErrors(`
|
|
262
|
+
${modelDecl}
|
|
263
|
+
let x: text = vibe notDefined m default
|
|
264
|
+
`);
|
|
265
|
+
expect(errors).toContain("'notDefined' is not defined");
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// ============================================================================
|
|
270
|
+
// Function parameters as prompts
|
|
271
|
+
// ============================================================================
|
|
272
|
+
|
|
273
|
+
describe('function parameters as prompts', () => {
|
|
274
|
+
test('vibe with function parameter is valid', () => {
|
|
275
|
+
const errors = getErrors(`
|
|
276
|
+
${modelDecl}
|
|
277
|
+
function askAI(question: text): text {
|
|
278
|
+
return vibe question m default
|
|
279
|
+
}
|
|
280
|
+
`);
|
|
281
|
+
expect(errors).toEqual([]);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test('vibe with message parameter is valid', () => {
|
|
285
|
+
const errors = getErrors(`
|
|
286
|
+
${modelDecl}
|
|
287
|
+
function getUserInput(message: text): text {
|
|
288
|
+
return vibe message m default
|
|
289
|
+
}
|
|
290
|
+
`);
|
|
291
|
+
expect(errors).toEqual([]);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test('vibe with function parameter is valid', () => {
|
|
295
|
+
const errors = getErrors(`
|
|
296
|
+
${modelDecl}
|
|
297
|
+
function generateCode(instruction: text): text {
|
|
298
|
+
return vibe instruction m default
|
|
299
|
+
}
|
|
300
|
+
`);
|
|
301
|
+
expect(errors).toEqual([]);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// ============================================================================
|
|
306
|
+
// Call expressions as prompts (valid - returns text at runtime)
|
|
307
|
+
// ============================================================================
|
|
308
|
+
|
|
309
|
+
describe('call expressions as prompts', () => {
|
|
310
|
+
test('vibe with function call as prompt is valid', () => {
|
|
311
|
+
const errors = getErrors(`
|
|
312
|
+
${modelDecl}
|
|
313
|
+
function getQuestion(): text {
|
|
314
|
+
return "What is 2+2?"
|
|
315
|
+
}
|
|
316
|
+
let x: text = vibe getQuestion() m default
|
|
317
|
+
`);
|
|
318
|
+
expect(errors).toEqual([]);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test('vibe with buildPrompt function call is valid', () => {
|
|
322
|
+
const errors = getErrors(`
|
|
323
|
+
${modelDecl}
|
|
324
|
+
function buildPrompt(): text {
|
|
325
|
+
return "Enter name:"
|
|
326
|
+
}
|
|
327
|
+
let x: text = vibe buildPrompt() m default
|
|
328
|
+
`);
|
|
329
|
+
expect(errors).toEqual([]);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test('vibe with function call as prompt is valid', () => {
|
|
333
|
+
const errors = getErrors(`
|
|
334
|
+
${modelDecl}
|
|
335
|
+
function getInstruction(): text {
|
|
336
|
+
return "Generate code"
|
|
337
|
+
}
|
|
338
|
+
let x: text = vibe getInstruction() m default
|
|
339
|
+
`);
|
|
340
|
+
expect(errors).toEqual([]);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
});
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { parse } from '../../parser/parse';
|
|
3
|
+
import { analyze } from '../index';
|
|
4
|
+
|
|
5
|
+
describe('Semantic Analysis - Scoping', () => {
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Block scope isolation
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
test('variable in block not accessible outside', () => {
|
|
11
|
+
const ast = parse(`
|
|
12
|
+
if true {
|
|
13
|
+
let x = "inside"
|
|
14
|
+
}
|
|
15
|
+
let y = x
|
|
16
|
+
`);
|
|
17
|
+
const errors = analyze(ast);
|
|
18
|
+
expect(errors.length).toBe(1);
|
|
19
|
+
expect(errors[0].message).toBe("'x' is not defined");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('variable in else block not accessible outside', () => {
|
|
23
|
+
const ast = parse(`
|
|
24
|
+
if false {
|
|
25
|
+
let a = "if"
|
|
26
|
+
} else {
|
|
27
|
+
let b = "else"
|
|
28
|
+
}
|
|
29
|
+
let x = b
|
|
30
|
+
`);
|
|
31
|
+
const errors = analyze(ast);
|
|
32
|
+
expect(errors.length).toBe(1);
|
|
33
|
+
expect(errors[0].message).toBe("'b' is not defined");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('variable in nested block not accessible outside', () => {
|
|
37
|
+
const ast = parse(`
|
|
38
|
+
if true {
|
|
39
|
+
if true {
|
|
40
|
+
let deep = "nested"
|
|
41
|
+
}
|
|
42
|
+
let x = deep
|
|
43
|
+
}
|
|
44
|
+
`);
|
|
45
|
+
const errors = analyze(ast);
|
|
46
|
+
expect(errors.length).toBe(1);
|
|
47
|
+
expect(errors[0].message).toBe("'deep' is not defined");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Function scope isolation
|
|
52
|
+
// ============================================================================
|
|
53
|
+
|
|
54
|
+
test('variable in function not accessible outside', () => {
|
|
55
|
+
const ast = parse(`
|
|
56
|
+
function test() {
|
|
57
|
+
let x = "inside"
|
|
58
|
+
return x
|
|
59
|
+
}
|
|
60
|
+
let y = x
|
|
61
|
+
`);
|
|
62
|
+
const errors = analyze(ast);
|
|
63
|
+
expect(errors.length).toBe(1);
|
|
64
|
+
expect(errors[0].message).toBe("'x' is not defined");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('parameter not accessible outside function', () => {
|
|
68
|
+
const ast = parse(`
|
|
69
|
+
function greet(name: text): text {
|
|
70
|
+
return name
|
|
71
|
+
}
|
|
72
|
+
let x = name
|
|
73
|
+
`);
|
|
74
|
+
const errors = analyze(ast);
|
|
75
|
+
expect(errors.length).toBe(1);
|
|
76
|
+
expect(errors[0].message).toBe("'name' is not defined");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Outer scope access
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
test('block can access outer scope', () => {
|
|
84
|
+
const ast = parse(`
|
|
85
|
+
let x = "outer"
|
|
86
|
+
if true {
|
|
87
|
+
let y = x
|
|
88
|
+
}
|
|
89
|
+
`);
|
|
90
|
+
const errors = analyze(ast);
|
|
91
|
+
expect(errors.length).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('function can access outer scope', () => {
|
|
95
|
+
const ast = parse(`
|
|
96
|
+
let x = "outer"
|
|
97
|
+
function test() {
|
|
98
|
+
return x
|
|
99
|
+
}
|
|
100
|
+
`);
|
|
101
|
+
const errors = analyze(ast);
|
|
102
|
+
expect(errors.length).toBe(0);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('nested block can access all outer scopes', () => {
|
|
106
|
+
const ast = parse(`
|
|
107
|
+
let a = "level1"
|
|
108
|
+
if true {
|
|
109
|
+
let b = "level2"
|
|
110
|
+
if true {
|
|
111
|
+
let c = a
|
|
112
|
+
let d = b
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`);
|
|
116
|
+
const errors = analyze(ast);
|
|
117
|
+
expect(errors.length).toBe(0);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Function parameter access
|
|
122
|
+
// ============================================================================
|
|
123
|
+
|
|
124
|
+
test('function body can access parameters', () => {
|
|
125
|
+
const ast = parse(`
|
|
126
|
+
function add(a: text): text {
|
|
127
|
+
return a
|
|
128
|
+
}
|
|
129
|
+
`);
|
|
130
|
+
const errors = analyze(ast);
|
|
131
|
+
expect(errors.length).toBe(0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('multiple parameters accessible', () => {
|
|
135
|
+
const ast = parse(`
|
|
136
|
+
function greet(first: text, last: text): text {
|
|
137
|
+
let full = first
|
|
138
|
+
return last
|
|
139
|
+
}
|
|
140
|
+
`);
|
|
141
|
+
const errors = analyze(ast);
|
|
142
|
+
expect(errors.length).toBe(0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('nested block in function can access parameters', () => {
|
|
146
|
+
const ast = parse(`
|
|
147
|
+
function test(x: text, flag: boolean): text {
|
|
148
|
+
if flag {
|
|
149
|
+
return x
|
|
150
|
+
}
|
|
151
|
+
return x
|
|
152
|
+
}
|
|
153
|
+
`);
|
|
154
|
+
const errors = analyze(ast);
|
|
155
|
+
expect(errors.length).toBe(0);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// ============================================================================
|
|
159
|
+
// Model scope
|
|
160
|
+
// ============================================================================
|
|
161
|
+
|
|
162
|
+
test('model accessible in same scope', () => {
|
|
163
|
+
const ast = parse(`
|
|
164
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
165
|
+
let x: text = vibe "prompt" myModel default
|
|
166
|
+
`);
|
|
167
|
+
const errors = analyze(ast);
|
|
168
|
+
expect(errors.length).toBe(0);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('model accessible in nested function', () => {
|
|
172
|
+
const ast = parse(`
|
|
173
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
174
|
+
function test() {
|
|
175
|
+
let x: text = vibe "prompt" myModel default
|
|
176
|
+
return x
|
|
177
|
+
}
|
|
178
|
+
`);
|
|
179
|
+
const errors = analyze(ast);
|
|
180
|
+
expect(errors.length).toBe(0);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('model accessible in nested block', () => {
|
|
184
|
+
const ast = parse(`
|
|
185
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
186
|
+
if true {
|
|
187
|
+
let x: text = vibe "prompt" myModel default
|
|
188
|
+
}
|
|
189
|
+
`);
|
|
190
|
+
const errors = analyze(ast);
|
|
191
|
+
expect(errors.length).toBe(0);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// ============================================================================
|
|
195
|
+
// Complex scoping scenarios
|
|
196
|
+
// ============================================================================
|
|
197
|
+
|
|
198
|
+
test('same name in parallel blocks', () => {
|
|
199
|
+
const ast = parse(`
|
|
200
|
+
if true {
|
|
201
|
+
let x = "first"
|
|
202
|
+
}
|
|
203
|
+
if true {
|
|
204
|
+
let x = "second"
|
|
205
|
+
}
|
|
206
|
+
`);
|
|
207
|
+
const errors = analyze(ast);
|
|
208
|
+
expect(errors.length).toBe(0);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('shadowing and access in same function', () => {
|
|
212
|
+
const ast = parse(`
|
|
213
|
+
let x = "outer"
|
|
214
|
+
function test() {
|
|
215
|
+
let y = x
|
|
216
|
+
let x = "inner"
|
|
217
|
+
return x
|
|
218
|
+
}
|
|
219
|
+
`);
|
|
220
|
+
const errors = analyze(ast);
|
|
221
|
+
expect(errors.length).toBe(0);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('multiple functions with same local variable names', () => {
|
|
225
|
+
const ast = parse(`
|
|
226
|
+
function first() {
|
|
227
|
+
let x = "a"
|
|
228
|
+
return x
|
|
229
|
+
}
|
|
230
|
+
function second() {
|
|
231
|
+
let x = "b"
|
|
232
|
+
return x
|
|
233
|
+
}
|
|
234
|
+
`);
|
|
235
|
+
const errors = analyze(ast);
|
|
236
|
+
expect(errors.length).toBe(0);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// Nested function restrictions
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
test('function inside if block is not allowed', () => {
|
|
244
|
+
const ast = parse(`
|
|
245
|
+
let name = "outer"
|
|
246
|
+
if true {
|
|
247
|
+
function greet(name: text): text {
|
|
248
|
+
return name
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
`);
|
|
252
|
+
const errors = analyze(ast);
|
|
253
|
+
expect(errors.length).toBe(1);
|
|
254
|
+
expect(errors[0].message).toContain('Functions can only be declared at global scope');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('function inside function is not allowed', () => {
|
|
258
|
+
const ast = parse(`
|
|
259
|
+
function outer() {
|
|
260
|
+
function inner() {
|
|
261
|
+
return "nested"
|
|
262
|
+
}
|
|
263
|
+
return inner()
|
|
264
|
+
}
|
|
265
|
+
`);
|
|
266
|
+
const errors = analyze(ast);
|
|
267
|
+
expect(errors.length).toBe(1);
|
|
268
|
+
expect(errors[0].message).toContain('Functions can only be declared at global scope');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('function inside else block is not allowed', () => {
|
|
272
|
+
const ast = parse(`
|
|
273
|
+
if false {
|
|
274
|
+
let x = "if"
|
|
275
|
+
} else {
|
|
276
|
+
function helper() {
|
|
277
|
+
return "help"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
`);
|
|
281
|
+
const errors = analyze(ast);
|
|
282
|
+
expect(errors.length).toBe(1);
|
|
283
|
+
expect(errors[0].message).toContain('Functions can only be declared at global scope');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test('deeply nested function is not allowed', () => {
|
|
287
|
+
const ast = parse(`
|
|
288
|
+
function outer() {
|
|
289
|
+
if true {
|
|
290
|
+
function deeplyNested() {
|
|
291
|
+
return "deep"
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return "outer"
|
|
295
|
+
}
|
|
296
|
+
`);
|
|
297
|
+
const errors = analyze(ast);
|
|
298
|
+
expect(errors.length).toBe(1);
|
|
299
|
+
expect(errors[0].message).toContain('Functions can only be declared at global scope');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test('function at global scope is allowed', () => {
|
|
303
|
+
const ast = parse(`
|
|
304
|
+
function topLevel(): text {
|
|
305
|
+
return "allowed"
|
|
306
|
+
}
|
|
307
|
+
let result = topLevel()
|
|
308
|
+
`);
|
|
309
|
+
const errors = analyze(ast);
|
|
310
|
+
expect(errors.length).toBe(0);
|
|
311
|
+
});
|
|
312
|
+
});
|