Add function calls and mult
This commit is contained in:
parent
4e89cd7355
commit
f22505be91
@ -1,6 +1,6 @@
|
|||||||
use reid::compile;
|
use reid::compile;
|
||||||
|
|
||||||
pub static EASIEST: &str = include_str!("./reid/easiest.reid");
|
pub static EASIEST: &str = include_str!("./reid/easy.reid");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let text = match compile(EASIEST) {
|
let text = match compile(EASIEST) {
|
||||||
|
@ -9,6 +9,6 @@ fn somethingelse() {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let hello = 32 + 2 + 4;
|
let hello = 32 + 2 + 4;
|
||||||
let beep =
|
let beep =
|
||||||
hello + 100;
|
hello + 100 + somethingelse();
|
||||||
return beep;
|
return beep;
|
||||||
}
|
}
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
import std::print;
|
import std::print;
|
||||||
|
|
||||||
let test = 5;
|
fn main() {
|
||||||
let simpleAdd = 2 + 2;
|
let test = 5;
|
||||||
let arithmetic = 3 + 2 * 5 + 1 * 2;
|
let simpleAdd = 2 + 2;
|
||||||
let multiplier = 5 * 2;
|
let arithmetic = 3 + 2 * 5 + 1 * 2;
|
||||||
|
let multiplier = 5 * 2;
|
||||||
|
|
||||||
let result = arithmetic + multiplier * arithmetic;
|
return arithmetic + multiplier * arithmetic;
|
||||||
print(result);
|
}
|
||||||
function(one, two);
|
|
@ -101,7 +101,7 @@ fn parse_binop_rhs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionCallExpression(String, Vec<Expression>);
|
pub struct FunctionCallExpression(pub String, pub Vec<Expression>);
|
||||||
|
|
||||||
impl Parse for FunctionCallExpression {
|
impl Parse for FunctionCallExpression {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
@ -184,7 +184,7 @@ impl Parse for FunctionDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionSignature {
|
pub struct FunctionSignature {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
117
src/codegen.rs
117
src/codegen.rs
@ -1,28 +1,29 @@
|
|||||||
use std::collections::{hash_map, HashMap};
|
use std::collections::{hash_map, HashMap};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{BinaryOperator, BlockLevelStatement, Expression, FunctionDefinition, TopLevelStatement},
|
ast::{
|
||||||
llvm_ir::{self, IRBlock, IRModule, IRValue, IRValueType},
|
BinaryOperator, BlockLevelStatement, Expression, FunctionCallExpression,
|
||||||
|
FunctionDefinition, FunctionSignature, TopLevelStatement,
|
||||||
|
},
|
||||||
|
llvm_ir::{self, IRBlock, IRFunction, IRModule, IRValue, IRValueType},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Scope<'a> {
|
#[derive(Clone)]
|
||||||
pub block: IRBlock<'a>,
|
pub struct ScopeData {
|
||||||
named_vars: HashMap<String, IRValue>,
|
named_vars: HashMap<String, IRValue>,
|
||||||
|
defined_functions: HashMap<String, (FunctionSignature, Option<IRFunction>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Scope<'a> {
|
impl ScopeData {
|
||||||
pub fn from(block: IRBlock<'a>) -> Self {
|
pub fn inner<'a>(&'a mut self, block: IRBlock<'a>) -> Scope {
|
||||||
Scope {
|
Scope { block, data: self }
|
||||||
block,
|
|
||||||
named_vars: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &String) -> Option<&IRValue> {
|
pub fn var(&self, name: &String) -> Option<&IRValue> {
|
||||||
self.named_vars.get(name)
|
self.named_vars.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, name: &str, val: IRValue) -> Result<(), Error> {
|
pub fn set_var(&mut self, name: &str, val: IRValue) -> Result<(), Error> {
|
||||||
if let hash_map::Entry::Vacant(e) = self.named_vars.entry(name.to_owned()) {
|
if let hash_map::Entry::Vacant(e) = self.named_vars.entry(name.to_owned()) {
|
||||||
e.insert(val);
|
e.insert(val);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -30,14 +31,66 @@ impl<'a> Scope<'a> {
|
|||||||
Err(Error::VariableAlreadyDefined(name.to_owned()))
|
Err(Error::VariableAlreadyDefined(name.to_owned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn function(
|
||||||
|
&mut self,
|
||||||
|
name: &String,
|
||||||
|
) -> Option<&mut (FunctionSignature, Option<IRFunction>)> {
|
||||||
|
self.defined_functions.get_mut(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_function_signature(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
sig: FunctionSignature,
|
||||||
|
ir: IRFunction,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let hash_map::Entry::Vacant(e) = self.defined_functions.entry(name.to_owned()) {
|
||||||
|
e.insert((sig, Some(ir)));
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::VariableAlreadyDefined(name.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Scope<'a, 'b> {
|
||||||
|
pub block: IRBlock<'a>,
|
||||||
|
pub data: &'b mut ScopeData,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn codegen_from_statements(statements: Vec<TopLevelStatement>) -> Result<IRModule, Error> {
|
||||||
|
let mut module = IRModule::new("testmod");
|
||||||
|
|
||||||
|
let mut scope = ScopeData {
|
||||||
|
defined_functions: HashMap::new(),
|
||||||
|
named_vars: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for statement in &statements {
|
||||||
|
match statement {
|
||||||
|
TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, _)) => {
|
||||||
|
let function = module.create_func(&sig.name, IRValueType::I32);
|
||||||
|
scope.set_function_signature(&sig.name.clone(), sig.clone(), function)?;
|
||||||
|
}
|
||||||
|
TopLevelStatement::Import(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for statement in &statements {
|
||||||
|
statement.codegen(&mut module, &mut scope)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TopLevelStatement {
|
impl TopLevelStatement {
|
||||||
pub fn codegen(&self, module: &mut IRModule) -> Result<(), Error> {
|
pub fn codegen(&self, module: &mut IRModule, root_data: &mut ScopeData) -> Result<(), Error> {
|
||||||
match self {
|
match self {
|
||||||
TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => {
|
TopLevelStatement::FunctionDefinition(FunctionDefinition(sig, block)) => {
|
||||||
let func = module.create_func(&sig.name, IRValueType::I32);
|
if let Some((_, ir)) = root_data.function(&sig.name) {
|
||||||
let mut scope = Scope::from(module.create_block());
|
if let Some(ir) = ir.take() {
|
||||||
|
let mut scope = root_data.inner(module.create_block());
|
||||||
|
|
||||||
for statement in &block.0 {
|
for statement in &block.0 {
|
||||||
statement.codegen(&mut scope)?;
|
statement.codegen(&mut scope)?;
|
||||||
@ -48,7 +101,13 @@ impl TopLevelStatement {
|
|||||||
} else {
|
} else {
|
||||||
panic!("Void-return type function not yet implemented!");
|
panic!("Void-return type function not yet implemented!");
|
||||||
};
|
};
|
||||||
func.add_definition(value, scope.block);
|
ir.add_definition(value, scope.block);
|
||||||
|
} else {
|
||||||
|
Err(Error::FunctionAlreadyDefined(sig.name.clone()))?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Function was not declared before it's definition")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TopLevelStatement::Import(_) => {}
|
TopLevelStatement::Import(_) => {}
|
||||||
}
|
}
|
||||||
@ -61,7 +120,7 @@ impl BlockLevelStatement {
|
|||||||
match self {
|
match self {
|
||||||
BlockLevelStatement::Let(let_statement) => {
|
BlockLevelStatement::Let(let_statement) => {
|
||||||
let val = let_statement.1.codegen(scope)?;
|
let val = let_statement.1.codegen(scope)?;
|
||||||
scope.set(&let_statement.0, val)?;
|
scope.data.set_var(&let_statement.0, val)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
BlockLevelStatement::Return(_) => panic!("Should never happen"),
|
BlockLevelStatement::Return(_) => panic!("Should never happen"),
|
||||||
@ -81,12 +140,24 @@ impl Expression {
|
|||||||
let rhs = rhs.codegen(scope)?;
|
let rhs = rhs.codegen(scope)?;
|
||||||
Ok(scope.block.add(lhs, rhs)?)
|
Ok(scope.block.add(lhs, rhs)?)
|
||||||
}
|
}
|
||||||
BinaryOperator::Mult => panic!("Not implemented!"),
|
BinaryOperator::Mult => {
|
||||||
|
let lhs = lhs.codegen(scope)?;
|
||||||
|
let rhs = rhs.codegen(scope)?;
|
||||||
|
Ok(scope.block.mul(lhs, rhs)?)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
BlockExpr(_) => panic!("Not implemented!"),
|
BlockExpr(_) => panic!("(BlockExpr) Not implemented!"),
|
||||||
FunctionCall(_) => panic!("Not implemented!"),
|
FunctionCall(fc) => {
|
||||||
|
let FunctionCallExpression(name, _) = &**fc;
|
||||||
|
if let Some((sig, _)) = scope.data.function(name) {
|
||||||
|
Ok(scope.block.function_call(sig)?)
|
||||||
|
} else {
|
||||||
|
Err(Error::UndefinedFunction(name.clone()))?
|
||||||
|
}
|
||||||
|
}
|
||||||
VariableName(name) => scope
|
VariableName(name) => scope
|
||||||
.get(name)
|
.data
|
||||||
|
.var(name)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(Error::UndefinedVariable(name.clone())),
|
.ok_or(Error::UndefinedVariable(name.clone())),
|
||||||
Literal(lit) => Ok(scope.block.get_const(lit)),
|
Literal(lit) => Ok(scope.block.get_const(lit)),
|
||||||
@ -100,6 +171,10 @@ pub enum Error {
|
|||||||
VariableAlreadyDefined(String),
|
VariableAlreadyDefined(String),
|
||||||
#[error("Variable '{0}' not yet defined")]
|
#[error("Variable '{0}' not yet defined")]
|
||||||
UndefinedVariable(String),
|
UndefinedVariable(String),
|
||||||
|
#[error("Function '{0}' not defined")]
|
||||||
|
UndefinedFunction(String),
|
||||||
|
#[error("Function '{0}' already defined")]
|
||||||
|
FunctionAlreadyDefined(String),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Deeper(#[from] llvm_ir::Error),
|
Deeper(#[from] llvm_ir::Error),
|
||||||
}
|
}
|
||||||
|
10
src/lib.rs
10
src/lib.rs
@ -1,4 +1,7 @@
|
|||||||
use crate::{ast::TopLevelStatement, lexer::Token, llvm_ir::IRModule, token_stream::TokenStream};
|
use crate::{
|
||||||
|
ast::TopLevelStatement, codegen::codegen_from_statements, lexer::Token, llvm_ir::IRModule,
|
||||||
|
token_stream::TokenStream,
|
||||||
|
};
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
@ -37,10 +40,7 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
|
|||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut module = IRModule::new("testmod");
|
let mut module = codegen_from_statements(statements)?;
|
||||||
for statement in statements {
|
|
||||||
statement.codegen(&mut module)?;
|
|
||||||
}
|
|
||||||
let text = module.print_to_string().unwrap();
|
let text = module.print_to_string().unwrap();
|
||||||
Ok(text.to_owned())
|
Ok(text.to_owned())
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::mem;
|
|||||||
|
|
||||||
use llvm_sys::{core::*, prelude::*, LLVMBuilder, LLVMContext, LLVMModule};
|
use llvm_sys::{core::*, prelude::*, LLVMBuilder, LLVMContext, LLVMModule};
|
||||||
|
|
||||||
use crate::ast::Literal;
|
use crate::ast::{FunctionSignature, Literal};
|
||||||
|
|
||||||
macro_rules! cstr {
|
macro_rules! cstr {
|
||||||
($string:expr) => {
|
($string:expr) => {
|
||||||
@ -11,19 +11,6 @@ macro_rules! cstr {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum IRValueType {
|
|
||||||
I32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IRValueType {
|
|
||||||
unsafe fn get_llvm_type(&self, codegen: &mut IRModule) -> LLVMTypeRef {
|
|
||||||
match *self {
|
|
||||||
Self::I32 => LLVMInt32TypeInContext(codegen.context),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "value contains raw pointer and must be inserted somewhere"]
|
#[must_use = "value contains raw pointer and must be inserted somewhere"]
|
||||||
pub struct IRValue(IRValueType, LLVMValueRef);
|
pub struct IRValue(IRValueType, LLVMValueRef);
|
||||||
@ -96,6 +83,20 @@ impl Drop for IRModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum IRValueType {
|
||||||
|
I32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IRValueType {
|
||||||
|
unsafe fn get_llvm_type(&self, codegen: &mut IRModule) -> LLVMTypeRef {
|
||||||
|
match *self {
|
||||||
|
Self::I32 => LLVMInt32TypeInContext(codegen.context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct IRFunction {
|
pub struct IRFunction {
|
||||||
value: IRValue,
|
value: IRValue,
|
||||||
}
|
}
|
||||||
@ -154,6 +155,45 @@ impl<'a> IRBlock<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mul(&mut self, lhs: IRValue, rhs: IRValue) -> Result<IRValue, Error> {
|
||||||
|
unsafe {
|
||||||
|
if lhs.0 == rhs.0 {
|
||||||
|
Ok(IRValue(
|
||||||
|
lhs.0,
|
||||||
|
LLVMBuildMul(self.module.builder, lhs.1, rhs.1, cstr!("tmpadd")),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(Error::TypeMismatch(lhs.0, rhs.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function_call(&mut self, callee: &FunctionSignature) -> Result<IRValue, Error> {
|
||||||
|
unsafe {
|
||||||
|
let function = LLVMGetNamedFunction(
|
||||||
|
self.module.module,
|
||||||
|
into_cstring(callee.name.clone()).as_ptr(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let ret_t = LLVMInt32TypeInContext(self.module.context);
|
||||||
|
let mut argts = [];
|
||||||
|
let mut args = [];
|
||||||
|
|
||||||
|
let fun_t = LLVMFunctionType(ret_t, argts.as_mut_ptr(), argts.len() as u32, 0);
|
||||||
|
|
||||||
|
let call = LLVMBuildCall2(
|
||||||
|
self.module.builder,
|
||||||
|
fun_t,
|
||||||
|
function,
|
||||||
|
args.as_mut_ptr(),
|
||||||
|
args.len() as u32,
|
||||||
|
into_cstring(&callee.name).as_ptr(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(IRValue(IRValueType::I32, call))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
Loading…
Reference in New Issue
Block a user