actually compiles and does stuff now

This commit is contained in:
2024-12-06 19:44:33 -05:00
parent 31c197e991
commit 620c4557e9
67 changed files with 1931 additions and 1287 deletions

1
src/ir/arch/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod riscv64;

37
src/ir/arch/riscv64.rs Normal file
View File

@@ -0,0 +1,37 @@
use crate::{compiler::arch::riscv64::*, ir::VarID};
#[derive(Copy, Clone)]
pub enum RV64Instruction {
Ecall,
Li { dest: RegRef, imm: i64 },
Mv { dest: RegRef, src: RegRef },
La { dest: RegRef, src: VarID },
Ld { dest: RegRef, offset: i64, base: RegRef },
}
#[derive(Copy, Clone)]
pub enum RegRef {
Var(VarID),
Reg(Reg),
}
impl std::fmt::Debug for RegRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Var(v) => write!(f, "{{{:?}}}", v),
Self::Reg(r) => r.fmt(f),
}
}
}
impl std::fmt::Debug for RV64Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ecall => write!(f, "ecall"),
Self::Li { dest, imm } => write!(f, "li {dest:?}, {imm:?}"),
Self::Mv { dest, src } => write!(f, "mv {dest:?}, {src:?}"),
Self::La { dest, src } => write!(f, "la {dest:?}, {src:?}"),
Self::Ld { dest, offset, base } => write!(f, "ld {dest:?}, {offset}({base:?})"),
}
}
}

13
src/ir/asm.rs Normal file
View File

@@ -0,0 +1,13 @@
use super::VarID;
#[derive(Clone)]
pub struct IRAsmInstruction {
op: String,
args: Vec<RegRef>,
}
#[derive(Clone)]
pub enum RegRef {
Var(VarID),
Reg(String),
}

42
src/ir/id.rs Normal file
View File

@@ -0,0 +1,42 @@
use std::fmt::Debug;
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct TypeID(pub usize);
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct VarID(pub usize);
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct FnID(pub usize);
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct DataID(pub usize);
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct AddrID(pub usize);
impl Debug for VarID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "var{}", self.0)
}
}
impl Debug for TypeID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ty{}", self.0)
}
}
impl Debug for FnID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "fn{}", self.0)
}
}
impl Debug for DataID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "data{}", self.0)
}
}
impl Debug for AddrID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "@{}", self.0)
}
}

6
src/ir/lower/data.rs Normal file
View File

@@ -0,0 +1,6 @@
use super::AddrID;
pub struct IRLData {
pub addr: AddrID,
pub data: Vec<u8>,
}

41
src/ir/lower/func.rs Normal file
View File

@@ -0,0 +1,41 @@
use super::*;
use crate::compiler::arch::riscv64::Reg;
use arch::riscv64::RV64Instruction;
use std::collections::HashMap;
#[derive(Debug)]
pub struct IRLFunction {
pub name: String,
pub addr: AddrID,
pub instructions: Vec<IRLInstruction>,
pub stack: HashMap<VarID, usize>,
pub args: Vec<(VarID, usize)>,
}
#[derive(Debug)]
pub enum IRLInstruction {
Mv {
dest: VarID,
src: VarID,
},
Ref {
dest: VarID,
src: VarID,
},
LoadAddr {
dest: VarID,
src: AddrID,
},
Call {
dest: VarID,
f: AddrID,
args: Vec<(VarID, usize)>,
},
AsmBlock {
instructions: Vec<RV64Instruction>,
args: Vec<(Reg, VarID)>,
},
Ret {
src: VarID,
},
}

9
src/ir/lower/mod.rs Normal file
View File

@@ -0,0 +1,9 @@
mod func;
mod data;
mod program;
pub use func::*;
pub use data::*;
pub use program::*;
use super::*;

85
src/ir/lower/program.rs Normal file
View File

