diff options
| author | Cody <cody@codyq.dev> | 2023-06-07 03:28:40 -0500 |
|---|---|---|
| committer | Cody <cody@codyq.dev> | 2023-06-07 03:28:40 -0500 |
| commit | 6f6613419f1511c5637c9f69b3caa5ae838270b9 (patch) | |
| tree | e203d6cdc0eb2140ae6f0a430e76f2992de66bec /sloth/src/compiler/mod.rs | |
| parent | 25c5ccb29a6f2387a04bfb5d50874e00084c15d6 (diff) | |
| download | sloth-6f6613419f1511c5637c9f69b3caa5ae838270b9.tar.gz | |
Moving over from a VM interpreter to natively compiled w/ LLVM
Diffstat (limited to 'sloth/src/compiler/mod.rs')
| -rw-r--r-- | sloth/src/compiler/mod.rs | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/sloth/src/compiler/mod.rs b/sloth/src/compiler/mod.rs new file mode 100644 index 0000000..87c0618 --- /dev/null +++ b/sloth/src/compiler/mod.rs @@ -0,0 +1,131 @@ +#![allow(unused)] + +use std::collections::HashMap; +use std::path::Path; +use std::vec; + +use inkwell::builder::Builder; +use inkwell::context::Context; +use inkwell::module::Module; +use inkwell::targets::{ + CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, +}; +use inkwell::values::IntValue; +use inkwell::OptimizationLevel; + +use crate::parser::ast::{BinaryOp, Expr, FuncArgs, Literal, Stmt, UnaryOp}; + +pub struct Compiler<'ctx> { + context: &'ctx Context, + builder: Builder<'ctx>, + module: Module<'ctx>, +} + +impl<'ctx> Compiler<'ctx> { + pub fn new(context: &'ctx Context) -> Self { + let builder = context.create_builder(); + let module = context.create_module("sloth"); + + Self { + context, + builder, + module, + } + } + + pub fn compile(&self, src: Vec<Stmt>) { + for stmt in src { + match stmt { + Stmt::DefineFunction { + ident, + args, + body, + return_type, + } => { + self.compile_function(&ident, &args, return_type.is_some(), body); + } + _ => panic!("You may only define a function top level"), + } + } + + Target::initialize_native(&InitializationConfig::default()).unwrap(); + + let triple = TargetMachine::get_default_triple(); + let target = Target::from_triple(&triple).unwrap(); + let machine = target + .create_target_machine( + &triple, + "x86-64", + "", + OptimizationLevel::None, + RelocMode::Default, + CodeModel::Default, + ) + .unwrap(); + + self.module.set_triple(&triple); + machine + .write_to_file(&self.module, FileType::Object, Path::new("output.o")) + .unwrap(); + } + + fn compile_function(&self, identifier: &str, args: &[FuncArgs], returns: bool, src: Vec<Stmt>) { + let void_type = self.context.void_type(); + let i64_type = self.context.i64_type(); + + let function_type = if returns { + i64_type.fn_type(&vec![i64_type.into(); args.len()], false) + } else { + void_type.fn_type(&vec![i64_type.into(); args.len()], false) + }; + let function = self.module.add_function(identifier, function_type, None); + + let basic_block = self.context.append_basic_block(function, "body"); + + self.builder.position_at_end(basic_block); + + let mut arg_values = HashMap::<String, IntValue>::new(); + for (i, arg) in args.iter().enumerate() { + arg_values.insert( + arg.name.clone(), + function.get_nth_param(i as u32).unwrap().into_int_value(), + ); + } + + for stmt in src { + match stmt { + Stmt::Return { value } => match value { + Expr::BinaryOp { op, lhs, rhs } => { + let lhs = match *lhs { + Expr::Variable(a) => arg_values[&a], + _ => unimplemented!(), + }; + + let rhs = match *rhs { + Expr::Variable(a) => arg_values[&a], + _ => unimplemented!(), + }; + + let res = match op { + BinaryOp::Add => self.builder.build_int_add(lhs, rhs, "addop"), + BinaryOp::Sub => self.builder.build_int_sub(lhs, rhs, "subop"), + _ => unimplemented!(), + }; + + self.builder.build_return(Some(&res)); + return; + } + Expr::Variable(name) => { + let var = arg_values[&name]; + self.builder.build_return(Some(&var)); + return; + } + _ => unimplemented!(), + }, + _ => unimplemented!(), + } + } + + self.builder.build_return(None); + } +} |
