1#![no_std]
3
4extern crate alloc;
5
6use alloc::{string::String, vec::Vec};
7
8pub mod value;
9pub mod cartridge;
10
11pub use value::{Value, HANDLE_NONE, HANDLE_SLOT_MAX};
12
13pub const FRAME_REGS: usize = 128;
14pub const FRAME_MASK_WORDS: usize = (FRAME_REGS + 63) / 64;
15
16pub const DISPATCH_ID: u8 = 0xE0;
17pub const DISPATCH_PORT_LOOKUP: u8 = 0x00;
18pub const DISPATCH_PORT_POP_HANDLER: u8 = 0x01;
19pub const DISPATCH_PORT_ENV: u8 = 0x02;
20pub const DISPATCH_PORT_RETURN_FN: u8 = 0x03;
21pub const DISPATCH_PORT_RETURN_ENV: u8 = 0x04;
22pub const DISPATCH_NO_MATCH: u16 = 0xFFFF;
23pub const DISPATCH_TAIL_FLAG: u64 = 1 << 16;
27
28pub const REGION_ID: u8 = 0xE1;
29pub const REGION_PORT_PUSH: u8 = 0x00;
30pub const REGION_PORT_POP: u8 = 0x01;
31pub const REGION_PORT_FORGET: u8 = 0x02;
32
33pub const MODULE_ID: u8 = 0xE2;
34pub const MODULE_PORT_TABLE: u8 = 0x00;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub struct Register(pub u8);
38
39impl Register {
40 pub fn to_usize(self) -> usize {
41 self.0 as usize
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum OpCode {
47 Add(Register, Register, Register),
48 Sub(Register, Register, Register),
49 Mul(Register, Register, Register),
50 Div(Register, Register, Register),
51 Mod(Register, Register, Register),
52 Neg(Register, Register),
53
54 FAdd(Register, Register, Register),
55 FSub(Register, Register, Register),
56 FMul(Register, Register, Register),
57 FDiv(Register, Register, Register),
58 FNeg(Register, Register),
59 FLt(Register, Register, Register),
60 FEq(Register, Register, Register),
61
62 Eq(Register, Register, Register),
63 Neq(Register, Register, Register),
64 Lt(Register, Register, Register),
65 Gt(Register, Register, Register),
66 Lte(Register, Register, Register),
67 Gte(Register, Register, Register),
68
69 And(Register, Register, Register),
70 Or(Register, Register, Register),
71 Xor(Register, Register, Register),
72 Shl(Register, Register, Register),
73 Shr(Register, Register, Register),
74
75 Jmp(i16),
76 Jz(Register, i16),
77 Jnz(Register, i16),
78 Call(Register, u16),
79 CallReg(Register, Register),
80 Ret(Register),
81
82 PushConst(Register, u16),
83 Copy(Register, Register),
84 Move(Register, Register),
85
86 Ld(Register, Register, u16),
87 St(Register, Register, u16),
88 LdIdx(Register, Register, Register),
89 StIdx(Register, Register, Register),
90
91 AddImm(Register, Register, i8),
92 SubImm(Register, Register, i8),
93
94 Alloc(Register, u16),
95 Drop(Register),
96
97 Dei(Register, Register),
98 Deo(Register, Register),
99
100 Handle(Register, u16),
101 Resume(Register, Register),
102
103 Raise(Register, Register, Register),
104}
105
106#[derive(Clone, Default, Debug)]
107pub struct BytecodeChunk {
108 pub code: Vec<OpCode>,
109 pub constants: Vec<u64>,
110 pub const_mask: Vec<u64>,
112 pub string_constants: Vec<String>,
113 pub reg_count: usize,
114 pub param_count: usize,
115 pub lines: Vec<u32>,
117 pub src_file: String,
119}
120
121impl BytecodeChunk {
122 #[inline]
123 pub fn const_is_handle(&self, idx: u16) -> bool {
124 let i = idx as usize;
125 let word = i / 64;
126 let bit = i % 64;
127 self.const_mask.get(word).map_or(false, |w| (w >> bit) & 1 == 1)
128 }
129}
130
131#[derive(Clone, Debug)]
132pub struct NativeChunk {
133 pub name: String,
134 pub param_count: usize,
135}
136
137#[derive(Clone, Debug)]
138pub enum Chunk {
139 Bytecode(BytecodeChunk),
140 Native(NativeChunk),
141}
142
143impl Chunk {
144 pub fn param_count(&self) -> usize {
145 match self {
146 Chunk::Bytecode(b) => b.param_count,
147 Chunk::Native(n) => n.param_count,
148 }
149 }
150
151 pub fn as_bytecode(&self) -> Option<&BytecodeChunk> {
152 if let Chunk::Bytecode(b) = self { Some(b) } else { None }
153 }
154}
155
156#[derive(Debug, Default)]
157pub struct Module {
158 pub functions: Vec<Chunk>,
159 pub entry: usize,
160 pub flags: u16,
161 pub exports: Vec<Export>,
162}
163
164#[derive(Debug, Clone)]
165pub struct Export {
166 pub name: String,
167 pub fn_id: u16,
168}
169
170pub const CART_FLAG_INT32_SAFE: u16 = 0x0001;
171
172#[inline(always)]
173pub fn mask_bit_set(mask: &[u64], idx: usize) -> bool {
174 let word = idx / 64;
175 let bit = idx % 64;
176 mask.get(word).map_or(false, |w| (w >> bit) & 1 == 1)
177}
178
179#[inline(always)]
180pub fn mask_set(mask: &mut [u64], idx: usize, on: bool) {
181 let word = idx / 64;
182 let bit = idx % 64;
183 if let Some(w) = mask.get_mut(word) {
184 if on { *w |= 1u64 << bit; } else { *w &= !(1u64 << bit); }
185 }
186}