@@ -0,0 +1,85 @@
use std::collections::HashMap;
use super::{AddrID, IRLData, IRLFunction, IRLInstruction, IRUInstruction, Namespace, VarID};
pub struct Program {
pub fns: Vec<IRLFunction>,
pub data: Vec<IRLData>,
}
impl Program {
pub fn create(ns: &Namespace) -> Self {
let mut fns = Vec::new();
let mut data = Vec::new();
let data_len = ns.data.len();
for (i, d) in ns.data.iter().enumerate() {
data.push(IRLData {
addr: AddrID(i),
data: d.clone(),
})
}
for (i, f) in ns.fns.iter().enumerate() {
let f = f.as_ref().unwrap();
let mut instructions = Vec::new();
let mut stack = HashMap::new();
let mut alloc = |i: &VarID| {
if !stack.contains_key(i) {
stack.insert(*i, 8);
}
};
for i in &f.instructions {
instructions.push(match i {
IRUInstruction::Mv { dest, src } => {
alloc(dest);
IRLInstruction::Mv {
dest: *dest,
src: *src,
}
}
IRUInstruction::Ref { dest, src } => {
alloc(dest);
IRLInstruction::Ref {
dest: *dest,
src: *src,
}
}
IRUInstruction::LoadData { dest, src } => {
alloc(dest);
IRLInstruction::LoadAddr {
dest: *dest,
src: AddrID(src.0),
}
}
IRUInstruction::LoadFn { dest, src } => {
alloc(dest);
IRLInstruction::LoadAddr {
dest: *dest,
src: AddrID(src.0 + data_len),
}
}
IRUInstruction::Call { dest, f, args } => {
alloc(dest);
IRLInstruction::Call {
dest: *dest,
f: AddrID(ns.fn_map[f].0 + data_len),
args: args.iter().map(|a| (*a, 8)).collect(),
}
}
IRUInstruction::AsmBlock { instructions, args } => IRLInstruction::AsmBlock {
instructions: instructions.clone(),
args: args.clone(),
},
IRUInstruction::Ret { src } => IRLInstruction::Ret { src: *src },
});
}
fns.push(IRLFunction {
name: f.name.clone(),
addr: AddrID(i + data_len),
instructions,
args: f.args.iter().map(|a| (*a, 8)).collect(),
stack,
})
}
Self { fns, data }
}
}

View File

@@ -1,56 +0,0 @@
use crate::compiler::riscv64::AsmInstruction;
use super::{FnIdent, VarIdent};
#[derive(Debug)]
pub struct Function {
instructions: Vec<Instruction>,
}
#[derive(Debug)]
pub enum Instruction {
Mv {
dest: VarIdent,
src: VarIdent,
},
Ref {
dest: VarIdent,
src: VarIdent,
},
Lf {
dest: VarIdent,
src: FnIdent,
},
Call {
dest: VarIdent,
f: FnIdent,
args: Vec<VarIdent>,
},
AsmBlock {
instructions: Vec<AsmInstruction>,
},
Ret {
src: VarIdent,
},
}
pub struct Instructions {
vec: Vec<Instruction>,
}
impl Function {
pub fn new(instructions: Instructions) -> Self {
Self {
instructions: instructions.vec,
}
}
}
impl Instructions {
pub fn new() -> Self {
Self { vec: Vec::new() }
}
pub fn push(&mut self, i: Instruction) {
self.vec.push(i);
}
}

View File

View File

@@ -1,9 +1,11 @@
mod namespace;
mod lvl1;
mod lvl2;
mod upper;
mod file;
mod lower;
mod id;
mod asm;
pub mod arch;
pub use namespace::*;
pub use lvl1::*;
pub use upper::*;
pub use lower::*;
pub use file::*;
pub use id::*;

View File

