Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3c428d8
Merge pull request #10 from Quickfall/master
Zffu Feb 11, 2026
397ea07
feat: added IR value class
Zffu Feb 11, 2026
6dd2788
feat: added positionless errors
Zffu Feb 11, 2026
3911018
feat: migrated IRValue to PositionlessResult rather than Option
Zffu Feb 11, 2026
a0c0585
feat: added expects
Zffu Feb 12, 2026
369acf1
feat: started working on the inkwell side of things, sucessfully made…
Zffu Feb 12, 2026
8a7c2d8
feat: added function return type parsing
Zffu Feb 14, 2026
a35de81
feat: added math IR utils
Zffu Feb 14, 2026
155e35b
feat: added ptr utils to ir
Zffu Feb 14, 2026
24bcf00
feat: added util creation of IRPointer::create
Zffu Feb 14, 2026
d33c679
feat: added ptr test
Zffu Feb 14, 2026
8485b7c
feat: added ir function utils
Zffu Feb 14, 2026
c91fddc
feat: added return statement
Zffu Feb 15, 2026
955ab4b
chore: removed accidental bins
Zffu Feb 15, 2026
c94e892
feat: started working on static var handling
Zffu Feb 15, 2026
dacd69b
feat: added compiletime replacement for integer based types on global…
Zffu Feb 15, 2026
56472c2
feat: started working on IRValueRefs for a universal value handlingé
Zffu Feb 15, 2026
0f24a5a
feat: added new safe IRValue version
Zffu Feb 15, 2026
b5e32e8
feat: replaced every usage of the IRValue with IRNewValue
Zffu Feb 15, 2026
d8ac16d
Ãchore: removed ir::values::IRValue
Zffu Feb 15, 2026
dd01e59
chore: renamed ir::values::IRNewValue -> ir::values::IRValue
Zffu Feb 15, 2026
6b14e8d
feat: made IRPointer::load_int standart into IRPointer::load
Zffu Feb 16, 2026
ddcedb1
feat: finished IRPointer
Zffu Feb 16, 2026
a3b113a
feat: added support for IRValueRef instead of IRValue on IRPointer::c…
Zffu Feb 16, 2026
4c1093e
chore: cleaned ast value refs a little
Zffu Feb 16, 2026
3de494d
feat: added parser dependency on ir
Zffu Feb 17, 2026
344fe86
chore: made functions return types compatible with non IntType<'a> types
Zffu Feb 17, 2026
ddaa343
feat: added sample struct type
Zffu Feb 17, 2026
e94a5e8
feat: added IRType::iks_same to avoid using PartialEq
Zffu Feb 17, 2026
fb36f57
feat: fully migrated IRType::Struct & IRType::Layout to use the bette…
Zffu Feb 17, 2026
c3e7dcf
fix: fixed IRPointer to use the new is_same
Zffu Feb 17, 2026
da270c9
feat: made IRPointer::create work with any IRType rather than just in…
Zffu Feb 17, 2026
00c84c6
feat: added struct & layout support for get_inkwell_base_metadatatype…
Zffu Feb 17, 2026
e4385e7
fix: fixed gett_pointer_for_field doing a wrong and useless index check
Zffu Feb 17, 2026
8235bc1
feat: added function to get the IRType's used type for loads
Zffu Feb 17, 2026
15a3fc1
feat: started working on passing IRContext on every function that nee…
Zffu Feb 17, 2026
4023b42
feat: changed every raw reference to LLVM context to use IRContext
Zffu Feb 17, 2026
abe5265
fix: removed a useless pointer load when trying to use get_pointer_fo…
Zffu Feb 17, 2026
16f31a8
feat: added get_variable_ref
Zffu Feb 17, 2026
cacce29
feat: made obtain_pointer work with values
Zffu Feb 17, 2026
a0840b1
feat: made obtainÃ_pointer work with statics
Zffu Feb 17, 2026
bc5ba6f
feat: made obtain_pointer work with statics
Zffu Feb 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
target/
target/
*.ll

out
out.*
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions commons/src/err/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use colored::Colorize;
use crate::Position;

pub type PositionedResult<K> = Result<K, PositionedError>;
pub type PositionlessResult<K> = Result<K, PositionlessError>;

/// An error that has a position
#[derive(Debug)]
Expand All @@ -18,6 +19,21 @@ pub struct PositionedError {
pub reason: String
}

#[derive(Debug)]
pub struct PositionlessError {
pub reason: String
}

impl PositionlessError {
pub fn new(reason: &str) -> Self {
let err = PositionlessError { reason: String::from(reason) };

println!("{}", err);

return err;
}
}

impl PositionedError {
pub fn new(start: Position, end: Position, reason: String) -> Self {

Expand Down Expand Up @@ -48,6 +64,16 @@ impl fmt::Display for PositionedError {
writeln!(f, "")?;
writeln!(f, "{}", self.reason.bright_red())?;

Ok(())
}
}

impl fmt::Display for PositionlessError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{} at ??:??", "ERR".bright_red().bold())?;

writeln!(f, "{}", self.reason.bright_red())?;

Ok(())
}
}
15 changes: 15 additions & 0 deletions commons/src/utils/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,21 @@ impl<V> HashedMap<V> {
return None;
}

