diff options
| author | Cody <cody@codyq.dev> | 2023-06-09 18:20:22 -0500 |
|---|---|---|
| committer | Cody <cody@codyq.dev> | 2023-06-09 18:20:22 -0500 |
| commit | 9c6ff27ba4ce313887251f59f45a220556e94398 (patch) | |
| tree | 9537cc936b101c5b2dd02659355e496a852fcbd1 | |
| parent | 6f6613419f1511c5637c9f69b3caa5ae838270b9 (diff) | |
| download | sloth-9c6ff27ba4ce313887251f59f45a220556e94398.tar.gz | |
HeheheheHAahhahaha
| -rw-r--r-- | sloth/src/codegen.rs | 90 | ||||
| -rw-r--r-- | sloth/src/compiler.rs | 57 | ||||
| -rw-r--r-- | sloth/src/compiler/mod.rs.disabled (renamed from sloth/src/compiler/mod.rs) | 0 | ||||
| -rw-r--r-- | sloth/src/main.rs | 11 | ||||
| -rw-r--r-- | sloth/src/symbol.rs | 90 |
5 files changed, 244 insertions, 4 deletions
diff --git a/sloth/src/codegen.rs b/sloth/src/codegen.rs new file mode 100644 index 0000000..217be71 --- /dev/null +++ b/sloth/src/codegen.rs @@ -0,0 +1,90 @@ +use inkwell::builder::Builder; +use inkwell::context::Context; +use inkwell::module::Module; +use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType}; +use inkwell::values::FunctionValue; +use itertools::Itertools; + +use crate::parser::ast::{FuncArgs, Stmt}; +use crate::symbol::SymbolTableStack; + +/// A module codegen is a struct designated to compiling a single module +pub struct ModuleCodegen<'ctx, 'a> { + context: &'ctx Context, + builder: Builder<'ctx>, + module: Module<'ctx>, + + symbol_table: &'a mut SymbolTableStack, +} + +impl<'ctx, 'a> ModuleCodegen<'ctx, 'a> { + pub fn new( + module: &str, + context: &'ctx Context, + symbol_table: &'a mut SymbolTableStack, + ) -> Self { + let builder = context.create_builder(); + let module = context.create_module(module); + + Self { + context, + builder, + module, + + symbol_table, + } + } + + pub fn compile_function( + &mut self, + ident: String, + args: Vec<FuncArgs>, + return_type: Option<String>, + body: &[Stmt], + ) { + let llvm_function_type = self.compile_function_type(&args, return_type.as_deref()); + let llvm_function = self.module.add_function(&ident, llvm_function_type, None); + + let entry_block = self.context.append_basic_block(llvm_function, "entry"); + + self.block(body); + } + + fn compile_function_type( + &self, + args: &[FuncArgs], + return_type: Option<&str>, + ) -> FunctionType<'ctx> { + let args = args + .iter() + .map(|it| { + self.compile_basic_metadata_type(it.typ.as_ref().unwrap()) + .unwrap() + }) + .collect_vec(); + + match return_type { + None => self.context.void_type().fn_type(&args, false), + Some("int") => self.context.i64_type().fn_type(&args, false), + Some("float") => self.context.f64_type().fn_type(&args, false), + _ => panic!(), + } + } + + fn compile_basic_metadata_type(&self, typ: &str) -> Option<BasicMetadataTypeEnum<'ctx>> { + match typ { + "int" => Some(self.context.i64_type().into()), + "float" => Some(self.context.f64_type().into()), + _ => None, + } + } + + fn block(&mut self, body: &[Stmt]) { + self.symbol_table.push(); + self.symbol_table.pop(); + } + + // fn compile(symbol_table: &'a mut SymbolTableStack, code: Vec<Stmt>) { + // // + // } +} diff --git a/sloth/src/compiler.rs b/sloth/src/compiler.rs new file mode 100644 index 0000000..2a02ce9 --- /dev/null +++ b/sloth/src/compiler.rs @@ -0,0 +1,57 @@ +use inkwell::context::Context; +use thiserror::Error; + +use crate::codegen::{self, ModuleCodegen}; +use crate::parser::ast::Stmt; +use crate::symbol::{Symbol, SymbolTable, SymbolTableStack, SymbolType}; + +#[derive(Debug, Error)] +pub enum CompilerError { + #[error("Unknown compiler error")] + Unknown, +} + +pub struct Compiler { + symbol_table: SymbolTableStack, +} + +impl Compiler { + /// Take in a AST in the form of a vector of statements and compile the + /// program. + pub fn compile(code: Vec<Stmt>) -> Result<(), CompilerError> { + let mut compiler = Self { + symbol_table: SymbolTableStack::new(), + }; + + // Resolve names + compiler.resolve_globals(&code); + + // Compile each function + let context = Context::create(); + let codegen = ModuleCodegen::new("root", &context, &mut compiler.symbol_table); + + for stmt in code.iter() { + if let Stmt::DefineFunction { body, .. } = stmt { + // compiler.compile_function(body); + } + } + + Ok(()) + } + + fn resolve_globals(&mut self, code: &[Stmt]) { + for stmt in code.iter() { + if let Stmt::DefineFunction { ident, .. } = stmt { + let symbol = Symbol { + typ: Some(SymbolType::Function), + }; + + self.symbol_table.insert(ident, symbol); + } + } + } +} + +// Step 1: Name resolution +// Step 2: Type checking +// Step 3: Code generation diff --git a/sloth/src/compiler/mod.rs b/sloth/src/compiler/mod.rs.disabled index 87c0618..87c0618 100644 --- a/sloth/src/compiler/mod.rs +++ b/sloth/src/compiler/mod.rs.disabled diff --git a/sloth/src/main.rs b/sloth/src/main.rs index a611156..0e429b5 100644 --- a/sloth/src/main.rs +++ b/sloth/src/main.rs @@ -6,14 +6,15 @@ unused_lifetimes )] +pub mod codegen; pub mod compiler; pub mod lexer; pub mod parser; +pub mod symbol; use std::{env, fs}; use compiler::Compiler; -use inkwell::context::Context; use itertools::Itertools; use lexer::Lexer; use parser::AstParser; @@ -36,8 +37,10 @@ fn main() { let tokens = Lexer::new(&source).collect_vec(); let ast = AstParser::new(tokens).parse(); - let context = Context::create(); - let compiler = Compiler::new(&context); + Compiler::compile(ast).unwrap(); - compiler.compile(ast); + // let context = Context::create(); + // let compiler = Compiler::new(&context); + // + // compiler.compile(ast); } diff --git a/sloth/src/symbol.rs b/sloth/src/symbol.rs new file mode 100644 index 0000000..416b042 --- /dev/null +++ b/sloth/src/symbol.rs @@ -0,0 +1,90 @@ +use std::collections::HashMap; + +// TODO: Change name with some sort of path to make modules possible + +#[derive(Debug)] +pub struct SymbolTableStack { + tables: Vec<SymbolTable>, +} + +impl Default for SymbolTableStack { + fn default() -> Self { + Self { + tables: vec![SymbolTable::default()], + } + } +} + +impl SymbolTableStack { + pub fn new() -> Self { + Self::default() + } + + pub fn get(&self, name: &str) -> Option<&Symbol> { + for table in self.tables.iter().rev() { + if let Some(symbol) = table.get(name) { + return Some(symbol); + } + } + + None + } + + /// Returning true means a symbol was overriden + pub fn insert(&mut self, name: impl Into<String>, symbol: Symbol) -> bool { + let head = self.tables.len() - 1; + self.tables[head].insert(name, symbol) + } + + pub fn push(&mut self) { + self.tables.push(SymbolTable::default()); + } + + pub fn pop(&mut self) -> bool { + if self.tables.len() <= 1 { + // Symbol table stacks must always have atleast 1 stack + return false; + } + + self.tables.pop(); + true + } + + pub fn root(&self) -> &SymbolTable { + &self.tables[0] + } + + pub fn root_mut(&mut self) -> &mut SymbolTable { + &mut self.tables[0] + } +} + +#[derive(Debug, Default)] +pub struct SymbolTable { + symbols: HashMap<String, Symbol>, +} + +impl SymbolTable { + pub fn new() -> Self { + Self::default() + } + + pub fn get(&self, name: &str) -> Option<&Symbol> { + self.symbols.get(name) + } + + /// Returning true means a symbol was overriden + pub fn insert(&mut self, name: impl Into<String>, symbol: Symbol) -> bool { + self.symbols.insert(name.into(), symbol).is_some() + } +} + +#[derive(Debug)] +pub struct Symbol { + pub typ: Option<SymbolType>, +} + +#[derive(Debug)] +pub enum SymbolType { + Function, +} |
