mech_core/program/compiler/
sections.rs

1use crate::*;
2use super::*;
3
4// Byetecode Compiler
5// ============================================================================
6
7// Format:
8// 1. Header
9// 2. Features
10// 3. Types
11// 4. Constants
12// 5. Symbols
13// 6. Instructions
14// 7. Dictionary
15
16// 1. Header
17// ----------------------------------------------------------------------------
18
19#[repr(C)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct ByteCodeHeader {
23  pub magic:        [u8; 4],   // e.g., b"MECH"
24  pub version:        u8,      // bytecode format version
25  pub mech_ver:       u16,     // Mech language version
26  pub flags:          u16,     // reserved/feature bit
27  pub reg_count:      u32,     // total virtual registers used
28  pub instr_count:    u32,     // number of instructions
29  
30  pub feature_count:  u32,     // number of feature flags  
31  pub feature_off:    u64,     // offset to feature flags (array of u64)
32
33  pub types_count:    u32,     // number of types
34  pub types_off:      u64,     // offset to type section
35
36  pub const_count:    u32,     // number of constants (entries
37  pub const_tbl_off:  u64,     // offset to constant table (array of entries)
38  pub const_tbl_len:  u64,     // bytes in constant table area (entries only)
39  pub const_blob_off: u64,     // offset to raw constant blob data
40  pub const_blob_len: u64,     // bytes in blob (payloads
41
42  pub symbols_len:    u64,     // number of symbols
43  pub symbols_off:    u64,     // offset to symbol section
44                               
45  pub instr_off:      u64,     // offset to instruction stream
46  pub instr_len:      u64,     // bytes of instruction stream
47
48  pub dict_off:       u64,     // offset to dictionary
49  pub dict_len:       u64,     // bytes in dictionary
50
51  pub reserved:       u32,     // pad/alignment
52}
53
54impl ByteCodeHeader {
55  // Header byte size when serialized. This is the number of bytes `write_to` will write.
56  // (Computed from the sum of sizes of each field written in little-endian.)
57  pub const HEADER_SIZE: usize = 4  // magic
58    + 1   // version
59    + 2   // mech_ver
60    + 2   // flags
61    + 4   // reg_count
62    + 4   // instr_count
63    + 4   // feature_count
64    + 8   // feature_off
65    + 4   // types_count
66    + 8   // types_off
67    + 4   // const_count
68    + 8   // const_tbl_off
69    + 8   // const_tbl_len
70    + 8   // const_blob_off
71    + 8   // const_blob_len
72    + 8   // symbols_len
73    + 8   // symbosl_off
74    + 8   // instr_off
75    + 8   // instr_len
76    + 8   // dict_off
77    + 8   // dict_len
78    + 4;  // reserved
79
80  // Serialize header using little-endian encoding.
81  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
82    // magic (4 bytes)
83    w.write_all(&self.magic)?;
84
85    // small fields
86    w.write_u8(self.version)?;
87    w.write_u16::<LittleEndian>(self.mech_ver)?;
88    w.write_u16::<LittleEndian>(self.flags)?;
89
90    // counts
91    w.write_u32::<LittleEndian>(self.reg_count)?;
92    w.write_u32::<LittleEndian>(self.instr_count)?;
93
94    // features (count + offset)
95    w.write_u32::<LittleEndian>(self.feature_count)?;
96    w.write_u64::<LittleEndian>(self.feature_off)?;
97
98    // types
99    w.write_u32::<LittleEndian>(self.types_count)?;
100    w.write_u64::<LittleEndian>(self.types_off)?;
101
102    // constants table / blob
103    w.write_u32::<LittleEndian>(self.const_count)?;
104    w.write_u64::<LittleEndian>(self.const_tbl_off)?;
105    w.write_u64::<LittleEndian>(self.const_tbl_len)?;
106    w.write_u64::<LittleEndian>(self.const_blob_off)?;
107    w.write_u64::<LittleEndian>(self.const_blob_len)?;
108
109    // symbols
110    w.write_u64::<LittleEndian>(self.symbols_len)?;
111    w.write_u64::<LittleEndian>(self.symbols_off)?;
112
113    // instructions
114    w.write_u64::<LittleEndian>(self.instr_off)?;
115    w.write_u64::<LittleEndian>(self.instr_len)?;
116
117    // dictionary
118    w.write_u64::<LittleEndian>(self.dict_off)?;
119    w.write_u64::<LittleEndian>(self.dict_len)?;
120
121    // footer
122    w.write_u32::<LittleEndian>(self.reserved)?;
123    Ok(())
124  }
125
126  // Read a header. Expects the same layout as `write_to`.
127  pub fn read_from(r: &mut impl Read) -> MResult<Self> {
128    let mut magic = [0u8; 4];
129    r.read_exact(&mut magic)?;
130
131    let version = r.read_u8()?;
132    let mech_ver = r.read_u16::<LittleEndian>()?;
133    let flags = r.read_u16::<LittleEndian>()?;
134
135    let reg_count = r.read_u32::<LittleEndian>()?;
136    let instr_count = r.read_u32::<LittleEndian>()?;
137
138    let feature_count = r.read_u32::<LittleEndian>()?;
139    let feature_off = r.read_u64::<LittleEndian>()?;
140
141    let types_count = r.read_u32::<LittleEndian>()?;
142    let types_off = r.read_u64::<LittleEndian>()?;
143
144    let const_count = r.read_u32::<LittleEndian>()?;
145    let const_tbl_off = r.read_u64::<LittleEndian>()?;
146    let const_tbl_len = r.read_u64::<LittleEndian>()?;
147    let const_blob_off = r.read_u64::<LittleEndian>()?;
148    let const_blob_len = r.read_u64::<LittleEndian>()?;
149
150    let symbols_len = r.read_u64::<LittleEndian>()?;
151    let symbols_off = r.read_u64::<LittleEndian>()?;
152
153    let instr_off = r.read_u64::<LittleEndian>()?;
154    let instr_len = r.read_u64::<LittleEndian>()?;
155
156    let dict_off = r.read_u64::<LittleEndian>()?;
157    let dict_len = r.read_u64::<LittleEndian>()?;
158
159    let reserved = r.read_u32::<LittleEndian>()?;
160
161    Ok(Self {
162      magic,
163      version,
164      mech_ver,
165      flags,
166      reg_count,
167      instr_count,
168      feature_count,
169      feature_off,
170      types_count,
171      types_off,
172      const_count,
173      const_tbl_off,
174      const_tbl_len,
175      const_blob_off,
176      const_blob_len,
177      instr_off,
178      instr_len,
179      symbols_len,
180      symbols_off,
181      dict_off,
182      dict_len,
183      reserved,
184    })
185  }
186
187  // Quick check: does the header magic match the expected magic?
188  pub fn validate_magic(&self, expected: &[u8;4]) -> bool {
189    &self.magic == expected
190  }
191}
192
193// 2. Features
194// ----------------------------------------------------------------------------
195
196#[repr(u16)]
197#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
198pub enum FeatureKind {
199  I8=1, I16, I32, I64, I128,
200  U8, U16, U32, U64, U128,
201  F32, F64, C64, R64, Index,
202  String, Bool, Atom,
203  Set, Map, Table, Tuple, Record, Enum,
204  VariableDefine, VariableAssign, KindDefine,
205  KindAnnotation, SubscriptRange, SubscriptFormula,
206  RangeInclusive, RangeExclusive,
207  DotIndexing, Swizzle, LogicalIndexing,
208  Matrix1, Matrix2, Matrix3, Matrix4,
209  Matrix2x3, Matrix3x2,
210  RowVector2, RowVector3, RowVector4,
211  Vector2, Vector3, Vector4,
212  VectorD, MatrixD, RowVectorD,
213  HorzCat, VertCat,
214  Compiler, PrettyPrint, Serde,
215  MatMul, Transpose, Dot, Cross,
216  Add, Sub, Mul, Div, Exp, Mod, Neg, OpAssign,
217  LT, LTE, GT, GTE, EQ, NEQ,
218  And, Or, Xor, Not,
219  Convert, Assign, Access,
220  Functions, Formulas,
221  Custom = 0xFFFF,
222}
223
224impl FeatureKind {
225
226  pub fn as_string(&self) -> String {
227    match self {
228      FeatureKind::I8 => "i8".to_string(),
229      FeatureKind::I16 => "i16".to_string(),
230      FeatureKind::I32 => "i32".to_string(),
231      FeatureKind::I64 => "i64".to_string(),
232      FeatureKind::I128 => "i128".to_string(),
233      FeatureKind::U8 => "u8".to_string(),
234      FeatureKind::U16 => "u16".to_string(),
235      FeatureKind::U32 => "u32".to_string(),
236      FeatureKind::U64 => "u64".to_string(),
237      FeatureKind::U128 => "u128".to_string(),
238      FeatureKind::F32 => "f32".to_string(),
239      FeatureKind::F64 => "f64".to_string(),
240      FeatureKind::C64 => "c64".to_string(),
241      FeatureKind::R64 => "r64".to_string(),
242      FeatureKind::Index => "index".to_string(),
243      FeatureKind::String => "string".to_string(),
244      FeatureKind::Bool => "bool".to_string(),
245      FeatureKind::Atom => "atom".to_string(),
246      FeatureKind::Set => "set".to_string(),
247      FeatureKind::Map => "map".to_string(),
248      FeatureKind::Table => "table".to_string(),
249      FeatureKind::Tuple => "tuple".to_string(),
250      FeatureKind::Record => "record".to_string(),
251      FeatureKind::Enum => "enum".to_string(),
252      FeatureKind::VariableDefine => "variable_define".to_string(),
253      FeatureKind::VariableAssign => "variable_assign".to_string(),
254      FeatureKind::KindDefine => "kind_define".to_string(),
255      FeatureKind::KindAnnotation => "kind_annotation".to_string(),
256      FeatureKind::SubscriptRange => "subscript_range".to_string(),
257      FeatureKind::SubscriptFormula => "subscript_formula".to_string(),
258      FeatureKind::RangeInclusive => "range_inclusive".to_string(),
259      FeatureKind::RangeExclusive => "range_exclusive".to_string(),
260      FeatureKind::DotIndexing => "dot_indexing".to_string(),
261      FeatureKind::Swizzle => "swizzle".to_string(),
262      FeatureKind::LogicalIndexing => "logical_indexing".to_string(),
263      FeatureKind::Matrix1 => "matrix1".to_string(),
264      FeatureKind::Matrix2 => "matrix2".to_string(),
265      FeatureKind::Matrix3 => "matrix3".to_string(),
266      FeatureKind::Matrix4 => "matrix4".to_string(),
267      FeatureKind::Matrix2x3 => "matrix2x3".to_string(),
268      FeatureKind::Matrix3x2 => "matrix3x2".to_string(),
269      FeatureKind::RowVector2 => "row_vector2".to_string(),
270      FeatureKind::RowVector3 => "row_vector3".to_string(),
271      FeatureKind::RowVector4 => "row_vector4".to_string(),
272      FeatureKind::Vector2 => "vector2".to_string(),
273      FeatureKind::Vector3 => "vector3".to_string(),
274      FeatureKind::Vector4 => "vector4".to_string(),
275      FeatureKind::VectorD => "vectord".to_string(),
276      FeatureKind::MatrixD => "matrixd".to_string(),
277      FeatureKind::RowVectorD => "row_vectord".to_string(),
278      FeatureKind::HorzCat => "matrix_horzcat".to_string(),
279      FeatureKind::VertCat => "matrix_vertcat".to_string(),
280      FeatureKind::Compiler => "compiler".to_string(),
281      FeatureKind::PrettyPrint => "pretty_print".to_string(),
282      FeatureKind::Serde => "serde".to_string(),
283      FeatureKind::MatMul => "matrix_matmul".to_string(),
284      FeatureKind::Transpose => "matrix_transpose".to_string(),
285      FeatureKind::Dot => "matrix_dot".to_string(),
286      FeatureKind::Cross => "matrix_cross".to_string(),
287      FeatureKind::Add => "math_add".to_string(),
288      FeatureKind::Sub => "math_sub".to_string(),
289      FeatureKind::Mul => "math_mul".to_string(),
290      FeatureKind::Div => "math_div".to_string(),
291      FeatureKind::Exp => "math_exp".to_string(),
292      FeatureKind::Mod => "math_mod".to_string(),
293      FeatureKind::Neg => "math_neg".to_string(),
294      FeatureKind::OpAssign => "math_opassign".to_string(),
295      FeatureKind::LT => "compare_lt".to_string(),
296      FeatureKind::LTE => "compare_lte".to_string(),
297      FeatureKind::GT => "compare_gt".to_string(),
298      FeatureKind::GTE => "compare_gte".to_string(),
299      FeatureKind::EQ => "compare_eq".to_string(),
300      FeatureKind::NEQ => "compare_neq".to_string(),
301      FeatureKind::And => "logic_and".to_string(),
302      FeatureKind::Or => "logic_or".to_string(),
303      FeatureKind::Xor => "logic_xor".to_string(),
304      FeatureKind::Not => "logic_not".to_string(),
305      FeatureKind::Convert => "convert".to_string(),
306      FeatureKind::Assign => "assign".to_string(),
307      FeatureKind::Access => "access".to_string(),
308      FeatureKind::Functions => "functions".to_string(),
309      FeatureKind::Formulas => "formulas".to_string(),
310      FeatureKind::Custom => "custom".to_string(),
311    }
312  }
313}
314
315#[derive(Debug, Clone, PartialEq, Eq, Hash)]
316pub enum FeatureFlag {
317  Builtin(FeatureKind),
318  Custom(u64),
319}
320
321impl FeatureFlag {
322
323  pub fn as_string(&self) -> String {
324    match self {
325      FeatureFlag::Builtin(f) => f.as_string(),
326      FeatureFlag::Custom(c) => format!("custom({})", c),
327    }
328  }
329}
330
331impl FeatureFlag {
332  pub fn as_u64(&self) -> u64 {
333    match self {
334      FeatureFlag::Builtin(f) => *f as u64,
335      FeatureFlag::Custom(c) => *c,
336    }
337  }
338}
339
340// 3. Type Section
341// ----------------------------------------------------------------------------
342
343#[repr(u16)]
344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
345#[derive(Debug, Clone, Copy, Eq, PartialEq)]
346pub enum TypeTag {
347  U8=1, U16, U32, U64, U128, I8, I16, I32, I64, I128,
348  F32, F64, C64, R64, String, Bool, Id, Index, Empty, Any,
349  MatrixU8, MatrixU16, MatrixU32, MatrixU64, MatrixU128,
350  MatrixI8, MatrixI16, MatrixI32, MatrixI64, MatrixI128,
351  MatrixF32, MatrixF64, MatrixC64, MatrixR64, MatrixBool, 
352  MatrixString, MatrixIndex,
353  EnumTag, Record, Map, Atom, 
354  Table, Tuple, Reference, Set, OptionT,
355}
356
357impl TypeTag {
358  pub fn from_u16(tag: u16) -> Option<Self> {
359    match tag {
360      1 => Some(TypeTag::U8), 2 => Some(TypeTag::U16), 3 => Some(TypeTag::U32), 4 => Some(TypeTag::U64), 5 => Some(TypeTag::U128),
361      6 => Some(TypeTag::I8), 7 => Some(TypeTag::I16), 8 => Some(TypeTag::I32), 9 => Some(TypeTag::I64), 10 => Some(TypeTag::I128),
362      11 => Some(TypeTag::F32), 12 => Some(TypeTag::F64), 13 => Some(TypeTag::C64), 14 => Some(TypeTag::R64),
363      15 => Some(TypeTag::String), 16 => Some(TypeTag::Bool), 17 => Some(TypeTag::Id), 18 => Some(TypeTag::Index), 19 => Some(TypeTag::Empty), 20 => Some(TypeTag::Any),
364      21 => Some(TypeTag::MatrixU8), 22 => Some(TypeTag::MatrixU16), 23 => Some(TypeTag::MatrixU32), 24 => Some(TypeTag::MatrixU64), 25 => Some(TypeTag::MatrixU128),
365      26 => Some(TypeTag::MatrixI8), 27 => Some(TypeTag::MatrixI16), 28 => Some(TypeTag::MatrixI32), 29 => Some(TypeTag::MatrixI64), 30 => Some(TypeTag::MatrixI128),
366      31 => Some(TypeTag::MatrixF32), 32 => Some(TypeTag::MatrixF64), 33 => Some(TypeTag::MatrixC64), 34 => Some(TypeTag::MatrixR64), 35 => Some(TypeTag::MatrixBool), 
367      36 => Some(TypeTag::MatrixString), 37 => Some(TypeTag::MatrixIndex),
368      38 => Some(TypeTag::EnumTag), 39 => Some(TypeTag::Record), 40 => Some(TypeTag::Map), 41 => Some(TypeTag::Atom), 
369      42 => Some(TypeTag::Table), 43 => Some(TypeTag::Tuple), 44 => Some(TypeTag::Reference), 45 => Some(TypeTag::Set), 46 => Some(TypeTag::OptionT),
370      _ => None,
371    }
372  }
373}
374
375#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
376#[derive(Debug, Clone, Eq, PartialEq)]
377pub struct TypeEntry {
378  pub tag: TypeTag,
379  pub bytes: Vec<u8>,
380}
381impl TypeEntry {
382  pub fn byte_len(&self) -> u64 {
383    2 + self.bytes.len() as u64
384  }
385}
386
387pub type TypeId = u32;
388
389#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
390#[derive(Default, Debug, Clone, Eq, PartialEq)]
391pub struct TypeSection {
392  pub interner: HashMap<ValueKind, TypeId>,
393  pub entries:  Vec<TypeEntry>, // index is TypeId
394}
395    
396impl TypeSection {
397
398  pub fn new() -> Self {
399    Self { interner: HashMap::new(), entries: Vec::new() }
400  }
401
402  pub fn get_or_intern(&mut self, vk: &ValueKind) -> TypeId {
403    if let Some(id) = self.interner.get(vk) { return *id; }
404    // recursively intern children and build payload
405    let (tag, mut bytes) = encode_value_kind(self, vk);
406    let id = self.entries.len() as u32;
407    self.entries.push(TypeEntry { tag, bytes });
408    self.interner.insert(vk.clone(), id);
409    id
410  }
411
412  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
413    w.write_u32::<LittleEndian>(self.entries.len() as u32)?;
414    for e in &self.entries {
415      w.write_u16::<LittleEndian>(e.tag as u16)?;
416      w.write_u16::<LittleEndian>(0)?;
417      w.write_u32::<LittleEndian>(1)?;
418      w.write_u32::<LittleEndian>(e.bytes.len() as u32)?;
419      w.write_all(&e.bytes)?;
420    }
421    Ok(())
422  }
423
424  pub fn byte_len(&self) -> u64 {
425    4 + self.entries.iter().map(|e| 12 + e.bytes.len() as u64).sum::<u64>()
426  }
427}
428
429// 4. Constants
430// ----------------------------------------------------------------------------
431
432#[repr(u8)]
433#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
434#[derive(Debug, Clone, Copy, Eq, PartialEq)]
435pub enum ConstEncoding { 
436  Inline = 1 
437}
438
439#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
440#[derive(Debug, Clone, Eq, PartialEq)]
441pub struct ConstEntry {
442  pub type_id: u32,
443  pub enc:     ConstEncoding,
444  pub align:   u8,
445  pub flags:   u8,
446  pub reserved:u16,
447  pub offset:  u64,
448  pub length:  u64,
449}
450
451impl ConstEntry {
452  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
453    w.write_u32::<LittleEndian>(self.type_id)?;
454    w.write_u8(self.enc as u8)?;
455    w.write_u8(self.align)?;
456    w.write_u8(self.flags)?;
457    w.write_u8(0)?; // pad to 4 bytes for the small fields
458    w.write_u64::<LittleEndian>(self.offset)?;
459    w.write_u64::<LittleEndian>(self.length)?;
460    Ok(())
461  }
462  pub fn byte_len() -> u64 { 4 + 1 + 1 + 1 + 1 + 8 + 8 } // = 24 bytes
463}
464
465// 5. Symbol Table
466// ----------------------------------------------------------------------------
467
468pub struct SymbolEntry {
469  pub id: u64,          // unique identifier for the symbol
470  pub mutable: bool,
471  pub reg: Register,    // register index this symbol maps to
472}
473
474impl SymbolEntry {
475
476  pub fn new(id: u64, mutable: bool, reg: Register) -> Self {
477    Self { id, mutable, reg }
478  }
479
480  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
481    w.write_u64::<LittleEndian>(self.id)?;
482    w.write_u8(if self.mutable { 1 } else { 0 })?;
483    w.write_u32::<LittleEndian>(self.reg)?;
484    Ok(())
485  }
486}
487
488// 6. Instruction Encoding (fixed forms)
489// ----------------------------------------------------------------------------
490
491#[repr(u8)]
492#[derive(Debug, Clone, Copy, PartialEq, Eq)]
493pub enum OpCode {
494  ConstLoad = 0x01,
495  NullOp    = 0x10,
496  Unop      = 0x20,
497  Binop     = 0x30,
498  Ternop    = 0x40,
499  Quadop    = 0x50,
500  VarArg    = 0x60,
501  Return    = 0xFF,
502}
503
504impl OpCode {
505  pub fn from_u8(num: u8) -> Option<OpCode> {
506    match num {
507      0x01 => Some(OpCode::ConstLoad),
508      0x10 => Some(OpCode::NullOp),
509      0x20 => Some(OpCode::Unop),
510      0x30 => Some(OpCode::Binop),
511      0x40 => Some(OpCode::Ternop),
512      0x50 => Some(OpCode::Quadop),
513      0x60 => Some(OpCode::VarArg),
514      0xFF => Some(OpCode::Return),
515      _    => None,
516    }
517  }
518}
519
520#[derive(Debug, Clone)]
521pub enum EncodedInstr {
522  ConstLoad { dst: u32, const_id: u32 },                               // [u64 opcode][u32 dst][u32 const_id]
523  NullOp    { fxn_id: u64, dst: u32 },                                 // [u64 opcode][u64 fxn_id][u32 dst]
524  UnOp      { fxn_id: u64, dst: u32, src: u32 },                       // [u64 opcode][u32 dst][u32 src]
525  BinOp     { fxn_id: u64, dst: u32, lhs: u32, rhs: u32 },             // [u64 opcode][u32 dst][u32 lhs][u32 rhs]
526  TernOp    { fxn_id: u64, dst: u32, a: u32, b: u32, c: u32 },         // [u64 opcode][u32 dst][u32 a][u32 b][u32 c]
527  QuadOp    { fxn_id: u64, dst: u32, a: u32, b: u32, c: u32, d: u32 }, // [u64 opcode][u32 dst][u32 a][u32 b][u32 c][u32 d]
528  VarArg    { fxn_id: u64, dst: u32, args: Vec<u32> },                 // [u64 opcode][u64 fxn_id][u32 dst][u32 arg_count][u32 args...]
529  Ret       { src: u32 },                                              // [u64 opcode][u32 src]
530}
531
532impl EncodedInstr {
533  pub fn byte_len(&self) -> u64 {
534    match self {
535      EncodedInstr::ConstLoad{..} => 1 + 4 + 4,
536      EncodedInstr::NullOp{..}    => 1 + 8 + 4,
537      EncodedInstr::UnOp{..}      => 1 + 8 + 4 + 4,
538      EncodedInstr::BinOp{..}     => 1 + 8 + 4 + 4 + 4,
539      EncodedInstr::TernOp{..}    => 1 + 8 + 4 + 4 + 4 + 4,
540      EncodedInstr::QuadOp{..}    => 1 + 8 + 4 + 4 + 4 + 4 + 4,
541      EncodedInstr::VarArg{ args, .. } => 1 + 8 + 4 + 4 + (4 * args.len() as u64),
542      EncodedInstr::Ret{..}       => 1 + 4,
543    }
544  }
545  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
546    match self {
547      EncodedInstr::ConstLoad{ dst, const_id } => {
548        w.write_u8(OpCode::ConstLoad as u8)?;
549        w.write_u32::<LittleEndian>(*dst)?;
550        w.write_u32::<LittleEndian>(*const_id)?;
551      }
552      EncodedInstr::NullOp{ fxn_id, dst } => {
553        w.write_u8(OpCode::NullOp as u8)?;
554        w.write_u64::<LittleEndian>(*fxn_id)?;
555        w.write_u32::<LittleEndian>(*dst)?;
556      }
557      EncodedInstr::UnOp{ fxn_id, dst, src } => {
558        w.write_u8(OpCode::Unop as u8)?;
559        w.write_u64::<LittleEndian>(*fxn_id)?;
560        w.write_u32::<LittleEndian>(*dst)?;
561        w.write_u32::<LittleEndian>(*src)?;
562      }
563      EncodedInstr::BinOp{ fxn_id, dst, lhs, rhs } => {
564        w.write_u8(OpCode::Binop as u8)?;
565        w.write_u64::<LittleEndian>(*fxn_id)?;
566        w.write_u32::<LittleEndian>(*dst)?;
567        w.write_u32::<LittleEndian>(*lhs)?;
568        w.write_u32::<LittleEndian>(*rhs)?;
569      }
570      EncodedInstr::TernOp{ fxn_id, dst, a, b, c } => {
571        w.write_u8(OpCode::Ternop as u8)?;
572        w.write_u64::<LittleEndian>(*fxn_id)?;
573        w.write_u32::<LittleEndian>(*dst)?;
574        w.write_u32::<LittleEndian>(*a)?;
575        w.write_u32::<LittleEndian>(*b)?;
576        w.write_u32::<LittleEndian>(*c)?;
577      }
578      EncodedInstr::QuadOp{ fxn_id, dst, a, b, c, d } => {
579        w.write_u8(OpCode::Quadop as u8)?;
580        w.write_u64::<LittleEndian>(*fxn_id)?;
581        w.write_u32::<LittleEndian>(*dst)?;
582        w.write_u32::<LittleEndian>(*a)?;
583        w.write_u32::<LittleEndian>(*b)?;
584        w.write_u32::<LittleEndian>(*c)?;
585        w.write_u32::<LittleEndian>(*d)?;
586      }
587      EncodedInstr::VarArg{ fxn_id, dst, args } => {
588        w.write_u8(OpCode::VarArg as u8)?;
589        w.write_u64::<LittleEndian>(*fxn_id)?;
590        w.write_u32::<LittleEndian>(*dst)?;
591        w.write_u32::<LittleEndian>(args.len() as u32)?;
592        for a in args {
593          w.write_u32::<LittleEndian>(*a)?;
594        }
595      }
596      EncodedInstr::Ret{ src } => {
597        w.write_u8(OpCode::Return as u8)?;
598        w.write_u32::<LittleEndian>(*src)?;
599      }
600    }
601    Ok(())
602  }
603}
604
605// 7. Dictionary
606// ----------------------------------------------------------------------------
607
608#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
609#[derive(Debug, Clone, Eq, PartialEq)]
610pub struct DictEntry {
611  pub id: u64,          // unique identifier for the dictionary entry
612  pub name: String,     // name of the entry
613} 
614
615impl DictEntry {
616  pub fn new(id: u64, name: &str) -> Self {
617    Self { id, name: name.to_string() }
618  }
619
620  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
621    w.write_u64::<LittleEndian>(self.id)?;
622    let name_bytes = self.name.as_bytes();
623    w.write_u32::<LittleEndian>(name_bytes.len() as u32)?;
624    w.write_all(name_bytes)?;
625    Ok(())
626  }
627}
628
629