Ifs and Phis

This commit is contained in:
Mia
2026-03-07 16:24:32 +01:00
parent fb84e09391
commit 168a12b4fc
11 changed files with 612 additions and 150 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
target/ target/
test.leaf *.leaf
out.asm *.asm
a.out a.out
.zed/ .zed/
+156 -26
View File
@@ -5,7 +5,13 @@ use crate::{
values::{AnyConst, AnyValue, Value, ValueFlags, default_associated_values}, 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, atomic::AtomicU16},
};
// Maybe unsafe but honestly it's extremely unlikely that this will go wrong and it won't cause any issues. // Maybe unsafe but honestly it's extremely unlikely that this will go wrong and it won't cause any issues.
struct Id(UnsafeCell<u32>); struct Id(UnsafeCell<u32>);
@@ -17,6 +23,8 @@ unsafe impl Sync for Id {}
#[display("%{}", unsafe { *id.0.get() })] #[display("%{}", unsafe { *id.0.get() })]
pub struct Instruction<'l> { pub struct Instruction<'l> {
id: Id, id: Id,
ty: OnceLock<Type<'l>>,
flags: AtomicU16,
pub parent_block: &'l Block<'l>, pub parent_block: &'l Block<'l>,
pub variant: InstructionVariant<'l>, pub variant: InstructionVariant<'l>,
} }
@@ -56,11 +64,19 @@ impl<'l> Instruction<'l> {
pub fn id(&self) -> u32 { pub fn id(&self) -> u32 {
unsafe { *self.id.0.get() } unsafe { *self.id.0.get() }
} }
#[inline]
pub unsafe fn edit_flags(&self, edit: impl FnOnce(ValueFlags) -> ValueFlags) {
let flags = self.flags.load(std::sync::atomic::Ordering::Relaxed);
let flags = edit(ValueFlags::from_bits_retain(flags));
self.flags
.store(flags.bits(), std::sync::atomic::Ordering::Relaxed);
}
} }
impl<'l> Value<'l> for &'l Instruction<'l> { impl<'l> Value<'l> for &'l Instruction<'l> {
fn ty(&self) -> Type<'l> { fn ty(&self) -> Type<'l> {
match self.variant { *self.ty.get_or_init(|| match self.variant {
InstructionVariant::Return(_) => Type::Void, InstructionVariant::Return(_) => Type::Void,
InstructionVariant::Store(_, _) => Type::Void, InstructionVariant::Store(_, _) => Type::Void,
InstructionVariant::StackAlloc(ty) => ty.make_ptr(true).into(), InstructionVariant::StackAlloc(ty) => ty.make_ptr(true).into(),
@@ -68,7 +84,7 @@ impl<'l> Value<'l> for &'l Instruction<'l> {
Type::Ptr(PtrT { base, .. }) => *base, Type::Ptr(PtrT { base, .. }) => *base,
_ => unreachable!(), _ => unreachable!(),
}, },
InstructionVariant::GetElementPtr(v, _) => match v.ty() { InstructionVariant::GetElementPtr(v, i) => match v.ty() {
Type::Ptr(PtrT { Type::Ptr(PtrT {
base: Type::Array(ArrayT { base, .. }), base: Type::Array(ArrayT { base, .. }),
mutable, mutable,
@@ -77,6 +93,26 @@ impl<'l> Value<'l> for &'l Instruction<'l> {
base: Type::Array(ArrayT { base, .. }), base: Type::Array(ArrayT { base, .. }),
mutable, mutable,
}) => base.make_ref(*mutable).into(), }) => base.make_ref(*mutable).into(),
Type::Ptr(PtrT {
base: Type::Struct(StructT { fields, .. }),
mutable,
}) => {
let fields = fields.get().unwrap();
let AnyValue::Constant(AnyConst::Str(name)) = i else {
unreachable!();
};
fields[name].ty.make_ptr(*mutable).into()
}
Type::Ref(RefT {
base: Type::Struct(StructT { fields, .. }),
mutable,
}) => {
let fields = fields.get().unwrap();
let AnyValue::Constant(AnyConst::Str(name)) = i else {
unreachable!();
};
fields[name].ty.make_ref(*mutable).into()
}
_ => unreachable!(), _ => unreachable!(),
}, },
InstructionVariant::GetElementVal(v, i) => match v.ty() { InstructionVariant::GetElementVal(v, i) => match v.ty() {
@@ -108,18 +144,13 @@ impl<'l> Value<'l> for &'l Instruction<'l> {
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,
InstructionVariant::Reinterpret(_, t, _) => t, InstructionVariant::Reinterpret(_, t) => t,
_ => todo!("{self:?}"), _ => todo!("{self:?}"),
} })
} }
fn flags(&self) -> ValueFlags { fn flags(&self) -> ValueFlags {
match self.variant { ValueFlags::from_bits_retain(self.flags.load(std::sync::atomic::Ordering::Relaxed))
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>> { fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
@@ -141,6 +172,13 @@ pub enum Cmp {
Ge, Ge,
} }
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("[{value}, #{block}]")]
pub struct PhiValue<'l> {
pub block: u32,
pub value: AnyValue<'l>,
}
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub enum InstructionVariant<'l> { pub enum InstructionVariant<'l> {
StackAlloc(Type<'l>), StackAlloc(Type<'l>),
@@ -171,6 +209,7 @@ pub enum InstructionVariant<'l> {
FCmp(AnyValue<'l>, AnyValue<'l>, Cmp), FCmp(AnyValue<'l>, AnyValue<'l>, Cmp),
MakeStruct(&'l StructT<'l>, &'l [AnyValue<'l>]), MakeStruct(&'l StructT<'l>, &'l [AnyValue<'l>]),
Phi(&'l [PhiValue<'l>]),
Call(&'l Function<'l>, Vec<AnyValue<'l>>), Call(&'l Function<'l>, Vec<AnyValue<'l>>),
Jump(&'l Block<'l>), Jump(&'l Block<'l>),
@@ -181,7 +220,7 @@ pub enum InstructionVariant<'l> {
}, },
Return(Option<AnyValue<'l>>), Return(Option<AnyValue<'l>>),
Reinterpret(AnyValue<'l>, Type<'l>, ValueFlags), Reinterpret(AnyValue<'l>, Type<'l>),
} }
impl InstructionVariant<'_> { impl InstructionVariant<'_> {
@@ -217,6 +256,15 @@ impl std::fmt::Debug for InstructionVariant<'_> {
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::Phi(values) => {
write!(f, "phi")?;
let mut separator = " ";
for val in *values {
write!(f, "{separator}{val}")?;
separator = ", ";
}
Ok(())
}
Self::MakeStruct(ty, vals) => { Self::MakeStruct(ty, vals) => {
write!( write!(
f, f,
@@ -258,7 +306,7 @@ impl std::fmt::Debug for InstructionVariant<'_> {
Self::Jump(b) => write!(f, "jump #{}", b.id), Self::Jump(b) => write!(f, "jump #{}", b.id),
Self::Return(None) => write!(f, "return"), Self::Return(None) => write!(f, "return"),
Self::Return(Some(v)) => write!(f, "return {v}"), Self::Return(Some(v)) => write!(f, "return {v}"),
Self::Reinterpret(v, t, fl) => write!(f, "reinterpret {v} as {t} {fl:?}"), Self::Reinterpret(v, t) => write!(f, "reinterpret {v} as {t}"),
} }
} }
} }
@@ -288,7 +336,7 @@ impl PartialEq for Block<'_> {
} }
pub struct BlockBuilder<'l> { pub struct BlockBuilder<'l> {
block: &'l Block<'l>, pub block: &'l Block<'l>,
instructions: Vec<&'l Instruction<'l>>, instructions: Vec<&'l Instruction<'l>>,
} }
@@ -298,6 +346,10 @@ 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, AnyValue<'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))?;
inst.flags.store(
ValueFlags::LValue.bits(),
std::sync::atomic::Ordering::Relaxed,
);
Ok(inst.into()) Ok(inst.into())
} }
@@ -477,6 +529,24 @@ impl<'l> BlockBuilder<'l> {
} }
} }
pub fn ptr_to_int(
&mut self,
val: AnyValue<'l>,
target: IntT,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
let ty = val.ty();
match ty {
Type::Ptr(_) => {
let inst = self.push_instruction(InstructionVariant::PtrToInt(val, target))?;
Ok(inst.into())
}
_ => Err(format!(
"Cannot convert non-pointer value of type `{ty}` to integer `{target}`."
)
.into()),
}
}
pub fn cmp( pub fn cmp(
&mut self, &mut self,
a: AnyValue<'l>, a: AnyValue<'l>,
@@ -506,23 +576,48 @@ impl<'l> BlockBuilder<'l> {
let v_ty = value.ty(); let v_ty = value.ty();
let i_ty = index.ty(); let i_ty = index.ty();
let _ = match v_ty { match v_ty {
Type::Ptr(PtrT { Type::Ptr(PtrT {
base: Type::Array(ArrayT { base, .. }), base: Type::Array(ArrayT { .. }),
.. ..
}) => *base, })
Type::Ref(RefT { | Type::Ref(RefT {
base: Type::Array(ArrayT { base, .. }), base: Type::Array(ArrayT { .. }),
.. ..
}) => *base, }) => {
if i_ty != Type::USIZE {
return Err(format!("Expeted index type `usize`, found {i_ty}.").into());
}
}
Type::Ptr(PtrT {
base: Type::Struct(StructT { fields, .. }),
..
})
| Type::Ref(RefT {
base: Type::Struct(StructT { fields, .. }),
..
}) => {
if i_ty != Type::ConstStr {
return Err(format!("Expeted index type `const str`, found {i_ty}.").into());
}
let AnyValue::Constant(AnyConst::Str(name)) = index else {
unreachable!();
};
let fields = fields.get().unwrap();
if !fields.contains_key(name) {
return Err(format!("Type `{v_ty}` does not contain field `{name}`.").into());
}
}
_ => return Err(format!("Cannot index a value of type `{}`.", v_ty).into()), _ => return Err(format!("Cannot index a value of type `{}`.", v_ty).into()),
}; };
if i_ty != Type::USIZE {
return Err(format!("Expeted index type `usize`, found {}.", i_ty).into());
}
let inst = self.push_instruction(InstructionVariant::GetElementPtr(value, index))?; let inst = self.push_instruction(InstructionVariant::GetElementPtr(value, index))?;
if value.is_lvalue() {
inst.flags.store(
ValueFlags::LValue.bits(),
std::sync::atomic::Ordering::Relaxed,
);
}
Ok(inst.into()) Ok(inst.into())
} }
@@ -571,7 +666,7 @@ impl<'l> BlockBuilder<'l> {
.find(|(_, (a, b))| a.ty != b.ty()) .find(|(_, (a, b))| a.ty != b.ty())
{ {
return Err(format!( return Err(format!(
"Invalid valua at position {i}. Expected type `{}`, found `{}`.", "Invalid value at position {i}. Expected type `{}`, found `{}`.",
a.ty, a.ty,
b.ty() b.ty()
) )
@@ -581,6 +676,22 @@ impl<'l> BlockBuilder<'l> {
return Ok(inst.into()); return Ok(inst.into());
} }
pub fn phi(
&mut self,
values: impl ExactSizeIterator<Item = PhiValue<'l>>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
if values.len() < 2 {
return Err("Instruction requires at least two values.".into());
}
let values = self.block.func.ctx().alloc.alloc_slice(values);
let ty = values[0].value.ty();
if values.iter().any(|v| v.value.ty() != ty) {
return Err("All values must have the same type.".into());
}
let inst = self.push_instruction(InstructionVariant::Phi(values))?;
Ok(inst.into())
}
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> { 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());
@@ -667,7 +778,9 @@ impl<'l> BlockBuilder<'l> {
ty: Type<'l>, ty: Type<'l>,
flags: ValueFlags, flags: ValueFlags,
) -> BlockBuilderResult<'l, AnyValue<'l>> { ) -> BlockBuilderResult<'l, AnyValue<'l>> {
let inst = self.push_instruction(InstructionVariant::Reinterpret(value, ty, flags))?; let inst = self.push_instruction(InstructionVariant::Reinterpret(value, ty))?;
inst.flags
.store(flags.bits(), std::sync::atomic::Ordering::Relaxed);
Ok(inst.into()) Ok(inst.into())
} }
@@ -697,6 +810,8 @@ impl<'l> BlockBuilder<'l> {
let instruction = &*self.block.func.ctx().alloc.alloc(Instruction { let instruction = &*self.block.func.ctx().alloc.alloc(Instruction {
id: Id(UnsafeCell::new(u32::MAX)), id: Id(UnsafeCell::new(u32::MAX)),
parent_block: self.block, parent_block: self.block,
ty: OnceLock::new(),
flags: AtomicU16::new(0),
variant, variant,
}); });
self.instructions.push(instruction); self.instructions.push(instruction);
@@ -841,6 +956,14 @@ impl<'l> FunctionBodyBuilder<'l> {
self.current_builder().int_to_ptr(val, target) self.current_builder().int_to_ptr(val, target)
} }
pub fn ptr_to_int(
&mut self,
val: AnyValue<'l>,
target: IntT,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().ptr_to_int(val, target)
}
pub fn cmp( pub fn cmp(
&mut self, &mut self,
a: AnyValue<'l>, a: AnyValue<'l>,
@@ -874,6 +997,13 @@ impl<'l> FunctionBodyBuilder<'l> {
self.current_builder().make_struct(struct_ty, values) self.current_builder().make_struct(struct_ty, values)
} }
pub fn phi(
&mut self,
values: impl ExactSizeIterator<Item = PhiValue<'l>>,
) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().phi(values)
}
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> { pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, AnyValue<'l>> {
self.current_builder().jump(block) self.current_builder().jump(block)
} }
+29 -12
View File
@@ -49,6 +49,23 @@ impl<'l> Value<'l> for IntT {
} }
} }
#[rustfmt::skip]
impl IntT {
pub const I8: Self = IntT { signed: true, precision: 8 };
pub const I16: Self = IntT { signed: true, precision: 16 };
pub const I32: Self = IntT { signed: true, precision: 32 };
pub const I64: Self = IntT { signed: true, precision: 64 };
pub const I128: Self = IntT { signed: true, precision: 128 };
pub const ISIZE: Self = IntT { signed: true, precision: u32::MAX };
pub const U8: Self = IntT { signed: false, precision: 8 };
pub const U16: Self = IntT { signed: false, precision: 16 };
pub const U32: Self = IntT { signed: false, precision: 32 };
pub const U64: Self = IntT { signed: false, precision: 64 };
pub const U128: Self = IntT { signed: false, precision: 128 };
pub const USIZE: Self = IntT { signed: false, precision: u32::MAX };
}
#[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)]
@@ -198,19 +215,19 @@ impl<'l> Value<'l> for Type<'l> {
#[rustfmt::skip] #[rustfmt::skip]
impl Type<'_> { impl Type<'_> {
pub const I8: Self = Type::Int(IntT { signed: true, precision: 8 }); pub const I8: Self = Type::Int(IntT::I8);
pub const I16: Self = Type::Int(IntT { signed: true, precision: 16 }); pub const I16: Self = Type::Int(IntT::I16);
pub const I32: Self = Type::Int(IntT { signed: true, precision: 32 }); pub const I32: Self = Type::Int(IntT::I32);
pub const I64: Self = Type::Int(IntT { signed: true, precision: 64 }); pub const I64: Self = Type::Int(IntT::I64);
pub const I128: Self = Type::Int(IntT { signed: true, precision: 128 }); pub const I128: Self = Type::Int(IntT::I128);
pub const ISIZE: Self = Type::Int(IntT { signed: true, precision: u32::MAX }); pub const ISIZE: Self = Type::Int(IntT::ISIZE);
pub const U8: Self = Type::Int(IntT { signed: false, precision: 8 }); pub const U8: Self = Type::Int(IntT::U8);
pub const U16: Self = Type::Int(IntT { signed: false, precision: 16 }); pub const U16: Self = Type::Int(IntT::U16);
pub const U32: Self = Type::Int(IntT { signed: false, precision: 32 }); pub const U32: Self = Type::Int(IntT::U32);
pub const U64: Self = Type::Int(IntT { signed: false, precision: 64 }); pub const U64: Self = Type::Int(IntT::U64);
pub const U128: Self = Type::Int(IntT { signed: false, precision: 128 }); pub const U128: Self = Type::Int(IntT::U128);
pub const USIZE: Self = Type::Int(IntT { signed: false, precision: u32::MAX }); pub const USIZE: Self = Type::Int(IntT::USIZE);
pub const F16: Self = Type::Float(FloatT { precision: 16 }); pub const F16: Self = Type::Float(FloatT { precision: 16 });
pub const F32: Self = Type::Float(FloatT { precision: 32 }); pub const F32: Self = Type::Float(FloatT { precision: 32 });
+6
View File
@@ -176,6 +176,10 @@ pub enum AnyConst<'l> {
#[display("{}", StructDisplay(_0, _1))] #[display("{}", StructDisplay(_0, _1))]
Struct(&'l StructT<'l>, &'l [AnyConst<'l>]), Struct(&'l StructT<'l>, &'l [AnyConst<'l>]),
Type(Type<'l>), Type(Type<'l>),
#[from(ignore)]
#[debug("SizeOf({:?})", _0)]
#[display("size_of({_0})")]
SizeOf(Type<'l>),
} }
impl<'l> Value<'l> for AnyConst<'l> { impl<'l> Value<'l> for AnyConst<'l> {
@@ -194,6 +198,7 @@ impl<'l> Value<'l> for AnyConst<'l> {
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::Str(s) => s.ty(),
Self::Struct(t, _) => Type::Struct(t), Self::Struct(t, _) => Type::Struct(t),
Self::SizeOf(_) => Type::USIZE,
_ => todo!("{self:?}"), _ => todo!("{self:?}"),
} }
} }
@@ -218,6 +223,7 @@ impl<'l> Value<'l> for AnyConst<'l> {
AnyConst::Array(_) => default_associated_values(self, name), AnyConst::Array(_) => default_associated_values(self, name),
AnyConst::Struct(t, _) => t.get_associated_value(name), AnyConst::Struct(t, _) => t.get_associated_value(name),
AnyConst::Type(t) => t.get_associated_value(name), AnyConst::Type(t) => t.get_associated_value(name),
AnyConst::SizeOf(_) => Type::USIZE.get_associated_value(name),
} }
} }
+1 -1
View File
@@ -77,7 +77,7 @@ impl<'l> Value<'l> for AnyValue<'l> {
fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> { fn get_associated_value(&self, name: &str) -> Option<AnyValue<'l>> {
match self { match self {
AnyValue::Constant(v) => v.get_associated_value(name), AnyValue::Constant(v) => v.get_associated_value(name),
AnyValue::Instruction(v) => todo!(), AnyValue::Instruction(_) => default_associated_values(self, name),
AnyValue::Parameter(_, _) => default_associated_values(self, name), AnyValue::Parameter(_, _) => default_associated_values(self, name),
} }
} }
+105 -22
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::{AggregateValueEnum, AnyValue as LlvmAnyValue, BasicValue, BasicValueEnum, IntValue}, values::{AnyValue as LlvmAnyValue, BasicValue, BasicValueEnum},
}; };
use leaf_assembly::{ use leaf_assembly::{
assembly::Assembly, assembly::Assembly,
@@ -45,11 +45,11 @@ impl<'l> CompilationContext<'l> {
functions: HashMap::default(), functions: HashMap::default(),
fields: 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(), 1 => ctx.i8_type(),
16 => ctx.i16_type(), 2 => ctx.i16_type(),
32 => ctx.i32_type(), 4 => ctx.i32_type(),
64 => ctx.i64_type(), 8 => ctx.i64_type(),
128 => ctx.i128_type(), 16 => ctx.i128_type(),
_ => unreachable!(), _ => unreachable!(),
}, },
} }
@@ -146,20 +146,61 @@ impl<'l> CompilationContext<'l> {
None None
} }
InstructionVariant::GetElementPtr(ptr, idx) => 'val: { InstructionVariant::GetElementPtr(ptr, idx) => 'val: {
let pointee_ty = self.get_type(match inst.ty() { let ptr_val =
Type::Ptr(PtrT { base, .. }) => *base, self.get_value(&values, ptr).unwrap().into_pointer_value();
Type::Ref(RefT { base, .. }) => *base,
_ => unreachable!(), match ptr.ty() {
}); Type::Ptr(PtrT {
let Ok(pointee_ty): Result<BasicTypeEnum, _> = pointee_ty.try_into() base: Type::Array(_),
else { ..
break 'val None; })
}; | Type::Ref(RefT {
let ptr = self.get_value(&values, ptr).unwrap().into_pointer_value(); base: Type::Array(_),
let idx = self.get_value(&values, idx).unwrap().into_int_value(); ..
unsafe { }) => unsafe {
let ptr = builder.build_gep(pointee_ty, ptr, &[idx], "").unwrap(); let pointee_ty = match inst.ty() {
Some(ptr.into()) Type::Ptr(PtrT { base, .. }) => *base,
Type::Ref(RefT { base, .. }) => *base,
_ => unreachable!(),
};
let Ok(pointee): Result<BasicTypeEnum, _> =
self.get_type(pointee_ty).try_into()
else {
break 'val None;
};
let idx =
self.get_value(&values, idx).unwrap().into_int_value();
let ptr =
builder.build_gep(pointee, ptr_val, &[idx], "").unwrap();
Some(ptr.into())
},
Type::Ptr(PtrT {
base: Type::Struct(ty),
..
})
| Type::Ref(RefT {
base: Type::Struct(ty),
..
}) => {
let Ok(pointee): Result<BasicTypeEnum, _> =
self.get_type(Type::Struct(ty)).try_into()
else {
break 'val None;
};
let AnyValue::Constant(AnyConst::Str(name)) = idx else {
unreachable!()
};
let idx = match self.fields.get_sync(&(*ty, *name)) {
Some(idx) => *idx,
None => break 'val None,
};
let ptr = builder
.build_struct_gep(pointee, ptr_val, idx, "")
.unwrap();
Some(ptr.into())
}
_ => unreachable!("{}", ptr.ty()),
} }
} }
InstructionVariant::GetElementVal( InstructionVariant::GetElementVal(
@@ -225,6 +266,11 @@ impl<'l> CompilationContext<'l> {
let ptr = self.get_type(Type::Ptr(ty)).into_pointer_type(); let ptr = self.get_type(Type::Ptr(ty)).into_pointer_type();
Some(builder.build_int_to_ptr(val, ptr, "").unwrap().into()) Some(builder.build_int_to_ptr(val, ptr, "").unwrap().into())
} }
InstructionVariant::PtrToInt(v, ty) => {
let val = self.get_value(&values, v).unwrap().into_pointer_value();
let int = self.get_type(Type::Int(*ty)).into_int_type();
Some(builder.build_ptr_to_int(val, int, "").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) {
@@ -261,6 +307,26 @@ impl<'l> CompilationContext<'l> {
Some(val.into()) Some(val.into())
} }
InstructionVariant::Phi(phi_values) => 'val: {
let Ok(ty): Result<BasicTypeEnum, _> =
self.get_type(phi_values[0].value.ty()).try_into()
else {
break 'val None;
};
let llvm_vals: Vec<_> = phi_values
.iter()
.map(|v| self.get_value(&values, &v.value).unwrap())
.collect();
let llvm_vals: Vec<_> = phi_values
.iter()
.zip(&llvm_vals)
.map(|(p, v)| (v as &dyn BasicValue, blocks[p.block as usize]))
.collect();
let phi = builder.build_phi(ty, "").unwrap();
phi.add_incoming(&llvm_vals);
Some(phi.as_basic_value())
}
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();
@@ -307,7 +373,7 @@ impl<'l> CompilationContext<'l> {
None None
} }
InstructionVariant::Reinterpret(v, t, _) => match (v.ty(), t) { InstructionVariant::Reinterpret(v, t) => match (v.ty(), t) {
(Type::Ptr(_), Type::Ptr(_)) => { (Type::Ptr(_), Type::Ptr(_)) => {
Some(self.get_value(&values, v).unwrap()) Some(self.get_value(&values, v).unwrap())
} }
@@ -356,6 +422,7 @@ impl<'l> CompilationContext<'l> {
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(), AnyTypeEnum::StructType(ty) => ty.fn_type(&par_t, false).into(),
AnyTypeEnum::PointerType(ty) => ty.fn_type(&par_t, false).into(),
_ => todo!("{ret_t:?}"), _ => todo!("{ret_t:?}"),
} }
} }
@@ -454,6 +521,15 @@ impl<'l> CompilationContext<'l> {
.collect(); .collect();
Some(ty.const_named_struct(&vals).into()) Some(ty.const_named_struct(&vals).into())
} }
AnyConst::SizeOf(Type::Int(ty)) => {
let ty = self.get_type(Type::Int(*ty)).into_int_type();
Some(
ty.size_of()
.const_truncate_or_bit_cast(self.native_int_ty)
.into(),
)
}
_ => todo!("{val:?}"), _ => todo!("{val:?}"),
}, },
_ => unreachable!("{val:#?}"), _ => unreachable!("{val:#?}"),
@@ -464,7 +540,14 @@ impl<'l> CompilationContext<'l> {
#[inline] #[inline]
fn is_signed(ty: Type) -> bool { fn is_signed(ty: Type) -> bool {
match ty { match ty {
Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128 | Type::USIZE => false, Type::U8
| Type::U16
| Type::U32
| Type::U64
| Type::U128
| Type::USIZE
| Type::Ptr(_)
| Type::Ref(_) => false,
Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 | Type::ISIZE => true, Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 | Type::ISIZE => true,
_ => unreachable!(), _ => unreachable!(),
} }
+1
View File
@@ -20,6 +20,7 @@ pub enum Kind {
NotAStruct = 0x0208, NotAStruct = 0x0208,
FieldNotFound = 0x0206, FieldNotFound = 0x0206,
InvalidCast = 0x0207, InvalidCast = 0x0207,
CannotDereference = 0x0209,
UninitializedField = 0x0300, UninitializedField = 0x0300,
+6 -6
View File
@@ -10,7 +10,10 @@ use leaf_backend_llvm::{
}; };
use leaf_compiler::CompilationContext; use leaf_compiler::CompilationContext;
use leaf_parser::SourceCode; use leaf_parser::SourceCode;
use std::{path::PathBuf, sync::Arc}; use std::{
path::{Path, PathBuf},
sync::Arc,
};
fn main() { fn main() {
let alloc = SyncArenaAllocator::default(); let alloc = SyncArenaAllocator::default();
@@ -54,10 +57,7 @@ fn main() {
module.print_to_stderr(); module.print_to_stderr();
module.verify().unwrap(); module.verify().unwrap();
let asm = target_machine target_machine
.write_to_memory_buffer(&module, FileType::Assembly) .write_to_file(&module, FileType::Assembly, Path::new("out.asm"))
.unwrap(); .unwrap();
let asm = std::str::from_utf8(asm.as_slice()).unwrap();
eprintln!("{asm}");
std::fs::write("out.asm", asm).unwrap();
} }
+238 -40
View File
@@ -4,20 +4,20 @@ use leaf_assembly::{
assembly::Assembly, assembly::Assembly,
functions::{ functions::{
Function, Function,
ir::{Cmp, FunctionBodyBuilder}, ir::{Cmp, FunctionBodyBuilder, PhiValue},
}, },
types::{ types::{
Type, IntT, Type,
compound::{Field, FieldMap, StructT}, compound::{Field, FieldMap, StructT},
derivations::PtrT, derivations::{PtrT, RefT},
}, },
values::{AnyConst, AnyValue, Int, Value, ValueFlags}, values::{AnyConst, AnyValue, Int, Value, ValueFlags},
}; };
use leaf_parser::{ use leaf_parser::{
SourceCode, SourceCode,
ast::{ ast::{
self, AccessExpr, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, IndexingExpr, NamePattern, self, AccessExpr, BinaryExpr, BinaryOp, Block, ConstDecl, Else, Expr, Ident, If,
While, IndexingExpr, NamePattern, While,
}, },
}; };
use std::{ use std::{
@@ -109,31 +109,30 @@ impl<'l> Scope<'l> {
pub fn compile_function( pub fn compile_function(
&mut self, &mut self,
func: &'l Function<'l>, func: &'l Function<'l>,
block: &ast::Block, block: &Arc<ast::Block>,
fn_queue: &mut FuncQueue<'l>, fn_queue: &mut FuncQueue<'l>,
) -> Result<(), CompilationError> { ) -> Result<(), CompilationError> {
let mut builder = func.create_body().unwrap(); let mut builder = func.create_body().unwrap();
let mut ctx = ExpressionContext { let mut ret = self.compile_block(
builder: Some(&mut builder), block,
decl_names: None, &mut ExpressionContext {
fn_queue: fn_queue, builder: Some(&mut builder),
}; decl_names: None,
fn_queue: fn_queue,
let mut last_expr = None; },
for expr in &block.0 { )?;
last_expr = Some(self.compile_expression(expr, &mut ctx)?);
}
if !builder.current_block().has_termination() { if !builder.current_block().has_termination() {
match func.ty.ret_t { match func.ty.ret_t {
Type::Void => builder.ret(None).unwrap(), Type::Void => {
builder.ret(None).unwrap();
}
_ => { _ => {
if let Some(expr) = last_expr.as_mut() if ret.is_lvalue() {
&& expr.is_lvalue() ret = builder.load(ret).unwrap();
{
*expr = builder.load(*expr).unwrap();
} }
builder.ret(last_expr).unwrap() self.assert_ty_eq(&ret, &Expr::Block(block.clone()), &func.ty.ret_t)?;
builder.ret(Some(ret)).unwrap();
} }
}; };
} }
@@ -255,6 +254,28 @@ impl<'l> Scope<'l> {
} }
} }
} }
Type::Ptr(PtrT {
base: 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();
let inst = builder
.get_element_ptr(value, field.name.as_any_value())
.unwrap()
.as_any_value();
unsafe {
if let AnyValue::Instruction(inst) = inst {
inst.edit_flags(|f| f | ValueFlags::LValue);
}
}
return Ok(inst);
}
}
}
_ => {} _ => {}
}; };
return Err(CompilationError { return Err(CompilationError {
@@ -347,7 +368,9 @@ impl<'l> Scope<'l> {
} }
} }
if match (lhs.ty(), rhs.ty()) { let (lhs_ty, rhs_ty) = (lhs.ty(), rhs.ty());
if match (lhs_ty, rhs_ty) {
(Type::Int(a_ty), Type::Int(b_ty)) => a_ty == b_ty, (Type::Int(a_ty), Type::Int(b_ty)) => a_ty == b_ty,
_ => false, _ => false,
} { } {
@@ -367,7 +390,31 @@ impl<'l> Scope<'l> {
}); });
} }
match (lhs.ty(), rhs.ty(), op) { if match (lhs_ty, rhs_ty) {
(Type::Ptr(a_ty), Type::Ptr(b_ty)) => a_ty == b_ty,
_ => false,
} {
let lhs = builder.ptr_to_int(lhs, IntT::USIZE).unwrap();
let rhs = builder.ptr_to_int(rhs, IntT::USIZE).unwrap();
return Ok(match op {
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) {
(Type::Ptr(ptr @ PtrT { base, .. }), Type::USIZE, BinaryOp::Add(_)) => {
let mut value = builder.ptr_to_int(lhs, IntT::USIZE).unwrap();
let add = builder.mul(rhs, AnyConst::SizeOf(*base).into()).unwrap();
value = builder.add(value, add).unwrap();
value = builder.int_to_ptr(value, ptr).unwrap();
Ok(value)
}
(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 {
@@ -407,6 +454,9 @@ impl<'l> Scope<'l> {
(Type::Int(_), Type::Ptr(dst_ty)) => { (Type::Int(_), Type::Ptr(dst_ty)) => {
return Ok(builder.int_to_ptr(lhs, dst_ty).unwrap()); return Ok(builder.int_to_ptr(lhs, dst_ty).unwrap());
} }
(Type::Ptr(_), dst_ty @ Type::Ptr(_)) => unsafe {
return Ok(builder.reinterpret(lhs, dst_ty, lhs.flags()).unwrap());
},
_ => todo!("{src_ty} as {dst_ty}"), _ => todo!("{src_ty} as {dst_ty}"),
} }
} }
@@ -414,8 +464,10 @@ impl<'l> Scope<'l> {
} }
} }
Expr::If(expr) => self.compile_if(expr, ctx),
Expr::While(expr) => { Expr::While(expr) => {
let While { value, block } = &**expr; let While { cond, block } = &**expr;
let mut builder = ctx.builder.as_mut().unwrap(); let mut builder = ctx.builder.as_mut().unwrap();
let cond_block = builder.create_block(); let cond_block = builder.create_block();
@@ -424,26 +476,18 @@ impl<'l> Scope<'l> {
builder.jump(cond_block).unwrap(); builder.jump(cond_block).unwrap();
builder.set_current_block(cond_block); builder.set_current_block(cond_block);
let condition = self.compile_expression(value, ctx)?; let condition = self.compile_expression(cond, ctx)?;
builder = ctx.builder.as_mut().unwrap(); builder = ctx.builder.as_mut().unwrap();
builder.branch(condition, exec_block, exit_block).unwrap(); builder.branch(condition, exec_block, exit_block).unwrap();
builder.set_current_block(exec_block); builder.set_current_block(exec_block);
let mut scope = self.clone(); let ret = self.compile_block(block, ctx)?;
let mut ctx = ExpressionContext { builder = ctx.builder.as_mut().unwrap();
builder: Some(builder),
decl_names: None,
fn_queue: ctx.fn_queue,
};
let mut last_expr = None;
for expr in &block.0 {
last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
}
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(AnyValue::Constant(AnyConst::Void))) Ok(ret)
} }
Expr::Call { Expr::Call {
@@ -586,9 +630,63 @@ impl<'l> Scope<'l> {
todo!() todo!()
} }
Expr::Deref(expr) => {
let value = self.compile_expression(expr, ctx)?;
let builder = ctx.builder.as_mut().unwrap();
let ty = value.ty();
match value.is_lvalue() {
false => unsafe {
if !matches!(ty, Type::Ptr(_)) {
return Err(CompilationError {
kind: Kind::CannotDereference,
message: format!("Cannot dereference a value of type `{ty}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: None,
});
}
Ok(builder
.reinterpret(value, value.ty(), value.flags() | ValueFlags::LValue)
.unwrap())
},
true => unsafe {
if !matches!(
ty,
Type::Ptr(PtrT {
base: Type::Ptr(_),
..
})
) {
let Type::Ptr(PtrT { base, .. }) = ty else {
unreachable!()
};
return Err(CompilationError {
kind: Kind::CannotDereference,
message: format!("Cannot dereference a value of type `{base}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: None,
});
}
let AnyValue::Instruction(value) = builder.load(value).unwrap() else {
unreachable!()
};
value.edit_flags(|v| v | ValueFlags::LValue);
Ok(AnyValue::Instruction(value))
},
_ => unimplemented!("{}", value.is_lvalue()),
}
}
Expr::Index(expr) => { Expr::Index(expr) => {
let IndexingExpr { value, index } = &**expr; let IndexingExpr { value, index } = &**expr;
let value = self.compile_expression(value, ctx)?; let mut value = self.compile_expression(value, ctx)?;
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();
@@ -609,6 +707,21 @@ impl<'l> Scope<'l> {
}); });
} }
// TODO This is probably wrong, make it better.
while value.is_lvalue()
&& !matches!(
value.ty(),
Type::Ptr(PtrT {
base: Type::Array(_),
..
}) | Type::Ref(RefT {
base: Type::Array(_),
..
})
) {
value = builder.load(value).unwrap();
}
if value.is_lvalue() { if value.is_lvalue() {
let gep = builder.get_element_ptr(value, index).unwrap(); let gep = builder.get_element_ptr(value, index).unwrap();
return Ok(gep); return Ok(gep);
@@ -620,7 +733,7 @@ impl<'l> Scope<'l> {
Expr::Struct(ctor) => { Expr::Struct(ctor) => {
let ty = self.compile_expression(&ctor.r#type, ctx)?; let ty = self.compile_expression(&ctor.r#type, ctx)?;
let AnyValue::Constant(AnyConst::Type(Type::Struct( let AnyValue::Constant(AnyConst::Type(Type::Struct(
struct_ty @ StructT { name, fields, .. }, struct_ty @ StructT { fields, .. },
))) = ty ))) = ty
else { else {
return Err(CompilationError { return Err(CompilationError {
@@ -734,8 +847,11 @@ impl<'l> Scope<'l> {
fn_queue: ctx.fn_queue, fn_queue: ctx.fn_queue,
}; };
let mut value = self.compile_expression(value, &mut sub_ctx)?; let mut value = self.compile_expression(value, &mut sub_ctx)?;
let builder = sub_ctx.builder.unwrap();
if value.is_lvalue() {
value = builder.load(value).unwrap();
}
if mutable { if mutable {
let builder = sub_ctx.builder.unwrap();
let variable = builder.stack_alloc(value.ty()).unwrap(); let variable = builder.stack_alloc(value.ty()).unwrap();
builder.store(variable, value).unwrap(); builder.store(variable, value).unwrap();
value = variable; value = variable;
@@ -756,6 +872,88 @@ impl<'l> Scope<'l> {
Ok(AnyConst::Void.into()) Ok(AnyConst::Void.into())
} }
fn compile_block(
&mut self,
expr: &Block,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> {
let mut scope = self.clone();
let builder = ctx.builder.as_mut().unwrap();
let mut ctx = ExpressionContext {
builder: Some(builder),
decl_names: None,
fn_queue: ctx.fn_queue,
};
let mut last_expr = None;
for expr in &expr.0 {
last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
}
Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void)))
}
fn compile_if(
&mut self,
expr: &If,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> {
let If { cond, block, else_ } = expr;
let condition = self.compile_expression(cond, ctx)?;
self.assert_ty_eq(&condition, cond, &Type::Bool)?;
let builder = ctx.builder.as_mut().unwrap();
let then_block = builder.create_block();
let else_block = builder.create_block();
builder.branch(condition, then_block, else_block).unwrap();
builder.set_current_block(then_block);
let then_val = self.compile_block(block, ctx)?;
let builder = ctx.builder.as_mut().unwrap();
let else_ = match else_ {
None => {
builder.jump(else_block).unwrap();
builder.set_current_block(else_block);
return Ok(then_val);
}
Some(else_) => else_,
};
let continue_block = builder.create_block();
builder.jump(continue_block).unwrap();
builder.set_current_block(else_block);
let else_val = match &**else_ {
Else::Block(block) => self.compile_block(block, ctx)?,
Else::If(if_) => self.compile_if(if_, ctx)?,
};
let builder = ctx.builder.as_mut().unwrap();
builder.jump(continue_block).unwrap();
builder.set_current_block(continue_block);
if then_val.ty() != else_val.ty() {
todo!()
}
Ok(builder
.phi(
[
PhiValue {
value: then_val,
block: then_block.id,
},
PhiValue {
value: else_val,
block: else_block.id,
},
]
.into_iter(),
)
.unwrap()
.into())
}
fn assert_ty( fn assert_ty(
&self, &self,
val: AnyValue<'l>, val: AnyValue<'l>,
+28 -12
View File
@@ -26,30 +26,33 @@ pub enum Expr {
Number(Number), Number(Number),
String(Substr), String(Substr),
#[debug("{_0:?}")] #[debug("{_0:?}")]
Binary(Arc<BinaryExpr>), Binary(Box<BinaryExpr>),
Index(Arc<IndexingExpr>), Index(Box<IndexingExpr>),
Access(Arc<AccessExpr>), Access(Box<AccessExpr>),
Deref(Box<Expr>),
Tuple(Vec<Expr>), Tuple(Vec<Expr>),
List(Vec<Expr>), List(Vec<Expr>),
Struct(Arc<StructCtor>), Struct(Box<StructCtor>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
Block(Block), Block(Arc<Block>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
Func(Arc<Function>), Func(Arc<Function>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
Type(Arc<Type>), Type(Box<Type>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
ConstDecl(Arc<ConstDecl>), ConstDecl(Box<ConstDecl>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
VarDecl(Arc<VarDecl>), VarDecl(Box<VarDecl>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
For(Arc<For>), For(Box<For>),
#[debug("{_0:?}")] #[debug("{_0:?}")]
While(Arc<While>), While(Box<While>),
#[debug("{_0:?}")]
If(Box<If>),
Call { Call {
func: Arc<Expr>, func: Box<Expr>,
args: Vec<Expr>, args: Vec<Expr>,
}, },
} }
@@ -191,10 +194,23 @@ pub struct For {
#[derive(Debug)] #[derive(Debug)]
pub struct While { pub struct While {
pub value: Expr, pub cond: Expr,
pub block: Block, pub block: Block,
} }
#[derive(Debug)]
pub struct If {
pub cond: Expr,
pub block: Block,
pub else_: Option<Box<Else>>,
}
#[derive(Debug)]
pub enum Else {
If(If),
Block(Block),
}
#[derive(Debug)] #[derive(Debug)]
pub struct CompilationUnit { pub struct CompilationUnit {
pub imports: Vec<Import>, pub imports: Vec<Import>,
+40 -29
View File
@@ -73,44 +73,48 @@ peg::parser! {
// ### EXPRESSIONS #### // ### EXPRESSIONS ####
rule expr() -> Expr = precedence! { rule expr() -> Expr = precedence! {
lhs:(@) __ op:$("as") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) } lhs:(@) __ op:$("as") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs }.into()) }
-- --
lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) } lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs }.into()) }
value:@ __ op:$(".") __ field:ident2() { Expr::Access(AccessExpr { value, field }.into()) } value:@ __ op:$(".") __ field:ident2() { Expr::Access(AccessExpr { value, field }.into()) }
lhs:@ "(" __ args:(expr() ** list_separator()) __ ")" { Expr::Call { func: Arc::new(lhs), args } } value:@ __ op:$(".^") { Expr::Deref(value.into()) }
value:@ "[" __ index:expr() __ "]" { Expr::Index(Arc::new(IndexingExpr { value, index })) } lhs:@ "(" __ args:(expr() ** list_separator()) __ ")" { Expr::Call { func: lhs.into(), args } }
value:@ "[" __ index:expr() __ "]" { Expr::Index(IndexingExpr { value, index }.into()) }
r#type:@ __ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Arc::new(StructCtor { r#type:@ __ "#{" __ values:name_value_pairs() __ "}" { Expr::Struct(
r#type, values: values.into_iter().map(|v| (v.name.0.clone(), v)).collect() StructCtor {
})) } r#type, values: values.into_iter().map(|v| (v.name.0.clone(), v)).collect()
}.into()
) }
-- --
lhs:@ __ op:$("+") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) } lhs:@ __ op:$("+") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs }.into()) }
lhs:@ __ op:$("-") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) } lhs:@ __ op:$("-") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs }.into()) }
-- --
lhs:@ __ op:$("*") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) } lhs:@ __ op:$("*") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs }.into()) }
lhs:@ __ op:$("/") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) } lhs:@ __ op:$("/") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs }.into()) }
lhs:@ __ op:$("%") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) } lhs:@ __ op:$("%") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs }.into()) }
-- --
lhs:@ __ op:$("..") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) } lhs:@ __ op:$("..") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs }.into()) }
-- --
lhs:@ __ op:$("==") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) } lhs:@ __ op:$("==") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs }.into()) }
lhs:@ __ op:$("!=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) } lhs:@ __ op:$("!=") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs }.into()) }
lhs:@ __ op:$("<") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) } lhs:@ __ op:$("<") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs }.into()) }
lhs:@ __ op:$(">") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) } lhs:@ __ op:$(">") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs }.into()) }
lhs:@ __ op:$("<=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) } lhs:@ __ op:$("<=") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs }.into()) }
lhs:@ __ op:$(">=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) } lhs:@ __ op:$(">=") __ rhs:expr() { Expr::Binary(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs }.into()) }
-- --
block:block() { Expr::Block(block)} block:block() { Expr::Block(block.into())}
for_loop:for_loop() { Expr::For(Arc::new(for_loop))} for_loop:for_loop() { Expr::For(for_loop.into())}
while_loop:while_loop() { Expr::While(Arc::new(while_loop))} while_loop:while_loop() { Expr::While(while_loop.into())}
if_statement:if_statement() { Expr::If(if_statement.into())}
func:func() { Expr::Func(Arc::new(func))} func:func() { Expr::Func(Arc::new(func))}
var_decl:var_decl() { Expr::VarDecl(Arc::new(var_decl)) } var_decl:var_decl() { Expr::VarDecl(var_decl.into()) }
const_decl:const_decl() { Expr::ConstDecl(Arc::new(const_decl)) } const_decl:const_decl() { Expr::ConstDecl(const_decl.into()) }
"(" __ 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 })) } "*" __ m:$"mut"? __ v:expr() { Expr::Type(Type::Ptr { base:v, mutable: m }.into()) }
v:struct_t() { Expr::Type(Arc::new(Type::Struct(v))) } v:struct_t() { Expr::Type(Type::Struct(v).into()) }
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) }
@@ -121,7 +125,7 @@ peg::parser! {
rule func() -> Function rule func() -> Function
= s:position!() t:$"fn" __ "(" __ args:name_type_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(Into::into), text: t.parent().substr(s..e), } }
rule name_type_pair() -> NameValuePair rule name_type_pair() -> NameValuePair
= name:ident() __ ":" __ value:expr() { NameValuePair { name, value } } = name:ident() __ ":" __ value:expr() { NameValuePair { name, value } }
@@ -168,8 +172,15 @@ peg::parser! {
{ For { names, value, block } } { For { names, value, block } }
rule while_loop() -> While = rule while_loop() -> While =
"while" _ value:expr() _ block:block() "while" _ cond:expr() _ block:block()
{ While { value, block } } { While { cond, block } }
rule if_statement() -> If =
"if" _ cond:expr() __ block:block() e:(__ e:else_statement() {e})? { If { cond, block, else_: e.map(Box::new) } }
rule else_statement() -> Else
= "else" _ i:if_statement() { Else::If(i) }
/ "else" __ b:block() { Else::Block(b) }
pub rule compilation_unit() -> CompilationUnit = pub rule compilation_unit() -> CompilationUnit =
__ imports:(i:import() statement_separator() {i})* __ imports:(i:import() statement_separator() {i})*