datex_core/decompiler/
ast_from_value_container.rs

1use crate::ast::expressions::{CreateRef, DatexExpressionData, List, Map};
2use crate::ast::spanned::Spanned;
3use crate::ast::type_expressions::{
4    Intersection, TypeExpression, TypeExpressionData, Union,
5};
6use crate::types::definition::TypeDefinition;
7use crate::types::structural_type_definition::StructuralTypeDefinition;
8use crate::values::core_value::CoreValue;
9use crate::values::core_values::r#type::Type;
10use crate::values::value::Value;
11use crate::values::value_container::ValueContainer;
12use datex_core::ast::expressions::CallableDeclaration;
13use datex_core::libs::core::CoreLibPointerId;
14
15impl From<&ValueContainer> for DatexExpressionData {
16    /// Converts a ValueContainer into a DatexExpression AST.
17    /// This AST can then be further processed or decompiled into human-readable DATEX code.
18    fn from(value: &ValueContainer) -> Self {
19        match value {
20            ValueContainer::Value(value) => value_to_datex_expression(value),
21            ValueContainer::Reference(reference) => {
22                DatexExpressionData::CreateRef(CreateRef {
23                    mutability: reference.mutability(),
24                    expression: Box::new(
25                        DatexExpressionData::from(&reference.value_container())
26                            .with_default_span(),
27                    ),
28                })
29            }
30        }
31    }
32}
33
34fn value_to_datex_expression(value: &Value) -> DatexExpressionData {
35    match &value.inner {
36        CoreValue::Integer(integer) => {
37            DatexExpressionData::Integer(integer.clone())
38        }
39        CoreValue::TypedInteger(typed_integer) => {
40            DatexExpressionData::TypedInteger(typed_integer.clone())
41        }
42        CoreValue::Decimal(decimal) => {
43            DatexExpressionData::Decimal(decimal.clone())
44        }
45        CoreValue::TypedDecimal(typed_decimal) => {
46            DatexExpressionData::TypedDecimal(typed_decimal.clone())
47        }
48        CoreValue::Boolean(boolean) => DatexExpressionData::Boolean(boolean.0),
49        CoreValue::Text(text) => DatexExpressionData::Text(text.0.clone()),
50        CoreValue::Endpoint(endpoint) => {
51            DatexExpressionData::Endpoint(endpoint.clone())
52        }
53        CoreValue::Null => DatexExpressionData::Null,
54        CoreValue::List(list) => DatexExpressionData::List(List::new(
55            list.into_iter()
56                .map(DatexExpressionData::from)
57                .map(|data| data.with_default_span())
58                .collect(),
59        )),
60        CoreValue::Map(map) => DatexExpressionData::Map(Map::new(
61            map.into_iter()
62                .map(|(key, value)| {
63                    (
64                        DatexExpressionData::from(&ValueContainer::from(key))
65                            .with_default_span(),
66                        DatexExpressionData::from(value).with_default_span(),
67                    )
68                })
69                .collect(),
70        )),
71        CoreValue::Type(type_value) => DatexExpressionData::TypeExpression(
72            type_to_type_expression(type_value),
73        ),
74        CoreValue::Callable(callable) => {
75            DatexExpressionData::CallableDeclaration(CallableDeclaration {
76                name: callable.name.clone(),
77                kind: callable.signature.kind.clone(),
78                parameters: callable
79                    .signature
80                    .parameter_types
81                    .iter()
82                    .map(|(maybe_name, ty)| {
83                        (
84                            maybe_name.clone().unwrap_or("_".to_string()),
85                            type_to_type_expression(ty),
86                        )
87                    })
88                    .collect(),
89                rest_parameter: callable
90                    .signature
91                    .rest_parameter_type
92                    .as_ref()
93                    .map(|(maybe_name, ty)| {
94                        (
95                            maybe_name.clone().unwrap_or("_".to_string()),
96                            type_to_type_expression(ty),
97                        )
98                    }),
99                return_type: callable
100                    .signature
101                    .return_type
102                    .as_ref()
103                    .map(|ty| type_to_type_expression(ty)),
104                yeet_type: callable
105                    .signature
106                    .yeet_type
107                    .as_ref()
108                    .map(|ty| type_to_type_expression(ty)),
109                body: Box::new(
110                    DatexExpressionData::NativeImplementationIndicator
111                        .with_default_span(),
112                ),
113            })
114        }
115    }
116}
117
118fn type_to_type_expression(type_value: &Type) -> TypeExpression {
119    match &type_value.type_definition {
120        TypeDefinition::Structural(struct_type) => match struct_type {
121            StructuralTypeDefinition::Integer(integer) => {
122                TypeExpressionData::Integer(integer.clone()).with_default_span()
123            }
124            StructuralTypeDefinition::Text(text) => {
125                TypeExpressionData::Text(text.0.clone()).with_default_span()
126            }
127            StructuralTypeDefinition::Boolean(boolean) => {
128                TypeExpressionData::Boolean(boolean.0).with_default_span()
129            }
130            StructuralTypeDefinition::Decimal(decimal) => {
131                TypeExpressionData::Decimal(decimal.clone()).with_default_span()
132            }
133            StructuralTypeDefinition::TypedInteger(typed_integer) => {
134                TypeExpressionData::TypedInteger(typed_integer.clone())
135                    .with_default_span()
136            }
137            StructuralTypeDefinition::TypedDecimal(typed_decimal) => {
138                TypeExpressionData::TypedDecimal(typed_decimal.clone())
139                    .with_default_span()
140            }
141            StructuralTypeDefinition::Endpoint(endpoint) => {
142                TypeExpressionData::Endpoint(endpoint.clone())
143                    .with_default_span()
144            }
145            StructuralTypeDefinition::Null => {
146                TypeExpressionData::Null.with_default_span()
147            }
148            _ => TypeExpressionData::Text(format!(
149                "[[STRUCTURAL TYPE {:?}]]",
150                struct_type
151            ))
152            .with_default_span(),
153        },
154        TypeDefinition::Union(union_types) => TypeExpressionData::Union(Union(
155            union_types
156                .iter()
157                .map(|t| type_to_type_expression(t))
158                .collect::<Vec<TypeExpression>>(),
159        ))
160        .with_default_span(),
161        TypeDefinition::Intersection(intersection_types) => {
162            TypeExpressionData::Intersection(Intersection(
163                intersection_types
164                    .iter()
165                    .map(|t| type_to_type_expression(t))
166                    .collect::<Vec<TypeExpression>>(),
167            ))
168            .with_default_span()
169        }
170        TypeDefinition::Unit => TypeExpressionData::Unit.with_default_span(),
171        TypeDefinition::Reference(type_reference) => {
172            // try to resolve to core lib value
173            if let Some(address) = &type_reference.borrow().pointer_address {
174                if let Ok(core_lib_type) = CoreLibPointerId::try_from(address) {
175                    TypeExpressionData::Identifier(core_lib_type.to_string())
176                        .with_default_span()
177                } else {
178                    todo!(
179                        "#651 Handle non-core-lib type references in decompiler"
180                    );
181                }
182            } else {
183                panic!("Unresolved type reference in decompiler"); // TODO #652: how to handle properly?
184            }
185        }
186        _ => TypeExpressionData::Text(format!(
187            "[[TYPE {:?}]]",
188            type_value.type_definition
189        ))
190        .with_default_span(),
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use crate::ast::expressions::{DatexExpressionData, List};
197    use crate::ast::spanned::Spanned;
198    use crate::values::core_values::decimal::Decimal;
199    use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
200    use crate::values::core_values::integer::Integer;
201    use crate::values::core_values::integer::typed_integer::TypedInteger;
202    use crate::values::value::Value;
203    use crate::values::value_container::ValueContainer;
204
205    #[test]
206    fn test_integer_to_ast() {
207        let value = ValueContainer::from(Integer::from(42));
208        let ast = DatexExpressionData::from(&value);
209        assert_eq!(ast, DatexExpressionData::Integer(Integer::from(42)));
210    }
211
212    #[test]
213    fn test_typed_integer_to_ast() {
214        let value = ValueContainer::from(TypedInteger::from(42i8));
215        let ast = DatexExpressionData::from(&value);
216        assert_eq!(
217            ast,
218            DatexExpressionData::TypedInteger(TypedInteger::from(42i8))
219        );
220    }
221
222    #[test]
223    fn test_decimal_to_ast() {
224        let value = ValueContainer::from(Decimal::from(1.23));
225        let ast = DatexExpressionData::from(&value);
226        assert_eq!(ast, DatexExpressionData::Decimal(Decimal::from(1.23)));
227    }
228
229    #[test]
230    fn test_typed_decimal_to_ast() {
231        let value = ValueContainer::from(TypedDecimal::from(2.71f32));
232        let ast = DatexExpressionData::from(&value);
233        assert_eq!(
234            ast,
235            DatexExpressionData::TypedDecimal(TypedDecimal::from(2.71f32))
236        );
237    }
238
239    #[test]
240    fn test_boolean_to_ast() {
241        let value = ValueContainer::from(true);
242        let ast = DatexExpressionData::from(&value);
243        assert_eq!(ast, DatexExpressionData::Boolean(true));
244    }
245
246    #[test]
247    fn test_text_to_ast() {
248        let value = ValueContainer::from("Hello, World!".to_string());
249        let ast = DatexExpressionData::from(&value);
250        assert_eq!(ast, DatexExpressionData::Text("Hello, World!".to_string()));
251    }
252
253    #[test]
254    fn test_null_to_ast() {
255        let value = ValueContainer::Value(Value::null());
256        let ast = DatexExpressionData::from(&value);
257        assert_eq!(ast, DatexExpressionData::Null);
258    }
259
260    #[test]
261    fn test_list_to_ast() {
262        let value = ValueContainer::from(vec![
263            Integer::from(1),
264            Integer::from(2),
265            Integer::from(3),
266        ]);
267        let ast = DatexExpressionData::from(&value);
268        assert_eq!(
269            ast,
270            DatexExpressionData::List(List::new(vec![
271                DatexExpressionData::Integer(Integer::from(1))
272                    .with_default_span(),
273                DatexExpressionData::Integer(Integer::from(2))
274                    .with_default_span(),
275                DatexExpressionData::Integer(Integer::from(3))
276                    .with_default_span(),
277            ]))
278        );
279    }
280}