@@ -1,226 +0,0 @@
#[derive(Debug)]
pub enum IRInstruction {
Li(Var, Literal),
Mv(Var, Var),
Not(Var, Var),
Add(Var, Var, Var),
La(Var, IRIdent),
Call(Var, FnIdent, Vec<ExprResult>),
}
#[derive(Debug)]
pub struct IRFunction {
args: Vec<Var>,
instructions: Vec<IRInstruction>,
}
impl Module {
pub fn lower(&self, map: &mut Namespace, errors: &mut ParserErrors) {
let mut fns = Vec::new();
for f in &self.functions {
if let Some(f) = f.as_ref() {
if let Some(id) = f.reserve(map, errors) {
fns.push((id, f));
}
}
}
for (id, f) in fns {
f.lower(id, map, errors);
}
}
}
impl Function {
pub fn reserve(&self, map: &mut Namespace, errors: &mut ParserErrors) -> Option<FnIdent> {
let name = self.name.as_ref()?;
if let Some(other) = map.get(name) {
errors.add(ParserError {
msg: format!("Already {:?} named '{:?}'", other.ty, self.name),
spans: vec![self.name.span, other.origin],
});
None
} else {
Some(map.reserve_fn(name, self.name.span))
}
}
pub fn lower(
&self,
ident: FnIdent,
map: &mut Namespace,
errors: &mut ParserErrors,
) -> Option<()> {
let mut instructions = Vec::new();
let mut map = map.push();
let mut args = Vec::new();
for arg in &self.args {
args.push(map.def_var(arg.as_ref()?, arg.span)?);
}
if let Some(b) = self.body.as_ref() {
b.lower(&mut map, &mut instructions, errors)
}
map.write_fn(ident, IRFunction { instructions, args });
Some(())
}
}
impl Body {
pub fn lower(
&self,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) {
let mut map = map.push();
for statement in &self.statements {
let Some(statement) = statement.as_ref() else {
continue;
};
match statement {
Statement::Let(name_node, expr) => {
let Some(name) = name_node.as_ref() else {
continue;
};
let res = expr.lower(&mut map, instructions, errors);
if let Some(res) = res {
match res {
ExprResult::Var(v) => map.name_var(name, v),
ExprResult::Fn(f) => todo!(),
};
}
}
Statement::Return(e) => todo!(),
Statement::Expr(expr) => {
expr.lower(&mut map, instructions, errors);
}
}
}
}
}
impl Node<Box<Expr>> {
pub fn lower(
&self,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) -> Option<ExprResult> {
self.as_ref()?.lower(self.span, map, instructions, errors)
}
}
impl Node<Expr> {
pub fn lower(
&self,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) -> Option<ExprResult> {
self.as_ref()?.lowerr(self.span, map, instructions, errors)
}
}
impl Expr {
pub fn lowerr(
&self,
span: FileSpan,
map: &mut Namespace,
instructions: &mut Vec<IRInstruction>,
errors: &mut ParserErrors,
) -> Option<ExprResult> {
match self {
Expr::Lit(l) => {
let temp = map.temp_var(span);
instructions.push(IRInstruction::Li(temp, l.as_ref()?.clone()));
Some(ExprResult::Var(temp))
},
Expr::Ident(i) => {
let Some(id) = map.get(i.as_ref()?) else {
errors.add(ParserError::identifier_not_found(i));
return None;
};
match id.ty() {
IdentTypeMatch::Var(var) => Some(ExprResult::Var(var)),
IdentTypeMatch::Fn(f) => Some(ExprResult::Fn(f)),
}
}
Expr::BinaryOp(op, e1, e2) => {
let res1 = e1.lower(map, instructions, errors)?;
let res2 = e2.lower(map, instructions, errors)?;
let (ExprResult::Var(v1), ExprResult::Var(v2)) = (res1, res2) else {
errors.add(ParserError::from_span(span, "Cannot operate on functions".to_string()));
return None;
};
let temp = map.temp_var(span);
match op {
crate::parser::BinaryOperator::Add => {
instructions.push(IRInstruction::Add(temp, v1, v2))
}
crate::parser::BinaryOperator::Sub => todo!(),
crate::parser::BinaryOperator::Mul => todo!(),
crate::parser::BinaryOperator::Div => todo!(),
crate::parser::BinaryOperator::LessThan => todo!(),
crate::parser::BinaryOperator::GreaterThan => todo!(),
crate::parser::BinaryOperator::Access => todo!(),
crate::parser::BinaryOperator::Assign => todo!(),
}
Some(ExprResult::Var(temp))
}
Expr::UnaryOp(op, e) => {
let res = e.lower(map, instructions, errors)?;
let res = match op {
crate::parser::UnaryOperator::Not => {
let temp = map.temp_var(span);
match res {
ExprResult::Var(i) => instructions.push(IRInstruction::Not(temp, i)),
ExprResult::Fn(_) => {
errors.add(ParserError::from_span(
span,
"Cannot call not on a function".to_string(),
));
return None;
}
}
temp
}
crate::parser::UnaryOperator::Ref => todo!(),
};
Some(ExprResult::Var(res))
}
Expr::Block(_) => todo!(),
Expr::Call(e, args) => {
let fe = e.lower(map, instructions, errors);
let mut nargs = Vec::new();
for arg in args.iter() {
let arg = arg.lower(map, instructions, errors)?;
nargs.push(arg);
}
if let Some(r) = fe {
match r {
ExprResult::Fn(f) => {
let temp = map.temp_var(span);
instructions.push(IRInstruction::Call(temp, f, nargs));
Some(ExprResult::Var(temp))
}
o => {
errors.add(ParserError::from_span(
span,
"Expected function".to_string(),
));
None
}
}
} else {
None
}
}
Expr::Group(e) => e.lower(map, instructions, errors),
}
}
}
#[derive(Debug)]
pub enum ExprResult {
Var(Var),
Fn(FnIdent),
}

