datex_core/compiler/
context.rs

1use crate::global::instruction_codes::InstructionCode;
2use crate::libs::core::CoreLibPointerId;
3use crate::references::reference::ReferenceMutability;
4use crate::utils::buffers::{
5    append_f32, append_f64, append_i8, append_i16, append_i32, append_i64,
6    append_i128, append_u8, append_u32, append_u128,
7};
8use crate::values::core_value::CoreValue;
9use crate::values::core_values::decimal::Decimal;
10use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
11use crate::values::core_values::endpoint::Endpoint;
12use crate::values::core_values::integer::Integer;
13use crate::values::core_values::integer::typed_integer::TypedInteger;
14use crate::values::core_values::integer::utils::smallest_fitting_signed;
15use crate::values::pointer::PointerAddress;
16use crate::values::value::Value;
17use crate::values::value_container::ValueContainer;
18use binrw::BinWrite;
19use itertools::Itertools;
20use std::cell::{Cell, RefCell};
21use std::cmp::PartialEq;
22use std::collections::HashMap;
23use std::io::Cursor;
24
25#[derive(Debug, Clone, Default, Copy, PartialEq, Eq, Hash)]
26pub struct VirtualSlot {
27    pub level: u8, // parent scope level if exists, otherwise 0
28    // local slot address of scope with level
29    pub virtual_address: u32,
30}
31
32impl VirtualSlot {
33    pub fn local(virtual_address: u32) -> Self {
34        VirtualSlot {
35            level: 0,
36            virtual_address,
37        }
38    }
39    pub fn is_external(&self) -> bool {
40        self.level > 0
41    }
42
43    pub fn external(level: u8, virtual_address: u32) -> Self {
44        VirtualSlot {
45            level,
46            virtual_address,
47        }
48    }
49
50    pub fn downgrade(&self) -> Self {
51        VirtualSlot {
52            level: self.level + 1,
53            virtual_address: self.virtual_address,
54        }
55    }
56
57    pub fn upgrade(&self) -> Self {
58        if self.level > 0 {
59            VirtualSlot {
60                level: self.level - 1,
61                virtual_address: self.virtual_address,
62            }
63        } else {
64            panic!("Cannot upgrade a local slot");
65        }
66    }
67}
68
69/// compilation context, created for each compiler call, even if compiling a script for the same scope
70pub struct CompilationContext<'a> {
71    pub index: Cell<usize>,
72    pub inserted_value_index: Cell<usize>,
73    pub buffer: RefCell<Vec<u8>>,
74    pub inserted_values: RefCell<&'a [&'a ValueContainer]>,
75    /// this flag is set to true if any non-static value is encountered
76    pub has_non_static_value: RefCell<bool>,
77
78    /// Set to true if no further source text is expected to be compiled.
79    /// Example: for a REPL, this is set to false
80    pub is_end_of_source_text: bool,
81
82    // mapping for temporary scope slot resolution
83    slot_indices: RefCell<HashMap<VirtualSlot, Vec<u32>>>,
84}
85
86impl<'a> CompilationContext<'a> {
87    const MAX_INT_32: i64 = 2_147_483_647;
88    const MIN_INT_32: i64 = -2_147_483_648;
89
90    const MAX_INT_8: i64 = 127;
91    const MIN_INT_8: i64 = -128;
92
93    const MAX_INT_16: i64 = 32_767;
94    const MIN_INT_16: i64 = -32_768;
95
96    const MAX_UINT_16: i64 = 65_535;
97
98    const INT_8_BYTES: u8 = 1;
99    const INT_16_BYTES: u8 = 2;
100    const INT_32_BYTES: u8 = 4;
101    const INT_64_BYTES: u8 = 8;
102    const INT_128_BYTES: u8 = 16;
103
104    const FLOAT_32_BYTES: u8 = 4;
105    const FLOAT_64_BYTES: u8 = 8;
106
107    pub fn new(
108        buffer: RefCell<Vec<u8>>,
109        inserted_values: &'a [&'a ValueContainer],
110        is_end_of_source_text: bool,
111    ) -> Self {
112        CompilationContext {
113            index: Cell::new(0),
114            inserted_value_index: Cell::new(0),
115            buffer,
116            inserted_values: RefCell::new(inserted_values),
117            has_non_static_value: RefCell::new(false),
118            slot_indices: RefCell::new(HashMap::new()),
119            is_end_of_source_text,
120        }
121    }
122
123    pub fn external_slots(&self) -> Vec<VirtualSlot> {
124        self.slot_indices
125            .borrow()
126            .iter()
127            .filter(|(slot, _)| slot.is_external())
128            .sorted_by(|a, b| a.0.virtual_address.cmp(&b.0.virtual_address))
129            .map(|(slot, _)| *slot)
130            .collect()
131    }
132
133    /// Gets all slots for either local or external slots depending on the value of external
134    pub fn get_slot_byte_indices(
135        &self,
136        match_externals: bool,
137    ) -> Vec<Vec<u32>> {
138        self.slot_indices
139            .borrow()
140            .iter()
141            .filter(|(slot, _)| slot.is_external() == match_externals)
142            .sorted_by(|a, b| a.0.virtual_address.cmp(&b.0.virtual_address))
143            .map(|(_, indices)| indices.clone())
144            .collect()
145    }
146
147    pub fn remap_virtual_slots(&self) {
148        let mut slot_address = 0;
149
150        // parent slots
151        for byte_indices in self.get_slot_byte_indices(true) {
152            for byte_index in byte_indices {
153                self.set_u32_at_index(slot_address, byte_index as usize);
154            }
155            slot_address += 1;
156        }
157
158        // local slots
159        for byte_indices in self.get_slot_byte_indices(false) {
160            for byte_index in byte_indices {
161                self.set_u32_at_index(slot_address, byte_index as usize);
162            }
163            slot_address += 1;
164        }
165    }
166
167    // This method writes a placeholder value for the slot
168    // since the slot address is not known yet and just temporary.
169    pub fn insert_virtual_slot_address(&self, virtual_slot: VirtualSlot) {
170        let mut slot_indices = self.slot_indices.borrow_mut();
171        if let Some(indices) = slot_indices.get_mut(&virtual_slot) {
172            indices.push(self.index.get() as u32);
173        } else {
174            slot_indices.insert(virtual_slot, vec![self.index.get() as u32]);
175        }
176        self.append_u32(0); // placeholder for the slot address
177    }
178
179    pub fn insert_value_container(&self, value_container: &ValueContainer) {
180        self.mark_has_non_static_value();
181        match value_container {
182            ValueContainer::Value(value) => self.insert_value(value),
183            ValueContainer::Reference(reference) => {
184                // TODO #160: in this case, the ref might also be inserted by pointer id, depending on the compiler settings
185                // add CREATE_REF/CREATE_REF_MUT instruction
186                if reference.mutability() == ReferenceMutability::Mutable {
187                    self.append_instruction_code(
188                        InstructionCode::CREATE_REF_MUT,
189                    );
190                } else {
191                    self.append_instruction_code(InstructionCode::CREATE_REF);
192                }
193                // insert pointer id + value or only id
194                // add pointer to memory if not there yet
195                self.insert_value(&reference.collapse_to_value().borrow())
196            }
197        }
198    }
199
200    pub fn insert_value(&self, value: &Value) {
201        match &value.inner {
202            CoreValue::Type(ty) => {
203                todo!("#439 Type value not supported in CompilationContext");
204            }
205            CoreValue::Integer(integer) => {
206                let integer = integer.to_smallest_fitting();
207                self.insert_encoded_integer(&integer);
208            }
209            CoreValue::TypedInteger(integer) => {
210                self.insert_typed_integer(integer);
211            }
212
213            CoreValue::Endpoint(endpoint) => self.insert_endpoint(endpoint),
214            CoreValue::Decimal(decimal) => self.insert_decimal(decimal),
215            CoreValue::TypedDecimal(val) => self.insert_typed_decimal(val),
216            CoreValue::Boolean(val) => self.insert_boolean(val.0),
217            CoreValue::Null => {
218                self.append_instruction_code(InstructionCode::NULL)
219            }
220            CoreValue::Text(val) => {
221                self.insert_text(&val.0.clone());
222            }
223            CoreValue::List(val) => {
224                self.append_instruction_code(InstructionCode::LIST_START);
225                for item in val {
226                    self.insert_value_container(item);
227                }
228                self.append_instruction_code(InstructionCode::SCOPE_END);
229            }
230            CoreValue::Map(val) => {
231                self.append_instruction_code(InstructionCode::MAP_START);
232                for (key, value) in val {
233                    self.insert_key_value_pair(
234                        &ValueContainer::from(key),
235                        value,
236                    );
237                }
238                self.append_instruction_code(InstructionCode::SCOPE_END);
239            }
240        }
241    }
242
243    // value insert functions
244    pub fn insert_boolean(&self, boolean: bool) {
245        if boolean {
246            self.append_instruction_code(InstructionCode::TRUE);
247        } else {
248            self.append_instruction_code(InstructionCode::FALSE);
249        }
250    }
251
252    pub fn insert_text(&self, string: &str) {
253        let bytes = string.as_bytes();
254        let len = bytes.len();
255
256        if len < 256 {
257            self.append_instruction_code(InstructionCode::SHORT_TEXT);
258            self.append_u8(len as u8);
259        } else {
260            self.append_instruction_code(InstructionCode::TEXT);
261            self.append_u32(len as u32);
262        }
263
264        self.append_buffer(bytes);
265    }
266
267    pub fn insert_key_value_pair(
268        &self,
269        key: &ValueContainer,
270        value: &ValueContainer,
271    ) {
272        // insert key
273        match key {
274            // if text, insert_key_string, else dynamic
275            ValueContainer::Value(Value {
276                inner: CoreValue::Text(text),
277                ..
278            }) => {
279                self.insert_key_string(&text.0);
280            }
281            _ => {
282                self.append_instruction_code(
283                    InstructionCode::KEY_VALUE_DYNAMIC,
284                );
285                self.insert_value_container(key);
286            }
287        }
288        // insert value
289        self.insert_value_container(value);
290    }
291
292    pub fn insert_struct_key_value_pair(
293        &self,
294        key: String,
295        value: &ValueContainer,
296    ) {
297        // insert key
298        self.insert_key_string(&key);
299        // insert value
300        self.insert_value_container(value);
301    }
302
303    pub fn insert_key_string(&self, key_string: &str) {
304        let bytes = key_string.as_bytes();
305        let len = bytes.len();
306
307        if len < 256 {
308            self.append_instruction_code(InstructionCode::KEY_VALUE_SHORT_TEXT);
309            self.append_u8(len as u8);
310            self.append_buffer(bytes);
311        } else {
312            self.append_instruction_code(InstructionCode::KEY_VALUE_DYNAMIC);
313            self.insert_text(key_string);
314        }
315    }
316
317    pub fn insert_encoded_decimal(&self, decimal: &TypedDecimal) {
318        fn insert_f32_or_f64(
319            scope: &CompilationContext,
320            decimal: &TypedDecimal,
321        ) {
322            match decimal {
323                TypedDecimal::F32(val) => {
324                    scope.insert_float32(val.into_inner());
325                }
326                TypedDecimal::F64(val) => {
327                    scope.insert_float64(val.into_inner());
328                }
329                TypedDecimal::Decimal(val) => {
330                    scope.insert_decimal(val);
331                }
332            }
333        }
334
335        match decimal.as_integer() {
336            Some(int) => {
337                let smallest = smallest_fitting_signed(int as i128);
338                match smallest {
339                    TypedInteger::I8(val) => {
340                        self.insert_float_as_i16(val as i16);
341                    }
342                    TypedInteger::I16(val) => {
343                        self.insert_float_as_i16(val);
344                    }
345                    TypedInteger::I32(val) => {
346                        self.insert_float_as_i32(val);
347                    }
348                    _ => insert_f32_or_f64(self, decimal),
349                }
350            }
351            None => insert_f32_or_f64(self, decimal),
352        }
353    }
354
355    pub fn insert_typed_decimal(&self, decimal: &TypedDecimal) {
356        self.append_instruction_code(InstructionCode::APPLY_SINGLE);
357        self.insert_get_ref(PointerAddress::from(CoreLibPointerId::from(
358            decimal,
359        )));
360        self.insert_encoded_decimal(decimal);
361    }
362
363    pub fn insert_float32(&self, float32: f32) {
364        self.append_instruction_code(InstructionCode::DECIMAL_F32);
365        self.append_f32(float32);
366    }
367    pub fn insert_float64(&self, float64: f64) {
368        self.append_instruction_code(InstructionCode::DECIMAL_F64);
369        self.append_f64(float64);
370    }
371
372    pub fn insert_endpoint(&self, endpoint: &Endpoint) {
373        self.append_instruction_code(InstructionCode::ENDPOINT);
374        self.append_buffer(&endpoint.to_binary());
375    }
376
377    // TODO #440: we should probably not compile unions with nested binary operations, but rather have a separate instruction for n-ary unions
378    // pub fn insert_union(&self, union: &Union) {
379    //     // insert values as nested UNION binary operations
380
381    //     self.append_binary_code(InstructionCode::UNION);
382    //     // insert first value
383    //     self.insert_value_container(&union.options[0]);
384
385    //     // insert rest of values recursively
386    //     self.insert_union_options(union.options[1..].to_vec());
387    // }
388
389    fn insert_union_options(&self, options: Vec<ValueContainer>) {
390        // directly insert value if only one option left
391        if options.len() == 1 {
392            self.insert_value_container(&options[0]);
393        } else {
394            self.append_instruction_code(InstructionCode::SCOPE_START);
395            self.append_instruction_code(InstructionCode::UNION);
396            // insert first value
397            self.insert_value_container(&options[0]);
398            // insert rest of values recursively
399            self.insert_union_options(options[1..].to_vec());
400            self.append_instruction_code(InstructionCode::SCOPE_END);
401        }
402    }
403
404    pub fn insert_big_integer(&self, integer: &Integer) {
405        // use BinWrite to write the integer to the buffer
406        // big_integer binrw write into buffer
407        let mut buffer = self.buffer.borrow_mut();
408        let original_length = buffer.len();
409        let mut buffer_writer = Cursor::new(&mut *buffer);
410        // set writer position to end
411        buffer_writer.set_position(original_length as u64);
412        integer
413            .write_le(&mut buffer_writer)
414            .expect("Failed to write big integer");
415        // get byte count of written data
416        let byte_count = buffer_writer.position() as usize;
417        // update index
418        self.index.update(|x| x + byte_count - original_length);
419    }
420
421    /// Inserts an encoded integer without explicit type casts
422    pub fn insert_encoded_integer(&self, integer: &TypedInteger) {
423        match integer {
424            TypedInteger::I8(val) => {
425                self.insert_i8(*val);
426            }
427            TypedInteger::I16(val) => {
428                self.insert_i16(*val);
429            }
430            TypedInteger::I32(val) => {
431                self.insert_i32(*val);
432            }
433            TypedInteger::I64(val) => {
434                self.insert_i64(*val);
435            }
436            TypedInteger::I128(val) => {
437                self.insert_i128(*val);
438            }
439            TypedInteger::U8(val) => {
440                self.insert_u8(*val);
441            }
442            TypedInteger::U16(val) => {
443                self.insert_u16(*val);
444            }
445            TypedInteger::U32(val) => {
446                self.insert_u32(*val);
447            }
448            TypedInteger::U64(val) => {
449                self.insert_u64(*val);
450            }
451            TypedInteger::U128(val) => {
452                self.insert_u128(*val);
453            }
454            TypedInteger::Big(val) => {
455                self.append_instruction_code(InstructionCode::INT_BIG);
456                self.insert_big_integer(val);
457            }
458        }
459    }
460
461    /// Inserts a typed integer with explicit type casts
462    pub fn insert_typed_integer(&self, integer: &TypedInteger) {
463        self.append_instruction_code(InstructionCode::APPLY_SINGLE);
464        self.insert_get_ref(PointerAddress::from(CoreLibPointerId::from(
465            integer,
466        )));
467        self.insert_encoded_integer(&integer.to_smallest_fitting());
468    }
469
470    pub fn insert_decimal(&self, decimal: &Decimal) {
471        self.append_instruction_code(InstructionCode::DECIMAL_BIG);
472        // big_decimal binrw write into buffer
473        let mut buffer = self.buffer.borrow_mut();
474        let original_length = buffer.len();
475        let mut buffer_writer = Cursor::new(&mut *buffer);
476        // set writer position to end
477        buffer_writer.set_position(original_length as u64);
478        decimal
479            .write_le(&mut buffer_writer)
480            .expect("Failed to write big decimal");
481        // get byte count of written data
482        let byte_count = buffer_writer.position() as usize;
483        // update index
484        self.index.update(|x| x + byte_count - original_length);
485    }
486
487    pub fn insert_float_as_i16(&self, int: i16) {
488        self.append_instruction_code(InstructionCode::DECIMAL_AS_INT_16);
489        self.append_i16(int);
490    }
491    pub fn insert_float_as_i32(&self, int: i32) {
492        self.append_instruction_code(InstructionCode::DECIMAL_AS_INT_32);
493        self.append_i32(int);
494    }
495    pub fn insert_i8(&self, int8: i8) {
496        self.append_instruction_code(InstructionCode::INT_8);
497        self.append_i8(int8);
498    }
499
500    pub fn insert_i16(&self, int16: i16) {
501        self.append_instruction_code(InstructionCode::INT_16);
502        self.append_i16(int16);
503    }
504    pub fn insert_i32(&self, int32: i32) {
505        self.append_instruction_code(InstructionCode::INT_32);
506        self.append_i32(int32);
507    }
508    pub fn insert_i64(&self, int64: i64) {
509        self.append_instruction_code(InstructionCode::INT_64);
510        self.append_i64(int64);
511    }
512    pub fn insert_i128(&self, int128: i128) {
513        self.append_instruction_code(InstructionCode::INT_128);
514        self.append_i128(int128);
515    }
516    pub fn insert_u8(&self, uint8: u8) {
517        self.append_instruction_code(InstructionCode::INT_16);
518        self.append_i16(uint8 as i16);
519    }
520    pub fn insert_u16(&self, uint16: u16) {
521        self.append_instruction_code(InstructionCode::INT_32);
522        self.append_i32(uint16 as i32);
523    }
524    pub fn insert_u32(&self, uint32: u32) {
525        self.append_instruction_code(InstructionCode::INT_64);
526        self.append_i64(uint32 as i64);
527    }
528    pub fn insert_u64(&self, uint64: u64) {
529        self.append_instruction_code(InstructionCode::INT_128);
530        self.append_i128(uint64 as i128);
531    }
532    pub fn insert_u128(&self, uint128: u128) {
533        self.append_instruction_code(InstructionCode::UINT_128);
534        self.append_i128(uint128 as i128);
535    }
536    pub fn append_u8(&self, u8: u8) {
537        append_u8(self.buffer.borrow_mut().as_mut(), u8);
538        self.index
539            .update(|x| x + CompilationContext::INT_8_BYTES as usize);
540    }
541    pub fn append_u32(&self, u32: u32) {
542        append_u32(self.buffer.borrow_mut().as_mut(), u32);
543        self.index
544            .update(|x| x + CompilationContext::INT_32_BYTES as usize);
545    }
546    pub fn set_u32_at_index(&self, u32: u32, index: usize) {
547        let mut buffer = self.buffer.borrow_mut();
548        buffer[index..index + CompilationContext::INT_32_BYTES as usize]
549            .copy_from_slice(&u32.to_le_bytes());
550    }
551    pub fn append_i8(&self, i8: i8) {
552        append_i8(self.buffer.borrow_mut().as_mut(), i8);
553        self.index
554            .update(|x| x + CompilationContext::INT_8_BYTES as usize);
555    }
556    pub fn append_i16(&self, i16: i16) {
557        append_i16(self.buffer.borrow_mut().as_mut(), i16);
558        self.index
559            .update(|x| x + CompilationContext::INT_16_BYTES as usize);
560    }
561    pub fn append_i32(&self, i32: i32) {
562        append_i32(self.buffer.borrow_mut().as_mut(), i32);
563        self.index
564            .update(|x| x + CompilationContext::INT_32_BYTES as usize);
565    }
566    pub fn append_i64(&self, i64: i64) {
567        append_i64(self.buffer.borrow_mut().as_mut(), i64);
568        self.index
569            .update(|x| x + CompilationContext::INT_64_BYTES as usize);
570    }
571    pub fn append_i128(&self, i128: i128) {
572        append_i128(self.buffer.borrow_mut().as_mut(), i128);
573        self.index
574            .update(|x| x + CompilationContext::INT_128_BYTES as usize);
575    }
576
577    pub fn append_u128(&self, u128: u128) {
578        append_u128(self.buffer.borrow_mut().as_mut(), u128);
579        self.index
580            .update(|x| x + CompilationContext::INT_128_BYTES as usize);
581    }
582
583    pub fn append_f32(&self, f32: f32) {
584        append_f32(self.buffer.borrow_mut().as_mut(), f32);
585        self.index
586            .update(|x| x + CompilationContext::FLOAT_32_BYTES as usize);
587    }
588    pub fn append_f64(&self, f64: f64) {
589        append_f64(self.buffer.borrow_mut().as_mut(), f64);
590        self.index
591            .update(|x| x + CompilationContext::FLOAT_64_BYTES as usize);
592    }
593    pub fn append_string_utf8(&self, string: &str) {
594        let bytes = string.as_bytes();
595        (*self.buffer.borrow_mut()).extend_from_slice(bytes);
596        self.index.update(|x| x + bytes.len());
597    }
598    pub fn append_buffer(&self, buffer: &[u8]) {
599        (*self.buffer.borrow_mut()).extend_from_slice(buffer);
600        self.index.update(|x| x + buffer.len());
601    }
602
603    pub fn insert_get_ref(&self, address: PointerAddress) {
604        match address {
605            PointerAddress::Internal(id) => {
606                self.append_instruction_code(InstructionCode::GET_INTERNAL_REF);
607                self.append_buffer(&id);
608            }
609            PointerAddress::Local(id) => {
610                self.append_instruction_code(InstructionCode::GET_LOCAL_REF);
611                self.append_buffer(&id);
612            }
613            PointerAddress::Remote(id) => {
614                self.append_instruction_code(InstructionCode::GET_REF);
615                self.append_buffer(&id);
616            }
617        }
618    }
619
620    pub fn mark_has_non_static_value(&self) {
621        self.has_non_static_value.replace(true);
622    }
623
624    pub fn append_instruction_code(&self, code: InstructionCode) {
625        self.append_u8(code as u8);
626    }
627}