pub mod eval;
pub mod lower;
mod print;
pub mod value;
#[cfg(all(test, not(miri)))]
mod test_eval;
use crate::{
ast::Identifier,
label::LabelRef,
runtime::{self, layout::Layout},
typechecker::{
self,
scope::{ResolvedName, ScopeRef},
},
};
pub use eval::Memory;
pub use lower::lower_to_lir;
use std::{fmt::Display, sync::Arc};
pub use value::{IrType, IrValue};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Var {
pub scope: ScopeRef,
pub kind: VarKind,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VarKind {
Explicit(Identifier),
Tmp(usize),
Return,
Context,
}
impl From<Var> for Operand {
fn from(value: Var) -> Self {
Operand::Place(value)
}
}
#[derive(Clone, Debug)]
pub enum Operand {
Place(Var),
Value(IrValue),
}
#[derive(Clone, Debug)]
pub enum Instruction {
Jump(LabelRef),
Switch {
examinee: Operand,
branches: Vec<(usize, LabelRef)>,
default: LabelRef,
},
Assign { to: Var, val: Operand, ty: IrType },
ConstantAddress { to: Var, name: ResolvedName },
FunctionAddress { to: Var, name: Identifier },
InitString {
to: Var,
string: String,
init_func: unsafe extern "C" fn(*mut Arc<str>, *mut u8, u32),
},
Call {
to: Option<(Var, IrType)>,
ctx: Option<Operand>,
func: Identifier,
args: Vec<Operand>,
return_ptr: Option<Var>,
},
CallRuntime {
func: runtime::RuntimeFunctionRef,
args: Vec<Operand>,
},
Return(Option<Operand>),
IntCmp {
to: Var,
cmp: IntCmp,
left: Operand,
right: Operand,
},
FloatCmp {
to: Var,
cmp: FloatCmp,
left: Operand,
right: Operand,
},
Add {
to: Var,
left: Operand,
right: Operand,
},
Sub {
to: Var,
left: Operand,
right: Operand,
},
Mul {
to: Var,
left: Operand,
right: Operand,
},
Div {
to: Var,
signed: bool,
left: Operand,
right: Operand,
},
FDiv {
to: Var,
left: Operand,
right: Operand,
},
Not { to: Var, val: Operand },
Negate { to: Var, val: Operand },
Offset { to: Var, from: Operand, offset: u32 },
Initialize {
to: Var,
bytes: Vec<u8>,
layout: Layout,
},
Write { to: Operand, val: Operand },
Read { to: Var, from: Operand, ty: IrType },
Copy {
to: Operand,
from: Operand,
size: u32,
},
Clone {
to: Operand,
from: Operand,
clone_fn: unsafe extern "C" fn(*const (), *mut ()),
},
Drop {
var: Operand,
drop: Option<unsafe extern "C" fn(*mut ())>,
},
}
#[derive(Clone, Debug)]
pub enum IntCmp {
Eq,
Ne,
ULt,
ULe,
UGt,
UGe,
SLt,
SLe,
SGt,
SGe,
}
impl Display for IntCmp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
IntCmp::Eq => "eq",
IntCmp::Ne => "ne",
IntCmp::ULt => "ult",
IntCmp::ULe => "ule",
IntCmp::UGt => "ugt",
IntCmp::UGe => "uge",
IntCmp::SLt => "slt",
IntCmp::SLe => "sle",
IntCmp::SGt => "sgt",
IntCmp::SGe => "sge",
};
write!(f, "{s}")
}
}
#[derive(Clone, Debug)]
pub enum FloatCmp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
impl Display for FloatCmp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
FloatCmp::Eq => "eq",
FloatCmp::Ne => "ne",
FloatCmp::Lt => "lt",
FloatCmp::Le => "le",
FloatCmp::Gt => "gt",
FloatCmp::Ge => "ge",
};
write!(f, "{s}")
}
}
#[derive(Debug)]
pub enum ValueOrSlot {
Val(IrType),
StackSlot(Layout),
}
#[derive(Debug)]
pub struct Function {
pub name: Identifier,
pub scope: ScopeRef,
pub signature: typechecker::types::Signature,
pub ir_signature: Signature,
pub entry_block: LabelRef,
pub variables: Vec<(Var, ValueOrSlot)>,
pub blocks: Vec<Block>,
pub public: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Signature {
pub parameters: Vec<(Identifier, IrType)>,
pub context: bool,
pub return_ptr: bool,
pub return_type: Option<IrType>,
}
#[derive(Debug)]
pub struct Block {
pub label: LabelRef,
pub instructions: Vec<Instruction>,
}
pub struct Lir {
pub functions: Vec<Function>,
}