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.
Files changed (221) hide show
  1. package/dist/cli.js +13 -1
  2. package/lib/index.di +9 -0
  3. package/{examples/lib → lib}/math.di +3 -3
  4. package/package.json +13 -1
  5. package/.env.example +0 -8
  6. package/COMMUNITY.md +0 -465
  7. package/CONDITIONAL-TAGS.md +0 -172
  8. package/EXCEPTION-HANDLING.md +0 -156
  9. package/LIBRARIES.md +0 -172
  10. package/LLM-VALIDATION.md +0 -128
  11. package/NAMESPACES.md +0 -366
  12. package/PROMOTION.md +0 -257
  13. package/QUICKSTART-LIBRARY.md +0 -93
  14. package/TEST-COVERAGE.md +0 -113
  15. package/TESTING.md +0 -162
  16. package/config.test.yml +0 -5
  17. package/dirac-http/examples/demo.di +0 -9
  18. package/dirac-http/lib/index.di +0 -12
  19. package/examples/add-demo.di +0 -74
  20. package/examples/add.bk +0 -11
  21. package/examples/advanced-math-demo.di +0 -53
  22. package/examples/calculator.di +0 -32
  23. package/examples/compact-test.di +0 -6
  24. package/examples/comprehensive.bk +0 -29
  25. package/examples/defvar-variable-demo.di +0 -18
  26. package/examples/direct-call.di +0 -17
  27. package/examples/disk-analysis.di +0 -16
  28. package/examples/exception-demo.di +0 -82
  29. package/examples/executable-hello.di +0 -7
  30. package/examples/execute-demo.di +0 -38
  31. package/examples/file-manager.di +0 -77
  32. package/examples/file-stats.di +0 -18
  33. package/examples/hello.bk +0 -1
  34. package/examples/hello.di +0 -5
  35. package/examples/if-comparison.di +0 -91
  36. package/examples/if-cstyle-test.di +0 -149
  37. package/examples/if-vs-testif.di +0 -56
  38. package/examples/import-demo.di +0 -31
  39. package/examples/inline-test.bk +0 -7
  40. package/examples/llm-agent.di +0 -32
  41. package/examples/llm-basic.di +0 -12
  42. package/examples/llm-command-more.di +0 -6
  43. package/examples/llm-command-no-exec.di +0 -13
  44. package/examples/llm-command.di +0 -6
  45. package/examples/llm-complex.di +0 -141
  46. package/examples/llm-feedback-debug.di +0 -30
  47. package/examples/llm-feedback-demo.di +0 -19
  48. package/examples/llm-feedback-math.di +0 -22
  49. package/examples/llm-feedback-simple.di +0 -16
  50. package/examples/llm-feedback-sub.di +0 -22
  51. package/examples/llm-no-feedback.di +0 -10
  52. package/examples/llm-recursive.di +0 -31
  53. package/examples/llm-reflection-test.di +0 -19
  54. package/examples/llm-simple-test.di +0 -12
  55. package/examples/llm-subs.di +0 -132
  56. package/examples/llm-use-subs.di +0 -6
  57. package/examples/llm-validate-test.di +0 -18
  58. package/examples/loop.di +0 -12
  59. package/examples/math-test.di +0 -22
  60. package/examples/minimal-test.di +0 -13
  61. package/examples/mongodb-context-test.di +0 -27
  62. package/examples/mongodb-count-events.di +0 -8
  63. package/examples/mongodb-import-demo.di +0 -25
  64. package/examples/mongodb-simple-test.di +0 -18
  65. package/examples/nl-agent.di +0 -47
  66. package/examples/parameters-demo.di +0 -68
  67. package/examples/params-meta-test.di +0 -17
  68. package/examples/params-test.di +0 -10
  69. package/examples/recipe-chain.di +0 -38
  70. package/examples/recursive-llm.di +0 -44
  71. package/examples/sample-library/README.md +0 -152
  72. package/examples/sample-library/examples/demo.di +0 -34
  73. package/examples/sample-library/lib/index.di +0 -65
  74. package/examples/sample-library/package.json +0 -31
  75. package/examples/scope-test-nested.di +0 -60
  76. package/examples/scope-test.di +0 -55
  77. package/examples/seamless.di +0 -45
  78. package/examples/shell-test.bk +0 -10
  79. package/examples/simple-import.di +0 -13
  80. package/examples/simple-recursive.di +0 -26
  81. package/examples/story-builder.di +0 -45
  82. package/examples/subroutine.di +0 -23
  83. package/examples/system-llm.di +0 -21
  84. package/examples/system-simple.di +0 -3
  85. package/examples/system-test.di +0 -8
  86. package/examples/tag-check-test.di +0 -139
  87. package/examples/task-assistant.di +0 -27
  88. package/examples/test-if-demo.di +0 -110
  89. package/examples/test-parameters.di +0 -50
  90. package/examples/try-catch-test.di +0 -118
  91. package/examples/two-styles.di +0 -28
  92. package/examples/var-debug.di +0 -6
  93. package/examples/var-inline.di +0 -4
  94. package/examples/var-test2.di +0 -6
  95. package/examples/variable-replace.di +0 -25
  96. package/examples/variable-simple.di +0 -16
  97. package/examples/variable-test.di +0 -22
  98. package/examples/whitespace-test.di +0 -24
  99. package/filePath +0 -1
  100. package/greeting.txt +0 -1
  101. package/src/cli.ts +0 -140
  102. package/src/index.ts +0 -33
  103. package/src/llm/ollama.ts +0 -58
  104. package/src/runtime/braket-parser.ts +0 -234
  105. package/src/runtime/interpreter.ts +0 -203
  106. package/src/runtime/parser.ts +0 -155
  107. package/src/runtime/session.ts +0 -325
  108. package/src/tags/assign.ts +0 -37
  109. package/src/tags/attr.ts +0 -64
  110. package/src/tags/available-subroutines.ts +0 -70
  111. package/src/tags/call.ts +0 -259
  112. package/src/tags/catch.ts +0 -24
  113. package/src/tags/defvar.ts +0 -115
  114. package/src/tags/environment.ts +0 -21
  115. package/src/tags/eval.ts +0 -71
  116. package/src/tags/exception.ts +0 -20
  117. package/src/tags/execute.ts +0 -52
  118. package/src/tags/expr.ts +0 -128
  119. package/src/tags/foreach.ts +0 -170
  120. package/src/tags/if.ts +0 -191
  121. package/src/tags/import.ts +0 -135
  122. package/src/tags/index.ts +0 -41
  123. package/src/tags/input.ts +0 -182
  124. package/src/tags/llm.ts +0 -415
  125. package/src/tags/loop.ts +0 -43
  126. package/src/tags/mongodb.ts +0 -70
  127. package/src/tags/output.ts +0 -53
  128. package/src/tags/parameters.ts +0 -81
  129. package/src/tags/require_module.ts +0 -19
  130. package/src/tags/subroutine.ts +0 -75
  131. package/src/tags/system.ts +0 -93
  132. package/src/tags/tag-check.ts +0 -176
  133. package/src/tags/test-if.ts +0 -112
  134. package/src/tags/throw.ts +0 -26
  135. package/src/tags/try.ts +0 -19
  136. package/src/tags/variable.ts +0 -25
  137. package/src/test-runner.ts +0 -300
  138. package/src/types/index.ts +0 -128
  139. package/src/utils/llm-adapter.ts +0 -113
  140. package/src/utils/tag-validator.ts +0 -231
  141. package/test-available-extends.di +0 -28
  142. package/test-available-simple.di +0 -12
  143. package/test-available-subroutines.di +0 -16
  144. package/test-call.di +0 -9
  145. package/test-extend-basic.di +0 -17
  146. package/test-extend-chain.di +0 -26
  147. package/test-extend-debug.di +0 -17
  148. package/test-extend-debug2.di +0 -15
  149. package/test-extend-person.di +0 -17
  150. package/test-extend-simple.di +0 -11
  151. package/test-extend-zhi.di +0 -23
  152. package/test-extend.di +0 -19
  153. package/test-extend2.di +0 -26
  154. package/test-extend3-fixed.di +0 -23
  155. package/test-extend3-trouble.di +0 -23
  156. package/test-extend3.di +0 -21
  157. package/test-factorial.di +0 -19
  158. package/test-input-debug.di +0 -19
  159. package/test-nested-debug.di +0 -7
  160. package/test-nested-debug2.di +0 -8
  161. package/test-no-extend.di +0 -16
  162. package/test-simple-call.di +0 -7
  163. package/test-simple.di +0 -6
  164. package/tests/README.md +0 -69
  165. package/tests/assign-basic.test.di +0 -7
  166. package/tests/assign-from-eval.test.di +0 -7
  167. package/tests/available-subroutines-foreach.test.di +0 -32
  168. package/tests/basic-output.test.di +0 -5
  169. package/tests/call-basic.test.di +0 -11
  170. package/tests/call-with-output.test.di +0 -10
  171. package/tests/comments-before-content.test.di +0 -6
  172. package/tests/defvar-multiple.test.di +0 -8
  173. package/tests/environment-basic.test.di +0 -22
  174. package/tests/environment-nonexistent.test.di +0 -5
  175. package/tests/environment-with-defvar.test.di +0 -15
  176. package/tests/eval-basic.test.di +0 -6
  177. package/tests/eval-with-variables.test.di +0 -8
  178. package/tests/exception-basic.test.di +0 -10
  179. package/tests/expr-basic.test.di +0 -11
  180. package/tests/extend-basic.test.di +0 -19
  181. package/tests/extend-inheritance-chain.test.di +0 -26
  182. package/tests/extend-multiple-nested.test.di +0 -24
  183. package/tests/extend-self.test.di +0 -19
  184. package/tests/extend-with-parameters.test.di +0 -14
  185. package/tests/generate-dirac.test.di +0 -22
  186. package/tests/if-conditional.test.di +0 -17
  187. package/tests/if-else.test.di +0 -11
  188. package/tests/if-with-variables.test.di +0 -8
  189. package/tests/import-basic.test.di +0 -6
  190. package/tests/input-file-all.test.di +0 -5
  191. package/tests/input-file-line.test.di +0 -15
  192. package/tests/input-file-loop.test.di +0 -12
  193. package/tests/input-stdin-all.test.di +0 -8
  194. package/tests/input-stdin-all.txt +0 -1
  195. package/tests/llm-validate.test.di +0 -17
  196. package/tests/loop-basic.test.di +0 -9
  197. package/tests/loop-nested.test.di +0 -10
  198. package/tests/loop-with-eval.test.di +0 -8
  199. package/tests/no-root-element.test.di +0 -6
  200. package/tests/output-file.test.di +0 -19
  201. package/tests/output-multiple.test.di +0 -9
  202. package/tests/parameters-basic.test.di +0 -6
  203. package/tests/require-module-basic.test.di +0 -7
  204. package/tests/subroutine-basic.test.di +0 -9
  205. package/tests/subroutine-multiple-params.test.di +0 -10
  206. package/tests/subroutine-nested-calls.test.di +0 -32
  207. package/tests/subroutine-sequential-calls.test.di +0 -36
  208. package/tests/system-background.test.di +0 -39
  209. package/tests/system-basic.test.di +0 -5
  210. package/tests/tag-check.test.di +0 -27
  211. package/tests/test-if-basic.test.di +0 -8
  212. package/tests/test-input.txt +0 -3
  213. package/tests/try-catch-basic.test.di +0 -10
  214. package/tests/try-catch-eval-error.test.di +0 -10
  215. package/tests/variable-basic.test.di +0 -6
  216. package/tests/variable-interpolation.test.di +0 -7
  217. package/tools/create-library.sh +0 -175
  218. package/tsconfig.json +0 -19
  219. /package/{examples/lib → lib}/advanced-math.di +0 -0
  220. /package/{examples/lib → lib}/fileops.di +0 -0
  221. /package/{examples/lib → lib}/mongodb.di +0 -0
@@ -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
- }
@@ -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
- }
@@ -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
- }