lucia_lang/
context.rs

1use std::ops;
2
3use gc_arena::{Arena, ArenaParameters, Collect, Mutation, Rootable};
4
5use crate::{
6    compiler::code::Code,
7    frame::{FrameMode, Frames},
8    libs,
9    objects::{Closure, Registry, StaticValue, Table},
10};
11
12#[derive(Clone, Collect)]
13#[collect(no_drop)]
14pub struct State<'gc> {
15    pub globals: Table<'gc>,
16    pub builtins: Table<'gc>,
17    pub libs: Table<'gc>,
18    pub registry: Registry<'gc>,
19    pub frames: Frames<'gc>,
20}
21
22impl<'gc> State<'gc> {
23    pub fn new(mc: &Mutation<'gc>) -> State<'gc> {
24        Self {
25            globals: Table::new(mc),
26            builtins: Table::new(mc),
27            libs: Table::new(mc),
28            registry: Registry::new(mc),
29            frames: Frames::new(mc),
30        }
31    }
32
33    pub fn ctx(&'gc self, mutation: &'gc Mutation<'gc>) -> Context<'gc> {
34        Context {
35            mutation,
36            state: self,
37        }
38    }
39}
40
41#[derive(Copy, Clone)]
42pub struct Context<'gc> {
43    pub mutation: &'gc Mutation<'gc>,
44    pub state: &'gc State<'gc>,
45}
46
47impl<'gc> ops::Deref for Context<'gc> {
48    type Target = Mutation<'gc>;
49
50    fn deref(&self) -> &Self::Target {
51        self.mutation
52    }
53}
54
55pub struct Lucia(Arena<Rootable![State<'_>]>);
56
57const COLLECTOR_GRANULARITY: f64 = 1024.0;
58
59impl Lucia {
60    pub fn new() -> Lucia {
61        let arena =
62            Arena::<Rootable![State<'_>]>::new(ArenaParameters::default(), |mc| State::new(mc));
63        let mut lucia = Lucia(arena);
64        lucia.load_libs();
65        lucia
66    }
67
68    pub fn load_libs(&mut self) {
69        self.run(|ctx| {
70            libs::load_builtin(ctx);
71            ctx.state.libs.set(ctx, "std::io", libs::io_lib(ctx));
72            ctx.state
73                .libs
74                .set(ctx, "std::string", libs::string_lib(ctx));
75            ctx.state.libs.set(ctx, "std::table", libs::table_lib(ctx));
76        })
77    }
78
79    pub fn gc_collect(&mut self) {
80        self.0.collect_all();
81    }
82
83    pub fn run<F, T>(&mut self, f: F) -> T
84    where
85        F: for<'gc> FnOnce(Context<'gc>) -> T,
86    {
87        let r = self.0.mutate(move |mc, state| f(state.ctx(mc)));
88        if self.0.allocation_debt() > COLLECTOR_GRANULARITY {
89            self.0.collect_debt();
90        }
91        r
92    }
93
94    pub fn run_frame(&mut self) {
95        loop {
96            if self.run(|ctx| match ctx.state.frames.mode() {
97                FrameMode::Normal => {
98                    ctx.state.frames.step(ctx).unwrap();
99                    false
100                }
101                _ => true,
102            }) {
103                break;
104            }
105        }
106    }
107
108    pub fn run_code(&mut self, code: Code) -> StaticValue {
109        self.run(|ctx| {
110            let closure = Closure::new(&ctx, code.clone(), None);
111            ctx.state
112                .frames
113                .start(ctx, closure.into(), Vec::new())
114                .unwrap();
115        });
116        self.run_frame();
117        self.run(|ctx| {
118            ctx.state
119                .registry
120                .stash(&ctx, ctx.state.frames.0.borrow().return_value)
121        })
122    }
123}
124
125impl Default for Lucia {
126    fn default() -> Self {
127        Lucia::new()
128    }
129}