dirac-lang 0.1.24 → 0.1.26
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/cli.js +13 -1
- package/lib/index.di +9 -0
- package/{examples/lib → lib}/math.di +3 -3
- 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 -135
- 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}/mongodb.di +0 -0
package/src/tags/execute.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <execute> tag - Execute dynamically generated Dirac code
|
|
3
|
-
* Takes LLM-generated or variable content and interprets it as Dirac XML
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { getVariable, substituteVariables } from '../runtime/session.js';
|
|
8
|
-
import { DiracParser } from '../runtime/parser.js';
|
|
9
|
-
import { integrate } from '../runtime/interpreter.js';
|
|
10
|
-
|
|
11
|
-
export async function executeExecute(session: DiracSession, element: DiracElement): Promise<void> {
|
|
12
|
-
const sourceAttr = element.attributes.source;
|
|
13
|
-
|
|
14
|
-
// Get the Dirac code to execute
|
|
15
|
-
let diracCode: string;
|
|
16
|
-
|
|
17
|
-
if (sourceAttr) {
|
|
18
|
-
// Get from variable
|
|
19
|
-
diracCode = getVariable(session, sourceAttr);
|
|
20
|
-
if (!diracCode) {
|
|
21
|
-
throw new Error(`<execute> source variable '${sourceAttr}' not found`);
|
|
22
|
-
}
|
|
23
|
-
} else if (element.text) {
|
|
24
|
-
// Get from text content (with variable substitution)
|
|
25
|
-
diracCode = substituteVariables(session, element.text);
|
|
26
|
-
} else {
|
|
27
|
-
throw new Error('<execute> requires source attribute or text content');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (session.debug) {
|
|
31
|
-
console.error(`[EXECUTE] Interpreting dynamic code:\n${diracCode}\n`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Strip markdown code blocks if present
|
|
35
|
-
diracCode = diracCode.trim();
|
|
36
|
-
if (diracCode.startsWith('```')) {
|
|
37
|
-
// Remove markdown code fences
|
|
38
|
-
diracCode = diracCode.replace(/^```(?:xml|html)?\n?/m, '').replace(/\n?```$/m, '').trim();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
// Parse the dynamic Dirac code
|
|
43
|
-
const parser = new DiracParser();
|
|
44
|
-
const dynamicAST = parser.parse(diracCode);
|
|
45
|
-
|
|
46
|
-
// Execute the dynamically generated code
|
|
47
|
-
await integrate(session, dynamicAST);
|
|
48
|
-
|
|
49
|
-
} catch (error) {
|
|
50
|
-
throw new Error(`Execute error: ${error instanceof Error ? error.message : String(error)}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
package/src/tags/expr.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <expr> tag - arithmetic and logical operations
|
|
3
|
-
* Maps to mask_tag_expr in MASK
|
|
4
|
-
*
|
|
5
|
-
* Supports: plus, minus, times, divide, mod, lt, gt, eq, and, or, not
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
9
|
-
import { emit, substituteVariables } from '../runtime/session.js';
|
|
10
|
-
import { integrate } from '../runtime/interpreter.js';
|
|
11
|
-
|
|
12
|
-
export async function executeExpr(session: DiracSession, element: DiracElement): Promise<void> {
|
|
13
|
-
const op = element.attributes.eval || element.attributes.op;
|
|
14
|
-
|
|
15
|
-
if (!op) {
|
|
16
|
-
throw new Error('<expr> requires eval or op attribute');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Collect arguments from <arg> children
|
|
20
|
-
const args: number[] = [];
|
|
21
|
-
const stringArgs: string[] = [];
|
|
22
|
-
|
|
23
|
-
for (const child of element.children) {
|
|
24
|
-
if (child.tag === 'arg') {
|
|
25
|
-
let argValue = '';
|
|
26
|
-
|
|
27
|
-
// Check if arg has text content directly
|
|
28
|
-
if (child.text) {
|
|
29
|
-
argValue = substituteVariables(session, child.text);
|
|
30
|
-
} else {
|
|
31
|
-
// Capture output from arg children
|
|
32
|
-
const oldOutput = session.output;
|
|
33
|
-
session.output = [];
|
|
34
|
-
|
|
35
|
-
for (const argChild of child.children) {
|
|
36
|
-
await integrate(session, argChild);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
argValue = session.output.join('');
|
|
40
|
-
session.output = oldOutput;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
stringArgs.push(argValue);
|
|
44
|
-
const numValue = parseFloat(argValue);
|
|
45
|
-
args.push(isNaN(numValue) ? 0 : numValue);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let result: number | boolean = 0;
|
|
50
|
-
|
|
51
|
-
switch (op.toLowerCase()) {
|
|
52
|
-
case 'plus':
|
|
53
|
-
case 'add':
|
|
54
|
-
result = args.reduce((a, b) => a + b, 0);
|
|
55
|
-
break;
|
|
56
|
-
|
|
57
|
-
case 'minus':
|
|
58
|
-
case 'subtract':
|
|
59
|
-
result = args.length > 0 ? args[0] - args.slice(1).reduce((a, b) => a + b, 0) : 0;
|
|
60
|
-
break;
|
|
61
|
-
|
|
62
|
-
case 'times':
|
|
63
|
-
case 'multiply':
|
|
64
|
-
case 'mul':
|
|
65
|
-
result = args.reduce((a, b) => a * b, 1);
|
|
66
|
-
break;
|
|
67
|
-
|
|
68
|
-
case 'divide':
|
|
69
|
-
case 'div':
|
|
70
|
-
if (args.length >= 2 && args[1] !== 0) {
|
|
71
|
-
result = args[0] / args[1];
|
|
72
|
-
} else {
|
|
73
|
-
result = 0;
|
|
74
|
-
}
|
|
75
|
-
break;
|
|
76
|
-
|
|
77
|
-
case 'mod':
|
|
78
|
-
case 'modulo':
|
|
79
|
-
if (args.length >= 2 && args[1] !== 0) {
|
|
80
|
-
result = args[0] % args[1];
|
|
81
|
-
} else {
|
|
82
|
-
result = 0;
|
|
83
|
-
}
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case 'lt':
|
|
87
|
-
case 'less':
|
|
88
|
-
result = args.length >= 2 ? args[0] < args[1] : false;
|
|
89
|
-
break;
|
|
90
|
-
|
|
91
|
-
case 'gt':
|
|
92
|
-
case 'greater':
|
|
93
|
-
result = args.length >= 2 ? args[0] > args[1] : false;
|
|
94
|
-
break;
|
|
95
|
-
|
|
96
|
-
case 'eq':
|
|
97
|
-
case 'equal':
|
|
98
|
-
result = args.length >= 2 ? args[0] === args[1] : false;
|
|
99
|
-
break;
|
|
100
|
-
|
|
101
|
-
case 'and':
|
|
102
|
-
result = args.every(a => a !== 0);
|
|
103
|
-
break;
|
|
104
|
-
|
|
105
|
-
case 'or':
|
|
106
|
-
result = args.some(a => a !== 0);
|
|
107
|
-
break;
|
|
108
|
-
|
|
109
|
-
case 'not':
|
|
110
|
-
result = args.length > 0 ? args[0] === 0 : true;
|
|
111
|
-
break;
|
|
112
|
-
|
|
113
|
-
case 'same':
|
|
114
|
-
case 'strcmp':
|
|
115
|
-
result = stringArgs.length >= 2 ? stringArgs[0] === stringArgs[1] : false;
|
|
116
|
-
break;
|
|
117
|
-
|
|
118
|
-
default:
|
|
119
|
-
throw new Error(`<expr> unknown operation: ${op}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Emit result
|
|
123
|
-
if (typeof result === 'boolean') {
|
|
124
|
-
emit(session, result ? '1' : '0');
|
|
125
|
-
} else {
|
|
126
|
-
emit(session, String(result));
|
|
127
|
-
}
|
|
128
|
-
}
|
package/src/tags/foreach.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <foreach> tag - iterate over XML elements
|
|
3
|
-
* Usage: <foreach from="<available-subroutines />" as="sub">...</foreach>
|
|
4
|
-
* or: <foreach from="$varname" as="item">...</foreach>
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
8
|
-
import { setVariable, getVariable, substituteVariables } from '../runtime/session.js';
|
|
9
|
-
import { integrateChildren } from '../runtime/interpreter.js';
|
|
10
|
-
import { XMLParser } from 'fast-xml-parser';
|
|
11
|
-
|
|
12
|
-
export async function executeForeach(session: DiracSession, element: DiracElement): Promise<void> {
|
|
13
|
-
const fromAttr = element.attributes.from;
|
|
14
|
-
const asVar = element.attributes.as || 'item';
|
|
15
|
-
const xpath = element.attributes.xpath; // Optional: filter like "//subroutine"
|
|
16
|
-
|
|
17
|
-
if (!fromAttr) {
|
|
18
|
-
throw new Error('<foreach> requires "from" attribute');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Get the XML content (either from variable or inline content)
|
|
22
|
-
let xmlContent: string;
|
|
23
|
-
|
|
24
|
-
if (fromAttr.startsWith('$')) {
|
|
25
|
-
// Get from variable
|
|
26
|
-
const varName = fromAttr.substring(1);
|
|
27
|
-
xmlContent = getVariable(session, varName) || '';
|
|
28
|
-
} else if (fromAttr.startsWith('<')) {
|
|
29
|
-
// Evaluate the "from" attribute as inline XML (e.g., <available-subroutines />)
|
|
30
|
-
const savedOutput = session.output;
|
|
31
|
-
session.output = [];
|
|
32
|
-
|
|
33
|
-
// Parse and execute the from content
|
|
34
|
-
const { DiracParser } = await import('../runtime/parser.js');
|
|
35
|
-
const parser = new DiracParser();
|
|
36
|
-
try {
|
|
37
|
-
const fromElement = parser.parse(fromAttr);
|
|
38
|
-
const { integrate } = await import('../runtime/interpreter.js');
|
|
39
|
-
await integrate(session, fromElement);
|
|
40
|
-
} catch (e) {
|
|
41
|
-
session.output = savedOutput;
|
|
42
|
-
throw new Error(`Failed to evaluate from="${fromAttr}": ${e}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
xmlContent = session.output.join('');
|
|
46
|
-
session.output = savedOutput;
|
|
47
|
-
} else {
|
|
48
|
-
// Treat as literal XML string
|
|
49
|
-
xmlContent = substituteVariables(session, fromAttr);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!xmlContent || xmlContent.trim() === '') {
|
|
53
|
-
return; // Nothing to iterate over
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Parse the XML content
|
|
57
|
-
const parser = new XMLParser({
|
|
58
|
-
ignoreAttributes: false,
|
|
59
|
-
attributeNamePrefix: '@_',
|
|
60
|
-
parseAttributeValue: false,
|
|
61
|
-
preserveOrder: true,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
let parsed;
|
|
65
|
-
try {
|
|
66
|
-
parsed = parser.parse(`<root>${xmlContent}</root>`);
|
|
67
|
-
} catch (e) {
|
|
68
|
-
throw new Error(`Failed to parse XML in <foreach>: ${e}`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Extract elements to iterate over
|
|
72
|
-
const items = extractElements(parsed, xpath);
|
|
73
|
-
|
|
74
|
-
// Iterate over each item
|
|
75
|
-
for (const item of items) {
|
|
76
|
-
// Store the item as a variable (as an object with tag, attributes, text)
|
|
77
|
-
setVariable(session, asVar, item, false);
|
|
78
|
-
|
|
79
|
-
// Execute the loop body
|
|
80
|
-
await integrateChildren(session, element);
|
|
81
|
-
|
|
82
|
-
if (session.isBreak) {
|
|
83
|
-
session.isBreak = false;
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (session.isReturn) {
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
interface XmlItem {
|
|
94
|
-
tag: string;
|
|
95
|
-
attributes: Record<string, string>;
|
|
96
|
-
text?: string;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function extractElements(parsed: any, xpath?: string): XmlItem[] {
|
|
100
|
-
const items: XmlItem[] = [];
|
|
101
|
-
|
|
102
|
-
// parsed is array with preserveOrder
|
|
103
|
-
if (!Array.isArray(parsed)) {
|
|
104
|
-
return items;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Recursively extract all elements matching xpath
|
|
108
|
-
const extractFromNode = (node: any) => {
|
|
109
|
-
if (!node) return;
|
|
110
|
-
|
|
111
|
-
const tagName = Object.keys(node).find(k => k !== ':@' && k !== '#text' && k !== '#comment');
|
|
112
|
-
if (!tagName) return;
|
|
113
|
-
|
|
114
|
-
const item: XmlItem = {
|
|
115
|
-
tag: tagName,
|
|
116
|
-
attributes: {},
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// Extract attributes
|
|
120
|
-
if (node[':@']) {
|
|
121
|
-
for (const [key, value] of Object.entries(node[':@'])) {
|
|
122
|
-
if (key.startsWith('@_')) {
|
|
123
|
-
item.attributes[key.slice(2)] = value as string;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Extract text content and recurse into children
|
|
129
|
-
const children = node[tagName];
|
|
130
|
-
if (Array.isArray(children)) {
|
|
131
|
-
for (const child of children) {
|
|
132
|
-
if (child['#text']) {
|
|
133
|
-
item.text = (item.text || '') + child['#text'];
|
|
134
|
-
} else {
|
|
135
|
-
// Recurse into child elements
|
|
136
|
-
extractFromNode(child);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Add this item if it matches xpath
|
|
142
|
-
if (!xpath || matchesXPath(item, xpath)) {
|
|
143
|
-
items.push(item);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// Start extraction from root
|
|
148
|
-
for (const rootItem of parsed) {
|
|
149
|
-
if (rootItem['root']) {
|
|
150
|
-
const rootChildren = rootItem['root'];
|
|
151
|
-
if (Array.isArray(rootChildren)) {
|
|
152
|
-
for (const child of rootChildren) {
|
|
153
|
-
extractFromNode(child);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return items;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function matchesXPath(item: XmlItem, xpath: string): boolean {
|
|
163
|
-
// Simple xpath matching - just tag name for now
|
|
164
|
-
// Supports: "//tagname" or "tagname"
|
|
165
|
-
const tagMatch = xpath.match(/\/{0,2}(\w+)/);
|
|
166
|
-
if (tagMatch) {
|
|
167
|
-
return item.tag === tagMatch[1];
|
|
168
|
-
}
|
|
169
|
-
return true;
|
|
170
|
-
}
|
package/src/tags/if.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <if> tag - conditional execution with <cond>, <then>, <else> children
|
|
3
|
-
* Maps to mask_if_integrate in MASK C implementation
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* <if>
|
|
7
|
-
* <cond>condition expression or <cond> tag</cond>
|
|
8
|
-
* <then>executed if true</then>
|
|
9
|
-
* <else>executed if false</else>
|
|
10
|
-
* </if>
|
|
11
|
-
*
|
|
12
|
-
* The first child can be:
|
|
13
|
-
* - A <cond> tag with condition logic
|
|
14
|
-
* - Any other element that evaluates to a value
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
18
|
-
import { getOutput } from '../runtime/session.js';
|
|
19
|
-
|
|
20
|
-
export async function executeIf(session: DiracSession, element: DiracElement): Promise<void> {
|
|
21
|
-
// Extract condition, then, and else elements from children
|
|
22
|
-
let conditionElement: DiracElement | null = null;
|
|
23
|
-
let thenElement: DiracElement | null = null;
|
|
24
|
-
let elseElement: DiracElement | null = null;
|
|
25
|
-
|
|
26
|
-
for (const child of element.children) {
|
|
27
|
-
const tag = child.tag.toLowerCase();
|
|
28
|
-
if (tag === 'cond') {
|
|
29
|
-
conditionElement = child;
|
|
30
|
-
} else if (tag === 'then' || tag === 'do') {
|
|
31
|
-
thenElement = child;
|
|
32
|
-
} else if (tag === 'else') {
|
|
33
|
-
elseElement = child;
|
|
34
|
-
} else if (!conditionElement && child.tag) {
|
|
35
|
-
// First non-cond/then/else element is treated as condition
|
|
36
|
-
conditionElement = child;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Evaluate the condition
|
|
41
|
-
const condition = await evaluatePredicate(session, conditionElement);
|
|
42
|
-
|
|
43
|
-
// Execute then or else block based on condition
|
|
44
|
-
if (condition) {
|
|
45
|
-
if (thenElement) {
|
|
46
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
47
|
-
await integrateChildren(session, thenElement);
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
if (elseElement) {
|
|
51
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
52
|
-
await integrateChildren(session, elseElement);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Evaluate a predicate element to determine if it's true or false
|
|
59
|
-
* Maps to mask_predicate_integrate in MASK
|
|
60
|
-
*/
|
|
61
|
-
async function evaluatePredicate(session: DiracSession, predicateElement: DiracElement | null): Promise<boolean> {
|
|
62
|
-
if (!predicateElement) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// If it's a <cond> tag, process it with condition evaluation
|
|
67
|
-
if (predicateElement.tag.toLowerCase() === 'cond') {
|
|
68
|
-
return await evaluateCondition(session, predicateElement);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Otherwise, execute the element and evaluate its output
|
|
72
|
-
const outputLengthBefore = session.output.length;
|
|
73
|
-
const { integrate } = await import('../runtime/interpreter.js');
|
|
74
|
-
await integrate(session, predicateElement);
|
|
75
|
-
|
|
76
|
-
// Get the new output chunks added during evaluation
|
|
77
|
-
const newOutputChunks = session.output.slice(outputLengthBefore);
|
|
78
|
-
const result = newOutputChunks.join('').trim();
|
|
79
|
-
|
|
80
|
-
// Restore output to state before evaluation (remove intermediate output)
|
|
81
|
-
session.output.length = outputLengthBefore;
|
|
82
|
-
|
|
83
|
-
// Evaluate the result as a boolean
|
|
84
|
-
if (result === '') {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
if (result === '0' || result === 'false') {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
if (result === '1' || result === 'true') {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
// Non-empty string is truthy
|
|
94
|
-
return result.length > 0;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Evaluate a <cond> element with eval attribute and arguments
|
|
99
|
-
* Maps to mask_condition_integrate in MASK
|
|
100
|
-
*/
|
|
101
|
-
async function evaluateCondition(session: DiracSession, condElement: DiracElement): Promise<boolean> {
|
|
102
|
-
const evalType = condElement.attributes?.eval;
|
|
103
|
-
|
|
104
|
-
if (!evalType) {
|
|
105
|
-
// No eval attribute, just evaluate children as predicate
|
|
106
|
-
return await evaluatePredicate(session, condElement);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Capture the current output level before evaluating args
|
|
110
|
-
const outputLengthBefore = session.output.length;
|
|
111
|
-
|
|
112
|
-
// Get arguments from children
|
|
113
|
-
const args: string[] = [];
|
|
114
|
-
const { integrate } = await import('../runtime/interpreter.js');
|
|
115
|
-
|
|
116
|
-
for (const child of condElement.children) {
|
|
117
|
-
if (child.tag.toLowerCase() === 'arg') {
|
|
118
|
-
const argOutputStart = session.output.length;
|
|
119
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
120
|
-
await integrateChildren(session, child);
|
|
121
|
-
const newChunks = session.output.slice(argOutputStart);
|
|
122
|
-
const argValue = newChunks.join('');
|
|
123
|
-
args.push(argValue);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Restore output to state before evaluation (remove arg outputs)
|
|
128
|
-
session.output.length = outputLengthBefore;
|
|
129
|
-
|
|
130
|
-
// Evaluate based on eval type
|
|
131
|
-
return evaluateConditionType(evalType, args);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Evaluate condition based on type and arguments
|
|
136
|
-
*/
|
|
137
|
-
function evaluateConditionType(evalType: string, args: string[]): boolean {
|
|
138
|
-
const type = evalType.toLowerCase();
|
|
139
|
-
|
|
140
|
-
switch (type) {
|
|
141
|
-
case 'eq':
|
|
142
|
-
case 'equal':
|
|
143
|
-
case 'same':
|
|
144
|
-
return args.length >= 2 && args[0] === args[1];
|
|
145
|
-
|
|
146
|
-
case 'ne':
|
|
147
|
-
case 'notequal':
|
|
148
|
-
case 'different':
|
|
149
|
-
return args.length >= 2 && args[0] !== args[1];
|
|
150
|
-
|
|
151
|
-
case 'lt':
|
|
152
|
-
case 'less':
|
|
153
|
-
if (args.length >= 2) {
|
|
154
|
-
const a = parseFloat(args[0]);
|
|
155
|
-
const b = parseFloat(args[1]);
|
|
156
|
-
return !isNaN(a) && !isNaN(b) && a < b;
|
|
157
|
-
}
|
|
158
|
-
return false;
|
|
159
|
-
|
|
160
|
-
case 'le':
|
|
161
|
-
case 'lessequal':
|
|
162
|
-
if (args.length >= 2) {
|
|
163
|
-
const a = parseFloat(args[0]);
|
|
164
|
-
const b = parseFloat(args[1]);
|
|
165
|
-
return !isNaN(a) && !isNaN(b) && a <= b;
|
|
166
|
-
}
|
|
167
|
-
return false;
|
|
168
|
-
|
|
169
|
-
case 'gt':
|
|
170
|
-
case 'greater':
|
|
171
|
-
if (args.length >= 2) {
|
|
172
|
-
const a = parseFloat(args[0]);
|
|
173
|
-
const b = parseFloat(args[1]);
|
|
174
|
-
return !isNaN(a) && !isNaN(b) && a > b;
|
|
175
|
-
}
|
|
176
|
-
return false;
|
|
177
|
-
|
|
178
|
-
case 'ge':
|
|
179
|
-
case 'greaterequal':
|
|
180
|
-
if (args.length >= 2) {
|
|
181
|
-
const a = parseFloat(args[0]);
|
|
182
|
-
const b = parseFloat(args[1]);
|
|
183
|
-
return !isNaN(a) && !isNaN(b) && a >= b;
|
|
184
|
-
}
|
|
185
|
-
return false;
|
|
186
|
-
|
|
187
|
-
default:
|
|
188
|
-
// Unknown eval type, return false
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
}
|
package/src/tags/import.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <import> tag - Import subroutines from other Dirac files
|
|
3
|
-
* Similar to Node.js require/import
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { readFileSync, existsSync } from 'fs';
|
|
8
|
-
import { resolve, dirname, join } from 'path';
|
|
9
|
-
import { DiracParser } from '../runtime/parser.js';
|
|
10
|
-
import { integrate } from '../runtime/interpreter.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Resolve import path - supports relative paths and node_modules packages
|
|
14
|
-
* @param src - The import source (e.g., "./file.di" or "package-name")
|
|
15
|
-
* @param currentDir - Current directory context
|
|
16
|
-
* @returns Resolved absolute path
|
|
17
|
-
*/
|
|
18
|
-
function resolveImportPath(src: string, currentDir: string): string {
|
|
19
|
-
// If it starts with ./ or ../ or /, it's a relative/absolute path
|
|
20
|
-
if (src.startsWith('./') || src.startsWith('../') || src.startsWith('/')) {
|
|
21
|
-
const resolved = resolve(currentDir, src);
|
|
22
|
-
// Add .di extension if not present
|
|
23
|
-
return resolved.endsWith('.di') ? resolved : resolved + '.di';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Otherwise, try to resolve as a package from node_modules
|
|
27
|
-
// Walk up the directory tree looking for node_modules
|
|
28
|
-
let searchDir = currentDir;
|
|
29
|
-
|
|
30
|
-
while (true) {
|
|
31
|
-
const nodeModulesPath = join(searchDir, 'node_modules', src);
|
|
32
|
-
|
|
33
|
-
if (existsSync(nodeModulesPath)) {
|
|
34
|
-
// Found the package, now find the entry point
|
|
35
|
-
// Try to read package.json to get the "main" field
|
|
36
|
-
const packageJsonPath = join(nodeModulesPath, 'package.json');
|
|
37
|
-
|
|
38
|
-
if (existsSync(packageJsonPath)) {
|
|
39
|
-
try {
|
|
40
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
41
|
-
const mainFile = packageJson.main || 'lib/index.di';
|
|
42
|
-
const entryPath = join(nodeModulesPath, mainFile);
|
|
43
|
-
|
|
44
|
-
if (existsSync(entryPath)) {
|
|
45
|
-
return entryPath;
|
|
46
|
-
}
|
|
47
|
-
} catch (err) {
|
|
48
|
-
// If package.json parse fails, fall through to default
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Fallback: try common entry points
|
|
53
|
-
const fallbacks = [
|
|
54
|
-
join(nodeModulesPath, 'lib', 'index.di'),
|
|
55
|
-
join(nodeModulesPath, 'index.di'),
|
|
56
|
-
];
|
|
57
|
-
|
|
58
|
-
for (const fallback of fallbacks) {
|
|
59
|
-
if (existsSync(fallback)) {
|
|
60
|
-
return fallback;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
throw new Error(`Package "${src}" found but no entry point (.di file) available`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Move up one directory
|
|
68
|
-
const parentDir = dirname(searchDir);
|
|
69
|
-
if (parentDir === searchDir) {
|
|
70
|
-
// Reached root, package not found
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
searchDir = parentDir;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Package not found in node_modules, treat as relative path with .di extension
|
|
77
|
-
const resolved = resolve(currentDir, src);
|
|
78
|
-
return resolved.endsWith('.di') ? resolved : resolved + '.di';
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export async function executeImport(session: DiracSession, element: DiracElement): Promise<void> {
|
|
82
|
-
const src = element.attributes.src;
|
|
83
|
-
|
|
84
|
-
if (!src) {
|
|
85
|
-
throw new Error('<import> requires src attribute');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Get the current file's directory (if available in session)
|
|
89
|
-
const currentDir = session.currentFile ? dirname(session.currentFile) : process.cwd();
|
|
90
|
-
|
|
91
|
-
// Resolve the import path (handles both relative paths and node_modules packages)
|
|
92
|
-
const importPath = resolveImportPath(src, currentDir);
|
|
93
|
-
|
|
94
|
-
if (session.debug) {
|
|
95
|
-
console.error(`[IMPORT] Loading: ${importPath}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Check if already imported (prevent circular imports)
|
|
99
|
-
if (!session.importedFiles) {
|
|
100
|
-
session.importedFiles = new Set();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (session.importedFiles.has(importPath)) {
|
|
104
|
-
if (session.debug) {
|
|
105
|
-
console.error(`[IMPORT] Already imported: ${importPath}`);
|
|
106
|
-
}
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
session.importedFiles.add(importPath);
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
// Read and parse the imported file
|
|
114
|
-
const source = readFileSync(importPath, 'utf-8');
|
|
115
|
-
const parser = new DiracParser();
|
|
116
|
-
const ast = parser.parse(source);
|
|
117
|
-
|
|
118
|
-
// Save current file context and set new one
|
|
119
|
-
const previousFile = session.currentFile;
|
|
120
|
-
session.currentFile = importPath;
|
|
121
|
-
|
|
122
|
-
// Execute the imported file (this will register its subroutines)
|
|
123
|
-
await integrate(session, ast);
|
|
124
|
-
|
|
125
|
-
// Restore previous file context
|
|
126
|
-
session.currentFile = previousFile;
|
|
127
|
-
|
|
128
|
-
if (session.debug) {
|
|
129
|
-
console.error(`[IMPORT] Loaded: ${importPath}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
} catch (error) {
|
|
133
|
-
throw new Error(`Import error: ${error instanceof Error ? error.message : String(error)}`);
|
|
134
|
-
}
|
|
135
|
-
}
|