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/assign.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <assign> tag - assign value to existing variable
|
|
3
|
-
* Maps to mask_tag_assign in MASK
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { getVariable, setVariable, substituteVariables } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export function executeAssign(session: DiracSession, element: DiracElement): void {
|
|
10
|
-
const name = element.attributes.name;
|
|
11
|
-
const valueAttr = element.attributes.value;
|
|
12
|
-
|
|
13
|
-
if (!name) {
|
|
14
|
-
throw new Error('<assign> requires name attribute');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Get value
|
|
18
|
-
let value: any;
|
|
19
|
-
if (valueAttr !== undefined) {
|
|
20
|
-
value = substituteVariables(session, valueAttr);
|
|
21
|
-
} else if (element.text) {
|
|
22
|
-
value = substituteVariables(session, element.text);
|
|
23
|
-
} else {
|
|
24
|
-
value = '';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Find existing variable and update it
|
|
28
|
-
for (let i = session.variables.length - 1; i >= 0; i--) {
|
|
29
|
-
if (session.variables[i].name === name) {
|
|
30
|
-
session.variables[i].value = value;
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Variable not found - create it (same as MASK behavior)
|
|
36
|
-
setVariable(session, name, value, false);
|
|
37
|
-
}
|
package/src/tags/attr.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <attr> tag - extract attribute value from XML item
|
|
3
|
-
* Usage: <attr name="description" from="$sub" />
|
|
4
|
-
* or: <attr name="param-format" from="$sub" />
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
8
|
-
import { getVariable, substituteVariables } from '../runtime/session.js';
|
|
9
|
-
|
|
10
|
-
export async function executeAttr(session: DiracSession, element: DiracElement): Promise<void> {
|
|
11
|
-
const nameAttr = element.attributes.name;
|
|
12
|
-
const fromAttr = element.attributes.from;
|
|
13
|
-
|
|
14
|
-
if (!nameAttr) {
|
|
15
|
-
throw new Error('<attr> requires "name" attribute');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (!fromAttr) {
|
|
19
|
-
throw new Error('<attr> requires "from" attribute');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Get the XML item from variable
|
|
23
|
-
let item: any;
|
|
24
|
-
|
|
25
|
-
if (fromAttr.startsWith('$')) {
|
|
26
|
-
const varName = fromAttr.substring(1);
|
|
27
|
-
item = getVariable(session, varName);
|
|
28
|
-
} else {
|
|
29
|
-
// Try substitution
|
|
30
|
-
const substituted = substituteVariables(session, fromAttr);
|
|
31
|
-
item = getVariable(session, substituted);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!item) {
|
|
35
|
-
// No output if item not found
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Extract the attribute value
|
|
40
|
-
let value = '';
|
|
41
|
-
|
|
42
|
-
if (typeof item === 'object') {
|
|
43
|
-
// If it's a structured XML item (from foreach)
|
|
44
|
-
if (item.attributes && typeof item.attributes === 'object') {
|
|
45
|
-
value = item.attributes[nameAttr] || '';
|
|
46
|
-
}
|
|
47
|
-
// If it's a direct object with the attribute
|
|
48
|
-
else if (item[nameAttr] !== undefined) {
|
|
49
|
-
value = String(item[nameAttr]);
|
|
50
|
-
}
|
|
51
|
-
} else if (typeof item === 'string') {
|
|
52
|
-
// If it's a string, try to parse as XML and extract
|
|
53
|
-
value = extractAttrFromXml(item, nameAttr);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
session.output.push(value);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function extractAttrFromXml(xml: string, attrName: string): string {
|
|
60
|
-
// Simple regex-based extraction for single-element XML
|
|
61
|
-
const regex = new RegExp(`${attrName}="([^"]*)"`, 'i');
|
|
62
|
-
const match = xml.match(regex);
|
|
63
|
-
return match ? match[1] : '';
|
|
64
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <available-subroutines> tag - list available nested subroutines
|
|
3
|
-
* Returns all subroutines within current call boundary with their metadata
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
|
|
8
|
-
export async function executeAvailableSubroutines(
|
|
9
|
-
session: DiracSession,
|
|
10
|
-
element: DiracElement
|
|
11
|
-
): Promise<void> {
|
|
12
|
-
// Get all subroutines from current boundary to top of stack
|
|
13
|
-
const availableSubroutines = new Map<string, DiracElement>();
|
|
14
|
-
|
|
15
|
-
// Get the name of the currently executing subroutine from the boundary
|
|
16
|
-
const currentSubroutineName = session.subBoundary < session.subroutines.length
|
|
17
|
-
? session.subroutines[session.subBoundary].name
|
|
18
|
-
: null;
|
|
19
|
-
|
|
20
|
-
// Read from top of stack (most recent) backwards to boundary
|
|
21
|
-
// This ensures we get the latest definition (handles extends override)
|
|
22
|
-
for (let i = session.subroutines.length - 1; i >= session.subBoundary; i--) {
|
|
23
|
-
const sub = session.subroutines[i];
|
|
24
|
-
|
|
25
|
-
// Skip the currently executing subroutine itself
|
|
26
|
-
if (sub.name === currentSubroutineName) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Only add if not already seen (first occurrence wins)
|
|
31
|
-
if (!availableSubroutines.has(sub.name)) {
|
|
32
|
-
availableSubroutines.set(sub.name, sub.element);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Generate structured output with container
|
|
37
|
-
session.output.push('<subroutines>');
|
|
38
|
-
|
|
39
|
-
for (const [name, subElement] of availableSubroutines) {
|
|
40
|
-
const attrs: string[] = [`name="${escapeXml(name)}"`];
|
|
41
|
-
|
|
42
|
-
// Add description if available
|
|
43
|
-
const description = subElement.attributes.description;
|
|
44
|
-
if (description) {
|
|
45
|
-
attrs.push(`description="${escapeXml(description)}"`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Add all param-* attributes with their definitions
|
|
49
|
-
for (const [attrName, attrValue] of Object.entries(subElement.attributes)) {
|
|
50
|
-
if (attrName.startsWith('param-')) {
|
|
51
|
-
attrs.push(`${attrName}="${escapeXml(attrValue)}"`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Build the output tag
|
|
56
|
-
const attrString = attrs.join(' ');
|
|
57
|
-
session.output.push(` <subroutine ${attrString} />`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
session.output.push('</subroutines>');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function escapeXml(text: string): string {
|
|
64
|
-
return text
|
|
65
|
-
.replace(/&/g, '&')
|
|
66
|
-
.replace(/</g, '<')
|
|
67
|
-
.replace(/>/g, '>')
|
|
68
|
-
.replace(/"/g, '"')
|
|
69
|
-
.replace(/'/g, ''');
|
|
70
|
-
}
|
package/src/tags/call.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
// Utility: Substitute both $var and ${var} in a string using session variables
|
|
2
|
-
import { substituteAttribute } from '../runtime/session.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* <call> tag - invoke subroutine
|
|
6
|
-
* Maps to mask_call_integrate in MASK
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
10
|
-
import {
|
|
11
|
-
getSubroutine,
|
|
12
|
-
getParentSubroutine,
|
|
13
|
-
setBoundary,
|
|
14
|
-
popToBoundary,
|
|
15
|
-
cleanToBoundary,
|
|
16
|
-
pushParameters,
|
|
17
|
-
popParameters,
|
|
18
|
-
substituteVariables,
|
|
19
|
-
setVariable,
|
|
20
|
-
getVariable,
|
|
21
|
-
} from '../runtime/session.js';
|
|
22
|
-
import { integrateChildren } from '../runtime/interpreter.js';
|
|
23
|
-
|
|
24
|
-
export async function executeCall(session: DiracSession, element: DiracElement): Promise<void> {
|
|
25
|
-
// Support both <call name="FOO" /> and direct <FOO /> syntax
|
|
26
|
-
// For <call> tag, use name/subroutine attribute
|
|
27
|
-
// For direct syntax, use element.tag
|
|
28
|
-
let name: string;
|
|
29
|
-
|
|
30
|
-
if (element.tag === 'call') {
|
|
31
|
-
// Explicit <call> tag - use name or subroutine attribute
|
|
32
|
-
name = element.attributes.name || element.attributes.subroutine || '';
|
|
33
|
-
} else {
|
|
34
|
-
// Direct tag syntax - use tag name itself, ignore name attribute
|
|
35
|
-
name = element.tag;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!name) {
|
|
39
|
-
throw new Error('<call> requires name or subroutine attribute');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const subroutine = getSubroutine(session, name);
|
|
43
|
-
if (!subroutine) {
|
|
44
|
-
throw new Error(`Subroutine '${name}' not found`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Handle extension (parent subroutine) using recursive descent
|
|
48
|
-
const extendAttr = subroutine.attributes.extend;
|
|
49
|
-
const extendsAttr = subroutine.attributes.extends;
|
|
50
|
-
|
|
51
|
-
if (extendAttr !== undefined || extendsAttr !== undefined) {
|
|
52
|
-
// This subroutine extends another - use recursive descent to build stack
|
|
53
|
-
const baseSubroutine = await registerExtendChain(session, subroutine, name);
|
|
54
|
-
// Execute the ultimate base subroutine with extend flag set
|
|
55
|
-
await executeCallInternal(session, baseSubroutine, element, true);
|
|
56
|
-
} else {
|
|
57
|
-
// No extension - normal subroutine call
|
|
58
|
-
await executeCallInternal(session, subroutine, element, false);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Recursive descent for extend mechanism:
|
|
64
|
-
* 1. Recursively descend to ultimate parent (no extend)
|
|
65
|
-
* 2. Register base's nested subroutines
|
|
66
|
-
* 3. As recursion unwinds, register each level's subroutines (latest on top of stack)
|
|
67
|
-
* 4. Return the ultimate base to be executed
|
|
68
|
-
*/
|
|
69
|
-
async function registerExtendChain(
|
|
70
|
-
session: DiracSession,
|
|
71
|
-
subroutine: DiracElement,
|
|
72
|
-
currentName: string
|
|
73
|
-
): Promise<DiracElement> {
|
|
74
|
-
const { executeSubroutine } = await import('./subroutine.js');
|
|
75
|
-
|
|
76
|
-
// Determine parent name
|
|
77
|
-
const extendsAttr = subroutine.attributes.extends;
|
|
78
|
-
let parentName: string;
|
|
79
|
-
|
|
80
|
-
if (extendsAttr) {
|
|
81
|
-
// extends="parentName" - use explicit parent name
|
|
82
|
-
parentName = extendsAttr;
|
|
83
|
-
} else {
|
|
84
|
-
// extend (no value) - use same name, search for earlier definition
|
|
85
|
-
parentName = currentName;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Get parent, passing current subroutine if using same name
|
|
89
|
-
const parent = getParentSubroutine(session, parentName, parentName === currentName ? subroutine : undefined);
|
|
90
|
-
|
|
91
|
-
if (!parent) {
|
|
92
|
-
// No parent found - shouldn't happen, but handle gracefully
|
|
93
|
-
return subroutine;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Check if parent also extends
|
|
97
|
-
const parentExtendAttr = parent.attributes.extend;
|
|
98
|
-
const parentExtendsAttr = parent.attributes.extends;
|
|
99
|
-
|
|
100
|
-
let baseSubroutine: DiracElement;
|
|
101
|
-
|
|
102
|
-
if (parentExtendAttr !== undefined || parentExtendsAttr !== undefined) {
|
|
103
|
-
// Parent extends - recursively process parent first
|
|
104
|
-
baseSubroutine = await registerExtendChain(session, parent, parentName);
|
|
105
|
-
} else {
|
|
106
|
-
// Parent doesn't extend - this is the ultimate base
|
|
107
|
-
// Register base's nested subroutines (bottom of stack)
|
|
108
|
-
for (const child of parent.children) {
|
|
109
|
-
if (child.tag === 'subroutine') {
|
|
110
|
-
executeSubroutine(session, child);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
baseSubroutine = parent;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// After parent chain is processed, register current level's nested subroutines
|
|
117
|
-
// These go on top and override parent's definitions
|
|
118
|
-
for (const child of subroutine.children) {
|
|
119
|
-
if (child.tag === 'subroutine') {
|
|
120
|
-
executeSubroutine(session, child);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return baseSubroutine;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async function executeCallInternal(
|
|
128
|
-
session: DiracSession,
|
|
129
|
-
subroutine: DiracElement,
|
|
130
|
-
callElement: DiracElement,
|
|
131
|
-
isExtendExecution: boolean = false
|
|
132
|
-
): Promise<void> {
|
|
133
|
-
// Set boundary for local scope
|
|
134
|
-
const oldBoundary = setBoundary(session);
|
|
135
|
-
const wasReturn = session.isReturn;
|
|
136
|
-
session.isReturn = false;
|
|
137
|
-
|
|
138
|
-
// Track current subroutine name for available-subroutines
|
|
139
|
-
const oldSubroutineName = session.currentSubroutineName;
|
|
140
|
-
session.currentSubroutineName = callElement.tag;
|
|
141
|
-
|
|
142
|
-
// For extend execution, skip subroutine registration during body execution
|
|
143
|
-
const oldSkipFlag = session.skipSubroutineRegistration;
|
|
144
|
-
if (isExtendExecution) {
|
|
145
|
-
session.skipSubroutineRegistration = true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Substitute variables in call element attributes before pushing to parameter stack
|
|
149
|
-
const substitutedElement: DiracElement = {
|
|
150
|
-
tag: callElement.tag,
|
|
151
|
-
attributes: {},
|
|
152
|
-
children: callElement.children
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
// Utility: Substitute both $var and ${var} in a string using session variables
|
|
156
|
-
for (const [key, value] of Object.entries(callElement.attributes)) {
|
|
157
|
-
substitutedElement.attributes[key] = substituteAttribute(session, value);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Push caller element onto parameter stack for <parameters select="*|@*|@attr"/> access
|
|
161
|
-
pushParameters(session, [substitutedElement]);
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
// 1. Set variables from <param-*> attributes if not already set in this boundary
|
|
165
|
-
for (const [attrName, attrValue] of Object.entries(subroutine.attributes)) {
|
|
166
|
-
if (attrName.startsWith('param-')) {
|
|
167
|
-
const paramName = attrName.substring(6);
|
|
168
|
-
// Check if variable exists in current boundary
|
|
169
|
-
const alreadySet = session.variables.slice(session.varBoundary).some(v => v.name === paramName);
|
|
170
|
-
if (!alreadySet) {
|
|
171
|
-
// Priority: call attribute > param-* default > empty string
|
|
172
|
-
let value = '';
|
|
173
|
-
if (callElement.attributes && callElement.attributes[paramName] !== undefined) {
|
|
174
|
-
value = substituteAttribute(session, callElement.attributes[paramName]);
|
|
175
|
-
} else {
|
|
176
|
-
// Always treat last colon-separated part as default value (if >3 fields)
|
|
177
|
-
const parts = attrValue.split(':');
|
|
178
|
-
if (parts.length > 3) {
|
|
179
|
-
value = parts[parts.length - 1];
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
setVariable(session, paramName, value, false);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// 2. Bind parameters from <parameters> if present
|
|
188
|
-
const paramElements = callElement.children.filter(c => c.tag === 'parameters');
|
|
189
|
-
if (paramElements.length > 0) {
|
|
190
|
-
await bindParameters(session, subroutine, paramElements[0]);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 3. Execute subroutine body
|
|
194
|
-
await integrateChildren(session, subroutine);
|
|
195
|
-
|
|
196
|
-
} finally {
|
|
197
|
-
// Restore skip flag
|
|
198
|
-
session.skipSubroutineRegistration = oldSkipFlag;
|
|
199
|
-
|
|
200
|
-
// Pop parameter stack
|
|
201
|
-
popParameters(session);
|
|
202
|
-
|
|
203
|
-
// Clean up scope (keep visible variables) BEFORE restoring boundary
|
|
204
|
-
cleanToBoundary(session);
|
|
205
|
-
session.varBoundary = oldBoundary;
|
|
206
|
-
session.isReturn = wasReturn;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async function bindParameters(
|
|
211
|
-
session: DiracSession,
|
|
212
|
-
subroutine: DiracElement,
|
|
213
|
-
callParams: DiracElement
|
|
214
|
-
): Promise<void> {
|
|
215
|
-
// Find <parameters> definition in subroutine
|
|
216
|
-
const paramDef = subroutine.children.find(c => c.tag === 'parameters');
|
|
217
|
-
if (!paramDef) {
|
|
218
|
-
return; // No parameters defined
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Get variable definitions from parameter declaration
|
|
222
|
-
const paramVars = paramDef.children.filter(c => c.tag === 'variable');
|
|
223
|
-
const callVars = callParams.children.filter(c => c.tag === 'variable');
|
|
224
|
-
|
|
225
|
-
// Bind each parameter
|
|
226
|
-
for (let i = 0; i < paramVars.length; i++) {
|
|
227
|
-
const paramVar = paramVars[i];
|
|
228
|
-
const callVar = callVars[i];
|
|
229
|
-
|
|
230
|
-
const paramName = paramVar.attributes.name;
|
|
231
|
-
const passby = paramVar.attributes.passby || 'value';
|
|
232
|
-
|
|
233
|
-
if (!paramName) continue;
|
|
234
|
-
|
|
235
|
-
let value: any;
|
|
236
|
-
|
|
237
|
-
if (callVar) {
|
|
238
|
-
// Get value from call site
|
|
239
|
-
const callValue = callVar.attributes.value;
|
|
240
|
-
if (callValue) {
|
|
241
|
-
if (passby === 'ref') {
|
|
242
|
-
// Pass by reference - store variable name
|
|
243
|
-
setVariable(session, paramName, getVariable(session, callValue), false);
|
|
244
|
-
session.variables[session.variables.length - 1].passby = 'ref';
|
|
245
|
-
session.variables[session.variables.length - 1].refName = callValue;
|
|
246
|
-
} else {
|
|
247
|
-
// Pass by value
|
|
248
|
-
value = substituteVariables(session, callValue);
|
|
249
|
-
setVariable(session, paramName, value, false);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
} else {
|
|
253
|
-
// No value provided - use default if available
|
|
254
|
-
const defaultValue = paramVar.attributes.default || '';
|
|
255
|
-
value = substituteVariables(session, defaultValue);
|
|
256
|
-
setVariable(session, paramName, value, false);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
package/src/tags/catch.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <catch> tag - catches exceptions by name
|
|
3
|
-
* Maps to mask_catch_integrate in MASK
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { lookupException, flushCurrentException } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export async function executeCatch(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
|
-
// Look up matching exceptions between current position and last boundary
|
|
14
|
-
const caughtCount = lookupException(session, exceptionName);
|
|
15
|
-
|
|
16
|
-
// If exceptions were caught, execute the catch block
|
|
17
|
-
if (caughtCount > 0) {
|
|
18
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
19
|
-
await integrateChildren(session, element);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Flush current exceptions after processing
|
|
23
|
-
flushCurrentException(session);
|
|
24
|
-
}
|
package/src/tags/defvar.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <defvar> tag - define variable
|
|
3
|
-
* Maps to mask_tag_defvar in MASK
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
8
|
-
import { setVariable, substituteVariables } from '../runtime/session.js';
|
|
9
|
-
import { integrate } from '../runtime/interpreter.js';
|
|
10
|
-
import { executeParameters } from './parameters.js';
|
|
11
|
-
|
|
12
|
-
export async function executeDefvar(session: DiracSession, element: DiracElement): Promise<void> {
|
|
13
|
-
const name = element.attributes.name;
|
|
14
|
-
const valueAttr = element.attributes.value;
|
|
15
|
-
const visibleAttr = element.attributes.visible || 'false';
|
|
16
|
-
const literal = 'literal' in element.attributes;
|
|
17
|
-
const trimAttr = element.attributes.trim;
|
|
18
|
-
const trim = trimAttr !== 'false'; // Trim by default unless explicitly set to false
|
|
19
|
-
|
|
20
|
-
if (!name) {
|
|
21
|
-
throw new Error('<defvar> requires name attribute');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Determine visibility
|
|
25
|
-
const visible = visibleAttr === 'true' || visibleAttr === 'variable' || visibleAttr === 'both';
|
|
26
|
-
|
|
27
|
-
let value: any;
|
|
28
|
-
if (valueAttr !== undefined) {
|
|
29
|
-
value = substituteVariables(session, valueAttr);
|
|
30
|
-
} else if (literal) {
|
|
31
|
-
// Literal mode: serialize children to XML text without executing
|
|
32
|
-
if (element.children && element.children.length > 0) {
|
|
33
|
-
value = serializeToXml(element.children);
|
|
34
|
-
} else if (element.text) {
|
|
35
|
-
value = substituteVariables(session, element.text);
|
|
36
|
-
} else {
|
|
37
|
-
value = '';
|
|
38
|
-
}
|
|
39
|
-
} else if (element.children && element.children.length > 0) {
|
|
40
|
-
// If the first child is a <parameters> tag, call and assign its return value
|
|
41
|
-
if (element.children.length === 1 && element.children[0].tag && element.children[0].tag.toLowerCase() === 'parameters') {
|
|
42
|
-
value = await executeParameters(session, element.children[0]);
|
|
43
|
-
} else {
|
|
44
|
-
// Otherwise, execute all children and capture output
|
|
45
|
-
const prevOutput = session.output;
|
|
46
|
-
session.output = [];
|
|
47
|
-
for (const child of element.children) {
|
|
48
|
-
await integrate(session, child);
|
|
49
|
-
}
|
|
50
|
-
value = session.output.join('');
|
|
51
|
-
session.output = prevOutput;
|
|
52
|
-
}
|
|
53
|
-
} else if (element.text) {
|
|
54
|
-
value = substituteVariables(session, element.text);
|
|
55
|
-
} else {
|
|
56
|
-
value = '';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Apply trim if requested
|
|
60
|
-
if (trim && typeof value === 'string') {
|
|
61
|
-
value = value.trim();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
setVariable(session, name, value, visible);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function serializeToXml(children: DiracElement[]): string {
|
|
68
|
-
let xml = '';
|
|
69
|
-
|
|
70
|
-
for (const child of children) {
|
|
71
|
-
if (!child.tag || child.tag === '') {
|
|
72
|
-
// Text node
|
|
73
|
-
xml += child.text || '';
|
|
74
|
-
} else {
|
|
75
|
-
// Element node
|
|
76
|
-
xml += `<${child.tag}`;
|
|
77
|
-
|
|
78
|
-
// Add attributes
|
|
79
|
-
for (const [attrName, attrValue] of Object.entries(child.attributes)) {
|
|
80
|
-
xml += ` ${attrName}="${escapeXml(attrValue)}"`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Self-closing or with children
|
|
84
|
-
if (child.children.length === 0 && !child.text) {
|
|
85
|
-
xml += ' />';
|
|
86
|
-
} else {
|
|
87
|
-
xml += '>';
|
|
88
|
-
|
|
89
|
-
// Only add text content if there are no children
|
|
90
|
-
// (if there are children, text is stored in text node children)
|
|
91
|
-
if (child.text && child.children.length === 0) {
|
|
92
|
-
xml += escapeXml(child.text);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Add children (which may include text nodes)
|
|
96
|
-
if (child.children.length > 0) {
|
|
97
|
-
xml += serializeToXml(child.children);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
xml += `</${child.tag}>`;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return xml;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function escapeXml(text: string): string {
|
|
109
|
-
return text
|
|
110
|
-
.replace(/&/g, '&')
|
|
111
|
-
.replace(/</g, '<')
|
|
112
|
-
.replace(/>/g, '>')
|
|
113
|
-
.replace(/"/g, '"')
|
|
114
|
-
.replace(/'/g, ''');
|
|
115
|
-
}
|
package/src/tags/environment.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <environment> tag - read environment variables
|
|
3
|
-
* Usage: <environment name="VAR_NAME" />
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { emit } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
export async function executeEnvironment(session: DiracSession, element: DiracElement): Promise<void> {
|
|
10
|
-
const name = element.attributes.name;
|
|
11
|
-
|
|
12
|
-
if (!name) {
|
|
13
|
-
throw new Error('<environment> requires name attribute');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Get environment variable value
|
|
17
|
-
const value = process.env[name] || '';
|
|
18
|
-
|
|
19
|
-
// Emit the value to output
|
|
20
|
-
emit(session, value);
|
|
21
|
-
}
|
package/src/tags/eval.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <eval> tag - evaluate JavaScript expression
|
|
3
|
-
* Maps to mask_tag_eval in MASK (but for JS, not C)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { setVariable, getVariable, substituteVariables } from '../runtime/session.js';
|
|
8
|
-
|
|
9
|
-
// AsyncFunction constructor
|
|
10
|
-
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
|
11
|
-
|
|
12
|
-
export async function executeEval(session: DiracSession, element: DiracElement): Promise<void> {
|
|
13
|
-
const name = element.attributes.name;
|
|
14
|
-
const exprAttr = element.attributes.expr;
|
|
15
|
-
|
|
16
|
-
// Get expression as-is (do not replace ${var})
|
|
17
|
-
let expr: string;
|
|
18
|
-
if (exprAttr) {
|
|
19
|
-
expr = exprAttr;
|
|
20
|
-
} else if (element.text) {
|
|
21
|
-
expr = element.text;
|
|
22
|
-
} else {
|
|
23
|
-
throw new Error('<eval> requires expr attribute or text content');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (session.debug) {
|
|
27
|
-
console.error(`[EVAL] Code after substitution:\n${expr}\n`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
// Build context object with all variables
|
|
32
|
-
const context: Record<string, any> = {};
|
|
33
|
-
for (const v of session.variables) {
|
|
34
|
-
context[v.name] = v.value;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Add Node.js modules to context
|
|
38
|
-
const { default: fs } = await import('fs');
|
|
39
|
-
const { default: path } = await import('path');
|
|
40
|
-
const { fileURLToPath } = await import('url');
|
|
41
|
-
context.fs = fs;
|
|
42
|
-
context.path = path;
|
|
43
|
-
context.__dirname = process.cwd(); // ESM doesn't have __dirname, use cwd
|
|
44
|
-
|
|
45
|
-
// Add helper to get current parameters from stack
|
|
46
|
-
context.getParams = () => {
|
|
47
|
-
const params = session.parameterStack[session.parameterStack.length - 1];
|
|
48
|
-
return params && params[0] ? params[0] : null;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Add session object for orchestration (reserved identifier in eval context)
|
|
52
|
-
context.session = session;
|
|
53
|
-
|
|
54
|
-
let result: any;
|
|
55
|
-
// Execute as async function to support top-level await
|
|
56
|
-
const func = new AsyncFunction(...Object.keys(context), expr);
|
|
57
|
-
result = await func(...Object.values(context));
|
|
58
|
-
|
|
59
|
-
if (session.debug) {
|
|
60
|
-
console.error(`[EVAL] Result: ${JSON.stringify(result)}`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Store result if name provided
|
|
64
|
-
if (name) {
|
|
65
|
-
setVariable(session, name, result, false);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
} catch (error) {
|
|
69
|
-
throw new Error(`Eval error: ${error instanceof Error ? error.message : String(error)}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
package/src/tags/exception.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <exception> tag - outputs currently caught exceptions
|
|
3
|
-
* Maps to mask_exception_integrate in MASK
|
|
4
|
-
* Used inside <catch> blocks to access exception content
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
8
|
-
import { getCurrentExceptions } from '../runtime/session.js';
|
|
9
|
-
|
|
10
|
-
export async function executeException(session: DiracSession, element: DiracElement): Promise<void> {
|
|
11
|
-
// Get the currently caught exceptions
|
|
12
|
-
const exceptions = getCurrentExceptions(session);
|
|
13
|
-
|
|
14
|
-
// Process each exception DOM element's children
|
|
15
|
-
const { integrateChildren } = await import('../runtime/interpreter.js');
|
|
16
|
-
for (const exceptionDom of exceptions) {
|
|
17
|
-
// Execute the children of the exception (the exception content)
|
|
18
|
-
await integrateChildren(session, exceptionDom);
|
|
19
|
-
}
|
|
20
|
-
}
|