fift/core/
cont.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use anyhow::Result;
5use num_bigint::BigInt;
6use tycho_vm::{SafeDelete, SafeRc};
7
8use super::stack::RcIntoDynFiftValue;
9use super::{Context, Dictionary, Stack, StackValue, StackValueType, WordList};
10use crate::core::IntoDynFiftValue;
11use crate::util::*;
12
13pub trait DynFiftCont {
14    fn new_dyn_fift_cont<T: FiftCont + 'static>(cont: T) -> RcFiftCont;
15}
16
17impl DynFiftCont for RcFiftCont {
18    #[inline]
19    fn new_dyn_fift_cont<T: FiftCont + 'static>(cont: T) -> RcFiftCont {
20        let cont: Rc<dyn FiftCont> = Rc::new(cont);
21        RcFiftCont::from(cont)
22    }
23}
24
25pub trait IntoDynFiftCont {
26    fn into_dyn_fift_cont(self) -> RcFiftCont;
27}
28
29impl<T: FiftCont> IntoDynFiftCont for Rc<T> {
30    #[inline]
31    fn into_dyn_fift_cont(self) -> RcFiftCont {
32        let this: Rc<dyn FiftCont> = self;
33        RcFiftCont::from(this)
34    }
35}
36
37impl<T: FiftCont> IntoDynFiftCont for SafeRc<T> {
38    #[inline]
39    fn into_dyn_fift_cont(self) -> RcFiftCont {
40        Rc::<T>::into_dyn_fift_cont(SafeRc::into_inner(self))
41    }
42}
43
44pub type RcFiftCont = SafeRc<dyn FiftCont>;
45
46pub trait FiftCont: SafeDelete + RcIntoDynFiftValue {
47    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>>;
48
49    fn up(&self) -> Option<&RcFiftCont> {
50        None
51    }
52
53    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
54
55    fn fmt_dump(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        self.fmt_name(d, f)
57    }
58}
59
60impl dyn FiftCont + '_ {
61    pub fn display_backtrace<'a>(&'a self, d: &'a Dictionary) -> impl std::fmt::Display + 'a {
62        struct ContinuationBacktrace<'a> {
63            d: &'a Dictionary,
64            cont: &'a dyn FiftCont,
65        }
66
67        impl std::fmt::Display for ContinuationBacktrace<'_> {
68            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69                let mut cont = self.cont;
70                let mut newline = "";
71                for i in 1..=16 {
72                    write!(f, "{newline}{i:>4}: {}", cont.display_dump(self.d))?;
73                    newline = "\n";
74                    match cont.up() {
75                        Some(next) => cont = next.as_ref(),
76                        None => return Ok(()),
77                    }
78                }
79                write!(f, "{newline}... more levels ...")
80            }
81        }
82
83        ContinuationBacktrace { d, cont: self }
84    }
85
86    pub fn display_name<'a>(&'a self, d: &'a Dictionary) -> impl std::fmt::Display + 'a {
87        struct ContinuationWriteName<'a> {
88            d: &'a Dictionary,
89            cont: &'a dyn FiftCont,
90        }
91
92        impl std::fmt::Display for ContinuationWriteName<'_> {
93            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94                self.cont.fmt_name(self.d, f)
95            }
96        }
97
98        ContinuationWriteName { d, cont: self }
99    }
100
101    pub fn display_dump<'a>(&'a self, d: &'a Dictionary) -> impl std::fmt::Display + 'a {
102        struct ContinuationDump<'a> {
103            d: &'a Dictionary,
104            cont: &'a dyn FiftCont,
105        }
106
107        impl std::fmt::Display for ContinuationDump<'_> {
108            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109                self.cont.fmt_dump(self.d, f)
110            }
111        }
112
113        ContinuationDump { d, cont: self }
114    }
115}
116
117impl<T: FiftCont + 'static> StackValue for T {
118    fn ty(&self) -> StackValueType {
119        StackValueType::Cont
120    }
121
122    fn is_equal(&self, other: &dyn StackValue) -> bool {
123        StackValue::is_equal(self as &dyn FiftCont, other)
124    }
125
126    fn fmt_dump(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        StackValue::fmt_dump(self as &dyn FiftCont, f)
128    }
129
130    fn as_cont(&self) -> ::anyhow::Result<&dyn FiftCont> {
131        Ok(self)
132    }
133
134    fn rc_into_cont(self: Rc<Self>) -> Result<Rc<dyn FiftCont>> {
135        Ok(self)
136    }
137}
138
139#[derive(Clone, Copy)]
140pub struct InterpreterCont;
141
142impl FiftCont for InterpreterCont {
143    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
144        thread_local! {
145            static COMPILE_EXECUTE: RcFiftCont = SafeRc::new_dyn_fift_cont(CompileExecuteCont);
146            static WORD: RefCell<String> = RefCell::new(String::with_capacity(128));
147        };
148
149        let this = self.into_dyn_fift_cont();
150
151        ctx.stdout.flush()?;
152
153        let compile_exec = COMPILE_EXECUTE.with(|c| c.clone());
154
155        'source_block: loop {
156            'token: {
157                let mut rewind = None;
158                let entry = 'entry: {
159                    let Some(token) = ctx.input.scan_word()? else {
160                        if ctx.input.pop_source_block() {
161                            continue 'source_block;
162                        }
163                        return Ok(None);
164                    };
165
166                    // Find in predefined entries
167                    if let Some(entry) = WORD.with(|word| {
168                        let mut word = word.borrow_mut();
169                        word.clear();
170                        word.push_str(token);
171                        word.push(' ');
172
173                        // Search parsed token as a separate word first
174                        if let Some(entry) = ctx.dicts.lookup(&word, false)? {
175                            return Ok::<_, anyhow::Error>(Some(entry));
176                        }
177
178                        // Then find the largest possible prefix
179                        while !word.is_empty() {
180                            word.pop();
181                            if let Some(entry) = ctx.dicts.lookup(&word, false)? {
182                                rewind = Some(word.len());
183                                return Ok(Some(entry));
184                            }
185                        }
186
187                        Ok(None)
188                    })? {
189                        break 'entry entry;
190                    }
191
192                    // Try parse as number
193                    if let Some(value) = ImmediateInt::try_from_str(token)? {
194                        ctx.stack.push(value.num)?;
195                        if let Some(denom) = value.denom {
196                            ctx.stack.push(denom)?;
197                            ctx.stack.push_argcount(2)?;
198                        } else {
199                            ctx.stack.push_argcount(1)?;
200                        }
201                        break 'token;
202                    }
203
204                    anyhow::bail!("Undefined word `{token}`");
205                };
206
207                if let Some(rewind) = rewind {
208                    ctx.input.rewind(rewind);
209                } else {
210                    ctx.input.skip_line_whitespace();
211                }
212
213                if entry.active {
214                    ctx.next = SeqCont::make(
215                        Some(compile_exec),
216                        SeqCont::make(Some(this), ctx.next.take()),
217                    );
218                    return Ok(Some(entry.definition.clone()));
219                } else {
220                    ctx.stack.push_int(0)?;
221                    ctx.stack.push_raw(entry.definition.into_dyn_fift_value())?;
222                }
223            };
224
225            ctx.exit_interpret.store(match &ctx.next {
226                Some(next) => next.clone().into_dyn_fift_value(),
227                None => NopCont::value_instance(),
228            });
229
230            ctx.next = SeqCont::make(Some(this), ctx.next.take());
231            break Ok(Some(compile_exec));
232        }
233    }
234
235    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236        f.write_str("<text interpreter continuation>")
237    }
238}
239
240#[derive(Clone, Copy)]
241struct CompileExecuteCont;
242
243impl FiftCont for CompileExecuteCont {
244    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
245        Ok(if ctx.state.is_compile() {
246            ctx.compile_stack_top()?;
247            None
248        } else {
249            Some(ctx.execute_stack_top()?)
250        })
251    }
252
253    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254        f.write_str("<compile execute continuation>")
255    }
256}
257
258#[derive(Clone)]
259pub struct ListCont {
260    pub list: Rc<WordList>,
261    pub after: Option<RcFiftCont>,
262    pub pos: usize,
263}
264
265impl FiftCont for ListCont {
266    fn run(mut self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
267        let is_last = self.pos + 1 >= self.list.items.len();
268        let Some(current) = self.list.items.get(self.pos).cloned() else {
269            return Ok(ctx.next.take());
270        };
271
272        match Rc::get_mut(&mut self) {
273            Some(this) => {
274                ctx.insert_before_next(&mut this.after);
275                this.pos += 1;
276                ctx.next = if is_last {
277                    this.after.take()
278                } else {
279                    Some(self.into_dyn_fift_cont())
280                };
281            }
282            None => {
283                if let Some(next) = ctx.next.take() {
284                    ctx.next = Some(RcFiftCont::new_dyn_fift_cont(ListCont {
285                        after: SeqCont::make(self.after.clone(), Some(next)),
286                        list: self.list.clone(),
287                        pos: self.pos + 1,
288                    }))
289                } else if is_last {
290                    ctx.next = self.after.clone()
291                } else {
292                    ctx.next = Some(RcFiftCont::new_dyn_fift_cont(ListCont {
293                        after: self.after.clone(),
294                        list: self.list.clone(),
295                        pos: self.pos + 1,
296                    }))
297                }
298            }
299        }
300
301        Ok(Some(current))
302    }
303
304    fn up(&self) -> Option<&RcFiftCont> {
305        self.after.as_ref()
306    }
307
308    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309        write_cont_name(self, d, f)
310    }
311
312    fn fmt_dump(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313        if self.pos == 0 {
314            f.write_str("{")?;
315            for item in &self.list.items {
316                write!(f, " {}", item.display_name(d))?;
317            }
318            f.write_str(" }")
319        } else {
320            const N: usize = 16;
321
322            if let Some(name) = d.resolve_name(self) {
323                write!(f, "[in {name}:] ")?;
324            }
325
326            let len = self.list.items.len();
327            let start = self.pos.saturating_sub(N);
328            let items = self.list.items.iter();
329
330            if start > 0 {
331                f.write_str("... ")?;
332            }
333            for (i, item) in items.enumerate().skip(start).take(N) {
334                if i == self.pos {
335                    f.write_str("**HERE** ")?;
336                }
337                write!(f, "{} ", item.display_name(d))?;
338            }
339            if self.pos + N < len {
340                f.write_str("...")?;
341            }
342            Ok(())
343        }
344    }
345}
346
347#[derive(Clone, Copy)]
348pub struct NopCont;
349
350impl NopCont {
351    thread_local! {
352        static INSTANCE: (RcFiftCont, SafeRc<dyn StackValue>) = {
353            let cont = RcFiftCont::new_dyn_fift_cont(NopCont);
354            let value: SafeRc<dyn StackValue> = cont.clone().into_dyn_fift_value();
355            (cont, value)
356        };
357    }
358
359    pub fn instance() -> RcFiftCont {
360        Self::INSTANCE.with(|(c, _)| c.clone())
361    }
362
363    pub fn value_instance() -> SafeRc<dyn StackValue> {
364        Self::INSTANCE.with(|(_, v)| v.clone())
365    }
366
367    pub fn is_nop(cont: &dyn FiftCont) -> bool {
368        let left = Self::INSTANCE.with(|(c, _)| SafeRc::as_ptr(c) as *const ());
369        std::ptr::addr_eq(left, cont)
370    }
371}
372
373impl FiftCont for NopCont {
374    fn run(self: Rc<Self>, _: &mut crate::Context) -> Result<Option<RcFiftCont>> {
375        Ok(None)
376    }
377
378    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
379        f.write_str("<nop>")
380    }
381}
382
383#[derive(Clone)]
384pub struct SeqCont {
385    pub first: Option<RcFiftCont>,
386    pub second: Option<RcFiftCont>,
387}
388
389impl SeqCont {
390    pub fn make(first: Option<RcFiftCont>, second: Option<RcFiftCont>) -> Option<RcFiftCont> {
391        if second.is_none() {
392            first
393        } else if let Some(first) = first {
394            Some(RcFiftCont::new_dyn_fift_cont(Self {
395                first: Some(first),
396                second,
397            }))
398        } else {
399            second
400        }
401    }
402}
403
404impl FiftCont for SeqCont {
405    fn run(mut self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
406        Ok(match Rc::get_mut(&mut self) {
407            Some(this) => {
408                if ctx.next.is_none() {
409                    ctx.next = this.second.take();
410                    this.first.take()
411                } else {
412                    let result = std::mem::replace(&mut this.first, this.second.take());
413                    this.second = ctx.next.take();
414                    ctx.next = Some(self.into_dyn_fift_cont());
415                    result
416                }
417            }
418            None => {
419                ctx.next = SeqCont::make(self.second.clone(), ctx.next.take());
420                self.first.clone()
421            }
422        })
423    }
424
425    fn up(&self) -> Option<&RcFiftCont> {
426        self.second.as_ref()
427    }
428
429    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
430        if let Some(first) = &self.first {
431            first.as_ref().fmt_name(d, f)
432        } else {
433            Ok(())
434        }
435    }
436
437    fn fmt_dump(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
438        if let Some(first) = &self.first {
439            first.as_ref().fmt_dump(d, f)?;
440        }
441        Ok(())
442    }
443}
444
445#[derive(Clone)]
446pub struct TimesCont {
447    pub body: Option<RcFiftCont>,
448    pub after: Option<RcFiftCont>,
449    pub count: usize,
450}
451
452impl FiftCont for TimesCont {
453    fn run(mut self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
454        Ok(match Rc::get_mut(&mut self) {
455            Some(this) => {
456                ctx.insert_before_next(&mut this.after);
457
458                if this.count > 1 {
459                    this.count -= 1;
460                    let body = this.body.clone();
461                    ctx.next = Some(self.into_dyn_fift_cont());
462                    body
463                } else {
464                    ctx.next = this.after.take();
465                    this.body.take()
466                }
467            }
468            None => {
469                let next = SeqCont::make(self.after.clone(), ctx.next.take());
470
471                ctx.next = if self.count > 1 {
472                    Some(RcFiftCont::new_dyn_fift_cont(Self {
473                        body: self.body.clone(),
474                        after: next,
475                        count: self.count - 1,
476                    }))
477                } else {
478                    next
479                };
480
481                self.body.clone()
482            }
483        })
484    }
485
486    fn up(&self) -> Option<&RcFiftCont> {
487        self.after.as_ref()
488    }
489
490    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491        write!(f, "<repeat {} times>", self.count)
492    }
493
494    fn fmt_dump(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495        write!(f, "<repeat {} times:> ", self.count)?;
496        if let Some(body) = &self.body {
497            FiftCont::fmt_dump(body.as_ref(), d, f)?;
498        }
499        Ok(())
500    }
501}
502
503#[derive(Clone)]
504pub struct UntilCont {
505    pub body: Option<RcFiftCont>,
506    pub after: Option<RcFiftCont>,
507}
508
509impl FiftCont for UntilCont {
510    fn run(mut self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
511        if ctx.stack.pop_bool()? {
512            return Ok(match Rc::get_mut(&mut self) {
513                Some(this) => this.after.take(),
514                None => self.after.clone(),
515            });
516        }
517
518        let body = self.body.clone();
519        let next = match Rc::get_mut(&mut self) {
520            Some(this) => {
521                ctx.insert_before_next(&mut this.after);
522                self
523            }
524            None => {
525                if let Some(next) = ctx.next.take() {
526                    Rc::new(UntilCont {
527                        body: self.body.clone(),
528                        after: SeqCont::make(self.after.clone(), Some(next)),
529                    })
530                } else {
531                    self
532                }
533            }
534        };
535        ctx.next = Some(next.into_dyn_fift_cont());
536        Ok(body)
537    }
538
539    fn up(&self) -> Option<&RcFiftCont> {
540        self.after.as_ref()
541    }
542
543    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544        f.write_str("<until loop continuation>")
545    }
546
547    fn fmt_dump(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
548        f.write_str("<until loop continuation:> ")?;
549        if let Some(body) = &self.body {
550            FiftCont::fmt_dump(body.as_ref(), d, f)?;
551        }
552        Ok(())
553    }
554}
555
556#[derive(Clone)]
557pub struct WhileCont {
558    pub condition: Option<RcFiftCont>,
559    pub body: Option<RcFiftCont>,
560    pub after: Option<RcFiftCont>,
561    pub running_body: bool,
562}
563
564impl WhileCont {
565    fn stage_name(&self) -> &'static str {
566        if self.running_body {
567            "body"
568        } else {
569            "condition"
570        }
571    }
572}
573
574impl FiftCont for WhileCont {
575    fn run(mut self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
576        let cont = if self.running_body {
577            if !ctx.stack.pop_bool()? {
578                return Ok(match Rc::get_mut(&mut self) {
579                    Some(this) => this.after.take(),
580                    None => self.after.clone(),
581                });
582            }
583
584            self.body.clone()
585        } else {
586            self.condition.clone()
587        };
588
589        let next = match Rc::get_mut(&mut self) {
590            Some(this) => {
591                ctx.insert_before_next(&mut this.after);
592                this.running_body = !this.running_body;
593                self
594            }
595            None => Rc::new(Self {
596                condition: self.condition.clone(),
597                body: self.body.clone(),
598                after: SeqCont::make(self.after.clone(), ctx.next.take()),
599                running_body: !self.running_body,
600            }),
601        };
602
603        ctx.next = Some(next.into_dyn_fift_cont());
604        Ok(cont)
605    }
606
607    fn up(&self) -> Option<&RcFiftCont> {
608        self.after.as_ref()
609    }
610
611    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
612        write!(f, "<while loop {}>", self.stage_name())
613    }
614
615    fn fmt_dump(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
616        write!(f, "<while loop {}:>", self.stage_name())?;
617        let stage = if self.running_body {
618            self.body.as_ref()
619        } else {
620            self.condition.as_ref()
621        };
622        if let Some(stage) = stage {
623            FiftCont::fmt_dump(stage.as_ref(), d, f)?;
624        }
625        Ok(())
626    }
627}
628
629pub struct LoopCont<T> {
630    inner: T,
631    state: LoopContState,
632    func: RcFiftCont,
633    after: Option<RcFiftCont>,
634}
635
636impl<T: Clone> Clone for LoopCont<T> {
637    #[inline]
638    fn clone(&self) -> Self {
639        Self {
640            inner: self.inner.clone(),
641            state: self.state,
642            func: self.func.clone(),
643            after: self.after.clone(),
644        }
645    }
646}
647
648impl<T> LoopCont<T> {
649    pub fn new(inner: T, func: RcFiftCont, after: Option<RcFiftCont>) -> Self {
650        Self {
651            inner,
652            state: LoopContState::Init,
653            func,
654            after,
655        }
656    }
657}
658
659impl<T: LoopContImpl + 'static> FiftCont for LoopCont<T> {
660    fn run(mut self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
661        let Some(this) = Rc::get_mut(&mut self) else {
662            return Ok(Some(SafeRc::new_dyn_fift_cont(Self {
663                inner: self.inner.clone(),
664                state: self.state,
665                func: self.func.clone(),
666                after: self.after.clone(),
667            })));
668        };
669
670        ctx.insert_before_next(&mut this.after);
671        Ok(loop {
672            match this.state {
673                LoopContState::Init => {
674                    if !this.inner.init(ctx)? {
675                        break this.after.take();
676                    }
677                    this.state = LoopContState::PreExec;
678                }
679                LoopContState::PreExec => {
680                    if !this.inner.pre_exec(ctx)? {
681                        this.state = LoopContState::Finalize;
682                        continue;
683                    }
684                    this.state = LoopContState::PostExec;
685                    let res = self.func.clone();
686                    ctx.next = Some(self.into_dyn_fift_cont());
687                    break Some(res);
688                }
689                LoopContState::PostExec => {
690                    if !this.inner.post_exec(ctx)? {
691                        this.state = LoopContState::Finalize;
692                        continue;
693                    }
694                    this.state = LoopContState::PreExec;
695                    break Some(self.into_dyn_fift_cont());
696                }
697                LoopContState::Finalize => {
698                    break if this.inner.finalize(ctx)? {
699                        this.after.take()
700                    } else {
701                        None
702                    };
703                }
704            }
705        })
706    }
707
708    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
709        write!(f, "<generic loop continuation state {:?}>", self.state)
710    }
711}
712
713pub trait LoopContImpl: Clone {
714    fn init(&mut self, ctx: &mut Context) -> Result<bool> {
715        _ = ctx;
716        Ok(true)
717    }
718    fn pre_exec(&mut self, ctx: &mut Context) -> Result<bool> {
719        _ = ctx;
720        Ok(true)
721    }
722    fn post_exec(&mut self, ctx: &mut Context) -> Result<bool> {
723        _ = ctx;
724        Ok(true)
725    }
726    fn finalize(&mut self, ctx: &mut Context) -> Result<bool> {
727        _ = ctx;
728        Ok(true)
729    }
730}
731
732#[derive(Debug, Clone, Copy, Eq, PartialEq)]
733enum LoopContState {
734    Init,
735    PreExec,
736    PostExec,
737    Finalize,
738}
739
740#[derive(Clone)]
741pub struct IntLitCont(BigInt);
742
743impl<T> From<T> for IntLitCont
744where
745    BigInt: From<T>,
746{
747    fn from(value: T) -> Self {
748        Self(BigInt::from(value))
749    }
750}
751
752impl FiftCont for IntLitCont {
753    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
754        let value = match Rc::try_unwrap(self) {
755            Ok(value) => value.0,
756            Err(this) => this.0.clone(),
757        };
758        ctx.stack.push(value)?;
759        Ok(None)
760    }
761
762    fn fmt_name(&self, _: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
763        write!(f, "{}", self.0)
764    }
765}
766
767#[derive(Clone)]
768pub struct LitCont(pub SafeRc<dyn StackValue>);
769
770impl FiftCont for LitCont {
771    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
772        let value = match Rc::try_unwrap(self) {
773            Ok(value) => value.0,
774            Err(this) => this.0.clone(),
775        };
776        ctx.stack.push_raw(value)?;
777        Ok(None)
778    }
779
780    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
781        write_lit_cont_name(self.0.as_ref(), d, f)
782    }
783}
784
785#[derive(Clone)]
786pub struct MultiLitCont(pub Vec<SafeRc<dyn StackValue>>);
787
788impl FiftCont for MultiLitCont {
789    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
790        match Rc::try_unwrap(self) {
791            Ok(value) => {
792                for item in value.0 {
793                    ctx.stack.push_raw(item)?;
794                }
795            }
796            Err(this) => {
797                for item in &this.0 {
798                    ctx.stack.push_raw(item.clone())?;
799                }
800            }
801        };
802        Ok(None)
803    }
804
805    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
806        let mut first = true;
807        for item in &self.0 {
808            if !std::mem::take(&mut first) {
809                f.write_str(" ")?;
810            }
811            write_lit_cont_name(item.as_ref(), d, f)?;
812        }
813        Ok(())
814    }
815}
816
817pub type ContextWordFunc = fn(&mut Context) -> Result<()>;
818
819impl FiftCont for ContextWordFunc {
820    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
821        (self)(ctx)?;
822        Ok(None)
823    }
824
825    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
826        write_cont_name(self, d, f)
827    }
828}
829
830pub type ContextTailWordFunc = fn(&mut Context) -> Result<Option<RcFiftCont>>;
831
832impl FiftCont for ContextTailWordFunc {
833    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
834        (self)(ctx)
835    }
836
837    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
838        write_cont_name(self, d, f)
839    }
840}
841
842pub type StackWordFunc = fn(&mut Stack) -> Result<()>;
843
844impl FiftCont for StackWordFunc {
845    fn run(self: Rc<Self>, ctx: &mut Context) -> Result<Option<RcFiftCont>> {
846        (self)(&mut ctx.stack)?;
847        Ok(None)
848    }
849
850    fn fmt_name(&self, d: &Dictionary, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
851        write_cont_name(self, d, f)
852    }
853}
854
855// === impl Context ===
856
857impl Context<'_> {
858    fn insert_before_next(&mut self, cont: &mut Option<RcFiftCont>) {
859        if let Some(next) = self.next.take() {
860            *cont = match cont.take() {
861                Some(prev) => Some(RcFiftCont::new_dyn_fift_cont(SeqCont {
862                    first: Some(prev),
863                    second: Some(next),
864                })),
865                None => Some(next),
866            };
867        }
868    }
869}
870
871fn write_lit_cont_name(
872    stack_entry: &dyn StackValue,
873    d: &Dictionary,
874    f: &mut std::fmt::Formatter<'_>,
875) -> std::fmt::Result {
876    let ty = stack_entry.ty();
877    match ty {
878        StackValueType::Int | StackValueType::String | StackValueType::Builder => {
879            stack_entry.fmt_dump(f)
880        }
881        _ => {
882            if let Ok(cont) = stack_entry.as_cont() {
883                write!(f, "{{ {} }}", cont.display_dump(d))
884            } else {
885                write!(f, "<literal of type {:?}>", ty)
886            }
887        }
888    }
889}
890
891fn write_cont_name(
892    cont: &dyn FiftCont,
893    d: &Dictionary,
894    f: &mut std::fmt::Formatter<'_>,
895) -> std::fmt::Result {
896    if let Some(name) = d.resolve_name(cont) {
897        f.write_str(name.trim_end())
898    } else {
899        write!(f, "<continuation {:?}>", cont as *const _ as *const ())
900    }
901}