pub fn entries(&self) -> Vec<&(u64, V)> {
let mut vec = Vec::new();

for i in 0..self.capacity {
if self.meta[i] == BUCKET_EMPTY || self.meta[i] == BUCKET_TOMBSTONE {
continue;
}

unsafe { vec.push(self.buckets[i].assume_init_ref()); }
}

return vec;
}


pub fn erase(&mut self, key: u64) {
let index = self.index_from_hash(key);
let fingerprint = self.fingerprint_from_hash(key);
Expand Down
3 changes: 2 additions & 1 deletion commons/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod map;
pub mod map;
pub mod num;
19 changes: 19 additions & 0 deletions commons/src/utils/num.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pub fn get_signed_highbound(bits: usize) -> i128 {
return 2_i128.pow(bits as u32 - 1) - 1;
}

pub fn get_signed_lowbound(bits: usize) -> i128 {
return 0 - 2_i128.pow(bits as u32 - 1) - 1;
}

pub fn get_unsigned_highbound(bits: usize) -> i128 {
return 2_i128.pow(bits as u32) - 1;
}

pub fn can_num_fit_inbits_signed(bits: usize, num: i128) -> bool {
return num >= get_signed_lowbound(bits) && num <= get_signed_highbound(bits);
}

pub fn can_num_fit_inbits_unsigned(bits: usize, num: i128) -> bool {
return num >= 0 && num <= get_unsigned_highbound(bits);
}
4 changes: 3 additions & 1 deletion ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ edition = "2024"

[dependencies]
inkwell = { version = "0.8.0", features = ["llvm21-1"]}
commons = { path = "../commons" }
commons = { path = "../commons" }
lexer = { path = "../lexer" }
parser = { path = "../parser" }
3 changes: 3 additions & 0 deletions ir/src/conv/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Critical AST -> IR conversion code module

pub mod val;
22 changes: 22 additions & 0 deletions ir/src/conv/val.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! AST value -> IR value conversion

use commons::err::{PositionedError, PositionedResult, PositionlessError, PositionlessResult};
use parser::ast::tree::ASTTreeNode;

use crate::{ctx::{IRContext, IRLocalContext}, irstruct::{ptr::IRPointer, staticvars::IRStaticVariable}, refs::IRValueRef};

pub fn get_variable_ref<'a>(lctx: &'a IRLocalContext<'a>, ctx: &'a IRContext<'a>, hash: u64) -> PositionlessResult<IRValueRef<'a>> {
match ctx.get_variable(hash) {
Ok(v) => return Ok(IRValueRef::from_static(IRStaticVariable::clone(v))),
Err(_) => {}
};

match lctx.get_variable(hash) {
Ok(v) => return Ok(IRValueRef::from_pointer(IRPointer::clone(v))),
Err(_) => return Err(PositionlessError::new(&format!("Cannot find variable with hash {} in the current context", hash)))
};
}

pub fn parse_ir_chain_access<'a>(node: Box<ASTTreeNode>, lctx: &'a IRLocalContext<'a>, ctx: &'a IRContext<'a>) -> PositionlessResult<bool> {

}
111 changes: 111 additions & 0 deletions ir/src/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//! IR context related code

use core::hash;
use std::ops::Add;

use commons::{err::{PositionlessError, PositionlessResult}, utils::map::HashedMap};
use inkwell::{AddressSpace, builder::Builder, context::Context, types::PointerType};

use crate::irstruct::{funcs::IRFunction, ptr::IRPointer, staticvars::IRStaticVariable};

/// The global IR context.
/// Basically holds anything related to the current IR compilation (eg: functions, types, global vars)
pub struct IRContext<'a> {
pub inkwell_ctx: &'a Context,
pub builder: Builder<'a>,
pub ptr_type: PointerType<'a>,

pub functions: HashedMap<IRFunction<'a>>,
pub static_vars: HashedMap<IRStaticVariable<'a>>
}

impl<'a> IRContext<'a> {
pub fn new(builder: Builder<'a>, ctx: &'a Context) -> Self {
return IRContext { inkwell_ctx: ctx, builder, ptr_type: ctx.ptr_type(AddressSpace::from(0)), functions: HashedMap::new(0), static_vars: HashedMap::new(0) }
}

pub fn add_variable(&'a mut self, hash: u64, var: IRStaticVariable<'a>) -> PositionlessResult<bool> {
if self.static_vars.get(hash).is_some() {
return Err(PositionlessError::new(&format!("Variable named {} is already registered in the current context.", hash)));
}

self.static_vars.put(hash, var);
return Ok(true);
}

pub fn get_variable(&'a self, hash: u64) -> PositionlessResult<&'a IRStaticVariable<'a>> {
return match self.static_vars.get(hash) {
Some(v) => Ok(v),
None => return Err(PositionlessError::new("Invalid variable name"))
};
}
}

pub struct LocalIRVariable<'a> {
pub ptr: IRPointer<'a>,
pub depth: usize // Depth is depth in body.
}

