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