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