Skip to content

Commit

Permalink
Initializes codegen for function body
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Sep 19, 2023
1 parent e182b35 commit 6cc84e1
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 23 deletions.
4 changes: 4 additions & 0 deletions stage0/src/ast/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ impl Attributes {
self.config.as_ref()
}

pub fn ext(&self) -> Option<&(AttributeName, Extern)> {
self.ext.as_ref()
}

pub fn repr(&self) -> Option<&(AttributeName, Representation)> {
self.repr.as_ref()
}
Expand Down
46 changes: 37 additions & 9 deletions stage0/src/ast/func.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::{Attributes, Statement, Type};
use crate::codegen::{Codegen, LlvmFunc, LlvmType, LlvmVoid};
use crate::lexer::{FnKeyword, Identifier, SyntaxError};
use super::{Attributes, Extern, Statement, Type};
use crate::codegen::{BasicBlock, Builder, Codegen, LlvmFunc, LlvmType, LlvmVoid};
use crate::lexer::{Identifier, SyntaxError};
use std::borrow::Cow;
use std::ffi::CString;

/// A function.
pub struct Function {
attrs: Attributes,
def: FnKeyword,
name: Identifier,
params: Vec<FunctionParam>,
ret: Option<Type>,
Expand All @@ -16,15 +16,13 @@ pub struct Function {
impl Function {
pub fn new(
attrs: Attributes,
def: FnKeyword,
name: Identifier,
params: Vec<FunctionParam>,
ret: Option<Type>,
body: Option<Vec<Statement>>,
) -> Self {
Self {
attrs,
def,
name,
params,
ret,
Expand All @@ -44,8 +42,14 @@ impl Function {
}
}

// Build function name.
let name = match self.attrs.ext() {
Some((_, Extern::C)) => Cow::Borrowed(self.name.value()),
None => Cow::Owned(cx.encode_name(container, self.name.value())),
};

// Check if function already exists.
let name = CString::new(cx.encode_name(container, self.name.value())).unwrap();
let name = CString::new(name.as_ref()).unwrap();

if LlvmFunc::get(cx, &name).is_some() {
return Err(SyntaxError::new(
Expand Down Expand Up @@ -85,11 +89,35 @@ impl Function {
};

// Create a function.
let func = LlvmFunc::new(cx, name, &params, ret);
let mut func = LlvmFunc::new(cx, name, &params, ret);

match &self.body {
Some(v) => Self::build_body(cx, &mut func, v),
None => {
if self.attrs.ext().is_none() {
return Err(SyntaxError::new(
self.name.span().clone(),
"a body is required for non-extern or non-abstract",
));
}
}
}

// TODO: Build function body.
Ok(Some(func))
}

fn build_body<'a, 'b: 'a>(
cx: &'a Codegen<'b>,
func: &mut LlvmFunc<'a, 'b>,
stmts: &[Statement],
) {
let mut bb = BasicBlock::new(cx);
let mut b = Builder::new(cx, &mut bb);

b.ret_void();

func.append(bb);
}
}

/// A function parameter.
Expand Down
19 changes: 7 additions & 12 deletions stage0/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ pub use self::ty::*;
pub use self::using::*;

use crate::lexer::{
ClassKeyword, FnKeyword, Identifier, ImplKeyword, Lexer, StructKeyword, SyntaxError, Token,
UseKeyword,
ClassKeyword, Identifier, ImplKeyword, Lexer, StructKeyword, SyntaxError, Token, UseKeyword,
};
use std::path::PathBuf;
use thiserror::Error;
Expand Down Expand Up @@ -342,8 +341,8 @@ impl SourceFile {

match tok {
Token::AttributeName(name) => attrs = Some(Attributes::parse(lex, name)?),
Token::FnKeyword(def) => {
functions.push(Self::parse_fn(lex, attrs.take().unwrap_or_default(), def)?);
Token::FnKeyword(_) => {
functions.push(Self::parse_fn(lex, attrs.take().unwrap_or_default())?);
}
Token::CloseCurly(_) => break,
t => return Err(SyntaxError::new(t.span().clone(), "syntax error")),
Expand All @@ -353,11 +352,7 @@ impl SourceFile {
Ok(TypeImpl::new(def, ty, functions))
}

fn parse_fn(
lex: &mut Lexer,
attrs: Attributes,
def: FnKeyword,
) -> Result<Function, SyntaxError> {
fn parse_fn(lex: &mut Lexer, attrs: Attributes) -> Result<Function, SyntaxError> {
let name = lex.next_ident()?;

// Parse parameters.
Expand Down Expand Up @@ -416,7 +411,7 @@ impl SourceFile {
};

let ret = match next {
Token::Semicolon(_) => return Ok(Function::new(attrs, def, name, params, None, None)),
Token::Semicolon(_) => return Ok(Function::new(attrs, name, params, None, None)),
Token::OpenCurly(_) => None,
Token::Colon(_) => {
let ret = Self::parse_type(lex)?;
Expand All @@ -432,7 +427,7 @@ impl SourceFile {

match next {
Token::Semicolon(_) => {
return Ok(Function::new(attrs, def, name, params, Some(ret), None));
return Ok(Function::new(attrs, name, params, Some(ret), None));
}
Token::OpenCurly(_) => {}
t => {
Expand All @@ -456,7 +451,7 @@ impl SourceFile {
// Parse body.
let body = Statement::parse_block(lex)?;

Ok(Function::new(attrs, def, name, params, ret, Some(body)))
Ok(Function::new(attrs, name, params, ret, Some(body)))
}

fn parse_type(lex: &mut Lexer) -> Result<Type, SyntaxError> {
Expand Down
29 changes: 29 additions & 0 deletions stage0/src/codegen/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use super::Codegen;
use llvm_sys::core::{LLVMCreateBasicBlockInContext, LLVMDeleteBasicBlock};
use llvm_sys::prelude::LLVMBasicBlockRef;
use std::marker::PhantomData;

/// Encapsulate an LLVM basic block.
pub struct BasicBlock<'a, 'b: 'a> {
value: LLVMBasicBlockRef,
phantom: PhantomData<&'a Codegen<'b>>,
}

impl<'a, 'b: 'a> BasicBlock<'a, 'b> {
pub fn new(cx: &'a Codegen<'b>) -> Self {
Self {
value: unsafe { LLVMCreateBasicBlockInContext(cx.llvm, b"\0".as_ptr() as _) },
phantom: PhantomData,
}
}

pub fn as_raw(&self) -> LLVMBasicBlockRef {
self.value
}
}

impl<'a, 'b: 'a> Drop for BasicBlock<'a, 'b> {
fn drop(&mut self) {
unsafe { LLVMDeleteBasicBlock(self.value) };
}
}
35 changes: 35 additions & 0 deletions stage0/src/codegen/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use super::{BasicBlock, Codegen};
use llvm_sys::core::{
LLVMBuildRetVoid, LLVMCreateBuilderInContext, LLVMDisposeBuilder, LLVMPositionBuilderAtEnd,
};
use llvm_sys::prelude::LLVMBuilderRef;
use std::marker::PhantomData;

/// Encapsulate an LLVM IR builder.
pub struct Builder<'a, 'b: 'a> {
raw: LLVMBuilderRef,
phantom: PhantomData<&'a Codegen<'b>>,
}

impl<'a, 'b: 'a> Builder<'a, 'b> {
pub fn new(cx: &'a Codegen<'b>, block: &mut BasicBlock<'a, 'b>) -> Self {
let raw = unsafe { LLVMCreateBuilderInContext(cx.llvm) };

unsafe { LLVMPositionBuilderAtEnd(raw, block.as_raw()) };

Self {
raw,
phantom: PhantomData,
}
}

pub fn ret_void(&mut self) {
unsafe { LLVMBuildRetVoid(self.raw) };
}
}

impl<'a, 'b: 'a> Drop for Builder<'a, 'b> {
fn drop(&mut self) {
unsafe { LLVMDisposeBuilder(self.raw) };
}
}
12 changes: 10 additions & 2 deletions stage0/src/codegen/func.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use super::{Codegen, LlvmType};
use llvm_sys::core::{LLVMAddFunction, LLVMFunctionType, LLVMGetNamedFunction};
use super::{BasicBlock, Codegen, LlvmType};
use llvm_sys::core::{
LLVMAddFunction, LLVMAppendExistingBasicBlock, LLVMFunctionType, LLVMGetNamedFunction,
};
use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};
use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem::forget;

/// A function.
pub struct LlvmFunc<'a, 'b: 'a> {
Expand Down Expand Up @@ -47,4 +50,9 @@ impl<'a, 'b: 'a> LlvmFunc<'a, 'b> {
phantom: PhantomData,
}
}

pub fn append(&mut self, block: BasicBlock<'a, 'b>) {
unsafe { LLVMAppendExistingBasicBlock(self.value, block.as_raw()) };
forget(block);
}
}
4 changes: 4 additions & 0 deletions stage0/src/codegen/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub use self::block::*;
pub use self::builder::*;
pub use self::func::*;
pub use self::resolver::*;
pub use self::target::*;
Expand All @@ -22,6 +24,8 @@ use llvm_sys::target_machine::{
use std::ffi::CStr;
use std::ptr::{null, null_mut};

mod block;
mod builder;
mod func;
mod resolver;
mod target;
Expand Down

0 comments on commit 6cc84e1

Please sign in to comment.