wlambda/
ops.rs

1// Copyright (c) 2020-2022 Weird Constructor <weirdconstructor@gmail.com>
2// This is a part of WLambda. See README.md and COPYING for details.
3
4/*!
5Implements the VM program and ops data structures for WLambda.
6*/
7
8use crate::vval::*;
9use crate::compiler::*;
10use crate::nvec::NVec;
11use crate::str_int::*;
12use std::fmt;
13use std::fmt::{Debug};
14use std::rc::Rc;
15
16#[derive(Clone, Default)]
17pub struct Prog {
18    pub debug:     std::vec::Vec<Option<SynPos>>,
19    pub data:      std::vec::Vec<VVal>,
20    pub(crate) ops:       std::vec::Vec<Op>,
21    pub nxt_debug: Option<SynPos>,
22}
23
24fn patch_respos_data(rp: &mut ResPos, idx: u16) {
25    match rp {
26        ResPos::Data(i)         => { *i += idx; },
27        ResPos::Global(i)       => { *i += idx; },
28        ResPos::GlobalRef(i)    => { *i += idx; },
29        ResPos::Local(_)
30        | ResPos::LocalRef(_)
31        | ResPos::Up(_)
32        | ResPos::UpRef(_)
33        | ResPos::Arg(_)
34        | ResPos::Stack(_)
35        | ResPos::Value(_)
36            => (),
37    }
38}
39
40impl Prog {
41    pub(crate) fn append(&mut self, mut prog: Prog) {
42        let self_data_next_idx : u16 = self.data.len() as u16;
43
44        for o in prog.ops.iter_mut() {
45            match o {
46                Op::Add(p1, p2, p3) => {
47                    patch_respos_data(p1, self_data_next_idx);
48                    patch_respos_data(p2, self_data_next_idx);
49                    patch_respos_data(p3, self_data_next_idx);
50                },
51                Op::Sub(p1, p2, p3) => {
52                    patch_respos_data(p1, self_data_next_idx);
53                    patch_respos_data(p2, self_data_next_idx);
54                    patch_respos_data(p3, self_data_next_idx);
55                },
56                Op::Mul(p1, p2, p3) => {
57                    patch_respos_data(p1, self_data_next_idx);
58                    patch_respos_data(p2, self_data_next_idx);
59                    patch_respos_data(p3, self_data_next_idx);
60                },
61                Op::Div(p1, p2, p3) => {
62                    patch_respos_data(p1, self_data_next_idx);
63                    patch_respos_data(p2, self_data_next_idx);
64                    patch_respos_data(p3, self_data_next_idx);
65                },
66                Op::Mod(p1, p2, p3) => {
67                    patch_respos_data(p1, self_data_next_idx);
68                    patch_respos_data(p2, self_data_next_idx);
69                    patch_respos_data(p3, self_data_next_idx);
70                },
71                Op::Le(p1, p2, p3) => {
72                    patch_respos_data(p1, self_data_next_idx);
73                    patch_respos_data(p2, self_data_next_idx);
74                    patch_respos_data(p3, self_data_next_idx);
75                },
76                Op::Lt(p1, p2, p3) => {
77                    patch_respos_data(p1, self_data_next_idx);
78                    patch_respos_data(p2, self_data_next_idx);
79                    patch_respos_data(p3, self_data_next_idx);
80                },
81                Op::Ge(p1, p2, p3) => {
82                    patch_respos_data(p1, self_data_next_idx);
83                    patch_respos_data(p2, self_data_next_idx);
84                    patch_respos_data(p3, self_data_next_idx);
85                },
86                Op::Gt(p1, p2, p3) => {
87                    patch_respos_data(p1, self_data_next_idx);
88                    patch_respos_data(p2, self_data_next_idx);
89                    patch_respos_data(p3, self_data_next_idx);
90                },
91                Op::Eq(p1, p2, p3) => {
92                    patch_respos_data(p1, self_data_next_idx);
93                    patch_respos_data(p2, self_data_next_idx);
94                    patch_respos_data(p3, self_data_next_idx);
95                },
96                Op::NewPair(p1, p2, p3) => {
97                    patch_respos_data(p1, self_data_next_idx);
98                    patch_respos_data(p2, self_data_next_idx);
99                    patch_respos_data(p3, self_data_next_idx);
100                },
101                Op::NewOpt(p1, p2) => {
102                    patch_respos_data(p1, self_data_next_idx);
103                    patch_respos_data(p2, self_data_next_idx);
104                },
105                Op::NewIter(p1, p2) => {
106                    patch_respos_data(p1, self_data_next_idx);
107                    patch_respos_data(p2, self_data_next_idx);
108                },
109                Op::NewNVec(vec, p1) => {
110                    use std::borrow::BorrowMut;
111                    match vec.borrow_mut() {
112                        NVecPos::IVec2(a, b) => {
113                            patch_respos_data(a, self_data_next_idx);
114                            patch_respos_data(b, self_data_next_idx);
115                        },
116                        NVecPos::IVec3(a, b, c) => {
117                            patch_respos_data(a, self_data_next_idx);
118                            patch_respos_data(b, self_data_next_idx);
119                            patch_respos_data(c, self_data_next_idx);
120                        },
121                        NVecPos::IVec4(a, b, c, d) => {
122                            patch_respos_data(a, self_data_next_idx);
123                            patch_respos_data(b, self_data_next_idx);
124                            patch_respos_data(c, self_data_next_idx);
125                            patch_respos_data(d, self_data_next_idx);
126                        },
127                        NVecPos::FVec2(a, b) => {
128                            patch_respos_data(a, self_data_next_idx);
129                            patch_respos_data(b, self_data_next_idx);
130                        },
131                        NVecPos::FVec3(a, b, c) => {
132                            patch_respos_data(a, self_data_next_idx);
133                            patch_respos_data(b, self_data_next_idx);
134                            patch_respos_data(c, self_data_next_idx);
135                        },
136                        NVecPos::FVec4(a, b, c, d) => {
137                            patch_respos_data(a, self_data_next_idx);
138                            patch_respos_data(b, self_data_next_idx);
139                            patch_respos_data(c, self_data_next_idx);
140                            patch_respos_data(d, self_data_next_idx);
141                        },
142                    }
143                    patch_respos_data(p1, self_data_next_idx);
144                },
145                Op::Mov(p1, p2) => {
146                    patch_respos_data(p1, self_data_next_idx);
147                    patch_respos_data(p2, self_data_next_idx);
148                },
149                Op::ToRef(p1, p2, _) => {
150                    patch_respos_data(p1, self_data_next_idx);
151                    patch_respos_data(p2, self_data_next_idx);
152                },
153                Op::NewErr(p1, p2) => {
154                    patch_respos_data(p1, self_data_next_idx);
155                    patch_respos_data(p2, self_data_next_idx);
156                },
157                Op::NewClos(p1, p2) => {
158                    patch_respos_data(p1, self_data_next_idx);
159                    patch_respos_data(p2, self_data_next_idx);
160                },
161                Op::ListPush(p1, p2, p3) => {
162                    patch_respos_data(p1, self_data_next_idx);
163                    patch_respos_data(p2, self_data_next_idx);
164                    patch_respos_data(p3, self_data_next_idx);
165                },
166                Op::ListSplice(p1, p2, p3) => {
167                    patch_respos_data(p1, self_data_next_idx);
168                    patch_respos_data(p2, self_data_next_idx);
169                    patch_respos_data(p3, self_data_next_idx);
170                },
171                Op::MapSetKey(p1, p2, p3, p4) => {
172                    patch_respos_data(p1, self_data_next_idx);
173                    patch_respos_data(p2, self_data_next_idx);
174                    patch_respos_data(p3, self_data_next_idx);
175                    patch_respos_data(p4, self_data_next_idx);
176                },
177                Op::MapSplice(p1, p2, p3) => {
178                    patch_respos_data(p1, self_data_next_idx);
179                    patch_respos_data(p2, self_data_next_idx);
180                    patch_respos_data(p3, self_data_next_idx);
181                },
182                Op::JmpIfN(p1, _) => {
183                    patch_respos_data(p1, self_data_next_idx);
184                },
185                Op::OrJmp(p1, _, p2, _) => {
186                    patch_respos_data(p1, self_data_next_idx);
187                    patch_respos_data(p2, self_data_next_idx);
188                },
189                Op::AndJmp(p1, _, p2) => {
190                    patch_respos_data(p1, self_data_next_idx);
191                    patch_respos_data(p2, self_data_next_idx);
192                },
193                Op::JmpTbl(p1, _) => {
194                    patch_respos_data(p1, self_data_next_idx);
195                },
196                Op::GetIdx(p1, _, _) => {
197                    patch_respos_data(p1, self_data_next_idx);
198                },
199                Op::GetIdx2(p1, _, _) => {
200                    patch_respos_data(p1, self_data_next_idx);
201                },
202                Op::GetIdx3(p1, _, _) => {
203                    patch_respos_data(p1, self_data_next_idx);
204                },
205                Op::GetSym(p1, _, _) => {
206                    patch_respos_data(p1, self_data_next_idx);
207                },
208                Op::GetSym2(p1, _, _) => {
209                    patch_respos_data(p1, self_data_next_idx);
210                },
211                Op::GetSym3(p1, _, _) => {
212                    patch_respos_data(p1, self_data_next_idx);
213                },
214                Op::GetKey(p1, p2, _) => {
215                    patch_respos_data(p1, self_data_next_idx);
216                    patch_respos_data(p2, self_data_next_idx);
217                },
218                Op::Destr(p1, _) => {
219                    patch_respos_data(p1, self_data_next_idx);
220                },
221                Op::Call(_, p1) => {
222                    patch_respos_data(p1, self_data_next_idx);
223                },
224                Op::CallDirect(fun) => {
225                    patch_respos_data(
226                        &mut Rc::get_mut(fun).expect("only rc").arg,
227                        self_data_next_idx);
228                    patch_respos_data(
229                        &mut Rc::get_mut(fun).expect("only rc").res,
230                        self_data_next_idx);
231                },
232                Op::CallMethodKey(p1, p2, _, p3) => {
233                    patch_respos_data(p1, self_data_next_idx);
234                    patch_respos_data(p2, self_data_next_idx);
235                    patch_respos_data(p3, self_data_next_idx);
236                },
237                Op::CallMethodSym(p1, _, p2) => {
238                    patch_respos_data(p1, self_data_next_idx);
239                    patch_respos_data(p2, self_data_next_idx);
240                },
241                Op::Apply(p1, p2, p3) => {
242                    patch_respos_data(p1, self_data_next_idx);
243                    patch_respos_data(p2, self_data_next_idx);
244                    patch_respos_data(p3, self_data_next_idx);
245                },
246                Op::Builtin(Builtin::Export(_, p1)) => {
247                    patch_respos_data(p1, self_data_next_idx);
248                },
249                Op::CtrlFlow(CtrlFlow::Break(p1)) => {
250                    patch_respos_data(p1, self_data_next_idx);
251                },
252                Op::IterInit(p1, _) => {
253                    patch_respos_data(p1, self_data_next_idx);
254                },
255                Op::IterNext(p1) => {
256                    patch_respos_data(p1, self_data_next_idx);
257                },
258//                Op::UnwindMov(p1, p2) => {
259//                    patch_respos_data(p1, self_data_next_idx);
260//                    patch_respos_data(p2, self_data_next_idx);
261//                },
262                Op::NewMap(p1)    => { patch_respos_data(p1, self_data_next_idx); },
263                Op::NewList(p1)   => { patch_respos_data(p1, self_data_next_idx); },
264                Op::Argv(p1)      => { patch_respos_data(p1, self_data_next_idx); },
265                Op::End
266                | Op::Builtin(Builtin::DumpStack(_))
267                | Op::Builtin(Builtin::DumpVM(_))
268                | Op::CtrlFlow(CtrlFlow::Next)
269                | Op::Unwind
270                | Op::Accumulator(_)
271                | Op::PushLoopInfo(_)
272                | Op::Jmp(_)
273                | Op::ClearLocals(_, _)
274                    => (),
275            }
276        }
277
278        self.debug.append(&mut prog.debug);
279        self.data.append(&mut prog.data);
280        self.ops.append(&mut prog.ops);
281    }
282
283    pub(crate) fn op_count(&self) -> usize { self.ops.len() }
284
285    pub(crate) fn new() -> Self {
286        Self {
287            data:       vec![],
288            ops:        vec![],
289            debug:      vec![],
290            nxt_debug:  None,
291        }
292    }
293
294    pub(crate) fn global_ref_pos(&mut self, data: VVal) -> ResPos {
295        self.data.push(data);
296        ResPos::GlobalRef((self.data.len() - 1) as u16)
297    }
298
299    pub(crate) fn global_pos(&mut self, data: VVal) -> ResPos {
300        self.data.push(data);
301        ResPos::Global((self.data.len() - 1) as u16)
302    }
303
304    pub(crate) fn data_pos(&mut self, data: VVal) -> ResPos {
305        self.data.push(data);
306        ResPos::Data((self.data.len() - 1) as u16)
307    }
308
309//    fn unshift_op(&mut self, o: Op) -> &mut Self {
310//        self.ops.insert(0, o);
311//        self.debug.insert(0, std::mem::replace(&mut self.nxt_debug, None));
312//        self
313//    }
314
315    pub(crate) fn push_op(&mut self, o: Op) -> &mut Self {
316        self.ops.push(o);
317        self.debug.push(std::mem::replace(&mut self.nxt_debug, None));
318        self
319    }
320
321    pub(crate) fn set_dbg(&mut self, sp: SynPos) -> &mut Self {
322        self.nxt_debug = Some(sp);
323        self
324    }
325
326    pub(crate) fn op_end(&mut self) -> &mut Self {
327        self.push_op(Op::End);
328        self
329    }
330
331    pub(crate) fn op_mov(&mut self, sp: &SynPos, a: ResPos, r: ResPos) {
332        self.set_dbg(sp.clone());
333        self.push_op(Op::Mov(a, r));
334    }
335
336    pub(crate) fn op_and_jmp(&mut self, sp: &SynPos, a: ResPos, jmp: i32, r: ResPos) {
337        self.set_dbg(sp.clone());
338        self.push_op(Op::AndJmp(a, jmp, r));
339    }
340
341    pub(crate) fn op_or_jmp_mode(&mut self, sp: &SynPos, a: ResPos, jmp: i32, r: ResPos, mode: OrMode) {
342        self.set_dbg(sp.clone());
343        self.push_op(Op::OrJmp(a, jmp, r, mode));
344    }
345
346    pub(crate) fn op_jmp_tbl(&mut self, sp: &SynPos, a: ResPos, tbl: Vec<i32>) {
347        self.set_dbg(sp.clone());
348        self.push_op(Op::JmpTbl(a, Box::new(tbl)));
349    }
350
351    pub(crate) fn op_destr(&mut self, sp: &SynPos, a: ResPos, destr_info: DestructureInfo) {
352        self.set_dbg(sp.clone());
353        self.push_op(Op::Destr(a, Box::new(destr_info)));
354    }
355
356    pub(crate) fn op_to_ref(&mut self, sp: &SynPos, a: ResPos, r: ResPos, typ: ToRefType) {
357        self.set_dbg(sp.clone());
358        self.push_op(Op::ToRef(a, r, typ));
359    }
360
361    pub(crate) fn op_new_list(&mut self, sp: &SynPos, r: ResPos) {
362        self.set_dbg(sp.clone());
363        self.push_op(Op::NewList(r));
364    }
365
366    pub(crate) fn op_list_splice(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
367        self.set_dbg(sp.clone());
368        self.push_op(Op::ListSplice(a, b, r));
369    }
370
371    pub(crate) fn op_list_push(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
372        self.set_dbg(sp.clone());
373        self.push_op(Op::ListPush(a, b, r));
374    }
375
376    pub(crate) fn op_new_map(&mut self, sp: &SynPos, r: ResPos) {
377        self.set_dbg(sp.clone());
378        self.push_op(Op::NewMap(r));
379    }
380
381    pub(crate) fn op_map_set_key(&mut self, sp: &SynPos, a: ResPos, b: ResPos, c: ResPos, r: ResPos) {
382        self.set_dbg(sp.clone());
383        self.push_op(Op::MapSetKey(a, b, c, r));
384    }
385
386    pub(crate) fn op_map_splice(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
387        self.set_dbg(sp.clone());
388        self.push_op(Op::MapSplice(a, b, r));
389    }
390
391    pub(crate) fn op_get_key(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
392        self.set_dbg(sp.clone());
393        self.push_op(Op::GetKey(a, b, r));
394    }
395
396    pub(crate) fn op_get_idx(&mut self, sp: &SynPos, a: ResPos, i: u32, r: ResPos) {
397        self.set_dbg(sp.clone());
398        self.push_op(Op::GetIdx(a, i, r));
399    }
400
401    pub(crate) fn op_get_idx2(&mut self, sp: &SynPos, a: ResPos, i: u32, i2: u32, r: ResPos) {
402        self.set_dbg(sp.clone());
403        self.push_op(Op::GetIdx2(a, Box::new((i, i2)), r));
404    }
405
406    pub(crate) fn op_get_idx3(&mut self, sp: &SynPos, a: ResPos, i: u32, i2: u32, i3: u32, r: ResPos) {
407        self.set_dbg(sp.clone());
408        self.push_op(Op::GetIdx3(a, Box::new((i, i2, i3)), r));
409    }
410
411    pub(crate) fn op_get_sym(&mut self, sp: &SynPos, a: ResPos, s: Symbol, r: ResPos) {
412        self.set_dbg(sp.clone());
413        self.push_op(Op::GetSym(a, Box::new(s), r));
414    }
415
416    pub(crate) fn op_get_sym2(&mut self, sp: &SynPos, a: ResPos, s: Symbol, s2: Symbol, r: ResPos) {
417        self.set_dbg(sp.clone());
418        self.push_op(Op::GetSym2(a, Box::new((s, s2)), r));
419    }
420
421    pub(crate) fn op_get_sym3(&mut self, sp: &SynPos, a: ResPos, s: Symbol, s2: Symbol, s3: Symbol, r: ResPos) {
422        self.set_dbg(sp.clone());
423        self.push_op(Op::GetSym3(a, Box::new((s, s2, s3)), r));
424    }
425
426    pub(crate) fn op_new_err(&mut self, sp: &SynPos, a: ResPos, r: ResPos) {
427        self.set_dbg(sp.clone());
428        self.push_op(Op::NewErr(a, r));
429    }
430
431    pub(crate) fn op_argv(&mut self, sp: &SynPos, r: ResPos) {
432        self.set_dbg(sp.clone());
433        self.push_op(Op::Argv(r));
434    }
435
436    pub(crate) fn op_unwind(&mut self, sp: &SynPos) {
437        self.set_dbg(sp.clone());
438        self.push_op(Op::Unwind);
439    }
440
441    pub(crate) fn op_binop(&mut self, sp: &SynPos, op: BinOp, a: ResPos, b: ResPos, r: ResPos) {
442        self.set_dbg(sp.clone());
443        self.push_op(op.to_op(a, b, r));
444    }
445
446    pub(crate) fn op_new_opt(&mut self, sp: &SynPos, a: ResPos, r: ResPos) {
447        self.set_dbg(sp.clone());
448        self.push_op(Op::NewOpt(a, r));
449    }
450
451    pub(crate) fn op_new_iter(&mut self, sp: &SynPos, a: ResPos, r: ResPos) {
452        self.set_dbg(sp.clone());
453        self.push_op(Op::NewIter(a, r));
454    }
455
456    pub(crate) fn op_new_clos(&mut self, sp: &SynPos, a: ResPos, r: ResPos) {
457        self.set_dbg(sp.clone());
458        self.push_op(Op::NewClos(a, r));
459    }
460
461    pub(crate) fn op_call_method_key(&mut self, sp: &SynPos, a: ResPos, b: ResPos, argc: u16, r: ResPos) {
462        self.set_dbg(sp.clone());
463        self.push_op(Op::CallMethodKey(a, b, argc, r));
464    }
465
466    pub(crate) fn op_call_method_sym(&mut self, sp: &SynPos, a: ResPos, sym: String, argc: u16, r: ResPos) {
467        self.set_dbg(sp.clone());
468        self.push_op(Op::CallMethodSym(a, Box::new((sym, argc)), r));
469    }
470
471    pub(crate) fn op_call_direct(&mut self, sp: &SynPos, a: ResPos, mut fun: DirectFun, r: ResPos) {
472        self.set_dbg(sp.clone());
473        fun.arg = a;
474        fun.res = r;
475        self.push_op(Op::CallDirect(Rc::new(fun)));
476    }
477
478    pub(crate) fn op_call(&mut self, sp: &SynPos, argc: u16, r: ResPos) {
479        self.set_dbg(sp.clone());
480        self.push_op(Op::Call(argc, r));
481    }
482
483    pub(crate) fn op_new_ivec2(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
484        self.set_dbg(sp.clone());
485        self.push_op(Op::NewNVec(Box::new(NVecPos::IVec2(a, b)), r));
486    }
487
488    pub(crate) fn op_new_ivec3(&mut self, sp: &SynPos, a: ResPos, b: ResPos, c: ResPos, r: ResPos) {
489        self.set_dbg(sp.clone());
490        self.push_op(Op::NewNVec(Box::new(NVecPos::IVec3(a, b, c)), r));
491    }
492
493    #[allow(clippy::many_single_char_names)]
494    pub(crate) fn op_new_ivec4(&mut self, sp: &SynPos, a: ResPos, b: ResPos, c: ResPos, d: ResPos, r: ResPos) {
495        self.set_dbg(sp.clone());
496        self.push_op(Op::NewNVec(Box::new(NVecPos::IVec4(a, b, c, d)), r));
497    }
498
499    pub(crate) fn op_new_fvec2(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
500        self.set_dbg(sp.clone());
501        self.push_op(Op::NewNVec(Box::new(NVecPos::FVec2(a, b)), r));
502    }
503
504    pub(crate) fn op_new_fvec3(&mut self, sp: &SynPos, a: ResPos, b: ResPos, c: ResPos, r: ResPos) {
505        self.set_dbg(sp.clone());
506        self.push_op(Op::NewNVec(Box::new(NVecPos::FVec3(a, b, c)), r));
507    }
508
509    #[allow(clippy::many_single_char_names)]
510    pub(crate) fn op_new_fvec4(&mut self, sp: &SynPos, a: ResPos, b: ResPos, c: ResPos, d: ResPos, r: ResPos) {
511        self.set_dbg(sp.clone());
512        self.push_op(Op::NewNVec(Box::new(NVecPos::FVec4(a, b, c, d)), r));
513    }
514
515    pub(crate) fn op_clear_locals(&mut self, sp: &SynPos, from: u16, to: u16) {
516        self.set_dbg(sp.clone());
517        self.push_op(Op::ClearLocals(from, to));
518    }
519
520    pub(crate) fn op_ctrl_flow_break(&mut self, sp: &SynPos, a: ResPos) {
521        self.set_dbg(sp.clone());
522        self.push_op(Op::CtrlFlow(CtrlFlow::Break(a)));
523    }
524
525    pub(crate) fn op_ctrl_flow_next(&mut self, sp: &SynPos) {
526        self.set_dbg(sp.clone());
527        self.push_op(Op::CtrlFlow(CtrlFlow::Next));
528    }
529
530    pub(crate) fn op_jmp(&mut self, sp: &SynPos, offs: i32) {
531        self.set_dbg(sp.clone());
532        self.push_op(Op::Jmp(offs));
533    }
534
535    pub(crate) fn op_jmp_ifn(&mut self, sp: &SynPos, a: ResPos, offs: i32) {
536        self.set_dbg(sp.clone());
537        self.push_op(Op::JmpIfN(a, offs));
538    }
539
540    pub(crate) fn op_push_loop_info(&mut self, sp: &SynPos, break_offs: u16) {
541        self.set_dbg(sp.clone());
542        self.push_op(Op::PushLoopInfo(break_offs));
543    }
544
545    pub(crate) fn op_iter_init(&mut self, sp: &SynPos, a: ResPos, end_offs: i32) {
546        self.set_dbg(sp.clone());
547        self.push_op(Op::IterInit(a, end_offs));
548    }
549
550    pub(crate) fn op_iter_next(&mut self, sp: &SynPos, r: ResPos) {
551        self.set_dbg(sp.clone());
552        self.push_op(Op::IterNext(r));
553    }
554
555    pub(crate) fn op_apply(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
556        self.set_dbg(sp.clone());
557        self.push_op(Op::Apply(a, b, r));
558    }
559
560    pub(crate) fn op_dump_vm(&mut self, sp: &SynPos) {
561        self.set_dbg(sp.clone());
562        self.push_op(Op::Builtin(Builtin::DumpVM(Box::new(sp.clone()))));
563    }
564
565    pub(crate) fn op_dump_stack(&mut self, sp: &SynPos) {
566        self.set_dbg(sp.clone());
567        self.push_op(Op::Builtin(Builtin::DumpStack(Box::new(sp.clone()))));
568    }
569
570    pub(crate) fn op_export(&mut self, sp: &SynPos, a: ResPos, name: String) {
571        self.set_dbg(sp.clone());
572        self.push_op(Op::Builtin(Builtin::Export(Box::new(name), a)));
573    }
574
575    pub(crate) fn op_new_pair(&mut self, sp: &SynPos, a: ResPos, b: ResPos, r: ResPos) {
576        self.set_dbg(sp.clone());
577        self.push_op(Op::NewPair(a, b, r));
578    }
579
580    pub(crate) fn op_accumulator(&mut self, sp: &SynPos, at: AccumType) {
581        self.set_dbg(sp.clone());
582        self.push_op(Op::Accumulator(at));
583    }
584
585    pub fn dump(&self) {
586        println!("PROG:");
587        for (i, o) in self.ops.iter().enumerate() {
588            println!("    [{:>3}] {:?}", i, o);
589        }
590        println!("  DATA:");
591        for (i, o) in self.data.iter().enumerate() {
592            println!("    [{:>3}] {:?}", i, o);
593        }
594    }
595}
596
597impl Debug for Prog {
598    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599        writeln!(f, "PROG:")?;
600        for (i, o) in self.ops.iter().enumerate() {
601            writeln!(f, "    [{:>3}] {:?}", i, o)?;
602        }
603        writeln!(f, "  DATA:")?;
604        for (i, o) in self.data.iter().enumerate() {
605            writeln!(f, "    [{:>3}] {:?}", i, o)?;
606        }
607        Ok(())
608    }
609}
610
611#[derive(Debug, Clone)]
612pub(crate) struct DestructureInfo {
613    pub vars:   VVal,
614    pub poses:  std::vec::Vec<VarPos>,
615    pub is_ref: bool,
616}
617
618fn set_env_at_varpos(e: &mut Env, pos: &VarPos, v: &VVal) {
619    match pos {
620        VarPos::UpValue(d)           => e.set_up(*d, v.clone()),
621        VarPos::Local(d)             => e.set_consume(*d, v.clone()),
622        VarPos::Global(VVal::Ref(r)) => { r.replace(v.clone()); },
623        VarPos::Global(_)
624        | VarPos::Const(_)
625        | VarPos::NoPos
626            => panic!(
627                "Fatal error in WLambda, can't destructure to {:?}", pos),
628    }
629}
630
631fn set_ref_at_varpos(e: &mut Env, pos: &VarPos, rv: &VVal) {
632    let v = rv.clone();
633    match pos {
634        VarPos::UpValue(d)           => e.assign_ref_up(*d, v),
635        VarPos::Local(d)             => e.assign_ref_local(*d, v),
636        VarPos::Global(VVal::Ref(r)) => { r.borrow().set_ref(v); },
637        VarPos::Global(_)
638        | VarPos::Const(_)
639        | VarPos::NoPos
640            => panic!(
641                "Fatal error in WLambda, can't ref destructure to {:?}", pos),
642    }
643}
644
645macro_rules! set_at_varpos {
646    ($self: ident, $env: ident, $pos: ident, $v: expr) => {
647        if $self.is_ref {
648            set_ref_at_varpos($env, $pos, $v);
649        } else {
650            set_env_at_varpos($env, $pos, $v);
651        }
652    }
653}
654
655impl DestructureInfo {
656    #[allow(clippy::cognitive_complexity)]
657    pub fn destructure(&self, env: &mut Env, val: VVal) {
658        match val {
659            VVal::Lst(l) => {
660                let nul = VVal::None;
661                for (i, pos) in self.poses.iter().enumerate() {
662                    set_at_varpos!(
663                        self, env, pos, l.borrow().get(i).unwrap_or(&nul));
664                }
665            },
666            VVal::Map(m) => {
667                for (i, pos) in self.poses.iter().enumerate() {
668                    let sym = self.vars.at(i).unwrap().to_sym();
669                    let val = m.borrow().get(&sym).cloned().unwrap_or(VVal::None);
670
671                    set_at_varpos!(self, env, pos, &val);
672                }
673            },
674            VVal::Pair(p) => {
675                let (lv, rv) = &*p;
676
677                if let Some(pos) = self.poses.get(0) {
678                    set_at_varpos!(self, env, pos, lv);
679                }
680
681                if let Some(pos) = self.poses.get(1) {
682                    set_at_varpos!(self, env, pos, rv);
683                }
684            },
685            VVal::IVec(vb) => {
686                match vb.as_ref() {
687                    NVec::Vec2(a, b) => {
688                        if let Some(pos) = self.poses.get(0) {
689                            set_at_varpos!(self, env, pos, &VVal::Int(*a));
690                        }
691
692                        if let Some(pos) = self.poses.get(1) {
693                            set_at_varpos!(self, env, pos, &VVal::Int(*b));
694                        }
695                    },
696                    NVec::Vec3(a, b, c) => {
697                        if let Some(pos) = self.poses.get(0) {
698                            set_at_varpos!(self, env, pos, &VVal::Int(*a));
699                        }
700
701                        if let Some(pos) = self.poses.get(1) {
702                            set_at_varpos!(self, env, pos, &VVal::Int(*b));
703                        }
704
705                        if let Some(pos) = self.poses.get(2) {
706                            set_at_varpos!(self, env, pos, &VVal::Int(*c));
707                        }
708                    },
709                    NVec::Vec4(a, b, c, d) => {
710                        if let Some(pos) = self.poses.get(0) {
711                            set_at_varpos!(self, env, pos, &VVal::Int(*a));
712                        }
713
714                        if let Some(pos) = self.poses.get(1) {
715                            set_at_varpos!(self, env, pos, &VVal::Int(*b));
716                        }
717
718                        if let Some(pos) = self.poses.get(2) {
719                            set_at_varpos!(self, env, pos, &VVal::Int(*c));
720                        }
721
722                        if let Some(pos) = self.poses.get(3) {
723                            set_at_varpos!(self, env, pos, &VVal::Int(*d));
724                        }
725                    },
726                }
727            },
728            VVal::FVec(vb) => {
729                match vb.as_ref() {
730                    NVec::Vec2(a, b) => {
731                        if let Some(pos) = self.poses.get(0) {
732                            set_at_varpos!(self, env, pos, &VVal::Flt(*a));
733                        }
734
735                        if let Some(pos) = self.poses.get(1) {
736                            set_at_varpos!(self, env, pos, &VVal::Flt(*b));
737                        }
738                    },
739                    NVec::Vec3(a, b, c) => {
740                        if let Some(pos) = self.poses.get(0) {
741                            set_at_varpos!(self, env, pos, &VVal::Flt(*a));
742                        }
743
744                        if let Some(pos) = self.poses.get(1) {
745                            set_at_varpos!(self, env, pos, &VVal::Flt(*b));
746                        }
747
748                        if let Some(pos) = self.poses.get(2) {
749                            set_at_varpos!(self, env, pos, &VVal::Flt(*c));
750                        }
751                    },
752                    NVec::Vec4(a, b, c, d) => {
753                        if let Some(pos) = self.poses.get(0) {
754                            set_at_varpos!(self, env, pos, &VVal::Flt(*a));
755                        }
756
757                        if let Some(pos) = self.poses.get(1) {
758                            set_at_varpos!(self, env, pos, &VVal::Flt(*b));
759                        }
760
761                        if let Some(pos) = self.poses.get(2) {
762                            set_at_varpos!(self, env, pos, &VVal::Flt(*c));
763                        }
764
765                        if let Some(pos) = self.poses.get(3) {
766                            set_at_varpos!(self, env, pos, &VVal::Flt(*d));
767                        }
768                    },
769                }
770            },
771            _ => {
772                for pos in self.poses.iter() {
773                    set_at_varpos!(self, env, pos, &val);
774                }
775            }
776        }
777    }
778}
779
780#[derive(Debug, Clone, Copy)]
781pub(crate) enum BinOp {
782    Add,
783    Sub,
784    Mul,
785    Div,
786    Mod,
787    Le,
788    Lt,
789    Ge,
790    Gt,
791    Eq,
792}
793
794impl BinOp {
795    pub(crate) fn to_op(self, a: ResPos, b: ResPos, out: ResPos) -> Op {
796        match self {
797            BinOp::Add       => Op::Add(a, b, out),
798            BinOp::Sub       => Op::Sub(a, b, out),
799            BinOp::Mul       => Op::Mul(a, b, out),
800            BinOp::Div       => Op::Div(a, b, out),
801            BinOp::Mod       => Op::Mod(a, b, out),
802            BinOp::Le        => Op::Le(a, b, out),
803            BinOp::Lt        => Op::Lt(a, b, out),
804            BinOp::Ge        => Op::Ge(a, b, out),
805            BinOp::Gt        => Op::Gt(a, b, out),
806            BinOp::Eq        => Op::Eq(a, b, out),
807        }
808    }
809}
810
811#[derive(Debug,Clone,Copy)]
812pub(crate) enum AccumType {
813    String,
814    Bytes,
815    Float,
816    Int,
817    Map,
818    Vec,
819}
820
821#[derive(Debug,Clone)]
822pub(crate) enum ToRefType {
823    CaptureRef,
824    ToRef,
825    Deref,
826    Hidden,
827    Weak,
828}
829
830#[derive(Debug,Clone)]
831#[allow(clippy::box_collection)]
832pub(crate) enum Builtin {
833    Export(Box<String>, ResPos),
834    DumpStack(Box<SynPos>),
835    DumpVM(Box<SynPos>),
836}
837
838#[derive(Debug,Clone)]
839pub(crate) enum CtrlFlow {
840    Next,
841    Break(ResPos),
842}
843
844#[derive(Debug,Clone)]
845pub(crate) enum NVecPos {
846    IVec2(ResPos, ResPos),
847    IVec3(ResPos, ResPos, ResPos),
848    IVec4(ResPos, ResPos, ResPos, ResPos),
849    FVec2(ResPos, ResPos),
850    FVec3(ResPos, ResPos, ResPos),
851    FVec4(ResPos, ResPos, ResPos, ResPos),
852}
853
854#[derive(Clone)]
855pub(crate) struct DirectFun {
856    pub arg: ResPos,
857    pub res: ResPos,
858    pub fun: Rc<dyn Fn(VVal, &mut Env) -> VVal>,
859}
860
861impl DirectFun {
862    pub fn new(fun: Rc<dyn Fn(VVal, &mut Env) -> VVal>) -> Self {
863        Self {
864            arg: ResPos::Stack(0),
865            res: ResPos::Stack(0),
866            fun,
867        }
868    }
869}
870
871impl Debug for DirectFun {
872    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
873        write!(f, "Box<DirectFun:?;arg={:?},res={:?}>", self.arg, self.res)
874    }
875}
876
877#[derive(Debug,Clone,Copy)]
878#[repr(u8)]
879pub(crate) enum OrMode {
880    Bool,
881    SomeOp,
882    ExtSomeOp,
883    NoneOp,
884    ErrOp,
885    OptOp,
886}
887
888#[allow(clippy::box_collection)]
889#[derive(Debug,Clone)]
890pub(crate) enum Op {
891    Mov(ResPos, ResPos),
892    NewOpt(ResPos, ResPos),
893    NewIter(ResPos, ResPos),
894    NewPair(ResPos, ResPos, ResPos),
895    NewNVec(Box<NVecPos>, ResPos),
896    Argv(ResPos),
897    ToRef(ResPos, ResPos, ToRefType),
898    ClearLocals(u16, u16),
899    Accumulator(AccumType),
900    PushLoopInfo(u16),
901    Add(ResPos, ResPos, ResPos),
902    Sub(ResPos, ResPos, ResPos),
903    Mul(ResPos, ResPos, ResPos),
904    Div(ResPos, ResPos, ResPos),
905    Mod(ResPos, ResPos, ResPos),
906    Le(ResPos, ResPos, ResPos),
907    Lt(ResPos, ResPos, ResPos),
908    Ge(ResPos, ResPos, ResPos),
909    Gt(ResPos, ResPos, ResPos),
910    Eq(ResPos, ResPos, ResPos),
911    NewErr(ResPos, ResPos),
912    NewList(ResPos),
913    ListPush(ResPos, ResPos, ResPos),
914    ListSplice(ResPos, ResPos, ResPos),
915    NewMap(ResPos),
916    MapSetKey(ResPos, ResPos, ResPos, ResPos),
917    MapSplice(ResPos, ResPos, ResPos),
918    NewClos(ResPos, ResPos),
919    GetIdx(ResPos, u32, ResPos),
920    GetIdx2(ResPos, Box<(u32, u32)>, ResPos),
921    GetIdx3(ResPos, Box<(u32, u32, u32)>, ResPos),
922    GetSym(ResPos, Box<Symbol>, ResPos),
923    GetSym2(ResPos, Box<(Symbol, Symbol)>, ResPos),
924    GetSym3(ResPos, Box<(Symbol, Symbol, Symbol)>, ResPos),
925    GetKey(ResPos, ResPos, ResPos),
926    Destr(ResPos, Box<DestructureInfo>),
927    Call(u16, ResPos),
928    CallDirect(Rc<DirectFun>),
929    CallMethodKey(ResPos, ResPos, u16, ResPos),
930    CallMethodSym(ResPos, Box<(String, u16)>, ResPos),
931    Apply(ResPos, ResPos, ResPos),
932    Jmp(i32),
933    JmpIfN(ResPos, i32),
934    OrJmp(ResPos, i32, ResPos, OrMode),
935    AndJmp(ResPos, i32, ResPos),
936    JmpTbl(ResPos, Box<Vec<i32>>),
937    CtrlFlow(CtrlFlow),
938    Builtin(Builtin),
939    IterInit(ResPos, i32),
940    IterNext(ResPos),
941//    UnwindMov(ResPos, ResPos),
942    Unwind,
943    End,
944}