Add necessary codegen for easy.reid

This commit is contained in:
Sofia 2024-08-21 23:31:09 +03:00
parent e00d9afc7b
commit 6448b0c438
3 changed files with 130 additions and 52 deletions

View File

@ -362,7 +362,7 @@ impl Parse for Block {
statements.push(BlockLevelStatement::Expression(e)); statements.push(BlockLevelStatement::Expression(e));
} }
let statement = stream.parse()?; let statement = stream.parse()?;
if let BlockLevelStatement::Return((r_type, e)) = &statement { if let BlockLevelStatement::Return(r_type, e) = &statement {
match r_type { match r_type {
ReturnType::Hard => { ReturnType::Hard => {
return_stmt = Some((*r_type, e.clone())); return_stmt = Some((*r_type, e.clone()));
@ -387,7 +387,7 @@ pub enum BlockLevelStatement {
Let(LetStatement), Let(LetStatement),
Import(ImportStatement), Import(ImportStatement),
Expression(Expression), Expression(Expression),
Return((ReturnType, Expression)), Return(ReturnType, Expression),
} }
impl Parse for BlockLevelStatement { impl Parse for BlockLevelStatement {
@ -400,14 +400,14 @@ impl Parse for BlockLevelStatement {
stream.next(); stream.next();
let exp = stream.parse()?; let exp = stream.parse()?;
stream.expect(Token::Semi)?; stream.expect(Token::Semi)?;
Stmt::Return((ReturnType::Hard, exp)) Stmt::Return(ReturnType::Hard, exp)
} }
_ => { _ => {
if let Ok(e) = stream.parse() { if let Ok(e) = stream.parse() {
if stream.expect(Token::Semi).is_ok() { if stream.expect(Token::Semi).is_ok() {
Stmt::Expression(e) Stmt::Expression(e)
} else { } else {
Stmt::Return((ReturnType::Soft, e)) Stmt::Return(ReturnType::Soft, e)
} }
} else { } else {
Err(stream.expected_err("expression")?)? Err(stream.expected_err("expression")?)?

View File

@ -12,6 +12,50 @@ fn into_cstring<T: Into<String>>(value: T) -> CString {
unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) }
} }
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Type mismatch: {0:?} vs {1:?}")]
TypeMismatch(IRType, IRType),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum IRType {
I32,
}
impl IRType {
fn in_context(&self, context: &mut IRContext) -> *mut LLVMType {
use IRType::*;
unsafe {
return match self {
I32 => LLVMInt32TypeInContext(context.context),
};
}
}
}
#[derive(Clone)]
pub struct IRValue(pub IRType, *mut LLVMValue);
impl IRValue {
pub fn from_literal(literal: &ast::Literal, block: &mut IRBlock) -> Self {
use ast::Literal;
match literal {
Literal::I32(v) => {
let ir_type = IRType::I32;
unsafe {
let ir_value = LLVMConstInt(
ir_type.in_context(block.function.module.context),
mem::transmute(*v as i64),
1,
);
return IRValue(ir_type, ir_value);
}
}
};
}
}
pub struct IRContext { pub struct IRContext {
context: *mut LLVMContext, context: *mut LLVMContext,
builder: *mut LLVMBuilder, builder: *mut LLVMBuilder,
@ -71,22 +115,6 @@ impl<'a> Drop for IRModule<'a> {
} }
} }
#[derive(Clone)]
pub enum IRType {
I32,
}
impl IRType {
fn in_context(&self, context: &mut IRContext) -> *mut LLVMType {
use IRType::*;
unsafe {
return match self {
I32 => LLVMInt32TypeInContext(context.context),
};
}
}
}
pub struct IRFunction<'a, 'b> { pub struct IRFunction<'a, 'b> {
module: &'b mut IRModule<'a>, module: &'b mut IRModule<'a>,
/// The actual function /// The actual function
@ -132,10 +160,54 @@ impl<'a, 'b, 'c> IRBlock<'a, 'b, 'c> {
} }
} }
pub fn add(
&mut self,
IRValue(lhs_t, lhs_v): IRValue,
IRValue(rhs_t, rhs_v): IRValue,
) -> Result<IRValue, Error> {
unsafe {
if lhs_t == rhs_t {
Ok(IRValue(
lhs_t,
LLVMBuildAdd(
self.function.module.context.builder,
lhs_v,
rhs_v,
c"tmpadd".as_ptr(),
),
))
} else {
Err(Error::TypeMismatch(lhs_t, rhs_t))
}
}
}
pub fn mult(
&mut self,
IRValue(lhs_t, lhs_v): IRValue,
IRValue(rhs_t, rhs_v): IRValue,
) -> Result<IRValue, Error> {
unsafe {
if lhs_t == rhs_t {
Ok(IRValue(
lhs_t,
LLVMBuildMul(
self.function.module.context.builder,
lhs_v,
rhs_v,
c"tmpadd".as_ptr(),
),
))
} else {
Err(Error::TypeMismatch(lhs_t, rhs_t))
}
}
}
pub fn add_return(self, value: Option<IRValue>) { pub fn add_return(self, value: Option<IRValue>) {
unsafe { unsafe {
if let Some(value) = value { if let Some(IRValue(_, value)) = value {
LLVMBuildRet(self.function.module.context.builder, value.ir_value); LLVMBuildRet(self.function.module.context.builder, value);
} else { } else {
LLVMBuildRetVoid(self.function.module.context.builder); LLVMBuildRetVoid(self.function.module.context.builder);
} }
@ -150,28 +222,3 @@ impl<'a, 'b, 'c> Drop for IRBlock<'a, 'b, 'c> {
} }
} }
} }
#[derive(Clone)]
pub struct IRValue {
pub ir_type: IRType,
ir_value: *mut LLVMValue,
}
impl IRValue {
pub fn from_literal(literal: &ast::Literal, block: &mut IRBlock) -> Self {
use ast::Literal;
match literal {
Literal::I32(v) => {
let ir_type = IRType::I32;
unsafe {
let ir_value = LLVMConstInt(
ir_type.in_context(block.function.module.context),
mem::transmute(*v as i64),
1,
);
return IRValue { ir_type, ir_value };
}
}
};
}
}

View File

@ -2,16 +2,16 @@ mod llvm;
use std::collections::HashMap; use std::collections::HashMap;
use llvm::{IRBlock, IRContext, IRFunction, IRModule, IRValue}; use llvm::{Error, IRBlock, IRContext, IRFunction, IRModule, IRValue};
use crate::{ use crate::{
ast::{Block, Expression, ExpressionKind, FunctionDefinition}, ast::{
BinaryOperator, Block, BlockLevelStatement, Expression, ExpressionKind, FunctionDefinition,
LetStatement, ReturnType,
},
TopLevelStatement, TopLevelStatement,
}; };
#[derive(thiserror::Error, Debug)]
pub enum Error {}
pub fn form_context() -> IRContext { pub fn form_context() -> IRContext {
IRContext::new() IRContext::new()
} }
@ -49,6 +49,10 @@ impl FunctionDefinition {
impl Block { impl Block {
fn codegen(&self, mut scope: Scope) { fn codegen(&self, mut scope: Scope) {
for statement in &self.0 {
statement.codegen(&mut scope);
}
if let Some((_, return_exp)) = &self.1 { if let Some((_, return_exp)) = &self.1 {
let value = return_exp.codegen(&mut scope); let value = return_exp.codegen(&mut scope);
scope.block.add_return(Some(value)); scope.block.add_return(Some(value));
@ -56,6 +60,23 @@ impl Block {
} }
} }
impl BlockLevelStatement {
fn codegen(&self, scope: &mut Scope) {
use BlockLevelStatement::*;
match self {
Expression(exp) | Return(ReturnType::Soft, exp) => {
exp.codegen(scope);
}
Let(LetStatement(name, exp, _)) => {
let val = exp.codegen(scope);
scope.data.insert(name, val);
}
Return(ReturnType::Hard, _) => panic!("hard returns here should not be possible.."),
Import(_) => panic!("block level import not supported"),
}
}
}
impl Expression { impl Expression {
fn codegen(&self, scope: &mut Scope) -> IRValue { fn codegen(&self, scope: &mut Scope) -> IRValue {
let Expression(kind, _) = self; let Expression(kind, _) = self;
@ -64,6 +85,16 @@ impl Expression {
match kind { match kind {
Literal(lit) => IRValue::from_literal(lit, &mut scope.block), Literal(lit) => IRValue::from_literal(lit, &mut scope.block),
VariableName(v) => scope.data.fetch(v), VariableName(v) => scope.data.fetch(v),
Binop(op, lhs, rhs) => {
let lhs = lhs.codegen(scope);
let rhs = rhs.codegen(scope);
use crate::ast::BinaryOperator::*;
match op {
Add => scope.block.add(lhs, rhs).unwrap(),
Mult => scope.block.mult(lhs, rhs).unwrap(),
_ => panic!("operator not supported: {:?}", op),
}
}
_ => panic!("expression type not supported"), _ => panic!("expression type not supported"),
} }
} }