dirac-lang 0.1.23 → 0.1.25
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/dist/{chunk-APWJJXNI.js → chunk-7OUYWIZV.js} +55 -14
- package/dist/{chunk-RGS2XK6T.js → chunk-OUMUIBK3.js} +1 -1
- package/dist/cli.js +15 -3
- package/dist/index.js +2 -2
- package/dist/{interpreter-UZDVASAW.js → interpreter-MTIIHIIQ.js} +1 -1
- package/dist/test-runner.js +1 -1
- package/lib/index.di +9 -0
- package/package.json +13 -1
- package/.env.example +0 -8
- package/COMMUNITY.md +0 -465
- package/CONDITIONAL-TAGS.md +0 -172
- package/EXCEPTION-HANDLING.md +0 -156
- package/LIBRARIES.md +0 -172
- package/LLM-VALIDATION.md +0 -128
- package/NAMESPACES.md +0 -366
- package/PROMOTION.md +0 -257
- package/QUICKSTART-LIBRARY.md +0 -93
- package/TEST-COVERAGE.md +0 -113
- package/TESTING.md +0 -162
- package/config.test.yml +0 -5
- package/dirac-http/examples/demo.di +0 -9
- package/dirac-http/lib/index.di +0 -12
- package/examples/add-demo.di +0 -74
- package/examples/add.bk +0 -11
- package/examples/advanced-math-demo.di +0 -53
- package/examples/calculator.di +0 -32
- package/examples/compact-test.di +0 -6
- package/examples/comprehensive.bk +0 -29
- package/examples/defvar-variable-demo.di +0 -18
- package/examples/direct-call.di +0 -17
- package/examples/disk-analysis.di +0 -16
- package/examples/exception-demo.di +0 -82
- package/examples/executable-hello.di +0 -7
- package/examples/execute-demo.di +0 -38
- package/examples/file-manager.di +0 -77
- package/examples/file-stats.di +0 -18
- package/examples/hello.bk +0 -1
- package/examples/hello.di +0 -5
- package/examples/if-comparison.di +0 -91
- package/examples/if-cstyle-test.di +0 -149
- package/examples/if-vs-testif.di +0 -56
- package/examples/import-demo.di +0 -31
- package/examples/inline-test.bk +0 -7
- package/examples/llm-agent.di +0 -32
- package/examples/llm-basic.di +0 -12
- package/examples/llm-command-more.di +0 -6
- package/examples/llm-command-no-exec.di +0 -13
- package/examples/llm-command.di +0 -6
- package/examples/llm-complex.di +0 -141
- package/examples/llm-feedback-debug.di +0 -30
- package/examples/llm-feedback-demo.di +0 -19
- package/examples/llm-feedback-math.di +0 -22
- package/examples/llm-feedback-simple.di +0 -16
- package/examples/llm-feedback-sub.di +0 -22
- package/examples/llm-no-feedback.di +0 -10
- package/examples/llm-recursive.di +0 -31
- package/examples/llm-reflection-test.di +0 -19
- package/examples/llm-simple-test.di +0 -12
- package/examples/llm-subs.di +0 -132
- package/examples/llm-use-subs.di +0 -6
- package/examples/llm-validate-test.di +0 -18
- package/examples/loop.di +0 -12
- package/examples/math-test.di +0 -22
- package/examples/minimal-test.di +0 -13
- package/examples/mongodb-context-test.di +0 -27
- package/examples/mongodb-count-events.di +0 -8
- package/examples/mongodb-import-demo.di +0 -25
- package/examples/mongodb-simple-test.di +0 -18
- package/examples/nl-agent.di +0 -47
- package/examples/parameters-demo.di +0 -68
- package/examples/params-meta-test.di +0 -17
- package/examples/params-test.di +0 -10
- package/examples/recipe-chain.di +0 -38
- package/examples/recursive-llm.di +0 -44
- package/examples/sample-library/README.md +0 -152
- package/examples/sample-library/examples/demo.di +0 -34
- package/examples/sample-library/lib/index.di +0 -65
- package/examples/sample-library/package.json +0 -31
- package/examples/scope-test-nested.di +0 -60
- package/examples/scope-test.di +0 -55
- package/examples/seamless.di +0 -45
- package/examples/shell-test.bk +0 -10
- package/examples/simple-import.di +0 -13
- package/examples/simple-recursive.di +0 -26
- package/examples/story-builder.di +0 -45
- package/examples/subroutine.di +0 -23
- package/examples/system-llm.di +0 -21
- package/examples/system-simple.di +0 -3
- package/examples/system-test.di +0 -8
- package/examples/tag-check-test.di +0 -139
- package/examples/task-assistant.di +0 -27
- package/examples/test-if-demo.di +0 -110
- package/examples/test-parameters.di +0 -50
- package/examples/try-catch-test.di +0 -118
- package/examples/two-styles.di +0 -28
- package/examples/var-debug.di +0 -6
- package/examples/var-inline.di +0 -4
- package/examples/var-test2.di +0 -6
- package/examples/variable-replace.di +0 -25
- package/examples/variable-simple.di +0 -16
- package/examples/variable-test.di +0 -22
- package/examples/whitespace-test.di +0 -24
- package/filePath +0 -1
- package/greeting.txt +0 -1
- package/src/cli.ts +0 -140
- package/src/index.ts +0 -33
- package/src/llm/ollama.ts +0 -58
- package/src/runtime/braket-parser.ts +0 -234
- package/src/runtime/interpreter.ts +0 -203
- package/src/runtime/parser.ts +0 -155
- package/src/runtime/session.ts +0 -325
- package/src/tags/assign.ts +0 -37
- package/src/tags/attr.ts +0 -64
- package/src/tags/available-subroutines.ts +0 -70
- package/src/tags/call.ts +0 -259
- package/src/tags/catch.ts +0 -24
- package/src/tags/defvar.ts +0 -115
- package/src/tags/environment.ts +0 -21
- package/src/tags/eval.ts +0 -71
- package/src/tags/exception.ts +0 -20
- package/src/tags/execute.ts +0 -52
- package/src/tags/expr.ts +0 -128
- package/src/tags/foreach.ts +0 -170
- package/src/tags/if.ts +0 -191
- package/src/tags/import.ts +0 -66
- package/src/tags/index.ts +0 -41
- package/src/tags/input.ts +0 -182
- package/src/tags/llm.ts +0 -415
- package/src/tags/loop.ts +0 -43
- package/src/tags/mongodb.ts +0 -70
- package/src/tags/output.ts +0 -53
- package/src/tags/parameters.ts +0 -81
- package/src/tags/require_module.ts +0 -19
- package/src/tags/subroutine.ts +0 -75
- package/src/tags/system.ts +0 -93
- package/src/tags/tag-check.ts +0 -176
- package/src/tags/test-if.ts +0 -112
- package/src/tags/throw.ts +0 -26
- package/src/tags/try.ts +0 -19
- package/src/tags/variable.ts +0 -25
- package/src/test-runner.ts +0 -300
- package/src/types/index.ts +0 -128
- package/src/utils/llm-adapter.ts +0 -113
- package/src/utils/tag-validator.ts +0 -231
- package/test-available-extends.di +0 -28
- package/test-available-simple.di +0 -12
- package/test-available-subroutines.di +0 -16
- package/test-call.di +0 -9
- package/test-extend-basic.di +0 -17
- package/test-extend-chain.di +0 -26
- package/test-extend-debug.di +0 -17
- package/test-extend-debug2.di +0 -15
- package/test-extend-person.di +0 -17
- package/test-extend-simple.di +0 -11
- package/test-extend-zhi.di +0 -23
- package/test-extend.di +0 -19
- package/test-extend2.di +0 -26
- package/test-extend3-fixed.di +0 -23
- package/test-extend3-trouble.di +0 -23
- package/test-extend3.di +0 -21
- package/test-factorial.di +0 -19
- package/test-input-debug.di +0 -19
- package/test-nested-debug.di +0 -7
- package/test-nested-debug2.di +0 -8
- package/test-no-extend.di +0 -16
- package/test-simple-call.di +0 -7
- package/test-simple.di +0 -6
- package/tests/README.md +0 -69
- package/tests/assign-basic.test.di +0 -7
- package/tests/assign-from-eval.test.di +0 -7
- package/tests/available-subroutines-foreach.test.di +0 -32
- package/tests/basic-output.test.di +0 -5
- package/tests/call-basic.test.di +0 -11
- package/tests/call-with-output.test.di +0 -10
- package/tests/comments-before-content.test.di +0 -6
- package/tests/defvar-multiple.test.di +0 -8
- package/tests/environment-basic.test.di +0 -22
- package/tests/environment-nonexistent.test.di +0 -5
- package/tests/environment-with-defvar.test.di +0 -15
- package/tests/eval-basic.test.di +0 -6
- package/tests/eval-with-variables.test.di +0 -8
- package/tests/exception-basic.test.di +0 -10
- package/tests/expr-basic.test.di +0 -11
- package/tests/extend-basic.test.di +0 -19
- package/tests/extend-inheritance-chain.test.di +0 -26
- package/tests/extend-multiple-nested.test.di +0 -24
- package/tests/extend-self.test.di +0 -19
- package/tests/extend-with-parameters.test.di +0 -14
- package/tests/generate-dirac.test.di +0 -22
- package/tests/if-conditional.test.di +0 -17
- package/tests/if-else.test.di +0 -11
- package/tests/if-with-variables.test.di +0 -8
- package/tests/import-basic.test.di +0 -6
- package/tests/input-file-all.test.di +0 -5
- package/tests/input-file-line.test.di +0 -15
- package/tests/input-file-loop.test.di +0 -12
- package/tests/input-stdin-all.test.di +0 -8
- package/tests/input-stdin-all.txt +0 -1
- package/tests/llm-validate.test.di +0 -17
- package/tests/loop-basic.test.di +0 -9
- package/tests/loop-nested.test.di +0 -10
- package/tests/loop-with-eval.test.di +0 -8
- package/tests/no-root-element.test.di +0 -6
- package/tests/output-file.test.di +0 -19
- package/tests/output-multiple.test.di +0 -9
- package/tests/parameters-basic.test.di +0 -6
- package/tests/require-module-basic.test.di +0 -7
- package/tests/subroutine-basic.test.di +0 -9
- package/tests/subroutine-multiple-params.test.di +0 -10
- package/tests/subroutine-nested-calls.test.di +0 -32
- package/tests/subroutine-sequential-calls.test.di +0 -36
- package/tests/system-background.test.di +0 -39
- package/tests/system-basic.test.di +0 -5
- package/tests/tag-check.test.di +0 -27
- package/tests/test-if-basic.test.di +0 -8
- package/tests/test-input.txt +0 -3
- package/tests/try-catch-basic.test.di +0 -10
- package/tests/try-catch-eval-error.test.di +0 -10
- package/tests/variable-basic.test.di +0 -6
- package/tests/variable-interpolation.test.di +0 -7
- package/tools/create-library.sh +0 -175
- package/tsconfig.json +0 -19
- /package/{examples/lib → lib}/advanced-math.di +0 -0
- /package/{examples/lib → lib}/fileops.di +0 -0
- /package/{examples/lib → lib}/math.di +0 -0
- /package/{examples/lib → lib}/mongodb.di +0 -0
package/src/tags/throw.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <throw> tag - throws an exception
|
|
3
|
-
* Maps to mask_throw_integrate in MASK
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { throwException } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export async function executeThrow(session: DiracSession, element: DiracElement): Promise<void> {
|
|
10
|
-
// Get exception name from 'name' attribute (default to "exception")
|
|
11
|
-
const exceptionName = element.attributes?.name || 'exception';
|
|
12
|
-
|
|
13
|
-
// Process children to build exception content
|
|
14
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
15
|
-
|
|
16
|
-
// Create a wrapper element to capture the processed content
|
|
17
|
-
const exceptionDom: DiracElement = {
|
|
18
|
-
tag: 'exception-content',
|
|
19
|
-
attributes: { name: exceptionName },
|
|
20
|
-
children: element.children,
|
|
21
|
-
text: element.text,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Throw the exception (add to exception stack)
|
|
25
|
-
throwException(session, exceptionName, exceptionDom);
|
|
26
|
-
}
|
package/src/tags/try.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <try> tag - establishes exception boundary
|
|
3
|
-
* Maps to mask_try_integrate in MASK
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { setExceptionBoundary, unsetExceptionBoundary } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export async function executeTry(session: DiracSession, element: DiracElement): Promise<void> {
|
|
10
|
-
// Set exception boundary (mark the start of try block)
|
|
11
|
-
setExceptionBoundary(session);
|
|
12
|
-
|
|
13
|
-
// Execute children (the try block content)
|
|
14
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
15
|
-
await integrateChildren(session, element);
|
|
16
|
-
|
|
17
|
-
// Unset boundary after execution
|
|
18
|
-
unsetExceptionBoundary(session);
|
|
19
|
-
}
|
package/src/tags/variable.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <variable> tag - retrieve variable value
|
|
3
|
-
* Outputs the stored variable content (text or tags)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { getVariable, emit } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export function executeVariable(session: DiracSession, element: DiracElement): void {
|
|
10
|
-
const name = element.attributes.name;
|
|
11
|
-
if (!name) {
|
|
12
|
-
// Debug: print the full element for diagnosis
|
|
13
|
-
console.error('[VariableTagError] <variable> tag missing name attribute:', JSON.stringify(element));
|
|
14
|
-
throw new Error('<variable> requires name attribute');
|
|
15
|
-
}
|
|
16
|
-
const value = getVariable(session, name);
|
|
17
|
-
if (value === undefined) {
|
|
18
|
-
if (session.debug) {
|
|
19
|
-
console.error(`[Warning] Variable '${name}' is undefined`);
|
|
20
|
-
}
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
// Output the variable value
|
|
24
|
-
emit(session, String(value));
|
|
25
|
-
}
|
package/src/test-runner.ts
DELETED
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple test runner for Dirac
|
|
3
|
-
* Tests are defined as .di files with expected output in comments
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { DiracParser } from './runtime/parser.js';
|
|
9
|
-
import { createSession, getOutput } from './runtime/session.js';
|
|
10
|
-
import { integrate } from './runtime/interpreter.js';
|
|
11
|
-
import yaml from 'js-yaml';
|
|
12
|
-
|
|
13
|
-
interface TestCase {
|
|
14
|
-
name: string;
|
|
15
|
-
file: string;
|
|
16
|
-
expectedOutput?: string;
|
|
17
|
-
expectedError?: string;
|
|
18
|
-
config?: any;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface TestResult {
|
|
22
|
-
name: string;
|
|
23
|
-
passed: boolean;
|
|
24
|
-
error?: string;
|
|
25
|
-
actualOutput?: string;
|
|
26
|
-
expectedOutput?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class TestRunner {
|
|
30
|
-
private testDir: string;
|
|
31
|
-
private config: any;
|
|
32
|
-
|
|
33
|
-
constructor(testDir: string = 'tests', configPath?: string) {
|
|
34
|
-
this.testDir = testDir;
|
|
35
|
-
|
|
36
|
-
// For tests, always use ollama as the default provider (no API keys needed)
|
|
37
|
-
// Unless a specific test config is provided
|
|
38
|
-
if (configPath && fs.existsSync(configPath)) {
|
|
39
|
-
this.config = yaml.load(fs.readFileSync(configPath, 'utf8')) || {};
|
|
40
|
-
} else {
|
|
41
|
-
this.config = { llmProvider: 'ollama', llmModel: 'llama2' };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Parse test metadata from comments in .di file
|
|
47
|
-
* Format:
|
|
48
|
-
* <!-- TEST: test_name -->
|
|
49
|
-
* <!-- EXPECT: expected output -->
|
|
50
|
-
* <!-- EXPECT_ERROR: expected error message -->
|
|
51
|
-
*/
|
|
52
|
-
private parseTestMetadata(content: string): { name?: string; expected?: string; expectError?: string } {
|
|
53
|
-
const nameMatch = content.match(/<!--\s*TEST:\s*(.+?)\s*-->/);
|
|
54
|
-
const expectMatch = content.match(/<!--\s*EXPECT:\s*(.+?)\s*-->/s);
|
|
55
|
-
const errorMatch = content.match(/<!--\s*EXPECT_ERROR:\s*(.+?)\s*-->/s);
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
name: nameMatch?.[1],
|
|
59
|
-
expected: expectMatch?.[1]?.trim(),
|
|
60
|
-
expectError: errorMatch?.[1]?.trim(),
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Run a single test file
|
|
66
|
-
*/
|
|
67
|
-
async runTest(filePath: string): Promise<TestResult> {
|
|
68
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
69
|
-
const metadata = this.parseTestMetadata(content);
|
|
70
|
-
const testName = metadata.name || path.basename(filePath);
|
|
71
|
-
|
|
72
|
-
// Remove test comments before execution
|
|
73
|
-
const cleanContent = content
|
|
74
|
-
.replace(/<!--\s*TEST:.*?-->/gs, '')
|
|
75
|
-
.replace(/<!--\s*EXPECT:.*?-->/gs, '')
|
|
76
|
-
.replace(/<!--\s*EXPECT_ERROR:.*?-->/gs, '');
|
|
77
|
-
|
|
78
|
-
const result: TestResult = {
|
|
79
|
-
name: testName,
|
|
80
|
-
passed: false,
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
// Check if there's a stdin input file for this test
|
|
85
|
-
const stdinFile = filePath.replace('.test.di', '.txt');
|
|
86
|
-
let stdinData: string | undefined;
|
|
87
|
-
if (fs.existsSync(stdinFile)) {
|
|
88
|
-
stdinData = fs.readFileSync(stdinFile, 'utf-8');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// If stdin data exists, we need to mock stdin
|
|
92
|
-
// Since we can't replace process.stdin directly, we'll use a workaround:
|
|
93
|
-
// temporarily store data in a place the input tag can access it
|
|
94
|
-
if (stdinData !== undefined) {
|
|
95
|
-
// Save original methods
|
|
96
|
-
const originalOn = process.stdin.on.bind(process.stdin);
|
|
97
|
-
const originalResume = process.stdin.resume.bind(process.stdin);
|
|
98
|
-
const originalRemoveAllListeners = process.stdin.removeAllListeners.bind(process.stdin);
|
|
99
|
-
const originalRemoveListener = process.stdin.removeListener.bind(process.stdin);
|
|
100
|
-
|
|
101
|
-
// Mock stdin methods
|
|
102
|
-
const listeners: { [key: string]: Function[] } = {};
|
|
103
|
-
|
|
104
|
-
(process.stdin as any).on = function(event: string, callback: Function) {
|
|
105
|
-
if (!listeners[event]) listeners[event] = [];
|
|
106
|
-
listeners[event].push(callback);
|
|
107
|
-
return this;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
(process.stdin as any).removeAllListeners = function(event?: string) {
|
|
111
|
-
if (event) {
|
|
112
|
-
delete listeners[event];
|
|
113
|
-
} else {
|
|
114
|
-
Object.keys(listeners).forEach(k => delete listeners[k]);
|
|
115
|
-
}
|
|
116
|
-
return this;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
(process.stdin as any).removeListener = function(event: string, callback: Function) {
|
|
120
|
-
if (listeners[event]) {
|
|
121
|
-
listeners[event] = listeners[event].filter(fn => fn !== callback);
|
|
122
|
-
}
|
|
123
|
-
return this;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
(process.stdin as any).resume = function() {
|
|
127
|
-
// Simulate data event
|
|
128
|
-
setImmediate(() => {
|
|
129
|
-
if (listeners['data']) {
|
|
130
|
-
listeners['data'].forEach(fn => fn(Buffer.from(stdinData!, 'utf-8')));
|
|
131
|
-
}
|
|
132
|
-
// Simulate end event
|
|
133
|
-
setImmediate(() => {
|
|
134
|
-
if (listeners['end']) {
|
|
135
|
-
listeners['end'].forEach(fn => fn());
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
return this;
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
const parser = new DiracParser();
|
|
144
|
-
const ast = parser.parse(cleanContent);
|
|
145
|
-
const session = createSession({ ...this.config, filePath });
|
|
146
|
-
await integrate(session, ast);
|
|
147
|
-
const output = getOutput(session);
|
|
148
|
-
result.actualOutput = output;
|
|
149
|
-
} finally {
|
|
150
|
-
// Restore original methods
|
|
151
|
-
(process.stdin as any).on = originalOn;
|
|
152
|
-
(process.stdin as any).resume = originalResume;
|
|
153
|
-
(process.stdin as any).removeAllListeners = originalRemoveAllListeners;
|
|
154
|
-
(process.stdin as any).removeListener = originalRemoveListener;
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
// Normal test without stdin
|
|
158
|
-
const parser = new DiracParser();
|
|
159
|
-
const ast = parser.parse(cleanContent);
|
|
160
|
-
const session = createSession({ ...this.config, filePath });
|
|
161
|
-
await integrate(session, ast);
|
|
162
|
-
const output = getOutput(session);
|
|
163
|
-
result.actualOutput = output;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (metadata.expectError) {
|
|
167
|
-
// Expected an error but got success
|
|
168
|
-
result.passed = false;
|
|
169
|
-
result.error = `Expected error but test succeeded. Output: ${result.actualOutput}`;
|
|
170
|
-
} else if (metadata.expected !== undefined) {
|
|
171
|
-
// Check if output matches expected
|
|
172
|
-
// Normalize whitespace for comparison (collapse multiple spaces/newlines)
|
|
173
|
-
const normalizedActual = result.actualOutput!.replace(/\s+/g, ' ').trim();
|
|
174
|
-
const normalizedExpected = metadata.expected.replace(/\s+/g, ' ').trim();
|
|
175
|
-
|
|
176
|
-
if (normalizedActual === normalizedExpected) {
|
|
177
|
-
result.passed = true;
|
|
178
|
-
} else {
|
|
179
|
-
result.passed = false;
|
|
180
|
-
result.error = `Output mismatch`;
|
|
181
|
-
result.expectedOutput = normalizedExpected;
|
|
182
|
-
result.actualOutput = normalizedActual;
|
|
183
|
-
}
|
|
184
|
-
} else {
|
|
185
|
-
// No expected output specified, just check it runs without error
|
|
186
|
-
result.passed = true;
|
|
187
|
-
}
|
|
188
|
-
} catch (error) {
|
|
189
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
190
|
-
|
|
191
|
-
if (metadata.expectError) {
|
|
192
|
-
// Check if error matches expected
|
|
193
|
-
if (errorMessage.includes(metadata.expectError)) {
|
|
194
|
-
result.passed = true;
|
|
195
|
-
} else {
|
|
196
|
-
result.passed = false;
|
|
197
|
-
result.error = `Error mismatch. Expected: "${metadata.expectError}", Got: "${errorMessage}"`;
|
|
198
|
-
}
|
|
199
|
-
} else {
|
|
200
|
-
// Unexpected error
|
|
201
|
-
result.passed = false;
|
|
202
|
-
result.error = errorMessage;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return result;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Run all tests in the test directory
|
|
211
|
-
*/
|
|
212
|
-
async runAll(pattern: string = '*.test.di'): Promise<TestResult[]> {
|
|
213
|
-
const testFiles = this.findTestFiles(this.testDir, pattern);
|
|
214
|
-
const results: TestResult[] = [];
|
|
215
|
-
|
|
216
|
-
console.log(`Running ${testFiles.length} tests...\n`);
|
|
217
|
-
|
|
218
|
-
for (const file of testFiles) {
|
|
219
|
-
const result = await this.runTest(file);
|
|
220
|
-
results.push(result);
|
|
221
|
-
|
|
222
|
-
// Print result immediately
|
|
223
|
-
if (result.passed) {
|
|
224
|
-
console.log(`✓ ${result.name}`);
|
|
225
|
-
} else {
|
|
226
|
-
console.log(`✗ ${result.name}`);
|
|
227
|
-
if (result.error) {
|
|
228
|
-
console.log(` Error: ${result.error}`);
|
|
229
|
-
}
|
|
230
|
-
if (result.expectedOutput !== undefined && result.actualOutput !== undefined) {
|
|
231
|
-
console.log(` Expected: ${JSON.stringify(result.expectedOutput)}`);
|
|
232
|
-
console.log(` Actual: ${JSON.stringify(result.actualOutput)}`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return results;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Find test files matching pattern
|
|
242
|
-
*/
|
|
243
|
-
private findTestFiles(dir: string, pattern: string): string[] {
|
|
244
|
-
if (!fs.existsSync(dir)) {
|
|
245
|
-
return [];
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const files: string[] = [];
|
|
249
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
250
|
-
|
|
251
|
-
for (const entry of entries) {
|
|
252
|
-
const fullPath = path.join(dir, entry.name);
|
|
253
|
-
|
|
254
|
-
if (entry.isDirectory()) {
|
|
255
|
-
files.push(...this.findTestFiles(fullPath, pattern));
|
|
256
|
-
} else if (entry.isFile() && entry.name.endsWith('.test.di')) {
|
|
257
|
-
files.push(fullPath);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return files;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Print summary of test results
|
|
266
|
-
*/
|
|
267
|
-
printSummary(results: TestResult[]): void {
|
|
268
|
-
const passed = results.filter(r => r.passed).length;
|
|
269
|
-
const failed = results.filter(r => !r.passed).length;
|
|
270
|
-
|
|
271
|
-
console.log('\n' + '='.repeat(50));
|
|
272
|
-
console.log(`Tests: ${passed} passed, ${failed} failed, ${results.length} total`);
|
|
273
|
-
|
|
274
|
-
if (failed > 0) {
|
|
275
|
-
console.log('\nFailed tests:');
|
|
276
|
-
results.filter(r => !r.passed).forEach(r => {
|
|
277
|
-
console.log(` - ${r.name}`);
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
console.log('='.repeat(50));
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// CLI interface
|
|
286
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
287
|
-
const testDir = process.argv[2] || 'tests';
|
|
288
|
-
const runner = new TestRunner(testDir);
|
|
289
|
-
|
|
290
|
-
runner.runAll().then(results => {
|
|
291
|
-
runner.printSummary(results);
|
|
292
|
-
|
|
293
|
-
// Exit with error code if any tests failed
|
|
294
|
-
const failed = results.filter(r => !r.passed).length;
|
|
295
|
-
process.exit(failed > 0 ? 1 : 0);
|
|
296
|
-
}).catch(error => {
|
|
297
|
-
console.error('Test runner error:', error);
|
|
298
|
-
process.exit(1);
|
|
299
|
-
});
|
|
300
|
-
}
|
package/src/types/index.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core types for Dirac interpreter
|
|
3
|
-
* Directly based on MASK C implementation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface DiracElement {
|
|
7
|
-
tag: string;
|
|
8
|
-
attributes: Record<string, string>;
|
|
9
|
-
children: DiracElement[];
|
|
10
|
-
text?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Variable info - maps to VarInfo in MASK
|
|
15
|
-
*/
|
|
16
|
-
export interface Variable {
|
|
17
|
-
name: string;
|
|
18
|
-
value: any;
|
|
19
|
-
visible: boolean;
|
|
20
|
-
boundary: number; // scope boundary marker
|
|
21
|
-
passby: 'value' | 'ref';
|
|
22
|
-
refName?: string; // for pass-by-reference
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Parameter metadata for introspection
|
|
27
|
-
*/
|
|
28
|
-
export interface ParameterMetadata {
|
|
29
|
-
name: string;
|
|
30
|
-
type?: string;
|
|
31
|
-
required?: boolean;
|
|
32
|
-
description?: string;
|
|
33
|
-
enum?: string[];
|
|
34
|
-
example?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Exception info - maps to Exception in MASK
|
|
39
|
-
*/
|
|
40
|
-
export interface Exception {
|
|
41
|
-
name: string;
|
|
42
|
-
dom: DiracElement; // The exception content as a DOM element
|
|
43
|
-
isBoundary: number; // Boundary marker for try/catch scope
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Current exception container - maps to CurrentException in MASK
|
|
48
|
-
*/
|
|
49
|
-
export interface CurrentException {
|
|
50
|
-
size: number;
|
|
51
|
-
exceptions: DiracElement[]; // List of caught exception DOM elements
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Subroutine info - maps to Subroutine in MASK
|
|
56
|
-
*/
|
|
57
|
-
export interface Subroutine {
|
|
58
|
-
name: string;
|
|
59
|
-
element: DiracElement;
|
|
60
|
-
boundary: number; // scope boundary marker
|
|
61
|
-
extends?: string; // parent subroutine
|
|
62
|
-
// Metadata for reflection/introspection
|
|
63
|
-
description?: string;
|
|
64
|
-
parameters?: ParameterMetadata[];
|
|
65
|
-
meta?: Record<string, string>;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Execution context - maps to MaskSession in MASK
|
|
70
|
-
*/
|
|
71
|
-
export interface DiracSession {
|
|
72
|
-
// Variable stack (all variables are on stack)
|
|
73
|
-
variables: Variable[];
|
|
74
|
-
|
|
75
|
-
// Subroutine registry
|
|
76
|
-
subroutines: Subroutine[];
|
|
77
|
-
|
|
78
|
-
// Scope boundaries (for cleanup)
|
|
79
|
-
varBoundary: number;
|
|
80
|
-
subBoundary: number;
|
|
81
|
-
|
|
82
|
-
// Parameter stack (for subroutine calls)
|
|
83
|
-
parameterStack: DiracElement[][];
|
|
84
|
-
|
|
85
|
-
// Exception handling (for try/catch/throw)
|
|
86
|
-
exceptions: Exception[]; // Exception stack
|
|
87
|
-
currentException: CurrentException; // Currently caught exceptions
|
|
88
|
-
|
|
89
|
-
// Output buffer
|
|
90
|
-
output: string[];
|
|
91
|
-
|
|
92
|
-
// LLM client
|
|
93
|
-
llmClient?: any;
|
|
94
|
-
|
|
95
|
-
// Execution limits
|
|
96
|
-
limits: {
|
|
97
|
-
maxLLMCalls: number;
|
|
98
|
-
currentLLMCalls: number;
|
|
99
|
-
maxDepth: number;
|
|
100
|
-
currentDepth: number;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// Control flow
|
|
104
|
-
isReturn: boolean;
|
|
105
|
-
isBreak: boolean;
|
|
106
|
-
|
|
107
|
-
// Extend mechanism
|
|
108
|
-
skipSubroutineRegistration: boolean;
|
|
109
|
-
currentSubroutineName?: string; // Track currently executing subroutine for available-subroutines
|
|
110
|
-
|
|
111
|
-
// Debugging
|
|
112
|
-
debug: boolean;
|
|
113
|
-
|
|
114
|
-
// Import tracking
|
|
115
|
-
currentFile?: string;
|
|
116
|
-
importedFiles?: Set<string>;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface DiracConfig {
|
|
120
|
-
apiKey?: string;
|
|
121
|
-
model?: string;
|
|
122
|
-
debug?: boolean;
|
|
123
|
-
maxLLMCalls?: number;
|
|
124
|
-
maxDepth?: number;
|
|
125
|
-
filePath?: string; // Current file path for imports
|
|
126
|
-
llmProvider?: string;
|
|
127
|
-
llmModel?: string;
|
|
128
|
-
}
|
package/src/utils/llm-adapter.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LLM Adapter - Auto-generate prompts and JSON→XML converters
|
|
3
|
-
* from Dirac subroutine definitions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession } from '../types/index.js';
|
|
7
|
-
import { getAvailableSubroutines } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export interface LLMPromptGenerator {
|
|
10
|
-
generatePrompt(userInput: string): string;
|
|
11
|
-
intentToXML(intent: any): string | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create LLM adapter from session's registered subroutines
|
|
16
|
-
*/
|
|
17
|
-
export function createLLMAdapter(session: DiracSession): LLMPromptGenerator {
|
|
18
|
-
const subroutines = getAvailableSubroutines(session);
|
|
19
|
-
|
|
20
|
-
// Build JSON schema from subroutines
|
|
21
|
-
const actions = subroutines.map(s => `"${s.name}"`).join('|');
|
|
22
|
-
|
|
23
|
-
// Build examples
|
|
24
|
-
const examples = subroutines.slice(0, 3).map(sub => {
|
|
25
|
-
if (!sub.parameters || sub.parameters.length === 0) {
|
|
26
|
-
return `"${sub.name}" → {"action":"${sub.name}","params":{}}`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const firstParam = sub.parameters[0];
|
|
30
|
-
const exampleValue = firstParam.enum?.[0] || 'value';
|
|
31
|
-
return `"call ${sub.name}" → {"action":"${sub.name}","params":{"${firstParam.name}":"${exampleValue}"}}`;
|
|
32
|
-
}).join('\n');
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
generatePrompt(userInput: string): string {
|
|
36
|
-
return `You are a command parser. Convert user input to JSON.
|
|
37
|
-
Return ONLY valid JSON, no other text.
|
|
38
|
-
|
|
39
|
-
Format: {"action": ${actions}, "params": {}}
|
|
40
|
-
|
|
41
|
-
Examples:
|
|
42
|
-
${examples}
|
|
43
|
-
|
|
44
|
-
User: ${userInput}
|
|
45
|
-
JSON:`;
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
intentToXML(intent: any): string | null {
|
|
49
|
-
if (!intent || !intent.action) return null;
|
|
50
|
-
|
|
51
|
-
const sub = subroutines.find(s => s.name === intent.action);
|
|
52
|
-
if (!sub) return null;
|
|
53
|
-
|
|
54
|
-
const attrs: string[] = [`name="${sub.name}"`];
|
|
55
|
-
|
|
56
|
-
// Map params to XML attributes
|
|
57
|
-
if (sub.parameters) {
|
|
58
|
-
for (const param of sub.parameters) {
|
|
59
|
-
const value = intent.params?.[param.name];
|
|
60
|
-
|
|
61
|
-
if (value != null) {
|
|
62
|
-
// Validate enum if present
|
|
63
|
-
if (param.enum && !param.enum.includes(value)) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
attrs.push(`${param.name}="${value}"`);
|
|
67
|
-
} else if (param.required) {
|
|
68
|
-
return null; // Missing required parameter
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return `<call ${attrs.join(' ')}/>`;
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Higher-level helper: execute user command via LLM
|
|
80
|
-
*/
|
|
81
|
-
export async function executeUserCommand(
|
|
82
|
-
session: DiracSession,
|
|
83
|
-
userInput: string,
|
|
84
|
-
llmExecuteFn: (prompt: string) => Promise<string>
|
|
85
|
-
): Promise<{ success: boolean; xml?: string; error?: string }> {
|
|
86
|
-
try {
|
|
87
|
-
const adapter = createLLMAdapter(session);
|
|
88
|
-
const prompt = adapter.generatePrompt(userInput);
|
|
89
|
-
|
|
90
|
-
// Call LLM
|
|
91
|
-
const llmResponse = await llmExecuteFn(prompt);
|
|
92
|
-
|
|
93
|
-
// Parse JSON
|
|
94
|
-
let jsonStr = llmResponse.trim();
|
|
95
|
-
jsonStr = jsonStr.replace(/```json\s*/g, '').replace(/```\s*/g, '');
|
|
96
|
-
|
|
97
|
-
const intent = JSON.parse(jsonStr);
|
|
98
|
-
|
|
99
|
-
// Convert to XML
|
|
100
|
-
const xml = adapter.intentToXML(intent);
|
|
101
|
-
|
|
102
|
-
if (!xml) {
|
|
103
|
-
return { success: false, error: 'Could not convert intent to valid command' };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return { success: true, xml };
|
|
107
|
-
} catch (error) {
|
|
108
|
-
return {
|
|
109
|
-
success: false,
|
|
110
|
-
error: error instanceof Error ? error.message : String(error)
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
}
|