View File

@@ -1,6 +1,7 @@
use super::{FileSpan, Type};
use std::fmt::Debug;
#[derive(Clone)]
pub struct FnDef {
pub name: String,
pub args: Vec<VarDef>,
@@ -8,6 +9,7 @@ pub struct FnDef {
pub origin: Origin,
}
#[derive(Clone)]
pub struct TypeDef {
pub name: String,
pub args: usize,

82
src/ir/upper/func.rs Normal file
View File

@@ -0,0 +1,82 @@
use crate::compiler::arch::riscv64::Reg;
use super::{arch::riscv64::RV64Instruction, DataID, FnID, VarID};
#[derive(Debug)]
pub struct IRUFunction {
pub name: String,
pub args: Vec<VarID>,
pub instructions: Vec<IRUInstruction>,
}
pub enum IRUInstruction {
Mv {
dest: VarID,
src: VarID,
},
Ref {
dest: VarID,
src: VarID,
},
LoadData {
dest: VarID,
src: DataID,
},
LoadFn {
dest: VarID,
src: FnID,
},
Call {
dest: VarID,
f: VarID,
args: Vec<VarID>,
},
AsmBlock {
instructions: Vec<RV64Instruction>,
args: Vec<(Reg, VarID)>,
},
Ret {
src: VarID,
},
}
pub struct IRInstructions {
vec: Vec<IRUInstruction>,
}
impl IRUFunction {
pub fn new(name: String, args: Vec<VarID>, instructions: IRInstructions) -> Self {
Self {
name,
args,
instructions: instructions.vec,
}
}
}
impl IRInstructions {
pub fn new() -> Self {
Self { vec: Vec::new() }
}
pub fn push(&mut self, i: IRUInstruction) {
self.vec.push(i);
}
}
impl std::fmt::Debug for IRUInstruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Mv { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"),
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::Call {
dest,
f: func,
args,
} => write!(f, "{dest:?} <- {func:?}({args:?})"),
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}"),
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish(),
}
}
}

View File

