added the compiler

This commit is contained in:
Andrew Segavac
2020-04-13 23:59:01 -06:00
parent 76c539cf5c
commit 084765744c
7 changed files with 321 additions and 16 deletions

View File

@@ -5,19 +5,19 @@ pub enum Operator {
Div,
Plus,
Minus,
Gt,
Gte,
Lt,
Lte,
Eq,
Mod,
Exp,
FloorDiv,
// Gt,
// Gte,
// Lt,
// Lte,
// Eq,
// Mod,
// Exp,
// FloorDiv,
}
pub struct LiteralInt {
pub value: i32
pub value: i64
}
// pub struct LiteralString {
@@ -28,9 +28,15 @@ pub struct Identifier {
pub name: String
}
pub struct FunctionCall {
pub name: Identifier,
pub arguments: Vec<Box<Expression>>,
}
pub enum Expression {
LiteralInt(LiteralInt),
// LiteralString(LiteralString),
FunctionCall(FunctionCall),
Identifier(Identifier),
Op(Box<Expression>, Operator, Box<Expression>),
}
@@ -58,6 +64,6 @@ pub struct Function {
// }
pub struct Program {
pub struct Module {
pub functions: Vec<Function>,
}

125
src/compiler.rs Normal file
View File

@@ -0,0 +1,125 @@
use std::collections::HashMap;
use std::mem;
use std::convert::TryInto;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::Module;
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue};
use crate::ast;
type Scope<'ctx> = HashMap<String, BasicValueEnum<'ctx>>;
pub struct ModuleCodeGen<'ctx> {
context: &'ctx Context,
module: Module<'ctx>,
builder: Builder<'ctx>,
scope: Scope<'ctx>,
}
impl<'ctx> ModuleCodeGen<'ctx> {
pub fn new(context: &'ctx Context, name: String) -> Self {
return ModuleCodeGen{
context: context,
module: context.create_module(&name),
builder: context.create_builder(),
scope: Scope::new(),
}
}
pub fn gen_literal_int(&mut self, literal_int: ast::LiteralInt) -> IntValue<'ctx> {
self.context.i64_type().const_int(unsafe { mem::transmute::<i64, u64>(literal_int.value) }, true)
}
pub fn gen_op_expression(&mut self, scope: &Scope<'ctx>, lhs: Box<ast::Expression>, op: ast::Operator, rhs: Box<ast::Expression>) -> IntValue<'ctx> {
let lhs_result = self.gen_expression(scope, lhs);
let rhs_result = self.gen_expression(scope, rhs);
self.gen_op_int(lhs_result, rhs_result, op)
}
pub fn gen_op_int(&mut self, lhs: IntValue<'ctx>, rhs: IntValue<'ctx>, op: ast::Operator) -> IntValue<'ctx> {
match op {
ast::Operator::Plus => self.builder.build_int_add(lhs, rhs, "add"),
ast::Operator::Minus => self.builder.build_int_sub(lhs, rhs, "sub"),
ast::Operator::Mul => self.builder.build_int_mul(lhs, rhs, "mul"),
ast::Operator::Div => self.builder.build_int_signed_div(lhs, rhs, "div"),
}
}
pub fn gen_expression(&mut self, scope: &Scope<'ctx>, expression: Box<ast::Expression>) -> IntValue<'ctx> {
match *expression {
ast::Expression::LiteralInt(literal_int) => self.gen_literal_int(literal_int),
ast::Expression::Identifier(identifier) => {
match scope[&identifier.name] {
BasicValueEnum::IntValue(value) => value,
_ => panic!("function returned type other than int, no types yet"),
}
},
ast::Expression::FunctionCall(function_call) => self.gen_function_call(scope, function_call),
ast::Expression::Op(lhs, op, rhs) => self.gen_op_expression(scope, lhs, op, rhs),
}
}
pub fn gen_function_call(&mut self, scope: &Scope<'ctx>, function_call: ast::FunctionCall) -> IntValue<'ctx> {
println!("Calling function: {}", &function_call.name.name);
let fn_value = self.module.get_function(&function_call.name.name).unwrap();
let mut arguments = Vec::new();
for expression in function_call.arguments.into_iter() {
arguments.push(BasicValueEnum::IntValue(self.gen_expression(scope, expression)));
}
let result = self.builder.build_call(fn_value, &arguments, &function_call.name.name)
.try_as_basic_value()
.left()
.unwrap();
match result {
BasicValueEnum::IntValue(value) => value,
_ => panic!("function returned type other than int, no types yet"),
}
}
// Generates a FunctionValue for an `ast::Function`. This does not genereate a body,
// that task is left to the `gen_function` function. The reason this is split
// between two functions is that first all signatures are generated and then all bodies. This
// allows bodies to reference `FunctionValue` wherever they are declared in the file.
pub fn gen_signature(&mut self, function: &ast::Function) -> FunctionValue {
let mut args = Vec::new();
for _ in &function.arguments {
args.push(self.context.i64_type().into());
}
let fn_type = self.context.i64_type().fn_type(&args, false);
println!("Adding function: {}", &function.name.name);
let fn_value = self.module.add_function(&function.name.name, fn_type, None);
fn_value
}
pub fn gen_function(&mut self, function: ast::Function) {
let fn_value = self.module.get_function(&function.name.name).unwrap();
let basic_block = self.context.append_basic_block(fn_value, "entry");
self.builder.position_at_end(basic_block);
let mut scope = self.scope.clone();
for (i, param) in function.arguments.into_iter().enumerate() {
scope.insert(param.name.name, fn_value.get_nth_param(i.try_into().unwrap()).unwrap());
}
let body = function.block;
let return_value = self.gen_expression(&scope, body.expression);
self.builder.build_return(Some(&return_value));
}
pub fn gen_module(&mut self, module: ast::Module) {
// generate all signatures before the fuction bodies
for function in &module.functions {
self.gen_signature(&function);
}
for function in module.functions {
self.gen_function(function);
}
}
pub fn dump(&self) -> String {
self.module.print_to_string().to_string()
}
}

View File

@@ -6,13 +6,17 @@ grammar;
pub LiteralInt: ast::LiteralInt = {
r"[0-9]+" => ast::LiteralInt{value: i32::from_str(<>).unwrap()}
r"[0-9]+" => ast::LiteralInt{value: i64::from_str(<>).unwrap()}
};
pub Identifier: ast::Identifier = {
r"[A-Za-z][A-Za-z0-9_]*" => ast::Identifier{name: <>.to_string()}
};
pub FunctionCall: ast::FunctionCall = {
<i:Identifier> "(" <args:Comma<Expression>> ")" => ast::FunctionCall{name:i, arguments: args}
}
pub Expression: Box<ast::Expression> = {
<l:Expression> "+" <r:Factor> => Box::new(ast::Expression::Op(l, ast::Operator::Plus, r)),
<l:Expression> "-" <r:Factor> => Box::new(ast::Expression::Op(l, ast::Operator::Minus, r)),
@@ -28,6 +32,7 @@ pub Factor: Box<ast::Expression> = {
pub Term: Box<ast::Expression> = {
LiteralInt => Box::new(ast::Expression::LiteralInt(<>)),
Identifier => Box::new(ast::Expression::Identifier(<>)),
<FunctionCall> => Box::new(ast::Expression::FunctionCall(<>)),
"(" <Expression> ")",
}
@@ -44,8 +49,8 @@ pub Function: ast::Function = {
}
pub Program: ast::Program = {
<fs:Function*> => ast::Program{functions: fs}
pub Module: ast::Module = {
<fs:Function*> => ast::Module{functions: fs}
}

View File

@@ -3,8 +3,26 @@ mod ast;
lalrpop_mod!(pub grammar); // synthesized by LALRPOP
mod compiler;
use inkwell::context::Context;
fn main() {
println!("Hello, world!");
let module_ast = grammar::ModuleParser::new().parse("
fn add(a, b) {
a + b
}
fn subtract(a, b) {
a - b
}
fn main() {
add(4, subtract(5, 2))
}
").unwrap();
let context = Context::create();
let mut code_gen = compiler::ModuleCodeGen::new(&context, "main".to_string());
code_gen.gen_module(module_ast);
println!("{}", code_gen.dump());
}
@@ -32,6 +50,8 @@ fn grammar() {
assert!(grammar::FunctionParser::new().parse("fn add(a, b) { a + }").is_err());
assert!(grammar::FunctionParser::new().parse("fn add(a, b)").is_err());
assert!(grammar::ProgramParser::new().parse("fn add(a, b) { a + b }").is_ok());
assert!(grammar::ProgramParser::new().parse("fn add(a, b) { a + b } fn subtract(a, b) { a - b }").is_ok());
assert!(grammar::FunctionCallParser::new().parse("foo(1, 2)").is_ok());
assert!(grammar::ModuleParser::new().parse("fn add(a, b) { a + b }").is_ok());
assert!(grammar::ModuleParser::new().parse("fn add(a, b) { a + b } fn subtract(a, b) { a - b }").is_ok());
}