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}