@@ -1,9 +1,10 @@
mod def;
mod func;
mod ty;
mod namespace;
use super::*;
pub use def::*;
pub use func::*;
pub use ty::*;
pub use namespace::*;

View File

@@ -4,13 +4,15 @@ use std::{
ops::{Deref, DerefMut},
};
use super::{BuiltinType, FileSpan, FnDef, Function, Type, TypeDef, VarDef};
use super::*;
pub struct Namespace {
pub fn_defs: Vec<FnDef>,
pub var_defs: Vec<VarDef>,
pub type_defs: Vec<TypeDef>,
pub fns: Vec<Option<Function>>,
pub fns: Vec<Option<IRUFunction>>,
pub data: Vec<Vec<u8>>,
pub fn_map: HashMap<VarID, FnID>,
pub temp: usize,
pub stack: Vec<HashMap<String, Idents>>,
}
@@ -21,6 +23,8 @@ impl Namespace {
fn_defs: Vec::new(),
var_defs: Vec::new(),
type_defs: Vec::new(),
data: Vec::new(),
fn_map: HashMap::new(),
fns: Vec::new(),
temp: 0,
stack: vec![HashMap::new()],
@@ -43,27 +47,36 @@ impl Namespace {
}
None
}
pub fn get_var(&self, id: VarIdent) -> &VarDef {
pub fn get_var(&self, id: VarID) -> &VarDef {
&self.var_defs[id.0]
}
pub fn get_fn(&self, id: FnIdent) -> &FnDef {
pub fn get_fn(&self, id: FnID) -> &FnDef {
&self.fn_defs[id.0]
}
pub fn get_type(&self, id: TypeIdent) -> &TypeDef {
pub fn get_fn_var(&self, id: VarID) -> &FnDef {
&self.fn_defs[self.fn_map[&id].0]
}
pub fn get_type(&self, id: TypeID) -> &TypeDef {
&self.type_defs[id.0]
}
pub fn alias_fn(&mut self, name: &str, id: FnIdent) {
pub fn alias_fn(&mut self, name: &str, id: FnID) {
self.insert(name, Ident::Fn(id));
}
pub fn name_var(&mut self, def: &VarDef, var: VarIdent) {
pub fn named_var(&mut self, def: VarDef) -> VarID {
// TODO: this is stupid
let id = self.def_var(def.clone());
self.name_var(&def, id);
id
}
pub fn name_var(&mut self, def: &VarDef, var: VarID) {
self.insert(&def.name, Ident::Var(var));
}
pub fn def_var(&mut self, var: VarDef) -> VarIdent {
pub fn def_var(&mut self, var: VarDef) -> VarID {
let i = self.var_defs.len();
self.var_defs.push(var);
VarIdent(i)
VarID(i)
}
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarIdent {
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID {
let v = self.def_var(VarDef {
name: format!("temp{}", self.temp),
origin: super::Origin::File(origin),
@@ -72,21 +85,38 @@ impl Namespace {
self.temp += 1;
v
}
pub fn def_fn(&mut self, def: FnDef) -> FnIdent {
pub fn def_fn(&mut self, def: FnDef) -> FnID {
let i = self.fn_defs.len();
let id = FnIdent(i);
let id = FnID(i);
let var_def = VarDef {
name: def.name.clone(),
origin: def.origin,
ty: def.ty(),
};
let vid = self.def_var(var_def);
self.insert(&def.name, Ident::Var(vid));
self.fn_map.insert(vid, id);
self.insert(&def.name, Ident::Fn(id));
self.fn_defs.push(def);
self.fns.push(None);
id
}
pub fn def_type(&mut self, def: TypeDef) -> TypeIdent {
pub fn def_type(&mut self, def: TypeDef) -> TypeID {
let i = self.type_defs.len();
let id = TypeIdent(i);
let id = TypeID(i);
self.insert(&def.name, Ident::Type(id));
self.type_defs.push(def);
id
}
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID {
let i = self.data.len();
self.data.push(bytes);
DataID(i)
}
pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new();
match ty {
@@ -121,6 +151,8 @@ impl Namespace {
}
Type::Error => str += "{error}",
Type::Infer => str += "{inferred}",
Type::Bits(size) => str += &format!("b{}", size),
Type::Array(t) => str += &format!("[{}]", self.type_name(t)),
}
str
}
@@ -133,7 +165,7 @@ impl Namespace {
last.insert(name.to_string(), Idents::new(id));
}
}
pub fn write_fn(&mut self, id: FnIdent, f: Function) {
pub fn write_fn(&mut self, id: FnID, f: IRUFunction) {
self.fns[id.0] = Some(f);
}
}
@@ -161,18 +193,17 @@ impl DerefMut for NamespaceGuard<'_> {
#[derive(Debug, Clone, Copy)]
pub enum Ident {
Var(VarIdent),
Fn(FnIdent),
Type(TypeIdent),
Var(VarID),
Fn(FnID),
Type(TypeID),
}
#[derive(Debug, Clone, Copy)]
pub struct Idents {
pub latest: Ident,
pub var: Option<VarIdent>,
pub func: Option<FnIdent>,
pub var_func: Option<VarOrFnIdent>,
pub ty: Option<TypeIdent>,
pub var: Option<VarID>,
pub func: Option<FnID>,
pub ty: Option<TypeID>,
}
impl Idents {
@@ -181,7 +212,6 @@ impl Idents {
latest,
var: None,
func: None,
var_func: None,
ty: None,
};
s.insert(latest);
@@ -192,50 +222,12 @@ impl Idents {
match i {
Ident::Var(v) => {
self.var = Some(v);
self.var_func = Some(VarOrFnIdent::Var(v));
}
Ident::Fn(f) => {
self.func = Some(f);
self.var_func = Some(VarOrFnIdent::Fn(f));
}
Ident::Type(t) => self.ty = Some(t),
}
}
}
#[derive(Clone, Copy)]
pub struct TypeIdent(usize);
#[derive(Clone, Copy)]
pub struct VarIdent(usize);
#[derive(Clone, Copy)]
pub struct FnIdent(usize);
#[derive(Debug, Clone, Copy)]
pub enum VarOrFnIdent {
Var(VarIdent),
Fn(FnIdent),
}
impl TypeIdent {
pub fn builtin(ty: &BuiltinType) -> Self {
Self(*ty as usize)
}
}
impl Debug for VarIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "v{}", self.0)
}
}
impl Debug for TypeIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "t{}", self.0)
}
}
impl Debug for FnIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "f{}", self.0)
}
}

View File

@@ -1,15 +1,26 @@
use super::{Origin, TypeDef, TypeIdent};
use super::{Origin, TypeDef, TypeID};
#[derive(Clone)]
pub enum Type {
Concrete(TypeIdent),
Generic { base: TypeIdent, args: Vec<Type> },
Concrete(TypeID),
Bits(u32),
Generic { base: TypeID, args: Vec<Type> },
Fn { args: Vec<Type>, ret: Box<Type> },
Ref(Box<Type>),
Array(Box<Type>),
Infer,
Error,
}
impl Type {
pub fn rf(self) -> Self {
Self::Ref(Box::new(self))
}
pub fn arr(self) -> Self {
Self::Array(Box::new(self))
}
}
#[repr(usize)]
#[derive(Debug, Clone, Copy)]
pub enum BuiltinType {
@@ -29,7 +40,14 @@ impl BuiltinType {
},
}
}
pub fn id(&self) -> TypeIdent {
TypeIdent::builtin(self)
pub fn id(&self) -> TypeID {
TypeID::builtin(self)
}
}
impl TypeID {
pub fn builtin(ty: &BuiltinType) -> Self {
Self(*ty as usize)
}
}