duskphantom_middle/ir/
value_type.rs

1// Copyright 2024 Duskphantom Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17use anyhow::{anyhow, Context, Result};
18
19use crate::context;
20
21use super::Constant;
22
23/// Represent the type of a value.
24#[derive(Clone, PartialEq, Eq, Hash)]
25pub enum ValueType {
26    Void,
27    SignedChar,
28    Int,
29    Float,
30    Bool,
31    Array(Box<ValueType>, usize),
32    Pointer(Box<ValueType>),
33}
34
35impl std::fmt::Display for ValueType {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            ValueType::Void => write!(f, "void"),
39            ValueType::SignedChar => write!(f, "i8"),
40            ValueType::Int => write!(f, "i32"),
41            ValueType::Float => write!(f, "float"),
42            ValueType::Bool => write!(f, "i1"),
43            ValueType::Array(one_type, size) => write!(f, "[{} x {}]", size, one_type),
44            ValueType::Pointer(pointer) => write!(f, "{}*", pointer),
45        }
46    }
47}
48
49impl std::fmt::Debug for ValueType {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(f, "{}", self)
52    }
53}
54
55impl ValueType {
56    pub fn is_basic_type(&self) -> bool {
57        matches!(
58            self,
59            ValueType::Void | ValueType::Int | ValueType::Float | ValueType::Bool
60        )
61    }
62
63    pub fn is_num(&self) -> bool {
64        matches!(self, ValueType::Bool | ValueType::Int | ValueType::Float)
65    }
66
67    pub fn is_pointer(&self) -> bool {
68        matches!(self, ValueType::Pointer(_))
69    }
70
71    pub fn is_array(&self) -> bool {
72        matches!(self, ValueType::Array(_, _))
73    }
74
75    /// Get size of this value type.
76    pub fn size(&self) -> usize {
77        match self {
78            ValueType::Array(element_type, dim) => *dim * element_type.size(),
79            _ => 1,
80        }
81    }
82
83    /// Get subtype of the value type.
84    /// Subtype is the type of the element in the array or the type of the pointer.
85    pub fn get_sub_type(&self) -> Option<&ValueType> {
86        match self {
87            ValueType::Array(sub_type, _) => Some(sub_type.as_ref()),
88            ValueType::Pointer(sub_type) => Some(sub_type.as_ref()),
89            _ => None,
90        }
91    }
92
93    /// Get base type of the value type.
94    /// Base type is i32 / f32 for array.
95    pub fn get_base_type(&self) -> ValueType {
96        match self {
97            ValueType::Array(sub_type, _) => sub_type.get_base_type(),
98            ValueType::Pointer(sub_type) => sub_type.get_base_type(),
99            _ => self.clone(),
100        }
101    }
102
103    /// Get default initializer of this type.
104    pub fn default_initializer(&self) -> Result<Constant> {
105        match self {
106            ValueType::Void => {
107                Err(anyhow!("Cannot convert void type to constant")).with_context(|| context!())
108            }
109            ValueType::Int => Ok(Constant::Int(0)),
110            ValueType::SignedChar => Ok(Constant::SignedChar(0)),
111            ValueType::Float => Ok(Constant::Float(0.0)),
112            ValueType::Bool => Ok(Constant::Bool(false)),
113            ValueType::Pointer(_) => {
114                Err(anyhow!("Cannot convert pointer type to constant")).with_context(|| context!())
115            }
116            ValueType::Array(ty, _) => Ok(Constant::Zero(*ty.clone())),
117        }
118    }
119
120    /// Convert a numeric value type to its precision level.
121    /// Higher is more precise.
122    pub fn to_precision_level(&self) -> i32 {
123        match self {
124            // All boolean should be converted to int when applying `+` and etc.
125            ValueType::Bool => 1,
126            ValueType::Int => 1,
127            ValueType::Float => 2,
128            _ => 0,
129        }
130    }
131
132    /// Convert a precision level to a value type.
133    pub fn from_precision_level(level: i32) -> Self {
134        match level {
135            1 => ValueType::Int,
136            2 => ValueType::Float,
137            _ => ValueType::Void,
138        }
139    }
140
141    /// Max this type with another type, return more precise one.
142    /// If types are not number, return void.
143    pub fn max_with(&self, b: &Self) -> Self {
144        if self.is_num() && b.is_num() {
145            let a_lv = self.to_precision_level();
146            let b_lv = b.to_precision_level();
147            let max_lv = if a_lv > b_lv { a_lv } else { b_lv };
148            ValueType::from_precision_level(max_lv)
149        } else {
150            ValueType::Void
151        }
152    }
153}