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