@vibe-lang/runtime 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/package.json +46 -0
  2. package/src/ast/index.ts +375 -0
  3. package/src/ast.ts +2 -0
  4. package/src/debug/advanced-features.ts +482 -0
  5. package/src/debug/bun-inspector.ts +424 -0
  6. package/src/debug/handoff-manager.ts +283 -0
  7. package/src/debug/index.ts +150 -0
  8. package/src/debug/runner.ts +365 -0
  9. package/src/debug/server.ts +565 -0
  10. package/src/debug/stack-merger.ts +267 -0
  11. package/src/debug/state.ts +581 -0
  12. package/src/debug/test/advanced-features.test.ts +300 -0
  13. package/src/debug/test/e2e.test.ts +218 -0
  14. package/src/debug/test/handoff-manager.test.ts +256 -0
  15. package/src/debug/test/runner.test.ts +256 -0
  16. package/src/debug/test/stack-merger.test.ts +163 -0
  17. package/src/debug/test/state.test.ts +400 -0
  18. package/src/debug/test/ts-debug-integration.test.ts +374 -0
  19. package/src/debug/test/ts-import-tracker.test.ts +125 -0
  20. package/src/debug/test/ts-source-map.test.ts +169 -0
  21. package/src/debug/ts-import-tracker.ts +151 -0
  22. package/src/debug/ts-source-map.ts +171 -0
  23. package/src/errors/index.ts +124 -0
  24. package/src/index.ts +358 -0
  25. package/src/lexer/index.ts +348 -0
  26. package/src/lexer.ts +2 -0
  27. package/src/parser/index.ts +792 -0
  28. package/src/parser/parse.ts +45 -0
  29. package/src/parser/test/async.test.ts +248 -0
  30. package/src/parser/test/destructuring.test.ts +167 -0
  31. package/src/parser/test/do-expression.test.ts +486 -0
  32. package/src/parser/test/errors/do-expression.test.ts +95 -0
  33. package/src/parser/test/errors/error-locations.test.ts +230 -0
  34. package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
  35. package/src/parser/test/errors/missing-tokens.test.ts +126 -0
  36. package/src/parser/test/errors/model-declaration.test.ts +185 -0
  37. package/src/parser/test/errors/nested-blocks.test.ts +226 -0
  38. package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
  39. package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
  40. package/src/parser/test/import-export.test.ts +143 -0
  41. package/src/parser/test/literals.test.ts +404 -0
  42. package/src/parser/test/model-declaration.test.ts +161 -0
  43. package/src/parser/test/nested-blocks.test.ts +402 -0
  44. package/src/parser/test/parser.test.ts +743 -0
  45. package/src/parser/test/private.test.ts +136 -0
  46. package/src/parser/test/template-literal.test.ts +127 -0
  47. package/src/parser/test/tool-declaration.test.ts +302 -0
  48. package/src/parser/test/ts-block.test.ts +252 -0
  49. package/src/parser/test/type-annotations.test.ts +254 -0
  50. package/src/parser/visitor/helpers.ts +330 -0
  51. package/src/parser/visitor.ts +794 -0
  52. package/src/parser.ts +2 -0
  53. package/src/runtime/ai/cache-chunking.test.ts +69 -0
  54. package/src/runtime/ai/cache-chunking.ts +73 -0
  55. package/src/runtime/ai/client.ts +109 -0
  56. package/src/runtime/ai/context.ts +168 -0
  57. package/src/runtime/ai/formatters.ts +316 -0
  58. package/src/runtime/ai/index.ts +38 -0
  59. package/src/runtime/ai/language-ref.ts +38 -0
  60. package/src/runtime/ai/providers/anthropic.ts +253 -0
  61. package/src/runtime/ai/providers/google.ts +201 -0
  62. package/src/runtime/ai/providers/openai.ts +156 -0
  63. package/src/runtime/ai/retry.ts +100 -0
  64. package/src/runtime/ai/return-tools.ts +301 -0
  65. package/src/runtime/ai/test/client.test.ts +83 -0
  66. package/src/runtime/ai/test/formatters.test.ts +485 -0
  67. package/src/runtime/ai/test/retry.test.ts +137 -0
  68. package/src/runtime/ai/test/return-tools.test.ts +450 -0
  69. package/src/runtime/ai/test/tool-loop.test.ts +319 -0
  70. package/src/runtime/ai/test/tool-schema.test.ts +241 -0
  71. package/src/runtime/ai/tool-loop.ts +203 -0
  72. package/src/runtime/ai/tool-schema.ts +151 -0
  73. package/src/runtime/ai/types.ts +113 -0
  74. package/src/runtime/ai-logger.ts +255 -0
  75. package/src/runtime/ai-provider.ts +347 -0
  76. package/src/runtime/async/dependencies.ts +276 -0
  77. package/src/runtime/async/executor.ts +293 -0
  78. package/src/runtime/async/index.ts +43 -0
  79. package/src/runtime/async/scheduling.ts +163 -0
  80. package/src/runtime/async/test/dependencies.test.ts +284 -0
  81. package/src/runtime/async/test/executor.test.ts +388 -0
  82. package/src/runtime/context.ts +357 -0
  83. package/src/runtime/exec/ai.ts +139 -0
  84. package/src/runtime/exec/expressions.ts +475 -0
  85. package/src/runtime/exec/frames.ts +26 -0
  86. package/src/runtime/exec/functions.ts +305 -0
  87. package/src/runtime/exec/interpolation.ts +312 -0
  88. package/src/runtime/exec/statements.ts +604 -0
  89. package/src/runtime/exec/tools.ts +129 -0
  90. package/src/runtime/exec/typescript.ts +215 -0
  91. package/src/runtime/exec/variables.ts +279 -0
  92. package/src/runtime/index.ts +975 -0
  93. package/src/runtime/modules.ts +452 -0
  94. package/src/runtime/serialize.ts +103 -0
  95. package/src/runtime/state.ts +489 -0
  96. package/src/runtime/stdlib/core.ts +45 -0
  97. package/src/runtime/stdlib/directory.test.ts +156 -0
  98. package/src/runtime/stdlib/edit.test.ts +154 -0
  99. package/src/runtime/stdlib/fastEdit.test.ts +201 -0
  100. package/src/runtime/stdlib/glob.test.ts +106 -0
  101. package/src/runtime/stdlib/grep.test.ts +144 -0
  102. package/src/runtime/stdlib/index.ts +16 -0
  103. package/src/runtime/stdlib/readFile.test.ts +123 -0
  104. package/src/runtime/stdlib/tools/index.ts +707 -0
  105. package/src/runtime/stdlib/writeFile.test.ts +157 -0
  106. package/src/runtime/step.ts +969 -0
  107. package/src/runtime/test/ai-context.test.ts +1086 -0
  108. package/src/runtime/test/ai-result-object.test.ts +419 -0
  109. package/src/runtime/test/ai-tool-flow.test.ts +859 -0
  110. package/src/runtime/test/async-execution-order.test.ts +618 -0
  111. package/src/runtime/test/async-execution.test.ts +344 -0
  112. package/src/runtime/test/async-nested.test.ts +660 -0
  113. package/src/runtime/test/async-parallel-timing.test.ts +546 -0
  114. package/src/runtime/test/basic1.test.ts +154 -0
  115. package/src/runtime/test/binary-operators.test.ts +431 -0
  116. package/src/runtime/test/break-statement.test.ts +257 -0
  117. package/src/runtime/test/context-modes.test.ts +650 -0
  118. package/src/runtime/test/context.test.ts +466 -0
  119. package/src/runtime/test/core-functions.test.ts +228 -0
  120. package/src/runtime/test/e2e.test.ts +88 -0
  121. package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
  122. package/src/runtime/test/error-locations/main-error.vibe +4 -0
  123. package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
  124. package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
  125. package/src/runtime/test/for-in.test.ts +312 -0
  126. package/src/runtime/test/helpers.ts +69 -0
  127. package/src/runtime/test/imports.test.ts +334 -0
  128. package/src/runtime/test/json-expressions.test.ts +232 -0
  129. package/src/runtime/test/literals.test.ts +372 -0
  130. package/src/runtime/test/logical-indexing.test.ts +478 -0
  131. package/src/runtime/test/member-methods.test.ts +324 -0
  132. package/src/runtime/test/model-config.test.ts +338 -0
  133. package/src/runtime/test/null-handling.test.ts +342 -0
  134. package/src/runtime/test/private-visibility.test.ts +332 -0
  135. package/src/runtime/test/runtime-state.test.ts +514 -0
  136. package/src/runtime/test/scoping.test.ts +370 -0
  137. package/src/runtime/test/string-interpolation.test.ts +354 -0
  138. package/src/runtime/test/template-literal.test.ts +181 -0
  139. package/src/runtime/test/tool-execution.test.ts +467 -0
  140. package/src/runtime/test/tool-schema-generation.test.ts +477 -0
  141. package/src/runtime/test/tostring.test.ts +210 -0
  142. package/src/runtime/test/ts-block.test.ts +594 -0
  143. package/src/runtime/test/ts-error-location.test.ts +231 -0
  144. package/src/runtime/test/types.test.ts +732 -0
  145. package/src/runtime/test/verbose-logger.test.ts +710 -0
  146. package/src/runtime/test/vibe-expression.test.ts +54 -0
  147. package/src/runtime/test/vibe-value-errors.test.ts +541 -0
  148. package/src/runtime/test/while.test.ts +232 -0
  149. package/src/runtime/tools/builtin.ts +30 -0
  150. package/src/runtime/tools/directory-tools.ts +70 -0
  151. package/src/runtime/tools/file-tools.ts +228 -0
  152. package/src/runtime/tools/index.ts +5 -0
  153. package/src/runtime/tools/registry.ts +48 -0
  154. package/src/runtime/tools/search-tools.ts +134 -0
  155. package/src/runtime/tools/security.ts +36 -0
  156. package/src/runtime/tools/system-tools.ts +312 -0
  157. package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
  158. package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
  159. package/src/runtime/tools/test/registry.test.ts +713 -0
  160. package/src/runtime/tools/test/security.test.ts +86 -0
  161. package/src/runtime/tools/test/system-tools.test.ts +679 -0
  162. package/src/runtime/tools/test/ts-schema.test.ts +357 -0
  163. package/src/runtime/tools/ts-schema.ts +341 -0
  164. package/src/runtime/tools/types.ts +89 -0
  165. package/src/runtime/tools/utility-tools.ts +198 -0
  166. package/src/runtime/ts-eval.ts +126 -0
  167. package/src/runtime/types.ts +797 -0
  168. package/src/runtime/validation.ts +160 -0
  169. package/src/runtime/verbose-logger.ts +459 -0
  170. package/src/runtime.ts +2 -0
  171. package/src/semantic/analyzer-context.ts +62 -0
  172. package/src/semantic/analyzer-validators.ts +575 -0
  173. package/src/semantic/analyzer-visitors.ts +534 -0
  174. package/src/semantic/analyzer.ts +83 -0
  175. package/src/semantic/index.ts +11 -0
  176. package/src/semantic/symbol-table.ts +58 -0
  177. package/src/semantic/test/async-validation.test.ts +301 -0
  178. package/src/semantic/test/compress-validation.test.ts +179 -0
  179. package/src/semantic/test/const-reassignment.test.ts +111 -0
  180. package/src/semantic/test/control-flow.test.ts +346 -0
  181. package/src/semantic/test/destructuring.test.ts +185 -0
  182. package/src/semantic/test/duplicate-declarations.test.ts +168 -0
  183. package/src/semantic/test/export-validation.test.ts +111 -0
  184. package/src/semantic/test/fixtures/math.ts +31 -0
  185. package/src/semantic/test/imports.test.ts +148 -0
  186. package/src/semantic/test/json-type.test.ts +68 -0
  187. package/src/semantic/test/literals.test.ts +127 -0
  188. package/src/semantic/test/model-validation.test.ts +179 -0
  189. package/src/semantic/test/prompt-validation.test.ts +343 -0
  190. package/src/semantic/test/scoping.test.ts +312 -0
  191. package/src/semantic/test/tool-validation.test.ts +306 -0
  192. package/src/semantic/test/ts-type-checking.test.ts +563 -0
  193. package/src/semantic/test/type-constraints.test.ts +111 -0
  194. package/src/semantic/test/type-inference.test.ts +87 -0
  195. package/src/semantic/test/type-validation.test.ts +552 -0
  196. package/src/semantic/test/undefined-variables.test.ts +163 -0
  197. package/src/semantic/ts-block-checker.ts +204 -0
  198. package/src/semantic/ts-signatures.ts +194 -0
  199. package/src/semantic/ts-types.ts +170 -0
  200. package/src/semantic/types.ts +58 -0
  201. package/tests/fixtures/conditional-logic.vibe +14 -0
  202. package/tests/fixtures/function-call.vibe +16 -0
  203. package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
  204. package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
  205. package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
  206. package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
  207. package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
  208. package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
  209. package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
  210. package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
  211. package/tests/fixtures/imports/nested-import/main.vibe +3 -0
  212. package/tests/fixtures/imports/nested-import/utils.ts +3 -0
  213. package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
  214. package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
  215. package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
  216. package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
  217. package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
  218. package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
  219. package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
  220. package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
  221. package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
  222. package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
  223. package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
  224. package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
  225. package/tests/fixtures/imports/ts-import/main.vibe +4 -0
  226. package/tests/fixtures/imports/ts-import/math.ts +9 -0
  227. package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
  228. package/tests/fixtures/imports/ts-variables/data.ts +10 -0
  229. package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
  230. package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
  231. package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
  232. package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
  233. package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
  234. package/tests/fixtures/multiple-ai-calls.vibe +10 -0
  235. package/tests/fixtures/simple-greeting.vibe +6 -0
  236. package/tests/fixtures/template-literals.vibe +11 -0
  237. package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
  238. package/tests/integration/basic-ai/basic-ai.vibe +12 -0
  239. package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
  240. package/tests/integration/bug-fix/buggy-code.ts +22 -0
  241. package/tests/integration/bug-fix/fix-bug.vibe +21 -0
  242. package/tests/integration/compress/compress.integration.test.ts +206 -0
  243. package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
  244. package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
  245. package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
  246. package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
  247. package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
  248. package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
  249. package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
  250. package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
@@ -0,0 +1,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
+ });