1#![cfg_attr(not(feature = "std"), no_std)]
2
3extern crate alloc;
4
5use alloc::boxed::Box;
6use alloc::rc::Rc;
7use alloc::string::String;
8use alloc::string::ToString;
9use alloc::vec;
10use alloc::vec::Vec;
11use core::cell::RefCell;
12
13#[cfg(all(feature = "serde", feature = "std"))]
14use serde::{Deserialize, Serialize};
15
16pub mod disasm;
17pub mod format;
18pub mod register;
19pub use disasm::{disassemble_register, disassemble_stack};
20pub use format::{decode, encode, BytecodeFormatError, FORMAT_MAGIC, FORMAT_VERSION};
21pub use register::{parameter_slots, RegChunk, RegOp, StackToRegister};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26#[cfg_attr(
27 all(feature = "serde", feature = "std"),
28 derive(Serialize, Deserialize)
29)]
30#[repr(u8)]
31pub enum Opcode {
32 Push = 0,
34 Pop,
35 Dup,
36
37 LoadLocal,
39 StoreLocal,
40 LoadGlobal,
41 StoreGlobal,
42 LoadUpvalue,
43 StoreUpvalue,
44
45 Add,
47 Sub,
48 Mul,
49 Div,
50 Mod,
51 Pow,
52 Neg,
53
54 BitAnd,
56 BitOr,
57 BitXor,
58 BitNot,
59 Shl,
60 Shr,
61
62 Eq,
64 Ne,
65 Lt,
66 Le,
67 Gt,
68 Ge,
69 AddImm,
71 SubImm,
72 MulImm,
73 EqImm,
74 NeImm,
75 LtImm,
76 LeImm,
77 GtImm,
78 GeImm,
79
80 And,
82 Or,
83 Not,
84
85 Jump,
87 JumpIfFalse,
88 JumpIfTrue,
89 Call,
90 TailCall,
91 Return,
92
93 GetProperty,
95 SetProperty,
96 Invoke,
97
98 BuildArray,
100 BuildMap,
101 IndexGet,
102 IndexSet,
103
104 CreateClass,
106 CreateInstance,
107 GetMethod,
108
109 MatchPattern,
111
112 MakeClosure,
114
115 Throw,
117 TryBegin,
118 TryEnd,
119 WrapOk,
120 WrapErr,
121 WrapSome,
122 UnwrapOk,
123 UnwrapErr,
124 UnwrapSome,
125 Try,
127
128 Nop,
130 Halt,
131 CallDirect,
134 Argc,
136 Slide,
141}
142
143impl Opcode {
144 pub fn as_u8(self) -> u8 {
146 self as u8
147 }
148
149 pub fn from_u8(v: u8) -> Option<Self> {
150 Some(match v {
151 0 => Opcode::Push,
152 1 => Opcode::Pop,
153 2 => Opcode::Dup,
154 3 => Opcode::LoadLocal,
155 4 => Opcode::StoreLocal,
156 5 => Opcode::LoadGlobal,
157 6 => Opcode::StoreGlobal,
158 7 => Opcode::LoadUpvalue,
159 8 => Opcode::StoreUpvalue,
160 9 => Opcode::Add,
161 10 => Opcode::Sub,
162 11 => Opcode::Mul,
163 12 => Opcode::Div,
164 13 => Opcode::Mod,
165 14 => Opcode::Pow,
166 15 => Opcode::Neg,
167 16 => Opcode::BitAnd,
168 17 => Opcode::BitOr,
169 18 => Opcode::BitXor,
170 19 => Opcode::BitNot,
171 20 => Opcode::Shl,
172 21 => Opcode::Shr,
173 22 => Opcode::Eq,
174 23 => Opcode::Ne,
175 24 => Opcode::Lt,
176 25 => Opcode::Le,
177 26 => Opcode::Gt,
178 27 => Opcode::Ge,
179 28 => Opcode::AddImm,
180 29 => Opcode::SubImm,
181 30 => Opcode::MulImm,
182 31 => Opcode::EqImm,
183 32 => Opcode::NeImm,
184 33 => Opcode::LtImm,
185 34 => Opcode::LeImm,
186 35 => Opcode::GtImm,
187 36 => Opcode::GeImm,
188 37 => Opcode::And,
189 38 => Opcode::Or,
190 39 => Opcode::Not,
191 40 => Opcode::Jump,
192 41 => Opcode::JumpIfFalse,
193 42 => Opcode::JumpIfTrue,
194 43 => Opcode::Call,
195 44 => Opcode::TailCall,
196 45 => Opcode::Return,
197 46 => Opcode::GetProperty,
198 47 => Opcode::SetProperty,
199 48 => Opcode::Invoke,
200 49 => Opcode::BuildArray,
201 50 => Opcode::BuildMap,
202 51 => Opcode::IndexGet,
203 52 => Opcode::IndexSet,
204 53 => Opcode::CreateClass,
205 54 => Opcode::CreateInstance,
206 55 => Opcode::GetMethod,
207 56 => Opcode::MatchPattern,
208 57 => Opcode::MakeClosure,
209 58 => Opcode::Throw,
210 59 => Opcode::TryBegin,
211 60 => Opcode::TryEnd,
212 61 => Opcode::WrapOk,
213 62 => Opcode::WrapErr,
214 63 => Opcode::WrapSome,
215 64 => Opcode::UnwrapOk,
216 65 => Opcode::UnwrapErr,
217 66 => Opcode::UnwrapSome,
218 67 => Opcode::Try,
219 68 => Opcode::Nop,
220 69 => Opcode::Halt,
221 70 => Opcode::CallDirect,
222 71 => Opcode::Argc,
223 72 => Opcode::Slide,
224 _ => return None,
225 })
226 }
227}
228
229#[derive(Debug, Clone, PartialEq)]
231#[cfg_attr(
232 all(feature = "serde", feature = "std"),
233 derive(Serialize, Deserialize)
234)]
235pub struct FunctionObj {
236 pub name: Rc<str>,
237 pub arity: usize,
239 pub required: usize,
241 pub chunk_index: usize,
242}
243
244#[derive(Debug, Clone, PartialEq)]
245#[cfg_attr(
246 all(feature = "serde", feature = "std"),
247 derive(Serialize, Deserialize)
248)]
249pub struct ClosureObj {
250 pub function_index: usize,
251 pub arity: usize,
252 pub required: usize,
253 pub upvalues: Vec<usize>,
254}
255
256#[derive(Debug, Clone, PartialEq)]
257#[cfg_attr(
258 all(feature = "serde", feature = "std"),
259 derive(Serialize, Deserialize)
260)]
261pub struct ClassObj {
262 pub name: Rc<str>,
263 pub methods: Rc<Vec<(String, usize)>>,
264 pub superclass: Option<Rc<str>>,
265 pub properties: Rc<Vec<(String, Value)>>,
266}
267
268#[derive(Debug, Clone)]
269#[cfg_attr(
270 all(feature = "serde", feature = "std"),
271 derive(Serialize, Deserialize)
272)]
273pub enum Value {
274 Null,
275 Bool(bool),
276 Int(i64),
277 Float(f64),
278 Str(Rc<str>),
279 Char(char),
280 Array(Rc<RefCell<Vec<Value>>>),
281 Map(Rc<RefCell<Vec<(Value, Value)>>>),
282 Tuple(Rc<RefCell<Vec<Value>>>),
283 Function(Rc<FunctionObj>),
284 Closure(Rc<ClosureObj>),
285 Class(Rc<ClassObj>),
286 Instance {
287 class_index: usize,
288 fields: Rc<RefCell<Vec<(String, Value)>>>,
289 },
290 Ok(Box<Value>),
291 Err(Box<Value>),
292 Some(Box<Value>),
293 Builtin {
294 name: Rc<str>,
295 arity: usize,
296 },
297}
298
299impl PartialEq for Value {
300 fn eq(&self, other: &Self) -> bool {
301 match (self, other) {
302 (Value::Null, Value::Null) => true,
303 (Value::Bool(a), Value::Bool(b)) => a == b,
304 (Value::Int(a), Value::Int(b)) => a == b,
305 (Value::Float(a), Value::Float(b)) => a == b,
306 (Value::Str(a), Value::Str(b)) => a == b,
307 (Value::Char(a), Value::Char(b)) => a == b,
308 (Value::Array(a), Value::Array(b)) => *a.borrow() == *b.borrow(),
309 (Value::Map(a), Value::Map(b)) => *a.borrow() == *b.borrow(),
310 (Value::Tuple(a), Value::Tuple(b)) => *a.borrow() == *b.borrow(),
311 (Value::Function(a), Value::Function(b)) => a == b,
312 (Value::Closure(a), Value::Closure(b)) => a == b,
313 (Value::Class(a), Value::Class(b)) => a == b,
314 (
315 Value::Instance {
316 class_index: c1,
317 fields: f1,
318 },
319 Value::Instance {
320 class_index: c2,
321 fields: f2,
322 },
323 ) => c1 == c2 && *f1.borrow() == *f2.borrow(),
324 (Value::Ok(a), Value::Ok(b)) => a == b,
325 (Value::Err(a), Value::Err(b)) => a == b,
326 (Value::Some(a), Value::Some(b)) => a == b,
327 (
328 Value::Builtin {
329 name: n1,
330 arity: a1,
331 },
332 Value::Builtin {
333 name: n2,
334 arity: a2,
335 },
336 ) => n1 == n2 && a1 == a2,
337 _ => false,
338 }
339 }
340}
341
342#[derive(Debug, Clone, Copy, PartialEq)]
344#[cfg_attr(
345 all(feature = "serde", feature = "std"),
346 derive(Serialize, Deserialize)
347)]
348pub struct Instruction {
349 pub opcode: Opcode,
350 pub operand: Option<u32>,
351 pub line: u32,
352}
353
354#[derive(Debug, Clone, PartialEq)]
355#[cfg_attr(
356 all(feature = "serde", feature = "std"),
357 derive(Serialize, Deserialize)
358)]
359pub struct Chunk {
360 pub instructions: Vec<Instruction>,
361 pub constants: Vec<Value>,
362 pub name: String,
363}
364
365impl Chunk {
366 pub fn new(name: String) -> Self {
367 Self {
368 instructions: Vec::new(),
369 constants: Vec::new(),
370 name,
371 }
372 }
373
374 pub fn emit(&mut self, opcode: Opcode, operand: Option<u32>, line: u32) {
375 self.instructions.push(Instruction {
376 opcode,
377 operand,
378 line,
379 });
380 }
381
382 pub fn add_constant(&mut self, value: Value) -> u32 {
383 let index = self.constants.len() as u32;
384 self.constants.push(value);
385 index
386 }
387}
388
389#[derive(Debug, Clone, PartialEq)]
390#[cfg_attr(
391 all(feature = "serde", feature = "std"),
392 derive(Serialize, Deserialize)
393)]
394pub struct Bytecode {
395 pub chunks: Vec<Chunk>,
396 pub main_chunk: usize,
397 pub global_names: Vec<String>,
399}
400
401impl Bytecode {
402 pub fn new() -> Self {
403 let main_chunk = Chunk::new("main".to_string());
404 Self {
405 chunks: vec![main_chunk],
406 main_chunk: 0,
407 global_names: Vec::new(),
408 }
409 }
410
411 pub fn intern_global(&mut self, name: &str) -> u32 {
413 if let Some(pos) = self.global_names.iter().position(|n| n == name) {
414 return pos as u32;
415 }
416 let idx = self.global_names.len() as u32;
417 self.global_names.push(name.to_string());
418 idx
419 }
420}
421
422impl Default for Bytecode {
423 fn default() -> Self {
424 Self::new()
425 }
426}