edlang/lib/edlang_ir/src/lib.rs

593 lines
14 KiB
Rust
Raw Normal View History

2024-01-27 11:55:54 +00:00
// Based on a cfg
2024-02-27 07:27:12 +00:00
use std::{
collections::{BTreeMap, HashMap, HashSet},
fmt,
};
2024-01-30 17:05:14 +00:00
2024-01-27 11:55:54 +00:00
use edlang_span::Span;
2024-02-28 08:53:58 +00:00
use educe::Educe;
2024-01-27 11:55:54 +00:00
use smallvec::SmallVec;
2024-01-30 17:05:14 +00:00
pub mod scalar_int;
2024-02-08 10:58:10 +00:00
#[derive(Debug, Clone, Default)]
pub struct SymbolTable {
pub symbols: BTreeMap<DefId, String>,
pub modules: BTreeMap<String, DefId>,
pub functions: BTreeMap<String, DefId>,
2024-04-09 10:15:13 +00:00
pub methods: BTreeMap<DefId, BTreeMap<String, DefId>>,
2024-02-08 10:58:10 +00:00
pub constants: BTreeMap<String, DefId>,
pub structs: BTreeMap<String, DefId>,
pub types: BTreeMap<String, DefId>,
}
#[derive(Debug, Clone, Default)]
pub struct ProgramBody {
pub top_level_module_names: BTreeMap<String, DefId>,
/// The top level modules.
pub top_level_modules: Vec<DefId>,
/// All the modules in a flat map.
pub modules: BTreeMap<DefId, ModuleBody>,
/// This stores all the functions from all modules
pub functions: BTreeMap<DefId, Body>,
2024-02-17 17:41:33 +00:00
pub structs: BTreeMap<DefId, AdtBody>,
2024-02-08 10:58:10 +00:00
/// The function signatures.
pub function_signatures: BTreeMap<DefId, (Vec<TypeInfo>, TypeInfo)>,
2024-03-13 10:12:36 +00:00
pub file_names: BTreeMap<usize, String>,
2024-02-08 10:58:10 +00:00
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
pub struct ModuleBody {
2024-02-03 13:33:42 +00:00
pub module_id: DefId,
2024-02-08 10:58:10 +00:00
pub parent_ids: Vec<DefId>,
2024-03-11 11:02:14 +00:00
pub file_id: usize,
2024-02-08 10:58:10 +00:00
pub name: String,
pub symbols: SymbolTable,
/// Functions defined in this module.
pub functions: HashSet<DefId>,
/// Structs defined in this module.
pub structs: HashSet<DefId>,
/// Types defined in this module.
pub types: HashSet<DefId>,
/// Constants defined in this module.
pub constants: HashSet<DefId>,
/// Submodules defined in this module.
pub modules: HashSet<DefId>,
/// Imported items. symbol -> id
pub imports: BTreeMap<String, DefId>,
2024-01-30 17:05:14 +00:00
pub span: Span,
}
/// Definition id.
2024-02-03 13:33:42 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2024-01-30 17:05:14 +00:00
pub struct DefId {
2024-02-08 10:58:10 +00:00
pub program_id: usize,
2024-01-30 17:05:14 +00:00
pub id: usize,
}
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct Body {
2024-01-30 17:05:14 +00:00
pub def_id: DefId,
pub is_pub: bool,
pub is_extern: bool,
2024-03-13 11:06:33 +00:00
// exported means externally available in a shared library or as main
pub is_exported: bool,
2024-02-08 10:58:10 +00:00
pub name: String,
2024-01-27 11:55:54 +00:00
pub locals: SmallVec<[Local; 4]>,
pub blocks: SmallVec<[BasicBlock; 8]>,
2024-01-30 17:05:14 +00:00
pub fn_span: Span,
2024-01-27 11:55:54 +00:00
}
2024-02-03 19:14:29 +00:00
impl Body {
pub fn get_args(&self) -> SmallVec<[Local; 4]> {
let mut args = SmallVec::default();
for x in &self.locals {
if let LocalKind::Arg = x.kind {
args.push(x.clone());
}
}
args
}
pub fn get_return_local(&self) -> Local {
self.locals[0].clone()
}
pub fn get_mangled_name(&self) -> String {
2024-03-13 11:06:33 +00:00
if self.is_extern || self.is_exported {
2024-02-28 08:53:58 +00:00
return self.name.clone();
}
2024-03-13 11:06:33 +00:00
format!(
2024-03-27 11:08:48 +00:00
"{}${}${}",
2024-03-13 11:06:33 +00:00
self.name, self.def_id.program_id, self.def_id.id
)
}
2024-02-03 19:14:29 +00:00
}
2024-02-17 17:41:33 +00:00
#[derive(Debug, Clone)]
pub struct AdtBody {
pub def_id: DefId,
2024-05-05 13:09:24 +00:00
pub mod_id: DefId,
2024-02-17 17:41:33 +00:00
pub is_pub: bool,
pub name: String,
pub variants: Vec<AdtVariant>,
2024-02-17 20:31:15 +00:00
pub name_to_idx: HashMap<String, usize>,
2024-02-17 17:41:33 +00:00
pub span: Span,
}
/// struct field or enum variant
#[derive(Debug, Clone)]
pub struct AdtVariant {
pub def_id: DefId,
pub name: String,
pub ty: TypeInfo,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct DebugInfo {
pub id: usize,
pub span: Span,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct BasicBlock {
pub statements: SmallVec<[Statement; 8]>,
pub terminator: Terminator,
2024-02-14 10:21:33 +00:00
pub terminator_span: Option<Span>,
2024-01-27 11:55:54 +00:00
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct Local {
pub mutable: bool,
2024-01-30 17:05:14 +00:00
pub span: Option<Span>,
2024-02-08 10:58:10 +00:00
pub debug_name: Option<String>,
2024-01-30 17:05:14 +00:00
pub ty: TypeInfo,
2024-01-27 11:55:54 +00:00
pub kind: LocalKind,
}
2024-02-08 10:58:10 +00:00
impl Local {
pub fn new(
span: Option<Span>,
kind: LocalKind,
ty: TypeInfo,
debug_name: Option<String>,
mutable: bool,
) -> Self {
Self {
span,
kind,
ty,
debug_name,
mutable,
}
}
2024-02-14 09:13:28 +00:00
pub const fn temp(ty: TypeKind) -> Self {
2024-02-08 10:58:10 +00:00
Self {
span: None,
2024-02-14 09:13:28 +00:00
ty: TypeInfo {
span: None,
kind: ty,
},
2024-02-08 10:58:10 +00:00
kind: LocalKind::Temp,
debug_name: None,
mutable: false,
}
}
2024-05-07 07:11:09 +00:00
pub fn is_mutable(&self) -> bool {
if self.mutable {
return true;
}
match self.ty.kind {
TypeKind::Ptr(is_mut, _) => is_mut,
TypeKind::Ref(is_mut, _) => is_mut,
_ => false,
}
}
2024-02-08 10:58:10 +00:00
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone, Copy)]
2024-01-27 11:55:54 +00:00
pub enum LocalKind {
Temp,
Arg,
ReturnPointer,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct Statement {
2024-01-30 17:05:14 +00:00
pub span: Option<Span>,
2024-01-27 11:55:54 +00:00
pub kind: StatementKind,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub enum StatementKind {
Assign(Place, RValue),
StorageLive(usize),
StorageDead(usize),
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub enum Terminator {
Target(usize),
Return,
2024-02-12 11:09:40 +00:00
SwitchInt {
discriminator: Operand,
targets: SwitchTarget,
},
2024-01-27 11:55:54 +00:00
Call {
2024-02-08 10:58:10 +00:00
/// The function to call.
func: DefId,
/// The arguments.
args: Vec<RValue>,
/// The place in memory to store the return value of the function call.
destination: Place,
/// What basic block to jump to after the function call, if the function is non-diverging (i.e it returns control back).
target: Option<usize>,
2024-01-27 11:55:54 +00:00
},
Unreachable,
}
2024-02-12 11:09:40 +00:00
/// Used for ifs, match
#[derive(Debug, Clone)]
pub struct SwitchTarget {
pub values: Vec<ValueTree>,
pub targets: Vec<usize>,
}
2024-02-28 08:53:58 +00:00
#[derive(Debug, Clone, Educe, Eq, PartialOrd, Ord)]
#[educe(PartialEq)]
2024-01-27 11:55:54 +00:00
pub struct TypeInfo {
2024-02-28 08:53:58 +00:00
#[educe(PartialEq(ignore))]
2024-01-30 17:05:14 +00:00
pub span: Option<Span>,
2024-01-27 11:55:54 +00:00
pub kind: TypeKind,
}
2024-02-27 07:27:12 +00:00
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
2024-01-27 11:55:54 +00:00
pub enum TypeKind {
2024-02-03 11:06:16 +00:00
Unit,
2024-01-27 11:55:54 +00:00
Bool,
Char,
Int(IntTy),
Uint(UintTy),
2024-01-30 17:05:14 +00:00
Float(FloatTy),
2024-02-03 11:06:16 +00:00
FnDef(DefId, Vec<TypeInfo>), // The vec are generic types, not arg types
2024-02-24 09:57:29 +00:00
Str,
Ptr(bool, Box<TypeInfo>),
2024-02-17 11:37:28 +00:00
Ref(bool, Box<TypeInfo>),
2024-02-28 08:04:56 +00:00
// name for print purposes
Struct(DefId, String), // todo, add generics
2024-01-27 11:55:54 +00:00
}
2024-02-03 13:33:42 +00:00
impl TypeKind {
pub const fn is_unit(&self) -> bool {
2024-02-04 16:27:06 +00:00
matches!(self, Self::Unit)
}
pub const fn is_integer(&self) -> bool {
matches!(self, Self::Int(_) | Self::Uint(_))
}
2024-03-02 09:20:33 +00:00
pub const fn is_signed_integer(&self) -> bool {
matches!(self, Self::Int(_))
}
pub const fn is_float(&self) -> bool {
matches!(self, Self::Float(_))
}
2024-02-03 13:33:42 +00:00
pub fn get_falsy_value(&self) -> ValueTree {
match self {
Self::Bool => ValueTree::Leaf(ConstValue::Bool(false)),
Self::Char => todo!(),
Self::Int(ty) => match ty {
IntTy::I8 => ValueTree::Leaf(ConstValue::I8(0)),
IntTy::I16 => ValueTree::Leaf(ConstValue::I16(0)),
IntTy::I32 => ValueTree::Leaf(ConstValue::I32(0)),
IntTy::I64 => ValueTree::Leaf(ConstValue::I64(0)),
IntTy::I128 => ValueTree::Leaf(ConstValue::I128(0)),
IntTy::Isize => todo!(),
},
Self::Uint(ty) => match ty {
UintTy::U8 => ValueTree::Leaf(ConstValue::U8(0)),
UintTy::U16 => ValueTree::Leaf(ConstValue::U16(0)),
UintTy::U32 => ValueTree::Leaf(ConstValue::U32(0)),
UintTy::U64 => ValueTree::Leaf(ConstValue::U64(0)),
UintTy::U128 => ValueTree::Leaf(ConstValue::U128(0)),
UintTy::Usize => todo!(),
},
Self::Float(_) => todo!(),
TypeKind::Unit => unreachable!(),
TypeKind::FnDef(_, _) => unreachable!(),
2024-02-24 09:57:29 +00:00
TypeKind::Ptr(_, _pointee) => todo!(),
2024-02-17 11:37:28 +00:00
TypeKind::Ref(_, inner) => inner.kind.get_falsy_value(),
2024-02-28 08:04:56 +00:00
TypeKind::Struct(_, _name) => todo!(),
2024-02-24 09:57:29 +00:00
TypeKind::Str => todo!(),
2024-02-03 13:33:42 +00:00
}
}
}
2024-02-27 07:27:12 +00:00
impl fmt::Display for TypeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TypeKind::Unit => write!(f, "()"),
TypeKind::Bool => write!(f, "bool"),
TypeKind::Char => write!(f, "char"),
TypeKind::Int(ty) => match ty {
IntTy::I128 => write!(f, "i128"),
IntTy::I64 => write!(f, "i64"),
IntTy::I32 => write!(f, "i32"),
IntTy::I16 => write!(f, "i16"),
IntTy::I8 => write!(f, "i8"),
IntTy::Isize => write!(f, "isize"),
},
TypeKind::Uint(ty) => match ty {
UintTy::U128 => write!(f, "u128"),
UintTy::U64 => write!(f, "u64"),
UintTy::U32 => write!(f, "u32"),
UintTy::U16 => write!(f, "u16"),
UintTy::U8 => write!(f, "u8"),
UintTy::Usize => write!(f, "usize"),
},
TypeKind::Float(ty) => match ty {
FloatTy::F32 => write!(f, "f64"),
FloatTy::F64 => write!(f, "f32"),
},
TypeKind::FnDef(_, _) => todo!(),
TypeKind::Str => write!(f, "str"),
TypeKind::Ptr(is_mut, inner) => {
let word = if *is_mut { "mut" } else { "const" };
write!(f, "*{word} {}", inner.kind)
}
TypeKind::Ref(is_mut, inner) => {
let word = if *is_mut { "mut" } else { "const" };
write!(f, "&{word} {}", inner.kind)
}
2024-02-28 08:04:56 +00:00
TypeKind::Struct(_, name) => write!(f, "{}", name),
2024-02-27 07:27:12 +00:00
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
2024-01-27 11:55:54 +00:00
pub enum IntTy {
I128,
I64,
I32,
I16,
I8,
Isize,
}
2024-02-27 07:27:12 +00:00
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
2024-01-27 11:55:54 +00:00
pub enum UintTy {
U128,
U64,
U32,
U16,
U8,
Usize,
}
2024-02-27 07:27:12 +00:00
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
2024-01-30 17:05:14 +00:00
pub enum FloatTy {
2024-01-27 11:55:54 +00:00
F32,
F64,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct ConstData {
2024-01-30 17:05:14 +00:00
pub span: Option<Span>,
pub type_info: TypeInfo,
2024-01-27 11:55:54 +00:00
pub kind: ConstKind,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub enum ConstKind {
Value(ValueTree),
2024-02-03 11:06:16 +00:00
ZeroSized,
2024-01-27 11:55:54 +00:00
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub enum ValueTree {
2024-01-30 17:05:14 +00:00
Leaf(ConstValue),
2024-01-27 11:55:54 +00:00
Branch(Vec<Self>),
}
2024-02-12 11:09:40 +00:00
impl ValueTree {
pub fn get_type(&self) -> TypeKind {
match self {
ValueTree::Leaf(value) => match value {
ConstValue::Bool(_) => TypeKind::Bool,
ConstValue::I8(_) => TypeKind::Int(IntTy::I8),
ConstValue::I16(_) => TypeKind::Int(IntTy::I16),
ConstValue::I32(_) => TypeKind::Int(IntTy::I32),
ConstValue::I64(_) => TypeKind::Int(IntTy::I64),
ConstValue::I128(_) => TypeKind::Int(IntTy::I128),
ConstValue::U8(_) => TypeKind::Uint(UintTy::U8),
ConstValue::U16(_) => TypeKind::Uint(UintTy::U16),
ConstValue::U32(_) => TypeKind::Uint(UintTy::U32),
ConstValue::U64(_) => TypeKind::Uint(UintTy::U64),
ConstValue::U128(_) => TypeKind::Uint(UintTy::U8),
ConstValue::F32(_) => TypeKind::Float(FloatTy::F32),
ConstValue::F64(_) => TypeKind::Float(FloatTy::F64),
2024-02-14 10:21:33 +00:00
ConstValue::Char(_) => TypeKind::Char,
2024-02-24 09:57:29 +00:00
ConstValue::Isize(_) => TypeKind::Int(IntTy::Isize),
2024-04-13 09:36:42 +00:00
ConstValue::Str(_) => TypeKind::Str,
2024-02-12 11:09:40 +00:00
},
ValueTree::Branch(_) => todo!(),
}
}
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub enum RValue {
2024-02-24 09:57:29 +00:00
Use(Operand, Span),
Ref(bool, Operand, Span),
BinOp(BinOp, Operand, Operand, Span),
LogicOp(LogicalOp, Operand, Operand, Span),
UnOp(UnOp, Operand, Span),
2024-03-12 12:03:35 +00:00
Cast(Operand, TypeInfo, Span),
2024-01-27 11:55:54 +00:00
}
2024-05-07 07:11:09 +00:00
impl RValue {
pub fn get_local(&self) -> Option<usize> {
match self {
RValue::Use(op, _) => op.get_local(),
RValue::Ref(_, op, _) => op.get_local(),
RValue::BinOp(_, _, _, _) => None,
RValue::LogicOp(_, _, _, _) => None,
RValue::UnOp(_, _, _) => None,
RValue::Cast(op, _, _) => op.get_local(),
}
}
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub enum Operand {
Copy(Place),
Move(Place),
Constant(ConstData),
}
2024-05-07 07:11:09 +00:00
impl Operand {
pub fn get_local(&self) -> Option<usize> {
match self {
Operand::Copy(place) => Some(place.local),
Operand::Move(place) => Some(place.local),
Operand::Constant(_) => None,
}
}
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone)]
2024-01-27 11:55:54 +00:00
pub struct Place {
pub local: usize,
pub projection: SmallVec<[PlaceElem; 1]>,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone, Copy)]
2024-01-27 11:55:54 +00:00
pub enum PlaceElem {
Deref,
2024-02-17 20:31:15 +00:00
Field { field_idx: usize },
2024-01-27 11:55:54 +00:00
Index { local: usize },
}
impl TypeKind {
pub fn get_i128() -> Self {
Self::Int(IntTy::I128)
}
pub fn get_i64() -> Self {
Self::Int(IntTy::I64)
}
pub fn get_i32() -> Self {
Self::Int(IntTy::I32)
}
pub fn get_i16() -> Self {
Self::Int(IntTy::I16)
}
pub fn get_i8() -> Self {
Self::Int(IntTy::I8)
}
pub fn get_u128() -> Self {
Self::Uint(UintTy::U128)
}
pub fn get_u64() -> Self {
Self::Uint(UintTy::U64)
}
pub fn get_u32() -> Self {
Self::Uint(UintTy::U32)
}
pub fn get_u16() -> Self {
Self::Uint(UintTy::U16)
}
pub fn get_u8() -> Self {
Self::Uint(UintTy::U8)
}
pub fn get_f32() -> Self {
2024-01-30 17:05:14 +00:00
Self::Float(FloatTy::F32)
2024-01-27 11:55:54 +00:00
}
pub fn get_f64() -> Self {
2024-01-30 17:05:14 +00:00
Self::Float(FloatTy::F64)
2024-01-27 11:55:54 +00:00
}
pub fn get_bool() -> Self {
Self::Bool
}
pub fn get_char() -> Self {
Self::Char
}
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone, Copy)]
2024-01-27 11:55:54 +00:00
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Rem,
BitXor,
BitAnd,
BitOr,
Shl,
Shr,
Eq,
Lt,
Le,
Ne,
Ge,
Gt,
Offset,
}
2024-02-03 13:33:42 +00:00
// Diferent than BinOp because operands needs to be lazily evaluated.
#[derive(Debug, Clone, Copy)]
pub enum LogicalOp {
And,
Or,
}
2024-01-30 17:05:14 +00:00
#[derive(Debug, Clone, Copy)]
2024-01-27 11:55:54 +00:00
pub enum UnOp {
Not,
Neg,
}
2024-01-30 17:05:14 +00:00
2024-04-13 09:36:42 +00:00
#[derive(Debug, Clone)]
2024-01-30 17:05:14 +00:00
pub enum ConstValue {
Bool(bool),
2024-02-14 10:21:33 +00:00
Char(char),
2024-01-30 17:05:14 +00:00
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
2024-02-24 09:57:29 +00:00
Isize(isize),
2024-01-30 17:05:14 +00:00
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
F32(f32),
F64(f64),
2024-04-13 09:36:42 +00:00
Str(String),
2024-01-30 17:05:14 +00:00
}