Skip to main content

chomsky_uir/
builder.rs

1use crate::egraph::{Analysis, EGraph, Id};
2use crate::intent::{CrossLanguageCall, IKun};
3use chomsky_types::Loc;
4
5pub struct IntentBuilder<'a, A: Analysis<IKun>> {
6    pub egraph: &'a mut EGraph<IKun, A>,
7}
8
9impl<'a, A: Analysis<IKun>> IntentBuilder<'a, A> {
10    pub fn new(egraph: &'a mut EGraph<IKun, A>) -> Self {
11        Self { egraph }
12    }
13
14    /// Add a raw IKun node to the graph with location
15    pub fn add(&mut self, node: IKun, loc: Loc) -> Id {
16        self.egraph.add_with_loc(node, loc)
17    }
18
19    // --- Basic Atoms ---
20
21    pub fn constant(&mut self, v: i64, loc: Loc) -> Id {
22        self.add(IKun::Constant(v), loc)
23    }
24
25    pub fn int(&mut self, v: i64, loc: Loc) -> Id {
26        self.constant(v, loc)
27    }
28
29    pub fn float(&mut self, v: f64, loc: Loc) -> Id {
30        self.add(IKun::FloatConstant(v.to_bits()), loc)
31    }
32
33    pub fn bool(&mut self, v: bool, loc: Loc) -> Id {
34        self.add(IKun::BooleanConstant(v), loc)
35    }
36
37    pub fn none(&mut self, loc: Loc) -> Id {
38        self.add(IKun::None, loc)
39    }
40
41    pub fn string(&mut self, s: &str, loc: Loc) -> Id {
42        self.add(IKun::StringConstant(s.to_string()), loc)
43    }
44
45    pub fn symbol(&mut self, s: &str, loc: Loc) -> Id {
46        self.add(IKun::Symbol(s.to_string()), loc)
47    }
48
49    pub fn import(&mut self, module: &str, name: &str, loc: Loc) -> Id {
50        self.add(IKun::Import(module.to_string(), name.to_string()), loc)
51    }
52
53    pub fn export(&mut self, name: &str, body: Id, loc: Loc) -> Id {
54        self.add(IKun::Export(name.to_string(), body), loc)
55    }
56
57    // --- Structure ---
58
59    pub fn seq(&mut self, items: Vec<Id>, loc: Loc) -> Id {
60        self.add(IKun::Seq(items), loc)
61    }
62
63    pub fn map(&mut self, f: Id, input: Id, loc: Loc) -> Id {
64        self.add(IKun::Map(f, input), loc)
65    }
66
67    pub fn reduce(&mut self, f: Id, init: Id, list: Id, loc: Loc) -> Id {
68        self.add(IKun::Reduce(f, init, list), loc)
69    }
70
71    pub fn filter(&mut self, f: Id, input: Id, loc: Loc) -> Id {
72        self.add(IKun::Filter(f, input), loc)
73    }
74
75    pub fn call(&mut self, func: Id, args: Vec<Id>, loc: Loc) -> Id {
76        self.add(IKun::Apply(func, args), loc)
77    }
78
79    pub fn lambda(&mut self, params: Vec<String>, body: Id, loc: Loc) -> Id {
80        self.add(IKun::Lambda(params, body), loc)
81    }
82
83    pub fn assign(&mut self, name: &str, value: Id, loc: Loc) -> Id {
84        let sym = self.symbol(name, loc);
85        self.add(IKun::StateUpdate(sym, value), loc)
86    }
87
88    pub fn assign_to_id(&mut self, target: Id, value: Id, loc: Loc) -> Id {
89        self.add(IKun::StateUpdate(target, value), loc)
90    }
91
92    pub fn block(&mut self, stmts: Vec<Id>, loc: Loc) -> Id {
93        self.seq(stmts, loc)
94    }
95
96    pub fn module(&mut self, name: &str, items: Vec<Id>, loc: Loc) -> Id {
97        self.add(IKun::Module(name.to_string(), items), loc)
98    }
99
100    // --- Control Flow ---
101
102    pub fn branch(&mut self, cond: Id, then_branch: Id, else_branch: Id, loc: Loc) -> Id {
103        self.add(IKun::Choice(cond, then_branch, else_branch), loc)
104    }
105
106    pub fn if_(&mut self, cond: Id, then_branch: Id, else_branch: Option<Id>, loc: Loc) -> Id {
107        let else_id = else_branch.unwrap_or_else(|| self.block(vec![], loc));
108        self.branch(cond, then_branch, else_id, loc)
109    }
110
111    pub fn loop_(&mut self, count: Id, body: Id, loc: Loc) -> Id {
112        self.add(IKun::Repeat(count, body), loc)
113    }
114
115    pub fn while_loop(&mut self, cond: Id, body: Id, loc: Loc) -> Id {
116        // While loop is a bit complex in pure functional IKun, usually represented as
117        // Repeat(Inf, Choice(cond, body, Break)) or similar.
118        // For now, let's map it to an Extension "while" or just use Repeat if semantic allows.
119        // But IKun::Repeat takes a count.
120        // Let's use Extension for "while" for now until we have a proper construct.
121        self.extension("while", vec![cond, body], loc)
122    }
123
124    pub fn while_(&mut self, cond: Id, body: Id, loc: Loc) -> Id {
125        self.while_loop(cond, body, loc)
126    }
127
128    pub fn break_(&mut self, loc: Loc) -> Id {
129        self.extension("break", vec![], loc)
130    }
131
132    pub fn continue_(&mut self, loc: Loc) -> Id {
133        self.extension("continue", vec![], loc)
134    }
135
136    pub fn return_(&mut self, value: Id, loc: Loc) -> Id {
137        self.add(IKun::Return(value), loc)
138    }
139
140    pub fn cross_lang_call(
141        &mut self,
142        lang: &str,
143        group: &str,
144        func: &str,
145        args: Vec<Id>,
146        loc: Loc,
147    ) -> Id {
148        self.add(
149            IKun::CrossLangCall(CrossLanguageCall {
150                language: lang.to_string(),
151                module_path: group.to_string(),
152                function_name: func.to_string(),
153                arguments: args,
154            }),
155            loc,
156        )
157    }
158
159    // --- Operations ---
160
161    pub fn extension(&mut self, name: &str, args: Vec<Id>, loc: Loc) -> Id {
162        self.add(IKun::Extension(name.to_string(), args), loc)
163    }
164
165    pub fn binary_op(&mut self, op: &str, left: Id, right: Id, loc: Loc) -> Id {
166        self.add(IKun::BinaryOp(op.to_string(), left, right), loc)
167    }
168
169    pub fn unary_op(&mut self, op: &str, operand: Id, loc: Loc) -> Id {
170        self.add(IKun::UnaryOp(op.to_string(), operand), loc)
171    }
172
173    pub fn address_of(&mut self, target: Id, loc: Loc) -> Id {
174        self.add(IKun::AddrOf(target), loc)
175    }
176
177    pub fn deref(&mut self, pointer: Id, loc: Loc) -> Id {
178        self.add(IKun::Deref(pointer), loc)
179    }
180
181    pub fn ptr_offset(&mut self, base: Id, offset: Id, loc: Loc) -> Id {
182        self.add(IKun::PtrOffset(base, offset), loc)
183    }
184
185    pub fn class_def(&mut self, name: &str, bases: Vec<Id>, body: Id, loc: Loc) -> Id {
186        self.add(IKun::ClassDef(name.to_string(), bases, body), loc)
187    }
188
189    pub fn table(&mut self, pairs: Vec<Id>, loc: Loc) -> Id {
190        self.add(IKun::Table(pairs), loc)
191    }
192
193    pub fn pair(&mut self, key: Id, value: Id, loc: Loc) -> Id {
194        self.add(IKun::Pair(key, value), loc)
195    }
196
197    pub fn get_index(&mut self, receiver: Id, index: Id, loc: Loc) -> Id {
198        self.add(IKun::GetIndex(receiver, index), loc)
199    }
200
201    pub fn set_index(&mut self, receiver: Id, index: Id, value: Id, loc: Loc) -> Id {
202        self.add(IKun::SetIndex(receiver, index, value), loc)
203    }
204
205    pub fn add_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
206        self.binary_op("add", left, right, loc)
207    }
208
209    pub fn sub_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
210        self.binary_op("sub", left, right, loc)
211    }
212
213    pub fn mul_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
214        self.binary_op("mul", left, right, loc)
215    }
216
217    pub fn div_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
218        self.binary_op("div", left, right, loc)
219    }
220
221    pub fn eq_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
222        self.binary_op("eq", left, right, loc)
223    }
224
225    pub fn ne_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
226        self.binary_op("ne", left, right, loc)
227    }
228
229    pub fn lt_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
230        self.binary_op("lt", left, right, loc)
231    }
232
233    pub fn le_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
234        self.binary_op("le", left, right, loc)
235    }
236
237    pub fn gt_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
238        self.binary_op("gt", left, right, loc)
239    }
240
241    pub fn ge_op(&mut self, left: Id, right: Id, loc: Loc) -> Id {
242        self.binary_op("ge", left, right, loc)
243    }
244
245    pub fn neg_op(&mut self, val: Id, loc: Loc) -> Id {
246        self.extension("neg", vec![val], loc)
247    }
248
249    pub fn not_op(&mut self, val: Id, loc: Loc) -> Id {
250        self.extension("not", vec![val], loc)
251    }
252
253    pub fn len_op(&mut self, val: Id, loc: Loc) -> Id {
254        self.extension("len", vec![val], loc)
255    }
256
257    pub fn bit_not_op(&mut self, val: Id, loc: Loc) -> Id {
258        self.extension("bit_not", vec![val], loc)
259    }
260
261    pub fn get_index_ext(&mut self, obj: Id, key: Id, loc: Loc) -> Id {
262        self.extension("get_index", vec![obj, key], loc)
263    }
264
265    pub fn set_index_ext(&mut self, obj: Id, key: Id, val: Id, loc: Loc) -> Id {
266        self.extension("set_index", vec![obj, key, val], loc)
267    }
268
269    pub fn parameter(&mut self, name: &str, _loc: Loc) -> String {
270        name.to_string()
271    }
272
273    pub fn function(&mut self, name: &str, params: Vec<String>, body: Vec<Id>, loc: Loc) -> Id {
274        let body_seq = self.block(body, loc.clone());
275        let lam = self.lambda(params, body_seq, loc.clone());
276        if name == "anonymous" {
277            lam
278        } else {
279            self.assign(name, lam, loc)
280        }
281    }
282
283    // --- Resource Management ---
284
285    pub fn resource_clone(&mut self, target: Id, loc: Loc) -> Id {
286        self.add(IKun::ResourceClone(target), loc)
287    }
288
289    pub fn resource_drop(&mut self, target: Id, loc: Loc) -> Id {
290        self.add(IKun::ResourceDrop(target), loc)
291    }
292
293    pub fn resource_context(&mut self, loc: Loc) -> Id {
294        self.add(IKun::ResourceContext, loc)
295    }
296}