datex_core/compiler/
context.rs

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