aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody <cody@codyq.dev>2023-06-25 23:23:04 -0500
committerCody <cody@codyq.dev>2023-06-25 23:23:04 -0500
commitae4c1af949c7230c07b2a7cc86a2e4031c37f651 (patch)
tree28d2f870bc0d6e57234b20bd9c443dc5d8d7f7e1
parent6a59bf6d5345fbe2487e1cc36c36aa6884fcc39d (diff)
downloadsloth-ae4c1af949c7230c07b2a7cc86a2e4031c37f651.tar.gz
getting loopy
-rw-r--r--examples/hello.sloth17
-rw-r--r--sloth/src/analysis/mod.rs4
-rw-r--r--sloth/src/analysis/setup.rs259
-rw-r--r--sloth/src/codegen/mod.rs268
-rw-r--r--sloth/src/main.rs10
-rw-r--r--sloth/src/symtable.rs16
-rw-r--r--test.c12
-rw-r--r--test.sloth7
8 files changed, 404 insertions, 189 deletions
diff --git a/examples/hello.sloth b/examples/hello.sloth
index 5deb0fc..4b99943 100644
--- a/examples/hello.sloth
+++ b/examples/hello.sloth
@@ -1,13 +1,12 @@
-# foreign fn example();
+foreign fn addz(lhs: Int, rhs: Int) Int;
-foreign fn foo() Int;
-foreign fn bar(y: Int, z: Int) Float;
+fn haiiii() Void {}
-fn main() Int {
- foo();
- foo();
- foo();
- bar(5, 8 * 3 + foo());
- return 7 + 5;
+fn hehehaha() Int {
+ var x: Int = 0;
+ while x < 10 {
+ x = x + 1;
+ }
+ return x;
}
diff --git a/sloth/src/analysis/mod.rs b/sloth/src/analysis/mod.rs
index 29f1a91..1c2f0d2 100644
--- a/sloth/src/analysis/mod.rs
+++ b/sloth/src/analysis/mod.rs
@@ -23,7 +23,9 @@ impl AnalysisError {
}
pub fn analyze(root: &mut Stmt) -> Result<(), AnalysisError> {
- setup::populate_symtable(&root.as_node())?;
+ let mut populator = setup::Populator::default();
+ populator.populate_symtable(&root.as_node())?;
+
setup::propagate_types_stmt(root)?;
check_usage(&root.as_node())?;
diff --git a/sloth/src/analysis/setup.rs b/sloth/src/analysis/setup.rs
index e690131..ad0bf93 100644
--- a/sloth/src/analysis/setup.rs
+++ b/sloth/src/analysis/setup.rs
@@ -2,80 +2,107 @@ use super::AnalysisError;
use crate::parser::ast::{
AstNode, Expr, ExprKind, Function, FunctionInput, FunctionKind, Literal, Stmt, StmtKind,
};
-use crate::symtable::{Symbol, SymbolTable, Type};
-
-pub(super) fn populate_symtable(node: &AstNode) -> Result<(), AnalysisError> {
- if let AstNode::Stmt(stmt) = node {
- let mut table = stmt.symtable.clone();
-
- match &stmt.kind {
- StmtKind::DefineVariable {
- identifier, typ, ..
- } => {
- // When a variable is defined add it to the symbol table of the current scope.
- let symbol = build_value_symbol(&table, typ)?;
- table.insert(identifier.to_owned(), symbol);
- }
- StmtKind::DefineFunction(Function {
- identifier,
- inputs,
- output,
- kind,
- }) => {
- // When a function is defined add the function to the symbol
- // table of the current scope, and add the inputs to the child
- // (body) scope.
- let function_symbol = build_function_symbol(&table, inputs, output.as_deref())?;
- table.insert(identifier.to_owned(), function_symbol);
-
- if let FunctionKind::Normal { body } = kind {
- let mut body_table = body.symtable.clone();
-
- for input in inputs {
- let symbol = build_value_symbol(&body_table, &input.typ)?;
- body_table.insert(input.identifier.to_owned(), symbol);
+use crate::symtable::{Symbol, SymbolTable, Type, ValueSymbol};
+
+#[derive(Default)]
+pub struct Populator {
+ next_id: i32,
+}
+
+impl Populator {
+ fn reserve_id(&mut self) -> i32 {
+ let id = self.next_id;
+ self.next_id += 1;
+ id
+ }
+}
+
+impl Populator {
+ pub(super) fn populate_symtable(&mut self, node: &AstNode) -> Result<(), AnalysisError> {
+ if let AstNode::Stmt(stmt) = node {
+ let mut table = stmt.symtable.clone();
+
+ match &stmt.kind {
+ StmtKind::DefineVariable {
+ identifier, typ, ..
+ } => {
+ // When a variable is defined add it to the symbol table of the current scope.
+ let symbol = self.build_value_symbol(&table, typ)?;
+ table.insert(identifier.to_owned(), symbol);
+ }
+ StmtKind::DefineFunction(Function {
+ identifier,
+ inputs,
+ output,
+ kind,
+ }) => {
+ // When a function is defined add the function to the symbol
+ // table of the current scope, and add the inputs to the child
+ // (body) scope.
+ let function_symbol =
+ self.build_function_symbol(&table, inputs, output.as_deref())?;
+ table.insert(identifier.to_owned(), function_symbol);
+
+ if let FunctionKind::Normal { body } = kind {
+ let mut body_table = body.symtable.clone();
+
+ for input in inputs {
+ let symbol = self.build_value_symbol(&body_table, &input.typ)?;
+ body_table.insert(input.identifier.to_owned(), symbol);
+ }
}
}
+ _ => (),
}
- _ => (),
}
- }
- for child in node.children() {
- populate_symtable(&child)?;
- }
-
- Ok(())
-}
+ for child in node.children() {
+ self.populate_symtable(&child)?;
+ }
-fn build_value_symbol(table: &SymbolTable, typ: &str) -> Result<Symbol, AnalysisError> {
- let typ = table
- .get_type(typ)
- .ok_or(AnalysisError::UnknownIdentifier(0, typ.to_owned()))?;
+ Ok(())
+ }
- Ok(Symbol::Value(typ))
-}
+ fn build_value_symbol(
+ &mut self,
+ table: &SymbolTable,
+ typ: &str,
+ ) -> Result<Symbol, AnalysisError> {
+ let typ = table
+ .get_type(typ)
+ .ok_or(AnalysisError::UnknownIdentifier(0, typ.to_owned()))?;
+
+ Ok(Symbol::Value(ValueSymbol {
+ typ,
+ id: self.reserve_id(),
+ }))
+ }
-fn build_function_symbol(
- table: &SymbolTable,
- inputs: &[FunctionInput],
- output: Option<&str>,
-) -> Result<Symbol, AnalysisError> {
- let inputs = inputs
- .iter()
- .map(|it| table.get_type(&it.typ))
- .collect::<Option<Vec<_>>>()
- .ok_or(AnalysisError::UnknownIdentifier(0, "0xOwO".to_owned()))?;
-
- let output = output
- .map(|it| table.get_type(it))
- .unwrap_or(Some(Type::Void))
- .ok_or(AnalysisError::UnknownIdentifier(0, "0xUwU".to_owned()))?;
-
- Ok(Symbol::Value(Type::Function {
- inputs,
- output: output.into(),
- }))
+ fn build_function_symbol(
+ &mut self,
+ table: &SymbolTable,
+ inputs: &[FunctionInput],
+ output: Option<&str>,
+ ) -> Result<Symbol, AnalysisError> {
+ let inputs = inputs
+ .iter()
+ .map(|it| table.get_type(&it.typ))
+ .collect::<Option<Vec<_>>>()
+ .ok_or(AnalysisError::UnknownIdentifier(0, "0xOwO".to_owned()))?;
+
+ let output = output
+ .map(|it| table.get_type(it))
+ .unwrap_or(Some(Type::Void))
+ .ok_or(AnalysisError::UnknownIdentifier(0, "0xUwU".to_owned()))?;
+
+ Ok(Symbol::Value(ValueSymbol {
+ typ: Type::Function {
+ inputs,
+ output: output.into(),
+ },
+ id: self.reserve_id(),
+ }))
+ }
}
pub(super) fn propagate_types_stmt(node: &mut Stmt) -> Result<(), AnalysisError> {
@@ -123,63 +150,61 @@ pub(super) fn propagate_types_stmt(node: &mut Stmt) -> Result<(), AnalysisError>
}
pub(super) fn propagate_types(node: &mut Expr) -> Result<(), AnalysisError> {
- let typ = match &mut node.kind {
- ExprKind::Grouping(child) => {
- propagate_types(child)?;
- child
- .typ
- .clone()
- .ok_or(AnalysisError::Unknown(node.line, "owo choco"))?
- }
- ExprKind::Literal(lit) => match lit {
- Literal::Integer(_) => Type::Integer,
- Literal::Float(_) => Type::Float,
- Literal::Boolean(_) => Type::Boolean,
- _ => todo!(),
- },
- ExprKind::Identifier(identifier) => {
- let table = node.symtable.clone();
- table
- .get_value(identifier)
- .ok_or(AnalysisError::UnknownIdentifier(
- node.line,
- identifier.to_owned(),
- ))?
- }
- ExprKind::BinaryOp { lhs, rhs, .. } => {
- // Propagating the types to the children
- propagate_types(lhs)?;
- propagate_types(rhs)?;
-
- if lhs.typ != rhs.typ {
- return Err(AnalysisError::TypeMismatch(node.line));
+ let typ =
+ match &mut node.kind {
+ ExprKind::Grouping(child) => {
+ propagate_types(child)?;
+ child
+ .typ
+ .clone()
+ .ok_or(AnalysisError::Unknown(node.line, "owo choco"))?
}
+ ExprKind::Literal(lit) => match lit {
+ Literal::Integer(_) => Type::Integer,
+ Literal::Float(_) => Type::Float,
+ Literal::Boolean(_) => Type::Boolean,
+ _ => todo!(),
+ },
+ ExprKind::Identifier(identifier) => {
+ let table = node.symtable.clone();
+ table.get_value(identifier).map(|it| it.typ).ok_or(
+ AnalysisError::UnknownIdentifier(node.line, identifier.to_owned()),
+ )?
+ }
+ ExprKind::BinaryOp { lhs, rhs, .. } => {
+ // Propagating the types to the children
+ propagate_types(lhs)?;
+ propagate_types(rhs)?;
- lhs.typ
- .clone()
- .ok_or(AnalysisError::Unknown(node.line, "owo?? choco???"))?
- }
- ExprKind::UnaryOp { value, .. } => {
- propagate_types(value)?;
+ if lhs.typ != rhs.typ {
+ return Err(AnalysisError::TypeMismatch(node.line));
+ }
- value.typ.clone().ok_or(AnalysisError::Unknown(
- node.line,
- "YOU'RE WRONG... SULFURIC ACID!",
- ))?
- }
- ExprKind::Call { callee, args } => {
- propagate_types(callee)?;
- for arg in args {
- propagate_types(arg)?;
+ lhs.typ
+ .clone()
+ .ok_or(AnalysisError::Unknown(node.line, "owo?? choco???"))?
+ }
+ ExprKind::UnaryOp { value, .. } => {
+ propagate_types(value)?;
+
+ value.typ.clone().ok_or(AnalysisError::Unknown(
+ node.line,
+ "YOU'RE WRONG... SULFURIC ACID!",
+ ))?
}
+ ExprKind::Call { callee, args } => {
+ propagate_types(callee)?;
+ for arg in args {
+ propagate_types(arg)?;
+ }
- let Some(Type::Function { ref output, .. }) = callee.typ else {
+ let Some(Type::Function { ref output, .. }) = callee.typ else {
return Err(AnalysisError::TypeMismatch(node.line));
};
- *output.clone()
- }
- };
+ *output.clone()
+ }
+ };
node.typ = Some(typ);
@@ -195,8 +220,8 @@ mod tests {
#[test]
fn haiiiiiuwu() {
let mut table = SymbolTable::new();
- table.insert("poggo".to_owned(), Symbol::Value(Type::Integer));
- table.insert("poggu".to_owned(), Symbol::Value(Type::Float));
+ // table.insert("poggo".to_owned(), Symbol::Value(Type::Integer));
+ // table.insert("poggu".to_owned(), Symbol::Value(Type::Float));
let mut x = Expr::new(
0,
diff --git a/sloth/src/codegen/mod.rs b/sloth/src/codegen/mod.rs
index fb83c99..81832e9 100644
--- a/sloth/src/codegen/mod.rs
+++ b/sloth/src/codegen/mod.rs
@@ -1,11 +1,19 @@
+use std::collections::HashMap;
use std::io::Write;
+use std::path::Path;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::Module;
-use inkwell::types::{BasicMetadataTypeEnum, BasicType};
-use inkwell::values::{BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue};
-use itertools::Itertools;
+use inkwell::targets::{
+ CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine,
+};
+use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
+use inkwell::values::{
+ BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, PointerValue,
+};
+use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
+use itertools::{Either, Itertools};
use crate::parser::ast::{
BinaryOp, Expr, ExprKind, Function, FunctionKind, Literal, Stmt, StmtKind,
@@ -18,41 +26,141 @@ pub struct Compiler<'ctx> {
module: Module<'ctx>,
current_func: Option<FunctionValue<'ctx>>,
+ current_func_void: bool,
+
+ references: HashMap<i32, PointerValue<'ctx>>,
}
impl<'ctx> Compiler<'ctx> {
- pub fn codegen(context: &'ctx Context, module: &str, code: &Stmt) {
+ pub fn new(context: &'ctx Context, module: &str) -> Self {
let builder = context.create_builder();
let module = context.create_module(module);
- let mut this = Compiler {
+ Compiler {
context,
builder,
module,
current_func: None,
- };
+ current_func_void: false,
+
+ references: Default::default(),
+ }
+ }
+ pub fn codegen(&mut self, code: &Stmt) {
let StmtKind::Block(ref stmts) = &code.kind else {
panic!("Code root should be a block");
};
for stmt in stmts {
- this.codegen_stmt(stmt);
- this.current_func.unwrap().print_to_stderr();
+ self.codegen_stmt(stmt);
+ self.current_func.unwrap().print_to_stderr();
}
}
+ fn codegen_alloca(&mut self, typ: BasicTypeEnum<'ctx>, name: &str) -> PointerValue<'ctx> {
+ let builder = self.context.create_builder();
+
+ let entry = self.current_func.unwrap().get_first_basic_block().unwrap();
+
+ match entry.get_first_instruction() {
+ Some(first) => builder.position_before(&first),
+ None => builder.position_at_end(entry),
+ }
+
+ builder.build_alloca(typ, &format!("alloca {name}"))
+ }
+
fn codegen_stmt(&mut self, code: &Stmt) {
match &code.kind {
StmtKind::Block(stmts) => self.codegen_block(stmts),
StmtKind::ExprStmt(expr) => {
self.codegen_expr(expr);
}
+ StmtKind::IfStmt {
+ condition,
+ if_then,
+ else_then,
+ } => {
+ // Get the current function
+ let func = self.current_func.unwrap();
+
+ // Get the condition
+ let condition = self.codegen_expr(condition).unwrap().into_int_value();
+
+ // Add the branching logic
+ let then_bb = self.context.append_basic_block(func, "then");
+ let else_bb = self.context.append_basic_block(func, "else");
+ let continue_bb = self.context.append_basic_block(func, "continue");
+
+ self.builder
+ .build_conditional_branch(condition, then_bb, else_bb);
+
+ // Building the blocks for then
+ self.builder.position_at_end(then_bb);
+ self.codegen_stmt(if_then);
+ self.builder.build_unconditional_branch(continue_bb);
+
+ // Building the blocks for else
+ self.builder.position_at_end(else_bb);
+ if let Some(else_then) = else_then {
+ self.codegen_stmt(else_then);
+ }
+ self.builder.build_unconditional_branch(continue_bb);
+
+ // Position the builder at the end of the continue block
+ self.builder.position_at_end(continue_bb);
+ }
+ StmtKind::WhileStmt { condition, body } => {
+ // Get the current function
+ let func = self.current_func.unwrap();
+
+ let loop_bb = self.context.append_basic_block(func, "loop");
+ let body_bb = self.context.append_basic_block(func, "loop body");
+ let after_bb = self.context.append_basic_block(func, "after loop");
+
+ self.builder.build_unconditional_branch(loop_bb);
+
+ // Building the blocks for the head of the loop
+ self.builder.position_at_end(loop_bb);
+ let condition = self.codegen_expr(condition).unwrap().into_int_value();
+ self.builder
+ .build_conditional_branch(condition, body_bb, after_bb);
+
+ // Building the blocks for the body of the loop
+ self.builder.position_at_end(body_bb);
+ self.codegen_stmt(body);
+ self.builder.build_unconditional_branch(loop_bb);
+
+ // Position the builder at the end of the loop
+ self.builder.position_at_end(after_bb);
+ }
StmtKind::Return(expr) => {
- let res = self.codegen_expr(expr);
+ let res = self.codegen_expr(expr).unwrap();
self.builder.build_return(Some(&res));
}
+ StmtKind::DefineVariable {
+ identifier, value, ..
+ } => {
+ let table = code.symtable.clone();
+ let symbol = table.get_value(identifier).unwrap();
+
+ let ptr = self.codegen_alloca(self.type_as_basic_type(symbol.typ), identifier);
+ let init_value = self.codegen_expr(value).unwrap();
+
+ self.builder.build_store(ptr, init_value);
+ self.references.insert(symbol.id, ptr);
+ }
+ StmtKind::AssignVariable { identifier, value } => {
+ let table = code.symtable.clone();
+ let symbol = table.get_value(identifier).unwrap();
+
+ let ptr = self.references.get(&symbol.id).unwrap();
+ let init_value = self.codegen_expr(value).unwrap();
+
+ self.builder.build_store(*ptr, init_value);
+ }
StmtKind::DefineFunction(function) => {
let table = code.symtable.clone();
self.codegen_function(table, function.clone());
@@ -61,7 +169,17 @@ impl<'ctx> Compiler<'ctx> {
// the block contents
if let FunctionKind::Normal { body } = &function.kind {
if let StmtKind::Block(body) = &body.kind {
+ // Make the block containing the code for the function
+ let func = self.current_func.unwrap();
+ let block = self.context.append_basic_block(func, "entrypoint");
+
+ // Position the builder to be at the block
+ self.builder.position_at_end(block);
self.codegen_block(body);
+
+ if self.current_func_void {
+ self.builder.build_return(None);
+ }
}
};
}
@@ -70,6 +188,9 @@ impl<'ctx> Compiler<'ctx> {
}
fn codegen_function(&mut self, table: SymbolTable, function: Function) -> FunctionValue {
+ // Clear references to variables
+ self.references.clear();
+
let inputs = function.inputs;
let inputs_typ = inputs
.iter()
@@ -96,59 +217,76 @@ impl<'ctx> Compiler<'ctx> {
.add_function(&function.identifier, llvm_function_type, None);
self.current_func = Some(llvm_function);
+ self.current_func_void = matches!(output_typ, Type::Void);
llvm_function
}
fn codegen_block(&mut self, code: &[Stmt]) {
- let Some(current_func) = self.current_func else {
- panic!("Block codegen requires function");
- };
-
- let block = self.context.append_basic_block(current_func, "block");
-
- self.builder.position_at_end(block);
-
for stmt in code {
self.codegen_stmt(stmt);
}
}
- fn codegen_expr(&self, code: &Expr) -> BasicValueEnum<'ctx> {
- // AnyValue
- match &code.kind {
+ fn codegen_expr(&self, code: &Expr) -> Option<BasicValueEnum<'ctx>> {
+ Some(match &code.kind {
ExprKind::Literal(literal) => self.codegen_value(literal.clone()),
- ExprKind::Grouping(inner) => self.codegen_expr(inner),
+ ExprKind::Grouping(inner) => self.codegen_expr(inner)?,
ExprKind::Identifier(ident) => {
- // FIXME: Do thsi
- todo!()
+ let table = code.symtable.clone();
+ let symbol = table.get_value(ident).unwrap();
+ let ptr = self.references.get(&symbol.id).unwrap();
+
+ self.builder
+ .build_load(self.type_as_basic_type(symbol.typ.clone()), *ptr, "deref")
}
ExprKind::BinaryOp { op, lhs, rhs } => match lhs.typ {
- Some(Type::Integer) => {
- let lhs_gen = self.codegen_expr(lhs).into_int_value();
- let rhs_gen = self.codegen_expr(rhs).into_int_value();
+ Some(Type::Integer) | Some(Type::Boolean) => {
+ use IntPredicate::*;
+
+ let l = self.codegen_expr(lhs).unwrap().into_int_value();
+ let r = self.codegen_expr(rhs).unwrap().into_int_value();
match op {
- BinaryOp::Add => self.builder.build_int_add(lhs_gen, rhs_gen, "add"),
- BinaryOp::Sub => self.builder.build_int_sub(lhs_gen, rhs_gen, "sub"),
- BinaryOp::Mul => self.builder.build_int_mul(lhs_gen, rhs_gen, "mul"),
- BinaryOp::Div => self.builder.build_int_signed_div(lhs_gen, rhs_gen, "div"),
+ BinaryOp::Add => self.builder.build_int_add(l, r, "add"),
+ BinaryOp::Sub => self.builder.build_int_sub(l, r, "sub"),
+ BinaryOp::Mul => self.builder.build_int_mul(l, r, "mul"),
+ BinaryOp::Div => self.builder.build_int_signed_div(l, r, "div"),
+ BinaryOp::Mod => self.builder.build_int_signed_rem(l, r, "mod"),
+
+ BinaryOp::Gt => self.builder.build_int_compare(SGT, l, r, "gt"),
+ BinaryOp::GtEq => self.builder.build_int_compare(SGE, l, r, ""),
+ BinaryOp::Lt => self.builder.build_int_compare(SLT, l, r, "lt"),
+ BinaryOp::LtEq => self.builder.build_int_compare(SLE, l, r, ""),
+
+ BinaryOp::EqEq => self.builder.build_int_compare(EQ, l, r, ""),
+ BinaryOp::NotEq => self.builder.build_int_compare(NE, l, r, ""),
_ => panic!(),
}
.into()
}
Some(Type::Float) => {
- let lhs_gen = self.codegen_expr(lhs).into_float_value();
- let rhs_gen = self.codegen_expr(rhs).into_float_value();
+ use FloatPredicate::*;
+
+ let l = self.codegen_expr(lhs).unwrap().into_float_value();
+ let r = self.codegen_expr(rhs).unwrap().into_float_value();
match op {
- BinaryOp::Add => self.builder.build_float_add(lhs_gen, rhs_gen, "add"),
- BinaryOp::Sub => self.builder.build_float_sub(lhs_gen, rhs_gen, "sub"),
- BinaryOp::Mul => self.builder.build_float_mul(lhs_gen, rhs_gen, "mul"),
- BinaryOp::Div => self.builder.build_float_div(lhs_gen, rhs_gen, "div"),
+ BinaryOp::Add => self.builder.build_float_add(l, r, "add").into(),
+ BinaryOp::Sub => self.builder.build_float_sub(l, r, "sub").into(),
+ BinaryOp::Mul => self.builder.build_float_mul(l, r, "mul").into(),
+ BinaryOp::Div => self.builder.build_float_div(l, r, "div").into(),
+ BinaryOp::Mod => self.builder.build_float_rem(l, r, "mod").into(),
+
+ BinaryOp::Gt => self.builder.build_float_compare(OGT, l, r, "gt").into(),
+ BinaryOp::GtEq => self.builder.build_float_compare(OGE, l, r, "gt").into(),
+ BinaryOp::Lt => self.builder.build_float_compare(OLT, l, r, "lt").into(),
+ BinaryOp::LtEq => self.builder.build_float_compare(OLE, l, r, "le").into(),
+
+ BinaryOp::EqEq => self.builder.build_float_compare(OEQ, l, r, "eq").into(),
+ BinaryOp::NotEq => self.builder.build_float_compare(ONE, l, r, "ne").into(),
_ => panic!(),
}
- .into()
}
None => unreachable!("Critical Error: Type should never be null by this point"),
_ => todo!(),
@@ -164,15 +302,20 @@ impl<'ctx> Compiler<'ctx> {
let args = args
.iter()
.map(|arg| self.codegen_expr(arg))
- .map(|arg| arg.into())
+ .map(|arg| arg.unwrap().into())
.collect::<Vec<BasicMetadataValueEnum>>();
- self.builder
+ let call = self
+ .builder
.build_call(function, &args, "")
- .try_as_basic_value()
- .unwrap_left()
+ .try_as_basic_value();
+
+ match call {
+ Either::Left(left) => left,
+ Either::Right(_) => return None,
+ }
}
- }
+ })
}
fn codegen_value(&self, value: Literal) -> BasicValueEnum<'ctx> {
@@ -187,18 +330,53 @@ impl<'ctx> Compiler<'ctx> {
.f64_type()
.const_float(value)
.as_basic_value_enum(),
+ Literal::Boolean(value) => self
+ .context
+ .bool_type()
+ .const_int(if value { 1 } else { 0 }, false)
+ .as_basic_value_enum(),
_ => unimplemented!(),
}
}
- fn type_as_metadata_type(&self, typ: Type) -> BasicMetadataTypeEnum<'ctx> {
+ fn type_as_basic_type(&self, typ: Type) -> BasicTypeEnum<'ctx> {
match typ {
Type::Integer => self.context.i64_type().into(),
Type::Float => self.context.f64_type().into(),
Type::Boolean => self.context.bool_type().into(),
- _ => todo!(), // Type::Function { inputs, output } => todo!(),
+ _ => todo!(),
}
}
- fn write_obj(&self, file: &mut impl Write) {}
+ fn type_as_metadata_type(&self, typ: Type) -> BasicMetadataTypeEnum<'ctx> {
+ self.type_as_basic_type(typ).into()
+ }
+
+ pub fn write_obj(&self, file: &mut impl Write, filetype: FileType) {
+ 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);
+
+ let buffer = machine
+ .write_to_memory_buffer(&self.module, filetype)
+ .unwrap();
+ // machine
+ // .write_to_file(&self.module, filetype, Path::new("export.o"))
+ // .unwrap();
+
+ file.write_all(buffer.as_slice()).unwrap();
+ }
}
diff --git a/sloth/src/main.rs b/sloth/src/main.rs
index bdcb4cb..c51b147 100644
--- a/sloth/src/main.rs
+++ b/sloth/src/main.rs
@@ -14,10 +14,12 @@ pub mod parser;
pub mod sloth_std;
pub mod symtable;
+use std::fs::File;
use std::{env, fs};
use codegen::Compiler;
use inkwell::context::Context;
+use inkwell::targets::FileType;
use itertools::Itertools;
use lexer::Lexer;
use parser::AstParser;
@@ -62,7 +64,13 @@ fn main() {
// println!("Suces");
let context = Context::create();
- Compiler::codegen(&context, "hi", &ast);
+ let mut compiler = Compiler::new(&context, "s");
+ let mut output_file = File::create("output.o").unwrap();
+
+ compiler.codegen(&ast);
+ compiler.write_obj(&mut output_file, FileType::Object);
+
+ // Compiler::codegen(&context, "hi", &ast);
// let graph = GraphBuilder::generate(Some(&source), &ast).unwrap();
// println!("{graph}");
diff --git a/sloth/src/symtable.rs b/sloth/src/symtable.rs
index b2bb209..8bfd16e 100644
--- a/sloth/src/symtable.rs
+++ b/sloth/src/symtable.rs
@@ -3,6 +3,8 @@ use std::collections::hash_map::Entry::Vacant;
use std::collections::HashMap;
use std::rc::Rc;
+use inkwell::values::PointerValue;
+
#[derive(Debug, Default)]
struct Scope {
parent: Option<Rc<Scope>>,
@@ -61,10 +63,10 @@ impl SymbolTable {
None
}
- pub fn get_value(&self, identifier: &str) -> Option<Type> {
+ pub fn get_value(&self, identifier: &str) -> Option<ValueSymbol> {
let symbol = self.get(identifier)?;
- if let Symbol::Value(ref typ) = *symbol {
- return Some(typ.clone());
+ if let Symbol::Value(ref symbol) = *symbol {
+ return Some(symbol.clone());
}
None
@@ -130,7 +132,13 @@ pub enum Symbol {
/// Symbol referencing a compile time type, such as the Int symbol
Type(Type),
/// Symbol referencing a runtime value, such as the println symbol
- Value(Type),
+ Value(ValueSymbol),
+}
+
+#[derive(Clone, Debug)]
+pub struct ValueSymbol {
+ pub typ: Type,
+ pub id: i32,
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
diff --git a/test.c b/test.c
index 3a39c44..26925e0 100644
--- a/test.c
+++ b/test.c
@@ -1,11 +1,13 @@
#include <stdio.h>
-int add(int, int);
-int subtract(int, int);
+long long hehehaha();
+
+long long addz(long long lhs, long long rhs) {
+ return lhs + rhs + 1;
+}
int main() {
- int a = add(5, 2);
- int b = subtract(3, 8);
- printf("%d %d\n", a, b);
+ long long res = hehehaha();
+ printf("%d\n", res);
return 0;
}
diff --git a/test.sloth b/test.sloth
deleted file mode 100644
index 8ad1754..0000000
--- a/test.sloth
+++ /dev/null
@@ -1,7 +0,0 @@
-fn add(x, y) {
- return x + y;
-}
-
-fn subtract(x, y) {
- return x - y;
-}