@o-lang/olang 1.2.30 → 1.2.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/parser/index.js +41 -29
- package/src/runtime/RuntimeAPI.js +24 -1
package/package.json
CHANGED
package/src/parser/index.js
CHANGED
|
@@ -305,7 +305,7 @@ function parseWorkflowLines(lines, filename) {
|
|
|
305
305
|
continue;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
// ✅ ADD: Set keyword (e.g., Set analysis_result = "")
|
|
309
309
|
const setMatch = line.match(/^Set\s+(\w+)\s*=\s*(.+)$/i);
|
|
310
310
|
if (setMatch) {
|
|
311
311
|
flushCurrentStep();
|
|
@@ -399,38 +399,41 @@ function parseWorkflowLines(lines, filename) {
|
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
// Ask (for Notify/resolver calls) - ✅ PRESERVE TARGET EXACTLY (NO NORMALIZATION)
|
|
402
|
-
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
403
|
-
if (askMatch) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
402
|
+
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
403
|
+
if (askMatch) {
|
|
404
|
+
flushCurrentStep();
|
|
405
|
+
let actionContent = askMatch[1].trim();
|
|
406
|
+
|
|
407
|
+
// ✅ Multiline heredoc support: Ask llm-groq """
|
|
408
|
+
if (actionContent.endsWith('"""')) {
|
|
409
|
+
// Consume lines until closing """
|
|
410
|
+
let multiline = actionContent.slice(0, -3).trim() + ' ';
|
|
411
|
+
while (i < lines.length) {
|
|
412
|
+
const nextLine = lines[i++].trim();
|
|
413
|
+
if (nextLine === '"""') break;
|
|
414
|
+
multiline += nextLine + ' ';
|
|
415
|
+
}
|
|
416
|
+
actionContent = multiline.trim();
|
|
417
|
+
}
|
|
418
418
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
419
|
+
workflow.steps.push({
|
|
420
|
+
type: 'action',
|
|
421
|
+
actionRaw: `Action ${actionContent}`,
|
|
422
|
+
stepNumber: workflow.steps.length + 1,
|
|
423
|
+
saveAs: null,
|
|
424
|
+
constraints: {}
|
|
425
|
+
});
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
428
|
|
|
429
|
-
// Return
|
|
429
|
+
// ✅ ADD: Return keyword support (ensures wf.returnValues is populated)
|
|
430
430
|
const returnMatch = line.match(/^Return\s+(.+)$/i);
|
|
431
431
|
if (returnMatch) {
|
|
432
432
|
flushCurrentStep();
|
|
433
|
-
workflow.returnValues = returnMatch[1]
|
|
433
|
+
workflow.returnValues = returnMatch[1]
|
|
434
|
+
.split(',')
|
|
435
|
+
.map(r => r.trim())
|
|
436
|
+
.filter(r => r !== '');
|
|
434
437
|
continue;
|
|
435
438
|
}
|
|
436
439
|
|
|
@@ -603,7 +606,7 @@ function parseBlock(lines) {
|
|
|
603
606
|
continue;
|
|
604
607
|
}
|
|
605
608
|
|
|
606
|
-
|
|
609
|
+
// ✅ ADD: Set keyword inside blocks (e.g., Set analysis_result = "")
|
|
607
610
|
const setMatch = line.match(/^Set\s+(\w+)\s*=\s*(.+)$/i);
|
|
608
611
|
if (setMatch) {
|
|
609
612
|
flush(); // Flush any pending step
|
|
@@ -615,6 +618,15 @@ function parseBlock(lines) {
|
|
|
615
618
|
});
|
|
616
619
|
continue;
|
|
617
620
|
}
|
|
621
|
+
|
|
622
|
+
// ✅ ADD: Return keyword inside blocks (rare but supported)
|
|
623
|
+
const returnMatch = line.match(/^Return\s+(.+)$/i);
|
|
624
|
+
if (returnMatch) {
|
|
625
|
+
flush();
|
|
626
|
+
// Note: Return inside blocks is unusual; this just parses it
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
|
|
618
630
|
// Fallback
|
|
619
631
|
if (current) {
|
|
620
632
|
current.actionRaw += ' ' + line; // ← PRESERVED EXACTLY (no normalizeAction)
|
|
@@ -690,15 +690,38 @@ class RuntimeAPI {
|
|
|
690
690
|
abs: a => Math.abs(a)
|
|
691
691
|
};
|
|
692
692
|
|
|
693
|
-
|
|
693
|
+
evaluateMath(expr) {
|
|
694
|
+
// ✅ Handle quoted string literals with interpolation: "{var}" → interpolated string
|
|
695
|
+
if (typeof expr === 'string') {
|
|
696
|
+
const trimmed = expr.trim();
|
|
697
|
+
|
|
698
|
+
// Check if it's a quoted string (single or double quotes)
|
|
699
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
700
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
701
|
+
// Extract the inner content
|
|
702
|
+
let inner = trimmed.slice(1, -1);
|
|
703
|
+
|
|
704
|
+
// Perform interpolation: replace {var} with context values
|
|
705
|
+
inner = inner.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
706
|
+
const value = this.getNested(this.context, path.trim());
|
|
707
|
+
return value !== undefined ? String(value) : `{${path}}`;
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
return inner;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// ── Original math evaluation logic (unchanged) ──────────────────────────
|
|
694
715
|
expr = expr.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
695
716
|
const value = this.getNested(this.context, path.trim());
|
|
696
717
|
if (typeof value === 'string') return `"${value.replace(/"/g, '\\"')}"`;
|
|
697
718
|
return value !== undefined ? value : 0;
|
|
698
719
|
});
|
|
720
|
+
|
|
699
721
|
const funcNames = Object.keys(this.mathFunctions);
|
|
700
722
|
const safeFunc = {};
|
|
701
723
|
funcNames.forEach(fn => safeFunc[fn] = this.mathFunctions[fn]);
|
|
724
|
+
|
|
702
725
|
try {
|
|
703
726
|
const f = new Function(...funcNames, `return ${expr};`);
|
|
704
727
|
return f(...funcNames.map(fn => safeFunc[fn]));
|