Structs and comptime reflection stuff

This commit is contained in:
Mia
2026-03-07 01:42:06 +01:00
parent 81d1dfe3d3
commit fb84e09391
18 changed files with 1399 additions and 321 deletions
+1
View File
@@ -2,3 +2,4 @@ target/
test.leaf test.leaf
out.asm out.asm
a.out a.out
.zed/
Generated
+24
View File
@@ -98,6 +98,12 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]] [[package]]
name = "find-msvc-tools" name = "find-msvc-tools"
version = "0.1.9" version = "0.1.9"
@@ -124,6 +130,22 @@ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "indexmap"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]] [[package]]
name = "inkwell" name = "inkwell"
version = "0.8.0" version = "0.8.0"
@@ -180,6 +202,7 @@ dependencies = [
"derive_more", "derive_more",
"fxhash", "fxhash",
"half", "half",
"indexmap",
"leaf_allocators", "leaf_allocators",
"scc", "scc",
] ]
@@ -216,6 +239,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"arcstr", "arcstr",
"derive_more", "derive_more",
"indexmap",
"peg", "peg",
] ]
+1 -1
View File
@@ -9,6 +9,6 @@ boxcar = "0.2.14"
derive_more = { version = "2.0.1", features = ["deref", "deref_mut", "debug", "display", "try_from", "from", "try_into", "into"] } derive_more = { version = "2.0.1", features = ["deref", "deref_mut", "debug", "display", "try_from", "from", "try_into", "into"] }
half = "2.7.1" half = "2.7.1"
scc = "3.3.7" scc = "3.3.7"
leaf_allocators = { path = "../allocators" } leaf_allocators = { path = "../allocators" }
fxhash = "0.2.1" fxhash = "0.2.1"
indexmap = "2.13.0"
+17 -3
View File
@@ -1,6 +1,9 @@
use crate::{ use crate::{
functions::Function, functions::Function,
types::derivations::{FuncT, TypeDerivations}, types::{
compound::StructT,
derivations::{FuncT, TypeDerivations},
},
}; };
use derive_more::{Debug, Display}; use derive_more::{Debug, Display};
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
@@ -76,6 +79,9 @@ impl<'l> Context<'l> {
} }
pub fn intern_str(&'l self, str: &str) -> &'l str { pub fn intern_str(&'l self, str: &str) -> &'l str {
if str.is_empty() {
return "";
}
if let Some(value) = self.strings.get_sync(str) { if let Some(value) = self.strings.get_sync(str) {
return *value; return *value;
} }
@@ -124,10 +130,18 @@ impl<'l> Assembly<'l> {
&self.ident &self.ident
} }
pub fn create_function(&'l self, ty: &'l FuncT<'l>) -> &'l Function<'l> { pub fn create_struct(&'l self, name: &str) -> &'l StructT<'l> {
self.ctx().alloc.alloc(StructT {
name: self.ctx().intern_str(name),
fields: OnceLock::new(),
declaring_assembly: self,
})
}
pub fn create_function(&'l self, ty: &'l FuncT<'l>, name: &str) -> &'l Function<'l> {
let func = self.ctx.alloc.alloc(Function { let func = self.ctx.alloc.alloc(Function {
ty, ty,
name: OnceLock::new(), name: self.ctx().intern_str(name),
body: OnceLock::new(), body: OnceLock::new(),
declaring_assembly: self, declaring_assembly: self,
}); });
+286 -85
View File
@@ -1,8 +1,8 @@
use crate::{ use crate::{
assembly::Ctx, assembly::Ctx,
functions::{Function, FunctionBody}, functions::{Function, FunctionBody},
types::{IntT, Type, derivations::*}, types::{IntT, Type, compound::StructT, derivations::*},
values::{Value, ValueFlags}, values::{AnyConst, AnyValue, Value, ValueFlags, default_associated_values},
}; };
use derive_more::{Debug, Display}; use derive_more::{Debug, Display};
use std::{borrow::Cow, cell::UnsafeCell, hash::Hash, ops::Deref, sync::OnceLock}; use std::{borrow::Cow, cell::UnsafeCell, hash::Hash, ops::Deref, sync::OnceLock};
@@ -56,19 +56,10 @@ impl<'l> Instruction<'l> {
pub fn id(&self) -> u32 { pub fn id(&self) -> u32 {
unsafe { *self.id.0.get() } unsafe { *self.id.0.get() }
} }
}
pub fn value_flags(&self) -> ValueFlags { impl<'l> Value<'l> for &'l Instruction<'l> {
match self.variant { fn ty(&self) -> Type<'l> {
InstructionVariant::StackAlloc(_) => ValueFlags::LValue,
InstructionVariant::GetElementPtr(v, _) if v.flags().contains(ValueFlags::LValue) => {
ValueFlags::LValue
}
InstructionVariant::Reinterpret(_, _, f) => f,
_ => ValueFlags::empty(),
}
}
pub fn value_ty(&'l self) -> Type<'l> {
match self.variant { match self.variant {
InstructionVariant::Return(_) => Type::Void, InstructionVariant::Return(_) => Type::Void,
InstructionVariant::Store(_, _) => Type::Void, InstructionVariant::Store(_, _) => Type::Void,
@@ -88,6 +79,15 @@ impl<'l> Instruction<'l> {
}) => base.make_ref(*mutable).into(), }) => base.make_ref(*mutable).into(),
_ => unreachable!(), _ => unreachable!(),
}, },
InstructionVariant::GetElementVal(v, i) => match v.ty() {
Type::Struct(StructT { fields, .. }) => {
let AnyValue::Constant(AnyConst::Str(name)) = i else {
unreachable!()
};
fields.get().unwrap()[name].ty
}
_ => unreachable!(),
},
InstructionVariant::IAdd(a, _) => a.ty(), InstructionVariant::IAdd(a, _) => a.ty(),
InstructionVariant::ISub(a, _) => a.ty(), InstructionVariant::ISub(a, _) => a.ty(),
InstructionVariant::IMul(a, _) => a.ty(), InstructionVariant::IMul(a, _) => a.ty(),
@@ -96,12 +96,15 @@ impl<'l> Instruction<'l> {
InstructionVariant::SExt(_, t) => Type::Int(t), InstructionVariant::SExt(_, t) => Type::Int(t),
InstructionVariant::ZExt(_, t) => Type::Int(t), InstructionVariant::ZExt(_, t) => Type::Int(t),
InstructionVariant::Trunc(_, t) => Type::Int(t), InstructionVariant::Trunc(_, t) => Type::Int(t),
InstructionVariant::IntToPtr(_, t) => Type::Ptr(t),
InstructionVariant::PtrToInt(_, t) => Type::Int(t),
InstructionVariant::FAdd(a, _) => a.ty(), InstructionVariant::FAdd(a, _) => a.ty(),
InstructionVariant::FSub(a, _) => a.ty(), InstructionVariant::FSub(a, _) => a.ty(),
InstructionVariant::FMul(a, _) => a.ty(), InstructionVariant::FMul(a, _) => a.ty(),
InstructionVariant::FDiv(a, _) => a.ty(), InstructionVariant::FDiv(a, _) => a.ty(),
InstructionVariant::FMod(a, _) => a.ty(), InstructionVariant::FMod(a, _) => a.ty(),
InstructionVariant::ICmp(_, _, _) => Type::Bool, InstructionVariant::ICmp(_, _, _) => Type::Bool,
InstructionVariant::MakeStruct(t, _) => Type::Struct(t),
InstructionVariant::Call(f, _) => f.ty.ret_t, InstructionVariant::Call(f, _) => f.ty.ret_t,
InstructionVariant::Jump(_) => Type::Void, InstructionVariant::Jump(_) => Type::Void,
InstructionVariant::Branch { .. } => Type::Void, InstructionVariant::Branch { .. } => Type::Void,
@@ -109,6 +112,23 @@ impl<'l> Instruction<'l> {
_ => todo!("{self:?}"), _ => todo!("{self:?}"),
} }
} }
fn flags(&self) -> ValueFlags {
match self.variant {
InstructionVariant::StackAlloc(_) => ValueFlags::LValue,
InstructionVariant::GetElementPtr(v, _) if v.is_lvalue() => ValueFlags::LValue,
InstructionVariant::Reinterpret(_, _, f) => f,
_ => ValueFlags::empty(),
}
}
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
default_associated_values(self, name)
}
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Instruction(self)
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -126,37 +146,42 @@ pub enum InstructionVariant<'l> {
StackAlloc(Type<'l>), StackAlloc(Type<'l>),
GCAlloc(Type<'l>), GCAlloc(Type<'l>),
Load(Value<'l>), Load(AnyValue<'l>),
Store(Value<'l>, Value<'l>), Store(AnyValue<'l>, AnyValue<'l>),
GetElementPtr(Value<'l>, Value<'l>), GetElementVal(AnyValue<'l>, AnyValue<'l>),
GetElementPtr(AnyValue<'l>, AnyValue<'l>),
IAdd(Value<'l>, Value<'l>), IAdd(AnyValue<'l>, AnyValue<'l>),
ISub(Value<'l>, Value<'l>), ISub(AnyValue<'l>, AnyValue<'l>),
IMul(Value<'l>, Value<'l>), IMul(AnyValue<'l>, AnyValue<'l>),
IDiv(Value<'l>, Value<'l>), IDiv(AnyValue<'l>, AnyValue<'l>),
IMod(Value<'l>, Value<'l>), IMod(AnyValue<'l>, AnyValue<'l>),
SExt(Value<'l>, IntT), SExt(AnyValue<'l>, IntT),
ZExt(Value<'l>, IntT), ZExt(AnyValue<'l>, IntT),
Trunc(Value<'l>, IntT), Trunc(AnyValue<'l>, IntT),
FAdd(Value<'l>, Value<'l>), IntToPtr(AnyValue<'l>, &'l PtrT<'l>),
FSub(Value<'l>, Value<'l>), PtrToInt(AnyValue<'l>, IntT),
FMul(Value<'l>, Value<'l>), FAdd(AnyValue<'l>, AnyValue<'l>),
FDiv(Value<'l>, Value<'l>), FSub(AnyValue<'l>, AnyValue<'l>),
FMod(Value<'l>, Value<'l>), FMul(AnyValue<'l>, AnyValue<'l>),
FDiv(AnyValue<'l>, AnyValue<'l>),
FMod(AnyValue<'l>, AnyValue<'l>),
ICmp(Value<'l>, Value<'l>, Cmp), ICmp(AnyValue<'l>, AnyValue<'l>, Cmp),
FCmp(Value<'l>, Value<'l>, Cmp), FCmp(AnyValue<'l>, AnyValue<'l>, Cmp),
Call(&'l Function<'l>, Vec<Value<'l>>), MakeStruct(&'l StructT<'l>, &'l [AnyValue<'l>]),
Call(&'l Function<'l>, Vec<AnyValue<'l>>),
Jump(&'l Block<'l>), Jump(&'l Block<'l>),
Branch { Branch {
cond: Value<'l>, cond: AnyValue<'l>,
true_case: &'l Block<'l>, true_case: &'l Block<'l>,
false_case: &'l Block<'l>, false_case: &'l Block<'l>,
}, },
Return(Option<Value<'l>>), Return(Option<AnyValue<'l>>),
Reinterpret(Value<'l>, Type<'l>, ValueFlags), Reinterpret(AnyValue<'l>, Type<'l>, ValueFlags),
} }
impl InstructionVariant<'_> { impl InstructionVariant<'_> {
@@ -172,7 +197,10 @@ impl std::fmt::Debug for InstructionVariant<'_> {
Self::GCAlloc(ty) => write!(f, "gcalloc {ty}"), Self::GCAlloc(ty) => write!(f, "gcalloc {ty}"),
Self::Load(v) => write!(f, "load {v}"), Self::Load(v) => write!(f, "load {v}"),
Self::Store(t, v) => write!(f, "store {t}, {v}"), Self::Store(t, v) => write!(f, "store {t}, {v}"),
Self::GetElementPtr(t, v) => write!(f, "gep {t}, {v}"), Self::GetElementVal(v, i) => write!(f, "gev {v}, {i}"),
Self::GetElementPtr(v, i) => write!(f, "gep {v}, {i}"),
Self::IntToPtr(v, t) => write!(f, "itp {v}, {t}"),
Self::PtrToInt(v, t) => write!(f, "pti {v}, {t}"),
Self::IAdd(a, b) => write!(f, "iadd {a}, {b}"), Self::IAdd(a, b) => write!(f, "iadd {a}, {b}"),
Self::ISub(a, b) => write!(f, "isub {a}, {b}"), Self::ISub(a, b) => write!(f, "isub {a}, {b}"),
Self::IMul(a, b) => write!(f, "imul {a}, {b}"), Self::IMul(a, b) => write!(f, "imul {a}, {b}"),
@@ -188,11 +216,32 @@ impl std::fmt::Debug for InstructionVariant<'_> {
Self::FMod(a, b) => write!(f, "fmod {a}, {b}"), Self::FMod(a, b) => write!(f, "fmod {a}, {b}"),
Self::ICmp(a, b, c) => write!(f, "icmp {c:?} {a}, {b}"), Self::ICmp(a, b, c) => write!(f, "icmp {c:?} {a}, {b}"),
Self::FCmp(a, b, c) => write!(f, "fcmp {c:?} {a}, {b}"), Self::FCmp(a, b, c) => write!(f, "fcmp {c:?} {a}, {b}"),
Self::MakeStruct(ty, vals) => {
write!(
f,
"struct {} {{",
match ty.name {
"" => "<anonymous struct>",
_ => ty.name,
}
)?;
let mut separator = "";
for val in *vals {
write!(f, "{separator}{val}")?;
separator = ", ";
}
write!(f, "}}")
}
Self::Call(func, args) => { Self::Call(func, args) => {
write!( write!(
f, f,
"call {}(", "call {}(",
func.name.get().unwrap_or(&"<anonymous function>") match func.name {
"" => "<anonymous function>",
_ => func.name,
}
)?; )?;
let mut separator = ""; let mut separator = "";
for arg in args { for arg in args {
@@ -247,16 +296,16 @@ pub type BlockBuilderError<'l> = Cow<'l, str>;
pub type BlockBuilderResult<'l, T> = Result<T, BlockBuilderError<'l>>; pub type BlockBuilderResult<'l, T> = Result<T, BlockBuilderError<'l>>;
impl<'l> BlockBuilder<'l> { impl<'l> BlockBuilder<'l> {
pub fn stack_alloc(&mut self, ty: Type<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn stack_alloc(&mut self, ty: Type<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
let inst = self.push_instruction(InstructionVariant::StackAlloc(ty))?; let inst = self.push_instruction(InstructionVariant::StackAlloc(ty))?;
Ok(inst.into()) Ok(inst.into())
} }
pub fn store( pub fn store(
&mut self, &mut self,
target: Value<'l>, target: AnyValue<'l>,
value: Value<'l>, value: AnyValue<'l>,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
let value_ty = value.ty(); let value_ty = value.ty();
let target_ty = target.ty(); let target_ty = target.ty();
match target_ty { match target_ty {
@@ -281,7 +330,7 @@ impl<'l> BlockBuilder<'l> {
Ok(inst.into()) Ok(inst.into())
} }
pub fn load(&mut self, value: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn load(&mut self, value: AnyValue<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
let value_ty = value.ty(); let value_ty = value.ty();
match value_ty { match value_ty {
Type::Ptr(PtrT { .. }) => {} Type::Ptr(PtrT { .. }) => {}
@@ -294,7 +343,11 @@ impl<'l> BlockBuilder<'l> {
Ok(inst.into()) Ok(inst.into())
} }
pub fn add(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn add(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let [a_ty, b_ty] = [a.ty(), b.ty()]; let [a_ty, b_ty] = [a.ty(), b.ty()];
match (a_ty, b_ty) { match (a_ty, b_ty) {
@@ -310,7 +363,11 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn sub(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn sub(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let [a_ty, b_ty] = [a.ty(), b.ty()]; let [a_ty, b_ty] = [a.ty(), b.ty()];
match (a_ty, b_ty) { match (a_ty, b_ty) {
@@ -326,7 +383,11 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn mul(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn mul(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let [a_ty, b_ty] = [a.ty(), b.ty()]; let [a_ty, b_ty] = [a.ty(), b.ty()];
match (a_ty, b_ty) { match (a_ty, b_ty) {
@@ -342,7 +403,11 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn div(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn div(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let [a_ty, b_ty] = [a.ty(), b.ty()]; let [a_ty, b_ty] = [a.ty(), b.ty()];
match (a_ty, b_ty) { match (a_ty, b_ty) {
@@ -358,7 +423,11 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn modulo(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn modulo(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let [a_ty, b_ty] = [a.ty(), b.ty()]; let [a_ty, b_ty] = [a.ty(), b.ty()];
match (a_ty, b_ty) { match (a_ty, b_ty) {
@@ -374,7 +443,11 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn trunc(&mut self, val: Value<'l>, target: IntT) -> BlockBuilderResult<'l, Value<'l>> { pub fn trunc(
&mut self,
val: AnyValue<'l>,
target: IntT,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let ty = val.ty(); let ty = val.ty();
match ty { match ty {
Type::Int(a_ty) if a_ty.precision > target.precision => { Type::Int(a_ty) if a_ty.precision > target.precision => {
@@ -387,12 +460,29 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn int_to_ptr(
&mut self,
val: AnyValue<'l>,
target: &'l PtrT<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let ty = val.ty();
match ty {
Type::Int(_) => {
let inst = self.push_instruction(InstructionVariant::IntToPtr(val, target))?;
Ok(inst.into())
}
_ => Err(
format!("Cannot convert value of type `{ty}` to pointer type `{target}`.").into(),
),
}
}
pub fn cmp( pub fn cmp(
&mut self, &mut self,
a: Value<'l>, a: AnyValue<'l>,
b: Value<'l>, b: AnyValue<'l>,
cmp: Cmp, cmp: Cmp,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
let [a_ty, b_ty] = [a.ty(), b.ty()]; let [a_ty, b_ty] = [a.ty(), b.ty()];
match (a_ty, b_ty) { match (a_ty, b_ty) {
@@ -408,7 +498,11 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn gep(&mut self, value: Value<'l>, index: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn get_element_ptr(
&mut self,
value: AnyValue<'l>,
index: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let v_ty = value.ty(); let v_ty = value.ty();
let i_ty = index.ty(); let i_ty = index.ty();
@@ -432,7 +526,62 @@ impl<'l> BlockBuilder<'l> {
Ok(inst.into()) Ok(inst.into())
} }
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn get_element_value(
&mut self,
value: AnyValue<'l>,
index: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let v_ty = value.ty();
match v_ty {
Type::Struct(StructT { fields, .. }) => 'val: {
let AnyValue::Constant(AnyConst::Str(field)) = index else {
return Err(
format!("Expeted index type `const str`, found {}.", index.ty()).into(),
);
};
if let Some(fields) = fields.get() {
if fields.contains_key(field) {
let inst =
self.push_instruction(InstructionVariant::GetElementVal(value, index))?;
break 'val Ok(inst.into());
}
}
Err(format!("Struct does not contain field `{field}`.").into())
}
_ => Err(format!("Cannot index a value of type `{}`.", v_ty).into()),
}
}
pub fn make_struct(
&mut self,
struct_ty: &'l StructT<'l>,
values: &'l [AnyValue<'l>],
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let fields = struct_ty.fields.get().unwrap();
if fields.len() != values.len() {
return Err(
format!("Expected {} values, found {}.", fields.len(), values.len()).into(),
);
}
if let Some((i, (a, b))) = fields
.values()
.zip(values)
.enumerate()
.find(|(_, (a, b))| a.ty != b.ty())
{
return Err(format!(
"Invalid valua at position {i}. Expected type `{}`, found `{}`.",
a.ty,
b.ty()
)
.into());
}
let inst = self.push_instruction(InstructionVariant::MakeStruct(struct_ty, values))?;
return Ok(inst.into());
}
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
if !std::ptr::eq(block.func, self.block.func) { if !std::ptr::eq(block.func, self.block.func) {
return Err("Block does not belong to this function.".into()); return Err("Block does not belong to this function.".into());
} }
@@ -442,10 +591,10 @@ impl<'l> BlockBuilder<'l> {
pub fn branch( pub fn branch(
&mut self, &mut self,
cond: Value<'l>, cond: AnyValue<'l>,
true_case: &'l Block<'l>, true_case: &'l Block<'l>,
false_case: &'l Block<'l>, false_case: &'l Block<'l>,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
if !std::ptr::eq(true_case.func, self.block.func) { if !std::ptr::eq(true_case.func, self.block.func) {
return Err("Block does not belong to this function.".into()); return Err("Block does not belong to this function.".into());
} }
@@ -466,8 +615,8 @@ impl<'l> BlockBuilder<'l> {
pub fn call( pub fn call(
&mut self, &mut self,
func: &'l Function<'l>, func: &'l Function<'l>,
args: Vec<Value<'l>>, args: Vec<AnyValue<'l>>,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
let par_t = &*func.ty.par_t; let par_t = &*func.ty.par_t;
if par_t.len() != args.len() { if par_t.len() != args.len() {
return Err(format!( return Err(format!(
@@ -491,7 +640,7 @@ impl<'l> BlockBuilder<'l> {
Ok(inst.into()) Ok(inst.into())
} }
pub fn ret(&mut self, value: Option<Value<'l>>) -> BlockBuilderResult<'l, Value<'l>> { pub fn ret(&mut self, value: Option<AnyValue<'l>>) -> BlockBuilderResult<'l, AnyValue<'l>> {
let ret_t = self.block.func.ty.ret_t; let ret_t = self.block.func.ty.ret_t;
let value_ty = match value { let value_ty = match value {
Some(v) => v.ty(), Some(v) => v.ty(),
@@ -514,10 +663,10 @@ impl<'l> BlockBuilder<'l> {
/// The target reinterpretation must maintain the IR's invariants. /// The target reinterpretation must maintain the IR's invariants.
pub unsafe fn reinterpret( pub unsafe fn reinterpret(
&mut self, &mut self,
value: Value<'l>, value: AnyValue<'l>,
ty: Type<'l>, ty: Type<'l>,
flags: ValueFlags, flags: ValueFlags,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
let inst = self.push_instruction(InstructionVariant::Reinterpret(value, ty, flags))?; let inst = self.push_instruction(InstructionVariant::Reinterpret(value, ty, flags))?;
Ok(inst.into()) Ok(inst.into())
} }
@@ -620,81 +769,133 @@ impl<'l> FunctionBodyBuilder<'l> {
Ok(self.func.body.get().unwrap()) Ok(self.func.body.get().unwrap())
} }
pub fn stack_alloc(&mut self, ty: Type<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn stack_alloc(&mut self, ty: Type<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().stack_alloc(ty) self.current_builder().stack_alloc(ty)
} }
pub fn store( pub fn store(
&mut self, &mut self,
target: Value<'l>, target: AnyValue<'l>,
value: Value<'l>, value: AnyValue<'l>,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().store(target, value) self.current_builder().store(target, value)
} }
pub fn load(&mut self, value: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn load(&mut self, value: AnyValue<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().load(value) self.current_builder().load(value)
} }
pub fn add(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn add(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().add(a, b) self.current_builder().add(a, b)
} }
pub fn sub(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn sub(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().sub(a, b) self.current_builder().sub(a, b)
} }
pub fn mul(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn mul(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().mul(a, b) self.current_builder().mul(a, b)
} }
pub fn div(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn div(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().div(a, b) self.current_builder().div(a, b)
} }
pub fn modulo(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn modulo(
&mut self,
a: AnyValue<'l>,
b: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().modulo(a, b) self.current_builder().modulo(a, b)
} }
pub fn trunc(&mut self, val: Value<'l>, target: IntT) -> BlockBuilderResult<'l, Value<'l>> { pub fn trunc(
&mut self,
val: AnyValue<'l>,
target: IntT,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().trunc(val, target) self.current_builder().trunc(val, target)
} }
pub fn int_to_ptr(
&mut self,
val: AnyValue<'l>,
target: &'l PtrT<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().int_to_ptr(val, target)
}
pub fn cmp( pub fn cmp(
&mut self, &mut self,
a: Value<'l>, a: AnyValue<'l>,
b: Value<'l>, b: AnyValue<'l>,
cmp: Cmp, cmp: Cmp,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().cmp(a, b, cmp) self.current_builder().cmp(a, b, cmp)
} }
pub fn gep(&mut self, value: Value<'l>, index: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn get_element_ptr(
self.current_builder().gep(value, index) &mut self,
value: AnyValue<'l>,
index: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().get_element_ptr(value, index)
} }
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, Value<'l>> { pub fn get_element_value(
&mut self,
value: AnyValue<'l>,
index: AnyValue<'l>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().get_element_value(value, index)
}
pub fn make_struct(
&mut self,
struct_ty: &'l StructT<'l>,
values: &'l [AnyValue<'l>],
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().make_struct(struct_ty, values)
}
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().jump(block) self.current_builder().jump(block)
} }
pub fn branch( pub fn branch(
&mut self, &mut self,
cond: Value<'l>, cond: AnyValue<'l>,
true_case: &'l Block<'l>, true_case: &'l Block<'l>,
false_case: &'l Block<'l>, false_case: &'l Block<'l>,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().branch(cond, true_case, false_case) self.current_builder().branch(cond, true_case, false_case)
} }
pub fn call( pub fn call(
&mut self, &mut self,
func: &'l Function<'l>, func: &'l Function<'l>,
args: Vec<Value<'l>>, args: Vec<AnyValue<'l>>,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().call(func, args) self.current_builder().call(func, args)
} }
pub fn ret(&mut self, value: Option<Value<'l>>) -> BlockBuilderResult<'l, Value<'l>> { pub fn ret(&mut self, value: Option<AnyValue<'l>>) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().ret(value) self.current_builder().ret(value)
} }
@@ -705,10 +906,10 @@ impl<'l> FunctionBodyBuilder<'l> {
/// The target reinterpretation must maintain the IR's invariants. /// The target reinterpretation must maintain the IR's invariants.
pub unsafe fn reinterpret( pub unsafe fn reinterpret(
&mut self, &mut self,
value: Value<'l>, value: AnyValue<'l>,
ty: Type<'l>, ty: Type<'l>,
flags: ValueFlags, flags: ValueFlags,
) -> BlockBuilderResult<'l, Value<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
unsafe { self.current_builder().reinterpret(value, ty, flags) } unsafe { self.current_builder().reinterpret(value, ty, flags) }
} }
+29 -6
View File
@@ -1,7 +1,8 @@
use crate::{ use crate::{
assembly::{Assembly, Ctx}, assembly::{Assembly, Ctx},
functions::ir::{Block, FunctionBodyBuilder}, functions::ir::{Block, FunctionBodyBuilder},
types::derivations::FuncT, types::{Type, derivations::FuncT},
values::{AnyConst, AnyValue, Value, ValueFlags, default_associated_values},
}; };
use std::{ use std::{
fmt::{Debug as FmtDebug, Display}, fmt::{Debug as FmtDebug, Display},
@@ -14,7 +15,7 @@ pub mod ir;
#[non_exhaustive] #[non_exhaustive]
pub struct Function<'l> { pub struct Function<'l> {
pub ty: &'l FuncT<'l>, pub ty: &'l FuncT<'l>,
pub name: OnceLock<&'l str>, pub name: &'l str,
pub(crate) body: OnceLock<FunctionBody<'l>>, pub(crate) body: OnceLock<FunctionBody<'l>>,
pub(crate) declaring_assembly: &'l Assembly<'l>, pub(crate) declaring_assembly: &'l Assembly<'l>,
} }
@@ -40,6 +41,28 @@ impl<'l> Function<'l> {
} }
} }
impl<'l> Value<'l> for &'l Function<'l> {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Func(self.ty)
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Function
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
default_associated_values(self, name)
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Function(self))
}
}
impl Eq for Function<'_> {} impl Eq for Function<'_> {}
impl PartialEq for Function<'_> { impl PartialEq for Function<'_> {
@@ -50,9 +73,9 @@ impl PartialEq for Function<'_> {
impl Display for Function<'_> { impl Display for Function<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.name.get() { match self.name {
Some(n) => write!(f, "{} @ {}", self.ty, n), "" => Display::fmt(&self.ty, f),
None => Display::fmt(&self.ty, f), _ => write!(f, "{} @ {}", self.ty, self.name),
} }
} }
} }
@@ -66,7 +89,7 @@ impl FmtDebug for Function<'_> {
f.debug_struct("Function") f.debug_struct("Function")
.field("ty", &format_args!("{}", self.ty)) .field("ty", &format_args!("{}", self.ty))
.field("name", &self.name.get()) .field("name", &self.name)
.field("body", body) .field("body", body)
.finish_non_exhaustive() .finish_non_exhaustive()
} }
+71
View File
@@ -0,0 +1,71 @@
use crate::{
assembly::Assembly,
types::Type,
values::{AnyConst, AnyValue, Value, ValueFlags},
};
use derive_more::{Debug, Display};
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use std::{hash::Hash, sync::OnceLock};
pub type FieldMap<'l> = IndexMap<&'l str, Field<'l>, FxBuildHasher>;
#[derive(Debug, Display, Clone)]
#[display("{}", if name.is_empty() { "<anonymous struct>" } else { name })]
pub struct StructT<'l> {
pub name: &'l str,
pub fields: OnceLock<FieldMap<'l>>,
#[debug(ignore)]
pub declaring_assembly: &'l Assembly<'l>,
}
impl Eq for StructT<'_> {}
impl PartialEq for StructT<'_> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
}
}
impl Hash for StructT<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::ptr::hash(self, state);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Field<'l> {
pub name: &'l str,
pub ty: Type<'l>,
pub public: bool,
pub mutable: bool,
}
impl<'l> Value<'l> for &'l StructT<'l> {
fn ty(&self) -> Type<'l> {
Type::Type
}
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
todo!()
}
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Struct(self)))
}
}
struct DebugFields<'l, 'r>(&'r OnceLock<FieldMap<'l>>);
impl std::fmt::Debug for DebugFields<'_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0.get() {
Some(v) => std::fmt::Debug::fmt(v, f),
None => f.write_str("{}"),
}
}
}
+133 -8
View File
@@ -61,13 +61,12 @@ impl<'l> TypeDerivations<'l> {
.fun_t .fun_t
.entry_sync((ret_t, par_t.clone())) .entry_sync((ret_t, par_t.clone()))
.or_insert_with(|| { .or_insert_with(|| {
let ctx = ret_t.ctx(); (&*self.alloc.alloc(FuncT {
for ty in par_t.iter() { ret_t,
if ty.ctx() != ctx { par_t,
panic!("All types must share the same context."); par_t_const: OnceLock::new(),
} }))
} .into()
(&*self.alloc.alloc(FuncT { ret_t, par_t })).into()
}) })
else { else {
unreachable!() unreachable!()
@@ -99,6 +98,32 @@ pub struct PtrT<'l> {
pub mutable: bool, pub mutable: bool,
} }
impl<'l> Value<'l> for &'l PtrT<'l> {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match name {
"base" => Some(self.base.as_any_value()),
"mutable" => Some(self.mutable.as_any_value()),
_ => default_associated_values(self, name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Ptr(self)))
}
}
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("&{}{}", if *mutable { "mut " } else { "" }, *base)] #[display("&{}{}", if *mutable { "mut " } else { "" }, *base)]
@@ -108,6 +133,32 @@ pub struct RefT<'l> {
pub mutable: bool, pub mutable: bool,
} }
impl<'l> Value<'l> for &'l RefT<'l> {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match name {
"base" => Some(self.base.as_any_value()),
"mutable" => Some(self.mutable.as_any_value()),
_ => default_associated_values(self, name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Ref(self)))
}
}
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ArrayT<'l> { pub struct ArrayT<'l> {
@@ -116,6 +167,35 @@ pub struct ArrayT<'l> {
pub length: Option<u32>, pub length: Option<u32>,
} }
impl<'l> Value<'l> for &'l ArrayT<'l> {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match name {
"base" => Some(self.base.as_any_value()),
"length" => match self.length {
None => None,
Some(len) => Some(len.as_any_value()),
},
_ => default_associated_values(self, name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Array(self)))
}
}
impl Display for ArrayT<'_> { impl Display for ArrayT<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.length { match self.length {
@@ -126,10 +206,55 @@ impl Display for ArrayT<'_> {
} }
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]
pub struct FuncT<'l> { pub struct FuncT<'l> {
pub ret_t: Type<'l>, pub ret_t: Type<'l>,
pub par_t: Arc<[Type<'l>]>, pub par_t: Arc<[Type<'l>]>,
par_t_const: OnceLock<Vec<AnyConst<'l>>>,
}
impl Eq for FuncT<'_> {}
impl PartialEq for FuncT<'_> {
fn eq(&self, other: &Self) -> bool {
self.ret_t == other.ret_t && self.par_t == other.par_t
}
}
impl Hash for FuncT<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ret_t.hash(state);
self.par_t.hash(state);
}
}
impl<'l> Value<'l> for &'l FuncT<'l> {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match name {
"ret_t" => Some(self.ret_t.as_any_value()),
"par_t" => Some(AnyValue::Constant(AnyConst::Array(
self.par_t_const
.get_or_init(|| self.par_t.iter().map(|t| AnyConst::Type(*t)).collect()),
))),
_ => default_associated_values(self, name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Func(self)))
}
} }
impl Display for FuncT<'_> { impl Display for FuncT<'_> {
+109 -11
View File
@@ -1,8 +1,13 @@
use crate::{assembly::Context, types::derivations::*}; use crate::{
assembly::Context,
types::{compound::*, derivations::*},
values::{AnyConst, AnyValue, Value, ValueFlags, default_associated_values},
};
use derive_more::{Debug, Display, From, TryInto}; use derive_more::{Debug, Display, From, TryInto};
use leaf_allocators::SyncArenaAllocator; use leaf_allocators::SyncArenaAllocator;
use std::{fmt::Display, sync::OnceLock}; use std::{fmt::Display, sync::OnceLock};
pub mod compound;
pub mod derivations; pub mod derivations;
#[non_exhaustive] #[non_exhaustive]
@@ -18,6 +23,32 @@ pub struct IntT {
pub precision: u32, pub precision: u32,
} }
impl<'l> Value<'l> for IntT {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match name {
"signed" => Some(self.signed.as_any_value()),
"precision" => Some(self.precision.as_any_value()),
_ => default_associated_values(self, name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Int(*self)))
}
}
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("f{}", precision)] #[display("f{}", precision)]
@@ -26,6 +57,31 @@ pub struct FloatT {
pub precision: u32, pub precision: u32,
} }
impl<'l> Value<'l> for FloatT {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match name {
"precision" => Some(self.precision.as_any_value()),
_ => default_associated_values(self, name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(Type::Float(*self)))
}
}
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)] #[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
pub enum Type<'l> { pub enum Type<'l> {
@@ -58,6 +114,10 @@ pub enum Type<'l> {
#[debug("{_0:?}")] #[debug("{_0:?}")]
#[display("{_0}")] #[display("{_0}")]
Func(&'l FuncT<'l>), Func(&'l FuncT<'l>),
#[debug("{_0:?}")]
#[display("{_0}")]
Struct(&'l StructT<'l>),
} }
impl<'l> Type<'l> { impl<'l> Type<'l> {
@@ -65,16 +125,7 @@ impl<'l> Type<'l> {
pub fn ctx(&self) -> &'l Context<'l> { pub fn ctx(&self) -> &'l Context<'l> {
match self.non_default_ctx() { match self.non_default_ctx() {
Some(ctx) => ctx, Some(ctx) => ctx,
None => unsafe { None => Self::default_ctx(),
static DEFAULT: OnceLock<&'static Context> = OnceLock::new();
static ALLOCATOR: OnceLock<SyncArenaAllocator> = OnceLock::new();
let ctx: &'static Context = DEFAULT.get_or_init(|| {
let allocator: &'static SyncArenaAllocator =
ALLOCATOR.get_or_init(SyncArenaAllocator::default);
Context::new(allocator)
});
std::mem::transmute(ctx)
},
} }
} }
@@ -94,8 +145,55 @@ impl<'l> Type<'l> {
Some(ctx) => Some(ctx), Some(ctx) => Some(ctx),
None => f.par_t.iter().find_map(|t| t.non_default_ctx()), None => f.par_t.iter().find_map(|t| t.non_default_ctx()),
}, },
Type::Struct(s) => Some(s.declaring_assembly.ctx()),
} }
} }
fn default_ctx() -> &'l Context<'l> {
static ALLOCATOR: OnceLock<SyncArenaAllocator> = OnceLock::new();
static DEFAULT: OnceLock<&'static Context> = OnceLock::new();
let ctx: &'static Context = DEFAULT.get_or_init(|| {
let allocator: &'static SyncArenaAllocator =
ALLOCATOR.get_or_init(SyncArenaAllocator::default);
Context::new(allocator)
});
unsafe { std::mem::transmute(ctx) }
}
}
impl<'l> Value<'l> for Type<'l> {
#[inline]
fn ty(&self) -> Type<'l> {
Type::Type
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Type
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match self {
Type::Void => default_associated_values(self, name),
Type::Char => default_associated_values(self, name),
Type::Bool => default_associated_values(self, name),
Type::Type => default_associated_values(self, name),
Type::ConstStr => default_associated_values(self, name),
Type::Int(t) => t.get_associated_value(name),
Type::Float(t) => t.get_associated_value(name),
Type::Ptr(t) => t.get_associated_value(name),
Type::Ref(t) => t.get_associated_value(name),
Type::Array(t) => t.get_associated_value(name),
Type::Func(t) => t.get_associated_value(name),
Type::Struct(t) => t.get_associated_value(name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Type(*self))
}
} }
#[rustfmt::skip] #[rustfmt::skip]
+186 -42
View File
@@ -1,7 +1,7 @@
use crate::{ use crate::{
functions::Function, functions::Function,
types::{Type, derivations::ArrayT}, types::{Type, compound::StructT, derivations::ArrayT},
values::ValueFlags, values::{AnyValue, Value, ValueFlags, default_associated_values},
}; };
use derive_more::{Debug, *}; use derive_more::{Debug, *};
use half::f16; use half::f16;
@@ -12,18 +12,66 @@ pub enum Int {
I8(i8), I8(i8),
I16(i16), I16(i16),
I32(i32), I32(i32),
I64(i64),
#[from] #[from]
I64(i64),
I128(i128), I128(i128),
ISize(i128), ISize(i64),
U8(u8), U8(u8),
U16(u16), U16(u16),
U32(u32), U32(u32),
U64(u64),
#[from] #[from]
U64(u64),
U128(u128), U128(u128),
USize(u128), USize(u64),
}
impl<'l> Value<'l> for Int {
#[inline]
fn ty(&self) -> Type<'l> {
match self {
Int::I8(v) => v.ty(),
Int::I16(v) => v.ty(),
Int::I32(v) => v.ty(),
Int::I64(v) => v.ty(),
Int::I128(v) => v.ty(),
Int::ISize(_) => Type::ISIZE,
Int::U8(v) => v.ty(),
Int::U16(v) => v.ty(),
Int::U32(v) => v.ty(),
Int::U64(v) => v.ty(),
Int::U128(v) => v.ty(),
Int::USize(_) => Type::USIZE,
}
}
#[inline]
fn flags(&self) -> ValueFlags {
default_value_flags(self)
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match self {
Int::I8(v) => v.get_associated_value(name),
Int::I16(v) => v.get_associated_value(name),
Int::I32(v) => v.get_associated_value(name),
Int::I64(v) => v.get_associated_value(name),
Int::I128(v) => v.get_associated_value(name),
Int::ISize(v) => v.get_associated_value(name),
Int::U8(v) => v.get_associated_value(name),
Int::U16(v) => v.get_associated_value(name),
Int::U32(v) => v.get_associated_value(name),
Int::U64(v) => v.get_associated_value(name),
Int::U128(v) => v.get_associated_value(name),
Int::USize(v) => v.get_associated_value(name),
}
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Int(*self))
}
} }
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq)] #[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq)]
@@ -33,6 +81,33 @@ pub enum Float {
F64(f64), F64(f64),
} }
impl<'l> Value<'l> for Float {
#[inline]
fn ty(&self) -> Type<'l> {
match self {
Float::F16(v) => v.ty(),
Float::F32(v) => v.ty(),
Float::F64(v) => v.ty(),
_ => unreachable!(),
}
}
#[inline]
fn flags(&self) -> ValueFlags {
ValueFlags::Const
}
#[inline]
fn get_associated_value(&self, _name: &str) -> Option<AnyValue<'l>> {
None
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
AnyValue::Constant(AnyConst::Float(*self))
}
}
impl Eq for Float {} impl Eq for Float {}
impl Hash for Float { impl Hash for Float {
@@ -45,20 +120,6 @@ impl Hash for Float {
} }
} }
#[derive(Debug, Display, Deref, DerefMut, Clone, Copy, From, PartialEq, Eq, Hash)]
#[debug("{:?}", _0)]
#[display("{}", _0)]
pub struct Const<T>(T);
impl<'l, T: 'l> From<&'l Const<T>> for AnyConst<'l>
where
for<'a> &'a T: Into<AnyConst<'a>>,
{
fn from(val: &'l Const<T>) -> Self {
(&val.0).into()
}
}
struct ListDisplay<'l>(&'l [AnyConst<'l>]); struct ListDisplay<'l>(&'l [AnyConst<'l>]);
impl std::fmt::Display for ListDisplay<'_> { impl std::fmt::Display for ListDisplay<'_> {
@@ -71,6 +132,19 @@ impl std::fmt::Display for ListDisplay<'_> {
} }
} }
struct StructDisplay<'l>(&'l StructT<'l>, &'l [AnyConst<'l>]);
impl std::fmt::Display for StructDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ", self.0)?;
let mut list = f.debug_list();
for ele in self.1 {
list.entry(&format_args!("{ele}"));
}
list.finish()
}
}
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)] #[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
#[from(forward)] #[from(forward)]
pub enum AnyConst<'l> { pub enum AnyConst<'l> {
@@ -98,45 +172,115 @@ pub enum AnyConst<'l> {
#[debug("{:?}", _0)] #[debug("{:?}", _0)]
#[display("{}", ListDisplay(_0))] #[display("{}", ListDisplay(_0))]
Array(&'l [AnyConst<'l>]), Array(&'l [AnyConst<'l>]),
#[debug("{:?}", _0)]
#[display("{}", StructDisplay(_0, _1))]
Struct(&'l StructT<'l>, &'l [AnyConst<'l>]),
Type(Type<'l>), Type(Type<'l>),
} }
impl<'l> AnyConst<'l> { impl<'l> Value<'l> for AnyConst<'l> {
pub fn ty(&self) -> Type<'l> { fn ty(&self) -> Type<'l> {
match self { match self {
Self::Void => Type::Void, Self::Void => Type::Void,
Self::Bool(_) => Type::Bool, Self::Bool(v) => v.ty(),
Self::Char(_) => Type::Char, Self::Char(v) => v.ty(),
Self::Type(_) => Type::Type, Self::Type(v) => v.ty(),
Self::Int(Int::I8(_)) => Type::I8, Self::Int(v) => v.ty(),
Self::Int(Int::I16(_)) => Type::I16, Self::Float(v) => v.ty(),
Self::Int(Int::I32(_)) => Type::I32,
Self::Int(Int::I64(_)) => Type::I64,
Self::Int(Int::I128(_)) => Type::I128,
Self::Int(Int::ISize(_)) => Type::ISIZE,
Self::Int(Int::U8(_)) => Type::U8,
Self::Int(Int::U16(_)) => Type::U16,
Self::Int(Int::U32(_)) => Type::U32,
Self::Int(Int::U64(_)) => Type::U64,
Self::Int(Int::U128(_)) => Type::U128,
Self::Int(Int::USize(_)) => Type::USIZE,
Self::Float(Float::F16(_)) => Type::F16,
Self::Float(Float::F32(_)) => Type::F32,
Self::Float(Float::F64(_)) => Type::F64,
Self::Array([]) => Type::Array(&ArrayT { Self::Array([]) => Type::Array(&ArrayT {
base: Type::Void, base: Type::Void,
length: Some(0), length: Some(0),
}), }),
Self::Array(a @ [v, ..]) => Type::Array(v.ty().make_array(Some(a.len() as u32))), Self::Array(a @ [v, ..]) => Type::Array(v.ty().make_array(Some(a.len() as u32))),
Self::Str(s) => s.ty(),
Self::Struct(t, _) => Type::Struct(t),
_ => todo!("{self:?}"), _ => todo!("{self:?}"),
} }
} }
pub fn flags(&self) -> super::ValueFlags { fn flags(&self) -> super::ValueFlags {
match self { match self {
AnyConst::Function(_) => ValueFlags::Function, AnyConst::Function(f) => ValueFlags::Function,
AnyConst::Type(_) => ValueFlags::Type, AnyConst::Type(_) => ValueFlags::Type,
_ => ValueFlags::Const, _ => ValueFlags::Const,
} }
} }
fn get_associated_value(&self, name: &str) -> Option<super::AnyValue<'l>> {
match self {
AnyConst::Void => ().get_associated_value(name),
AnyConst::Bool(v) => v.get_associated_value(name),
AnyConst::Char(v) => v.get_associated_value(name),
AnyConst::Int(v) => v.get_associated_value(name),
AnyConst::Float(v) => v.get_associated_value(name),
AnyConst::Str(v) => v.get_associated_value(name),
AnyConst::Function(f) => f.get_associated_value(name),
AnyConst::Array(_) => default_associated_values(self, name),
AnyConst::Struct(t, _) => t.get_associated_value(name),
AnyConst::Type(t) => t.get_associated_value(name),
}
}
fn as_any_value(&self) -> super::AnyValue<'l> {
AnyValue::Constant(*self)
}
}
#[inline]
fn default_value_flags(_: &dyn Value) -> ValueFlags {
ValueFlags::Const
}
macro_rules! impl_value {
($(
$variant:ident : $ty:ty | $leaf_ty:expr => |$ident:ident| $expr:expr,
)*) => {
$(
impl<'l> Value<'l> for $ty {
#[inline]
fn ty(&self) -> Type<'l> {
$leaf_ty
}
#[inline]
fn flags(&self) -> ValueFlags {
default_value_flags(self)
}
#[inline]
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
default_associated_values(self, name)
}
#[inline]
fn as_any_value(&self) -> AnyValue<'l> {
let $ident = self;
$expr
}
}
)*
};
}
impl_value! {
Void: () | Type::Void => |_v| AnyValue::Constant(AnyConst::Void),
Char: char | Type::Char => |v| AnyValue::Constant(AnyConst::Char(*v)),
Bool: bool | Type::Bool => |v| AnyValue::Constant(AnyConst::Bool(*v)),
I8 : i8 | Type::I8 => |v| AnyValue::Constant(AnyConst::Int(Int::I8(*v))),
I16 : i16 | Type::I16 => |v| AnyValue::Constant(AnyConst::Int(Int::I16(*v))),
I32 : i32 | Type::I32 => |v| AnyValue::Constant(AnyConst::Int(Int::I32(*v))),
I64 : i64 | Type::I64 => |v| AnyValue::Constant(AnyConst::Int(Int::I64(*v))),
I128: i128 | Type::I128 => |v| AnyValue::Constant(AnyConst::Int(Int::I128(*v))),
U8 : u8 | Type::U8 => |v| AnyValue::Constant(AnyConst::Int(Int::U8(*v))),
U16 : u16 | Type::U16 => |v| AnyValue::Constant(AnyConst::Int(Int::U16(*v))),
U32 : u32 | Type::U32 => |v| AnyValue::Constant(AnyConst::Int(Int::U32(*v))),
U64 : u64 | Type::U64 => |v| AnyValue::Constant(AnyConst::Int(Int::U64(*v))),
U128: u128 | Type::U128 => |v| AnyValue::Constant(AnyConst::Int(Int::U128(*v))),
F16 : f16 | Type::F16 => |v| AnyValue::Constant(AnyConst::Float(Float::F16(*v))),
F32 : f32 | Type::F32 => |v| AnyValue::Constant(AnyConst::Float(Float::F32(*v))),
F64 : f64 | Type::F64 => |v| AnyValue::Constant(AnyConst::Float(Float::F64(*v))),
ConstStr: &'l str | Type::ConstStr => |v| AnyValue::Constant(AnyConst::Str(*v)),
} }
+48 -13
View File
@@ -23,7 +23,7 @@ bitflags! {
} }
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)] #[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
pub enum Value<'l> { pub enum AnyValue<'l> {
#[display("{_0}")] #[display("{_0}")]
Constant(AnyConst<'l>), Constant(AnyConst<'l>),
#[display("{_0}")] #[display("{_0}")]
@@ -34,27 +34,62 @@ pub enum Value<'l> {
Parameter(usize, &'l Function<'l>), Parameter(usize, &'l Function<'l>),
} }
impl From<Int> for Value<'_> { impl From<Int> for AnyValue<'_> {
fn from(value: Int) -> Self { fn from(value: Int) -> Self {
Value::Constant(AnyConst::Int(value)) AnyValue::Constant(AnyConst::Int(value))
} }
} }
impl<'l> Value<'l> { pub trait Value<'l> {
pub fn ty(&self) -> Type<'l> { fn ty(&self) -> Type<'l>;
fn flags(&self) -> ValueFlags;
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>>;
fn as_any_value(&self) -> AnyValue<'l>;
#[inline]
fn is_const(&self) -> bool {
self.flags().contains(ValueFlags::Const)
}
#[inline]
fn is_lvalue(&self) -> bool {
self.flags().contains(ValueFlags::LValue)
}
}
impl<'l> Value<'l> for AnyValue<'l> {
fn ty(&self) -> Type<'l> {
match self { match self {
Value::Constant(v) => v.ty(), AnyValue::Constant(v) => v.ty(),
Value::Instruction(v) => v.value_ty(), AnyValue::Instruction(v) => v.ty(),
Value::Parameter(i, f) => f.ty.par_t[*i], AnyValue::Parameter(i, f) => f.ty.par_t[*i],
} }
} }
pub fn flags(&self) -> ValueFlags { fn flags(&self) -> ValueFlags {
match self { match self {
Value::Instruction(v) => v.value_flags(), AnyValue::Instruction(v) => v.flags(),
Value::Parameter(_, _) => ValueFlags::empty(), AnyValue::Parameter(_, _) => ValueFlags::empty(),
Value::Constant(c) => c.flags(), AnyValue::Constant(c) => c.flags(),
_ => todo!("{self:?}"),
} }
} }
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match self {
AnyValue::Constant(v) => v.get_associated_value(name),
AnyValue::Instruction(v) => todo!(),
AnyValue::Parameter(_, _) => default_associated_values(self, name),
}
}
fn as_any_value(&self) -> AnyValue<'l> {
*self
}
}
pub(crate) fn default_associated_values<'l>(v: &dyn Value<'l>, name: &str) -> Option<AnyValue<'l>> {
match name {
"#type" => Some(AnyValue::Constant(AnyConst::Type(v.ty()))),
_ => None,
}
} }
+88 -12
View File
@@ -5,7 +5,7 @@ use inkwell::{
module::Module, module::Module,
targets::TargetMachine, targets::TargetMachine,
types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum, IntType}, types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum, IntType},
values::{AnyValue, BasicValue, BasicValueEnum}, values::{AggregateValueEnum, AnyValue as LlvmAnyValue, BasicValue, BasicValueEnum, IntValue},
}; };
use leaf_assembly::{ use leaf_assembly::{
assembly::Assembly, assembly::Assembly,
@@ -15,9 +15,10 @@ use leaf_assembly::{
}, },
types::{ types::{
Type, Type,
compound::{Field, StructT},
derivations::{ArrayT, FuncT, PtrT, RefT}, derivations::{ArrayT, FuncT, PtrT, RefT},
}, },
values::{AnyConst, Int, Value}, values::{AnyConst, AnyValue, Int, Value},
}; };
use scc::HashMap; use scc::HashMap;
@@ -32,6 +33,7 @@ pub struct CompilationContext<'l> {
types: HashMap<Type<'l>, AnyTypeEnum<'l>, FxBuildHasher>, types: HashMap<Type<'l>, AnyTypeEnum<'l>, FxBuildHasher>,
modules: HashMap<&'l Assembly<'l>, Module<'l>, FxBuildHasher>, modules: HashMap<&'l Assembly<'l>, Module<'l>, FxBuildHasher>,
functions: HashMap<(&'l Assembly<'l>, &'l Function<'l>), LlvmFunction<'l>, FxBuildHasher>, functions: HashMap<(&'l Assembly<'l>, &'l Function<'l>), LlvmFunction<'l>, FxBuildHasher>,
fields: HashMap<(&'l StructT<'l>, &'l str), u32, FxBuildHasher>,
} }
impl<'l> CompilationContext<'l> { impl<'l> CompilationContext<'l> {
@@ -41,6 +43,7 @@ impl<'l> CompilationContext<'l> {
types: HashMap::default(), types: HashMap::default(),
modules: HashMap::default(), modules: HashMap::default(),
functions: HashMap::default(), functions: HashMap::default(),
fields: HashMap::default(),
native_int_ty: match target.get_target_data().get_pointer_byte_size(None) { native_int_ty: match target.get_target_data().get_pointer_byte_size(None) {
8 => ctx.i8_type(), 8 => ctx.i8_type(),
16 => ctx.i16_type(), 16 => ctx.i16_type(),
@@ -70,9 +73,9 @@ impl<'l> CompilationContext<'l> {
for (i, func) in assembly.functions() { for (i, func) in assembly.functions() {
let ty = self.get_type(Type::Func(func.ty)).into_function_type(); let ty = self.get_type(Type::Func(func.ty)).into_function_type();
let name = match func.name.get() { let name = match func.name {
Some(n) => *n, "" => &format!("<fn_{i}>"),
None => &format!("<fn_{i}>"), _ => func.name,
}; };
self.functions self.functions
@@ -87,12 +90,12 @@ impl<'l> CompilationContext<'l> {
continue; continue;
}; };
let mut values = FxHashMap::<Value, Option<BasicValueEnum>>::default(); let mut values = FxHashMap::<AnyValue, Option<BasicValueEnum>>::default();
for (i, ty) in func.ty.par_t.iter().enumerate() { for (i, ty) in func.ty.par_t.iter().enumerate() {
let ty = self.get_type(*ty); let ty = self.get_type(*ty);
if BasicMetadataTypeEnum::try_from(ty).is_ok() { if BasicMetadataTypeEnum::try_from(ty).is_ok() {
values.insert( values.insert(
Value::Parameter(i, func), AnyValue::Parameter(i, func),
Some(llvm_func.get_nth_param(values.len() as u32).unwrap()), Some(llvm_func.get_nth_param(values.len() as u32).unwrap()),
); );
} }
@@ -143,7 +146,7 @@ impl<'l> CompilationContext<'l> {
None None
} }
InstructionVariant::GetElementPtr(ptr, idx) => 'val: { InstructionVariant::GetElementPtr(ptr, idx) => 'val: {
let pointee_ty = self.get_type(match inst.value_ty() { let pointee_ty = self.get_type(match inst.ty() {
Type::Ptr(PtrT { base, .. }) => *base, Type::Ptr(PtrT { base, .. }) => *base,
Type::Ref(RefT { base, .. }) => *base, Type::Ref(RefT { base, .. }) => *base,
_ => unreachable!(), _ => unreachable!(),
@@ -159,6 +162,23 @@ impl<'l> CompilationContext<'l> {
Some(ptr.into()) Some(ptr.into())
} }
} }
InstructionVariant::GetElementVal(
val,
AnyValue::Constant(AnyConst::Str(fld)),
) => 'val: {
let Type::Struct(ty) = val.ty() else {
unreachable!()
};
let idx = match self.fields.get_sync(&(ty, *fld)) {
None => break 'val None,
Some(idx) => *idx,
};
let Some(val) = self.get_value(&values, val) else {
break 'val None;
};
let val = val.into_struct_value();
Some(builder.build_extract_value(val, idx, "").unwrap().into())
}
InstructionVariant::IAdd(lhs, rhs) => { InstructionVariant::IAdd(lhs, rhs) => {
let lhs = self.get_value(&values, lhs).unwrap().into_int_value(); let lhs = self.get_value(&values, lhs).unwrap().into_int_value();
@@ -200,6 +220,11 @@ impl<'l> CompilationContext<'l> {
let target = self.get_type(Type::Int(*target)).into_int_type(); let target = self.get_type(Type::Int(*target)).into_int_type();
Some(builder.build_int_truncate(val, target, "").unwrap().into()) Some(builder.build_int_truncate(val, target, "").unwrap().into())
} }
InstructionVariant::IntToPtr(v, ty) => {
let val = self.get_value(&values, v).unwrap().into_int_value();
let ptr = self.get_type(Type::Ptr(ty)).into_pointer_type();
Some(builder.build_int_to_ptr(val, ptr, "").unwrap().into())
}
InstructionVariant::ICmp(lhs, rhs, cmp) => { InstructionVariant::ICmp(lhs, rhs, cmp) => {
let u = !is_signed(lhs.ty()); let u = !is_signed(lhs.ty());
let cmp = match (cmp, u) { let cmp = match (cmp, u) {
@@ -219,6 +244,23 @@ impl<'l> CompilationContext<'l> {
Some(builder.build_int_compare(cmp, lhs, rhs, "").unwrap().into()) Some(builder.build_int_compare(cmp, lhs, rhs, "").unwrap().into())
} }
InstructionVariant::MakeStruct(ty, fields) => {
let ty = self.get_type(Type::Struct(ty)).into_struct_type();
let mut i = 0;
let mut val = ty.get_undef();
for field in *fields {
let Some(field) = self.get_value(&values, field) else {
continue;
};
val = builder
.build_insert_value(val, field, i, "")
.unwrap()
.into_struct_value();
i += 1;
}
Some(val.into())
}
InstructionVariant::Call(func, args) => { InstructionVariant::Call(func, args) => {
// TODO This will fail with external assemblies. Fix this. // TODO This will fail with external assemblies. Fix this.
let func = *self.functions.get_sync(&(assembly, *func)).unwrap(); let func = *self.functions.get_sync(&(assembly, *func)).unwrap();
@@ -290,6 +332,7 @@ impl<'l> CompilationContext<'l> {
return *ty; return *ty;
} }
let mut post_insertion_action = None::<Box<dyn FnOnce()>>;
let llvm_ty = match ty { let llvm_ty = match ty {
Type::Void => self.ctx.void_type().into(), Type::Void => self.ctx.void_type().into(),
Type::I8 | Type::U8 => self.ctx.i8_type().into(), Type::I8 | Type::U8 => self.ctx.i8_type().into(),
@@ -312,6 +355,7 @@ impl<'l> CompilationContext<'l> {
match ret_t { match ret_t {
AnyTypeEnum::VoidType(ty) => ty.fn_type(&par_t, false).into(), AnyTypeEnum::VoidType(ty) => ty.fn_type(&par_t, false).into(),
AnyTypeEnum::IntType(ty) => ty.fn_type(&par_t, false).into(), AnyTypeEnum::IntType(ty) => ty.fn_type(&par_t, false).into(),
AnyTypeEnum::StructType(ty) => ty.fn_type(&par_t, false).into(),
_ => todo!("{ret_t:?}"), _ => todo!("{ret_t:?}"),
} }
} }
@@ -329,23 +373,45 @@ impl<'l> CompilationContext<'l> {
_ => todo!("{ty:#?}"), _ => todo!("{ty:#?}"),
} }
} }
Type::Struct(s @ StructT { fields, name, .. }) => {
let ty = self.ctx.opaque_struct_type(name);
post_insertion_action = Some(Box::new(move || {
let mut types = vec![];
let fields = fields.get().unwrap();
for Field { ty, name, .. } in fields.values() {
if let Ok(ty) = self.get_type(*ty).try_into() {
self.fields
.insert_sync((s, name), types.len() as _)
.unwrap();
types.push(ty);
}
}
ty.set_body(&types, false);
}));
ty.into()
}
_ => todo!("{ty:#?}"), _ => todo!("{ty:#?}"),
}; };
self.types.entry_sync(ty).or_insert(llvm_ty); self.types.entry_sync(ty).or_insert(llvm_ty);
if let Some(post_insertion_action) = post_insertion_action {
post_insertion_action();
}
llvm_ty llvm_ty
} }
#[allow(clippy::mutable_key_type)] #[allow(clippy::mutable_key_type)]
fn get_value( fn get_value(
&self, &self,
map: &FxHashMap<Value<'l>, Option<BasicValueEnum<'l>>>, map: &FxHashMap<AnyValue<'l>, Option<BasicValueEnum<'l>>>,
val: &Value<'l>, val: &AnyValue<'l>,
) -> Option<BasicValueEnum<'l>> { ) -> Option<BasicValueEnum<'l>> {
if let Some(value) = map.get(val) { if let Some(value) = map.get(val) {
return *value; return *value;
} }
match val { match val {
Value::Constant(val) => match val { AnyValue::Constant(val) => match val {
AnyConst::Int(Int::U8(v)) => { AnyConst::Int(Int::U8(v)) => {
Some(self.ctx.i8_type().const_int(*v as u64, false).into()) Some(self.ctx.i8_type().const_int(*v as u64, false).into())
} }
@@ -359,6 +425,7 @@ impl<'l> CompilationContext<'l> {
AnyConst::Int(Int::USize(v)) => { AnyConst::Int(Int::USize(v)) => {
Some(self.native_int_ty.const_int(*v as u64, false).into()) Some(self.native_int_ty.const_int(*v as u64, false).into())
} }
AnyConst::Array([]) => todo!("{val:?}"), AnyConst::Array([]) => todo!("{val:?}"),
AnyConst::Array(array) => { AnyConst::Array(array) => {
let ty = self.get_type(array[0].ty()); let ty = self.get_type(array[0].ty());
@@ -367,7 +434,7 @@ impl<'l> CompilationContext<'l> {
let mut values = vec![]; let mut values = vec![];
for v in *array { for v in *array {
let Some(BasicValueEnum::IntValue(v)) = let Some(BasicValueEnum::IntValue(v)) =
self.get_value(map, &Value::Constant(*v)) self.get_value(map, &AnyValue::Constant(*v))
else { else {
unreachable!(); unreachable!();
}; };
@@ -378,6 +445,15 @@ impl<'l> CompilationContext<'l> {
_ => todo!("{ty:?}"), _ => todo!("{ty:?}"),
} }
} }
AnyConst::Struct(s_ty, vals) => {
let ty = self.get_type(Type::Struct(s_ty)).into_struct_type();
let vals: Vec<_> = vals
.iter()
.filter_map(|v| self.get_value(map, &v.as_any_value()))
.collect();
Some(ty.const_named_struct(&vals).into())
}
_ => todo!("{val:?}"), _ => todo!("{val:?}"),
}, },
_ => unreachable!("{val:#?}"), _ => unreachable!("{val:#?}"),
+6 -1
View File
@@ -14,9 +14,14 @@ pub enum Kind {
SymbolNotFound = 0x0200, SymbolNotFound = 0x0200,
UninitializedSymbol = 0x0201, UninitializedSymbol = 0x0201,
NotAType = 0x0202, NotAType = 0x0202,
NotAFunction = 0x0205,
InvalidIntegerType = 0x0203, InvalidIntegerType = 0x0203,
InvalidType = 0x0204, InvalidType = 0x0204,
NotAFunction = 0x0205,
NotAStruct = 0x0208,
FieldNotFound = 0x0206,
InvalidCast = 0x0207,
UninitializedField = 0x0300,
FunctionCompilationFailed = 0x0301, FunctionCompilationFailed = 0x0301,
} }
+2 -2
View File
@@ -5,7 +5,7 @@ use leaf_assembly::{
assembly::{Assembly, AssemblyIdentifier, Context}, assembly::{Assembly, AssemblyIdentifier, Context},
functions::Function, functions::Function,
types::Type, types::Type,
values::{AnyConst, Value}, values::{AnyConst, AnyValue},
}; };
use leaf_parser::{SourceCode, ast}; use leaf_parser::{SourceCode, ast};
use std::{collections::VecDeque, ops::Deref, sync::Arc}; use std::{collections::VecDeque, ops::Deref, sync::Arc};
@@ -66,7 +66,7 @@ impl<'l> CompilationContext<'l> {
$( $(
scope.insert( scope.insert(
literal_substr!($id), literal_substr!($id),
Value::Constant(AnyConst::Type($ty.into())), AnyValue::Constant(AnyConst::Type($ty.into())),
false, false,
); );
)* )*
+317 -112
View File
@@ -1,17 +1,24 @@
use crate::{FuncQueue, error::*}; use crate::{FuncQueue, error::*};
use arcstr::Substr; use arcstr::{Substr, literal_substr};
use leaf_assembly::{ use leaf_assembly::{
assembly::Assembly, assembly::Assembly,
functions::{ functions::{
Function, Function,
ir::{Cmp, FunctionBodyBuilder}, ir::{Cmp, FunctionBodyBuilder},
}, },
types::{Type, derivations::PtrT}, types::{
values::{AnyConst, Int, Value, ValueFlags}, Type,
compound::{Field, FieldMap, StructT},
derivations::PtrT,
},
values::{AnyConst, AnyValue, Int, Value, ValueFlags},
}; };
use leaf_parser::{ use leaf_parser::{
SourceCode, SourceCode,
ast::{self, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, IndexingExpr, NamePattern, While}, ast::{
self, AccessExpr, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, IndexingExpr, NamePattern,
While,
},
}; };
use std::{ use std::{
collections::HashMap, collections::HashMap,
@@ -26,7 +33,7 @@ struct ExpressionContext<'l, 'r> {
#[derive(Clone)] #[derive(Clone)]
struct Variable<'l> { struct Variable<'l> {
value: Arc<OnceLock<Value<'l>>>, value: Arc<OnceLock<AnyValue<'l>>>,
mutable: bool, mutable: bool,
} }
@@ -46,7 +53,7 @@ impl<'l> Scope<'l> {
} }
} }
pub fn insert(&mut self, name: Substr, value: Value<'l>, mutable: bool) { pub fn insert(&mut self, name: Substr, value: AnyValue<'l>, mutable: bool) {
self.values.insert( self.values.insert(
name, name,
Variable { Variable {
@@ -122,7 +129,7 @@ impl<'l> Scope<'l> {
Type::Void => builder.ret(None).unwrap(), Type::Void => builder.ret(None).unwrap(),
_ => { _ => {
if let Some(expr) = last_expr.as_mut() if let Some(expr) = last_expr.as_mut()
&& expr.flags().contains(ValueFlags::LValue) && expr.is_lvalue()
{ {
*expr = builder.load(*expr).unwrap(); *expr = builder.load(*expr).unwrap();
} }
@@ -139,7 +146,7 @@ impl<'l> Scope<'l> {
&mut self, &mut self,
expr: &Expr, expr: &Expr,
ctx: &mut ExpressionContext<'l, '_>, ctx: &mut ExpressionContext<'l, '_>,
) -> Result<Value<'l>, CompilationError> { ) -> Result<AnyValue<'l>, CompilationError> {
match expr { match expr {
Expr::Ident(Ident(name)) => match self.values.get(name) { Expr::Ident(Ident(name)) => match self.values.get(name) {
None => Err(CompilationError { None => Err(CompilationError {
@@ -167,7 +174,7 @@ impl<'l> Scope<'l> {
Expr::Func(func) => self Expr::Func(func) => self
.make_function(func, ctx) .make_function(func, ctx)
.map(|f| Value::Constant(AnyConst::Function(f))) .map(|f| AnyValue::Constant(AnyConst::Function(f)))
.map_err(|err| CompilationError { .map_err(|err| CompilationError {
kind: Kind::FunctionCompilationFailed, kind: Kind::FunctionCompilationFailed,
message: "Could not compile function.".to_string(), message: "Could not compile function.".to_string(),
@@ -189,7 +196,7 @@ impl<'l> Scope<'l> {
Some(("0x", value)) => <$ty>::from_str_radix(value, 16), Some(("0x", value)) => <$ty>::from_str_radix(value, 16),
_ => n.text.parse::<$ty>(), _ => n.text.parse::<$ty>(),
} }
.map(|v| Value::Constant(AnyConst::Int(Int::$id(v)))) .map(|v| AnyValue::Constant(AnyConst::Int(Int::$id(v))))
.map_err(|_| CompilationError { .map_err(|_| CompilationError {
kind: Kind::InvalidInteger, kind: Kind::InvalidInteger,
message: format!("`{}` is not a valid integer.", n.text), message: format!("`{}` is not a valid integer.", n.text),
@@ -202,19 +209,19 @@ impl<'l> Scope<'l> {
}; };
} }
match n.r#type.as_ref().map(|v| v.as_str()) { match n.r#type.as_ref().map(|v| v.as_str()) {
None => parse_number!(i128, ISize), None => parse_number!(i64, ISize),
Some("i8") => parse_number!(i8, I8), Some("i8") => parse_number!(i8, I8),
Some("i16") => parse_number!(i16, I16), Some("i16") => parse_number!(i16, I16),
Some("i32") => parse_number!(i32, I32), Some("i32") => parse_number!(i32, I32),
Some("i64") => parse_number!(i64, I64), Some("i64") => parse_number!(i64, I64),
Some("i128") => parse_number!(i128, I128), Some("i128") => parse_number!(i128, I128),
Some("isize") => parse_number!(i128, ISize), Some("isize") => parse_number!(i64, ISize),
Some("u8") => parse_number!(u8, U8), Some("u8") => parse_number!(u8, U8),
Some("u16") => parse_number!(u16, U16), Some("u16") => parse_number!(u16, U16),
Some("u32") => parse_number!(u32, U32), Some("u32") => parse_number!(u32, U32),
Some("u64") => parse_number!(u64, U64), Some("u64") => parse_number!(u64, U64),
Some("u128") => parse_number!(u128, U128), Some("u128") => parse_number!(u128, U128),
Some("usize") => parse_number!(u128, USize), Some("usize") => parse_number!(u64, USize),
Some(ty) => Err(CompilationError { Some(ty) => Err(CompilationError {
kind: Kind::InvalidIntegerType, kind: Kind::InvalidIntegerType,
message: format!("`{ty}` is not a valid integer type."), message: format!("`{ty}` is not a valid integer type."),
@@ -227,6 +234,40 @@ impl<'l> Scope<'l> {
} }
} }
Expr::Access(expr) => {
let AccessExpr {
value: value_expr,
field,
} = &**expr;
let value = self.compile_expression(value_expr, ctx)?;
if let Some(value) = value.get_associated_value(&field.0) {
return Ok(value);
}
match value.ty() {
Type::Struct(StructT { fields, .. }) => {
if let Some(fields) = fields.get() {
if let Some(field) = fields.get(field.0.as_str()) {
let builder = ctx.builder.as_mut().unwrap();
return Ok(builder
.get_element_value(value, field.name.as_any_value())
.unwrap()
.as_any_value());
}
}
}
_ => {}
};
return Err(CompilationError {
kind: Kind::FieldNotFound,
message: format!("Value does not contain field `{}`.", field.0),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
cause: None,
});
}
Expr::Binary(bin_expr) => { Expr::Binary(bin_expr) => {
let BinaryExpr { let BinaryExpr {
lhs: lhs_expr, lhs: lhs_expr,
@@ -235,50 +276,98 @@ impl<'l> Scope<'l> {
} = &**bin_expr; } = &**bin_expr;
let mut lhs = self.compile_expression(lhs_expr, ctx)?; let mut lhs = self.compile_expression(lhs_expr, ctx)?;
if lhs.flags().contains(ValueFlags::LValue) && !matches!(op, BinaryOp::Assign(_)) { if lhs.is_lvalue() && !matches!(op, BinaryOp::Assign(_)) {
lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap(); lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap();
} }
let mut rhs = self.compile_expression(rhs_expr, ctx)?; let mut rhs = self.compile_expression(rhs_expr, ctx)?;
if rhs.flags().contains(ValueFlags::LValue) { if rhs.is_lvalue() {
rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap(); rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap();
} }
let builder = ctx.builder.as_mut().unwrap(); let builder = ctx.builder.as_mut().unwrap();
macro_rules! int_bin_ops {
(
const exact
$([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)*
) => {
match op {
$(
$op => match (lhs, rhs) {
$(
(
AnyValue::Constant(AnyConst::Int(Int::$ty($a))),
AnyValue::Constant(AnyConst::Int(Int::$ty($b))),
) => return Ok(AnyValue::Constant(AnyConst::Int(Int::$ty($expr)))),
)*
_ => {}
}
)*
_ => {}
}
};
(
const auto
$([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)*
) => {
match op {
$(
$op => match (lhs, rhs) {
$(
(
AnyValue::Constant(AnyConst::Int(Int::$ty($a))),
AnyValue::Constant(AnyConst::Int(Int::$ty($b))),
) => return Ok($expr.as_any_value()),
)*
_ => {}
}
)*
_ => {}
}
};
}
if lhs.is_const() && rhs.is_const() {
int_bin_ops! {
const exact
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Add(_) => |a, b| a + b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Sub(_) => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Mul(_) => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Div(_) => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Mod(_) => |a, b| a - b,
}
int_bin_ops! {
const auto
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Eq(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Ne(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Lt(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Gt(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Le(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Ge(_) => |a, b| a == b,
}
}
if match (lhs.ty(), rhs.ty()) {
(Type::Int(a_ty), Type::Int(b_ty)) => a_ty == b_ty,
_ => false,
} {
return Ok(match op {
BinaryOp::Add(_) => builder.add(lhs, rhs).unwrap(),
BinaryOp::Sub(_) => builder.sub(lhs, rhs).unwrap(),
BinaryOp::Mul(_) => builder.mul(lhs, rhs).unwrap(),
BinaryOp::Div(_) => builder.div(lhs, rhs).unwrap(),
BinaryOp::Mod(_) => builder.modulo(lhs, rhs).unwrap(),
BinaryOp::Eq(_) => builder.cmp(lhs, rhs, Cmp::Eq).unwrap(),
BinaryOp::Ne(_) => builder.cmp(lhs, rhs, Cmp::Ne).unwrap(),
BinaryOp::Lt(_) => builder.cmp(lhs, rhs, Cmp::Lt).unwrap(),
BinaryOp::Gt(_) => builder.cmp(lhs, rhs, Cmp::Gt).unwrap(),
BinaryOp::Le(_) => builder.cmp(lhs, rhs, Cmp::Le).unwrap(),
BinaryOp::Ge(_) => builder.cmp(lhs, rhs, Cmp::Ge).unwrap(),
_ => todo!("{lhs:?} {op:?} {rhs:?}"),
});
}
match (lhs.ty(), rhs.ty(), op) { match (lhs.ty(), rhs.ty(), op) {
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Add(_)) if a_ty == b_ty => {
Ok(builder.add(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Sub(_)) if a_ty == b_ty => {
Ok(builder.sub(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Mul(_)) if a_ty == b_ty => {
Ok(builder.mul(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Div(_)) if a_ty == b_ty => {
Ok(builder.div(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Mod(_)) if a_ty == b_ty => {
Ok(builder.modulo(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Eq(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Eq).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Ne(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Ne).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Lt(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Lt).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Gt(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Gt).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Le(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Le).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Ge(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Ge).unwrap())
}
(Type::Ptr(PtrT { base, .. }), ty, BinaryOp::Assign(_)) => match *base == ty { (Type::Ptr(PtrT { base, .. }), ty, BinaryOp::Assign(_)) => match *base == ty {
true => Ok(builder.store(lhs, rhs).unwrap()), true => Ok(builder.store(lhs, rhs).unwrap()),
false => Err(CompilationError { false => Err(CompilationError {
@@ -294,25 +383,20 @@ impl<'l> Scope<'l> {
}), }),
}, },
(src_ty, Type::Type, BinaryOp::Cast(_)) => { (src_ty, Type::Type, BinaryOp::Cast(_)) => {
let Value::Constant(AnyConst::Type(dst_ty)) = rhs else { let dst_ty =
return Err(CompilationError { self.assert_ty(rhs, rhs_expr)
kind: Kind::NotAType, .map_err(|err| CompilationError {
message: "Cannot perform cast.".to_string(), kind: Kind::InvalidCast,
location: Location::Range { message: "Cannot perform cast.".to_string(),
file: self.source.clone(),
range: expr.range(),
},
cause: Some(Box::new(CompilationError {
kind: Kind::NotAType,
message: "Cast target is not a type.".to_string(),
location: Location::Range { location: Location::Range {
file: self.source.clone(), file: self.source.clone(),
range: rhs_expr.range(), range: expr.range(),
}, },
cause: None, cause: Some(Box::new(err)),
})), })?;
}); if src_ty == dst_ty {
}; return Ok(lhs);
}
match (src_ty, dst_ty) { match (src_ty, dst_ty) {
(Type::Int(src_ty), Type::Int(dst_ty)) => { (Type::Int(src_ty), Type::Int(dst_ty)) => {
if dst_ty.precision < src_ty.precision { if dst_ty.precision < src_ty.precision {
@@ -320,6 +404,9 @@ impl<'l> Scope<'l> {
} }
todo!("{src_ty} as {dst_ty}"); todo!("{src_ty} as {dst_ty}");
} }
(Type::Int(_), Type::Ptr(dst_ty)) => {
return Ok(builder.int_to_ptr(lhs, dst_ty).unwrap());
}
_ => todo!("{src_ty} as {dst_ty}"), _ => todo!("{src_ty} as {dst_ty}"),
} }
} }
@@ -356,7 +443,7 @@ impl<'l> Scope<'l> {
} }
builder.jump(cond_block).unwrap(); builder.jump(cond_block).unwrap();
builder.set_current_block(exit_block); builder.set_current_block(exit_block);
Ok(last_expr.unwrap_or(Value::Constant(AnyConst::Void))) Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void)))
} }
Expr::Call { Expr::Call {
@@ -364,7 +451,7 @@ impl<'l> Scope<'l> {
args: args_exprs, args: args_exprs,
} => { } => {
let func = match self.compile_expression(func, ctx)? { let func = match self.compile_expression(func, ctx)? {
Value::Constant(AnyConst::Function(func)) => func, AnyValue::Constant(AnyConst::Function(func)) => func,
_ => { _ => {
return Err(CompilationError { return Err(CompilationError {
kind: Kind::NotAFunction, kind: Kind::NotAFunction,
@@ -380,7 +467,7 @@ impl<'l> Scope<'l> {
let mut args = Vec::with_capacity(args_exprs.len()); let mut args = Vec::with_capacity(args_exprs.len());
for expr in args_exprs { for expr in args_exprs {
let mut arg = self.compile_expression(expr, ctx)?; let mut arg = self.compile_expression(expr, ctx)?;
if arg.flags().contains(ValueFlags::LValue) { if arg.is_lvalue() {
arg = ctx.builder.as_mut().unwrap().load(arg).unwrap(); arg = ctx.builder.as_mut().unwrap().load(arg).unwrap();
} }
args.push(arg); args.push(arg);
@@ -390,20 +477,58 @@ impl<'l> Scope<'l> {
} }
Expr::Type(ty_expr) => match &**ty_expr { Expr::Type(ty_expr) => match &**ty_expr {
ast::Type::Ptr { base, mutable } => match self.compile_expression(base, ctx)? { ast::Type::Struct(ast::Struct { fields }) => {
Value::Constant(AnyConst::Type(ty)) => { let name = match &ctx.decl_names {
Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(*mutable))).into()) Some(NamePattern::Single(func_name)) => func_name.0.as_str(),
_ => "",
};
let struct_ty = self.assembly.create_struct(name);
let mut scope = self.clone();
let mut expr_ctx = ExpressionContext {
builder: None,
decl_names: None,
fn_queue: ctx.fn_queue,
};
let ctx = self.assembly.ctx();
scope.insert(literal_substr!("Self"), struct_ty.as_any_value(), false);
let mut field_map = FieldMap::default();
for ast::Field {
name,
ty: ty_expr,
public,
mutable,
} in fields
{
let ty = scope.compile_expression(ty_expr, &mut expr_ctx)?;
let name = ctx.intern_str(&name.0);
field_map.insert(
name,
Field {
name,
ty: self.assert_ty(ty, ty_expr)?,
public: public.is_some(),
mutable: mutable.is_some(),
},
);
} }
Value::Instruction(inst) if inst.value_flags().contains(ValueFlags::LValue) => { struct_ty.fields.set(field_map).unwrap();
Ok(struct_ty.as_any_value())
}
ast::Type::Ptr { base, mutable } => match self.compile_expression(base, ctx)? {
AnyValue::Constant(AnyConst::Type(ty)) => {
Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(mutable.is_some()))).into())
}
AnyValue::Instruction(inst) if inst.is_lvalue() => {
let Type::Ptr(PtrT { let Type::Ptr(PtrT {
base, base,
mutable: is_mut, mutable: is_mut,
.. ..
}) = inst.value_ty() }) = inst.ty()
else { else {
unreachable!() unreachable!()
}; };
if *mutable && !*is_mut { if mutable.is_some() && !*is_mut {
return Err(CompilationError { return Err(CompilationError {
kind: Kind::NotAFunction, kind: Kind::NotAFunction,
message: "Cannot obtain a mutable pointer to an immutable value." message: "Cannot obtain a mutable pointer to an immutable value."
@@ -415,27 +540,28 @@ impl<'l> Scope<'l> {
cause: None, cause: None,
}); });
} }
let mut flags = inst.value_flags(); let mut flags = inst.flags();
let builder = ctx.builder.as_mut().unwrap(); let builder = ctx.builder.as_mut().unwrap();
flags.remove( flags.remove(
ValueFlags::Mutable | ValueFlags::Volatile | ValueFlags::LValue, ValueFlags::Mutable | ValueFlags::Volatile | ValueFlags::LValue,
); );
let ptr = Type::Ptr(base.make_ptr(*mutable)); let ptr = Type::Ptr(base.make_ptr(mutable.is_some()));
unsafe { unsafe {
Ok(builder Ok(builder
.reinterpret(Value::Instruction(inst), ptr, flags) .reinterpret(AnyValue::Instruction(inst), ptr, flags)
.unwrap()) .unwrap())
} }
} }
v => todo!("{v:?}"), v => todo!("{v:?}"),
}, },
v => todo!("{v:#?}"),
}, },
Expr::List(expr) => { Expr::List(expr) => {
let mut expr = expr.iter(); let mut expr = expr.iter();
let mut values = Vec::with_capacity(expr.len()); let mut values = Vec::with_capacity(expr.len());
match expr.next() { match expr.next() {
None => return Ok(Value::Constant(AnyConst::Array(&[]))), None => return Ok(AnyValue::Constant(AnyConst::Array(&[]))),
Some(expr) => { Some(expr) => {
let value = self.compile_expression(expr, ctx)?; let value = self.compile_expression(expr, ctx)?;
// TODO Check if it matches the ctx type hint // TODO Check if it matches the ctx type hint
@@ -445,28 +571,14 @@ impl<'l> Scope<'l> {
let element_ty = values[0].ty(); let element_ty = values[0].ty();
for expr in expr { for expr in expr {
let value = self.compile_expression(expr, ctx)?; let value = self.compile_expression(expr, ctx)?;
if value.ty() != element_ty { self.assert_ty_eq(&value, expr, &element_ty)?;
return Err(CompilationError {
kind: Kind::InvalidType,
message: format!(
"Expected type `{}`, found `{}`",
element_ty,
value.ty()
),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: None,
});
}
values.push(value); values.push(value);
} }
if values.iter().all(|v| matches!(v, Value::Constant(_))) { if values.iter().all(|v| matches!(v, AnyValue::Constant(_))) {
let alloc = self.assembly.ctx().alloc(); let alloc = self.assembly.ctx().alloc();
return Ok(Value::Constant(AnyConst::Array(alloc.alloc_slice( return Ok(AnyValue::Constant(AnyConst::Array(alloc.alloc_slice(
values.into_iter().map(|v| match v { values.into_iter().map(|v| match v {
Value::Constant(c) => c, AnyValue::Constant(c) => c,
_ => unreachable!(), _ => unreachable!(),
}), }),
)))); ))));
@@ -480,7 +592,7 @@ impl<'l> Scope<'l> {
let mut index = self.compile_expression(index, ctx)?; let mut index = self.compile_expression(index, ctx)?;
let builder = ctx.builder.as_mut().unwrap(); let builder = ctx.builder.as_mut().unwrap();
if index.flags().contains(ValueFlags::LValue) { if index.is_lvalue() {
index = builder.load(index).unwrap(); index = builder.load(index).unwrap();
} }
@@ -497,48 +609,111 @@ impl<'l> Scope<'l> {
}); });
} }
if value.flags().contains(ValueFlags::LValue) { if value.is_lvalue() {
let gep = builder.gep(value, index).unwrap(); let gep = builder.get_element_ptr(value, index).unwrap();
return Ok(gep); return Ok(gep);
} }
todo!("{:#?}", value.ty()); todo!("{:#?}", value.ty());
} }
Expr::Struct(ctor) => {
let ty = self.compile_expression(&ctor.r#type, ctx)?;
let AnyValue::Constant(AnyConst::Type(Type::Struct(
struct_ty @ StructT { name, fields, .. },
))) = ty
else {
return Err(CompilationError {
kind: Kind::NotAStruct,
message: format!("Expected struct type, got value of type `{}`.", ty.ty()),
location: Location::Range {
file: self.source.clone(),
range: ctor.r#type.range(),
},
cause: None,
});
};
let mut non_const = false;
let fields = fields.get().unwrap();
let mut values = Vec::with_capacity(fields.len());
for Field {
name: fld_name, ty, ..
} in fields.values()
{
let Some(name_value_pair) = ctor.values.get(*fld_name) else {
return Err(CompilationError {
kind: Kind::UninitializedField,
message: format!("Uninitialized field `{fld_name}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: None,
});
};
let value = self.compile_expression(&name_value_pair.value, ctx)?;
self.assert_ty_eq(&value, &name_value_pair.value, ty)?;
non_const |= !value.flags().contains(ValueFlags::Const);
values.push(value);
}
Ok(match non_const {
true => {
let builder = ctx.builder.as_mut().unwrap();
let values = self.assembly.ctx().alloc().alloc_slice(values.into_iter());
builder.make_struct(struct_ty, values).unwrap()
}
false => AnyValue::Constant(AnyConst::Struct(
struct_ty,
self.assembly
.ctx()
.alloc()
.alloc_slice(values.into_iter().map(|v| {
let AnyValue::Constant(c) = v else {
unreachable!()
};
c
})),
)),
})
}
_ => todo!("{expr:#?}"), _ => todo!("{expr:#?}"),
} }
} }
fn make_function( fn make_function(
&mut self, &mut self,
ast: &ast::Function, ast: &Arc<ast::Function>,
ctx: &mut ExpressionContext<'l, '_>, ctx: &mut ExpressionContext<'l, '_>,
) -> Result<&'l Function<'l>, CompilationError> { ) -> Result<&'l Function<'l>, CompilationError> {
let ret_ty = match ast.ret.as_ref() { let ret_ty = match ast.ret.as_ref() {
None => Value::Constant(AnyConst::Type(Type::Void)), None => AnyValue::Constant(AnyConst::Type(Type::Void)),
Some(ty) => self.compile_expression(ty, ctx)?, Some(ty) => self.compile_expression(ty, ctx)?,
}; };
let ret_ty = self.assert_type(ret_ty)?; let ast_as_expr = Expr::Func(ast.clone());
let ret_ty = self.assert_ty(ret_ty, ast.ret.as_ref().unwrap_or(&ast_as_expr))?;
let mut par_ty = Vec::with_capacity(ast.args.len()); let mut par_ty = Vec::with_capacity(ast.args.len());
for arg in &ast.args { for arg in &ast.args {
let ty = self.compile_expression(&arg.r#type, ctx)?; let ty = self.compile_expression(&arg.value, ctx)?;
let ty = self.assert_type(ty)?; let ty = self.assert_ty(ty, &arg.value)?;
par_ty.push(ty); par_ty.push(ty);
} }
let fn_ty = ret_ty.make_fn(par_ty); let fn_ty = ret_ty.make_fn(par_ty);
let func = self.assembly.create_function(fn_ty); let name = match &ctx.decl_names {
if let Some(NamePattern::Single(func_name)) = &ctx.decl_names { Some(NamePattern::Single(func_name)) => func_name.0.as_str(),
func.name.set(func.ctx().intern_str(&func_name.0)).unwrap(); _ => "",
}; };
let func = self.assembly.create_function(fn_ty, name);
let Some(block) = &ast.block else { let Some(block) = &ast.block else {
return Ok(func); return Ok(func);
}; };
let mut scope = self.clone(); let mut scope = self.clone();
for (i, arg) in ast.args.iter().enumerate() { for (i, arg) in ast.args.iter().enumerate() {
scope.insert(arg.name.0.clone(), Value::Parameter(i, func), false); scope.insert(arg.name.0.clone(), AnyValue::Parameter(i, func), false);
} }
ctx.fn_queue.push_back((func, block.clone(), scope)); ctx.fn_queue.push_back((func, block.clone(), scope));
@@ -552,7 +727,7 @@ impl<'l> Scope<'l> {
value: &Expr, value: &Expr,
mutable: bool, mutable: bool,
ctx: &mut ExpressionContext<'l, '_>, ctx: &mut ExpressionContext<'l, '_>,
) -> Result<Value<'l>, CompilationError> { ) -> Result<AnyValue<'l>, CompilationError> {
let mut sub_ctx = ExpressionContext { let mut sub_ctx = ExpressionContext {
decl_names: Some(names), decl_names: Some(names),
builder: ctx.builder.as_deref_mut(), builder: ctx.builder.as_deref_mut(),
@@ -581,15 +756,45 @@ impl<'l> Scope<'l> {
Ok(AnyConst::Void.into()) Ok(AnyConst::Void.into())
} }
fn assert_type(&self, val: Value<'l>) -> Result<Type<'l>, CompilationError> { fn assert_ty(
&self,
val: AnyValue<'l>,
value_expr: &Expr,
) -> Result<Type<'l>, CompilationError> {
match val { match val {
Value::Constant(AnyConst::Type(ty)) => Ok(ty), AnyValue::Constant(AnyConst::Type(ty)) => Ok(ty),
_ => Err(CompilationError { _ => Err(CompilationError {
kind: Kind::NotAType, kind: Kind::NotAType,
message: "Value is not a type.".to_string(), message: "Value is not a type.".to_string(),
location: Location::None, location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
cause: None, cause: None,
}), }),
} }
} }
pub fn assert_ty_eq(
&self,
value: &AnyValue<'l>,
value_expr: &Expr,
expected: &Type<'l>,
) -> Result<Type<'l>, CompilationError> {
let value_ty = value.ty();
match value_ty == *expected {
true => Ok(value_ty),
false => {
return Err(CompilationError {
kind: Kind::InvalidType,
message: format!("Expected value of type `{expected}`, found `{value_ty}`."),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
cause: None,
});
}
}
}
} }
+1
View File
@@ -6,4 +6,5 @@ edition = "2024"
[dependencies] [dependencies]
arcstr = "1.2.0" arcstr = "1.2.0"
derive_more = { version = "2.1.0", features = ["deref", "debug", "display"] } derive_more = { version = "2.1.0", features = ["deref", "debug", "display"] }
indexmap = "2.13.0"
peg = "0.8.5" peg = "0.8.5"
+33 -4
View File
@@ -1,5 +1,6 @@
use arcstr::Substr; use arcstr::Substr;
use derive_more::Deref; use derive_more::Deref;
use indexmap::IndexMap;
use std::ops::Range; use std::ops::Range;
use std::sync::Arc; use std::sync::Arc;
@@ -27,6 +28,7 @@ pub enum Expr {
#[debug("{_0:?}")] #[debug("{_0:?}")]
Binary(Arc<BinaryExpr>), Binary(Arc<BinaryExpr>),
Index(Arc<IndexingExpr>), Index(Arc<IndexingExpr>),
Access(Arc<AccessExpr>),
Tuple(Vec<Expr>), Tuple(Vec<Expr>),
List(Vec<Expr>), List(Vec<Expr>),
Struct(Arc<StructCtor>), Struct(Arc<StructCtor>),
@@ -56,6 +58,8 @@ impl Expr {
pub fn range(&self) -> Range<usize> { pub fn range(&self) -> Range<usize> {
match self { match self {
Self::Ident(e) => e.range(), Self::Ident(e) => e.range(),
Self::Access(e) => e.range(),
Self::Number(e) => e.text.range(),
_ => todo!("{self:?}"), _ => todo!("{self:?}"),
} }
} }
@@ -74,6 +78,18 @@ pub struct IndexingExpr {
pub index: Expr, pub index: Expr,
} }
#[derive(Debug)]
pub struct AccessExpr {
pub value: Expr,
pub field: Ident,
}
impl AccessExpr {
pub fn range(&self) -> Range<usize> {
self.value.range().start..self.field.0.range().end
}
}
#[rustfmt::skip] #[rustfmt::skip]
#[derive(derive_more::Debug)] #[derive(derive_more::Debug)]
pub enum BinaryOp { pub enum BinaryOp {
@@ -82,7 +98,6 @@ pub enum BinaryOp {
#[debug("{_0}")] Mul(Substr), #[debug("{_0}")] Mul(Substr),
#[debug("{_0}")] Div(Substr), #[debug("{_0}")] Div(Substr),
#[debug("{_0}")] Mod(Substr), #[debug("{_0}")] Mod(Substr),
#[debug("{_0}")] Dot(Substr),
#[debug("{_0}")] Eq(Substr), #[debug("{_0}")] Eq(Substr),
#[debug("{_0}")] Ne(Substr), #[debug("{_0}")] Ne(Substr),
#[debug("{_0}")] Lt(Substr), #[debug("{_0}")] Lt(Substr),
@@ -96,7 +111,8 @@ pub enum BinaryOp {
#[derive(Debug)] #[derive(Debug)]
pub enum Type { pub enum Type {
Ptr { base: Expr, mutable: bool }, Ptr { base: Expr, mutable: Option<Substr> },
Struct(Struct),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -141,13 +157,26 @@ pub struct Function {
#[derive(Debug)] #[derive(Debug)]
pub struct NameValuePair { pub struct NameValuePair {
pub name: Ident, pub name: Ident,
pub r#type: Expr, pub value: Expr,
}
#[derive(Debug)]
pub struct Struct {
pub fields: Vec<Field>,
}
#[derive(Debug)]
pub struct Field {
pub name: Ident,
pub ty: Expr,
pub public: Option<Substr>,
pub mutable: Option<Substr>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct StructCtor { pub struct StructCtor {
pub r#type: Expr, pub r#type: Expr,
pub r#values: Vec<NameValuePair>, pub r#values: IndexMap<Substr, NameValuePair>,
} }
#[derive(Debug)] #[derive(Debug)]
+47 -21
View File
@@ -60,6 +60,9 @@ peg::parser! {
rule ident() -> Ident rule ident() -> Ident
= text:$(['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) { Ident(text) } = text:$(['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) { Ident(text) }
rule ident2() -> Ident
= text:$("#"? ['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) { Ident(text) }
rule string() -> Substr rule string() -> Substr
= str:$("\"" char()* "\"") { str } = str:$("\"" char()* "\"") { str }
@@ -70,29 +73,32 @@ peg::parser! {
// ### EXPRESSIONS #### // ### EXPRESSIONS ####
rule expr() -> Expr = precedence! { rule expr() -> Expr = precedence! {
lhs:(@) __ op:$("as") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) } lhs:(@) __ op:$("as") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) }
-- --
lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) } lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) }
lhs:(@) __ op:$(".") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Dot(op), rhs })) } value:@ __ op:$(".") __ field:ident2() { Expr::Access(AccessExpr { value, field }.into()) }
lhs:(@) "(" __ args:(expr() ** ("," __)) __ ")" { Expr::Call { func: Arc::new(lhs), args } } lhs:@ "(" __ args:(expr() ** list_separator()) __ ")" { Expr::Call { func: Arc::new(lhs), args } }
value:(@) "[" __ index:expr() __ "]" { Expr::Index(Arc::new(IndexingExpr { value, index })) } value:@ "[" __ index:expr() __ "]" { Expr::Index(Arc::new(IndexingExpr { value, index })) }
r#type:(@) _ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Arc::new(StructCtor { r#type, values })) }
r#type:@ __ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Arc::new(StructCtor {
r#type, values: values.into_iter().map(|v| (v.name.0.clone(), v)).collect()
})) }
-- --
lhs:(@) __ op:$("+") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) } lhs:@ __ op:$("+") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) }
lhs:(@) __ op:$("-") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) } lhs:@ __ op:$("-") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) }
-- --
lhs:(@) __ op:$("*") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) } lhs:@ __ op:$("*") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) }
lhs:(@) __ op:$("/") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) } lhs:@ __ op:$("/") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) }
lhs:(@) __ op:$("%") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) } lhs:@ __ op:$("%") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) }
-- --
lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) } lhs:@ __ op:$("..") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) }
-- --
lhs:(@) __ op:$("==") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) } lhs:@ __ op:$("==") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) }
lhs:(@) __ op:$("!=") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) } lhs:@ __ op:$("!=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) }
lhs:(@) __ op:$("<") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) } lhs:@ __ op:$("<") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) }
lhs:(@) __ op:$(">") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) } lhs:@ __ op:$(">") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) }
lhs:(@) __ op:$("<=") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) } lhs:@ __ op:$("<=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) }
lhs:(@) __ op:$(">=") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) } lhs:@ __ op:$(">=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) }
-- --
block:block() { Expr::Block(block)} block:block() { Expr::Block(block)}
for_loop:for_loop() { Expr::For(Arc::new(for_loop))} for_loop:for_loop() { Expr::For(Arc::new(for_loop))}
@@ -103,7 +109,8 @@ peg::parser! {
"(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) } "(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) }
"[" __ list:(expr() ** ("," __)) __ "]" { Expr::List(list) } "[" __ list:(expr() ** ("," __)) __ "]" { Expr::List(list) }
"(" __ v:expr() __ ")" { v } "(" __ v:expr() __ ")" { v }
"*" __ m:"mut"? __ v:expr() { Expr::Type(Arc::new(Type::Ptr { base:v, mutable: m.is_some() })) } "*" __ m:$"mut"? __ v:expr() { Expr::Type(Arc::new(Type::Ptr { base:v, mutable: m })) }
v:struct_t() { Expr::Type(Arc::new(Type::Struct(v))) }
v:string() { Expr::String(v) } v:string() { Expr::String(v) }
v:number() { Expr::Number(v) } v:number() { Expr::Number(v) }
v:ident() { Expr::Ident(v) } v:ident() { Expr::Ident(v) }
@@ -113,14 +120,32 @@ peg::parser! {
= "{" __ exprs:(i:expr() statement_separator() {i})* __ "}" { Block(exprs) } = "{" __ exprs:(i:expr() statement_separator() {i})* __ "}" { Block(exprs) }
rule func() -> Function rule func() -> Function
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!() = s:position!() t:$"fn" __ "(" __ args:name_type_pairs() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!()
{ Function { args, ret, block: block.map(Arc::new), text: t.parent().substr(s..e), } } { Function { args, ret, block: block.map(Arc::new), text: t.parent().substr(s..e), } }
rule name_type_pair() -> NameValuePair
= name:ident() __ ":" __ value:expr() { NameValuePair { name, value } }
rule name_type_pairs() -> Vec<NameValuePair>
= v:(name_type_pair() **<1,> list_separator()) list_separator()? { v }
/ { vec![] }
rule name_value_pair() -> NameValuePair rule name_value_pair() -> NameValuePair
= name:ident() __ ":" __ r#type:expr() { NameValuePair { name, r#type } } = name:ident() __ "=" __ value:expr() { NameValuePair { name, value } }
rule name_value_pairs() -> Vec<NameValuePair> rule name_value_pairs() -> Vec<NameValuePair>
= v:(name_value_pair() ** ("," __)) { v } = v:(name_value_pair() **<1,> list_separator()) list_separator()? { v }
/ { vec![] }
rule struct_t() -> Struct
= "struct" __ "{" __ fields:fields() __ "}" { Struct { fields } }
rule field() -> Field
= public:$"pub"? __ mutable:$"mut"? __ name:ident() __ ":" __ ty:expr() { Field { name, ty, public, mutable } }
rule fields() -> Vec<Field>
= v:(field() **<1,> list_separator()) list_separator()? { v }
/ { vec![] }
rule import() -> Import rule import() -> Import
= "import" _ expr:expr() { Import(expr) } = "import" _ expr:expr() { Import(expr) }
@@ -156,6 +181,7 @@ peg::parser! {
rule _ = quiet! { [' '|'\t']+ } rule _ = quiet! { [' '|'\t']+ }
rule __ = quiet! { [' '|'\t'|'\n']* } rule __ = quiet! { [' '|'\t'|'\n']* }
rule statement_separator() = quiet! { [';'|'\n'] __ } rule statement_separator() = quiet! { [';'|'\n'] __ }
rule list_separator() = quiet! { [','|'\n'] __ }
} }
} }