/// The local IR context.
/// Holds anything held and created in the given body (eg: vars).
pub struct IRLocalContext<'a> {
pub vars: HashedMap<LocalIRVariable<'a>>,
pub current_depth: usize // Starts at 0 where 0 is function body
}

impl<'a> IRLocalContext<'a> {
pub fn new() -> Self {
return IRLocalContext { vars: HashedMap::new(0), current_depth: 0 }
}

/// Attempts to add a variable in the current local context. Will return an error if the operation is impossible
pub fn add_variable(&mut self, hash: u64, var: IRPointer<'a>) -> PositionlessResult<bool> {
if self.vars.get(hash).is_some() {
return Err(PositionlessError::new(&format!("Variable named {} is already registered in the current context.", hash)));
}

self.vars.put(hash, LocalIRVariable { ptr: var, depth: self.current_depth });
return Ok(true);
}

pub fn get_variable(&'a self, hash: u64) -> PositionlessResult<&'a IRPointer<'a>> {
return match self.vars.get(hash) {
Some(v) => Ok(&v.ptr),
None => return Err(PositionlessError::new("Invalid variable name"))
};
}

pub fn increment_body_depth(&mut self) {
self.current_depth += 1;
}

/// Ends the current nested body. Is responsible for removing non-valid variable indices
/// Example:
/// ```
/// func test() {
/// // body of depth 0 starts
/// if(true) {
/// // body of depth 1 starts
/// // body of depth 1 ends
/// }
///
/// // body of depth 0 ends
/// }
/// ```
pub fn end_nested_body_depth(&mut self) {
self.current_depth -= 1;

let mut hashToRemove: Vec<u64> = vec![];

for entry in self.vars.entries() {
if entry.1.depth > self.current_depth {
hashToRemove.push(entry.0);
}
}

for hash in hashToRemove {
self.vars.erase(hash);
}
}

}
82 changes: 82 additions & 0 deletions ir/src/irstruct/funcs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use commons::err::{PositionedError, PositionlessError, PositionlessResult};
use inkwell::{basic_block::BasicBlock, builder::Builder, context::Context, module::Module, types::BasicType, values::{BasicValueEnum, FunctionValue, IntValue}};

use crate::types::typing::IRType;

pub struct IRFunction<'a> {
pub inkwell_func: FunctionValue<'a>,
ret_type: &'a IRType<'a>,
args: Vec<&'a IRType<'a>>,
name: String,

entry: Option<BasicBlock<'a>>
}

impl<'a> IRFunction<'a> {
pub fn new(ctx: &'a Context, name: String, func: FunctionValue<'a>, ret_type: &'a IRType<'a>, args: Vec<&'a IRType<'a>>) -> Self {

let block = ctx.append_basic_block(func, "entry");

return IRFunction { inkwell_func: func, ret_type, args, name, entry: Some(block) }
}

pub fn new_shadow(name: String, func: FunctionValue<'a>, ret_type: &'a IRType<'a>, args: Vec<&'a IRType<'a>>) -> Self {
return IRFunction { inkwell_func: func, ret_type, args, name, entry: None }
}

pub fn create_shadow(name: String, module: &Module<'a>, ret_type: &'a IRType<'a>, args: Vec<&'a IRType<'a>>) -> PositionlessResult<Self> {
let mut kargs = vec![];

for k in &args {
kargs.push(k.get_inkwell_base_metadatatype()?);
}

let t = ret_type.get_inkwell_basetype()?.fn_type(&kargs, false);

let func = module.add_function(&name, t, None);

return Ok(IRFunction::new_shadow(name, func, ret_type, args));
}

pub fn create(ctx: &'a Context, name: String, module: &Module<'a>, ret_type: &'a IRType<'a>, args: Vec<&'a IRType<'a>>) -> PositionlessResult<Self> {
let mut kargs = vec![];

for k in &args {
kargs.push(k.get_inkwell_base_metadatatype()?);
}

let t = ret_type.get_inkwell_basetype()?.fn_type(&kargs, false);

let func = module.add_function(&name, t, None);

return Ok(IRFunction::new(ctx, name, func, ret_type, args));
}

/// Prepares the addition of the function body.
pub fn prepare_body_filling(&self, builder: &Builder<'a>) {
if self.entry.is_none() {
return;
}

builder.position_at_end(self.entry.unwrap());
}

pub fn get_nth_arg(&self, ind: u32) -> PositionlessResult<BasicValueEnum<'a>> {
let res = match self.inkwell_func.get_nth_param(ind) {
Some(v) => v,
None => return Err(PositionlessError::new("Couldn't get nth param using get_nth_param"))
};

return Ok(res);
}

pub fn get_nth_arg_int(&self, ind: u32) -> PositionlessResult<IntValue<'a>> {
if !self.args[ind as usize].is_numeric_type() {
return Err(PositionlessError::new("Tried getting nth argument but given argument's type isn't numeric!"));
}

return Ok(self.get_nth_arg(ind)?.into_int_value());

}

}
6 changes: 6 additions & 0 deletions ir/src/irstruct/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Common definitions used internally to structure the IR.

pub mod ptr;
pub mod funcs;
pub mod staticvars;
pub mod structs;
Loading