1use std::collections::hash_map;
4use std::{iter, mem};
5use std::sync::atomic::{Ordering, AtomicUsize};
6
7use chasm::LblMap;
8use fnv::{FnvHashSet, FnvHashMap};
9
10use crate::nkgc::{PV, SymID, Int};
11use crate::r8vm::{R8VM, ArgSpec, r8c, Func};
12use crate::chasm::{ChOp, ChASM, Lbl, self, Arg};
13use crate::error::Source;
14use crate::ast::{AST2, M, Prog, Progn, M2, ArgList2, VarDecl, Visitor, Visitable};
15use crate::r8vm::r8c::{OpName::*, Op as R8C};
16use crate::builtins::*;
17use crate::error::Result;
18
19static LAMBDA_COUNT: AtomicUsize = AtomicUsize::new(0);
20static MODULE_COUNT: AtomicUsize = AtomicUsize::new(0);
21static DEFVAR_COUNT: AtomicUsize = AtomicUsize::new(0);
22
23macro_rules! def_macros {
24 ($d:tt, $ret:expr, $self:expr) => {
25 #[allow(unused_macros)]
26 macro_rules! asm {
27 ($d ($d args:tt)*) => {{ $self.unit().op(chasm!($d ($d args)*)); }};
28 }
29
30 #[allow(unused_macros)]
31 macro_rules! opcall {
32 ($d op:ident $d ($d arg:expr),*) => {{
33 if $ret {
34 $d ($self.push($d arg)?;)*
35 asm!($d op);
36 $self.env_pop(count_args!($d($d arg),*))?;
37 } else {
38 $d ($self.compile(false, $d arg)?;)*
39 }
40 }};
41 }
42
43 #[allow(unused_macros)]
44 macro_rules! opcall_mut {
45 ($d op:ident $d ($d arg:expr),*) => {{
46 $d ($self.push($d arg)?;)*
47 asm!($d op);
48 if !$ret {
49 asm!(POP 1);
50 }
51 $self.env_pop(count_args!($d($d arg),*))?;
52 }};
53 }
54
55 #[allow(unused_macros)]
56 macro_rules! vopcall {
57 ($d op:ident $d argv:expr) => {{
58 if $ret {
59 let nargs = $self.pushit(($d argv).into_iter())?;
60 asm!($d op nargs);
61 $self.env_pop(nargs)?;
62 } else {
63 for arg in ($d argv).into_iter() {
64 $self.compile(false, arg)?;
65 }
66 }
67 }};
68 }
69 };
70}
71
72pub type SourceList = Vec<(usize, Source)>;
73
74type VarIdx = u32;
75
76#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
77pub enum BoundVar {
78 Local(VarIdx),
79 Env(VarIdx),
80}
81
82#[derive(Default, Debug)]
83struct Env {
84 name: Option<SymID>,
85 vars: Vec<SymID>,
86 statics: FnvHashMap<SymID, usize>,
87}
88
89impl Env {
93 pub fn new(name: Option<SymID>, args: Vec<SymID>) -> Env {
94 let mut env = Env {
95 name,
96 vars: args,
97 statics: FnvHashMap::default()
98 };
99 env.defvar(Builtin::IP.sym());
100 env.defvar(Builtin::Frame.sym());
101 env
102 }
103
104 pub fn len(&self) -> usize {
105 self.vars.len()
106 }
107
108 #[allow(dead_code)]
109 pub fn is_empty(&self) -> bool {
110 self.len() == 0
111 }
112
113 pub fn none(name: Option<SymID>) -> Env {
114 Env { vars: vec![], statics: FnvHashMap::default(), name }
115 }
116
117 pub fn defvar(&mut self, var: SymID) {
118 self.vars.push(var);
119 }
120
121 pub fn anon(&mut self) -> usize {
122 let pos = self.vars.len();
123 self.vars.push(Builtin::Epsilon.sym());
124 pos
125 }
126
127 pub fn defenv(&mut self, var: SymID, env_idx: usize) {
128 self.statics.insert(var, env_idx);
129 }
130
131 pub fn pop(&mut self, n: usize) {
132 let new_top = self.vars.len() - n;
133 self.vars.truncate(new_top);
134 }
135
136 pub fn get_env_idx(&self, var: SymID) -> Option<usize> {
137 self.statics.get(&var).copied()
138 }
139
140 pub fn get_idx(&self, var: SymID) -> Option<VarIdx> {
141 for (i, &v) in self.vars.iter().enumerate().rev() {
142 if var == v {
143 return Some(i as VarIdx);
144 }
145 }
146 None
147 }
148}
149
150
151#[derive(Debug)]
152pub enum Sym {
153 Id(SymID),
154 Str(String),
155}
156
157#[derive(Debug)]
161pub struct R8Compiler {
162 labels: LblMap,
163 code: Vec<R8C>,
164 units: Vec<ChASM<R8C>>,
165 srctbl: SourceList,
166 estack: Vec<Env>,
167 loops: Vec<LoopCtx>,
168 fn_ctxs: Vec<FnCtx>,
169 const_offset: usize,
170 consts: Vec<PV>,
171 code_offset: usize,
172 new_fns: Vec<(Sym, ArgSpec, Vec<SymID>, usize, usize)>,
173 new_envs: Vec<(SymID, usize, usize)>,
174 env: FnvHashMap<SymID, usize>,
175 fns: FnvHashMap<SymID, Func>,
176 unlinked_fns: FnvHashMap<SymID, Vec<usize>>,
177 #[allow(dead_code)]
178 debug_mode: bool,
179}
180
181#[derive(Debug, Clone, Copy)]
182struct FnCtx {
183 start: Lbl,
184}
185
186#[derive(Debug, Clone, Copy)]
187struct LoopCtx {
188 start: Lbl,
189 epilogue: Option<Lbl>,
190 end: Lbl,
191 ret: bool,
192 height: usize,
193}
194
195type VarSet = FnvHashSet<(SymID, BoundVar)>;
196type FnSet = FnvHashMap<SymID, Func>;
197
198struct ClzScoper<'a, 'b> {
199 env: Env,
200 outside: &'a Env,
201 fns: &'b FnSet,
202 lowered: VarSet,
203}
204
205impl Visitor for ClzScoper<'_, '_> {
206 fn visit(&mut self, elem: &mut AST2) -> Result<()> {
207 match elem.kind {
208 M::SymApp(op, _) => if let Some(var) = self.outside.get_idx(op) {
209 self.lowered.insert((op, BoundVar::Local(var)));
210 }
211 M::Let(ref vars, _) => {
212 let len = vars.len();
213 vars.iter().for_each(|VarDecl(var, _, _)| self.env.defvar(*var));
214 elem.visit(self)?;
215 self.env.pop(len);
216 return Ok(());
217 }
218 M::Lambda(ArgList2(_, ref vars), _) => {
219 let len = vars.len();
220 vars.iter().for_each(|(var, _)| self.env.defvar(*var));
221 elem.visit(self)?;
222 self.env.pop(len);
223 return Ok(());
224 }
225 M::Var(var) => {
226 if self.env.get_idx(var).is_some() {
227 } else if let Some(bound) = self.outside.get_idx(var) {
228 self.lowered.insert((var, BoundVar::Local(bound)));
229 } else if var != Builtin::Nil.sym() && !self.fns.contains_key(&var) {
230 return err_src!(elem.src.clone(), UndefinedVariable, var);
231 }
232 }
233 _ => ()
234 }
235 elem.visit(self)
236 }
237}
238
239impl ClzScoper<'_, '_> {
240 pub fn scope<'a, 'b>(args: Vec<SymID>,
241 outside: &Env,
242 fns: &'b FnSet,
243 body: impl Iterator<Item = &'a mut AST2>) -> Result<VarSet> {
244 let mut scoper = ClzScoper {
245 lowered: FnvHashSet::default(),
246 env: Env::new(None, args),
247 fns,
248 outside,
249 };
250 for part in body {
251 scoper.visit(part)?;
252 }
253 Ok(scoper.lowered)
254 }
255}
256
257fn add_unlinked(ufns: &mut FnvHashMap<SymID, Vec<usize>>, name: SymID, pos: usize) {
258 match ufns.entry(name) {
259 hash_map::Entry::Occupied(mut e) => e.get_mut().push(pos),
260 hash_map::Entry::Vacant(e) => {e.insert(vec![pos]);}
261 }
262
263}
264
265impl R8Compiler {
266 pub fn new(vm: &R8VM) -> R8Compiler {
267 let mut cc = R8Compiler {
268 const_offset: 0,
269 debug_mode: vm.get_debug_mode(),
270 fn_ctxs: Default::default(),
271 new_fns: Default::default(),
272 estack: Default::default(),
273 labels: Default::default(),
274 consts: Default::default(),
275 loops: Default::default(),
276 srctbl: Default::default(),
277 code: Default::default(),
278 units: Default::default(),
279 new_envs: Default::default(),
280 env: vm.globals.clone(),
281 unlinked_fns: Default::default(),
282 fns: {
283 let mut map: FnvHashMap<SymID, Func> = Default::default();
284 for (sym, funk) in vm.funcs.iter() {
285 map.insert(*sym, *funk);
286 }
287 map
288 },
289 code_offset: 0,
290 };
291 cc.begin_unit();
292 let none: Option<SymID> = None;
293 cc.enter_fn(None, none.into_iter(), ArgSpec::none());
294 cc.set_offsets(vm);
295 cc
296 }
297
298 pub fn unit(&mut self) -> &mut ChASM<R8C> {
299 self.units.last_mut().expect("No unit to save asm to")
300 }
301
302 pub fn end_unit(&mut self) -> Result<usize> {
303 let len = self.code.len();
304 self.units.pop()
305 .expect("No unit to end")
306 .link_into(&mut self.code,
307 len + self.code_offset,
308 &mut self.labels)
309 }
310
311 pub fn begin_unit(&mut self) {
312 self.units.push(ChASM::new())
313 }
314
315 pub fn set_source(&mut self, src: Source) {
316 if src.line == 0 { return } match self.srctbl.last() {
318 Some((_, last_src)) if *last_src == src => (),
319 _ => {
320 let idx = self.unit().len() + self.code_offset;
321 self.srctbl.push((idx, src));
322 }
323 }
324 }
325
326 pub fn enter_fn(&mut self,
327 name: Option<SymID>,
328 args: impl Iterator<Item = SymID>,
329 spec: ArgSpec) {
330 let mut env = Env::none(name);
331 if spec.has_env() {
332 env.defvar(Builtin::LambdaObject.sym());
333 }
334 for arg in args {
335 env.defvar(arg);
336 }
337 env.defvar(Builtin::IP.sym());
338 env.defvar(Builtin::Frame.sym());
339 self.estack.push(env);
340 let start = self.unit().label("fn-begin");
341 self.unit().mark(start);
342 self.fn_ctxs.push(FnCtx { start });
343 if spec.is_special() {
344 self.unit().op(chasm!(SAV 2));
345 if spec.has_opt() {
346 self.unit().op(chasm!(TOP spec.nargs));
347 self.unit().op(chasm!(JV 1, spec.nopt));
348 for _ in 0..spec.nopt {
349 self.unit().op(chasm!(NIL));
350 }
351 }
352 if spec.has_body() {
353 self.unit().op(chasm!(TOP spec.nargs + spec.nopt));
354 self.unit().op(chasm!(VLT));
355 }
356 if spec.has_env() {
357 self.unit().op(chasm!(ZXP));
358 }
359 self.unit().op(chasm!(RST));
360 }
361 }
362
363 fn leave_fn(&mut self) {
364 self.unit().op(chasm!(RET));
365 self.estack.pop();
366 self.fn_ctxs.pop();
367 }
368
369 fn with_env<T>(&mut self, f: impl Fn(&mut Env) -> T) -> Result<T> {
370 self.estack
371 .last_mut()
372 .map(f)
373 .ok_or_else(|| "No environment".into())
374 }
375
376 #[inline]
377 fn asm_op(&mut self, op: ChOp<r8c::OpName>) {
378 self.unit().op(op);
379 }
380
381 #[inline]
399 fn push(&mut self, code: AST2) -> Result<usize> {
400 self.compile(true, code)?;
401 self.with_env(|env| env.anon())
402 }
403
404 fn pushit(&mut self, args: impl Iterator<Item = AST2>) -> Result<usize> {
405 let mut nargs = 0;
406 for arg in args {
407 nargs += 1;
408 self.push(arg)?;
409 }
410 Ok(nargs)
411 }
412
413 fn env_pop(&mut self, n: usize) -> Result<()> {
414 self.with_env(|env| env.pop(n))
415 }
416
417 pub fn argument_clinic(mut code: AST2) -> (bool, AST2) {
442 let mut flipped = false;
443 while let AST2 { kind: M::Not(sub), .. } = code {
444 flipped = !flipped;
445 code = *sub;
446 }
447 (flipped, code)
448 }
449
450 fn loop_ctx(&self) -> Result<&LoopCtx> {
451 self.loops
452 .last()
453 .ok_or(error!(OutsideContext,
454 op: Builtin::Break,
455 ctx: Builtin::Loop))
456 }
457
458 fn loop_epilogue(&self) -> Result<Lbl> {
459 self.loop_ctx().map(|ctx| ctx.epilogue.unwrap_or(ctx.start))
460 }
461
462 fn loop_end(&self) -> Result<Lbl> {
463 self.loop_ctx().map(|ctx| ctx.end)
464 }
465
466 fn loop_simple_jmp_to(&self, op: &M) -> Option<Result<Lbl>> {
467 match (op, self.loop_ctx().map(|x| x.ret).ok()) {
468 (M::Break(None), Some(false)) => Some(self.loop_end()),
469 (M::Next, Some(false)) => Some(self.loop_epilogue()),
470 _ => None
471 }
472 }
473
474 fn bt_if(&mut self, ret: bool,
475 cond: AST2, if_t: Option<AST2>, if_f: Option<AST2>
476 ) -> Result<()> {
477 let if_t = if_t.unwrap_or_else(|| AST2::nil(cond.src.clone()));
478 let (flipped, cond) = R8Compiler::argument_clinic(cond);
479 let src = cond.src.clone();
480 let ((jt, jn), cond) = match cond.kind {
481 M::Eq(u, v) => match (*u, *v) {
482 (AST2 { kind: M::Atom(PV::Int(0)), .. }, v) |
483 (v, AST2 { kind: M::Atom(PV::Int(0)), .. }) => ((JZ, JNZ), v),
484 (u, v) => ((JT, JN),
485 AST2 { src, kind: M::Eq(Box::new(u), Box::new(v)) }),
486 },
487 _ => ((JT, JN), cond)
488 };
489 self.compile(true, cond)?;
490
491 if let Some(lbl) = self.loop_simple_jmp_to(&if_t.kind) {
492 if flipped {
493 self.unit().op(chasm!(jn lbl?));
494 } else {
495 self.unit().op(chasm!(jt lbl?));
496 }
497 if let Some(if_false) = if_f {
498 self.compile(ret, if_false)?;
499 } else if ret {
500 self.unit().op(chasm!(NIL));
501 }
502 } else {
503 let end_lbl = self.unit().label("if_end");
504 let if_false_lbl = self.unit().label("if_false");
505 let _jmp_loc = if flipped {
506 self.unit().op(chasm!(jt if_false_lbl))
507 } else {
508 self.unit().op(chasm!(jn if_false_lbl))
509 };
510 self.compile(ret, if_t)?;
511 if let Some(if_false) = if_f {
512 self.asm_op(chasm!(JMP end_lbl));
513 self.unit().mark(if_false_lbl);
514 self.compile(ret, if_false)?;
515 self.unit().mark(end_lbl);
516 } else if ret {
517 self.asm_op(chasm!(JMP end_lbl));
518 self.unit().mark(if_false_lbl);
519 self.unit().op(chasm!(NIL));
520 self.unit().mark(end_lbl);
521 } else {
522 self.unit().mark(if_false_lbl);
523 }
524 }
525 Ok(())
526 }
527
528 fn compile_seq(&mut self,
529 ret: bool,
530 seq: impl IntoIterator<Item = AST2>
531 ) -> Result<()> {
532 let mut seq = seq.into_iter();
533 let Some(mut last) = seq.next() else {
534 if ret { self.asm_op(chasm!(NIL)) }
535 return Ok(())
536 };
537 for nx in seq {
538 self.compile(false, last)?;
539 last = nx;
540 }
541 self.compile(ret, last)
542 }
543
544 fn gen_call_nargs(&mut self,
549 ret: bool,
550 op: (r8c::OpName, &mut [chasm::Arg]),
551 nargs_idx: usize,
552 args: impl Iterator<Item = AST2>) -> Result<()> {
553 let nargs = self.pushit(args)?;
554 op.1[nargs_idx] = nargs.into();
555 self.unit().add(op.0, op.1);
556 self.env_pop(nargs)?;
557 if !ret {
558 self.asm_op(chasm!(POP 1));
559 }
560 Ok(())
561 }
562
563 fn asm_get_var(&mut self,
564 var: SymID,
565 src: &Source) -> Result<()> {
566 match self.get_var_idx(var, src)? {
567 BoundVar::Local(idx) => self.unit().op(chasm!(MOV idx)),
568 BoundVar::Env(idx) => self.unit().op(chasm!(GET idx)),
569 };
570 Ok(())
571 }
572
573 fn get_var_idx(&mut self,
574 var: SymID,
575 src: &Source) -> Result<BoundVar> {
576 if let Some(idx) = self.with_env(|env| env.get_idx(var))? {
577 return Ok(BoundVar::Local(idx));
578 }
579 for env in self.estack.iter().rev() {
580 if let Some(idx) = env.get_env_idx(var) {
581 return Ok(BoundVar::Env(idx as u32))
582 }
583 }
584 if let Some(idx) = self.env.get(&var) {
585 return Ok(BoundVar::Env(*idx as u32))
586 }
587 err_src!(src.clone(), UndefinedVariable, var)
588 }
589
590 fn asm_set_var_idx(&mut self, idx: &BoundVar) -> Result<()> {
591 match idx {
592 BoundVar::Local(idx) => self.unit().op(chasm!(STR *idx)),
593 BoundVar::Env(idx) => self.unit().op(chasm!(SET *idx)),
594 };
595 Ok(())
596 }
597
598 fn bt_sym_app(&mut self, ret: bool, src: Source, op: SymID, args: Vec<AST2>) -> Result<()> {
599 if let Ok(()) = self.asm_get_var(op, &src) { self.with_env(|env| env.anon())?;
601 let args = args.into_iter();
602 self.gen_call_nargs(ret, (r8c::OpName::ZCALL, &mut [0.into()]),
603 0, args)?;
604 self.env_pop(1).unwrap();
605 } else if self.with_env(|e| e.name)?.map(|s| op == s).unwrap_or_default() {
606 let start = self.fn_ctxs.last().unwrap().start;
607 self.gen_call_nargs(ret, (r8c::OpName::CALL,
608 &mut [Arg::AbsLbl(start), 0.into()]),
609 1, args.into_iter())?;
610 } else { let idx = self.new_const(PV::Sym(op));
612 self.gen_call_nargs(ret, (r8c::OpName::VCALL,
613 &mut [idx.into(), 0.into()]),
614 1, args.into_iter())?;
615 }
616 Ok(())
617 }
618
619 fn gapp(&mut self, ret: bool, op: AST2, args: Vec<AST2>) -> Result<()> {
620 if !matches!(op.type_of(), Builtin::Unknown | Builtin::Lambda) {
621 return Err(error!(TypeError,
622 expect: Builtin::Lambda,
623 got: op.type_of())
624 .src(op.src).argn(0).bop(Builtin::Apply))
625 }
626 self.compile(true, op)?;
627 self.with_env(|env| env.anon())?; self.gen_call_nargs(ret, (r8c::OpName::ZCALL, &mut [0.into()]),
629 0, args.into_iter())?;
630 self.env_pop(1)
631 }
632
633 pub fn bt_vec_set(&mut self,
634 ret: bool,
635 _src: Source,
636 dst: AST2,
637 idx: AST2,
638 init: AST2) -> Result<()> {
639 self.compile(true, init)?;
640 if ret { self.unit().op(chasm!(DUP)); }
641 self.compile(true, dst)?;
642 self.compile(true, idx)?;
643 self.unit().op(chasm!(VSET));
644 Ok(())
645 }
646
647 pub fn bt_set(&mut self,
648 ret: bool,
649 src: Source,
650 dst: SymID,
651 init: AST2) -> Result<()> {
652 let bound = self.get_var_idx(dst, &src)?;
653 if let BoundVar::Local(idx) = bound {
654 let mut inplace_op = |op, val: Int| {
655 self.unit().add(op, &[idx.into(), val.into()]);
656 if ret { self.asm_op(chasm!(MOV idx)) }
657 };
658 match init.kind.binary() {
659 Some((M2::Add(M::Var(sym), M::Atom(PV::Int(num))), _)) |
664 Some((M2::Add(M::Atom(PV::Int(num)), M::Var(sym)), _))
665 if *sym == dst => {
666 inplace_op(INC, *num);
667 return Ok(())
668 }
669 Some((M2::Sub(M::Var(sym), M::Atom(PV::Int(num))), _))
670 if *sym == dst => {
671 inplace_op(DEC, *num);
672 return Ok(())
673 }
674 Some((M2::Add(M::Var(u), M::Var(v)), (src_u, src_v))) => 'out: {
675 let (src, src_src) =
676 if *u == dst { (*v, src_v) }
677 else if *v == dst { (*u, src_u) }
678 else { break 'out };
679 if let BoundVar::Local(src_idx) = self.get_var_idx(src, src_src)? {
680 self.unit().op(chasm!(ADS idx, src_idx));
681 return Ok(())
682 }
683 }
684 Some((M2::Sub(M::Var(u), M::Var(v)), (_, src_v))) if *u == dst => {
685 if let BoundVar::Local(src_idx) = self.get_var_idx(*v, src_v)? {
686 self.unit().op(chasm!(SUS idx, src_idx));
687 return Ok(())
688 }
689 }
690 _ => ()
691 }
692 }
693 self.compile(true, init)?;
694 if ret { self.asm_op(chasm!(DUP)) }
695 self.asm_set_var_idx(&bound)
699 }
700
701 fn lambda(&mut self,
702 name: Option<SymID>,
703 spec: ArgSpec,
704 names: Vec<(SymID, Source)>,
705 prog: impl IntoIterator<Item = AST2>) -> Result<(usize, usize)> {
706 self.begin_unit();
707 self.enter_fn(name, names.into_iter().map(|(s,_)| s), spec);
708 self.compile_seq(true, prog)?;
709 self.leave_fn();
710 let pos = self.code.len() + self.code_offset;
711 let sz = self.end_unit()?;
712 Ok((pos, sz))
713 }
714
715 fn bt_lambda(&mut self,
716 mut spec: ArgSpec,
717 names: Vec<(SymID, Source)>,
718 mut prog: Progn,
719 _src: Source) -> Result<()> {
720 let mut args: Vec<_> = names.iter().map(|(s,_)| *s).collect();
721 let Some(outside) = self.estack.last() else { unimplemented!() };
722 let lowered = ClzScoper::scope(args.clone(),
723 outside,
724 &self.fns,
725 prog.iter_mut())?;
726 let num = LAMBDA_COUNT.fetch_add(1, Ordering::SeqCst);
727 let name = format!("<λ>-{num}");
728 let mut num = 0;
729 for (var, bound) in lowered.iter() {
730 if let BoundVar::Local(idx) = bound {
731 args.push(*var);
732 self.unit().op(chasm!(MOV *idx));
733 num += 1;
734 }
735 }
736 spec.env = num;
737 self.begin_unit();
738 self.enter_fn(None, args.iter().copied(), spec);
739 for (var, bound) in lowered.iter() {
740 if let BoundVar::Env(idx) = bound {
741 self.with_env(|env| env.defenv(*var, *idx as usize))?;
742 }
743 }
744 self.compile_seq(true, prog)?;
745 if spec.has_env() {
746 self.asm_op(chasm!(ZAV spec.sum_nargs() + 1, spec.env));
747 }
748 self.leave_fn();
749 let pos = self.code.len() + self.code_offset;
750 let sz = self.end_unit()?;
751 self.unit().op(
752 chasm!(ARGS spec.nargs, spec.nopt, spec.env, spec.rest as u8)
753 );
754 self.unit().op(chasm!(CLZ pos, num));
755 self.new_fns.push((Sym::Str(name), spec, args, pos, sz));
756 Ok(())
757 }
758
759 fn popa(&mut self, num: usize) {
760 match self.unit().last_mut() {
761 Some(ChOp { id: r8c::OpName::POPA, ref mut args }) => {
762 args[1].add_mut(num as isize)
763 .expect("Invalid popa instruction");
764 },
765 _ => { self.unit().op(chasm!(POPA 1, num)); },
766 }
767 }
768
769 fn bt_let(&mut self, ret: bool, decls: Vec<VarDecl>, prog: Progn) -> Result<()> {
770 let len = decls.len();
771 for VarDecl(name, _src, val) in decls.into_iter() {
772 self.compile(true, *val)?;
773 self.with_env(|env| env.defvar(name))?;
774 }
775 self.compile_seq(ret, prog)?;
776 if ret {
777 self.popa(len);
778 } else {
779 self.unit().op(chasm!(POP len));
780 }
781 self.env_pop(len)
782 }
783
784 fn bt_loop(&mut self,
785 ret: bool,
786 seq: impl IntoIterator<Item = AST2>,
787 epl: Option<impl IntoIterator<Item = AST2>>) -> Result<()> {
788 let start = self.unit().label("loop_start");
789 let end = self.unit().label("loop_end");
790 let epl_lbl = if epl.is_some() { Some(self.unit().label("epilogue")) } else { None };
791 let height = self.with_env(|env| env.len())?;
792 self.loops.push(LoopCtx { start, end, epilogue: epl_lbl, ret, height });
793 self.unit().mark(start);
794 self.compile_seq(false, seq)?;
795 if let Some(epl) = epl {
796 self.unit().mark(epl_lbl.unwrap());
797 self.compile_seq(false, epl)?;
798 }
799 self.unit().op(chasm!(JMP start));
800 self.unit().mark(end);
801 self.loops.pop();
802 Ok(())
803 }
804
805 fn bt_break(&mut self, src: Source, arg: Option<Prog>) -> Result<()> {
806 let outer = self.loops
807 .last()
808 .copied()
809 .ok_or(error_src!(src, OutsideContext,
810 op: Builtin::Break,
811 ctx: Builtin::Loop))?;
812 let LoopCtx { end, ret, height, .. } = outer;
813 let dist = self.with_env(|env| env.len())? - height;
814 let popa = |cc: &mut R8Compiler| if dist > 0 {
815 cc.popa(dist-1);
816 };
817 match arg {
818 Some(code) if ret => {
819 self.compile(true, *code)?;
820 popa(self);
821 }
822 None if ret => {
823 self.asm_op(chasm!(NIL));
824 popa(self);
825 }
826 _ if dist > 0 => self.asm_op(chasm!(POP dist)),
827 _ => ()
828 }
829 self.asm_op(chasm!(JMP end));
830 Ok(())
831 }
832
833 fn bt_loop_next(&mut self, src: Source) -> Result<()> {
834 let outer = self.loops
835 .last()
836 .copied()
837 .ok_or(error_src!(src, OutsideContext,
838 op: Builtin::Next,
839 ctx: Builtin::Loop))?;
840 let LoopCtx { start, epilogue, height, .. } = outer;
841 let dist = self.with_env(|env| env.len())? - height;
842 self.asm_op(chasm!(POP dist));
843 if let Some(epl) = epilogue {
844 self.asm_op(chasm!(JMP epl));
845 } else {
846 self.asm_op(chasm!(JMP start));
847 }
848 Ok(())
849 }
850
851 fn binop(&mut self,
852 op: Builtin,
853 src: Source,
854 bop: ChOp<r8c::OpName>,
855 one_arg_pre: Option<ChOp<r8c::OpName>>,
856 default: Option<ChOp<r8c::OpName>>,
857 args: impl IntoIterator<Item = AST2>) -> Result<()> {
858 let mut it = args.into_iter().peekable();
859 if let Some(fst) = it.next() {
860 if let (Some(pre), true) = (one_arg_pre, it.peek().is_none()) {
861 self.unit().op(pre);
862 self.with_env(|env| env.anon())?;
863 self.compile(true, fst)?;
864 self.unit().op(bop);
865 } else {
866 self.push(fst)?;
867 for arg in it {
868 self.compile(true, arg)?;
869 self.unit().op(bop.clone());
870 }
871 }
872 self.env_pop(1)?;
873 } else if let Some(op) = default {
874 self.unit().op(op);
875 } else {
876 return Err(error!(ArgError,
877 expect: ArgSpec::rest(1, 0),
878 got_num: 0)
879 .src(src).bop(op))
880 }
881 Ok(())
882 }
883
884 fn bt_vpush(&mut self, ret: bool, vec: AST2, val: AST2) -> Result<()> {
893 self.push(val)?;
894 if ret {
895 self.unit().op(chasm!(DUP));
896 }
897 self.push(vec)?;
898 self.unit().op(chasm!(VPUSH));
899 self.env_pop(2)
900 }
901
902 fn bt_next(&mut self, ret: bool, arg: AST2) -> Result<()> {
903 let AST2 { src, kind } = arg;
904 match kind {
905 M::Var(var) => {
906 let bound = self.get_var_idx(var, &src)?;
907 match bound {
908 BoundVar::Local(idx) => self.asm_op(chasm!(NXT idx)),
909 BoundVar::Env(idx) => {
910 self.asm_op(chasm!(GET idx));
911 let idx = self.with_env(|env| env.anon())?;
912 self.asm_op(chasm!(NXT idx));
913 self.popa(1);
914 self.env_pop(1)?;
915 }
916 }
917 }
918 init => {
919 self.compile(true, AST2 { kind: init, src })?;
920 let idx = self.with_env(|env| env.anon())?;
921 self.asm_op(chasm!(NXT idx));
922 self.popa(1);
923 self.env_pop(1)?;
924 }
925 };
926 if !ret {
927 self.asm_op(chasm!(POP 1));
928 }
929 Ok(())
930 }
931
932 fn bt_and(&mut self, ret: bool, args: impl IntoIterator<Item = AST2>) -> Result<()> {
933 let mut it = args.into_iter().peekable();
934 if it.peek().is_none() {
935 if ret {
936 self.unit().op(chasm!(BOOL 1));
937 }
938 return Ok(());
939 }
940 let end_l = self.unit().label("and_end");
941 let and_exit = self.unit().label("and_early_exit");
942 while let Some(part) = it.next() {
943 let (flip, part) = R8Compiler::argument_clinic(part);
944 self.compile(it.peek().is_some() || ret, part)?;
945 if flip {
946 self.unit().op(chasm!(JT and_exit));
947 } else {
948 self.unit().op(chasm!(JN and_exit));
949 }
950 }
951 self.unit().pop();
952 if ret {
953 self.unit().op(chasm!(JMP end_l));
954 self.unit().mark(and_exit);
955 self.unit().op(chasm!(NIL));
956 self.unit().mark(end_l);
957 } else {
958 self.unit().mark(and_exit);
959 }
960 Ok(())
961 }
962
963 fn bt_or(&mut self, ret: bool, args: impl IntoIterator<Item = AST2>) -> Result<()> {
964 let mut it = args.into_iter().peekable();
965 if it.peek().is_none() {
966 if ret {
967 self.unit().op(chasm!(BOOL 0));
968 }
969 return Ok(());
970 }
971 let end_l = self.unit().label("or_end");
972 while let Some(part) = it.next() {
973 let (flip, part) = R8Compiler::argument_clinic(part);
974 self.compile(it.peek().is_some() || ret, part)?;
975 if ret { self.unit().op(chasm!(DUP)); }
976 if flip {
977 self.unit().op(chasm!(JN end_l));
978 } else {
979 self.unit().op(chasm!(JT end_l));
980 }
981 if ret { self.unit().op(chasm!(POP 1)); }
982 }
983 if ret { self.unit().op(chasm!(NIL)); }
984 self.unit().mark(end_l);
985 Ok(())
986 }
987
988 pub fn new_const(&mut self, pv: PV) -> usize {
989 let idx = self.const_offset + self.consts.len();
990 self.consts.push(pv);
991 idx
992 }
993
994 fn atom(&mut self, pv: PV) -> Result<()> {
995 let op = match pv {
996 PV::Bool(true) => chasm!(BOOL 1),
997 PV::Bool(false) => chasm!(BOOL 0),
998 PV::Char(c) => chasm!(CHR c as u32),
999 PV::Int(i) => chasm!(INT i),
1000 PV::Real(r) => chasm!(FLT r.to_bits()),
1001 PV::Nil => chasm!(NIL),
1002 pv => {
1003 let idx = self.new_const(pv);
1004 if pv.bt_type_of() == Builtin::String {
1005 chasm!(GET idx) } else {
1007 chasm!(INS idx)
1008 }
1009 }
1010 };
1011 self.unit().op(op);
1012 Ok(())
1013 }
1014
1015 fn bt_append(&mut self, ret: bool, mut xs: Vec<AST2>, src: Source) -> Result<()> {
1016 if xs.iter().all(|e| matches!(e.kind, M::List(..))) {
1017 let ast = AST2 {
1018 src,
1019 kind: M::List(xs.into_iter().flat_map(|xs| if let M::List(src) = xs.kind {
1020 src.into_iter()
1021 } else {
1022 unreachable!()
1023 }).collect())
1024 };
1025 self.compile(ret, ast)
1026 } else {
1027 if let Some(mut i) = xs.iter().position(|m| matches!(m.kind, M::List(..))) {
1028 for j in (i+1)..xs.len() {
1029 match xs[j].kind {
1030 M::List(..) => {
1031 let (pre, post) = xs.split_at_mut(j);
1032 let M::List(dst) = &mut pre[i].kind else {
1033 i = j;
1034 continue
1035 };
1036 let M::List(src) = &mut post[0].kind else { unreachable!() };
1037 dst.append(src);
1038 }
1039 _ => i = j,
1040 }
1041 }
1042 xs.retain(|s| if let M::List(xs) = &s.kind {
1043 !xs.is_empty()
1044 } else { true });
1045 }
1046 let nargs = xs.len();
1047 for arg in xs.into_iter() {
1048 self.compile(ret, arg)?;
1049 }
1050 if ret { self.unit().op(chasm!(APN nargs)); }
1051 Ok(())
1052 }
1053 }
1054
1055 pub fn bt1(&mut self, ret: bool, op: Builtin, arg: AST2) -> Result<()> {
1056 def_macros!($, ret, self);
1057
1058 match op {
1059 Builtin::Len => opcall!(LEN arg),
1060 x => unimplemented!("{x:?}"),
1061 }
1062
1063 Ok(())
1064 }
1065
1066 pub fn bt2(&mut self, ret: bool, op: Builtin, a0: AST2, a1: AST2) -> Result<()> {
1067 def_macros!($, ret, self);
1068
1069 match op {
1070 Builtin::Apply => opcall_mut!(APL a0, a1),
1071 Builtin::LoopWithEpilogue => self.bt_loop(ret,
1072 Some(a0).into_iter(),
1073 Some(Some(a1).into_iter()))?,
1074 x => unimplemented!("{x:?}"),
1075 }
1076
1077 Ok(())
1078 }
1079
1080 fn compile(&mut self, ret: bool, AST2 { kind, src }: AST2) -> Result<()> {
1081 def_macros!($, ret, self);
1082
1083 self.set_source(src.clone());
1084
1085 match kind {
1086 M::Var(var) => match self.get_var_idx(var, &src) {
1087 Ok(BoundVar::Local(idx)) => asm!(MOV idx),
1088 Ok(BoundVar::Env(idx)) => asm!(GET idx),
1089 Err(e) => match self.fns.get(&var) {
1090 Some(funk) => {
1091 let s = funk.args;
1092 let pos = funk.pos;
1093 asm!(ARGS s.nargs, s.nopt, 0, s.rest as u8);
1094 asm!(CLZ pos, 0);
1095 }
1096 _ => return Err(e)
1097 }
1098 },
1099 M::If(cond, if_t, if_f) =>
1100 self.bt_if(ret, *cond, if_t.map(|v| *v), if_f.map(|v| *v))?,
1101 M::Atom(pv) => if ret { self.atom(pv)? },
1102 M::Progn(seq) => self.compile_seq(ret, seq.into_iter())?,
1103 M::SymApp(op, args) => self.bt_sym_app(ret, src, op, args)?,
1104 M::App(op, args) => self.gapp(ret, *op, args)?,
1105 M::Lambda(ArgList2(spec, names), progn) =>
1106 self.bt_lambda(spec, names, progn, src)?,
1107 M::Defvar(sym, init) => {
1108 let spec = ArgSpec::none();
1109 let (pos, sz) = self.lambda(None, spec, vec![], Some(*init))?;
1110 let num = DEFVAR_COUNT.fetch_add(1, Ordering::SeqCst);
1111 let name = format!("<δ>-{num}");
1112 self.new_fns.push((Sym::Str(name), spec, vec![], pos, sz));
1113 let idx = self.new_const(PV::Nil);
1114 self.new_envs.push((sym, idx, pos));
1115 self.env.insert(sym, idx);
1116 if ret {
1117 asm!(GET idx);
1118 }
1119 },
1120 M::VecSet(dst, idx, init) => self.bt_vec_set(ret, src, *dst, *idx, *init)?,
1121 M::Set(dst, init) => self.bt_set(ret, src, dst, *init)?,
1122 M::Defun(name, ArgList2(spec, names), progn) => {
1123 let syms = names.iter().map(|(s,_)| *s).collect();
1124 let (pos, sz) = self.lambda(Some(name), spec, names, progn)?;
1125 self.new_fns.push((Sym::Id(name), spec, syms, pos, sz));
1126 self.fns.insert(name, Func { pos, sz, args: spec });
1127 if ret {
1128 asm!(ARGS spec.nargs, spec.nopt, 0, spec.rest as u8);
1129 asm!(CLZ pos, 0);
1130 }
1131 },
1132 M::Let(decls, progn) => {
1133 self.bt_let(ret, decls, progn)?
1134 },
1135 M::Loop(prog) => {
1136 let s: Option<iter::Empty<AST2>> = None;
1137 self.bt_loop(ret, prog, s)?
1138 },
1139 M::Break(arg) => self.bt_break(src, arg)?,
1140 M::Next => self.bt_loop_next(src)?,
1141 M::Throw(arg) => {
1142 self.compile(true, *arg)?;
1143 asm!(UWND);
1144 },
1145 M::Not(x) => opcall!(NOT *x),
1146 M::Gt(x, y) => opcall!(GT *x, *y),
1147 M::Gte(x, y) => opcall!(GTE *x, *y),
1148 M::Lt(x, y) => opcall!(LT *x, *y),
1149 M::Lte(x, y) => opcall!(LTE *x, *y),
1150 M::Eq(x, y) => opcall!(EQL *x, *y),
1151 M::Eqp(x, y) => opcall!(EQP *x, *y),
1152 M::Add(args) if ret => self.binop(Builtin::Add, src, chasm!(ADD),
1153 None, Some(chasm!(INT 0)), args)?,
1154 M::Add(args) => vopcall!(NIL args),
1155 M::Sub(args) if ret => self.binop(Builtin::Sub, src, chasm!(SUB),
1156 Some(chasm!(INT 0)), None, args)?,
1157 M::Sub(args) => vopcall!(NIL args),
1158 M::Mul(args) if ret => self.binop(Builtin::Mul, src, chasm!(MUL),
1159 None, Some(chasm!(INT 1)), args)?,
1160 M::Mul(args) => vopcall!(NIL args),
1161 M::Div(args) if ret => self.binop(Builtin::Div, src, chasm!(DIV),
1162 Some(chasm!(FLT 1.0_f32.to_bits())), None, args)?,
1163 M::Div(args) => vopcall!(NIL args),
1164 M::And(args) => self.bt_and(ret, args)?,
1165 M::Or(args) => self.bt_or(ret, args)?,
1166
1167 M::NextIter(it) => self.bt_next(ret, *it)?,
1168 M::Car(x) => opcall!(CAR *x),
1169 M::Cdr(x) => opcall!(CDR *x),
1170 M::Cons(x, y) => opcall!(CNS *x, *y),
1171 M::List(xs) => vopcall!(LST xs),
1172 M::Append(xs) => self.bt_append(ret, xs, src)?,
1173 M::Vector(xs) => vopcall!(VEC xs),
1174 M::Push(vec, elem) => self.bt_vpush(ret, *vec, *elem)?,
1175 M::Get(vec, idx) => opcall!(VGET *vec, *idx),
1176 M::Pop(vec) => opcall_mut!(VPOP *vec),
1177 M::CallCC(funk) => {
1178 self.compile(true, *funk)?;
1179 asm!(CCONT 0);
1180 if !ret { asm!(POP 1) }
1181 }
1182 M::Bt1(op, arg) => self.bt1(ret, op, *arg)?,
1183 M::Bt2(op, a0, a1) => self.bt2(ret, op, *a0, *a1)?,
1184 M::TailCall(_args) => todo!(),
1185 }
1186
1187 Ok(())
1188 }
1189
1190 pub fn compile_top(&mut self, code: AST2) -> Result<()> {
1191 self.compile(false, code)
1192 }
1193
1194 pub fn compile_top_tail(&mut self, code: AST2) -> Result<usize> {
1195 let num = MODULE_COUNT.fetch_add(1, Ordering::SeqCst);
1196 let name = format!("<σ>-{num}");
1197 self.compile(true, code)?;
1198 self.leave_fn();
1199 let pos = self.code.len() + self.code_offset;
1200 let sz = self.end_unit()?;
1201 self.new_fns.push((Sym::Str(name), ArgSpec::none(), vec![], pos, sz));
1202 Ok(pos)
1203 }
1204
1205 pub fn take(&mut self, vm: &mut R8VM) -> Result<()> {
1206 vm.mem.env.append(&mut self.consts);
1207 let mut ufn = mem::take(&mut self.unlinked_fns);
1208 for (i, op) in self.code.iter_mut().enumerate() {
1209 *op = match *op {
1210 R8C::VCALL(idx, nargs) => {
1211 let sym = vm.mem.get_env(idx as usize).sym().unwrap();
1212 match vm.get_func(sym) {
1213 Some(funk) => {
1214 funk.args.check(nargs).map_err(|e| e.op(sym))?;
1215 R8C::CALL(funk.pos.try_into()?, nargs)
1216 }
1217 None => {
1218 add_unlinked(&mut ufn, sym, self.code_offset + i);
1219 *op
1220 }
1221 }
1222 },
1223 op => op
1224 };
1225 }
1226 self.unlinked_fns = ufn;
1227 vm.pmem.append(&mut self.code);
1228 vm.srctbl.append(&mut self.srctbl);
1229 vm.labels.extend(self.labels.drain());
1230 for (name, spec, names, pos, sz) in self.new_fns.drain(..) {
1231 let name = match name {
1232 Sym::Id(id) => id,
1233 Sym::Str(s) => vm.mem.symdb.put(s).id(),
1234 };
1235 vm.defun(name, spec, names, pos, sz);
1236 }
1237 for (name, idx, init_pos) in self.new_envs.drain(..) {
1238 vm.defvar(name, idx, init_pos)?;
1239 }
1240 self.set_offsets(vm);
1241 Ok(())
1242 }
1243
1244 pub fn set_offsets(&mut self, vm: &R8VM) {
1245 self.code_offset = vm.pmem.len();
1246 self.const_offset = vm.mem.env.len();
1247 }
1248}