aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sloth/src/codegen.rs90
-rw-r--r--sloth/src/compiler.rs57
-rw-r--r--sloth/src/compiler/mod.rs.disabled (renamed from sloth/src/compiler/mod.rs)0
-rw-r--r--sloth/src/main.rs11
-rw-r--r--sloth/src/symbol.rs90
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,
+}