@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
package/src/index.ts
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// Version (updated by publish script)
|
|
2
|
+
export const VERSION = '0.2.4';
|
|
3
|
+
|
|
4
|
+
// Re-export public API
|
|
5
|
+
export { VibeLexer, tokenize, allTokens } from './lexer';
|
|
6
|
+
export { vibeParser } from './parser';
|
|
7
|
+
export { parse } from './parser/parse';
|
|
8
|
+
export { analyze } from './semantic';
|
|
9
|
+
export { Runtime, RuntimeStatus } from './runtime';
|
|
10
|
+
export type { RuntimeState, AIProvider } from './runtime';
|
|
11
|
+
export * as AST from './ast';
|
|
12
|
+
export * from './errors';
|
|
13
|
+
|
|
14
|
+
import { parse } from './parser/parse';
|
|
15
|
+
import { analyze } from './semantic';
|
|
16
|
+
import { Runtime, AIProvider, createRealAIProvider } from './runtime';
|
|
17
|
+
import { readdirSync, rmSync, statSync } from 'fs';
|
|
18
|
+
import { join, dirname } from 'path';
|
|
19
|
+
|
|
20
|
+
// Clean up orphaned temp directories from previous failed updates (Windows)
|
|
21
|
+
function cleanupOrphanedDirs(): void {
|
|
22
|
+
if (process.platform !== 'win32') return;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Find @vibe-lang in the executable path (works with nvm, volta, standard installs)
|
|
26
|
+
const execPath = process.execPath;
|
|
27
|
+
const marker = '@vibe-lang';
|
|
28
|
+
const markerIndex = execPath.indexOf(marker);
|
|
29
|
+
if (markerIndex === -1) return;
|
|
30
|
+
|
|
31
|
+
// Construct path to node_modules/@vibe-lang
|
|
32
|
+
const vibeLangDir = execPath.substring(0, markerIndex + marker.length);
|
|
33
|
+
|
|
34
|
+
const entries = readdirSync(vibeLangDir);
|
|
35
|
+
|
|
36
|
+
// Look for orphaned .vibe-* temp directories
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
if (entry.startsWith('.vibe-')) {
|
|
39
|
+
const fullPath = join(vibeLangDir, entry);
|
|
40
|
+
try {
|
|
41
|
+
const stat = statSync(fullPath);
|
|
42
|
+
// Only delete if it's a directory and older than 1 minute
|
|
43
|
+
if (stat.isDirectory() && Date.now() - stat.mtimeMs > 60000) {
|
|
44
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// Ignore errors - directory may still be locked
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// Silently ignore cleanup errors
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Simple mock AI provider for testing
|
|
57
|
+
class MockAIProvider implements AIProvider {
|
|
58
|
+
async execute(prompt: string) {
|
|
59
|
+
return { value: `[AI Response to: ${prompt}]` };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async generateCode(prompt: string) {
|
|
63
|
+
return { value: `// Generated code for: ${prompt}\nlet result = "generated"` };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async askUser(prompt: string): Promise<string> {
|
|
67
|
+
return `[User response to: ${prompt}]`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Options for running a vibe program
|
|
72
|
+
export interface RunVibeOptions {
|
|
73
|
+
aiProvider?: AIProvider;
|
|
74
|
+
file?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Main function to run a vibe program
|
|
78
|
+
export async function runVibe(source: string, options?: RunVibeOptions): Promise<unknown> {
|
|
79
|
+
// 1. Parse
|
|
80
|
+
const ast = parse(source, { file: options?.file });
|
|
81
|
+
|
|
82
|
+
// 2. Semantic analysis
|
|
83
|
+
const errors = analyze(ast, source);
|
|
84
|
+
if (errors.length > 0) {
|
|
85
|
+
throw errors[0];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 3. Runtime
|
|
89
|
+
const runtime = new Runtime(ast, options?.aiProvider ?? new MockAIProvider(), { basePath: options?.file });
|
|
90
|
+
return runtime.run();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// CLI entry point
|
|
94
|
+
async function main(): Promise<void> {
|
|
95
|
+
// Clean up orphaned temp directories from previous updates
|
|
96
|
+
cleanupOrphanedDirs();
|
|
97
|
+
|
|
98
|
+
const args = Bun.argv.slice(2);
|
|
99
|
+
|
|
100
|
+
// Handle upgrade/update command
|
|
101
|
+
if (args[0] === 'upgrade' || args[0] === 'update') {
|
|
102
|
+
const targetVersion = args[1] || 'latest';
|
|
103
|
+
const packageSpec = `@vibe-lang/vibe@${targetVersion}`;
|
|
104
|
+
console.log(`Upgrading vibe to ${targetVersion}...`);
|
|
105
|
+
|
|
106
|
+
const proc = Bun.spawn(['npm', 'install', '-g', packageSpec], {
|
|
107
|
+
stdout: 'pipe',
|
|
108
|
+
stderr: 'pipe',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Stream stdout directly
|
|
112
|
+
(async () => {
|
|
113
|
+
const reader = proc.stdout.getReader();
|
|
114
|
+
while (true) {
|
|
115
|
+
const { done, value } = await reader.read();
|
|
116
|
+
if (done) break;
|
|
117
|
+
process.stdout.write(value);
|
|
118
|
+
}
|
|
119
|
+
})();
|
|
120
|
+
|
|
121
|
+
// Filter stderr to suppress cleanup warnings on Windows
|
|
122
|
+
(async () => {
|
|
123
|
+
const reader = proc.stderr.getReader();
|
|
124
|
+
const decoder = new TextDecoder();
|
|
125
|
+
let buffer = '';
|
|
126
|
+
|
|
127
|
+
while (true) {
|
|
128
|
+
const { done, value } = await reader.read();
|
|
129
|
+
if (done) break;
|
|
130
|
+
|
|
131
|
+
buffer += decoder.decode(value, { stream: true });
|
|
132
|
+
const lines = buffer.split('\n');
|
|
133
|
+
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
134
|
+
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
// Skip npm cleanup warnings (Windows file locking issue)
|
|
137
|
+
if (line.includes('npm warn cleanup')) continue;
|
|
138
|
+
if (line.trim()) {
|
|
139
|
+
process.stderr.write(line + '\n');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Handle remaining buffer
|
|
145
|
+
if (buffer.trim() && !buffer.includes('npm warn cleanup')) {
|
|
146
|
+
process.stderr.write(buffer + '\n');
|
|
147
|
+
}
|
|
148
|
+
})();
|
|
149
|
+
|
|
150
|
+
const exitCode = await proc.exited;
|
|
151
|
+
|
|
152
|
+
if (exitCode === 0) {
|
|
153
|
+
console.log('vibe upgraded successfully!');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
process.exit(exitCode);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Handle version flag
|
|
160
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
161
|
+
console.log(`vibe ${VERSION}`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Parse flags
|
|
166
|
+
const verbose = args.includes('--verbose');
|
|
167
|
+
const inspect = args.includes('--inspect');
|
|
168
|
+
const inspectBrk = args.includes('--inspect-brk');
|
|
169
|
+
const debugMode = inspect || inspectBrk;
|
|
170
|
+
const stopOnEntry = inspectBrk;
|
|
171
|
+
|
|
172
|
+
// Parse --inspect-port=PORT option
|
|
173
|
+
let debugPort = 9229; // Default debug port
|
|
174
|
+
const portArg = args.find(arg => arg.startsWith('--inspect-port='));
|
|
175
|
+
if (portArg) {
|
|
176
|
+
debugPort = parseInt(portArg.split('=')[1], 10);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Parse --log-dir=PATH option
|
|
180
|
+
let logDir: string | undefined;
|
|
181
|
+
const logDirArg = args.find(arg => arg.startsWith('--log-dir='));
|
|
182
|
+
if (logDirArg) {
|
|
183
|
+
logDir = logDirArg.split('=')[1];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Parse --max-parallel=N option (for async operations)
|
|
187
|
+
let maxParallel = 4; // Default
|
|
188
|
+
const maxParallelArg = args.find(arg => arg.startsWith('--max-parallel='));
|
|
189
|
+
if (maxParallelArg) {
|
|
190
|
+
const parsed = parseInt(maxParallelArg.split('=')[1], 10);
|
|
191
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
192
|
+
maxParallel = parsed;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const fileArgs = args.filter(arg => !arg.startsWith('--'));
|
|
197
|
+
|
|
198
|
+
if (fileArgs.length === 0) {
|
|
199
|
+
console.log('Vibe - AI Agent Language');
|
|
200
|
+
console.log('Usage: vibe [command] [options] <file.vibe>');
|
|
201
|
+
console.log('');
|
|
202
|
+
console.log('Commands:');
|
|
203
|
+
console.log(' upgrade [version] Update vibe (default: latest)');
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log('Options:');
|
|
206
|
+
console.log(' --verbose Enable verbose JSONL logging (console + file)');
|
|
207
|
+
console.log(' --log-dir=PATH Directory for logs (default: .vibe-logs)');
|
|
208
|
+
console.log(' --max-parallel=N Max concurrent async operations (default: 4)');
|
|
209
|
+
console.log(' --inspect Start with debugger server');
|
|
210
|
+
console.log(' --inspect-brk Start with debugger, break on entry');
|
|
211
|
+
console.log(' --inspect-port=PORT Debug server port (default: 9229)');
|
|
212
|
+
console.log(' -v, --version Show version number');
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log('Example program:');
|
|
215
|
+
console.log(' let x = "hello"');
|
|
216
|
+
console.log(' let y = vibe "what is 2 + 2?"');
|
|
217
|
+
console.log(' function greet(name) {');
|
|
218
|
+
console.log(' return "Hello, {name}!"');
|
|
219
|
+
console.log(' }');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const filePath = fileArgs[0];
|
|
224
|
+
const file = Bun.file(filePath);
|
|
225
|
+
|
|
226
|
+
if (!(await file.exists())) {
|
|
227
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const source = await file.text();
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
// Parse and analyze
|
|
235
|
+
const ast = parse(source, { file: filePath });
|
|
236
|
+
const errors = analyze(ast, source);
|
|
237
|
+
if (errors.length > 0) {
|
|
238
|
+
throw errors[0];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (debugMode) {
|
|
242
|
+
// Run in debug mode
|
|
243
|
+
await runDebugMode(ast, filePath, debugPort, stopOnEntry, verbose, logDir);
|
|
244
|
+
} else {
|
|
245
|
+
// Normal execution
|
|
246
|
+
const runtime: Runtime = new Runtime(
|
|
247
|
+
ast,
|
|
248
|
+
createRealAIProvider(() => runtime.getState()),
|
|
249
|
+
{
|
|
250
|
+
basePath: filePath,
|
|
251
|
+
verbose,
|
|
252
|
+
logDir,
|
|
253
|
+
maxParallel,
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
const result = await runtime.run();
|
|
258
|
+
|
|
259
|
+
// Show log paths if verbose logging was enabled
|
|
260
|
+
if (verbose) {
|
|
261
|
+
const mainLogPath = runtime.getMainLogPath();
|
|
262
|
+
const contextDir = runtime.getContextDir();
|
|
263
|
+
if (mainLogPath) {
|
|
264
|
+
console.error(`[Verbose] Logs written to: ${mainLogPath}`);
|
|
265
|
+
}
|
|
266
|
+
if (contextDir) {
|
|
267
|
+
console.error(`[Verbose] Context files in: ${contextDir}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (result !== null && result !== undefined) {
|
|
272
|
+
console.log('Result:', result);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Debug mode execution
|
|
282
|
+
async function runDebugMode(
|
|
283
|
+
ast: AST.Program,
|
|
284
|
+
filePath: string,
|
|
285
|
+
port: number,
|
|
286
|
+
stopOnEntry: boolean,
|
|
287
|
+
verbose?: boolean,
|
|
288
|
+
logDir?: string
|
|
289
|
+
): Promise<void> {
|
|
290
|
+
// Import debug modules
|
|
291
|
+
const { createDebugState, runWithDebug, getCurrentLocation } = await import('./debug');
|
|
292
|
+
const { startDebugServer, sendEvent, stopDebugServer } = await import('./debug/server');
|
|
293
|
+
const { createInitialState } = await import('./runtime/state');
|
|
294
|
+
const { loadImports } = await import('./runtime/modules');
|
|
295
|
+
const { createRealAIProvider } = await import('./runtime/ai-provider');
|
|
296
|
+
|
|
297
|
+
// Create initial state
|
|
298
|
+
// Note: verbose logging in debug mode is limited for now
|
|
299
|
+
let runtimeState = createInitialState(ast);
|
|
300
|
+
|
|
301
|
+
// Load imports
|
|
302
|
+
runtimeState = await loadImports(runtimeState, filePath);
|
|
303
|
+
|
|
304
|
+
// Create debug state
|
|
305
|
+
const debugState = createDebugState({ stopOnEntry });
|
|
306
|
+
|
|
307
|
+
// Create AI provider that uses the current state
|
|
308
|
+
const aiProvider = createRealAIProvider(() => runtimeState);
|
|
309
|
+
|
|
310
|
+
console.error(`[Debug] Starting debug server on port ${port}...`);
|
|
311
|
+
console.error(`[Debug] Waiting for debugger to attach...`);
|
|
312
|
+
|
|
313
|
+
// Start server and wait for connection
|
|
314
|
+
await startDebugServer(port, runtimeState, debugState, aiProvider);
|
|
315
|
+
|
|
316
|
+
console.error(`[Debug] Debugger attached, starting execution...`);
|
|
317
|
+
|
|
318
|
+
// If stop on entry, send stopped event
|
|
319
|
+
if (stopOnEntry) {
|
|
320
|
+
const location = getCurrentLocation(runtimeState);
|
|
321
|
+
if (location) {
|
|
322
|
+
sendEvent({
|
|
323
|
+
type: 'event',
|
|
324
|
+
event: 'stopped',
|
|
325
|
+
body: {
|
|
326
|
+
reason: 'entry',
|
|
327
|
+
location,
|
|
328
|
+
threadId: 1,
|
|
329
|
+
allThreadsStopped: true,
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
// Run until first breakpoint or completion
|
|
335
|
+
const result = await runWithDebug(
|
|
336
|
+
runtimeState,
|
|
337
|
+
debugState,
|
|
338
|
+
aiProvider,
|
|
339
|
+
sendEvent
|
|
340
|
+
);
|
|
341
|
+
runtimeState = result.runtimeState;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Keep process alive while debugging
|
|
345
|
+
// The server will exit on disconnect
|
|
346
|
+
await new Promise<void>((resolve) => {
|
|
347
|
+
process.on('SIGINT', () => {
|
|
348
|
+
console.error('\n[Debug] Interrupted, shutting down...');
|
|
349
|
+
stopDebugServer();
|
|
350
|
+
resolve();
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Run if executed directly
|
|
356
|
+
if (import.meta.main) {
|
|
357
|
+
main();
|
|
358
|
+
}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { createToken, Lexer, ITokenConfig } from 'chevrotain';
|
|
2
|
+
import { LexerError } from '../errors';
|
|
3
|
+
|
|
4
|
+
// Helper to create tokens
|
|
5
|
+
function token(config: ITokenConfig) {
|
|
6
|
+
return createToken(config);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Whitespace & Comments (skipped)
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
export const WhiteSpace = token({
|
|
14
|
+
name: 'WhiteSpace',
|
|
15
|
+
pattern: /\s+/,
|
|
16
|
+
group: Lexer.SKIPPED,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const LineComment = token({
|
|
20
|
+
name: 'LineComment',
|
|
21
|
+
pattern: /\/\/[^\n]*/,
|
|
22
|
+
group: Lexer.SKIPPED,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const BlockComment = token({
|
|
26
|
+
name: 'BlockComment',
|
|
27
|
+
pattern: /\/\*[\s\S]*?\*\//,
|
|
28
|
+
group: Lexer.SKIPPED,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Keywords (must come before Identifier)
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
// Identifier must be defined first for longer_alt references
|
|
36
|
+
export const Identifier = token({
|
|
37
|
+
name: 'Identifier',
|
|
38
|
+
pattern: /[a-zA-Z_][a-zA-Z0-9_]*/,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const Let = token({ name: 'Let', pattern: /let/, longer_alt: Identifier });
|
|
42
|
+
export const Const = token({ name: 'Const', pattern: /const/, longer_alt: Identifier });
|
|
43
|
+
export const Vibe = token({ name: 'Vibe', pattern: /vibe/, longer_alt: Identifier });
|
|
44
|
+
export const Do = token({ name: 'Do', pattern: /do/, longer_alt: Identifier });
|
|
45
|
+
export const Function = token({ name: 'Function', pattern: /function/, longer_alt: Identifier });
|
|
46
|
+
export const Tool = token({ name: 'Tool', pattern: /tool/, longer_alt: Identifier });
|
|
47
|
+
export const Return = token({ name: 'Return', pattern: /return/, longer_alt: Identifier });
|
|
48
|
+
export const Break = token({ name: 'Break', pattern: /break/, longer_alt: Identifier });
|
|
49
|
+
export const If = token({ name: 'If', pattern: /if/, longer_alt: Identifier });
|
|
50
|
+
export const Else = token({ name: 'Else', pattern: /else/, longer_alt: Identifier });
|
|
51
|
+
export const While = token({ name: 'While', pattern: /while/, longer_alt: Identifier });
|
|
52
|
+
export const True = token({ name: 'True', pattern: /true/, longer_alt: Identifier });
|
|
53
|
+
export const False = token({ name: 'False', pattern: /false/, longer_alt: Identifier });
|
|
54
|
+
export const Null = token({ name: 'Null', pattern: /null/, longer_alt: Identifier });
|
|
55
|
+
export const Model = token({ name: 'Model', pattern: /model/, longer_alt: Identifier });
|
|
56
|
+
export const Default = token({ name: 'Default', pattern: /default/, longer_alt: Identifier });
|
|
57
|
+
export const Local = token({ name: 'Local', pattern: /local/, longer_alt: Identifier });
|
|
58
|
+
export const Import = token({ name: 'Import', pattern: /import/, longer_alt: Identifier });
|
|
59
|
+
export const Export = token({ name: 'Export', pattern: /export/, longer_alt: Identifier });
|
|
60
|
+
export const From = token({ name: 'From', pattern: /from/, longer_alt: Identifier });
|
|
61
|
+
export const Private = token({ name: 'Private', pattern: /private/, longer_alt: Identifier });
|
|
62
|
+
export const Async = token({ name: 'Async', pattern: /async/, longer_alt: Identifier });
|
|
63
|
+
|
|
64
|
+
// TsBlock pattern function: Captures entire ts(params) { body }
|
|
65
|
+
// Defined separately to avoid initialization issues
|
|
66
|
+
function matchTsBlock(text: string, startOffset: number): RegExpExecArray | null {
|
|
67
|
+
// Must start with 'ts'
|
|
68
|
+
if (text.slice(startOffset, startOffset + 2) !== 'ts') return null;
|
|
69
|
+
|
|
70
|
+
// Check it's not part of a longer identifier
|
|
71
|
+
const nextChar = text[startOffset + 2];
|
|
72
|
+
if (nextChar && /[a-zA-Z0-9_]/.test(nextChar)) return null;
|
|
73
|
+
|
|
74
|
+
let i = startOffset + 2;
|
|
75
|
+
|
|
76
|
+
// Skip whitespace
|
|
77
|
+
while (i < text.length && /\s/.test(text[i])) i++;
|
|
78
|
+
|
|
79
|
+
// Must have '('
|
|
80
|
+
if (text[i] !== '(') return null;
|
|
81
|
+
i++;
|
|
82
|
+
|
|
83
|
+
// Find matching ')'
|
|
84
|
+
let parenDepth = 1;
|
|
85
|
+
while (i < text.length && parenDepth > 0) {
|
|
86
|
+
if (text[i] === '(') parenDepth++;
|
|
87
|
+
else if (text[i] === ')') parenDepth--;
|
|
88
|
+
i++;
|
|
89
|
+
}
|
|
90
|
+
if (parenDepth !== 0) return null;
|
|
91
|
+
|
|
92
|
+
// Skip whitespace
|
|
93
|
+
while (i < text.length && /\s/.test(text[i])) i++;
|
|
94
|
+
|
|
95
|
+
// Must have '{'
|
|
96
|
+
if (text[i] !== '{') return null;
|
|
97
|
+
i++;
|
|
98
|
+
|
|
99
|
+
// Find matching '}' with balanced brace counting
|
|
100
|
+
// Handle strings and comments to avoid false matches
|
|
101
|
+
let braceDepth = 1;
|
|
102
|
+
while (i < text.length && braceDepth > 0) {
|
|
103
|
+
const char = text[i];
|
|
104
|
+
|
|
105
|
+
// Handle string literals
|
|
106
|
+
if (char === '"' || char === "'") {
|
|
107
|
+
const quote = char;
|
|
108
|
+
i++;
|
|
109
|
+
while (i < text.length && text[i] !== quote) {
|
|
110
|
+
if (text[i] === '\\') i++; // Skip escaped char
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Handle template literals
|
|
115
|
+
else if (char === '`') {
|
|
116
|
+
i++;
|
|
117
|
+
while (i < text.length && text[i] !== '`') {
|
|
118
|
+
if (text[i] === '\\') i++;
|
|
119
|
+
i++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Handle line comments
|
|
123
|
+
else if (char === '/' && text[i + 1] === '/') {
|
|
124
|
+
while (i < text.length && text[i] !== '\n') i++;
|
|
125
|
+
}
|
|
126
|
+
// Handle block comments
|
|
127
|
+
else if (char === '/' && text[i + 1] === '*') {
|
|
128
|
+
i += 2;
|
|
129
|
+
while (i < text.length - 1 && !(text[i] === '*' && text[i + 1] === '/')) i++;
|
|
130
|
+
i++; // Skip the '/'
|
|
131
|
+
}
|
|
132
|
+
// Handle braces
|
|
133
|
+
else if (char === '{') braceDepth++;
|
|
134
|
+
else if (char === '}') braceDepth--;
|
|
135
|
+
|
|
136
|
+
i++;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (braceDepth !== 0) return null;
|
|
140
|
+
|
|
141
|
+
// Create a fake RegExpExecArray
|
|
142
|
+
const match = text.slice(startOffset, i);
|
|
143
|
+
const result = [match] as RegExpExecArray;
|
|
144
|
+
result.index = startOffset;
|
|
145
|
+
result.input = text;
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// TsBlock: Captures entire ts(params) { body } as a single token
|
|
150
|
+
export const TsBlock = createToken({
|
|
151
|
+
name: 'TsBlock',
|
|
152
|
+
pattern: matchTsBlock,
|
|
153
|
+
line_breaks: true,
|
|
154
|
+
start_chars_hint: ['t'], // TsBlock always starts with 't' (from 'ts')
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Type keywords
|
|
158
|
+
export const TextType = token({ name: 'TextType', pattern: /text/, longer_alt: Identifier });
|
|
159
|
+
export const JsonType = token({ name: 'JsonType', pattern: /json/, longer_alt: Identifier });
|
|
160
|
+
export const PromptType = token({ name: 'PromptType', pattern: /prompt/, longer_alt: Identifier });
|
|
161
|
+
export const BooleanType = token({ name: 'BooleanType', pattern: /boolean/, longer_alt: Identifier });
|
|
162
|
+
export const NumberType = token({ name: 'NumberType', pattern: /number/, longer_alt: Identifier });
|
|
163
|
+
|
|
164
|
+
// Loop keywords
|
|
165
|
+
export const For = token({ name: 'For', pattern: /for/, longer_alt: Identifier });
|
|
166
|
+
export const In = token({ name: 'In', pattern: /in/, longer_alt: Identifier });
|
|
167
|
+
|
|
168
|
+
// Context mode keywords
|
|
169
|
+
export const Forget = token({ name: 'Forget', pattern: /forget/, longer_alt: Identifier });
|
|
170
|
+
export const Verbose = token({ name: 'Verbose', pattern: /verbose/, longer_alt: Identifier });
|
|
171
|
+
export const Compress = token({ name: 'Compress', pattern: /compress/, longer_alt: Identifier });
|
|
172
|
+
|
|
173
|
+
// Tool metadata decorators
|
|
174
|
+
export const AtDescription = token({ name: 'AtDescription', pattern: /@description/ });
|
|
175
|
+
export const AtParam = token({ name: 'AtParam', pattern: /@param/ });
|
|
176
|
+
|
|
177
|
+
// Logical operators (word-based)
|
|
178
|
+
export const And = token({ name: 'And', pattern: /and/, longer_alt: Identifier });
|
|
179
|
+
export const Or = token({ name: 'Or', pattern: /or/, longer_alt: Identifier });
|
|
180
|
+
export const Not = token({ name: 'Not', pattern: /not/, longer_alt: Identifier });
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Literals
|
|
184
|
+
// ============================================================================
|
|
185
|
+
|
|
186
|
+
export const StringLiteral = token({
|
|
187
|
+
name: 'StringLiteral',
|
|
188
|
+
pattern: /"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
export const TemplateLiteral = token({
|
|
192
|
+
name: 'TemplateLiteral',
|
|
193
|
+
pattern: /`(?:[^`\\]|\\.|\r?\n)*`/,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Number literals: integers and decimals (optional leading minus)
|
|
197
|
+
export const NumberLiteral = token({
|
|
198
|
+
name: 'NumberLiteral',
|
|
199
|
+
pattern: /-?[0-9]+(\.[0-9]+)?/,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Operators
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
// Comparison (multi-char must come before single-char)
|
|
207
|
+
export const EqualEqual = token({ name: 'EqualEqual', pattern: /==/ });
|
|
208
|
+
export const NotEqual = token({ name: 'NotEqual', pattern: /!=/ });
|
|
209
|
+
export const LessEqual = token({ name: 'LessEqual', pattern: /<=/ });
|
|
210
|
+
export const GreaterEqual = token({ name: 'GreaterEqual', pattern: />=/ });
|
|
211
|
+
export const LessThan = token({ name: 'LessThan', pattern: /</ });
|
|
212
|
+
export const GreaterThan = token({ name: 'GreaterThan', pattern: />/ });
|
|
213
|
+
|
|
214
|
+
// Assignment (after == to avoid conflict)
|
|
215
|
+
export const Equals = token({ name: 'Equals', pattern: /=/ });
|
|
216
|
+
|
|
217
|
+
// Arithmetic
|
|
218
|
+
export const Plus = token({ name: 'Plus', pattern: /\+/ });
|
|
219
|
+
export const Minus = token({ name: 'Minus', pattern: /-/ });
|
|
220
|
+
export const Star = token({ name: 'Star', pattern: /\*/ });
|
|
221
|
+
export const Slash = token({ name: 'Slash', pattern: /\// });
|
|
222
|
+
export const Percent = token({ name: 'Percent', pattern: /%/ });
|
|
223
|
+
|
|
224
|
+
// ============================================================================
|
|
225
|
+
// Delimiters
|
|
226
|
+
// ============================================================================
|
|
227
|
+
|
|
228
|
+
export const LParen = token({ name: 'LParen', pattern: /\(/ });
|
|
229
|
+
export const RParen = token({ name: 'RParen', pattern: /\)/ });
|
|
230
|
+
export const LBrace = token({ name: 'LBrace', pattern: /\{/ });
|
|
231
|
+
export const RBrace = token({ name: 'RBrace', pattern: /\}/ });
|
|
232
|
+
export const LBracket = token({ name: 'LBracket', pattern: /\[/ });
|
|
233
|
+
export const RBracket = token({ name: 'RBracket', pattern: /\]/ });
|
|
234
|
+
export const Comma = token({ name: 'Comma', pattern: /,/ });
|
|
235
|
+
export const Colon = token({ name: 'Colon', pattern: /:/ });
|
|
236
|
+
export const DotDot = token({ name: 'DotDot', pattern: /\.\./ });
|
|
237
|
+
export const Dot = token({ name: 'Dot', pattern: /\./ }); // Must be after DotDot
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// All tokens in order (order matters for matching!)
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
export const allTokens = [
|
|
244
|
+
// Whitespace & comments first
|
|
245
|
+
WhiteSpace,
|
|
246
|
+
LineComment,
|
|
247
|
+
BlockComment,
|
|
248
|
+
|
|
249
|
+
// Keywords before Identifier
|
|
250
|
+
Let,
|
|
251
|
+
Const,
|
|
252
|
+
Vibe,
|
|
253
|
+
Do,
|
|
254
|
+
Function,
|
|
255
|
+
Tool,
|
|
256
|
+
Return,
|
|
257
|
+
Break,
|
|
258
|
+
If,
|
|
259
|
+
Else,
|
|
260
|
+
While,
|
|
261
|
+
// Context mode keywords (Forget must come before For since 'forget' starts with 'for')
|
|
262
|
+
Forget,
|
|
263
|
+
Verbose,
|
|
264
|
+
Compress,
|
|
265
|
+
// Tool metadata decorators (must come before For/other identifiers)
|
|
266
|
+
AtDescription,
|
|
267
|
+
AtParam,
|
|
268
|
+
For,
|
|
269
|
+
In,
|
|
270
|
+
And,
|
|
271
|
+
Or,
|
|
272
|
+
Not,
|
|
273
|
+
True,
|
|
274
|
+
False,
|
|
275
|
+
Null,
|
|
276
|
+
Model,
|
|
277
|
+
Default,
|
|
278
|
+
Local,
|
|
279
|
+
Import,
|
|
280
|
+
Export,
|
|
281
|
+
From,
|
|
282
|
+
Private,
|
|
283
|
+
Async,
|
|
284
|
+
TsBlock, // Must be before Identifier - captures entire ts(...) { ... }
|
|
285
|
+
TextType,
|
|
286
|
+
JsonType,
|
|
287
|
+
PromptType,
|
|
288
|
+
BooleanType,
|
|
289
|
+
NumberType,
|
|
290
|
+
|
|
291
|
+
// Literals
|
|
292
|
+
StringLiteral,
|
|
293
|
+
TemplateLiteral,
|
|
294
|
+
NumberLiteral,
|
|
295
|
+
|
|
296
|
+
// Identifier after keywords
|
|
297
|
+
Identifier,
|
|
298
|
+
|
|
299
|
+
// Operators (multi-char before single-char)
|
|
300
|
+
EqualEqual,
|
|
301
|
+
NotEqual,
|
|
302
|
+
LessEqual,
|
|
303
|
+
GreaterEqual,
|
|
304
|
+
LessThan,
|
|
305
|
+
GreaterThan,
|
|
306
|
+
Equals,
|
|
307
|
+
Plus,
|
|
308
|
+
Minus,
|
|
309
|
+
Star,
|
|
310
|
+
Slash,
|
|
311
|
+
Percent,
|
|
312
|
+
|
|
313
|
+
// Delimiters
|
|
314
|
+
LParen,
|
|
315
|
+
RParen,
|
|
316
|
+
LBrace,
|
|
317
|
+
RBrace,
|
|
318
|
+
LBracket,
|
|
319
|
+
RBracket,
|
|
320
|
+
Comma,
|
|
321
|
+
Colon,
|
|
322
|
+
DotDot,
|
|
323
|
+
Dot,
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// Create the Lexer instance
|
|
328
|
+
// ============================================================================
|
|
329
|
+
|
|
330
|
+
export const VibeLexer = new Lexer(allTokens, {
|
|
331
|
+
ensureOptimizations: true,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Helper function to tokenize source code
|
|
335
|
+
export function tokenize(source: string) {
|
|
336
|
+
const result = VibeLexer.tokenize(source);
|
|
337
|
+
|
|
338
|
+
if (result.errors.length > 0) {
|
|
339
|
+
const error = result.errors[0];
|
|
340
|
+
throw new LexerError(
|
|
341
|
+
error.message,
|
|
342
|
+
{ line: error.line ?? 1, column: error.column ?? 1 },
|
|
343
|
+
source
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return result.tokens;
|
|
348
|
+
}
|
package/src/lexer.ts
ADDED