|
| 1 | +#include <libasr/casting_utils.h> |
| 2 | +#include <libasr/asr_utils.h> |
| 3 | + |
| 4 | +#include <map> |
| 5 | + |
| 6 | + |
| 7 | +namespace LCompilers::CastingUtil { |
| 8 | + |
| 9 | + // Data structure which contains priorities for |
| 10 | + // intrinsic types defined in ASR |
| 11 | + const std::map<ASR::ttypeType, int>& type2weight = { |
| 12 | + {ASR::ttypeType::Complex, 4}, |
| 13 | + {ASR::ttypeType::Real, 3}, |
| 14 | + {ASR::ttypeType::Integer, 2}, |
| 15 | + {ASR::ttypeType::Logical, 1} |
| 16 | + }; |
| 17 | + |
| 18 | + // Data structure which contains casting rules for non-equal |
| 19 | + // intrinsic types defined in ASR |
| 20 | + const std::map<std::pair<ASR::ttypeType, ASR::ttypeType>, ASR::cast_kindType>& type_rules = { |
| 21 | + {std::make_pair(ASR::ttypeType::Complex, ASR::ttypeType::Real), ASR::cast_kindType::ComplexToReal}, |
| 22 | + {std::make_pair(ASR::ttypeType::Complex, ASR::ttypeType::Logical), ASR::cast_kindType::ComplexToLogical}, |
| 23 | + {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Complex), ASR::cast_kindType::RealToComplex}, |
| 24 | + {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Integer), ASR::cast_kindType::RealToInteger}, |
| 25 | + {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Logical), ASR::cast_kindType::RealToLogical}, |
| 26 | + {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::UnsignedInteger), ASR::cast_kindType::RealToUnsignedInteger}, |
| 27 | + {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Complex), ASR::cast_kindType::IntegerToComplex}, |
| 28 | + {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Real), ASR::cast_kindType::IntegerToReal}, |
| 29 | + {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Logical), ASR::cast_kindType::IntegerToLogical}, |
| 30 | + {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::UnsignedInteger), ASR::cast_kindType::IntegerToUnsignedInteger}, |
| 31 | + {std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Real), ASR::cast_kindType::LogicalToReal}, |
| 32 | + {std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Integer), ASR::cast_kindType::LogicalToInteger}, |
| 33 | + {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Integer), ASR::cast_kindType::UnsignedIntegerToInteger}, |
| 34 | + {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Real), ASR::cast_kindType::UnsignedIntegerToReal}, |
| 35 | + {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::SymbolicExpression), ASR::cast_kindType::IntegerToSymbolicExpression} |
| 36 | + }; |
| 37 | + |
| 38 | + // Data structure which contains casting rules for equal intrinsic |
| 39 | + // types but with different kinds. |
| 40 | + const std::map<ASR::ttypeType, ASR::cast_kindType>& kind_rules = { |
| 41 | + {ASR::ttypeType::Complex, ASR::cast_kindType::ComplexToComplex}, |
| 42 | + {ASR::ttypeType::Real, ASR::cast_kindType::RealToReal}, |
| 43 | + {ASR::ttypeType::Integer, ASR::cast_kindType::IntegerToInteger}, |
| 44 | + {ASR::ttypeType::UnsignedInteger, ASR::cast_kindType::UnsignedIntegerToUnsignedInteger} |
| 45 | + }; |
| 46 | + |
| 47 | + int get_type_priority(ASR::ttypeType type) { |
| 48 | + if( type2weight.find(type) == type2weight.end() ) { |
| 49 | + return -1; |
| 50 | + } |
| 51 | + |
| 52 | + return type2weight.at(type); |
| 53 | + } |
| 54 | + |
| 55 | + int get_src_dest(ASR::expr_t* left_expr, ASR::expr_t* right_expr, |
| 56 | + ASR::expr_t*& src_expr, ASR::expr_t*& dest_expr, |
| 57 | + ASR::ttype_t*& src_type, ASR::ttype_t*& dest_type, |
| 58 | + bool is_assign) { |
| 59 | + ASR::ttype_t* left_type = ASRUtils::expr_type(left_expr); |
| 60 | + ASR::ttype_t* right_type = ASRUtils::expr_type(right_expr); |
| 61 | + if( ASR::is_a<ASR::Const_t>(*left_type) ) { |
| 62 | + left_type = ASRUtils::get_contained_type(left_type); |
| 63 | + } |
| 64 | + if( ASR::is_a<ASR::Const_t>(*right_type) ) { |
| 65 | + right_type = ASRUtils::get_contained_type(right_type); |
| 66 | + } |
| 67 | + left_type = ASRUtils::type_get_past_pointer(left_type); |
| 68 | + right_type = ASRUtils::type_get_past_pointer(right_type); |
| 69 | + if( ASRUtils::check_equal_type(left_type, right_type) || |
| 70 | + ASRUtils::is_character(*left_type) || ASRUtils::is_character(*right_type) ) { |
| 71 | + return 2; |
| 72 | + } |
| 73 | + if( is_assign ) { |
| 74 | + if( ASRUtils::is_real(*left_type) && ASRUtils::is_integer(*right_type)) { |
| 75 | + throw SemanticError("Assigning integer to float is not supported", |
| 76 | + right_expr->base.loc); |
| 77 | + } |
| 78 | + if ( ASRUtils::is_complex(*left_type) && !ASRUtils::is_complex(*right_type)) { |
| 79 | + throw SemanticError("Assigning non-complex to complex is not supported", |
| 80 | + right_expr->base.loc); |
| 81 | + } |
| 82 | + dest_expr = left_expr, dest_type = left_type; |
| 83 | + src_expr = right_expr, src_type = right_type; |
| 84 | + return 1; |
| 85 | + } |
| 86 | + |
| 87 | + int casted_expr_signal = 2; |
| 88 | + ASR::ttypeType left_Type = left_type->type, right_Type = right_type->type; |
| 89 | + int left_kind = ASRUtils::extract_kind_from_ttype_t(left_type); |
| 90 | + int right_kind = ASRUtils::extract_kind_from_ttype_t(right_type); |
| 91 | + int left_priority = get_type_priority(left_Type); |
| 92 | + int right_priority = get_type_priority(right_Type); |
| 93 | + if( left_priority > right_priority ) { |
| 94 | + src_expr = right_expr, src_type = right_type; |
| 95 | + dest_expr = left_expr, dest_type = left_type; |
| 96 | + casted_expr_signal = 1; |
| 97 | + } else if( left_priority < right_priority ) { |
| 98 | + src_expr = left_expr, src_type = left_type; |
| 99 | + dest_expr = right_expr, dest_type = right_type; |
| 100 | + casted_expr_signal = 0; |
| 101 | + } else { |
| 102 | + if( left_kind > right_kind ) { |
| 103 | + src_expr = right_expr, src_type = right_type; |
| 104 | + dest_expr = left_expr, dest_type = left_type; |
| 105 | + casted_expr_signal = 1; |
| 106 | + } else if( left_kind < right_kind ) { |
| 107 | + src_expr = left_expr, src_type = left_type; |
| 108 | + dest_expr = right_expr, dest_type = right_type; |
| 109 | + casted_expr_signal = 0; |
| 110 | + } else { |
| 111 | + return 2; |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + return casted_expr_signal; |
| 116 | + } |
| 117 | + |
| 118 | + ASR::expr_t* perform_casting(ASR::expr_t* expr, ASR::ttype_t* src, |
| 119 | + ASR::ttype_t* dest, Allocator& al, |
| 120 | + const Location& loc) { |
| 121 | + ASR::ttypeType src_type = src->type; |
| 122 | + ASR::ttypeType dest_type = dest->type; |
| 123 | + ASR::cast_kindType cast_kind; |
| 124 | + if( src_type == dest_type ) { |
| 125 | + if( kind_rules.find(src_type) == kind_rules.end() ) { |
| 126 | + return expr; |
| 127 | + } |
| 128 | + cast_kind = kind_rules.at(src_type); |
| 129 | + } else { |
| 130 | + std::pair<ASR::ttypeType, ASR::ttypeType> cast_key = std::make_pair(src_type, dest_type); |
| 131 | + if( type_rules.find(cast_key) == type_rules.end() ) { |
| 132 | + return expr; |
| 133 | + } |
| 134 | + cast_kind = type_rules.at(cast_key); |
| 135 | + } |
| 136 | + if( ASRUtils::check_equal_type(src, dest, true) ) { |
| 137 | + return expr; |
| 138 | + } |
| 139 | + // TODO: Fix loc |
| 140 | + return ASRUtils::EXPR(ASRUtils::make_Cast_t_value(al, loc, expr, |
| 141 | + cast_kind, dest)); |
| 142 | + } |
| 143 | +} |
0 commit comments