Skip to main content

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
202  F32, F64, C64, R64, Index,
203  String, Bool, Atom, Set, Map, 
204  
205  Table, Tuple, Record, Enum,
206  VariableDefine, VariableAssign, KindDefine,
207  KindAnnotation, SubscriptRange, SubscriptFormula,
208  
209  RangeInclusive, RangeExclusive,
210  DotIndexing, Swizzle, LogicalIndexing,
211  Matrix1, Matrix2, Matrix3, Matrix4, Matrix2x3, 
212  
213  Matrix3x2, RowVector2, RowVector3, RowVector4,
214  Vector2, Vector3, Vector4, VectorD, MatrixD, RowVectorD,
215  
216  HorzCat, VertCat,
217  Compiler, PrettyPrint, Serde,
218  MatMul, Transpose, Dot, Cross, Solve,
219  MatrixComprehensions,
220  
221  Add, Sub, Mul, Div, Pow, Mod, 
222  Neg, OpAssign, LT, LTE, GT,
223  
224  GTE, EQ, NEQ, And, Or, 
225  Xor, Not, Convert, Assign, Access,
226  Min, Max,
227
228  Union, Intersection, Difference, Complement, Subset, 
229  Superset, ProperSubset, ProperSuperset, ElementOf, NotElementOf,
230  SetComprehensions,
231
232  Concat,
233
234  Functions, Formulas,
235  Custom = 0xFFFF,
236}
237
238impl FeatureKind {
239
240  pub fn as_string(&self) -> String {
241    match self {
242      FeatureKind::I8 => "i8".to_string(),
243      FeatureKind::I16 => "i16".to_string(),
244      FeatureKind::I32 => "i32".to_string(),
245      FeatureKind::I64 => "i64".to_string(),
246      FeatureKind::I128 => "i128".to_string(),
247      FeatureKind::U8 => "u8".to_string(),
248      FeatureKind::U16 => "u16".to_string(),
249      FeatureKind::U32 => "u32".to_string(),
250      FeatureKind::U64 => "u64".to_string(),
251      FeatureKind::U128 => "u128".to_string(),
252      FeatureKind::F32 => "f32".to_string(),
253      FeatureKind::F64 => "f64".to_string(),
254      FeatureKind::C64 => "c64".to_string(),
255      FeatureKind::R64 => "r64".to_string(),
256      FeatureKind::Index => "index".to_string(),
257      FeatureKind::String => "string".to_string(),
258      FeatureKind::Bool => "bool".to_string(),
259      FeatureKind::Atom => "atom".to_string(),
260      FeatureKind::Set => "set".to_string(),
261      FeatureKind::Map => "map".to_string(),
262      FeatureKind::Table => "table".to_string(),
263      FeatureKind::Tuple => "tuple".to_string(),
264      FeatureKind::Record => "record".to_string(),
265      FeatureKind::Enum => "enum".to_string(),
266      FeatureKind::VariableDefine => "variable_define".to_string(),
267      FeatureKind::VariableAssign => "variable_assign".to_string(),
268      FeatureKind::KindDefine => "kind_define".to_string(),
269      FeatureKind::KindAnnotation => "kind_annotation".to_string(),
270      FeatureKind::SubscriptRange => "subscript_range".to_string(),
271      FeatureKind::SubscriptFormula => "subscript_formula".to_string(),
272      FeatureKind::RangeInclusive => "range_inclusive".to_string(),
273      FeatureKind::RangeExclusive => "range_exclusive".to_string(),
274      FeatureKind::DotIndexing => "dot_indexing".to_string(),
275      FeatureKind::Swizzle => "swizzle".to_string(),
276      FeatureKind::LogicalIndexing => "logical_indexing".to_string(),
277      FeatureKind::Matrix1 => "matrix1".to_string(),
278      FeatureKind::Matrix2 => "matrix2".to_string(),
279      FeatureKind::Matrix3 => "matrix3".to_string(),
280      FeatureKind::Matrix4 => "matrix4".to_string(),
281      FeatureKind::Matrix2x3 => "matrix2x3".to_string(),
282      FeatureKind::Matrix3x2 => "matrix3x2".to_string(),
283      FeatureKind::RowVector2 => "row_vector2".to_string(),
284      FeatureKind::RowVector3 => "row_vector3".to_string(),
285      FeatureKind::RowVector4 => "row_vector4".to_string(),
286      FeatureKind::Vector2 => "vector2".to_string(),
287      FeatureKind::Vector3 => "vector3".to_string(),
288      FeatureKind::Vector4 => "vector4".to_string(),
289      FeatureKind::VectorD => "vectord".to_string(),
290      FeatureKind::MatrixD => "matrixd".to_string(),
291      FeatureKind::RowVectorD => "row_vectord".to_string(),
292      FeatureKind::HorzCat => "matrix_horzcat".to_string(),
293      FeatureKind::VertCat => "matrix_vertcat".to_string(),
294      FeatureKind::Compiler => "compiler".to_string(),
295      FeatureKind::PrettyPrint => "pretty_print".to_string(),
296      FeatureKind::Serde => "serde".to_string(),
297      FeatureKind::MatMul => "matrix_matmul".to_string(),
298      FeatureKind::Transpose => "matrix_transpose".to_string(),
299      FeatureKind::Dot => "matrix_dot".to_string(),
300      FeatureKind::Solve => "matrix_solve".to_string(),
301      FeatureKind::Cross => "matrix_cross".to_string(),
302      FeatureKind::MatrixComprehensions => "matrix_comprehensions".to_string(),
303      FeatureKind::Add => "math_add".to_string(),
304      FeatureKind::Sub => "math_sub".to_string(),
305      FeatureKind::Mul => "math_mul".to_string(),
306      FeatureKind::Div => "math_div".to_string(),
307      FeatureKind::Pow => "math_pow".to_string(),
308      FeatureKind::Mod => "math_mod".to_string(),
309      FeatureKind::Neg => "math_neg".to_string(),
310      FeatureKind::OpAssign => "math_opassign".to_string(),
311      FeatureKind::LT => "compare_lt".to_string(),
312      FeatureKind::LTE => "compare_lte".to_string(),
313      FeatureKind::GT => "compare_gt".to_string(),
314      FeatureKind::GTE => "compare_gte".to_string(),
315      FeatureKind::EQ => "compare_eq".to_string(),
316      FeatureKind::NEQ => "compare_neq".to_string(),
317      FeatureKind::Min => "compare_min".to_string(),
318      FeatureKind::Max => "compare_max".to_string(),
319      FeatureKind::And => "logic_and".to_string(),
320      FeatureKind::Or => "logic_or".to_string(),
321      FeatureKind::Xor => "logic_xor".to_string(),
322      FeatureKind::Not => "logic_not".to_string(),
323      FeatureKind::Convert => "convert".to_string(),
324      FeatureKind::Assign => "assign".to_string(),
325      FeatureKind::Access => "access".to_string(),
326      FeatureKind::Union => "set_union".to_string(),
327      FeatureKind::Intersection => "set_intersection".to_string(),
328      FeatureKind::Difference => "set_difference".to_string(),
329      FeatureKind::Complement => "set_complement".to_string(),
330      FeatureKind::Subset => "set_subset".to_string(),
331      FeatureKind::Superset => "set_superset".to_string(),
332      FeatureKind::ProperSubset => "set_proper_subset".to_string(),
333      FeatureKind::ProperSuperset => "set_proper_superset".to_string(),
334      FeatureKind::ElementOf => "set_element_of".to_string(),
335      FeatureKind::NotElementOf => "set_not_element_of".to_string(),
336      FeatureKind::SetComprehensions => "set_comprehensions".to_string(),
337      FeatureKind::Functions => "functions".to_string(),
338      FeatureKind::Formulas => "formulas".to_string(),
339      FeatureKind::Concat => "string_concat".to_string(),
340      FeatureKind::Custom => "custom".to_string(),
341    }
342  }
343}
344
345#[derive(Debug, Clone, PartialEq, Eq, Hash)]
346pub enum FeatureFlag {
347  Builtin(FeatureKind),
348  Custom(u64),
349}
350
351impl FeatureFlag {
352
353  pub fn as_string(&self) -> String {
354    match self {
355      FeatureFlag::Builtin(f) => f.as_string(),
356      FeatureFlag::Custom(c) => format!("custom({})", c),
357    }
358  }
359}
360
361impl FeatureFlag {
362  pub fn as_u64(&self) -> u64 {
363    match self {
364      FeatureFlag::Builtin(f) => *f as u64,
365      FeatureFlag::Custom(c) => *c,
366    }
367  }
368}
369
370// 3. Type Section
371// ----------------------------------------------------------------------------
372
373#[repr(u16)]
374#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
375#[derive(Debug, Clone, Copy, Eq, PartialEq)]
376pub enum TypeTag {
377  U8=1, U16, U32, U64, U128, I8, I16, I32, I64, I128,
378  F32, F64, C64, R64, String, Bool, Id, Index, Empty, Any,
379  MatrixU8, MatrixU16, MatrixU32, MatrixU64, MatrixU128,
380  MatrixI8, MatrixI16, MatrixI32, MatrixI64, MatrixI128,
381  MatrixF32, MatrixF64, MatrixC64, MatrixR64, MatrixBool, 
382  MatrixString, MatrixIndex,
383  EnumTag, Record, Map, Atom, 
384  Table, Tuple, Reference, Set, OptionT, Kind, None,
385}
386
387impl TypeTag {
388  pub fn from_u16(tag: u16) -> Option<Self> {
389    match tag {
390      1 => Some(TypeTag::U8), 2 => Some(TypeTag::U16), 3 => Some(TypeTag::U32), 4 => Some(TypeTag::U64), 5 => Some(TypeTag::U128),
391      6 => Some(TypeTag::I8), 7 => Some(TypeTag::I16), 8 => Some(TypeTag::I32), 9 => Some(TypeTag::I64), 10 => Some(TypeTag::I128),
392      11 => Some(TypeTag::F32), 12 => Some(TypeTag::F64), 13 => Some(TypeTag::C64), 14 => Some(TypeTag::R64),
393      15 => Some(TypeTag::String), 16 => Some(TypeTag::Bool), 17 => Some(TypeTag::Id), 18 => Some(TypeTag::Index), 19 => Some(TypeTag::Empty), 20 => Some(TypeTag::Any),
394      21 => Some(TypeTag::MatrixU8), 22 => Some(TypeTag::MatrixU16), 23 => Some(TypeTag::MatrixU32), 24 => Some(TypeTag::MatrixU64), 25 => Some(TypeTag::MatrixU128),
395      26 => Some(TypeTag::MatrixI8), 27 => Some(TypeTag::MatrixI16), 28 => Some(TypeTag::MatrixI32), 29 => Some(TypeTag::MatrixI64), 30 => Some(TypeTag::MatrixI128),
396      31 => Some(TypeTag::MatrixF32), 32 => Some(TypeTag::MatrixF64), 33 => Some(TypeTag::MatrixC64), 34 => Some(TypeTag::MatrixR64), 35 => Some(TypeTag::MatrixBool), 
397      36 => Some(TypeTag::MatrixString), 37 => Some(TypeTag::MatrixIndex),
398      38 => Some(TypeTag::EnumTag), 39 => Some(TypeTag::Record), 40 => Some(TypeTag::Map), 41 => Some(TypeTag::Atom), 
399      42 => Some(TypeTag::Table), 43 => Some(TypeTag::Tuple), 44 => Some(TypeTag::Reference), 45 => Some(TypeTag::Set), 46 => Some(TypeTag::OptionT), 47 => Some(TypeTag::Kind), 48 => Some(TypeTag::None),
400      _ => None,
401    }
402  }
403}
404
405#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
406#[derive(Debug, Clone, Eq, PartialEq)]
407pub struct TypeEntry {
408  pub tag: TypeTag,
409  pub bytes: Vec<u8>,
410}
411impl TypeEntry {
412  pub fn byte_len(&self) -> u64 {
413    2 + self.bytes.len() as u64
414  }
415}
416
417pub type TypeId = u32;
418
419#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
420#[derive(Default, Debug, Clone, Eq, PartialEq)]
421pub struct TypeSection {
422  pub interner: HashMap<ValueKind, TypeId>,
423  pub entries:  Vec<TypeEntry>, // index is TypeId
424}
425    
426impl TypeSection {
427
428  pub fn new() -> Self {
429    Self { interner: HashMap::new(), entries: Vec::new() }
430  }
431
432  pub fn get_or_intern(&mut self, vk: &ValueKind) -> TypeId {
433    if let Some(id) = self.interner.get(vk) { return *id; }
434    // recursively intern children and build payload
435    let (tag, mut bytes) = encode_value_kind(self, vk);
436    let id = self.entries.len() as u32;
437    self.entries.push(TypeEntry { tag, bytes });
438    self.interner.insert(vk.clone(), id);
439    id
440  }
441
442  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
443    w.write_u32::<LittleEndian>(self.entries.len() as u32)?;
444    for e in &self.entries {
445      w.write_u16::<LittleEndian>(e.tag as u16)?;
446      w.write_u16::<LittleEndian>(0)?;
447      w.write_u32::<LittleEndian>(1)?;
448      w.write_u32::<LittleEndian>(e.bytes.len() as u32)?;
449      w.write_all(&e.bytes)?;
450    }
451    Ok(())
452  }
453
454  pub fn byte_len(&self) -> u64 {
455    4 + self.entries.iter().map(|e| 12 + e.bytes.len() as u64).sum::<u64>()
456  }
457}
458
459// 4. Constants
460// ----------------------------------------------------------------------------
461
462#[repr(u8)]
463#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
464#[derive(Debug, Clone, Copy, Eq, PartialEq)]
465pub enum ConstEncoding { 
466  Inline = 1 
467}
468
469#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
470#[derive(Debug, Clone, Eq, PartialEq)]
471pub struct ConstEntry {
472  pub type_id: u32,
473  pub enc:     ConstEncoding,
474  pub align:   u8,
475  pub flags:   u8,
476  pub reserved:u16,
477  pub offset:  u64,
478  pub length:  u64,
479}
480
481impl ConstEntry {
482  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
483    w.write_u32::<LittleEndian>(self.type_id)?;
484    w.write_u8(self.enc as u8)?;
485    w.write_u8(self.align)?;
486    w.write_u8(self.flags)?;
487    w.write_u8(0)?; // pad to 4 bytes for the small fields
488    w.write_u64::<LittleEndian>(self.offset)?;
489    w.write_u64::<LittleEndian>(self.length)?;
490    Ok(())
491  }
492  pub fn byte_len() -> u64 { 4 + 1 + 1 + 1 + 1 + 8 + 8 } // = 24 bytes
493}
494
495// 5. Symbol Table
496// ----------------------------------------------------------------------------
497
498pub struct SymbolEntry {
499  pub id: u64,          // unique identifier for the symbol
500  pub mutable: bool,
501  pub reg: Register,    // register index this symbol maps to
502}
503
504impl SymbolEntry {
505
506  pub fn new(id: u64, mutable: bool, reg: Register) -> Self {
507    Self { id, mutable, reg }
508  }
509
510  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
511    w.write_u64::<LittleEndian>(self.id)?;
512    w.write_u8(if self.mutable { 1 } else { 0 })?;
513    w.write_u32::<LittleEndian>(self.reg)?;
514    Ok(())
515  }
516}
517
518// 6. Instruction Encoding (fixed forms)
519// ----------------------------------------------------------------------------
520
521#[repr(u8)]
522#[derive(Debug, Clone, Copy, PartialEq, Eq)]
523pub enum OpCode {
524  ConstLoad = 0x01,
525  NullOp    = 0x10,
526  Unop      = 0x20,
527  Binop     = 0x30,
528  Ternop    = 0x40,
529  Quadop    = 0x50,
530  VarArg    = 0x60,
531  Return    = 0xFF,
532}
533
534impl std::fmt::Display for OpCode {
535  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
536    let s = match self {
537      OpCode::ConstLoad => "ConstLoad",
538      OpCode::NullOp    => "NullOp",
539      OpCode::Unop      => "Unop",
540      OpCode::Binop     => "Binop",
541      OpCode::Ternop    => "Ternop",
542      OpCode::Quadop    => "Quadop",
543      OpCode::VarArg    => "VarArg",
544      OpCode::Return    => "Return",
545    };
546    write!(f, "{}", s)
547  }
548}
549
550impl OpCode {
551  pub fn from_u8(num: u8) -> Option<OpCode> {
552    match num {
553      0x01 => Some(OpCode::ConstLoad),
554      0x10 => Some(OpCode::NullOp),
555      0x20 => Some(OpCode::Unop),
556      0x30 => Some(OpCode::Binop),
557      0x40 => Some(OpCode::Ternop),
558      0x50 => Some(OpCode::Quadop),
559      0x60 => Some(OpCode::VarArg),
560      0xFF => Some(OpCode::Return),
561      _    => None,
562    }
563  }
564}
565
566#[derive(Debug, Clone)]
567pub enum EncodedInstr {
568  ConstLoad { dst: u32, const_id: u32 },                               // [u64 opcode][u32 dst][u32 const_id]
569  NullOp    { fxn_id: u64, dst: u32 },                                 // [u64 opcode][u64 fxn_id][u32 dst]
570  UnOp      { fxn_id: u64, dst: u32, src: u32 },                       // [u64 opcode][u32 dst][u32 src]
571  BinOp     { fxn_id: u64, dst: u32, lhs: u32, rhs: u32 },             // [u64 opcode][u32 dst][u32 lhs][u32 rhs]
572  TernOp    { fxn_id: u64, dst: u32, a: u32, b: u32, c: u32 },         // [u64 opcode][u32 dst][u32 a][u32 b][u32 c]
573  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]
574  VarArg    { fxn_id: u64, dst: u32, args: Vec<u32> },                 // [u64 opcode][u64 fxn_id][u32 dst][u32 arg_count][u32 args...]
575  Ret       { src: u32 },                                              // [u64 opcode][u32 src]
576}
577
578impl EncodedInstr {
579  pub fn byte_len(&self) -> u64 {
580    match self {
581      EncodedInstr::ConstLoad{..} => 1 + 4 + 4,
582      EncodedInstr::NullOp{..}    => 1 + 8 + 4,
583      EncodedInstr::UnOp{..}      => 1 + 8 + 4 + 4,
584      EncodedInstr::BinOp{..}     => 1 + 8 + 4 + 4 + 4,
585      EncodedInstr::TernOp{..}    => 1 + 8 + 4 + 4 + 4 + 4,
586      EncodedInstr::QuadOp{..}    => 1 + 8 + 4 + 4 + 4 + 4 + 4,
587      EncodedInstr::VarArg{ args, .. } => 1 + 8 + 4 + 4 + (4 * args.len() as u64),
588      EncodedInstr::Ret{..}       => 1 + 4,
589    }
590  }
591  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
592    match self {
593      EncodedInstr::ConstLoad{ dst, const_id } => {
594        w.write_u8(OpCode::ConstLoad as u8)?;
595        w.write_u32::<LittleEndian>(*dst)?;
596        w.write_u32::<LittleEndian>(*const_id)?;
597      }
598      EncodedInstr::NullOp{ fxn_id, dst } => {
599        w.write_u8(OpCode::NullOp as u8)?;
600        w.write_u64::<LittleEndian>(*fxn_id)?;
601        w.write_u32::<LittleEndian>(*dst)?;
602      }
603      EncodedInstr::UnOp{ fxn_id, dst, src } => {
604        w.write_u8(OpCode::Unop as u8)?;
605        w.write_u64::<LittleEndian>(*fxn_id)?;
606        w.write_u32::<LittleEndian>(*dst)?;
607        w.write_u32::<LittleEndian>(*src)?;
608      }
609      EncodedInstr::BinOp{ fxn_id, dst, lhs, rhs } => {
610        w.write_u8(OpCode::Binop as u8)?;
611        w.write_u64::<LittleEndian>(*fxn_id)?;
612        w.write_u32::<LittleEndian>(*dst)?;
613        w.write_u32::<LittleEndian>(*lhs)?;
614        w.write_u32::<LittleEndian>(*rhs)?;
615      }
616      EncodedInstr::TernOp{ fxn_id, dst, a, b, c } => {
617        w.write_u8(OpCode::Ternop as u8)?;
618        w.write_u64::<LittleEndian>(*fxn_id)?;
619        w.write_u32::<LittleEndian>(*dst)?;
620        w.write_u32::<LittleEndian>(*a)?;
621        w.write_u32::<LittleEndian>(*b)?;
622        w.write_u32::<LittleEndian>(*c)?;
623      }
624      EncodedInstr::QuadOp{ fxn_id, dst, a, b, c, d } => {
625        w.write_u8(OpCode::Quadop as u8)?;
626        w.write_u64::<LittleEndian>(*fxn_id)?;
627        w.write_u32::<LittleEndian>(*dst)?;
628        w.write_u32::<LittleEndian>(*a)?;
629        w.write_u32::<LittleEndian>(*b)?;
630        w.write_u32::<LittleEndian>(*c)?;
631        w.write_u32::<LittleEndian>(*d)?;
632      }
633      EncodedInstr::VarArg{ fxn_id, dst, args } => {
634        w.write_u8(OpCode::VarArg as u8)?;
635        w.write_u64::<LittleEndian>(*fxn_id)?;
636        w.write_u32::<LittleEndian>(*dst)?;
637        w.write_u32::<LittleEndian>(args.len() as u32)?;
638        for a in args {
639          w.write_u32::<LittleEndian>(*a)?;
640        }
641      }
642      EncodedInstr::Ret{ src } => {
643        w.write_u8(OpCode::Return as u8)?;
644        w.write_u32::<LittleEndian>(*src)?;
645      }
646    }
647    Ok(())
648  }
649}
650
651// 7. Dictionary
652// ----------------------------------------------------------------------------
653
654#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
655#[derive(Debug, Clone, Eq, PartialEq)]
656pub struct DictEntry {
657  pub id: u64,          // unique identifier for the dictionary entry
658  pub name: String,     // name of the entry
659} 
660
661impl DictEntry {
662  pub fn new(id: u64, name: &str) -> Self {
663    Self { id, name: name.to_string() }
664  }
665
666  pub fn write_to(&self, w: &mut impl Write) -> MResult<()> {
667    w.write_u64::<LittleEndian>(self.id)?;
668    let name_bytes = self.name.as_bytes();
669    w.write_u32::<LittleEndian>(name_bytes.len() as u32)?;
670    w.write_all(name_bytes)?;
671    Ok(())
672  }
673}
674
675