Skip to content

Commit

Permalink
Working dynamically sized arrays (syntax not right)
Browse files Browse the repository at this point in the history
  • Loading branch information
cody-quinn committed Jun 26, 2023
1 parent 0302126 commit 849ba9f
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 43 deletions.
15 changes: 7 additions & 8 deletions examples/hello.sloth
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
foreign fn addz(lhs: Int, rhs: Int) Int;
fn test() [Int 3] {
var list: [Int 3] = [9, 5, 7];

fn haiiii() Void {}
vpushi(list, 3);
vpushi(list, 3);
vpushi(list, 3);
vpushi(list, 5);

fn hehehaha() Int {
var x: Int = 0;
while x < 10 {
x = x + 1;
}
return x;
return list;
}

23 changes: 19 additions & 4 deletions sloth/src/analysis/setup.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::AnalysisError;
use crate::parser::ast::{
AstNode, Expr, ExprKind, Function, FunctionInput, FunctionKind, Literal, Stmt, StmtKind,
TypeIdentifier,
};
use crate::symtable::{Symbol, SymbolTable, Type, ValueSymbol};

Expand Down Expand Up @@ -40,7 +41,7 @@ impl Populator {
// table of the current scope, and add the inputs to the child
// (body) scope.
let function_symbol =
self.build_function_symbol(node.line(), &table, inputs, output.as_deref())?;
self.build_function_symbol(node.line(), &table, inputs, output.as_ref())?;
table.insert(identifier.to_owned(), function_symbol);

if let FunctionKind::Normal { body } = kind {
Expand Down Expand Up @@ -68,11 +69,11 @@ impl Populator {
&mut self,
line: u32,
table: &SymbolTable,
typ: &str,
typ: &TypeIdentifier,
) -> Result<Symbol, AnalysisError> {
let typ = table
.get_type(typ)
.ok_or(AnalysisError::UnknownIdentifier(line, typ.to_owned()))?;
.ok_or(AnalysisError::UnknownIdentifier(line, typ.to_string()))?;

Ok(Symbol::Value(ValueSymbol {
typ,
Expand All @@ -85,7 +86,7 @@ impl Populator {
line: u32,
table: &SymbolTable,
inputs: &[FunctionInput],
output: Option<&str>,
output: Option<&TypeIdentifier>,
) -> Result<Symbol, AnalysisError> {
let inputs = inputs
.iter()
Expand Down Expand Up @@ -166,6 +167,20 @@ pub(super) fn propagate_types(node: &mut Expr) -> Result<(), AnalysisError> {
Literal::Integer(_) => Type::Integer,
Literal::Float(_) => Type::Float,
Literal::Boolean(_) => Type::Boolean,
Literal::Array(members) => {
let mut last = None;
for member in members {
propagate_types(member)?;
if let Some(ref last) = last {
if member.typ.as_ref().unwrap() != last {
return Err(AnalysisError::TypeMismatch(node.line));
}
}
last = Some(member.typ.clone().unwrap());
}

last.expect("need 1 element in literal im sozzy")
}
_ => todo!(),
},
ExprKind::Identifier(identifier) => {
Expand Down
195 changes: 190 additions & 5 deletions sloth/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use inkwell::module::Module;
use inkwell::targets::{
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine,
};
use inkwell::types::{BasicMetadataTypeEnum, BasicTypeEnum};
use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum, PointerType};
use inkwell::values::{
BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, PointerValue,
};
use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
use inkwell::{AddressSpace, FloatPredicate, IntPredicate, OptimizationLevel};
use itertools::{Either, Itertools};

use crate::parser::ast::{
Expand All @@ -35,7 +35,7 @@ impl<'ctx> Codegen<'ctx> {
let builder = context.create_builder();
let module = context.create_module(module);

Codegen {
let mut this = Codegen {
context,
builder,
module,
Expand All @@ -44,7 +44,13 @@ impl<'ctx> Codegen<'ctx> {
current_func_void: false,

references: Default::default(),
}
};

this.INTRINSIC_vpush("i", Type::Integer);
this.INTRINSIC_vpush("f", Type::Float);
this.INTRINSIC_vpush("b", Type::Boolean);

this
}

pub fn codegen(&mut self, code: &Stmt) {
Expand All @@ -68,7 +74,7 @@ impl<'ctx> Codegen<'ctx> {
None => builder.position_at_end(entry),
}

builder.build_alloca(typ, &format!("alloca {name}"))
builder.build_alloca(typ, name)
}

fn codegen_stmt(&mut self, code: &Stmt) {
Expand Down Expand Up @@ -207,6 +213,25 @@ impl<'ctx> Codegen<'ctx> {
Type::Integer => self.context.i64_type().fn_type(&inputs_typ, false),
Type::Float => self.context.f64_type().fn_type(&inputs_typ, false),
Type::Boolean => self.context.bool_type().fn_type(&inputs_typ, false),
Type::Array { ref typ, .. } => {
let i32_type = self.context.i32_type().as_basic_type_enum();

let typ = self
.type_as_basic_type(*typ.clone())
.ptr_type(AddressSpace::default())
.as_basic_type_enum();

let vector_type = self.context.struct_type(&[i32_type, i32_type, typ], false);

let ptr_to_that = vector_type.ptr_type(AddressSpace::default());

ptr_to_that.fn_type(&inputs_typ, false)

// killll me
// self.type_as_basic_type(*typ.clone())
// .ptr_type(AddressSpace::default())
// .fn_type(&inputs_typ, false)
}
_ => todo!(),
};

Expand Down Expand Up @@ -333,15 +358,89 @@ impl<'ctx> Codegen<'ctx> {
.bool_type()
.const_int(if value { 1 } else { 0 }, false)
.as_basic_value_enum(),
Literal::Array(values) => {
// FIXME: Allocating a new dynamic array for constants is really inefficient
let element_type = self.type_as_basic_type(values[0].typ.clone().unwrap());
let i32_type = self.context.i32_type();

let inner_ptr = self
.builder
.build_array_malloc(element_type, i32_type.const_int(100, false), "vecinnerptr")
.unwrap();

for (idx, value) in values.iter().enumerate() {
let value = self.codegen_expr(value).unwrap();
let value_ptr = unsafe {
self.builder.build_gep(
i32_type,
inner_ptr,
&[i32_type.const_int(idx as u64, false)],
"",
)
};

self.builder.build_store(value_ptr, value);
}

let vector_type = self.context.struct_type(
&[
i32_type.as_basic_type_enum(),
i32_type.as_basic_type_enum(),
inner_ptr.get_type().as_basic_type_enum(),
],
false,
);

let vector_ptr = self.builder.build_malloc(vector_type, "vecptr").unwrap();

// Set the size and capacity values
let size = self
.builder
.build_struct_gep(vector_type, vector_ptr, 0, "gepvec")
.unwrap();
self.builder
.build_store(size, i32_type.const_int(values.len() as u64, false));

let cap = self
.builder
.build_struct_gep(vector_type, vector_ptr, 1, "gepvec")
.unwrap();
self.builder
.build_store(cap, i32_type.const_int(100, false));

let inner = self
.builder
.build_struct_gep(vector_type, vector_ptr, 2, "gepvec")
.unwrap();
self.builder.build_store(inner, inner_ptr);

vector_ptr.as_basic_value_enum()
}
_ => unimplemented!(),
}
}

fn type_as_basic_type(&self, typ: Type) -> BasicTypeEnum<'ctx> {
// self.context.i64_type().ptr_type(Address)
match typ {
Type::Integer => self.context.i64_type().into(),
Type::Float => self.context.f64_type().into(),
Type::Boolean => self.context.bool_type().into(),
Type::Array { typ, .. } => {
let i32_type = self.context.i32_type().as_basic_type_enum();

let typ = self
.type_as_basic_type(*typ)
.ptr_type(AddressSpace::default())
.as_basic_type_enum();

let vector_type = self.context.struct_type(&[i32_type, i32_type, typ], false);

let ptr_to_that = vector_type.ptr_type(AddressSpace::default());

ptr_to_that.as_basic_type_enum()
}
// Type::Array { typ, len } => self.type_as_basic_type(*typ).array_type(len).into(),
_ => todo!(),
}
}
Expand Down Expand Up @@ -375,3 +474,89 @@ impl<'ctx> Codegen<'ctx> {
file.write_all(buffer.as_slice()).unwrap();
}
}

#[allow(non_snake_case)]
impl<'ctx> Codegen<'ctx> {
fn INTRINSIC_vpush(&mut self, name: &str, typ: Type) {
// Preparing for function
self.references.clear();

let bruh = self.type_as_basic_type(Type::Array {
typ: Box::new(typ.clone()),
len: 0,
});

let inputs = &[bruh.into(), self.type_as_metadata_type(typ.clone())];

// Making the function
let func_type = self.context.void_type().fn_type(inputs, false);
let func = self
.module
.add_function(&format!("vpush{name}"), func_type, None);

self.current_func = Some(func);
self.current_func_void = true;

let block = self.context.append_basic_block(func, "entrypoint");
self.builder.position_at_end(block);

// Writing the logic
let element_type = self.type_as_basic_type(typ);
let i32_type = self.context.i32_type();

let vector_type = self.context.struct_type(
&[
i32_type.as_basic_type_enum(),
i32_type.as_basic_type_enum(),
element_type
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
],
false,
);

let vector_ptr = func.get_nth_param(0).unwrap().into_pointer_value();

let size_ptr = self
.builder
.build_struct_gep(vector_type, vector_ptr, 0, "sizegep")
.unwrap();
let cap_ptr = self
.builder
.build_struct_gep(vector_type, vector_ptr, 1, "capgep")
.unwrap();
let inner_ptr = self
.builder
.build_struct_gep(vector_type, vector_ptr, 2, "innergep")
.unwrap();

let size = self
.builder
.build_load(i32_type, size_ptr, "size")
.into_int_value();
let _cap = self
.builder
.build_load(i32_type, cap_ptr, "cap")
.into_int_value();

// Put the new element into backing array
let slot_ptr = unsafe {
self.builder
.build_gep(element_type, inner_ptr, &[size], "slot")
};

let element = func.get_nth_param(1).unwrap();
self.builder.build_store(slot_ptr, element);

// TODO: Handle going over capacity

// Increase size tracker
let new_size = self
.builder
.build_int_add(size, i32_type.const_int(1, false), "");
self.builder.build_store(size_ptr, new_size);

// Function return
self.builder.build_return(None);
}
}
14 changes: 13 additions & 1 deletion sloth/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use inkwell::targets::FileType;
use itertools::Itertools;
use lexer::Lexer;
use parser::AstParser;
use symtable::{Symbol, SymbolTable};
use symtable::{Symbol, SymbolTable, ValueSymbol};

use crate::analysis::analyze;
use crate::symtable::Type;
Expand All @@ -49,6 +49,18 @@ fn main() {
global_symtable.insert("Float".into(), Symbol::Type(Type::Float));
global_symtable.insert("Bool".into(), Symbol::Type(Type::Boolean));

let dummy = Symbol::Value(ValueSymbol {
typ: Type::Function {
inputs: vec![],
output: Box::new(Type::Void),
},
id: 0,
});

global_symtable.insert("vpushi".into(), dummy.clone());
global_symtable.insert("vpushf".into(), dummy.clone());
global_symtable.insert("vpushb".into(), dummy);

// Parsing
let tokens = Lexer::new(&source).collect_vec();
let mut ast = AstParser::parse(tokens, global_symtable).unwrap();
Expand Down
Loading

0 comments on commit 849ba9f

Please sign in to comment.