@grimoirelabs/core 0.1.0
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/builders/expressions.d.ts +33 -0
- package/dist/builders/expressions.d.ts.map +1 -0
- package/dist/builders/expressions.js +57 -0
- package/dist/builders/expressions.js.map +1 -0
- package/dist/builders/index.d.ts +44 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +32 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/builders/spell-builder.d.ts +124 -0
- package/dist/builders/spell-builder.d.ts.map +1 -0
- package/dist/builders/spell-builder.js +299 -0
- package/dist/builders/spell-builder.js.map +1 -0
- package/dist/builders/step-builder.d.ts +212 -0
- package/dist/builders/step-builder.d.ts.map +1 -0
- package/dist/builders/step-builder.js +499 -0
- package/dist/builders/step-builder.js.map +1 -0
- package/dist/compiler/expression-parser.d.ts +14 -0
- package/dist/compiler/expression-parser.d.ts.map +1 -0
- package/dist/compiler/expression-parser.js +460 -0
- package/dist/compiler/expression-parser.js.map +1 -0
- package/dist/compiler/grimoire/ast.d.ts +450 -0
- package/dist/compiler/grimoire/ast.d.ts.map +1 -0
- package/dist/compiler/grimoire/ast.js +19 -0
- package/dist/compiler/grimoire/ast.js.map +1 -0
- package/dist/compiler/grimoire/errors.d.ts +65 -0
- package/dist/compiler/grimoire/errors.d.ts.map +1 -0
- package/dist/compiler/grimoire/errors.js +86 -0
- package/dist/compiler/grimoire/errors.js.map +1 -0
- package/dist/compiler/grimoire/index.d.ts +24 -0
- package/dist/compiler/grimoire/index.d.ts.map +1 -0
- package/dist/compiler/grimoire/index.js +63 -0
- package/dist/compiler/grimoire/index.js.map +1 -0
- package/dist/compiler/grimoire/parser.d.ts +135 -0
- package/dist/compiler/grimoire/parser.d.ts.map +1 -0
- package/dist/compiler/grimoire/parser.js +2148 -0
- package/dist/compiler/grimoire/parser.js.map +1 -0
- package/dist/compiler/grimoire/tokenizer.d.ts +59 -0
- package/dist/compiler/grimoire/tokenizer.d.ts.map +1 -0
- package/dist/compiler/grimoire/tokenizer.js +509 -0
- package/dist/compiler/grimoire/tokenizer.js.map +1 -0
- package/dist/compiler/grimoire/transformer.d.ts +71 -0
- package/dist/compiler/grimoire/transformer.d.ts.map +1 -0
- package/dist/compiler/grimoire/transformer.js +1011 -0
- package/dist/compiler/grimoire/transformer.js.map +1 -0
- package/dist/compiler/index.d.ts +45 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +97 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/compiler/ir-generator.d.ts +16 -0
- package/dist/compiler/ir-generator.d.ts.map +1 -0
- package/dist/compiler/ir-generator.js +997 -0
- package/dist/compiler/ir-generator.js.map +1 -0
- package/dist/compiler/validator.d.ts +15 -0
- package/dist/compiler/validator.d.ts.map +1 -0
- package/dist/compiler/validator.js +401 -0
- package/dist/compiler/validator.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/circuit-breaker.d.ts +59 -0
- package/dist/runtime/circuit-breaker.d.ts.map +1 -0
- package/dist/runtime/circuit-breaker.js +155 -0
- package/dist/runtime/circuit-breaker.js.map +1 -0
- package/dist/runtime/context.d.ts +92 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.js +219 -0
- package/dist/runtime/context.js.map +1 -0
- package/dist/runtime/error-classifier.d.ts +16 -0
- package/dist/runtime/error-classifier.d.ts.map +1 -0
- package/dist/runtime/error-classifier.js +38 -0
- package/dist/runtime/error-classifier.js.map +1 -0
- package/dist/runtime/expression-evaluator.d.ts +36 -0
- package/dist/runtime/expression-evaluator.d.ts.map +1 -0
- package/dist/runtime/expression-evaluator.js +391 -0
- package/dist/runtime/expression-evaluator.js.map +1 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +11 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/interpreter.d.ts +59 -0
- package/dist/runtime/interpreter.d.ts.map +1 -0
- package/dist/runtime/interpreter.js +414 -0
- package/dist/runtime/interpreter.js.map +1 -0
- package/dist/runtime/skills/registry.d.ts +11 -0
- package/dist/runtime/skills/registry.d.ts.map +1 -0
- package/dist/runtime/skills/registry.js +73 -0
- package/dist/runtime/skills/registry.js.map +1 -0
- package/dist/runtime/sqlite-state-store.d.ts +28 -0
- package/dist/runtime/sqlite-state-store.d.ts.map +1 -0
- package/dist/runtime/sqlite-state-store.js +180 -0
- package/dist/runtime/sqlite-state-store.js.map +1 -0
- package/dist/runtime/state-store.d.ts +52 -0
- package/dist/runtime/state-store.d.ts.map +1 -0
- package/dist/runtime/state-store.js +32 -0
- package/dist/runtime/state-store.js.map +1 -0
- package/dist/runtime/steps/action.d.ts +17 -0
- package/dist/runtime/steps/action.d.ts.map +1 -0
- package/dist/runtime/steps/action.js +430 -0
- package/dist/runtime/steps/action.js.map +1 -0
- package/dist/runtime/steps/advisory.d.ts +28 -0
- package/dist/runtime/steps/advisory.d.ts.map +1 -0
- package/dist/runtime/steps/advisory.js +209 -0
- package/dist/runtime/steps/advisory.js.map +1 -0
- package/dist/runtime/steps/compute.d.ts +9 -0
- package/dist/runtime/steps/compute.d.ts.map +1 -0
- package/dist/runtime/steps/compute.js +74 -0
- package/dist/runtime/steps/compute.js.map +1 -0
- package/dist/runtime/steps/conditional.d.ts +14 -0
- package/dist/runtime/steps/conditional.d.ts.map +1 -0
- package/dist/runtime/steps/conditional.js +58 -0
- package/dist/runtime/steps/conditional.js.map +1 -0
- package/dist/runtime/steps/emit.d.ts +9 -0
- package/dist/runtime/steps/emit.d.ts.map +1 -0
- package/dist/runtime/steps/emit.js +70 -0
- package/dist/runtime/steps/emit.js.map +1 -0
- package/dist/runtime/steps/halt.d.ts +9 -0
- package/dist/runtime/steps/halt.d.ts.map +1 -0
- package/dist/runtime/steps/halt.js +19 -0
- package/dist/runtime/steps/halt.js.map +1 -0
- package/dist/runtime/steps/loop.d.ts +14 -0
- package/dist/runtime/steps/loop.d.ts.map +1 -0
- package/dist/runtime/steps/loop.js +109 -0
- package/dist/runtime/steps/loop.js.map +1 -0
- package/dist/runtime/steps/parallel.d.ts +9 -0
- package/dist/runtime/steps/parallel.d.ts.map +1 -0
- package/dist/runtime/steps/parallel.js +87 -0
- package/dist/runtime/steps/parallel.js.map +1 -0
- package/dist/runtime/steps/pipeline.d.ts +9 -0
- package/dist/runtime/steps/pipeline.d.ts.map +1 -0
- package/dist/runtime/steps/pipeline.js +125 -0
- package/dist/runtime/steps/pipeline.js.map +1 -0
- package/dist/runtime/steps/try.d.ts +13 -0
- package/dist/runtime/steps/try.d.ts.map +1 -0
- package/dist/runtime/steps/try.js +222 -0
- package/dist/runtime/steps/try.js.map +1 -0
- package/dist/runtime/steps/wait.d.ts +9 -0
- package/dist/runtime/steps/wait.d.ts.map +1 -0
- package/dist/runtime/steps/wait.js +38 -0
- package/dist/runtime/steps/wait.js.map +1 -0
- package/dist/types/actions.d.ts +162 -0
- package/dist/types/actions.d.ts.map +1 -0
- package/dist/types/actions.js +5 -0
- package/dist/types/actions.js.map +1 -0
- package/dist/types/execution.d.ts +276 -0
- package/dist/types/execution.d.ts.map +1 -0
- package/dist/types/execution.js +5 -0
- package/dist/types/execution.js.map +1 -0
- package/dist/types/expressions.d.ts +100 -0
- package/dist/types/expressions.d.ts.map +1 -0
- package/dist/types/expressions.js +48 -0
- package/dist/types/expressions.js.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/ir.d.ts +187 -0
- package/dist/types/ir.d.ts.map +1 -0
- package/dist/types/ir.js +5 -0
- package/dist/types/ir.js.map +1 -0
- package/dist/types/policy.d.ts +123 -0
- package/dist/types/policy.d.ts.map +1 -0
- package/dist/types/policy.js +5 -0
- package/dist/types/policy.js.map +1 -0
- package/dist/types/primitives.d.ts +76 -0
- package/dist/types/primitives.d.ts.map +1 -0
- package/dist/types/primitives.js +10 -0
- package/dist/types/primitives.js.map +1 -0
- package/dist/types/steps.d.ts +226 -0
- package/dist/types/steps.d.ts.map +1 -0
- package/dist/types/steps.js +5 -0
- package/dist/types/steps.js.map +1 -0
- package/dist/venues/index.d.ts +6 -0
- package/dist/venues/index.d.ts.map +1 -0
- package/dist/venues/index.js +26 -0
- package/dist/venues/index.js.map +1 -0
- package/dist/venues/types.d.ts +40 -0
- package/dist/venues/types.d.ts.map +1 -0
- package/dist/venues/types.js +5 -0
- package/dist/venues/types.js.map +1 -0
- package/dist/wallet/executor.d.ts +109 -0
- package/dist/wallet/executor.d.ts.map +1 -0
- package/dist/wallet/executor.js +354 -0
- package/dist/wallet/executor.js.map +1 -0
- package/dist/wallet/index.d.ts +14 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +13 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/keystore.d.ts +44 -0
- package/dist/wallet/keystore.d.ts.map +1 -0
- package/dist/wallet/keystore.js +296 -0
- package/dist/wallet/keystore.js.map +1 -0
- package/dist/wallet/provider.d.ts +111 -0
- package/dist/wallet/provider.d.ts.map +1 -0
- package/dist/wallet/provider.js +309 -0
- package/dist/wallet/provider.js.map +1 -0
- package/dist/wallet/tx-builder.d.ts +85 -0
- package/dist/wallet/tx-builder.d.ts.map +1 -0
- package/dist/wallet/tx-builder.js +290 -0
- package/dist/wallet/tx-builder.js.map +1 -0
- package/dist/wallet/types.d.ts +116 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/types.js +86 -0
- package/dist/wallet/types.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, extname, resolve } from "node:path";
|
|
3
|
+
import { parse } from "./parser.js";
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// TRANSFORMER CLASS
|
|
6
|
+
// =============================================================================
|
|
7
|
+
export class Transformer {
|
|
8
|
+
stepCounter = 0;
|
|
9
|
+
blockMap = new Map();
|
|
10
|
+
advisorDefaults = new Map();
|
|
11
|
+
assetDecimals = new Map();
|
|
12
|
+
venueLabelMap = new Map();
|
|
13
|
+
importStack = [];
|
|
14
|
+
/** Transform AST to SpellSource */
|
|
15
|
+
transform(ast, options) {
|
|
16
|
+
const source = {
|
|
17
|
+
spell: ast.name,
|
|
18
|
+
version: "1.0.0", // Default
|
|
19
|
+
};
|
|
20
|
+
// Pre-scan assets for unit conversion
|
|
21
|
+
for (const section of ast.sections) {
|
|
22
|
+
if (section.kind !== "assets")
|
|
23
|
+
continue;
|
|
24
|
+
for (const item of section.items) {
|
|
25
|
+
this.assetDecimals.set(item.symbol, item.decimals);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Pre-scan venues to resolve skill adapters that reference venue labels
|
|
29
|
+
for (const section of ast.sections) {
|
|
30
|
+
if (section.kind !== "venues")
|
|
31
|
+
continue;
|
|
32
|
+
for (const group of section.groups) {
|
|
33
|
+
const set = this.venueLabelMap.get(group.name) ?? new Set();
|
|
34
|
+
for (const venue of group.venues) {
|
|
35
|
+
set.add(venue.name);
|
|
36
|
+
}
|
|
37
|
+
this.venueLabelMap.set(group.name, set);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Resolve imports before local blocks
|
|
41
|
+
if (options?.filePath && ast.imports?.length) {
|
|
42
|
+
this.loadImports(ast.imports, dirname(options.filePath));
|
|
43
|
+
}
|
|
44
|
+
// Register blocks for do-invocations
|
|
45
|
+
for (const block of ast.blocks ?? []) {
|
|
46
|
+
if (this.blockMap.has(block.name)) {
|
|
47
|
+
throw new Error(`Duplicate block name '${block.name}'`);
|
|
48
|
+
}
|
|
49
|
+
this.blockMap.set(block.name, block);
|
|
50
|
+
}
|
|
51
|
+
// Process sections
|
|
52
|
+
for (const section of ast.sections) {
|
|
53
|
+
this.transformSection(section, source);
|
|
54
|
+
}
|
|
55
|
+
// Process triggers and their handlers
|
|
56
|
+
if (ast.triggers.length > 0) {
|
|
57
|
+
const trigger = ast.triggers[0];
|
|
58
|
+
if (trigger) {
|
|
59
|
+
source.trigger = this.transformTriggerType(trigger.trigger);
|
|
60
|
+
source.steps = this.transformStatements(trigger.body);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Multiple triggers → any trigger
|
|
64
|
+
if (ast.triggers.length > 1) {
|
|
65
|
+
const triggers = ast.triggers.map((t) => this.transformTriggerType(t.trigger));
|
|
66
|
+
source.trigger = { any: triggers };
|
|
67
|
+
// Merge all steps (simplified - in practice we'd need more complex handling)
|
|
68
|
+
source.steps = ast.triggers.flatMap((t) => this.transformStatements(t.body));
|
|
69
|
+
}
|
|
70
|
+
return source;
|
|
71
|
+
}
|
|
72
|
+
loadImports(imports, baseDir, prefix = "") {
|
|
73
|
+
for (const imp of imports) {
|
|
74
|
+
const importPath = resolve(baseDir, imp.path);
|
|
75
|
+
if (this.importStack.includes(importPath)) {
|
|
76
|
+
const cycle = [...this.importStack, importPath].join(" -> ");
|
|
77
|
+
throw new Error(`Import cycle detected: ${cycle}`);
|
|
78
|
+
}
|
|
79
|
+
const source = readFileSync(importPath, "utf8");
|
|
80
|
+
const ast = parse(source);
|
|
81
|
+
const alias = imp.alias && imp.alias.length > 0 ? imp.alias : basename(importPath, extname(importPath));
|
|
82
|
+
const namespace = prefix ? `${prefix}.${alias}` : alias;
|
|
83
|
+
this.importStack.push(importPath);
|
|
84
|
+
// Register imported blocks with namespace
|
|
85
|
+
for (const block of ast.blocks ?? []) {
|
|
86
|
+
const name = namespace ? `${namespace}.${block.name}` : block.name;
|
|
87
|
+
if (this.blockMap.has(name)) {
|
|
88
|
+
throw new Error(`Duplicate block name '${name}' from import '${imp.path}'`);
|
|
89
|
+
}
|
|
90
|
+
this.blockMap.set(name, { ...block, name });
|
|
91
|
+
}
|
|
92
|
+
if (ast.imports?.length) {
|
|
93
|
+
this.loadImports(ast.imports, dirname(importPath), namespace);
|
|
94
|
+
}
|
|
95
|
+
this.importStack.pop();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Transform a section to SpellSource fields */
|
|
99
|
+
transformSection(section, source) {
|
|
100
|
+
switch (section.kind) {
|
|
101
|
+
case "version":
|
|
102
|
+
source.version = section.value;
|
|
103
|
+
break;
|
|
104
|
+
case "description":
|
|
105
|
+
source.description = section.value;
|
|
106
|
+
break;
|
|
107
|
+
case "assets":
|
|
108
|
+
source.assets = {};
|
|
109
|
+
for (const item of section.items) {
|
|
110
|
+
source.assets[item.symbol] = {
|
|
111
|
+
chain: item.chain ?? 1, // Default to mainnet
|
|
112
|
+
address: item.address ?? `0x${item.symbol.toLowerCase()}`, // Placeholder
|
|
113
|
+
decimals: item.decimals,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
case "params":
|
|
118
|
+
source.params = {};
|
|
119
|
+
for (const item of section.items) {
|
|
120
|
+
if (item.type || item.min !== undefined || item.max !== undefined || item.asset) {
|
|
121
|
+
source.params[item.name] = {
|
|
122
|
+
type: item.type,
|
|
123
|
+
asset: item.asset,
|
|
124
|
+
default: item.value !== undefined ? this.exprToValue(item.value) : undefined,
|
|
125
|
+
min: item.min,
|
|
126
|
+
max: item.max,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else if (item.value !== undefined) {
|
|
130
|
+
source.params[item.name] = this.exprToValue(item.value);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
source.params[item.name] = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
case "limits":
|
|
138
|
+
// Store limits as params
|
|
139
|
+
if (!source.params)
|
|
140
|
+
source.params = {};
|
|
141
|
+
for (const item of section.items) {
|
|
142
|
+
source.params[`limit_${item.name}`] = this.exprToValue(item.value);
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
case "venues":
|
|
146
|
+
source.venues = {};
|
|
147
|
+
for (const group of section.groups) {
|
|
148
|
+
for (const venue of group.venues) {
|
|
149
|
+
source.venues[venue.name] = {
|
|
150
|
+
chain: venue.chain ?? 1,
|
|
151
|
+
address: venue.address ?? `0x${venue.name}`,
|
|
152
|
+
label: group.name,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
case "state": {
|
|
158
|
+
const state = {
|
|
159
|
+
persistent: source.state?.persistent ?? {},
|
|
160
|
+
ephemeral: source.state?.ephemeral ?? {},
|
|
161
|
+
};
|
|
162
|
+
source.state = state;
|
|
163
|
+
for (const item of section.persistent) {
|
|
164
|
+
state.persistent[item.name] = this.exprToValue(item.initialValue);
|
|
165
|
+
}
|
|
166
|
+
for (const item of section.ephemeral) {
|
|
167
|
+
state.ephemeral[item.name] = this.exprToValue(item.initialValue);
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case "skills": {
|
|
172
|
+
const skillsSection = section;
|
|
173
|
+
source.skills = source.skills ?? {};
|
|
174
|
+
for (const item of skillsSection.items) {
|
|
175
|
+
const resolvedAdapters = [];
|
|
176
|
+
for (const adapter of item.adapters) {
|
|
177
|
+
const byLabel = this.venueLabelMap.get(adapter);
|
|
178
|
+
if (byLabel && byLabel.size > 0) {
|
|
179
|
+
for (const alias of byLabel)
|
|
180
|
+
resolvedAdapters.push(alias);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
resolvedAdapters.push(adapter);
|
|
184
|
+
}
|
|
185
|
+
source.skills[item.name] = {
|
|
186
|
+
type: item.type,
|
|
187
|
+
adapters: Array.from(new Set(resolvedAdapters)),
|
|
188
|
+
default_constraints: item.defaultConstraints?.maxSlippage
|
|
189
|
+
? { max_slippage: this.exprToValue(item.defaultConstraints.maxSlippage) }
|
|
190
|
+
: undefined,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
case "advisors": {
|
|
196
|
+
const advisorsSection = section;
|
|
197
|
+
source.advisors = source.advisors ?? {};
|
|
198
|
+
for (const item of advisorsSection.items) {
|
|
199
|
+
source.advisors[item.name] = {
|
|
200
|
+
model: item.model,
|
|
201
|
+
system_prompt: item.systemPrompt,
|
|
202
|
+
skills: item.skills,
|
|
203
|
+
allowed_tools: item.allowedTools,
|
|
204
|
+
mcp: item.mcp,
|
|
205
|
+
timeout: item.timeout,
|
|
206
|
+
fallback: item.fallback,
|
|
207
|
+
rate_limit: item.maxPerRun || item.maxPerHour
|
|
208
|
+
? { max_per_run: item.maxPerRun, max_per_hour: item.maxPerHour }
|
|
209
|
+
: undefined,
|
|
210
|
+
};
|
|
211
|
+
this.advisorDefaults.set(item.name, {
|
|
212
|
+
timeout: item.timeout,
|
|
213
|
+
fallback: item.fallback,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case "guards": {
|
|
219
|
+
const guardsSection = section;
|
|
220
|
+
source.guards = guardsSection.items.map((item) => ({
|
|
221
|
+
id: item.id,
|
|
222
|
+
...(item.check.kind === "advisory_expr"
|
|
223
|
+
? {
|
|
224
|
+
advisory: item.check.advisor ?? "default",
|
|
225
|
+
check: item.check.prompt,
|
|
226
|
+
severity: item.severity ?? "warn",
|
|
227
|
+
fallback: item.fallback ?? true,
|
|
228
|
+
}
|
|
229
|
+
: {
|
|
230
|
+
check: this.exprToString(item.check),
|
|
231
|
+
severity: item.severity ?? "halt",
|
|
232
|
+
message: item.message,
|
|
233
|
+
}),
|
|
234
|
+
}));
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** Transform trigger type */
|
|
240
|
+
transformTriggerType(trigger) {
|
|
241
|
+
switch (trigger.kind) {
|
|
242
|
+
case "manual":
|
|
243
|
+
return { manual: true };
|
|
244
|
+
case "hourly":
|
|
245
|
+
return { schedule: "0 * * * *" };
|
|
246
|
+
case "daily":
|
|
247
|
+
return { schedule: "0 0 * * *" };
|
|
248
|
+
case "schedule":
|
|
249
|
+
return { schedule: trigger.cron };
|
|
250
|
+
case "condition":
|
|
251
|
+
return {
|
|
252
|
+
condition: this.exprToString(trigger.expression),
|
|
253
|
+
poll_interval: trigger.pollInterval ?? 60,
|
|
254
|
+
};
|
|
255
|
+
case "event":
|
|
256
|
+
return {
|
|
257
|
+
event: trigger.event,
|
|
258
|
+
filter: trigger.filter ? this.exprToString(trigger.filter) : undefined,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** Transform statements to step array */
|
|
263
|
+
transformStatements(statements) {
|
|
264
|
+
const steps = [];
|
|
265
|
+
for (const stmt of statements) {
|
|
266
|
+
const stmtSteps = this.transformStatement(stmt);
|
|
267
|
+
// Attach source location from AST span to the first step produced by this statement
|
|
268
|
+
if (stmt.span && stmtSteps.length > 0) {
|
|
269
|
+
const firstStep = stmtSteps[0];
|
|
270
|
+
if (firstStep) {
|
|
271
|
+
firstStep._sourceLocation = {
|
|
272
|
+
line: stmt.span.start.line,
|
|
273
|
+
column: stmt.span.start.column,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
steps.push(...stmtSteps);
|
|
278
|
+
}
|
|
279
|
+
return steps;
|
|
280
|
+
}
|
|
281
|
+
/** Transform a single statement */
|
|
282
|
+
transformStatement(stmt) {
|
|
283
|
+
switch (stmt.kind) {
|
|
284
|
+
case "assignment":
|
|
285
|
+
return this.transformAssignment(stmt);
|
|
286
|
+
case "if":
|
|
287
|
+
return this.transformIf(stmt);
|
|
288
|
+
case "for":
|
|
289
|
+
return this.transformFor(stmt);
|
|
290
|
+
case "repeat":
|
|
291
|
+
return this.transformRepeat(stmt);
|
|
292
|
+
case "until":
|
|
293
|
+
return this.transformUntil(stmt);
|
|
294
|
+
case "try":
|
|
295
|
+
return this.transformTry(stmt);
|
|
296
|
+
case "parallel":
|
|
297
|
+
return this.transformParallel(stmt);
|
|
298
|
+
case "pipeline":
|
|
299
|
+
return this.transformPipeline(stmt);
|
|
300
|
+
case "advise":
|
|
301
|
+
return this.transformAdvise(stmt);
|
|
302
|
+
case "do":
|
|
303
|
+
return this.transformDo(stmt);
|
|
304
|
+
case "atomic":
|
|
305
|
+
return this.transformAtomic(stmt);
|
|
306
|
+
case "method_call":
|
|
307
|
+
return this.transformMethodCall(stmt);
|
|
308
|
+
case "emit":
|
|
309
|
+
return this.transformEmit(stmt);
|
|
310
|
+
case "halt":
|
|
311
|
+
return this.transformHalt(stmt);
|
|
312
|
+
case "wait":
|
|
313
|
+
return this.transformWait(stmt);
|
|
314
|
+
case "advisory":
|
|
315
|
+
return this.transformAdvisory(stmt);
|
|
316
|
+
case "pass":
|
|
317
|
+
return [];
|
|
318
|
+
default:
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/** Transform assignment to compute step, or action step if RHS is a venue method call */
|
|
323
|
+
transformAssignment(stmt) {
|
|
324
|
+
// Check if RHS is a method call (venue action with output binding)
|
|
325
|
+
if (stmt.value.kind === "call") {
|
|
326
|
+
const callExpr = stmt.value;
|
|
327
|
+
if (callExpr.callee.kind === "property_access") {
|
|
328
|
+
const prop = callExpr.callee;
|
|
329
|
+
const methodCall = {
|
|
330
|
+
kind: "method_call",
|
|
331
|
+
object: prop.object,
|
|
332
|
+
method: prop.property,
|
|
333
|
+
args: callExpr.args,
|
|
334
|
+
outputBinding: stmt.target,
|
|
335
|
+
skill: stmt.skill,
|
|
336
|
+
};
|
|
337
|
+
if (stmt.constraints) {
|
|
338
|
+
methodCall.constraints = stmt.constraints;
|
|
339
|
+
}
|
|
340
|
+
return this.transformMethodCall(methodCall);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Default: compute step
|
|
344
|
+
const id = this.nextStepId("compute");
|
|
345
|
+
return [
|
|
346
|
+
{
|
|
347
|
+
id,
|
|
348
|
+
compute: {
|
|
349
|
+
[stmt.target]: this.exprToString(stmt.value),
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
];
|
|
353
|
+
}
|
|
354
|
+
/** Transform if statement to conditional step */
|
|
355
|
+
transformIf(stmt) {
|
|
356
|
+
const steps = [];
|
|
357
|
+
const id = this.nextStepId("cond");
|
|
358
|
+
// Check for advisory condition
|
|
359
|
+
if (stmt.condition.kind === "advisory_expr") {
|
|
360
|
+
const advisory = stmt.condition;
|
|
361
|
+
const thenSteps = this.transformStatements(stmt.thenBody);
|
|
362
|
+
const elseSteps = this.transformStatements(stmt.elseBody);
|
|
363
|
+
const advisorName = advisory.advisor ?? "default";
|
|
364
|
+
const defaults = this.advisorDefaults.get(advisorName);
|
|
365
|
+
// Advisory steps need special handling
|
|
366
|
+
steps.push({
|
|
367
|
+
id,
|
|
368
|
+
advisory: {
|
|
369
|
+
prompt: advisory.prompt,
|
|
370
|
+
advisor: advisorName,
|
|
371
|
+
output: `${id}_result`,
|
|
372
|
+
timeout: defaults?.timeout ?? 30,
|
|
373
|
+
fallback: defaults?.fallback ?? true,
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
// Add conditional based on advisory result
|
|
377
|
+
const condId = this.nextStepId("cond");
|
|
378
|
+
steps.push({
|
|
379
|
+
id: condId,
|
|
380
|
+
if: `${id}_result == true`,
|
|
381
|
+
then: thenSteps.map((s) => s.id),
|
|
382
|
+
else: elseSteps.map((s) => s.id),
|
|
383
|
+
});
|
|
384
|
+
steps.push(...thenSteps, ...elseSteps);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
// Regular conditional
|
|
388
|
+
const thenSteps = this.transformStatements(stmt.thenBody);
|
|
389
|
+
if (stmt.elifs && stmt.elifs.length > 0) {
|
|
390
|
+
// Build elif chain as nested conditionals (from last to first)
|
|
391
|
+
let elseChainSteps = this.transformStatements(stmt.elseBody);
|
|
392
|
+
let elseChainIds = elseChainSteps.map((s) => s.id);
|
|
393
|
+
for (let i = stmt.elifs.length - 1; i >= 0; i--) {
|
|
394
|
+
const elif = stmt.elifs[i];
|
|
395
|
+
if (!elif)
|
|
396
|
+
continue;
|
|
397
|
+
const elifId = this.nextStepId("cond");
|
|
398
|
+
const elifThenSteps = this.transformStatements(elif.body);
|
|
399
|
+
const elifCond = {
|
|
400
|
+
id: elifId,
|
|
401
|
+
if: this.exprToString(elif.condition),
|
|
402
|
+
then: elifThenSteps.map((s) => s.id),
|
|
403
|
+
else: elseChainIds,
|
|
404
|
+
};
|
|
405
|
+
elseChainSteps = [elifCond, ...elifThenSteps, ...elseChainSteps];
|
|
406
|
+
elseChainIds = [elifId];
|
|
407
|
+
}
|
|
408
|
+
steps.push({
|
|
409
|
+
id,
|
|
410
|
+
if: this.exprToString(stmt.condition),
|
|
411
|
+
then: thenSteps.map((s) => s.id),
|
|
412
|
+
else: elseChainIds,
|
|
413
|
+
});
|
|
414
|
+
steps.push(...thenSteps, ...elseChainSteps);
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
// Simple if/else (no elif)
|
|
418
|
+
const elseSteps = this.transformStatements(stmt.elseBody);
|
|
419
|
+
steps.push({
|
|
420
|
+
id,
|
|
421
|
+
if: this.exprToString(stmt.condition),
|
|
422
|
+
then: thenSteps.map((s) => s.id),
|
|
423
|
+
else: elseSteps.map((s) => s.id),
|
|
424
|
+
});
|
|
425
|
+
steps.push(...thenSteps, ...elseSteps);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return steps;
|
|
429
|
+
}
|
|
430
|
+
/** Transform for loop to loop step */
|
|
431
|
+
transformFor(stmt) {
|
|
432
|
+
const id = this.nextStepId("loop");
|
|
433
|
+
const bodySteps = this.transformStatements(stmt.body);
|
|
434
|
+
return [
|
|
435
|
+
{
|
|
436
|
+
id,
|
|
437
|
+
for: `${stmt.variable} in ${this.exprToString(stmt.iterable)}`,
|
|
438
|
+
steps: bodySteps.map((s) => s.id),
|
|
439
|
+
max: stmt.maxIterations ?? 100,
|
|
440
|
+
},
|
|
441
|
+
...bodySteps,
|
|
442
|
+
];
|
|
443
|
+
}
|
|
444
|
+
/** Transform repeat loop to loop step */
|
|
445
|
+
transformRepeat(stmt) {
|
|
446
|
+
const id = this.nextStepId("loop");
|
|
447
|
+
const bodySteps = this.transformStatements(stmt.body);
|
|
448
|
+
const countValue = this.exprToValue(stmt.count);
|
|
449
|
+
const count = typeof countValue === "number" ? countValue : Number.parseFloat(String(countValue));
|
|
450
|
+
return [
|
|
451
|
+
{
|
|
452
|
+
id,
|
|
453
|
+
repeat: count,
|
|
454
|
+
steps: bodySteps.map((s) => s.id),
|
|
455
|
+
max: count,
|
|
456
|
+
},
|
|
457
|
+
...bodySteps,
|
|
458
|
+
];
|
|
459
|
+
}
|
|
460
|
+
/** Transform until loop to loop step */
|
|
461
|
+
transformUntil(stmt) {
|
|
462
|
+
const id = this.nextStepId("loop");
|
|
463
|
+
const bodySteps = this.transformStatements(stmt.body);
|
|
464
|
+
return [
|
|
465
|
+
{
|
|
466
|
+
id,
|
|
467
|
+
loop: {
|
|
468
|
+
until: this.exprToString(stmt.condition),
|
|
469
|
+
max: stmt.maxIterations ?? 100,
|
|
470
|
+
},
|
|
471
|
+
steps: bodySteps.map((s) => s.id),
|
|
472
|
+
max: stmt.maxIterations ?? 100,
|
|
473
|
+
},
|
|
474
|
+
...bodySteps,
|
|
475
|
+
];
|
|
476
|
+
}
|
|
477
|
+
/** Transform try/catch/finally to try step */
|
|
478
|
+
transformTry(stmt) {
|
|
479
|
+
const id = this.nextStepId("try");
|
|
480
|
+
const trySteps = this.transformStatements(stmt.tryBody);
|
|
481
|
+
const catchBlocks = [];
|
|
482
|
+
const catchSteps = [];
|
|
483
|
+
for (const c of stmt.catches) {
|
|
484
|
+
const steps = this.transformStatements(c.body);
|
|
485
|
+
catchSteps.push(...steps);
|
|
486
|
+
const block = {
|
|
487
|
+
error: c.error,
|
|
488
|
+
steps: steps.map((s) => s.id),
|
|
489
|
+
};
|
|
490
|
+
if (c.action)
|
|
491
|
+
block.action = c.action;
|
|
492
|
+
if (c.retry) {
|
|
493
|
+
block.retry = {
|
|
494
|
+
maxAttempts: c.retry.maxAttempts,
|
|
495
|
+
backoff: c.retry.backoff,
|
|
496
|
+
backoffBase: c.retry.backoffBase,
|
|
497
|
+
maxBackoff: c.retry.maxBackoff,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
catchBlocks.push(block);
|
|
501
|
+
}
|
|
502
|
+
const finallySteps = stmt.finallyBody ? this.transformStatements(stmt.finallyBody) : [];
|
|
503
|
+
return [
|
|
504
|
+
{
|
|
505
|
+
id,
|
|
506
|
+
try: trySteps.map((s) => s.id),
|
|
507
|
+
catch: catchBlocks,
|
|
508
|
+
finally: finallySteps.map((s) => s.id),
|
|
509
|
+
},
|
|
510
|
+
...trySteps,
|
|
511
|
+
...catchSteps,
|
|
512
|
+
...finallySteps,
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
/** Transform parallel block */
|
|
516
|
+
transformParallel(stmt) {
|
|
517
|
+
const id = this.nextStepId("parallel");
|
|
518
|
+
const branches = [];
|
|
519
|
+
const branchSteps = [];
|
|
520
|
+
for (const branch of stmt.branches) {
|
|
521
|
+
const steps = this.transformStatements(branch.body);
|
|
522
|
+
branchSteps.push(...steps);
|
|
523
|
+
branches.push({ name: branch.name, steps: steps.map((s) => s.id) });
|
|
524
|
+
}
|
|
525
|
+
const join = stmt.join
|
|
526
|
+
? {
|
|
527
|
+
type: stmt.join.type,
|
|
528
|
+
metric: stmt.join.metric ? this.exprToString(stmt.join.metric) : undefined,
|
|
529
|
+
order: stmt.join.order,
|
|
530
|
+
count: stmt.join.count,
|
|
531
|
+
}
|
|
532
|
+
: undefined;
|
|
533
|
+
return [
|
|
534
|
+
{
|
|
535
|
+
id,
|
|
536
|
+
parallel: {
|
|
537
|
+
branches,
|
|
538
|
+
join,
|
|
539
|
+
on_fail: stmt.onFail ?? "abort",
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
...branchSteps,
|
|
543
|
+
];
|
|
544
|
+
}
|
|
545
|
+
/** Transform pipeline statement */
|
|
546
|
+
transformPipeline(stmt) {
|
|
547
|
+
const id = this.nextStepId("pipeline");
|
|
548
|
+
const stages = [];
|
|
549
|
+
const stageSteps = [];
|
|
550
|
+
let parallel = false;
|
|
551
|
+
for (const stage of stmt.stages) {
|
|
552
|
+
let op = stage.op === "pmap" ? "map" : stage.op;
|
|
553
|
+
if (op === "where")
|
|
554
|
+
op = "filter";
|
|
555
|
+
if (stage.op === "pmap")
|
|
556
|
+
parallel = true;
|
|
557
|
+
// Stages without step bodies
|
|
558
|
+
if (op === "take" || op === "skip" || op === "sort") {
|
|
559
|
+
const entry = { op };
|
|
560
|
+
if (stage.count !== undefined)
|
|
561
|
+
entry.count = stage.count;
|
|
562
|
+
if (stage.order)
|
|
563
|
+
entry.order = stage.order;
|
|
564
|
+
if (stage.by)
|
|
565
|
+
entry.by = this.exprToString(stage.by);
|
|
566
|
+
stages.push(entry);
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
const steps = this.transformStatement(stage.step);
|
|
570
|
+
if (steps.length === 0)
|
|
571
|
+
continue;
|
|
572
|
+
stageSteps.push(...steps);
|
|
573
|
+
const stepId = steps[0]?.id;
|
|
574
|
+
const entry = { op, step: stepId };
|
|
575
|
+
if (stage.initial) {
|
|
576
|
+
entry.initial = this.exprToString(stage.initial);
|
|
577
|
+
}
|
|
578
|
+
stages.push(entry);
|
|
579
|
+
}
|
|
580
|
+
return [
|
|
581
|
+
{
|
|
582
|
+
id,
|
|
583
|
+
pipeline: {
|
|
584
|
+
source: this.exprToString(stmt.source),
|
|
585
|
+
stages,
|
|
586
|
+
parallel,
|
|
587
|
+
},
|
|
588
|
+
output: stmt.outputBinding,
|
|
589
|
+
},
|
|
590
|
+
...stageSteps,
|
|
591
|
+
];
|
|
592
|
+
}
|
|
593
|
+
/** Transform advise statement */
|
|
594
|
+
transformAdvise(stmt) {
|
|
595
|
+
const id = this.nextStepId("advisory");
|
|
596
|
+
return [
|
|
597
|
+
{
|
|
598
|
+
id,
|
|
599
|
+
advisory: {
|
|
600
|
+
prompt: stmt.prompt,
|
|
601
|
+
advisor: stmt.advisor,
|
|
602
|
+
output: stmt.target,
|
|
603
|
+
timeout: stmt.timeout,
|
|
604
|
+
fallback: this.exprToFallback(stmt.fallback),
|
|
605
|
+
output_schema: this.serializeOutputSchema(stmt.outputSchema),
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
];
|
|
609
|
+
}
|
|
610
|
+
exprToFallback(expr) {
|
|
611
|
+
switch (expr.kind) {
|
|
612
|
+
case "literal":
|
|
613
|
+
case "array_literal":
|
|
614
|
+
case "object_literal":
|
|
615
|
+
case "percentage":
|
|
616
|
+
case "unit_literal":
|
|
617
|
+
return { __literal: this.exprToValue(expr) };
|
|
618
|
+
default:
|
|
619
|
+
return { __expr: this.exprToString(expr) };
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/** Transform block invocation */
|
|
623
|
+
transformDo(stmt) {
|
|
624
|
+
const block = this.blockMap.get(stmt.name);
|
|
625
|
+
if (!block) {
|
|
626
|
+
return [];
|
|
627
|
+
}
|
|
628
|
+
if (block.params.length !== stmt.args.length) {
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
631
|
+
const assignments = block.params.map((param, i) => ({
|
|
632
|
+
kind: "assignment",
|
|
633
|
+
target: param,
|
|
634
|
+
value: stmt.args[i],
|
|
635
|
+
}));
|
|
636
|
+
return this.transformStatements([...assignments, ...block.body]);
|
|
637
|
+
}
|
|
638
|
+
/** Transform atomic block to try step */
|
|
639
|
+
transformAtomic(stmt) {
|
|
640
|
+
const id = this.nextStepId("atomic");
|
|
641
|
+
const bodySteps = this.transformStatements(stmt.body);
|
|
642
|
+
return [
|
|
643
|
+
{
|
|
644
|
+
id,
|
|
645
|
+
try: bodySteps.map((s) => s.id),
|
|
646
|
+
catch: [{ error: "*", action: stmt.onFailure ?? "revert" }],
|
|
647
|
+
},
|
|
648
|
+
...bodySteps,
|
|
649
|
+
];
|
|
650
|
+
}
|
|
651
|
+
/** Transform method call to action step */
|
|
652
|
+
transformMethodCall(stmt) {
|
|
653
|
+
const id = this.nextStepId("action");
|
|
654
|
+
// Determine action type from method name
|
|
655
|
+
const method = stmt.method.toLowerCase();
|
|
656
|
+
let actionType = method;
|
|
657
|
+
// Map common method names to action types
|
|
658
|
+
const methodMap = {
|
|
659
|
+
deposit: "lend",
|
|
660
|
+
supply: "lend",
|
|
661
|
+
borrow: "borrow",
|
|
662
|
+
repay: "repay",
|
|
663
|
+
withdraw: "withdraw",
|
|
664
|
+
stake: "stake",
|
|
665
|
+
unstake: "unstake",
|
|
666
|
+
claim: "claim",
|
|
667
|
+
swap: "swap",
|
|
668
|
+
bridge: "bridge",
|
|
669
|
+
transfer: "transfer",
|
|
670
|
+
get_supply_rates: "query", // Query operations
|
|
671
|
+
get_rates: "query",
|
|
672
|
+
};
|
|
673
|
+
actionType = methodMap[method] ?? method;
|
|
674
|
+
// Build action object
|
|
675
|
+
const action = {
|
|
676
|
+
type: actionType,
|
|
677
|
+
};
|
|
678
|
+
// Extract venue from object
|
|
679
|
+
if (stmt.object.kind === "identifier") {
|
|
680
|
+
action.venue = stmt.object.name;
|
|
681
|
+
}
|
|
682
|
+
else if (stmt.object.kind === "venue_ref_expr") {
|
|
683
|
+
action.venue = stmt.object.name;
|
|
684
|
+
}
|
|
685
|
+
else if (stmt.object.kind === "property_access") {
|
|
686
|
+
// e.g., venues.lending
|
|
687
|
+
const prop = stmt.object;
|
|
688
|
+
if (prop.object.kind === "identifier" && prop.object.name === "venues") {
|
|
689
|
+
action.venue = prop.property;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
// Map arguments based on action type
|
|
693
|
+
if (actionType === "lend" ||
|
|
694
|
+
actionType === "withdraw" ||
|
|
695
|
+
actionType === "repay" ||
|
|
696
|
+
actionType === "stake" ||
|
|
697
|
+
actionType === "unstake") {
|
|
698
|
+
const assetArg = stmt.args[0];
|
|
699
|
+
const amountArg = stmt.args[1];
|
|
700
|
+
if (assetArg) {
|
|
701
|
+
action.asset = this.exprToString(assetArg);
|
|
702
|
+
}
|
|
703
|
+
if (amountArg) {
|
|
704
|
+
action.amount = this.exprToString(amountArg);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
else if (actionType === "borrow") {
|
|
708
|
+
const assetArg = stmt.args[0];
|
|
709
|
+
const amountArg = stmt.args[1];
|
|
710
|
+
const collateralArg = stmt.args[2];
|
|
711
|
+
if (assetArg) {
|
|
712
|
+
action.asset = this.exprToString(assetArg);
|
|
713
|
+
}
|
|
714
|
+
if (amountArg) {
|
|
715
|
+
action.amount = this.exprToString(amountArg);
|
|
716
|
+
}
|
|
717
|
+
if (collateralArg) {
|
|
718
|
+
action.collateral = this.exprToString(collateralArg);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
else if (actionType === "claim") {
|
|
722
|
+
const assetArg = stmt.args[0];
|
|
723
|
+
if (assetArg) {
|
|
724
|
+
action.asset = this.exprToString(assetArg);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
else if (actionType === "bridge") {
|
|
728
|
+
const assetArg = stmt.args[0];
|
|
729
|
+
const amountArg = stmt.args[1];
|
|
730
|
+
const chainArg = stmt.args[2];
|
|
731
|
+
if (assetArg) {
|
|
732
|
+
action.asset = this.exprToString(assetArg);
|
|
733
|
+
}
|
|
734
|
+
if (amountArg) {
|
|
735
|
+
action.amount = this.exprToString(amountArg);
|
|
736
|
+
}
|
|
737
|
+
if (chainArg) {
|
|
738
|
+
action.to_chain = this.exprToString(chainArg);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
else if (actionType === "swap") {
|
|
742
|
+
const assetInArg = stmt.args[0];
|
|
743
|
+
const assetOutArg = stmt.args[1];
|
|
744
|
+
const amountArg = stmt.args[2];
|
|
745
|
+
if (assetInArg && assetOutArg) {
|
|
746
|
+
action.asset_in = this.exprToString(assetInArg);
|
|
747
|
+
action.asset_out = this.exprToString(assetOutArg);
|
|
748
|
+
}
|
|
749
|
+
if (amountArg) {
|
|
750
|
+
action.amount = this.exprToString(amountArg);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
else if (actionType === "transfer") {
|
|
754
|
+
const assetArg = stmt.args[0];
|
|
755
|
+
const amountArg = stmt.args[1];
|
|
756
|
+
const toArg = stmt.args[2];
|
|
757
|
+
if (assetArg) {
|
|
758
|
+
action.asset = this.exprToString(assetArg);
|
|
759
|
+
}
|
|
760
|
+
if (amountArg) {
|
|
761
|
+
action.amount = this.exprToString(amountArg);
|
|
762
|
+
}
|
|
763
|
+
if (toArg) {
|
|
764
|
+
action.to = this.exprToString(toArg);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
else if (actionType === "query") {
|
|
768
|
+
// Query operations become compute steps
|
|
769
|
+
return [
|
|
770
|
+
{
|
|
771
|
+
id,
|
|
772
|
+
compute: {
|
|
773
|
+
[`${id}_result`]: `${this.exprToString(stmt.object)}.${stmt.method}(${stmt.args.map((a) => this.exprToString(a)).join(", ")})`,
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
];
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
// Generic mapping
|
|
780
|
+
stmt.args.forEach((arg, i) => {
|
|
781
|
+
action[`arg${i}`] = this.exprToString(arg);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
const step = {
|
|
785
|
+
id,
|
|
786
|
+
action,
|
|
787
|
+
};
|
|
788
|
+
if (stmt.skill) {
|
|
789
|
+
step.skill = stmt.skill;
|
|
790
|
+
}
|
|
791
|
+
if (stmt.outputBinding) {
|
|
792
|
+
step.output = stmt.outputBinding;
|
|
793
|
+
}
|
|
794
|
+
if (stmt.constraints) {
|
|
795
|
+
const constraints = {};
|
|
796
|
+
for (const { key, value } of stmt.constraints.constraints) {
|
|
797
|
+
const constraintKey = key === "slippage"
|
|
798
|
+
? "max_slippage"
|
|
799
|
+
: key === "min_out"
|
|
800
|
+
? "min_output"
|
|
801
|
+
: key === "max_in"
|
|
802
|
+
? "max_input"
|
|
803
|
+
: key;
|
|
804
|
+
constraints[constraintKey] = this.exprToValue(value);
|
|
805
|
+
}
|
|
806
|
+
step.constraints = constraints;
|
|
807
|
+
}
|
|
808
|
+
return [step];
|
|
809
|
+
}
|
|
810
|
+
/** Transform emit to emit step */
|
|
811
|
+
transformEmit(stmt) {
|
|
812
|
+
const id = this.nextStepId("emit");
|
|
813
|
+
const data = {};
|
|
814
|
+
for (const { key, value } of stmt.data) {
|
|
815
|
+
data[key] = this.exprToString(value);
|
|
816
|
+
}
|
|
817
|
+
return [
|
|
818
|
+
{
|
|
819
|
+
id,
|
|
820
|
+
emit: {
|
|
821
|
+
event: stmt.event,
|
|
822
|
+
data,
|
|
823
|
+
},
|
|
824
|
+
},
|
|
825
|
+
];
|
|
826
|
+
}
|
|
827
|
+
/** Transform halt to halt step */
|
|
828
|
+
transformHalt(stmt) {
|
|
829
|
+
const id = this.nextStepId("halt");
|
|
830
|
+
return [{ id, halt: stmt.reason }];
|
|
831
|
+
}
|
|
832
|
+
/** Transform wait to wait step */
|
|
833
|
+
transformWait(stmt) {
|
|
834
|
+
const id = this.nextStepId("wait");
|
|
835
|
+
return [{ id, wait: stmt.duration }];
|
|
836
|
+
}
|
|
837
|
+
/** Transform advisory */
|
|
838
|
+
transformAdvisory(stmt) {
|
|
839
|
+
const id = this.nextStepId("advisory");
|
|
840
|
+
const thenSteps = this.transformStatements(stmt.thenBody);
|
|
841
|
+
const elseSteps = this.transformStatements(stmt.elseBody);
|
|
842
|
+
const advisorName = stmt.advisor ?? "default";
|
|
843
|
+
const defaults = this.advisorDefaults.get(advisorName);
|
|
844
|
+
return [
|
|
845
|
+
{
|
|
846
|
+
id,
|
|
847
|
+
advisory: {
|
|
848
|
+
prompt: stmt.prompt,
|
|
849
|
+
advisor: advisorName,
|
|
850
|
+
timeout: stmt.timeout ?? defaults?.timeout ?? 30,
|
|
851
|
+
fallback: stmt.fallback ?? defaults?.fallback ?? true,
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
...thenSteps,
|
|
855
|
+
...elseSteps,
|
|
856
|
+
];
|
|
857
|
+
}
|
|
858
|
+
/** Convert expression to string representation */
|
|
859
|
+
exprToString(expr) {
|
|
860
|
+
switch (expr.kind) {
|
|
861
|
+
case "literal": {
|
|
862
|
+
const lit = expr;
|
|
863
|
+
if (lit.literalType === "string") {
|
|
864
|
+
return `"${lit.value}"`;
|
|
865
|
+
}
|
|
866
|
+
return String(lit.value);
|
|
867
|
+
}
|
|
868
|
+
case "identifier":
|
|
869
|
+
return expr.name;
|
|
870
|
+
case "venue_ref_expr":
|
|
871
|
+
return `@${expr.name}`;
|
|
872
|
+
case "advisory_expr":
|
|
873
|
+
return `**${expr.prompt}**`;
|
|
874
|
+
case "percentage":
|
|
875
|
+
return String(expr.value);
|
|
876
|
+
case "unit_literal": {
|
|
877
|
+
const raw = this.unitLiteralToRaw(expr);
|
|
878
|
+
return String(raw);
|
|
879
|
+
}
|
|
880
|
+
case "binary": {
|
|
881
|
+
const bin = expr;
|
|
882
|
+
const op = bin.op === "and" ? "AND" : bin.op === "or" ? "OR" : bin.op;
|
|
883
|
+
return `(${this.exprToString(bin.left)} ${op} ${this.exprToString(bin.right)})`;
|
|
884
|
+
}
|
|
885
|
+
case "unary": {
|
|
886
|
+
const un = expr;
|
|
887
|
+
const op = un.op === "not" ? "NOT " : un.op;
|
|
888
|
+
return `${op}${this.exprToString(un.arg)}`;
|
|
889
|
+
}
|
|
890
|
+
case "call": {
|
|
891
|
+
const call = expr;
|
|
892
|
+
const callee = this.exprToString(call.callee);
|
|
893
|
+
const args = call.args.map((a) => this.exprToString(a)).join(", ");
|
|
894
|
+
return `${callee}(${args})`;
|
|
895
|
+
}
|
|
896
|
+
case "property_access": {
|
|
897
|
+
const prop = expr;
|
|
898
|
+
return `${this.exprToString(prop.object)}.${prop.property}`;
|
|
899
|
+
}
|
|
900
|
+
case "array_access": {
|
|
901
|
+
const arr = expr;
|
|
902
|
+
return `${this.exprToString(arr.array)}[${this.exprToString(arr.index)}]`;
|
|
903
|
+
}
|
|
904
|
+
case "array_literal": {
|
|
905
|
+
const arrLit = expr;
|
|
906
|
+
return `[${arrLit.elements.map((e) => this.exprToString(e)).join(", ")}]`;
|
|
907
|
+
}
|
|
908
|
+
case "object_literal": {
|
|
909
|
+
const objLit = expr;
|
|
910
|
+
const entries = objLit.entries.map((e) => `${e.key}: ${this.exprToString(e.value)}`);
|
|
911
|
+
return `{${entries.join(", ")}}`;
|
|
912
|
+
}
|
|
913
|
+
case "ternary": {
|
|
914
|
+
const tern = expr;
|
|
915
|
+
return `(${this.exprToString(tern.condition)} ? ${this.exprToString(tern.thenExpr)} : ${this.exprToString(tern.elseExpr)})`;
|
|
916
|
+
}
|
|
917
|
+
default:
|
|
918
|
+
return "";
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
/** Convert expression to runtime value */
|
|
922
|
+
exprToValue(expr) {
|
|
923
|
+
switch (expr.kind) {
|
|
924
|
+
case "literal":
|
|
925
|
+
return expr.value;
|
|
926
|
+
case "percentage":
|
|
927
|
+
return expr.value;
|
|
928
|
+
case "unit_literal":
|
|
929
|
+
return this.unitLiteralToRaw(expr);
|
|
930
|
+
case "array_literal":
|
|
931
|
+
return expr.elements.map((e) => this.exprToValue(e));
|
|
932
|
+
case "object_literal": {
|
|
933
|
+
const obj = {};
|
|
934
|
+
for (const entry of expr.entries) {
|
|
935
|
+
obj[entry.key] = this.exprToValue(entry.value);
|
|
936
|
+
}
|
|
937
|
+
return obj;
|
|
938
|
+
}
|
|
939
|
+
case "unary": {
|
|
940
|
+
const un = expr;
|
|
941
|
+
if (un.arg.kind === "literal") {
|
|
942
|
+
const lit = un.arg;
|
|
943
|
+
if (un.op === "-" && typeof lit.value === "number") {
|
|
944
|
+
return -lit.value;
|
|
945
|
+
}
|
|
946
|
+
if (un.op === "not") {
|
|
947
|
+
return !lit.value;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (un.arg.kind === "unit_literal") {
|
|
951
|
+
const raw = this.unitLiteralToRaw(un.arg);
|
|
952
|
+
if (un.op === "-") {
|
|
953
|
+
return -raw;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return this.exprToString(expr);
|
|
957
|
+
}
|
|
958
|
+
default:
|
|
959
|
+
// For expressions, return string representation
|
|
960
|
+
return this.exprToString(expr);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
/** Generate next step ID */
|
|
964
|
+
nextStepId(prefix) {
|
|
965
|
+
return `${prefix}_${++this.stepCounter}`;
|
|
966
|
+
}
|
|
967
|
+
unitLiteralToRaw(expr) {
|
|
968
|
+
const unit = expr.unit;
|
|
969
|
+
if (unit === "bps" || unit === "bp") {
|
|
970
|
+
return expr.value;
|
|
971
|
+
}
|
|
972
|
+
if (!this.assetDecimals.has(unit)) {
|
|
973
|
+
throw new Error(`Unknown asset '${unit}' for unit literal`);
|
|
974
|
+
}
|
|
975
|
+
const decimals = this.assetDecimals.get(unit);
|
|
976
|
+
if (decimals === undefined) {
|
|
977
|
+
throw new Error(`Asset '${unit}' is missing decimals for unit literal conversion`);
|
|
978
|
+
}
|
|
979
|
+
const multiplier = 10 ** decimals;
|
|
980
|
+
return Math.floor(expr.value * multiplier);
|
|
981
|
+
}
|
|
982
|
+
serializeOutputSchema(schema) {
|
|
983
|
+
const fields = schema.fields &&
|
|
984
|
+
Object.fromEntries(Object.entries(schema.fields).map(([key, value]) => [
|
|
985
|
+
key,
|
|
986
|
+
this.serializeOutputSchema(value),
|
|
987
|
+
]));
|
|
988
|
+
return {
|
|
989
|
+
type: schema.type,
|
|
990
|
+
values: schema.values,
|
|
991
|
+
min: schema.min,
|
|
992
|
+
max: schema.max,
|
|
993
|
+
min_length: schema.minLength,
|
|
994
|
+
max_length: schema.maxLength,
|
|
995
|
+
pattern: schema.pattern,
|
|
996
|
+
fields,
|
|
997
|
+
items: schema.items ? this.serializeOutputSchema(schema.items) : undefined,
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
// =============================================================================
|
|
1002
|
+
// PUBLIC API
|
|
1003
|
+
// =============================================================================
|
|
1004
|
+
/**
|
|
1005
|
+
* Transform Grimoire AST to SpellSource
|
|
1006
|
+
*/
|
|
1007
|
+
export function transform(ast, options) {
|
|
1008
|
+
const transformer = new Transformer();
|
|
1009
|
+
return transformer.transform(ast, options);
|
|
1010
|
+
}
|
|
1011
|
+
//# sourceMappingURL=transformer.js.map
|