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}