kaiju_core/
assembly.rs

1#![allow(clippy::unused_io_amount)]
2#![allow(clippy::map_entry)]
3
4use crate::error::*;
5use crate::program::{
6    Access as CoreAccess, BlockOp as CoreBlockOp, Extern as CoreExtern, Function as CoreFunction,
7    Number as CoreNumber, OpsDescriptor, Program as CoreProgram, Struct as CoreStruct,
8    Type as CoreType, Value as CoreValue, Variable as CoreVariable,
9};
10use crate::utils::*;
11use byteorder::{BigEndian, WriteBytesExt};
12use std::collections::HashMap;
13use std::ffi::CString;
14use std::io::{Cursor, Write};
15use std::mem::size_of;
16
17pub type OpsMap = HashMap<String, (u64, Option<CoreType>)>;
18
19#[derive(Debug, Clone, Copy)]
20pub enum OpIndex {
21    NoOp = 0,
22    DataPointer = 1,
23    ParamsPointer = 2,
24    ResultPointer = 3,
25    LocalsPointer = 4,
26    GlobalsPointer = 5,
27    OffsetPointer = 6,
28    ReferencePointer = 7,
29    DereferencePointer = 8,
30    StoreTargetAddress = 9,
31    StoreParamAddress = 10,
32    ExecuteOpStart = 11,
33    ExecuteOpStop = 12,
34    ExecuteOpInlineStart = 13,
35    ExecuteOpInlineStop = 14,
36    ProduceTuple = 15,
37    CallFunction = 16,
38}
39
40impl From<u8> for OpIndex {
41    fn from(v: u8) -> Self {
42        match v {
43            0 => OpIndex::NoOp,
44            1 => OpIndex::DataPointer,
45            2 => OpIndex::ParamsPointer,
46            3 => OpIndex::ResultPointer,
47            4 => OpIndex::LocalsPointer,
48            5 => OpIndex::GlobalsPointer,
49            6 => OpIndex::OffsetPointer,
50            7 => OpIndex::ReferencePointer,
51            8 => OpIndex::DereferencePointer,
52            9 => OpIndex::StoreTargetAddress,
53            10 => OpIndex::StoreParamAddress,
54            11 => OpIndex::ExecuteOpStart,
55            12 => OpIndex::ExecuteOpStop,
56            13 => OpIndex::ExecuteOpInlineStart,
57            14 => OpIndex::ExecuteOpInlineStop,
58            15 => OpIndex::ProduceTuple,
59            16 => OpIndex::CallFunction,
60            _ => panic!("Unsupported op index: {}", v),
61        }
62    }
63}
64
65#[derive(Debug, Clone, Copy)]
66pub enum DataType {
67    Unknown = 0,
68    I8 = 1,
69    U8 = 2,
70    I16 = 3,
71    U16 = 4,
72    I32 = 5,
73    U32 = 6,
74    I64 = 7,
75    U64 = 8,
76    F32 = 9,
77    F64 = 10,
78    Isize = 11,
79    Usize = 12,
80    StringU8 = 13,
81}
82
83impl From<u8> for DataType {
84    fn from(v: u8) -> Self {
85        match v {
86            0 => DataType::Unknown,
87            1 => DataType::I8,
88            2 => DataType::U8,
89            3 => DataType::I16,
90            4 => DataType::U16,
91            5 => DataType::I32,
92            6 => DataType::U32,
93            7 => DataType::I64,
94            8 => DataType::U64,
95            9 => DataType::F32,
96            10 => DataType::F64,
97            11 => DataType::Isize,
98            12 => DataType::Usize,
99            13 => DataType::StringU8,
100            _ => panic!("Unsupported data type: {}", v),
101        }
102    }
103}
104
105pub fn encode_assembly(program: &CoreProgram, ops: &OpsDescriptor) -> SimpleResult<Vec<u8>> {
106    let assembly = Assembly::from_core(program)?;
107    assembly.to_bytes(ops)
108}
109
110fn write_core_type(
111    typeid: &CoreType,
112    stream: &mut dyn Write,
113    assembly: &Assembly,
114) -> SimpleResult<()> {
115    match typeid {
116        CoreType::Identifier(id) => {
117            stream.write_u8(0)?;
118            let index = assembly
119                .structs()
120                .iter()
121                .position(|s| s.id() == id)
122                .unwrap();
123            stream.write_u64::<BigEndian>(index as u64)?;
124        }
125        CoreType::Pointer(typeid) => {
126            stream.write_u8(1)?;
127            write_core_type(&typeid, stream, assembly)?;
128        }
129        CoreType::Tuple(types) => {
130            stream.write_u8(2)?;
131            stream.write_u64::<BigEndian>(types.len() as u64)?;
132            for t in types {
133                write_core_type(t, stream, assembly)?;
134            }
135        }
136    }
137    Ok(())
138}
139
140fn write_string(value: &str, stream: &mut dyn Write) -> SimpleResult<()> {
141    stream.write_u64::<BigEndian>(value.as_bytes().len() as u64)?;
142    stream.write(value.as_bytes())?;
143    Ok(())
144}
145
146#[derive(Debug, Clone)]
147pub struct Assembly {
148    magic: [u8; 4],
149    structs: Vec<Struct>,
150    globals: Vec<Variable>,
151    functions: Vec<Function>,
152    modules: Vec<Module>,
153    export_structs: Vec<usize>,
154    export_functions: Vec<usize>,
155}
156
157impl Assembly {
158    pub fn from_core(program: &CoreProgram) -> SimpleResult<Self> {
159        let mut structs = vec![
160            Struct::new_atom(0, "i8", 1),
161            Struct::new_atom(1, "u8", 1),
162            Struct::new_atom(2, "i16", 2),
163            Struct::new_atom(3, "u16", 2),
164            Struct::new_atom(4, "i32", 4),
165            Struct::new_atom(5, "u32", 4),
166            Struct::new_atom(6, "i64", 8),
167            Struct::new_atom(7, "u64", 8),
168            Struct::new_atom(8, "f32", 4),
169            Struct::new_atom(9, "f64", 8),
170            Struct::new_atom(10, "isize", size_of::<isize>()),
171            Struct::new_atom(11, "usize", size_of::<usize>()),
172        ];
173        let mut globals = vec![];
174        let mut functions = vec![];
175        let mut modules = vec![];
176        for module in &program.modules {
177            let index = modules.len();
178            let structs = module
179                .structs
180                .iter()
181                .map(|struct_| {
182                    let index = structs.len();
183                    let s = Struct::from_core(index, struct_, program)?;
184                    structs.push(s);
185                    Ok(index)
186                })
187                .collect::<SimpleResult<_>>()?;
188            let globals = module
189                .globals
190                .iter()
191                .map(|global| {
192                    let index = globals.len();
193                    let g = Variable::from_core(index, global, program, None)?;
194                    globals.push(g);
195                    Ok(index)
196                })
197                .collect::<SimpleResult<_>>()?;
198            let functions = module
199                .functions
200                .iter()
201                .map(|function| {
202                    let index = functions.len();
203                    let f = Function::from_core(index, function, program)?;
204                    functions.push(f);
205                    Ok(index)
206                })
207                .collect::<SimpleResult<_>>()?;
208            modules.push(Module {
209                index,
210                structs,
211                globals,
212                functions,
213            });
214        }
215        for (index, module) in program.modules.iter().enumerate() {
216            let data: Vec<(Vec<usize>, Vec<usize>)> = module
217                .imports
218                .iter()
219                .map(|import| {
220                    let mi = program
221                        .modules
222                        .iter()
223                        .position(|m| m.path == import.module)
224                        .unwrap();
225                    let pm = &program.modules[mi];
226                    let m = &modules[mi];
227                    let ss = import
228                        .names
229                        .iter()
230                        .filter_map(|name| {
231                            if let Some(i) = pm.structs.iter().position(|s| &s.id == name) {
232                                Some(m.structs[i])
233                            } else {
234                                None
235                            }
236                        })
237                        .collect();
238                    let ff = import
239                        .names
240                        .iter()
241                        .filter_map(|name| {
242                            if let Some(i) = pm
243                                .functions
244                                .iter()
245                                .position(|f| &f.header.id.clone() == name)
246                            {
247                                Some(m.functions[i])
248                            } else {
249                                None
250                            }
251                        })
252                        .collect();
253                    (ss, ff)
254                })
255                .collect();
256            for (ss, ff) in data {
257                modules[index].structs.extend(ss);
258                modules[index].functions.extend(ff);
259            }
260        }
261        let mut extern_functions = HashMap::<String, Function>::new();
262        for module in &program.modules {
263            for extern_ in &module.externs {
264                let id = extern_.item.to_string();
265                if !extern_functions.contains_key(&id) {
266                    let index = functions.len() + extern_functions.len();
267                    let f = Function::from_core_extern(index, extern_, program)?;
268                    extern_functions.insert(id, f);
269                }
270            }
271        }
272        for (i, pm) in program.modules.iter().enumerate() {
273            let m = &mut modules[i];
274            for extern_ in &pm.externs {
275                let id = extern_.item.id.clone();
276                let index = extern_functions
277                    .iter()
278                    .find(|(i, _)| i == &&id)
279                    .unwrap()
280                    .1
281                    .index;
282                m.functions.push(index);
283            }
284        }
285        for (_, f) in extern_functions {
286            functions.push(f);
287        }
288        let export_structs = structs
289            .iter()
290            .filter_map(|s| if s.export { Some(s.index) } else { None })
291            .collect();
292        let export_functions = functions
293            .iter()
294            .filter_map(|f| if f.export { Some(f.index) } else { None })
295            .collect();
296        Ok(Self {
297            magic: program.magic,
298            structs,
299            globals,
300            functions,
301            modules,
302            export_structs,
303            export_functions,
304        })
305    }
306
307    pub fn to_bytes(&self, ops: &OpsDescriptor) -> SimpleResult<Vec<u8>> {
308        let mut stream = Cursor::new(vec![]);
309        let export_structs = {
310            let mut stream = Cursor::new(vec![]);
311            for i in &self.export_structs {
312                let i = &self.structs[*i];
313                stream.write_u64::<BigEndian>(i.index() as u64)?;
314                write_string(i.id(), &mut stream)?;
315            }
316            stream.into_inner()
317        };
318        let export_functions = {
319            let mut stream = Cursor::new(vec![]);
320            for i in &self.export_functions {
321                let i = &self.functions[*i];
322                stream.write_u64::<BigEndian>(i.index() as u64)?;
323                write_string(i.id(), &mut stream)?;
324            }
325            stream.into_inner()
326        };
327        let structs = self
328            .structs
329            .iter()
330            .map(|i| Ok((i, i.to_bytes(self)?)))
331            .collect::<SimpleResult<Vec<(&Struct, Vec<u8>)>>>()?;
332        let structs_offsets = {
333            let mut stream = Cursor::new(vec![]);
334            let mut offset = 0;
335            for (i, b) in &structs {
336                stream.write_u64::<BigEndian>(i.index() as u64)?;
337                stream.write_u64::<BigEndian>(offset)?;
338                offset += b.len() as u64;
339            }
340            stream.into_inner()
341        };
342        let functions = self
343            .functions
344            .iter()
345            .map(|i| Ok((i, i.to_header_bytes(self)?)))
346            .collect::<SimpleResult<Vec<(&Function, Vec<u8>)>>>()?;
347        let functions_offsets = {
348            let mut stream = Cursor::new(vec![]);
349            let mut offset = 0;
350            for (i, b) in &functions {
351                stream.write_u64::<BigEndian>(i.index() as u64)?;
352                stream.write_u64::<BigEndian>(offset)?;
353                offset += b.len() as u64;
354            }
355            stream.into_inner()
356        };
357        let (data_offsets, data) = self.collect_data()?;
358        let (globals, globals_size) = {
359            let mut result = HashMap::new();
360            let mut offset = 0;
361            for i in &self.globals {
362                result.insert(i.id().to_owned(), offset);
363                offset += i.size() as u64;
364            }
365            (result, offset)
366        };
367        let (ops_map, ops) = self.collect_ops(ops)?;
368        let bodies = self
369            .functions
370            .iter()
371            .map(|i| Ok((i, i.to_body_bytes(&ops_map, &data_offsets, &globals, self)?)))
372            .collect::<SimpleResult<Vec<(&Function, Vec<u8>)>>>()?;
373        let bodies_offsets = {
374            let mut stream = Cursor::new(vec![]);
375            let mut offset = 0;
376            for (i, b) in &bodies {
377                stream.write_u64::<BigEndian>(i.index() as u64)?;
378                stream.write_u64::<BigEndian>(offset)?;
379                offset += b.len() as u64;
380            }
381            stream.into_inner()
382        };
383
384        stream.write(&self.magic)?;
385
386        stream.write_u64::<BigEndian>(export_structs.len() as u64)?;
387        stream.write_u64::<BigEndian>(self.export_structs.len() as u64)?;
388        stream.write(&export_structs)?;
389
390        stream.write_u64::<BigEndian>(export_functions.len() as u64)?;
391        stream.write_u64::<BigEndian>(self.export_functions.len() as u64)?;
392        stream.write(&export_functions)?;
393
394        stream.write_u64::<BigEndian>(structs_offsets.len() as u64)?;
395        stream.write_u64::<BigEndian>(structs.len() as u64)?;
396        stream.write(&structs_offsets)?;
397        for (_, b) in &structs {
398            stream.write(&b)?;
399        }
400
401        stream.write_u64::<BigEndian>(functions_offsets.len() as u64)?;
402        stream.write_u64::<BigEndian>(functions.len() as u64)?;
403        stream.write(&functions_offsets)?;
404        for (_, b) in &functions {
405            stream.write(&b)?;
406        }
407
408        stream.write_u64::<BigEndian>(data.len() as u64)?;
409        stream.write_u64::<BigEndian>(data_offsets.len() as u64)?;
410        stream.write(&data)?;
411
412        stream.write_u64::<BigEndian>(globals_size)?;
413
414        stream.write_u64::<BigEndian>(ops.len() as u64)?;
415        stream.write_u64::<BigEndian>(ops_map.len() as u64)?;
416        stream.write(&ops)?;
417
418        stream.write_u64::<BigEndian>(bodies_offsets.len() as u64)?;
419        stream.write_u64::<BigEndian>(bodies.len() as u64)?;
420        stream.write(&bodies_offsets)?;
421        for (_, b) in &bodies {
422            stream.write_u64::<BigEndian>(b.len() as u64)?;
423            stream.write(&b)?;
424        }
425
426        Ok(stream.into_inner())
427    }
428
429    #[inline]
430    pub fn magic(&self) -> &[u8; 4] {
431        &self.magic
432    }
433
434    #[inline]
435    pub fn structs(&self) -> &[Struct] {
436        &self.structs
437    }
438
439    #[inline]
440    pub fn globals(&self) -> &[Variable] {
441        &self.globals
442    }
443
444    #[inline]
445    pub fn functions(&self) -> &[Function] {
446        &self.functions
447    }
448
449    #[inline]
450    pub fn modules(&self) -> &[Module] {
451        &self.modules
452    }
453
454    #[inline]
455    pub fn export_structs(&self) -> &[usize] {
456        &self.export_structs
457    }
458
459    #[inline]
460    pub fn export_functions(&self) -> &[usize] {
461        &self.export_functions
462    }
463
464    #[inline]
465    pub fn find_struct(&self, id: &str) -> Option<&Struct> {
466        self.structs.iter().find(|s| s.id() == id)
467    }
468
469    #[inline]
470    pub fn find_function(&self, id: &str) -> Option<&Function> {
471        self.functions.iter().find(|f| f.id() == id)
472    }
473
474    #[inline]
475    pub fn find_module_function(&self, index: usize, id: &str) -> Option<&Function> {
476        if index < self.modules.len() {
477            for f in self.modules[index].functions() {
478                let f = &self.functions[*f];
479                if f.id() == id {
480                    return Some(f);
481                }
482            }
483        }
484        None
485    }
486
487    fn collect_data(&self) -> SimpleResult<(HashMap<String, u64>, Vec<u8>)> {
488        let mut stream = Cursor::new(vec![]);
489        let mut offsets = HashMap::new();
490        let mut offset = 0;
491        for f in &self.functions {
492            for o in &f.body {
493                if let CoreBlockOp::Operation(o) = o {
494                    for p in &o.params {
495                        offset = self.collect_op_data(p, &mut stream, &mut offsets, offset)?;
496                    }
497                }
498            }
499        }
500        Ok((offsets, stream.into_inner()))
501    }
502
503    fn collect_op_data(
504        &self,
505        value: &CoreValue,
506        stream: &mut Cursor<Vec<u8>>,
507        offsets: &mut HashMap<String, u64>,
508        mut offset: usize,
509    ) -> SimpleResult<usize> {
510        match value {
511            CoreValue::Ref(ref v, _) => self.collect_op_data(v, stream, offsets, offset),
512            CoreValue::Deref(ref v, _) => self.collect_op_data(v, stream, offsets, offset),
513            CoreValue::FunctionCall(_, ref v, _) => {
514                for v in v {
515                    offset = self.collect_op_data(v, stream, offsets, offset)?;
516                }
517                Ok(offset)
518            }
519            CoreValue::Tuple(ref v, _) => {
520                for v in v {
521                    offset = self.collect_op_data(v, stream, offsets, offset)?;
522                }
523                Ok(offset)
524            }
525            CoreValue::String(ref s, ref t) => {
526                let id = format!("___CONST_STRING_{}", hash(s));
527                if !offsets.contains_key(&id) {
528                    if let Ok(ref cs) = CString::new(s.as_str()) {
529                        match t.to_string().as_str() {
530                            "*u8" => {
531                                stream.write_u8(DataType::StringU8 as u8)?;
532                                write_string(s, stream)?;
533                                offset += cs.as_bytes_with_nul().len();
534                                offsets.insert(id, offset as u64);
535                                Ok(offset + size_of::<usize>())
536                            }
537                            _ => Err(SimpleError::new(format!(
538                                "Trying to store constant as non-string bytes type `{}`",
539                                t.to_string()
540                            ))),
541                        }
542                    } else {
543                        Err(SimpleError::new(format!(
544                            "Could not store string that is not C-compatible: '{}'",
545                            s
546                        )))
547                    }
548                } else {
549                    Ok(offset)
550                }
551            }
552            CoreValue::Number(ref n) => match n {
553                CoreNumber::Integer(i, ref t) => {
554                    let id = format!("___CONST_INTEGER_{}", i);
555                    if !offsets.contains_key(&id) {
556                        match t.to_string().as_str() {
557                            "i8" => {
558                                stream.write_u8(DataType::I8 as u8)?;
559                                stream.write_i8(*i as i8)?;
560                                offsets.insert(id, offset as u64);
561                                Ok(offset + 1)
562                            }
563                            "u8" => {
564                                stream.write_u8(DataType::U8 as u8)?;
565                                stream.write_u8(*i as u8)?;
566                                offsets.insert(id, offset as u64);
567                                Ok(offset + 1)
568                            }
569                            "i16" => {
570                                stream.write_u8(DataType::I16 as u8)?;
571                                stream.write_i16::<BigEndian>(*i as i16)?;
572                                offsets.insert(id, offset as u64);
573                                Ok(offset + 2)
574                            }
575                            "u16" => {
576                                stream.write_u8(DataType::U16 as u8)?;
577                                stream.write_u16::<BigEndian>(*i as u16)?;
578                                offsets.insert(id, offset as u64);
579                                Ok(offset + 2)
580                            }
581                            "i32" => {
582                                stream.write_u8(DataType::I32 as u8)?;
583                                stream.write_i32::<BigEndian>(*i as i32)?;
584                                offsets.insert(id, offset as u64);
585                                Ok(offset + 4)
586                            }
587                            "u32" => {
588                                stream.write_u8(DataType::U32 as u8)?;
589                                stream.write_u32::<BigEndian>(*i as u32)?;
590                                offsets.insert(id, offset as u64);
591                                Ok(offset + 4)
592                            }
593                            "i64" => {
594                                stream.write_u8(DataType::I64 as u8)?;
595                                stream.write_i64::<BigEndian>(*i as i64)?;
596                                offsets.insert(id, offset as u64);
597                                Ok(offset + 8)
598                            }
599                            "u64" => {
600                                stream.write_u8(DataType::U64 as u8)?;
601                                stream.write_u64::<BigEndian>(*i as u64)?;
602                                offsets.insert(id, offset as u64);
603                                Ok(offset + 8)
604                            }
605                            "isize" => {
606                                stream.write_u8(DataType::Isize as u8)?;
607                                stream.write_int::<BigEndian>(*i as i64, size_of::<isize>())?;
608                                offsets.insert(id, offset as u64);
609                                Ok(offset + size_of::<isize>())
610                            }
611                            "usize" => {
612                                stream.write_u8(DataType::Usize as u8)?;
613                                stream.write_uint::<BigEndian>(*i as u64, size_of::<usize>())?;
614                                offsets.insert(id, offset as u64);
615                                Ok(offset + size_of::<usize>())
616                            }
617                            _ => Err(SimpleError::new(format!(
618                                "Trying to store constant as non-integer type `{}`",
619                                t.to_string()
620                            ))),
621                        }
622                    } else {
623                        Ok(offset)
624                    }
625                }
626                CoreNumber::Float(f, ref t) => {
627                    let id = format!("___CONST_FLOAT_{}", f);
628                    if !offsets.contains_key(&id) {
629                        match t.to_string().as_str() {
630                            "f32" => {
631                                stream.write_u8(DataType::F32 as u8)?;
632                                stream.write_f32::<BigEndian>(*f as f32)?;
633                                offsets.insert(id, offset as u64);
634                                Ok(offset + 4)
635                            }
636                            "f64" => {
637                                stream.write_u8(DataType::F64 as u8)?;
638                                stream.write_f64::<BigEndian>(*f as f64)?;
639                                offsets.insert(id, offset as u64);
640                                Ok(offset + 8)
641                            }
642                            _ => Err(SimpleError::new(format!(
643                                "Trying to store constant as non-float type `{}`",
644                                t.to_string()
645                            ))),
646                        }
647                    } else {
648                        Ok(offset)
649                    }
650                }
651            },
652            CoreValue::OperationInline(_, ref v, _) => {
653                for v in v {
654                    offset = self.collect_op_data(v, stream, offsets, offset)?;
655                }
656                Ok(offset)
657            }
658            CoreValue::Variable(_, _) => Ok(offset),
659        }
660    }
661
662    fn collect_ops(&self, opsdesc: &OpsDescriptor) -> SimpleResult<(OpsMap, Vec<u8>)> {
663        let mut stream = Cursor::new(vec![]);
664        let mut index = 0;
665        let mut ops = HashMap::new();
666        for f in &self.functions {
667            for o in &f.body {
668                if let CoreBlockOp::Operation(o) = o {
669                    if !ops.contains_key(&o.id) {
670                        write_string(&o.id, &mut stream)?;
671                        ops.insert(o.id.to_owned(), (index, self.find_op_type(&o.id, opsdesc)));
672                        index += 1;
673                    }
674                    for v in &o.params {
675                        self.collect_value_ops(v, opsdesc, &mut stream, &mut ops, &mut index)?;
676                    }
677                    for v in &o.targets {
678                        self.collect_value_ops(v, opsdesc, &mut stream, &mut ops, &mut index)?;
679                    }
680                }
681            }
682        }
683        Ok((ops, stream.into_inner()))
684    }
685
686    fn collect_value_ops(
687        &self,
688        value: &CoreValue,
689        opsdesc: &OpsDescriptor,
690        stream: &mut dyn Write,
691        ops: &mut OpsMap,
692        index: &mut u64,
693    ) -> SimpleResult<()> {
694        match value {
695            CoreValue::Ref(v, _) => self.collect_value_ops(v, opsdesc, stream, ops, index),
696            CoreValue::Deref(v, _) => self.collect_value_ops(v, opsdesc, stream, ops, index),
697            CoreValue::FunctionCall(_, v, _) => {
698                for v in v {
699                    self.collect_value_ops(v, opsdesc, stream, ops, index)?;
700                }
701                Ok(())
702            }
703            CoreValue::Tuple(v, _) => {
704                for v in v {
705                    self.collect_value_ops(v, opsdesc, stream, ops, index)?;
706                }
707                Ok(())
708            }
709            CoreValue::OperationInline(id, v, _) => {
710                if !ops.contains_key(id) {
711                    write_string(id, stream)?;
712                    ops.insert(id.to_owned(), (*index, self.find_op_type(id, opsdesc)));
713                    *index += 1;
714                }
715                for v in v {
716                    self.collect_value_ops(v, opsdesc, stream, ops, index)?;
717                }
718                Ok(())
719            }
720            _ => Ok(()),
721        }
722    }
723
724    fn find_op_type(&self, id: &str, opsdesc: &OpsDescriptor) -> Option<CoreType> {
725        opsdesc
726            .rules
727            .iter()
728            .find(|r| r.id == id && r.targets.len() == 1)
729            .map(|r| r.targets[0].clone())
730    }
731
732    fn write_core_value(
733        &self,
734        value: &CoreValue,
735        stream: &mut Cursor<Vec<u8>>,
736        function: &Function,
737        data: &HashMap<String, u64>,
738        globals: &HashMap<String, u64>,
739        ops: &HashMap<String, (u64, Option<CoreType>)>,
740    ) -> SimpleResult<()> {
741        match value {
742            CoreValue::Ref(ref v, ref a) => {
743                self.write_core_value(v, stream, function, data, globals, ops)?;
744                stream.write_u8(OpIndex::ReferencePointer as u8)?;
745                if a.is_some() {
746                    Err(SimpleError::new(
747                        "References cannot be accessed. They can be passed or dereferenced"
748                            .to_owned(),
749                    ))
750                } else {
751                    Ok(())
752                }
753            }
754            CoreValue::Deref(ref v, ref a) => {
755                self.write_core_value(v, stream, function, data, globals, ops)?;
756                stream.write_u8(OpIndex::DereferencePointer as u8)?;
757                if let Some(ref a) = a {
758                    stream.write_u8(OpIndex::OffsetPointer as u8)?;
759                    let t = self.find_value_type(v, function, data, ops)?;
760                    self.write_core_value_access(stream, &t, a)?;
761                }
762                Ok(())
763            }
764            CoreValue::FunctionCall(ref id, ref v, ref a) => {
765                let f = self.find_function(id).unwrap();
766                for v in v.iter().rev() {
767                    self.write_core_value(v, stream, function, data, globals, ops)?;
768                }
769                stream.write_u8(OpIndex::CallFunction as u8)?;
770                stream.write_u64::<BigEndian>(f.index() as u64)?;
771                if let Some(ref t) = f.typeid() {
772                    if let Some(ref a) = a {
773                        stream.write_u8(OpIndex::OffsetPointer as u8)?;
774                        self.write_core_value_access(stream, t, a)?;
775                    }
776                    Ok(())
777                } else if a.is_some() {
778                    Err(SimpleError::new(format!(
779                        "Trying to access return value of non-returning function: {}",
780                        id
781                    )))
782                } else {
783                    Ok(())
784                }
785            }
786            CoreValue::Tuple(ref v, ref a) => {
787                for v in v.iter().rev() {
788                    self.write_core_value(v, stream, function, data, globals, ops)?;
789                }
790                stream.write_u8(OpIndex::ProduceTuple as u8)?;
791                stream.write_u64::<BigEndian>(v.len() as u64)?;
792                for v in v {
793                    let t = self.find_value_type(v, function, data, ops)?;
794                    stream.write_u64::<BigEndian>(self.type_size(&t) as u64)?;
795                }
796                if let Some(ref a) = a {
797                    stream.write_u8(OpIndex::OffsetPointer as u8)?;
798                    let mut types = vec![];
799                    for v in v {
800                        types.push(self.find_value_type(v, function, data, ops)?);
801                    }
802                    self.write_core_value_access_tuple(stream, &types, a)?;
803                }
804                Ok(())
805            }
806            CoreValue::String(ref s, _) => {
807                stream.write_u8(OpIndex::DataPointer as u8)?;
808                stream.write_u64::<BigEndian>(data[&format!("___CONST_STRING_{}", hash(s))])?;
809                Ok(())
810            }
811            CoreValue::Number(ref n) => {
812                stream.write_u8(OpIndex::DataPointer as u8)?;
813                match n {
814                    CoreNumber::Integer(ref v, _) => {
815                        stream.write_u64::<BigEndian>(data[&format!("___CONST_INTEGER_{}", v)])?;
816                        Ok(())
817                    }
818                    CoreNumber::Float(ref v, _) => {
819                        stream.write_u64::<BigEndian>(data[&format!("___CONST_FLOAT_{}", v)])?;
820                        Ok(())
821                    }
822                }
823            }
824            CoreValue::OperationInline(ref id, ref v, ref a) => {
825                stream.write_u8(OpIndex::ExecuteOpInlineStart as u8)?;
826                for v in v {
827                    self.write_core_value(v, stream, function, data, globals, ops)?;
828                    stream.write_u8(OpIndex::StoreParamAddress as u8)?;
829                }
830                stream.write_u8(OpIndex::ExecuteOpInlineStop as u8)?;
831                stream.write_u64::<BigEndian>(ops[id].0)?;
832                let t = ops[id].1.clone().unwrap();
833                stream.write_u64::<BigEndian>(self.type_size(&t) as u64)?;
834                if let Some(ref a) = a {
835                    stream.write_u8(OpIndex::OffsetPointer as u8)?;
836                    self.write_core_value_access(stream, &t, a)?;
837                }
838                Ok(())
839            }
840            CoreValue::Variable(ref id, ref a) => {
841                let t = if let Some(v) = function.params().iter().find(|v| v.id() == id) {
842                    stream.write_u8(OpIndex::ParamsPointer as u8)?;
843                    stream.write_u64::<BigEndian>(v.offset().unwrap() as u64)?;
844                    v.typeid()
845                } else if let Some(v) = function.locals().iter().find(|v| v.id() == id) {
846                    stream.write_u8(OpIndex::LocalsPointer as u8)?;
847                    stream.write_u64::<BigEndian>(v.offset().unwrap() as u64)?;
848                    v.typeid()
849                } else if let Some(o) = globals.get(id) {
850                    stream.write_u8(OpIndex::GlobalsPointer as u8)?;
851                    stream.write_u64::<BigEndian>(*o)?;
852                    self.globals.iter().find(|v| v.id() == id).unwrap().typeid()
853                } else if id == "_" {
854                    if let Some(t) = function.typeid() {
855                        stream.write_u8(OpIndex::ResultPointer as u8)?;
856                        t
857                    } else if a.is_some() {
858                        return Err(SimpleError::new(format!(
859                            "Trying to access return value of non-returning function: {}",
860                            function.index(),
861                        )));
862                    } else {
863                        unreachable!()
864                    }
865                } else {
866                    unreachable!()
867                };
868                if let Some(ref a) = a {
869                    stream.write_u8(OpIndex::OffsetPointer as u8)?;
870                    self.write_core_value_access(stream, t, a)?;
871                }
872                Ok(())
873            }
874        }
875    }
876
877    fn write_core_value_access(
878        &self,
879        stream: &mut Cursor<Vec<u8>>,
880        type_: &CoreType,
881        access: &CoreAccess,
882    ) -> SimpleResult<()> {
883        match type_ {
884            CoreType::Identifier(ref id) => {
885                let s = self.find_struct(id).unwrap();
886                self.write_core_value_access_struct(stream, s, access)
887            }
888            CoreType::Tuple(ref v) => self.write_core_value_access_tuple(stream, v, access),
889            CoreType::Pointer(ref v) => self.write_core_value_access(stream, v, access),
890        }
891    }
892
893    fn write_core_value_access_struct(
894        &self,
895        stream: &mut Cursor<Vec<u8>>,
896        struct_: &Struct,
897        access: &CoreAccess,
898    ) -> SimpleResult<()> {
899        match access {
900            CoreAccess::Variable(ref i, ref a) => {
901                let field = struct_.find_field(i).unwrap();
902                stream.write_u64::<BigEndian>(field.offset() as u64)?;
903                if let Some(ref a) = a {
904                    stream.write_u8(OpIndex::OffsetPointer as u8)?;
905                    self.write_core_value_access(stream, field.typeid(), a)?;
906                }
907                Ok(())
908            }
909            _ => Err(SimpleError::new(format!(
910                "Trying to get struct access of not straight struct id: {}",
911                struct_.id()
912            ))),
913        }
914    }
915
916    fn write_core_value_access_tuple(
917        &self,
918        stream: &mut Cursor<Vec<u8>>,
919        types: &[CoreType],
920        access: &CoreAccess,
921    ) -> SimpleResult<()> {
922        match access {
923            CoreAccess::Tuple(i, ref a) => {
924                let (typeid, offset) = self.find_tuple_field(types, *i as usize)?;
925                stream.write_u64::<BigEndian>(offset as u64)?;
926                if let Some(ref a) = a {
927                    stream.write_u8(OpIndex::OffsetPointer as u8)?;
928                    self.write_core_value_access(stream, typeid, a)?;
929                }
930                Ok(())
931            }
932            _ => Err(SimpleError::new(format!(
933                "Trying to get tuple access of not straight tuple id: {:?}",
934                types
935            ))),
936        }
937    }
938
939    fn find_tuple_field<'a>(
940        &self,
941        types: &'a [CoreType],
942        index: usize,
943    ) -> SimpleResult<(&'a CoreType, usize)> {
944        let mut offset = 0;
945        for (i, t) in types.iter().enumerate() {
946            let size = self.type_size(t);
947            if i == index {
948                return Ok((t, offset));
949            } else {
950                offset += size;
951            }
952        }
953        Err(SimpleError::new(format!(
954            "Tuple does not have field #{}",
955            index
956        )))
957    }
958
959    #[inline]
960    pub fn type_size(&self, typeid: &CoreType) -> usize {
961        match typeid {
962            CoreType::Identifier(id) => self.structs.iter().find(|s| s.id() == id).unwrap().size(),
963            CoreType::Pointer(_) => size_of::<usize>(),
964            CoreType::Tuple(t) => t.iter().map(|t| self.type_size(t)).sum(),
965        }
966    }
967
968    pub fn find_value_type(
969        &self,
970        value: &CoreValue,
971        function: &Function,
972        data: &HashMap<String, u64>,
973        ops: &HashMap<String, (u64, Option<CoreType>)>,
974    ) -> SimpleResult<CoreType> {
975        match value {
976            CoreValue::Ref(ref v, ref a) => {
977                let t = CoreType::Pointer(Box::new(self.find_value_type(v, function, data, ops)?));
978                if a.is_some() {
979                    Err(SimpleError::new(
980                        "References cannot be accessed. They can be passed or dereferenced"
981                            .to_owned(),
982                    ))
983                } else {
984                    Ok(t)
985                }
986            }
987            CoreValue::Deref(ref v, ref a) => {
988                if let CoreType::Pointer(t) = self.find_value_type(v, function, data, ops)? {
989                    if let Some(ref a) = a {
990                        self.find_access_type(&t, a, function, data)
991                    } else {
992                        Ok(*t)
993                    }
994                } else {
995                    Err(SimpleError::new(format!(
996                        "Trying to get type of dereferenced non-pointer value: {:?}",
997                        v
998                    )))
999                }
1000            }
1001            CoreValue::FunctionCall(ref id, _, ref a) => {
1002                if let Some(f) = self.find_function(id) {
1003                    if let Some(ref t) = f.typeid() {
1004                        if let Some(ref a) = a {
1005                            self.find_access_type(t, a, function, data)
1006                        } else {
1007                            Ok(t.clone())
1008                        }
1009                    } else {
1010                        Err(SimpleError::new(format!("Trying to get type of function call where function does not return any value: {:?}", id)))
1011                    }
1012                } else {
1013                    Err(SimpleError::new(format!(
1014                        "Trying to get type of non-existing function call: {:?}",
1015                        id
1016                    )))
1017                }
1018            }
1019            CoreValue::Tuple(ref v, ref a) => {
1020                let mut t = vec![];
1021                for v in v {
1022                    t.push(self.find_value_type(v, function, data, ops)?);
1023                }
1024                let t = CoreType::Tuple(t);
1025                if let Some(ref a) = a {
1026                    self.find_access_type(&t, a, function, data)
1027                } else {
1028                    Ok(t)
1029                }
1030            }
1031            CoreValue::String(_, ref t) => Ok(t.clone()),
1032            CoreValue::Number(ref n) => Ok(match n {
1033                CoreNumber::Integer(_, ref t) => t.clone(),
1034                CoreNumber::Float(_, ref t) => t.clone(),
1035            }),
1036            CoreValue::OperationInline(ref id, _, ref a) => {
1037                let t = if let Some((_, Some(t))) = ops.get(id) {
1038                    Ok(t.clone())
1039                } else {
1040                    Err(SimpleError::new(format!(
1041                        "There is no op `{}` that can be inlined",
1042                        id
1043                    )))
1044                }?;
1045                if let Some(ref a) = a {
1046                    self.find_access_type(&t, a, function, data)
1047                } else {
1048                    Ok(t)
1049                }
1050            }
1051            CoreValue::Variable(ref id, ref a) => {
1052                let t = if let Some(v) = function.params().iter().find(|v| v.id() == id) {
1053                    v.typeid()
1054                } else if let Some(v) = function.locals().iter().find(|v| v.id() == id) {
1055                    v.typeid()
1056                } else if let Some(v) = self.globals.iter().find(|v| v.id() == id) {
1057                    v.typeid()
1058                } else {
1059                    return Err(SimpleError::new(format!(
1060                        "Trying to get type of non-existing symbol: {}",
1061                        id
1062                    )));
1063                };
1064                if let Some(ref a) = a {
1065                    self.find_access_type(t, a, function, data)
1066                } else {
1067                    Ok(t.clone())
1068                }
1069            }
1070        }
1071    }
1072
1073    pub fn find_access_type(
1074        &self,
1075        type_: &CoreType,
1076        access: &CoreAccess,
1077        function: &Function,
1078        data: &HashMap<String, u64>,
1079    ) -> SimpleResult<CoreType> {
1080        match access {
1081            CoreAccess::Tuple(i, ref a) => match type_ {
1082                CoreType::Tuple(ref v) => {
1083                    let i = *i as usize;
1084                    if i < v.len() {
1085                        if let Some(ref a) = a {
1086                            self.find_access_type(&v[i], a, function, data)
1087                        } else {
1088                            Ok(v[i].clone())
1089                        }
1090                    } else {
1091                        Err(SimpleError::new(format!(
1092                            "Trying to get access of tuple with index out of bounds: {}",
1093                            i
1094                        )))
1095                    }
1096                }
1097                _ => Err(SimpleError::new(format!(
1098                    "Trying to get access of tuple on non-tuple type: {:?}",
1099                    type_
1100                ))),
1101            },
1102            CoreAccess::Variable(ref i, ref a) => match type_ {
1103                CoreType::Identifier(ref id) => {
1104                    if let Some(s) = self.find_struct(id) {
1105                        if let Some(f) = s.find_field(i) {
1106                            if let Some(ref a) = a {
1107                                self.find_access_type(f.typeid(), a, function, data)
1108                            } else {
1109                                Ok(f.typeid().clone())
1110                            }
1111                        } else {
1112                            Err(SimpleError::new(format!(
1113                                "Trying to get access of non-existing `{}` field of struct: {}",
1114                                i, id
1115                            )))
1116                        }
1117                    } else {
1118                        Err(SimpleError::new(format!(
1119                            "Trying to get `{}` field access of non-existing struct: {}",
1120                            i, id
1121                        )))
1122                    }
1123                }
1124                _ => Err(SimpleError::new(format!(
1125                    "Trying to get access of field which is not straight type name: {}",
1126                    i
1127                ))),
1128            },
1129        }
1130    }
1131}
1132
1133#[derive(Debug, Clone)]
1134pub struct Struct {
1135    index: usize,
1136    id: String,
1137    fields: Vec<StructField>,
1138    size: usize,
1139    export: bool,
1140}
1141
1142impl Struct {
1143    pub fn new_atom(index: usize, id: &str, size: usize) -> Self {
1144        Struct {
1145            index,
1146            id: id.to_owned(),
1147            fields: vec![],
1148            size,
1149            export: false,
1150        }
1151    }
1152
1153    pub fn from_core(
1154        index: usize,
1155        struct_: &CoreStruct,
1156        program: &CoreProgram,
1157    ) -> SimpleResult<Self> {
1158        let mut fields = vec![];
1159        let mut offset = 0;
1160        for f in &struct_.fields {
1161            let field = StructField::from_core(f, offset, program)?;
1162            offset += field.size;
1163            fields.push(field);
1164        }
1165        Ok(Self {
1166            index,
1167            id: struct_.id.clone(),
1168            fields,
1169            size: offset,
1170            export: struct_.export,
1171        })
1172    }
1173
1174    pub fn to_bytes(&self, assembly: &Assembly) -> SimpleResult<Vec<u8>> {
1175        let mut stream = Cursor::new(vec![]);
1176        stream.write_u64::<BigEndian>(self.index as u64)?;
1177        stream.write_u64::<BigEndian>(self.fields.len() as u64)?;
1178        for field in &self.fields {
1179            field.write(&mut stream, assembly)?;
1180        }
1181        stream.write_u64::<BigEndian>(self.size as u64)?;
1182        stream.write_u8(if self.export { 1 } else { 0 })?;
1183        Ok(stream.into_inner())
1184    }
1185
1186    #[inline]
1187    pub fn index(&self) -> usize {
1188        self.index
1189    }
1190
1191    #[inline]
1192    pub fn id(&self) -> &str {
1193        &self.id
1194    }
1195
1196    #[inline]
1197    pub fn fields(&self) -> &[StructField] {
1198        &self.fields
1199    }
1200
1201    #[inline]
1202    pub fn size(&self) -> usize {
1203        self.size
1204    }
1205
1206    #[inline]
1207    pub fn export(&self) -> bool {
1208        self.export
1209    }
1210
1211    #[inline]
1212    pub fn find_field(&self, id: &str) -> Option<&StructField> {
1213        self.fields.iter().find(|f| f.id() == id)
1214    }
1215}
1216
1217#[derive(Debug, Clone)]
1218pub struct StructField {
1219    id: String,
1220    typeid: CoreType,
1221    offset: usize,
1222    size: usize,
1223}
1224
1225impl StructField {
1226    pub fn from_core(
1227        field: &CoreVariable,
1228        offset: usize,
1229        program: &CoreProgram,
1230    ) -> SimpleResult<Self> {
1231        Ok(Self {
1232            id: field.id.clone(),
1233            typeid: field.typeid.clone(),
1234            offset,
1235            size: calculate_type_size(&field.typeid, program),
1236        })
1237    }
1238
1239    pub fn write(&self, stream: &mut dyn Write, assembly: &Assembly) -> SimpleResult<()> {
1240        write_core_type(&self.typeid, stream, assembly)?;
1241        stream.write_u64::<BigEndian>(self.offset as u64)?;
1242        stream.write_u64::<BigEndian>(self.size as u64)?;
1243        Ok(())
1244    }
1245
1246    #[inline]
1247    pub fn id(&self) -> &str {
1248        &self.id
1249    }
1250
1251    #[inline]
1252    pub fn typeid(&self) -> &CoreType {
1253        &self.typeid
1254    }
1255
1256    #[inline]
1257    pub fn offset(&self) -> usize {
1258        self.offset
1259    }
1260
1261    #[inline]
1262    pub fn size(&self) -> usize {
1263        self.size
1264    }
1265}
1266
1267#[derive(Debug, Clone)]
1268pub struct Variable {
1269    index: usize,
1270    id: String,
1271    typeid: CoreType,
1272    size: usize,
1273    offset: Option<usize>,
1274}
1275
1276impl Variable {
1277    pub fn from_core(
1278        index: usize,
1279        variable: &CoreVariable,
1280        program: &CoreProgram,
1281        offset: Option<usize>,
1282    ) -> SimpleResult<Self> {
1283        Ok(Self {
1284            index,
1285            id: variable.id.clone(),
1286            typeid: variable.typeid.clone(),
1287            size: calculate_type_size(&variable.typeid, program),
1288            offset,
1289        })
1290    }
1291
1292    pub fn to_bytes(&self, assembly: &Assembly) -> SimpleResult<Vec<u8>> {
1293        let mut stream = Cursor::new(vec![]);
1294        stream.write_u64::<BigEndian>(self.index as u64)?;
1295        write_core_type(&self.typeid, &mut stream, assembly)?;
1296        stream.write_u64::<BigEndian>(self.size as u64)?;
1297        if let Some(o) = self.offset {
1298            stream.write_u8(1)?;
1299            stream.write_u64::<BigEndian>(o as u64)?;
1300        } else {
1301            stream.write_u8(0)?;
1302        }
1303        Ok(stream.into_inner())
1304    }
1305
1306    pub fn write(&self, stream: &mut dyn Write, assembly: &Assembly) -> SimpleResult<()> {
1307        stream.write(&self.to_bytes(assembly)?)?;
1308        Ok(())
1309    }
1310
1311    #[inline]
1312    pub fn index(&self) -> usize {
1313        self.index
1314    }
1315
1316    #[inline]
1317    pub fn id(&self) -> &str {
1318        &self.id
1319    }
1320
1321    #[inline]
1322    pub fn typeid(&self) -> &CoreType {
1323        &self.typeid
1324    }
1325
1326    #[inline]
1327    pub fn size(&self) -> usize {
1328        self.size
1329    }
1330
1331    #[inline]
1332    pub fn offset(&self) -> &Option<usize> {
1333        &self.offset
1334    }
1335}
1336
1337#[derive(Debug, Clone)]
1338pub struct Function {
1339    index: usize,
1340    id: String,
1341    params: Vec<Variable>,
1342    typeid: Option<CoreType>,
1343    locals: Vec<Variable>,
1344    body: Vec<CoreBlockOp>,
1345    external: Option<(String, String)>,
1346    export: bool,
1347}
1348
1349impl Function {
1350    pub fn from_core(
1351        index: usize,
1352        function: &CoreFunction,
1353        program: &CoreProgram,
1354    ) -> SimpleResult<Function> {
1355        let mut po = 0;
1356        let mut lo = 0;
1357        Ok(Self {
1358            index,
1359            id: function.header.id.clone(),
1360            params: function
1361                .header
1362                .params
1363                .iter()
1364                .enumerate()
1365                .map(|(i, p)| {
1366                    let v = Variable::from_core(i, p, program, Some(po))?;
1367                    po += v.size();
1368                    Ok(v)
1369                })
1370                .collect::<SimpleResult<_>>()?,
1371            typeid: function.header.typeid.clone(),
1372            locals: function
1373                .locals
1374                .iter()
1375                .enumerate()
1376                .map(|(i, p)| {
1377                    let v = Variable::from_core(i, p, program, Some(lo))?;
1378                    lo += v.size();
1379                    Ok(v)
1380                })
1381                .collect::<SimpleResult<_>>()?,
1382            body: function.body.clone(),
1383            external: None,
1384            export: function.export,
1385        })
1386    }
1387
1388    pub fn from_core_extern(
1389        index: usize,
1390        extern_: &CoreExtern,
1391        program: &CoreProgram,
1392    ) -> SimpleResult<Function> {
1393        let mut po = 0;
1394        Ok(Self {
1395            index,
1396            id: extern_.item.id.clone(),
1397            params: extern_
1398                .item
1399                .params
1400                .iter()
1401                .enumerate()
1402                .map(|(i, p)| {
1403                    let v = Variable::from_core(i, p, program, Some(po))?;
1404                    po += v.size();
1405                    Ok(v)
1406                })
1407                .collect::<SimpleResult<_>>()?,
1408            typeid: extern_.item.typeid.clone(),
1409            locals: vec![],
1410            body: vec![],
1411            external: Some((
1412                extern_.location_module.clone(),
1413                extern_.location_function.clone(),
1414            )),
1415            export: false,
1416        })
1417    }
1418
1419    pub fn to_header_bytes(&self, assembly: &Assembly) -> SimpleResult<Vec<u8>> {
1420        let mut stream = Cursor::new(vec![]);
1421        stream.write_u64::<BigEndian>(self.index as u64)?;
1422        stream.write_u64::<BigEndian>(self.params.len() as u64)?;
1423        for p in &self.params {
1424            p.write(&mut stream, assembly)?;
1425        }
1426        if let Some(t) = &self.typeid {
1427            stream.write_u8(1)?;
1428            write_core_type(t, &mut stream, assembly)?;
1429        } else {
1430            stream.write_u8(0)?;
1431        }
1432        stream.write_u64::<BigEndian>(self.locals.len() as u64)?;
1433        for l in &self.locals {
1434            l.write(&mut stream, assembly)?;
1435        }
1436        if let Some((m, f)) = &self.external {
1437            stream.write_u8(1)?;
1438            write_string(&m, &mut stream)?;
1439            write_string(&f, &mut stream)?;
1440        } else {
1441            stream.write_u8(0)?;
1442        }
1443        stream.write_u8(if self.export { 1 } else { 0 })?;
1444        Ok(stream.into_inner())
1445    }
1446
1447    pub fn to_body_bytes(
1448        &self,
1449        ops: &HashMap<String, (u64, Option<CoreType>)>,
1450        data: &HashMap<String, u64>,
1451        globals: &HashMap<String, u64>,
1452        assembly: &Assembly,
1453    ) -> SimpleResult<Vec<u8>> {
1454        let mut stream_labels = Cursor::new(vec![]);
1455        let mut stream_ops = Cursor::new(vec![]);
1456        let mut labels_count = 0;
1457        let mut ops_count = 0;
1458        for op in &self.body {
1459            match op {
1460                CoreBlockOp::Operation(op) => {
1461                    stream_ops.write_u8(OpIndex::ExecuteOpStart as u8)?;
1462                    for v in op.targets.iter() {
1463                        assembly.write_core_value(v, &mut stream_ops, self, data, globals, ops)?;
1464                        stream_ops.write_u8(OpIndex::StoreTargetAddress as u8)?;
1465                    }
1466                    for v in op.params.iter() {
1467                        assembly.write_core_value(v, &mut stream_ops, self, data, globals, ops)?;
1468                        stream_ops.write_u8(OpIndex::StoreParamAddress as u8)?;
1469                    }
1470                    stream_ops.write_u8(OpIndex::ExecuteOpStop as u8)?;
1471                    stream_ops.write_u64::<BigEndian>(ops[&op.id].0)?;
1472                    ops_count += 1;
1473                }
1474                CoreBlockOp::Label(name) => {
1475                    write_string(name, &mut stream_labels)?;
1476                    stream_labels.write_u64::<BigEndian>(stream_ops.position())?;
1477                    labels_count += 1;
1478                }
1479            }
1480        }
1481        let mut stream = Cursor::new(vec![]);
1482        stream.write_u64::<BigEndian>(stream_labels.position())?;
1483        stream.write_u64::<BigEndian>(labels_count)?;
1484        stream.write(&stream_labels.into_inner())?;
1485        stream.write_u64::<BigEndian>(stream_ops.position())?;
1486        stream.write_u64::<BigEndian>(ops_count)?;
1487        stream.write(&stream_ops.into_inner())?;
1488        Ok(stream.into_inner())
1489    }
1490
1491    #[inline]
1492    pub fn index(&self) -> usize {
1493        self.index
1494    }
1495
1496    #[inline]
1497    pub fn id(&self) -> &str {
1498        &self.id
1499    }
1500
1501    #[inline]
1502    pub fn params(&self) -> &[Variable] {
1503        &self.params
1504    }
1505
1506    #[inline]
1507    pub fn typeid(&self) -> &Option<CoreType> {
1508        &self.typeid
1509    }
1510
1511    #[inline]
1512    pub fn locals(&self) -> &[Variable] {
1513        &self.locals
1514    }
1515
1516    #[inline]
1517    pub fn body(&self) -> &[CoreBlockOp] {
1518        &self.body
1519    }
1520
1521    #[inline]
1522    pub fn external(&self) -> &Option<(String, String)> {
1523        &self.external
1524    }
1525
1526    #[inline]
1527    pub fn export(&self) -> bool {
1528        self.export
1529    }
1530}
1531
1532#[derive(Debug, Clone)]
1533pub struct Module {
1534    index: usize,
1535    structs: Vec<usize>,
1536    globals: Vec<usize>,
1537    functions: Vec<usize>,
1538}
1539
1540impl Module {
1541    #[inline]
1542    pub fn index(&self) -> usize {
1543        self.index
1544    }
1545
1546    #[inline]
1547    pub fn structs(&self) -> &[usize] {
1548        &self.structs
1549    }
1550
1551    #[inline]
1552    pub fn globals(&self) -> &[usize] {
1553        &self.globals
1554    }
1555
1556    #[inline]
1557    pub fn functions(&self) -> &[usize] {
1558        &self.functions
1559    }
1560
1561    #[inline]
1562    pub fn find_function<'a>(&self, id: &str, assembly: &'a Assembly) -> Option<&'a Function> {
1563        for f in &self.functions {
1564            let f = &assembly.functions()[*f];
1565            if f.id() == id {
1566                return Some(f);
1567            }
1568        }
1569        None
1570    }
1571}
1572
1573pub fn calculate_type_size(typeid: &CoreType, program: &CoreProgram) -> usize {
1574    match typeid {
1575        CoreType::Identifier(ref id) => match id.as_str() {
1576            "i8" | "u8" => 1,
1577            "i16" | "u16" => 2,
1578            "i32" | "u32" | "f32" => 4,
1579            "i64" | "u64" | "f64" => 8,
1580            "isize" | "usize" => size_of::<usize>(),
1581            _ => {
1582                if let Some(s) = program.find_struct(id) {
1583                    s.fields
1584                        .iter()
1585                        .map(|f| calculate_type_size(&f.typeid, program))
1586                        .sum()
1587                } else {
1588                    0
1589                }
1590            }
1591        },
1592        CoreType::Pointer(_) => size_of::<usize>(),
1593        CoreType::Tuple(ref v) => v.iter().map(|t| calculate_type_size(t, program)).sum(),
1594    }
1595}