Refactor a bunch of stuff, produce compiling MIR
This commit is contained in:
parent
05c585d47c
commit
8a32e66ba8
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -100,6 +100,7 @@ name = "reid"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"llvm-sys",
|
"llvm-sys",
|
||||||
|
"reid-lib",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# Do note this file is extremely simply for my own personal convenience
|
# Do note this file is extremely simply for my own personal convenience
|
||||||
|
|
||||||
export .env
|
export .env
|
||||||
cargo run --example libtest && \
|
cargo run --example testcodegen && \
|
||||||
# clang hello.o -o main && \
|
# clang hello.o -o main && \
|
||||||
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
|
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
|
||||||
-o main /usr/lib/crt1.o hello.o -lc && \
|
-o main /usr/lib/crt1.o hello.o -lc && \
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
Context, IntPredicate,
|
Context, IntPredicate,
|
||||||
types::{BasicType, IntegerType, IntegerValue, Value},
|
types::{BasicType, IntegerValue, Value},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@ -16,15 +16,19 @@ pub fn main() {
|
|||||||
|
|
||||||
let int_32 = context.type_i32();
|
let int_32 = context.type_i32();
|
||||||
|
|
||||||
let fibonacci = module.add_function(int_32.function_type(vec![&int_32]), "fibonacci");
|
let fibonacci = module.add_function(int_32.function_type(vec![int_32.into()]), "fibonacci");
|
||||||
let f_main = fibonacci.block("main");
|
let mut f_main = fibonacci.block("main");
|
||||||
|
|
||||||
let param = fibonacci.get_param::<IntegerValue>(0).unwrap();
|
let param = fibonacci
|
||||||
let cmp = f_main
|
.get_param::<IntegerValue>(0, int_32.into())
|
||||||
|
.unwrap();
|
||||||
|
let mut cmp = f_main
|
||||||
.integer_compare(¶m, &int_32.from_unsigned(3), &IntPredicate::ULT, "cmp")
|
.integer_compare(¶m, &int_32.from_unsigned(3), &IntPredicate::ULT, "cmp")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (done, recurse) = f_main.conditional_br(&cmp, "done", "recurse").unwrap();
|
let mut done = fibonacci.block("done");
|
||||||
|
let mut recurse = fibonacci.block("recurse");
|
||||||
|
f_main.conditional_br(&cmp, &done, &recurse).unwrap();
|
||||||
|
|
||||||
done.ret(&int_32.from_unsigned(1)).unwrap();
|
done.ret(&int_32.from_unsigned(1)).unwrap();
|
||||||
|
|
||||||
@ -34,7 +38,7 @@ pub fn main() {
|
|||||||
let minus_two = recurse
|
let minus_two = recurse
|
||||||
.sub(¶m, &int_32.from_unsigned(2), "minus_two")
|
.sub(¶m, &int_32.from_unsigned(2), "minus_two")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let one = recurse
|
let one: IntegerValue = recurse
|
||||||
.call(&fibonacci, vec![Value::Integer(minus_one)], "call_one")
|
.call(&fibonacci, vec![Value::Integer(minus_one)], "call_one")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let two = recurse
|
let two = recurse
|
||||||
@ -47,8 +51,8 @@ pub fn main() {
|
|||||||
|
|
||||||
let main_f = module.add_function(int_32.function_type(Vec::new()), "main");
|
let main_f = module.add_function(int_32.function_type(Vec::new()), "main");
|
||||||
|
|
||||||
let main_b = main_f.block("main");
|
let mut main_b = main_f.block("main");
|
||||||
let call = main_b
|
let call: IntegerValue = main_b
|
||||||
.call(
|
.call(
|
||||||
&fibonacci,
|
&fibonacci,
|
||||||
vec![Value::Integer(int_32.from_unsigned(8))],
|
vec![Value::Integer(int_32.from_unsigned(8))],
|
||||||
|
@ -20,15 +20,20 @@ pub mod types;
|
|||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub enum IntPredicate {
|
pub enum IntPredicate {
|
||||||
ULT,
|
|
||||||
SLT,
|
SLT,
|
||||||
|
SGT,
|
||||||
|
|
||||||
|
ULT,
|
||||||
|
UGT,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntPredicate {
|
impl IntPredicate {
|
||||||
pub fn as_llvm(&self) -> LLVMIntPredicate {
|
pub fn as_llvm(&self) -> LLVMIntPredicate {
|
||||||
match *self {
|
match *self {
|
||||||
Self::ULT => LLVMIntPredicate::LLVMIntULT,
|
|
||||||
Self::SLT => LLVMIntPredicate::LLVMIntSLT,
|
Self::SLT => LLVMIntPredicate::LLVMIntSLT,
|
||||||
|
Self::SGT => LLVMIntPredicate::LLVMIntSGT,
|
||||||
|
Self::ULT => LLVMIntPredicate::LLVMIntULT,
|
||||||
|
Self::UGT => LLVMIntPredicate::LLVMIntUGT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,8 +73,8 @@ impl Context {
|
|||||||
IntegerType::in_context(&self, 32)
|
IntegerType::in_context(&self, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module<T: Into<String>>(&self, name: T) -> Module {
|
pub fn module(&self, name: &str) -> Module {
|
||||||
Module::with_name(self, name.into())
|
Module::with_name(self, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +95,7 @@ pub struct Module<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Module<'ctx> {
|
impl<'ctx> Module<'ctx> {
|
||||||
fn with_name(context: &'ctx Context, name: String) -> Module<'ctx> {
|
fn with_name(context: &'ctx Context, name: &str) -> Module<'ctx> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let cstring_name = into_cstring(name);
|
let cstring_name = into_cstring(name);
|
||||||
let module_ref =
|
let module_ref =
|
||||||
@ -103,11 +108,7 @@ impl<'ctx> Module<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_function<ReturnValue: BasicValue<'ctx>>(
|
pub fn add_function(&'ctx self, fn_type: FunctionType<'ctx>, name: &str) -> Function<'ctx> {
|
||||||
&'ctx self,
|
|
||||||
fn_type: FunctionType<'ctx, ReturnValue::BaseType>,
|
|
||||||
name: &str,
|
|
||||||
) -> Function<'ctx, ReturnValue> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let name_cstring = into_cstring(name);
|
let name_cstring = into_cstring(name);
|
||||||
let function_ref =
|
let function_ref =
|
||||||
@ -193,21 +194,26 @@ impl<'a> Drop for Module<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Function<'ctx, ReturnValue: BasicValue<'ctx>> {
|
#[derive(Clone)]
|
||||||
|
pub struct Function<'ctx> {
|
||||||
module: &'ctx Module<'ctx>,
|
module: &'ctx Module<'ctx>,
|
||||||
name: CString,
|
name: CString,
|
||||||
fn_type: FunctionType<'ctx, ReturnValue::BaseType>,
|
fn_type: FunctionType<'ctx>,
|
||||||
fn_ref: LLVMValueRef,
|
fn_ref: LLVMValueRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, ReturnValue: BasicValue<'ctx>> Function<'ctx, ReturnValue> {
|
impl<'ctx> Function<'ctx> {
|
||||||
pub fn block<T: Into<String>>(&'ctx self, name: T) -> BasicBlock<'ctx, ReturnValue> {
|
pub fn block<T: Into<String>>(&'ctx self, name: T) -> BasicBlock<'ctx> {
|
||||||
BasicBlock::in_function(&self, name.into())
|
BasicBlock::in_function(&self, name.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_param<T: BasicValue<'ctx>>(&'ctx self, nth: usize) -> Result<T, String> {
|
pub fn get_param<T: BasicValue<'ctx>>(
|
||||||
if let Some(param_type) = self.fn_type.param_types.iter().nth(nth) {
|
&'ctx self,
|
||||||
if self.fn_type.return_type(self.module.context).llvm_type() != *param_type {
|
nth: usize,
|
||||||
|
param_type: T::BaseType,
|
||||||
|
) -> Result<T, String> {
|
||||||
|
if let Some(actual_type) = self.fn_type.param_types.iter().nth(nth) {
|
||||||
|
if param_type.llvm_type() != *actual_type {
|
||||||
return Err(String::from("Wrong type"));
|
return Err(String::from("Wrong type"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -217,29 +223,27 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> Function<'ctx, ReturnValue> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BasicBlock<'ctx, ReturnValue: BasicValue<'ctx>> {
|
pub struct BasicBlock<'ctx> {
|
||||||
function: &'ctx Function<'ctx, ReturnValue>,
|
function: &'ctx Function<'ctx>,
|
||||||
builder_ref: LLVMBuilderRef,
|
builder_ref: LLVMBuilderRef,
|
||||||
name: CString,
|
name: String,
|
||||||
blockref: LLVMBasicBlockRef,
|
blockref: LLVMBasicBlockRef,
|
||||||
inserted: bool,
|
inserted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
impl<'ctx> BasicBlock<'ctx> {
|
||||||
fn in_function(
|
fn in_function(function: &'ctx Function<'ctx>, name: String) -> BasicBlock<'ctx> {
|
||||||
function: &'ctx Function<'ctx, ReturnValue>,
|
|
||||||
name: String,
|
|
||||||
) -> BasicBlock<'ctx, ReturnValue> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let block_name = into_cstring(name);
|
let block_name = into_cstring(name.clone());
|
||||||
let block_ref = LLVMCreateBasicBlockInContext(
|
let block_ref = LLVMCreateBasicBlockInContext(
|
||||||
function.module.context.context_ref,
|
function.module.context.context_ref,
|
||||||
block_name.as_ptr(),
|
block_name.as_ptr(),
|
||||||
);
|
);
|
||||||
|
LLVMAppendExistingBasicBlock(function.fn_ref, block_ref);
|
||||||
BasicBlock {
|
BasicBlock {
|
||||||
function: function,
|
function: function,
|
||||||
builder_ref: function.module.context.builder_ref,
|
builder_ref: function.module.context.builder_ref,
|
||||||
name: block_name,
|
name,
|
||||||
blockref: block_ref,
|
blockref: block_ref,
|
||||||
inserted: false,
|
inserted: false,
|
||||||
}
|
}
|
||||||
@ -269,12 +273,12 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn call(
|
pub fn call<T: BasicValue<'ctx>>(
|
||||||
&self,
|
&self,
|
||||||
callee: &'ctx Function<'ctx, ReturnValue>,
|
callee: &Function<'ctx>,
|
||||||
params: Vec<Value<'ctx>>,
|
params: Vec<Value<'ctx>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<ReturnValue, ()> {
|
) -> Result<T, ()> {
|
||||||
if params.len() != callee.fn_type.param_types.len() {
|
if params.len() != callee.fn_type.param_types.len() {
|
||||||
return Err(()); // TODO invalid amount of parameters
|
return Err(()); // TODO invalid amount of parameters
|
||||||
}
|
}
|
||||||
@ -283,6 +287,9 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
return Err(()); // TODO wrong types in parameters
|
return Err(()); // TODO wrong types in parameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !T::BaseType::is_type(callee.fn_type.return_type) {
|
||||||
|
return Err(()); // TODO wrong return type
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut param_list: Vec<LLVMValueRef> = params.iter().map(|p| p.llvm_value()).collect();
|
let mut param_list: Vec<LLVMValueRef> = params.iter().map(|p| p.llvm_value()).collect();
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
||||||
@ -294,7 +301,7 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
param_list.len() as u32,
|
param_list.len() as u32,
|
||||||
into_cstring(name).as_ptr(),
|
into_cstring(name).as_ptr(),
|
||||||
);
|
);
|
||||||
Ok(ReturnValue::from_llvm(ret_val))
|
Ok(T::from_llvm(ret_val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,6 +324,8 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn sub<T: BasicValue<'ctx>>(&self, lhs: &T, rhs: &T, name: &str) -> Result<T, ()> {
|
pub fn sub<T: BasicValue<'ctx>>(&self, lhs: &T, rhs: &T, name: &str) -> Result<T, ()> {
|
||||||
|
dbg!(lhs, rhs);
|
||||||
|
dbg!(lhs.llvm_type(), rhs.llvm_type());
|
||||||
if lhs.llvm_type() != rhs.llvm_type() {
|
if lhs.llvm_type() != rhs.llvm_type() {
|
||||||
return Err(()); // TODO error
|
return Err(()); // TODO error
|
||||||
}
|
}
|
||||||
@ -335,9 +344,9 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn phi<PhiValue: BasicValue<'ctx>>(
|
pub fn phi<PhiValue: BasicValue<'ctx>>(
|
||||||
&self,
|
&self,
|
||||||
phi_type: &'ctx PhiValue::BaseType,
|
phi_type: &PhiValue::BaseType,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<PhiBuilder<'ctx, ReturnValue, PhiValue>, ()> {
|
) -> Result<PhiBuilder<'ctx, PhiValue>, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
||||||
let phi_node = LLVMBuildPhi(
|
let phi_node = LLVMBuildPhi(
|
||||||
@ -350,26 +359,24 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn br(self, into: &BasicBlock<'ctx, ReturnValue>) -> Result<(), ()> {
|
pub fn br(&mut self, into: &BasicBlock<'ctx>) -> Result<(), ()> {
|
||||||
|
self.try_insert()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
||||||
LLVMBuildBr(self.builder_ref, into.blockref);
|
LLVMBuildBr(self.builder_ref, into.blockref);
|
||||||
self.terminate();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn conditional_br<T: BasicValue<'ctx>>(
|
pub fn conditional_br<T: BasicValue<'ctx>>(
|
||||||
self,
|
&mut self,
|
||||||
condition: &T,
|
condition: &T,
|
||||||
lhs_name: &str,
|
lhs: &BasicBlock<'ctx>,
|
||||||
rhs_name: &str,
|
rhs: &BasicBlock<'ctx>,
|
||||||
) -> Result<(BasicBlock<'ctx, ReturnValue>, BasicBlock<'ctx, ReturnValue>), ()> {
|
) -> Result<(), ()> {
|
||||||
|
self.try_insert()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let lhs = BasicBlock::in_function(&self.function, lhs_name.into());
|
|
||||||
let rhs = BasicBlock::in_function(&self.function, rhs_name.into());
|
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
||||||
LLVMBuildCondBr(
|
LLVMBuildCondBr(
|
||||||
self.builder_ref,
|
self.builder_ref,
|
||||||
@ -377,39 +384,34 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> BasicBlock<'ctx, ReturnValue> {
|
|||||||
lhs.blockref,
|
lhs.blockref,
|
||||||
rhs.blockref,
|
rhs.blockref,
|
||||||
);
|
);
|
||||||
self.terminate();
|
|
||||||
Ok((lhs, rhs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn ret(self, return_value: &ReturnValue) -> Result<(), ()> {
|
|
||||||
if self
|
|
||||||
.function
|
|
||||||
.fn_type
|
|
||||||
.return_type(self.function.module.context)
|
|
||||||
.llvm_type()
|
|
||||||
!= return_value.llvm_type()
|
|
||||||
{
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
LLVMBuildRet(self.builder_ref, return_value.llvm_value());
|
|
||||||
self.terminate();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn terminate(mut self) {
|
#[must_use]
|
||||||
unsafe {
|
pub fn ret<T: BasicValue<'ctx>>(&mut self, return_value: &T) -> Result<(), ()> {
|
||||||
LLVMAppendExistingBasicBlock(self.function.fn_ref, self.blockref);
|
if self.function.fn_type.return_type != return_value.llvm_type() {
|
||||||
self.inserted = true;
|
return Err(());
|
||||||
}
|
}
|
||||||
|
self.try_insert()?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
||||||
|
LLVMBuildRet(self.builder_ref, return_value.llvm_value());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, ReturnValue: BasicValue<'ctx>> Drop for BasicBlock<'ctx, ReturnValue> {
|
fn try_insert(&mut self) -> Result<(), ()> {
|
||||||
|
if self.inserted {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
self.inserted = true;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Drop for BasicBlock<'ctx> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !self.inserted {
|
if !self.inserted {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -419,22 +421,20 @@ impl<'ctx, ReturnValue: BasicValue<'ctx>> Drop for BasicBlock<'ctx, ReturnValue>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PhiBuilder<'ctx, ReturnValue: BasicValue<'ctx>, PhiValue: BasicValue<'ctx>> {
|
pub struct PhiBuilder<'ctx, PhiValue: BasicValue<'ctx>> {
|
||||||
phi_node: LLVMValueRef,
|
phi_node: LLVMValueRef,
|
||||||
phantom: PhantomData<&'ctx (PhiValue, ReturnValue)>,
|
phantom: PhantomData<&'ctx PhiValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, ReturnValue: BasicValue<'ctx>, PhiValue: BasicValue<'ctx>>
|
impl<'ctx, PhiValue: BasicValue<'ctx>> PhiBuilder<'ctx, PhiValue> {
|
||||||
PhiBuilder<'ctx, ReturnValue, PhiValue>
|
fn new(phi_node: LLVMValueRef) -> PhiBuilder<'ctx, PhiValue> {
|
||||||
{
|
|
||||||
fn new(phi_node: LLVMValueRef) -> PhiBuilder<'ctx, ReturnValue, PhiValue> {
|
|
||||||
PhiBuilder {
|
PhiBuilder {
|
||||||
phi_node,
|
phi_node,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_incoming(&self, value: &PhiValue, block: &BasicBlock<'ctx, ReturnValue>) -> &Self {
|
pub fn add_incoming(&self, value: &PhiValue, block: &BasicBlock<'ctx>) -> &Self {
|
||||||
let mut values = vec![value.llvm_value()];
|
let mut values = vec![value.llvm_value()];
|
||||||
let mut blocks = vec![block.blockref];
|
let mut blocks = vec![block.blockref];
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -6,36 +6,40 @@ use llvm_sys::{
|
|||||||
prelude::{LLVMTypeRef, LLVMValueRef},
|
prelude::{LLVMTypeRef, LLVMValueRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Context;
|
use crate::{BasicBlock, Context, PhiBuilder};
|
||||||
|
|
||||||
pub trait BasicType<'ctx> {
|
pub trait BasicType<'ctx> {
|
||||||
fn llvm_type(&self) -> LLVMTypeRef;
|
fn llvm_type(&self) -> LLVMTypeRef;
|
||||||
fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
|
||||||
|
fn is_type(llvm_type: LLVMTypeRef) -> bool
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
fn function_type(&'ctx self, params: Vec<&'ctx dyn BasicType>) -> FunctionType<'ctx, Self>
|
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized;
|
||||||
{
|
|
||||||
|
fn function_type(&self, params: Vec<TypeEnum>) -> FunctionType<'ctx> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut typerefs: Vec<LLVMTypeRef> = params.iter().map(|b| b.llvm_type()).collect();
|
let mut typerefs: Vec<LLVMTypeRef> = params.iter().map(|b| b.llvm_type()).collect();
|
||||||
let param_ptr = typerefs.as_mut_ptr();
|
let param_ptr = typerefs.as_mut_ptr();
|
||||||
let param_len = typerefs.len();
|
let param_len = typerefs.len();
|
||||||
FunctionType {
|
FunctionType {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
return_type: self.llvm_type(),
|
||||||
param_types: typerefs,
|
param_types: typerefs,
|
||||||
type_ref: LLVMFunctionType(self.llvm_type(), param_ptr, param_len as u32, 0),
|
type_ref: LLVMFunctionType(self.llvm_type(), param_ptr, param_len as u32, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_type(&'ctx self, length: u32) -> ArrayType<'ctx, Self>
|
fn array_type(&'ctx self, length: u32) -> ArrayType<'ctx>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
ArrayType {
|
ArrayType {
|
||||||
element_type: self,
|
phantom: PhantomData,
|
||||||
|
element_type: self.llvm_type(),
|
||||||
length,
|
length,
|
||||||
type_ref: unsafe { LLVMArrayType(self.llvm_type(), length) },
|
type_ref: unsafe { LLVMArrayType(self.llvm_type(), length) },
|
||||||
}
|
}
|
||||||
@ -54,6 +58,7 @@ impl<'ctx> PartialEq<LLVMTypeRef> for &dyn BasicType<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct IntegerType<'ctx> {
|
pub struct IntegerType<'ctx> {
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
type_ref: LLVMTypeRef,
|
type_ref: LLVMTypeRef,
|
||||||
@ -64,7 +69,7 @@ impl<'ctx> BasicType<'ctx> for IntegerType<'ctx> {
|
|||||||
self.type_ref
|
self.type_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
@ -73,6 +78,10 @@ impl<'ctx> BasicType<'ctx> for IntegerType<'ctx> {
|
|||||||
type_ref: llvm_type,
|
type_ref: llvm_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_type(llvm_type: LLVMTypeRef) -> bool {
|
||||||
|
unsafe { LLVMGetTypeKind(llvm_type) == LLVMTypeKind::LLVMIntegerTypeKind }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> IntegerType<'ctx> {
|
impl<'ctx> IntegerType<'ctx> {
|
||||||
@ -91,15 +100,15 @@ impl<'ctx> IntegerType<'ctx> {
|
|||||||
IntegerType { context, type_ref }
|
IntegerType { context, type_ref }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_signed(&self, value: i64) -> IntegerValue<'_> {
|
pub fn from_signed(&self, value: i64) -> IntegerValue<'ctx> {
|
||||||
self.from_const(value as u64, true)
|
self.from_const(value as u64, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_unsigned(&self, value: i64) -> IntegerValue<'_> {
|
pub fn from_unsigned(&self, value: i64) -> IntegerValue<'ctx> {
|
||||||
self.from_const(value as u64, false)
|
self.from_const(value as u64, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_const(&self, value: u64, sign: bool) -> IntegerValue<'_> {
|
fn from_const(&self, value: u64, sign: bool) -> IntegerValue<'ctx> {
|
||||||
unsafe {
|
unsafe {
|
||||||
IntegerValue::from_llvm(LLVMConstInt(
|
IntegerValue::from_llvm(LLVMConstInt(
|
||||||
self.type_ref,
|
self.type_ref,
|
||||||
@ -113,18 +122,20 @@ impl<'ctx> IntegerType<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionType<'ctx, ReturnType: BasicType<'ctx>> {
|
#[derive(Clone)]
|
||||||
phantom: PhantomData<&'ctx ReturnType>,
|
pub struct FunctionType<'ctx> {
|
||||||
|
phantom: PhantomData<&'ctx ()>,
|
||||||
|
pub(crate) return_type: LLVMTypeRef,
|
||||||
pub(crate) param_types: Vec<LLVMTypeRef>,
|
pub(crate) param_types: Vec<LLVMTypeRef>,
|
||||||
type_ref: LLVMTypeRef,
|
type_ref: LLVMTypeRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, ReturnType: BasicType<'ctx>> BasicType<'ctx> for FunctionType<'ctx, ReturnType> {
|
impl<'ctx> BasicType<'ctx> for FunctionType<'ctx> {
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
fn llvm_type(&self) -> LLVMTypeRef {
|
||||||
self.type_ref
|
self.type_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_llvm(_context: &'ctx Context, fn_type: LLVMTypeRef) -> Self
|
unsafe fn from_llvm(_context: &'ctx Context, fn_type: LLVMTypeRef) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
@ -139,34 +150,32 @@ impl<'ctx, ReturnType: BasicType<'ctx>> BasicType<'ctx> for FunctionType<'ctx, R
|
|||||||
.collect();
|
.collect();
|
||||||
FunctionType {
|
FunctionType {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
return_type: LLVMGetReturnType(fn_type),
|
||||||
param_types,
|
param_types,
|
||||||
type_ref: fn_type,
|
type_ref: fn_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, ReturnType: BasicType<'ctx>> FunctionType<'ctx, ReturnType> {
|
fn is_type(llvm_type: LLVMTypeRef) -> bool {
|
||||||
pub fn return_type(&self, context: &'ctx Context) -> ReturnType {
|
unsafe { LLVMGetTypeKind(llvm_type) == LLVMTypeKind::LLVMFunctionTypeKind }
|
||||||
unsafe {
|
|
||||||
let return_type = LLVMGetReturnType(self.type_ref);
|
|
||||||
ReturnType::from_llvm(context, return_type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ArrayType<'ctx, T: BasicType<'ctx>> {
|
#[derive(Clone, Copy)]
|
||||||
element_type: &'ctx T,
|
pub struct ArrayType<'ctx> {
|
||||||
|
phantom: PhantomData<&'ctx ()>,
|
||||||
|
element_type: LLVMTypeRef,
|
||||||
length: u32,
|
length: u32,
|
||||||
type_ref: LLVMTypeRef,
|
type_ref: LLVMTypeRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, T: BasicType<'ctx>> BasicType<'ctx> for ArrayType<'ctx, T> {
|
impl<'ctx> BasicType<'ctx> for ArrayType<'ctx> {
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
fn llvm_type(&self) -> LLVMTypeRef {
|
||||||
self.type_ref
|
self.type_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
@ -175,9 +184,81 @@ impl<'ctx, T: BasicType<'ctx>> BasicType<'ctx> for ArrayType<'ctx, T> {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_type(llvm_type: LLVMTypeRef) -> bool {
|
||||||
|
unsafe { LLVMGetTypeKind(llvm_type) == LLVMTypeKind::LLVMArrayTypeKind }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BasicValue<'ctx> {
|
#[derive(Clone)]
|
||||||
|
pub enum TypeEnum<'ctx> {
|
||||||
|
Integer(IntegerType<'ctx>),
|
||||||
|
Array(ArrayType<'ctx>),
|
||||||
|
Function(FunctionType<'ctx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<IntegerType<'ctx>> for TypeEnum<'ctx> {
|
||||||
|
fn from(int: IntegerType<'ctx>) -> Self {
|
||||||
|
TypeEnum::Integer(int)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<ArrayType<'ctx>> for TypeEnum<'ctx> {
|
||||||
|
fn from(arr: ArrayType<'ctx>) -> Self {
|
||||||
|
TypeEnum::Array(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<FunctionType<'ctx>> for TypeEnum<'ctx> {
|
||||||
|
fn from(func: FunctionType<'ctx>) -> Self {
|
||||||
|
TypeEnum::Function(func)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> TypeEnum<'ctx> {
|
||||||
|
fn inner_basic(&'ctx self) -> &'ctx dyn BasicType<'ctx> {
|
||||||
|
match self {
|
||||||
|
TypeEnum::Integer(integer_type) => integer_type,
|
||||||
|
TypeEnum::Array(array_type) => array_type,
|
||||||
|
TypeEnum::Function(function_type) => function_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> BasicType<'ctx> for TypeEnum<'ctx> {
|
||||||
|
fn llvm_type(&self) -> LLVMTypeRef {
|
||||||
|
self.inner_basic().llvm_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_type(llvm_type: LLVMTypeRef) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
match LLVMGetTypeKind(llvm_type) {
|
||||||
|
LLVMTypeKind::LLVMIntegerTypeKind => {
|
||||||
|
TypeEnum::Integer(IntegerType::from_llvm(context, llvm_type))
|
||||||
|
}
|
||||||
|
LLVMTypeKind::LLVMArrayTypeKind => {
|
||||||
|
TypeEnum::Array(ArrayType::from_llvm(context, llvm_type))
|
||||||
|
}
|
||||||
|
LLVMTypeKind::LLVMFunctionTypeKind => {
|
||||||
|
TypeEnum::Function(FunctionType::from_llvm(context, llvm_type))
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait BasicValue<'ctx>: std::fmt::Debug {
|
||||||
type BaseType: BasicType<'ctx>;
|
type BaseType: BasicType<'ctx>;
|
||||||
unsafe fn from_llvm(value: LLVMValueRef) -> Self
|
unsafe fn from_llvm(value: LLVMValueRef) -> Self
|
||||||
where
|
where
|
||||||
@ -186,6 +267,7 @@ pub trait BasicValue<'ctx> {
|
|||||||
fn llvm_type(&self) -> LLVMTypeRef;
|
fn llvm_type(&self) -> LLVMTypeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct IntegerValue<'ctx> {
|
pub struct IntegerValue<'ctx> {
|
||||||
phantom: PhantomData<&'ctx ()>,
|
phantom: PhantomData<&'ctx ()>,
|
||||||
pub(crate) value_ref: LLVMValueRef,
|
pub(crate) value_ref: LLVMValueRef,
|
||||||
@ -210,11 +292,14 @@ impl<'ctx> BasicValue<'ctx> for IntegerValue<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum Value<'ctx> {
|
pub enum Value<'ctx> {
|
||||||
Integer(IntegerValue<'ctx>),
|
Integer(IntegerValue<'ctx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Value<'ctx> {
|
impl<'ctx> BasicValue<'ctx> for Value<'ctx> {
|
||||||
|
type BaseType = TypeEnum<'ctx>;
|
||||||
|
|
||||||
unsafe fn from_llvm(value: LLVMValueRef) -> Self
|
unsafe fn from_llvm(value: LLVMValueRef) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -231,15 +316,21 @@ impl<'ctx> Value<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn llvm_value(&self) -> LLVMValueRef {
|
fn llvm_value(&self) -> LLVMValueRef {
|
||||||
match self {
|
match self {
|
||||||
Self::Integer(i) => i.llvm_value(),
|
Self::Integer(i) => i.llvm_value(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn llvm_type(&self) -> LLVMTypeRef {
|
fn llvm_type(&self) -> LLVMTypeRef {
|
||||||
match self {
|
match self {
|
||||||
Self::Integer(i) => i.llvm_type(),
|
Self::Integer(i) => i.llvm_type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<IntegerValue<'ctx>> for Value<'ctx> {
|
||||||
|
fn from(value: IntegerValue<'ctx>) -> Self {
|
||||||
|
Value::Integer(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,3 +10,4 @@ edition = "2021"
|
|||||||
llvm-sys = "160"
|
llvm-sys = "160"
|
||||||
## Make it easier to generate errors
|
## Make it easier to generate errors
|
||||||
thiserror = "1.0.44"
|
thiserror = "1.0.44"
|
||||||
|
reid-lib = { path = "../reid-llvm-lib" }
|
172
reid/examples/testcodegen.rs
Normal file
172
reid/examples/testcodegen.rs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
use reid::mir::*;
|
||||||
|
use reid_lib::Context;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fibonacci_name = "fibonacci".to_owned();
|
||||||
|
let fibonacci_n = "N".to_owned();
|
||||||
|
|
||||||
|
let fibonacci = FunctionDefinition {
|
||||||
|
name: fibonacci_name.clone(),
|
||||||
|
parameters: vec![(fibonacci_n.clone(), TypeKind::I32)],
|
||||||
|
kind: FunctionDefinitionKind::Local(
|
||||||
|
Block {
|
||||||
|
statements: vec![Statement(
|
||||||
|
StatementKind::If(IfExpression(
|
||||||
|
// If N < 3
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::BinOp(
|
||||||
|
BinaryOperator::Logic(LogicOperator::GreaterThan),
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Variable(VariableReference(
|
||||||
|
TypeKind::I32,
|
||||||
|
"N".to_string(),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Literal(Literal::I32(2)),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
// Then
|
||||||
|
Block {
|
||||||
|
statements: vec![],
|
||||||
|
return_expression: Some((
|
||||||
|
ReturnKind::HardReturn,
|
||||||
|
// return fibonacci(n-1) + fibonacci(n-2)
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::BinOp(
|
||||||
|
BinaryOperator::Add,
|
||||||
|
// fibonacci(n-1)
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::FunctionCall(FunctionCall {
|
||||||
|
name: fibonacci_name.clone(),
|
||||||
|
return_type: TypeKind::I32,
|
||||||
|
parameters: vec![Expression(
|
||||||
|
ExpressionKind::BinOp(
|
||||||
|
BinaryOperator::Minus,
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Variable(
|
||||||
|
VariableReference(
|
||||||
|
TypeKind::I32,
|
||||||
|
fibonacci_n.clone(),
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Literal(Literal::I32(
|
||||||
|
1,
|
||||||
|
)),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
)],
|
||||||
|
}),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
// fibonacci(n-2)
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::FunctionCall(FunctionCall {
|
||||||
|
name: fibonacci_name.clone(),
|
||||||
|
return_type: TypeKind::I32,
|
||||||
|
parameters: vec![Expression(
|
||||||
|
ExpressionKind::BinOp(
|
||||||
|
BinaryOperator::Minus,
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Variable(
|
||||||
|
VariableReference(
|
||||||
|
TypeKind::I32,
|
||||||
|
fibonacci_n.clone(),
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Literal(Literal::I32(
|
||||||
|
2,
|
||||||
|
)),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
)],
|
||||||
|
}),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
range: Default::default(),
|
||||||
|
},
|
||||||
|
// No else-block
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
Default::default(),
|
||||||
|
)],
|
||||||
|
// return 1
|
||||||
|
return_expression: Some((
|
||||||
|
ReturnKind::SoftReturn,
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::Literal(Literal::I32(1)),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
range: Default::default(),
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let main = FunctionDefinition {
|
||||||
|
name: "main".to_owned(),
|
||||||
|
parameters: vec![],
|
||||||
|
kind: FunctionDefinitionKind::Local(
|
||||||
|
Block {
|
||||||
|
statements: vec![],
|
||||||
|
return_expression: Some((
|
||||||
|
ReturnKind::SoftReturn,
|
||||||
|
Box::new(Expression(
|
||||||
|
ExpressionKind::FunctionCall(FunctionCall {
|
||||||
|
name: fibonacci_name.clone(),
|
||||||
|
return_type: TypeKind::I32,
|
||||||
|
parameters: vec![Expression(
|
||||||
|
ExpressionKind::Literal(Literal::I32(5)),
|
||||||
|
Default::default(),
|
||||||
|
)],
|
||||||
|
}),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
range: Default::default(),
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("test1");
|
||||||
|
|
||||||
|
let module = Module {
|
||||||
|
name: "test module".to_owned(),
|
||||||
|
imports: vec![],
|
||||||
|
functions: vec![fibonacci, main],
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("test2");
|
||||||
|
let context = Context::new();
|
||||||
|
let codegen_module = module.codegen(&context);
|
||||||
|
|
||||||
|
println!("test3");
|
||||||
|
|
||||||
|
match codegen_module.module.print_to_string() {
|
||||||
|
Ok(v) => println!("{}", v),
|
||||||
|
Err(e) => println!("Err: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
281
reid/src/codegen.rs
Normal file
281
reid/src/codegen.rs
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
use std::{collections::HashMap, mem, ops::Deref};
|
||||||
|
|
||||||
|
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
||||||
|
use reid_lib::{
|
||||||
|
types::{BasicType, BasicValue, IntegerValue, TypeEnum, Value},
|
||||||
|
BasicBlock, Context, Function, IntPredicate, Module,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ModuleCodegen<'ctx> {
|
||||||
|
context: &'ctx Context,
|
||||||
|
pub module: Module<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::Module {
|
||||||
|
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> {
|
||||||
|
let module = context.module(&self.name);
|
||||||
|
|
||||||
|
let mut functions = HashMap::new();
|
||||||
|
|
||||||
|
for function in &self.functions {
|
||||||
|
let ret_type = function.return_type().unwrap().get_type(&context);
|
||||||
|
let fn_type = ret_type.function_type(
|
||||||
|
function
|
||||||
|
.parameters
|
||||||
|
.iter()
|
||||||
|
.map(|(_, p)| p.get_type(&context))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let func = match &function.kind {
|
||||||
|
mir::FunctionDefinitionKind::Local(_, _) => {
|
||||||
|
module.add_function(fn_type, &function.name)
|
||||||
|
}
|
||||||
|
mir::FunctionDefinitionKind::Extern(_) => todo!(),
|
||||||
|
};
|
||||||
|
functions.insert(function.name.clone(), func);
|
||||||
|
}
|
||||||
|
|
||||||
|
for mir_function in &self.functions {
|
||||||
|
let function = functions.get(&mir_function.name).unwrap();
|
||||||
|
|
||||||
|
let mut stack_values = HashMap::new();
|
||||||
|
for (i, (p_name, p_type)) in mir_function.parameters.iter().enumerate() {
|
||||||
|
stack_values.insert(
|
||||||
|
p_name.clone(),
|
||||||
|
function.get_param(i, p_type.get_type(&context)).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut scope = Scope {
|
||||||
|
context,
|
||||||
|
module: &module,
|
||||||
|
function,
|
||||||
|
block: function.block("entry"),
|
||||||
|
functions: functions.clone(),
|
||||||
|
stack_values,
|
||||||
|
};
|
||||||
|
match &mir_function.kind {
|
||||||
|
mir::FunctionDefinitionKind::Local(block, _) => {
|
||||||
|
if let Some(ret) = block.codegen(&mut scope) {
|
||||||
|
scope.block.ret(&ret).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mir::FunctionDefinitionKind::Extern(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleCodegen { context, module }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Scope<'ctx> {
|
||||||
|
context: &'ctx Context,
|
||||||
|
module: &'ctx Module<'ctx>,
|
||||||
|
function: &'ctx Function<'ctx>,
|
||||||
|
block: BasicBlock<'ctx>,
|
||||||
|
functions: HashMap<String, Function<'ctx>>,
|
||||||
|
stack_values: HashMap<String, Value<'ctx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Scope<'ctx> {
|
||||||
|
pub fn with_block(&self, block: BasicBlock<'ctx>) -> Scope<'ctx> {
|
||||||
|
Scope {
|
||||||
|
block,
|
||||||
|
context: self.context,
|
||||||
|
function: self.function,
|
||||||
|
module: self.module,
|
||||||
|
functions: self.functions.clone(),
|
||||||
|
stack_values: self.stack_values.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the block out from this scope, swaps the given block in it's place
|
||||||
|
/// and returns the old block.
|
||||||
|
pub fn swap_block(&mut self, block: BasicBlock<'ctx>) -> BasicBlock<'ctx> {
|
||||||
|
let mut old_block = block;
|
||||||
|
mem::swap(&mut self.block, &mut old_block);
|
||||||
|
old_block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::Statement {
|
||||||
|
pub fn codegen<'ctx>(&self, scope: &mut Scope<'ctx>) -> Option<Value<'ctx>> {
|
||||||
|
match &self.0 {
|
||||||
|
mir::StatementKind::Let(VariableReference(_, name, _), expression) => {
|
||||||
|
let value = expression.codegen(scope).unwrap();
|
||||||
|
scope.stack_values.insert(name.clone(), value);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
mir::StatementKind::If(if_expression) => if_expression.codegen(scope),
|
||||||
|
mir::StatementKind::Import(_) => todo!(),
|
||||||
|
mir::StatementKind::Expression(expression) => {
|
||||||
|
let value = expression.codegen(scope).unwrap();
|
||||||
|
Some(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::IfExpression {
|
||||||
|
pub fn codegen<'ctx>(&self, scope: &mut Scope<'ctx>) -> Option<Value<'ctx>> {
|
||||||
|
let condition = self.0.codegen(scope).unwrap();
|
||||||
|
|
||||||
|
// Create blocks
|
||||||
|
let then_bb = scope.function.block("then");
|
||||||
|
let after_bb = scope.function.block("after");
|
||||||
|
let mut before_bb = scope.swap_block(after_bb);
|
||||||
|
|
||||||
|
let mut then_scope = scope.with_block(then_bb);
|
||||||
|
let then_res = self.1.codegen(&mut then_scope);
|
||||||
|
then_scope.block.br(&scope.block).ok();
|
||||||
|
|
||||||
|
let else_bb = scope.function.block("else");
|
||||||
|
let mut else_scope = scope.with_block(else_bb);
|
||||||
|
|
||||||
|
let else_opt = if let Some(else_block) = &self.2 {
|
||||||
|
before_bb
|
||||||
|
.conditional_br(&condition, &then_scope.block, &else_scope.block)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let opt = else_block.codegen(&mut else_scope);
|
||||||
|
|
||||||
|
if let Some(ret) = opt {
|
||||||
|
else_scope.block.br(&scope.block).ok();
|
||||||
|
Some((else_scope.block, ret))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
else_scope.block.br(&scope.block).unwrap();
|
||||||
|
before_bb
|
||||||
|
.conditional_br(&condition, &then_scope.block, &scope.block)
|
||||||
|
.unwrap();
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if then_res.is_none() && else_opt.is_none() {
|
||||||
|
None
|
||||||
|
} else if let Ok(ret_type) = self.1.return_type() {
|
||||||
|
let phi = scope
|
||||||
|
.block
|
||||||
|
.phi(&ret_type.get_type(scope.context), "phi")
|
||||||
|
.unwrap();
|
||||||
|
if let Some(then_ret) = then_res {
|
||||||
|
phi.add_incoming(&then_ret, &then_scope.block);
|
||||||
|
}
|
||||||
|
if let Some((else_bb, else_ret)) = else_opt {
|
||||||
|
phi.add_incoming(&else_ret, &else_bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(phi.build())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::Expression {
|
||||||
|
pub fn codegen<'ctx>(&self, scope: &mut Scope<'ctx>) -> Option<Value<'ctx>> {
|
||||||
|
match &self.0 {
|
||||||
|
mir::ExpressionKind::Variable(varref) => {
|
||||||
|
let v = scope
|
||||||
|
.stack_values
|
||||||
|
.get(&varref.1)
|
||||||
|
.expect("Variable reference not found?!");
|
||||||
|
Some(v.clone())
|
||||||
|
}
|
||||||
|
mir::ExpressionKind::Literal(lit) => Some(lit.codegen(scope.context)),
|
||||||
|
mir::ExpressionKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
||||||
|
let lhs = lhs_exp.codegen(scope).expect("lhs has no return value");
|
||||||
|
let rhs = rhs_exp.codegen(scope).expect("rhs has no return value");
|
||||||
|
Some(match binop {
|
||||||
|
mir::BinaryOperator::Add => scope.block.add(&lhs, &rhs, "add").unwrap(),
|
||||||
|
mir::BinaryOperator::Minus => scope.block.sub(&lhs, &rhs, "sub").unwrap(),
|
||||||
|
mir::BinaryOperator::Mult => todo!(),
|
||||||
|
mir::BinaryOperator::And => todo!(),
|
||||||
|
mir::BinaryOperator::Logic(l) => {
|
||||||
|
let ret_type = lhs_exp.return_type().expect("No ret type in lhs?");
|
||||||
|
scope
|
||||||
|
.block
|
||||||
|
.integer_compare(&lhs, &rhs, &l.int_predicate(ret_type.signed()), "cmp")
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
mir::ExpressionKind::FunctionCall(call) => {
|
||||||
|
let params = call
|
||||||
|
.parameters
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.codegen(scope).unwrap())
|
||||||
|
.collect();
|
||||||
|
let callee = scope
|
||||||
|
.functions
|
||||||
|
.get(&call.name)
|
||||||
|
.expect("function not found!");
|
||||||
|
Some(scope.block.call(callee, params, "call").unwrap())
|
||||||
|
}
|
||||||
|
mir::ExpressionKind::If(if_expression) => if_expression.codegen(scope),
|
||||||
|
mir::ExpressionKind::Block(block) => {
|
||||||
|
let mut inner_scope = scope.with_block(scope.function.block("inner"));
|
||||||
|
if let Some(ret) = block.codegen(&mut inner_scope) {
|
||||||
|
inner_scope.block.br(&scope.block);
|
||||||
|
Some(ret)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::LogicOperator {
|
||||||
|
fn int_predicate(&self, signed: bool) -> IntPredicate {
|
||||||
|
match (self, signed) {
|
||||||
|
(mir::LogicOperator::LessThan, true) => IntPredicate::SLT,
|
||||||
|
(mir::LogicOperator::GreaterThan, true) => IntPredicate::SGT,
|
||||||
|
(mir::LogicOperator::LessThan, false) => IntPredicate::ULT,
|
||||||
|
(mir::LogicOperator::GreaterThan, false) => IntPredicate::UGT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::Block {
|
||||||
|
pub fn codegen<'ctx>(&self, mut scope: &mut Scope<'ctx>) -> Option<Value<'ctx>> {
|
||||||
|
for stmt in &self.statements {
|
||||||
|
stmt.codegen(&mut scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((kind, expr)) = &self.return_expression {
|
||||||
|
let ret = expr.codegen(&mut scope).unwrap();
|
||||||
|
match kind {
|
||||||
|
mir::ReturnKind::HardReturn => {
|
||||||
|
scope.block.ret(&ret).unwrap();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
mir::ReturnKind::SoftReturn => Some(ret),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mir::Literal {
|
||||||
|
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> Value<'ctx> {
|
||||||
|
let val: IntegerValue<'ctx> = match *self {
|
||||||
|
mir::Literal::I32(val) => context.type_i32().from_signed(val as i64),
|
||||||
|
mir::Literal::I16(val) => context.type_i16().from_signed(val as i64),
|
||||||
|
};
|
||||||
|
Value::Integer(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeKind {
|
||||||
|
fn get_type<'ctx>(&self, context: &'ctx Context) -> TypeEnum<'ctx> {
|
||||||
|
match &self {
|
||||||
|
TypeKind::I32 => TypeEnum::Integer(context.type_i32()),
|
||||||
|
TypeKind::I16 => TypeEnum::Integer(context.type_i16()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
use codegen::{form_context, from_statements};
|
use old_codegen::{form_context, from_statements};
|
||||||
|
|
||||||
use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
use crate::{lexer::Token, parser::TopLevelStatement, token_stream::TokenStream};
|
||||||
|
|
||||||
mod ast;
|
|
||||||
mod codegen;
|
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
pub mod mir;
|
||||||
|
mod old_codegen;
|
||||||
|
mod parser;
|
||||||
// mod llvm_ir;
|
// mod llvm_ir;
|
||||||
|
pub mod codegen;
|
||||||
mod token_stream;
|
mod token_stream;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
120
reid/src/mir/mod.rs
Normal file
120
reid/src/mir/mod.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/// In this module are defined structs that are used for performing passes on
|
||||||
|
/// Reid. It contains a simplified version of Reid which must already be
|
||||||
|
/// type-checked beforehand.
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use types::*;
|
||||||
|
|
||||||
|
use crate::token_stream::TokenRange;
|
||||||
|
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum TypeKind {
|
||||||
|
I32,
|
||||||
|
I16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeKind {
|
||||||
|
pub fn signed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Literal {
|
||||||
|
I32(i32),
|
||||||
|
I16(i16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Literal {
|
||||||
|
fn as_type(self: &Literal) -> TypeKind {
|
||||||
|
match self {
|
||||||
|
Literal::I32(_) => TypeKind::I32,
|
||||||
|
Literal::I16(_) => TypeKind::I16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum BinaryOperator {
|
||||||
|
Add,
|
||||||
|
Minus,
|
||||||
|
Mult,
|
||||||
|
And,
|
||||||
|
Logic(LogicOperator),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum LogicOperator {
|
||||||
|
LessThan,
|
||||||
|
GreaterThan,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum ReturnKind {
|
||||||
|
HardReturn,
|
||||||
|
SoftReturn,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VariableReference(pub TypeKind, pub String, pub TokenRange);
|
||||||
|
|
||||||
|
pub struct Import(pub String, pub TokenRange);
|
||||||
|
|
||||||
|
pub enum ExpressionKind {
|
||||||
|
Variable(VariableReference),
|
||||||
|
Literal(Literal),
|
||||||
|
BinOp(BinaryOperator, Box<Expression>, Box<Expression>),
|
||||||
|
FunctionCall(FunctionCall),
|
||||||
|
If(IfExpression),
|
||||||
|
Block(Block),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Expression(pub ExpressionKind, pub TokenRange);
|
||||||
|
|
||||||
|
/// Condition, Then, Else
|
||||||
|
pub struct IfExpression(pub Box<Expression>, pub Block, pub Option<Block>);
|
||||||
|
|
||||||
|
pub struct FunctionCall {
|
||||||
|
pub name: String,
|
||||||
|
pub return_type: TypeKind,
|
||||||
|
pub parameters: Vec<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FunctionDefinition {
|
||||||
|
pub name: String,
|
||||||
|
pub parameters: Vec<(String, TypeKind)>,
|
||||||
|
pub kind: FunctionDefinitionKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FunctionDefinitionKind {
|
||||||
|
/// Actual definition block and surrounding signature range
|
||||||
|
Local(Block, TokenRange),
|
||||||
|
/// Return Type
|
||||||
|
Extern(TypeKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Block {
|
||||||
|
/// List of non-returning statements
|
||||||
|
pub statements: Vec<Statement>,
|
||||||
|
pub return_expression: Option<(ReturnKind, Box<Expression>)>,
|
||||||
|
pub range: TokenRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Statement(pub StatementKind, pub TokenRange);
|
||||||
|
|
||||||
|
pub enum StatementKind {
|
||||||
|
/// Variable name+type, evaluation
|
||||||
|
Let(VariableReference, Expression),
|
||||||
|
If(IfExpression),
|
||||||
|
Import(Import),
|
||||||
|
Expression(Expression),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Module {
|
||||||
|
pub name: String,
|
||||||
|
pub imports: Vec<Import>,
|
||||||
|
pub functions: Vec<FunctionDefinition>,
|
||||||
|
}
|
75
reid/src/mir/types.rs
Normal file
75
reid/src/mir/types.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ReturnTypeOther {
|
||||||
|
Import(TokenRange),
|
||||||
|
Let(TokenRange),
|
||||||
|
EmptyBlock(TokenRange),
|
||||||
|
NoBlockReturn(TokenRange),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ReturnType {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for Block {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
self.return_expression
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(ReturnTypeOther::NoBlockReturn(self.range.clone()))
|
||||||
|
.and_then(|(_, stmt)| stmt.return_type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for Statement {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
use StatementKind::*;
|
||||||
|
match &self.0 {
|
||||||
|
Expression(e) => e.return_type(),
|
||||||
|
If(e) => e.return_type(),
|
||||||
|
Import(_) => Err(ReturnTypeOther::Import(self.1)),
|
||||||
|
Let(_, _) => Err(ReturnTypeOther::Let(self.1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for Expression {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
use ExpressionKind::*;
|
||||||
|
match &self.0 {
|
||||||
|
Literal(lit) => Ok(lit.as_type()),
|
||||||
|
Variable(var) => var.return_type(),
|
||||||
|
BinOp(_, expr, _) => expr.return_type(),
|
||||||
|
Block(block) => block.return_type(),
|
||||||
|
FunctionCall(fcall) => fcall.return_type(),
|
||||||
|
If(expr) => expr.return_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for IfExpression {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
self.1.return_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for VariableReference {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
Ok(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for FunctionCall {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
Ok(self.return_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType for FunctionDefinition {
|
||||||
|
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
||||||
|
match &self.kind {
|
||||||
|
FunctionDefinitionKind::Local(block, _) => block.return_type(),
|
||||||
|
FunctionDefinitionKind::Extern(type_kind) => Ok(*type_kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,10 +9,10 @@ use llvm_sys::transforms::pass_manager_builder::{
|
|||||||
LLVMPassManagerBuilderSetOptLevel,
|
LLVMPassManagerBuilderSetOptLevel,
|
||||||
};
|
};
|
||||||
use llvm_sys::{
|
use llvm_sys::{
|
||||||
LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue, core::*, prelude::*,
|
core::*, prelude::*, LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ast;
|
use crate::parser;
|
||||||
|
|
||||||
fn into_cstring<T: Into<String>>(value: T) -> CString {
|
fn into_cstring<T: Into<String>>(value: T) -> CString {
|
||||||
let string = value.into();
|
let string = value.into();
|
||||||
@ -47,8 +47,8 @@ impl IRType {
|
|||||||
pub struct IRValue(pub IRType, *mut LLVMValue);
|
pub struct IRValue(pub IRType, *mut LLVMValue);
|
||||||
|
|
||||||
impl IRValue {
|
impl IRValue {
|
||||||
pub fn from_literal(literal: &ast::Literal, module: &IRModule) -> Self {
|
pub fn from_literal(literal: &parser::Literal, module: &IRModule) -> Self {
|
||||||
use ast::Literal;
|
use parser::Literal;
|
||||||
match literal {
|
match literal {
|
||||||
Literal::I32(v) => {
|
Literal::I32(v) => {
|
||||||
let ir_type = IRType::I32;
|
let ir_type = IRType::I32;
|
@ -5,7 +5,7 @@ use std::collections::HashMap;
|
|||||||
use llvm::{Error, IRBlock, IRContext, IRFunction, IRModule, IRValue};
|
use llvm::{Error, IRBlock, IRContext, IRFunction, IRModule, IRValue};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
parser::{
|
||||||
Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition, IfExpression,
|
Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition, IfExpression,
|
||||||
LetStatement, ReturnType,
|
LetStatement, ReturnType,
|
||||||
},
|
},
|
||||||
@ -97,7 +97,7 @@ impl Expression {
|
|||||||
Binop(op, lhs, rhs) => {
|
Binop(op, lhs, rhs) => {
|
||||||
let lhs = lhs.codegen(scope);
|
let lhs = lhs.codegen(scope);
|
||||||
let rhs = rhs.codegen(scope);
|
let rhs = rhs.codegen(scope);
|
||||||
use crate::ast::BinaryOperator::*;
|
use crate::parser::BinaryOperator::*;
|
||||||
match op {
|
match op {
|
||||||
Add => scope.block.add(lhs, rhs).unwrap(),
|
Add => scope.block.add(lhs, rhs).unwrap(),
|
||||||
Mult => scope.block.mult(lhs, rhs).unwrap(),
|
Mult => scope.block.mult(lhs, rhs).unwrap(),
|
||||||
@ -121,7 +121,7 @@ impl Expression {
|
|||||||
_ => then.block.move_into(&mut scope.block),
|
_ => then.block.move_into(&mut scope.block),
|
||||||
}
|
}
|
||||||
|
|
||||||
IRValue::from_literal(&crate::ast::Literal::I32(1), scope.block.function.module)
|
IRValue::from_literal(&crate::parser::Literal::I32(1), scope.block.function.module)
|
||||||
}
|
}
|
||||||
BlockExpr(_) => panic!("block expr not supported"),
|
BlockExpr(_) => panic!("block expr not supported"),
|
||||||
FunctionCall(_) => panic!("function call expr not supported"),
|
FunctionCall(_) => panic!("function call expr not supported"),
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::Parse,
|
|
||||||
lexer::{FullToken, Position, Token},
|
lexer::{FullToken, Position, Token},
|
||||||
|
parser::Parse,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TokenStream<'a, 'b> {
|
pub struct TokenStream<'a, 'b> {
|
||||||
@ -156,7 +156,7 @@ impl Drop for TokenStream<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct TokenRange {
|
pub struct TokenRange {
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
@ -168,6 +168,15 @@ impl std::fmt::Debug for TokenRange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for TokenRange {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
start: Default::default(),
|
||||||
|
end: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
||||||
|
Loading…
Reference in New Issue
Block a user