1use crate::{Bytecode, Chunk, ClassObj, ClosureObj, FunctionObj, Instruction, Opcode, Value};
27use alloc::boxed::Box;
28use alloc::rc::Rc;
29use alloc::string::{String, ToString};
30use alloc::vec::Vec;
31use core::cell::RefCell;
32
33pub const FORMAT_MAGIC: &[u8; 8] = b"MAILBC01";
34pub const FORMAT_VERSION: u16 = 1;
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum BytecodeFormatError {
38 Truncated,
39 BadMagic,
40 UnsupportedVersion(u16),
41 InvalidOpcode(u8),
42 InvalidTag(u8),
43 InvalidUtf8,
44 TrailingData,
45}
46
47struct Writer {
48 buf: Vec<u8>,
49}
50
51impl Writer {
52 fn new() -> Self {
53 Self { buf: Vec::new() }
54 }
55
56 fn u8(&mut self, v: u8) {
57 self.buf.push(v);
58 }
59
60 fn u16(&mut self, v: u16) {
61 self.buf.extend_from_slice(&v.to_le_bytes());
62 }
63
64 fn u32(&mut self, v: u32) {
65 self.buf.extend_from_slice(&v.to_le_bytes());
66 }
67
68 fn i64(&mut self, v: i64) {
69 self.buf.extend_from_slice(&v.to_le_bytes());
70 }
71
72 fn f64(&mut self, v: f64) {
73 self.buf.extend_from_slice(&v.to_le_bytes());
74 }
75
76 fn str(&mut self, s: &str) {
77 self.u32(s.len() as u32);
78 self.buf.extend_from_slice(s.as_bytes());
79 }
80
81 fn value(&mut self, v: &Value) {
82 match v {
83 Value::Null => self.u8(0),
84 Value::Bool(b) => {
85 self.u8(1);
86 self.u8(*b as u8);
87 }
88 Value::Int(n) => {
89 self.u8(2);
90 self.i64(*n);
91 }
92 Value::Float(n) => {
93 self.u8(3);
94 self.f64(*n);
95 }
96 Value::Str(s) => {
97 self.u8(4);
98 self.str(s);
99 }
100 Value::Char(c) => {
101 self.u8(5);
102 self.u32(*c as u32);
103 }
104 Value::Array(items) => {
105 self.u8(6);
106 let items = items.borrow();
107 self.u32(items.len() as u32);
108 for item in items.iter() {
109 self.value(item);
110 }
111 }
112 Value::Map(entries) => {
113 self.u8(7);
114 let entries = entries.borrow();
115 self.u32(entries.len() as u32);
116 for (k, val) in entries.iter() {
117 self.value(k);
118 self.value(val);
119 }
120 }
121 Value::Tuple(items) => {
122 self.u8(8);
123 let items = items.borrow();
124 self.u32(items.len() as u32);
125 for item in items.iter() {
126 self.value(item);
127 }
128 }
129 Value::Function(f) => {
130 self.u8(9);
131 self.str(&f.name);
132 self.u32(f.arity as u32);
133 self.u32(f.chunk_index as u32);
134 }
135 Value::Closure(c) => {
136 self.u8(10);
137 self.u32(c.function_index as u32);
138 self.u32(c.arity as u32);
139 self.u32(c.upvalues.len() as u32);
140 for u in &c.upvalues {
141 self.u32(*u as u32);
142 }
143 }
144 Value::Class(cls) => {
145 self.u8(11);
146 self.str(&cls.name);
147 self.u32(cls.methods.len() as u32);
148 for (mname, ci) in cls.methods.iter() {
149 self.str(mname);
150 self.u32(*ci as u32);
151 }
152 match &cls.superclass {
153 Some(s) => {
154 self.u8(1);
155 self.str(s);
156 }
157 None => self.u8(0),
158 }
159 self.u32(cls.properties.len() as u32);
160 for (pname, pval) in cls.properties.iter() {
161 self.str(pname);
162 self.value(pval);
163 }
164 }
165 Value::Instance {
166 class_index,
167 fields,
168 } => {
169 self.u8(12);
170 self.u32(*class_index as u32);
171 let fields = fields.borrow();
172 self.u32(fields.len() as u32);
173 for (fname, fval) in fields.iter() {
174 self.str(fname);
175 self.value(fval);
176 }
177 }
178 Value::Ok(inner) => {
179 self.u8(13);
180 self.value(inner);
181 }
182 Value::Err(inner) => {
183 self.u8(14);
184 self.value(inner);
185 }
186 Value::Some(inner) => {
187 self.u8(15);
188 self.value(inner);
189 }
190 Value::Builtin { name, arity } => {
191 self.u8(16);
192 self.str(name);
193 self.u32(*arity as u32);
194 }
195 }
196 }
197}
198
199struct Reader<'a> {
200 data: &'a [u8],
201 pos: usize,
202}
203
204impl<'a> Reader<'a> {
205 fn new(data: &'a [u8]) -> Self {
206 Self { data, pos: 0 }
207 }
208
209 fn remaining(&self) -> usize {
210 self.data.len().saturating_sub(self.pos)
211 }
212
213 fn take(&mut self, n: usize) -> Result<&'a [u8], BytecodeFormatError> {
214 if self.remaining() < n {
215 return Err(BytecodeFormatError::Truncated);
216 }
217 let s = &self.data[self.pos..self.pos + n];
218 self.pos += n;
219 Ok(s)
220 }
221
222 fn u8(&mut self) -> Result<u8, BytecodeFormatError> {
223 Ok(self.take(1)?[0])
224 }
225
226 fn u16(&mut self) -> Result<u16, BytecodeFormatError> {
227 let b = self.take(2)?;
228 Ok(u16::from_le_bytes([b[0], b[1]]))
229 }
230
231 fn u32(&mut self) -> Result<u32, BytecodeFormatError> {
232 let b = self.take(4)?;
233 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
234 }
235
236 fn u64(&mut self) -> Result<u64, BytecodeFormatError> {
237 let b = self.take(8)?;
238 let mut a = [0u8; 8];
239 a.copy_from_slice(b);
240 Ok(u64::from_le_bytes(a))
241 }
242
243 fn i64(&mut self) -> Result<i64, BytecodeFormatError> {
244 Ok(self.u64()? as i64)
245 }
246
247 fn f64(&mut self) -> Result<f64, BytecodeFormatError> {
248 Ok(f64::from_bits(self.u64()?))
249 }
250
251 fn str(&mut self) -> Result<String, BytecodeFormatError> {
252 let len = self.u32()? as usize;
253 let bytes = self.take(len)?;
254 core::str::from_utf8(bytes)
255 .map(|s| s.to_string())
256 .map_err(|_| BytecodeFormatError::InvalidUtf8)
257 }
258
259 fn value(&mut self) -> Result<Value, BytecodeFormatError> {
260 let tag = self.u8()?;
261 match tag {
262 0 => Ok(Value::Null),
263 1 => Ok(Value::Bool(self.u8()? != 0)),
264 2 => Ok(Value::Int(self.i64()?)),
265 3 => Ok(Value::Float(self.f64()?)),
266 4 => {
267 let s = self.str()?;
268 Ok(Value::Str(Rc::from(s.as_str())))
269 }
270 5 => {
271 let cp = self.u32()?;
272 let c = char::from_u32(cp).ok_or(BytecodeFormatError::InvalidTag(tag))?;
273 Ok(Value::Char(c))
274 }
275 6 => {
276 let n = self.u32()? as usize;
277 let mut items = Vec::with_capacity(n);
278 for _ in 0..n {
279 items.push(self.value()?);
280 }
281 Ok(Value::Array(Rc::new(RefCell::new(items))))
282 }
283 7 => {
284 let n = self.u32()? as usize;
285 let mut entries = Vec::with_capacity(n);
286 for _ in 0..n {
287 let k = self.value()?;
288 let v = self.value()?;
289 entries.push((k, v));
290 }
291 Ok(Value::Map(Rc::new(RefCell::new(entries))))
292 }
293 8 => {
294 let n = self.u32()? as usize;
295 let mut items = Vec::with_capacity(n);
296 for _ in 0..n {
297 items.push(self.value()?);
298 }
299 Ok(Value::Tuple(Rc::new(RefCell::new(items))))
300 }
301 9 => {
302 let name = self.str()?;
303 let arity = self.u32()? as usize;
304 let chunk_index = self.u32()? as usize;
305 Ok(Value::Function(Rc::new(FunctionObj {
306 name: Rc::from(name.as_str()),
307 arity,
308 chunk_index,
309 })))
310 }
311 10 => {
312 let function_index = self.u32()? as usize;
313 let arity = self.u32()? as usize;
314 let n = self.u32()? as usize;
315 let mut upvalues = Vec::with_capacity(n);
316 for _ in 0..n {
317 upvalues.push(self.u32()? as usize);
318 }
319 Ok(Value::Closure(Rc::new(ClosureObj {
320 function_index,
321 arity,
322 upvalues,
323 })))
324 }
325 11 => {
326 let name = self.str()?;
327 let n_methods = self.u32()? as usize;
328 let mut methods = Vec::with_capacity(n_methods);
329 for _ in 0..n_methods {
330 let mname = self.str()?;
331 let ci = self.u32()? as usize;
332 methods.push((mname, ci));
333 }
334 let has_super = self.u8()?;
335 let superclass = if has_super == 1 {
336 Some(Rc::from(self.str()?.as_str()))
337 } else {
338 None
339 };
340 let n_props = self.u32()? as usize;
341 let mut properties = Vec::with_capacity(n_props);
342 for _ in 0..n_props {
343 let pname = self.str()?;
344 let pval = self.value()?;
345 properties.push((pname, pval));
346 }
347 Ok(Value::Class(Rc::new(ClassObj {
348 name: Rc::from(name.as_str()),
349 methods: Rc::new(methods),
350 superclass,
351 properties: Rc::new(properties),
352 })))
353 }
354 12 => {
355 let class_index = self.u32()? as usize;
356 let n = self.u32()? as usize;
357 let mut fields = Vec::with_capacity(n);
358 for _ in 0..n {
359 let fname = self.str()?;
360 let fval = self.value()?;
361 fields.push((fname, fval));
362 }
363 Ok(Value::Instance {
364 class_index,
365 fields: Rc::new(RefCell::new(fields)),
366 })
367 }
368 13 => Ok(Value::Ok(Box::new(self.value()?))),
369 14 => Ok(Value::Err(Box::new(self.value()?))),
370 15 => Ok(Value::Some(Box::new(self.value()?))),
371 16 => {
372 let name = self.str()?;
373 let arity = self.u32()? as usize;
374 Ok(Value::Builtin {
375 name: Rc::from(name.as_str()),
376 arity,
377 })
378 }
379 other => Err(BytecodeFormatError::InvalidTag(other)),
380 }
381 }
382}
383
384pub fn encode(bc: &Bytecode) -> Vec<u8> {
386 let mut w = Writer::new();
387 w.buf.extend_from_slice(FORMAT_MAGIC);
388 w.u16(FORMAT_VERSION);
389 w.u16(0); w.u32(bc.main_chunk as u32);
391
392 w.u32(bc.global_names.len() as u32);
393 for name in &bc.global_names {
394 w.str(name);
395 }
396
397 w.u32(bc.chunks.len() as u32);
398 for chunk in &bc.chunks {
399 w.str(&chunk.name);
400 w.u32(chunk.constants.len() as u32);
401 for c in &chunk.constants {
402 w.value(c);
403 }
404 w.u32(chunk.instructions.len() as u32);
405 for ins in &chunk.instructions {
406 w.u8(ins.opcode.as_u8());
407 match ins.operand {
408 Some(op) => {
409 w.u8(1);
410 w.u32(op);
411 }
412 None => w.u8(0),
413 }
414 w.u32(ins.line);
415 }
416 }
417 w.buf
418}
419
420pub fn decode(data: &[u8]) -> Result<Bytecode, BytecodeFormatError> {
422 let mut r = Reader::new(data);
423 let magic = r.take(8)?;
424 if magic != FORMAT_MAGIC {
425 return Err(BytecodeFormatError::BadMagic);
426 }
427 let version = r.u16()?;
428 if version != FORMAT_VERSION {
429 return Err(BytecodeFormatError::UnsupportedVersion(version));
430 }
431 let _flags = r.u16()?;
432 let main_chunk = r.u32()? as usize;
433
434 let n_globals = r.u32()? as usize;
435 let mut global_names = Vec::with_capacity(n_globals);
436 for _ in 0..n_globals {
437 global_names.push(r.str()?);
438 }
439
440 let n_chunks = r.u32()? as usize;
441 let mut chunks = Vec::with_capacity(n_chunks);
442 for _ in 0..n_chunks {
443 let name = r.str()?;
444 let n_const = r.u32()? as usize;
445 let mut constants = Vec::with_capacity(n_const);
446 for _ in 0..n_const {
447 constants.push(r.value()?);
448 }
449 let n_instr = r.u32()? as usize;
450 let mut instructions = Vec::with_capacity(n_instr);
451 for _ in 0..n_instr {
452 let op_u8 = r.u8()?;
453 let opcode = Opcode::from_u8(op_u8).ok_or(BytecodeFormatError::InvalidOpcode(op_u8))?;
454 let has_operand = r.u8()?;
455 let operand = if has_operand == 1 {
456 Some(r.u32()?)
457 } else {
458 None
459 };
460 let line = r.u32()?;
461 instructions.push(Instruction {
462 opcode,
463 operand,
464 line,
465 });
466 }
467 chunks.push(Chunk {
468 instructions,
469 constants,
470 name,
471 });
472 }
473
474 if r.remaining() != 0 {
475 return Err(BytecodeFormatError::TrailingData);
476 }
477
478 Ok(Bytecode {
479 chunks,
480 main_chunk,
481 global_names,
482 })
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488 use crate::Bytecode;
489
490 #[test]
491 fn roundtrip_empty() {
492 let bc = Bytecode::new();
493 let bytes = encode(&bc);
494 let back = decode(&bytes).unwrap();
495 assert_eq!(bc, back);
496 }
497
498 #[test]
499 fn roundtrip_simple_program() {
500 let mut bc = Bytecode::new();
501 let slot = bc.intern_global("x");
502 let main = &mut bc.chunks[0];
503 main.emit(Opcode::Push, Some(0), 1);
504 main.emit(Opcode::StoreGlobal, Some(slot), 1);
505 main.emit(Opcode::Halt, None, 2);
506 main.add_constant(Value::Int(42));
507
508 let bytes = encode(&bc);
509 let back = decode(&bytes).unwrap();
510 assert_eq!(bc, back);
511 }
512
513 #[test]
514 fn reject_bad_magic() {
515 assert_eq!(decode(b"NOTMAGIC0000"), Err(BytecodeFormatError::BadMagic));
516 }
517}