245 lines
8.0 KiB
Rust
245 lines
8.0 KiB
Rust
use std::fmt::Display;
|
|
|
|
use anyhow::bail;
|
|
|
|
use crate::{common::loc::LocBox, validator::predefined::get_builtin_from_name};
|
|
|
|
use super::{expr::Expr, literal::Literal, Ident, Program};
|
|
|
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
|
pub enum Type {
|
|
Ref {
|
|
inner: Box<Type>,
|
|
mutable: bool,
|
|
},
|
|
SizedArray {
|
|
inner: Box<Type>,
|
|
count: LocBox<Expr>,
|
|
},
|
|
UnsizedArray {
|
|
inner: Box<Type>,
|
|
},
|
|
Owned(Ident),
|
|
Builtin {
|
|
name: String,
|
|
size: u8,
|
|
signed: bool,
|
|
}
|
|
}
|
|
|
|
impl Type {
|
|
pub fn get_absolute_value(&self, program: &Program) -> anyhow::Result<Self> {
|
|
match self {
|
|
Self::Ref { inner, .. } => inner.get_absolute_value(program),
|
|
Self::Owned(ident) => {
|
|
if let Some(t) = get_builtin_from_name(ident.0.as_str()) {
|
|
return Ok(t)
|
|
}
|
|
if let Some(t) = program.curr_fn_args.get(ident) {
|
|
return Ok(t.inner().clone().get_absolute_value(program)?);
|
|
} else
|
|
if program.types.get(ident).is_some() ||
|
|
program.structs.get(ident).is_some() ||
|
|
program.enums.get(ident).is_some()
|
|
{
|
|
return Ok(self.clone());
|
|
}
|
|
if let Some(var) = program.get_var(ident) {
|
|
Ok(var.1.inner().typ.clone().expect("type should be computed if were already using it").inner().clone().get_absolute_value(program)?)
|
|
} else {
|
|
bail!("owo? missing value: {ident}");
|
|
}
|
|
}
|
|
Self::SizedArray { .. } |
|
|
Self::Builtin { .. } |
|
|
Self::UnsizedArray { .. } => Ok(self.clone()),
|
|
|
|
}
|
|
}
|
|
|
|
pub fn get_variable_type(&self, program: &Program) -> anyhow::Result<Self> {
|
|
match self {
|
|
Self::Owned(ident) => {
|
|
if let Some(t) = program.types.get(ident) {
|
|
Ok(t.inner().clone())
|
|
} else
|
|
if let Some(var) = program.get_var(ident) {
|
|
Ok(var.1.inner().typ.clone().expect("type should be computed if were already using it").inner().clone())
|
|
} else {
|
|
bail!("owo? missing value: {ident}");
|
|
}
|
|
}
|
|
Self::Ref { .. } |
|
|
Self::SizedArray { .. } |
|
|
Self::Builtin { .. } |
|
|
Self::UnsizedArray { .. } => Ok(self.clone()),
|
|
|
|
}
|
|
}
|
|
pub fn is_numeric(&self, program: &Program) -> bool {
|
|
match self {
|
|
Self::Ref { inner, .. } => {
|
|
inner.is_numeric(program)
|
|
}
|
|
Self::Owned(name) => {
|
|
match program.types.get(&name) {
|
|
Some(t) => t.inner().is_numeric(program),
|
|
_ => false
|
|
}
|
|
},
|
|
Self::SizedArray { .. } => false,
|
|
Self::UnsizedArray { .. } => false,
|
|
Self::Builtin { name, .. } => {
|
|
match name.as_str() {
|
|
"u8" | "i8" |
|
|
"u16" | "i16" |
|
|
"u32" | "i32" |
|
|
"u64" | "i64" |
|
|
"usize" | "isize" => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Returns None if non numeric
|
|
pub fn is_signed(&self, program: &Program) -> Option<bool> {
|
|
if self.is_ptr(program) {
|
|
return Some(false);
|
|
}
|
|
match self {
|
|
Self::Ref { inner, .. } => {
|
|
inner.is_signed(program)
|
|
}
|
|
Self::Owned(name) => {
|
|
match program.types.get(&name) {
|
|
Some(t) => t.inner().is_signed(program),
|
|
_ => None
|
|
}
|
|
},
|
|
Self::SizedArray { .. } => None,
|
|
Self::UnsizedArray { .. } => None,
|
|
Self::Builtin { name, .. } => {
|
|
match name.as_str() {
|
|
"i8" |
|
|
"i16" |
|
|
"i32" |
|
|
"i64" |
|
|
"isize" => Some(true),
|
|
"u8" |
|
|
"u16" |
|
|
"u32" |
|
|
"u64" |
|
|
"usize" => Some(false),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn is_ptr(&self, program: &Program) -> bool {
|
|
match self {
|
|
Self::Owned(name) => {
|
|
match program.types.get(&name) {
|
|
Some(t) => t.inner().is_ptr(program),
|
|
_ => false
|
|
}
|
|
},
|
|
Self::Ref { .. } => true,
|
|
_ => false
|
|
}
|
|
}
|
|
|
|
pub fn is_bool(&self, program: &Program) -> bool {
|
|
match self {
|
|
Self::Owned(name) => {
|
|
match program.types.get(&name) {
|
|
Some(t) => t.inner().is_bool(program),
|
|
_ => false
|
|
}
|
|
},
|
|
Self::Builtin { name, .. } if name.as_str() == "bool" => true,
|
|
_ => false
|
|
}
|
|
}
|
|
pub fn size_of(&self, program: &Program) -> anyhow::Result<usize> {
|
|
fn f(t: &Type, program: &Program, behind_a_ptr: bool) -> anyhow::Result<usize> {
|
|
match t {
|
|
Type::Ref { .. } => {
|
|
// TODO: Use the actual ptr size
|
|
Ok(size_of::<*const ()>())
|
|
}
|
|
Type::UnsizedArray { .. } => {
|
|
if behind_a_ptr {
|
|
Ok(size_of::<*const ()>())
|
|
} else {
|
|
bail!("Unsized arrays dont have a known size and must be behind a pointer");
|
|
}
|
|
}
|
|
Type::SizedArray { inner, .. } => {
|
|
Ok(inner.size_of(program)? )
|
|
}
|
|
Type::Builtin { size, .. } => {
|
|
Ok(*size as usize)
|
|
}
|
|
Type::Owned(name) => {
|
|
if let Some(v) = program.structs.get(&name) {
|
|
return Ok(v.inner().get_size(program)?);
|
|
}
|
|
if let Some(v) = program.types.get(&name) {
|
|
return Ok(f(v.inner(), program, behind_a_ptr)?);
|
|
}
|
|
if let Some(_) = program.enums.get(&name) {
|
|
return Ok(4); // TODO: Make enum size changeable
|
|
}
|
|
bail!("Unknown type '{name}'")
|
|
}
|
|
}
|
|
}
|
|
|
|
f(self, program, false)
|
|
}
|
|
pub fn size_of_allow_unsized_arrays(&self, program: &Program) -> anyhow::Result<usize> {
|
|
match self.size_of(program) {
|
|
Ok(v) => Ok(v),
|
|
Err(e) => {
|
|
if e.to_string().as_str() == "Unsized arrays dont have a known size and must be behind a pointer" {
|
|
return Ok(0);
|
|
}
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for Type {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Ref { inner, mutable } => {
|
|
if *mutable {
|
|
write!(f, "&mut {inner}")
|
|
} else {
|
|
write!(f, "&{inner}")
|
|
}
|
|
}
|
|
Self::UnsizedArray { inner } => {
|
|
write!(f, "[{inner}]")
|
|
}
|
|
Self::SizedArray { inner, count } => {
|
|
match count.inner() {
|
|
Expr::Path(p) => {
|
|
write!(f, "[{inner}; {p}]")
|
|
}
|
|
Expr::Literal(_, Literal::Number(n)) => {
|
|
write!(f, "[{inner}; {n}]")
|
|
}
|
|
_ => unreachable!()
|
|
}
|
|
}
|
|
Self::Owned(ident) => write!(f, "{ident}"),
|
|
Self::Builtin { name, size, signed } => {
|
|
write!(f, "(builtin) {} {}({})", name, if *signed { "signed" } else { "unsigned" }, size)
|
|
}
|
|
}
|
|
}
|
|
}
|