(broken) add part 1 of mutability

This commit is contained in:
Sofia 2025-07-12 02:38:31 +03:00
parent 85b2ebf04a
commit 14e0dcbe15
13 changed files with 148 additions and 24 deletions

View File

@ -3,6 +3,8 @@
use std::{cell::RefCell, rc::Rc};
use llvm_sys::core::{LLVMBuildAlloca, LLVMBuildLoad2, LLVMBuildStore};
use crate::{
BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type,
util::match_types,
@ -250,6 +252,29 @@ impl Builder {
}
Ok(())
}
Alloca(_, _) => Ok(()),
Load(ptr, _) => {
if let Ok(ty) = ptr.get_type(&self) {
if let Type::Ptr(_) = ty {
Ok(())
} else {
Err(())
}
} else {
Err(())
}
}
Store(ptr, _) => {
if let Ok(ty) = ptr.get_type(&self) {
if let Type::Ptr(_) = ty {
Ok(())
} else {
Err(())
}
} else {
Err(())
}
}
}
}
}
@ -298,7 +323,7 @@ impl InstructionValue {
.function_data(&self.0.0)
.params
.get(*nth)
.copied()
.cloned()
.ok_or(()),
Constant(c) => Ok(c.get_type()),
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
@ -308,6 +333,9 @@ impl InstructionValue {
ICmp(_, _, _) => Ok(Type::Bool),
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
Alloca(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
Load(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
Store(_, value) => value.get_type(builder),
}
}
}
@ -347,6 +375,7 @@ impl Type {
Type::U128 => true,
Type::Bool => true,
Type::Void => false,
Type::Ptr(_) => false,
}
}
@ -364,6 +393,7 @@ impl Type {
Type::U128 => false,
Type::Bool => false,
Type::Void => false,
Type::Ptr(_) => false,
}
}
}

View File

@ -333,6 +333,22 @@ impl InstructionHolder {
);
phi
}
Alloca(name, ty) => LLVMBuildAlloca(
module.builder_ref,
ty.as_llvm(module.context_ref),
into_cstring(name).as_ptr(),
),
Load(ptr, ty) => LLVMBuildLoad2(
module.builder_ref,
ty.as_llvm(module.context_ref),
module.values.get(&ptr).unwrap().value_ref,
c"load".as_ptr(),
),
Store(ptr, val) => LLVMBuildStore(
module.builder_ref,
module.values.get(&val).unwrap().value_ref,
module.values.get(&ptr).unwrap().value_ref,
),
}
};
LLVMValue {
@ -428,6 +444,7 @@ impl Type {
I128 | U128 => LLVMInt128TypeInContext(context),
Bool => LLVMInt1TypeInContext(context),
Void => LLVMVoidType(),
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
}
}
}

View File

@ -97,6 +97,9 @@ impl Debug for Instr {
Self::Phi(val) => fmt_call(f, &"Phi", &val),
Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
Self::FunctionCall(fun, params) => fmt_call(f, fun, params),
Instr::Alloca(name, ty) => write!(f, "alloca<{:?}>({})", ty, name),
Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val),
Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val),
}
}
}

View File

@ -174,13 +174,17 @@ pub enum Instr {
And(InstructionValue, InstructionValue),
Phi(Vec<InstructionValue>),
Alloca(String, Type),
Load(InstructionValue, Type),
Store(InstructionValue, InstructionValue),
/// Integer Comparison
ICmp(CmpPredicate, InstructionValue, InstructionValue),
FunctionCall(FunctionValue, Vec<InstructionValue>),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Type {
I8,
I16,
@ -194,6 +198,7 @@ pub enum Type {
U128,
Bool,
Void,
Ptr(Box<Type>),
}
#[derive(Debug, Clone, Hash)]

View File

@ -133,7 +133,7 @@ pub struct Block(
pub enum BlockLevelStatement {
Let(LetStatement),
/// Try to set a variable to a specified expression value
Set(String, Expression),
Set(String, Expression, TokenRange),
Import {
_i: ImportStatement,
},

View File

@ -363,8 +363,8 @@ impl Parse for BlockLevelStatement {
Stmt::Return(ReturnType::Hard, exp)
}
_ => {
if let Ok(SetStatement(ident, expr)) = stream.parse() {
Stmt::Set(ident, expr)
if let Ok(SetStatement(ident, expr, range)) = stream.parse() {
Stmt::Set(ident, expr, range)
} else {
if let Ok(e) = stream.parse() {
if stream.expect(Token::Semi).is_ok() {
@ -382,7 +382,7 @@ impl Parse for BlockLevelStatement {
}
#[derive(Debug)]
pub struct SetStatement(String, Expression);
pub struct SetStatement(String, Expression, TokenRange);
impl Parse for SetStatement {
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
@ -390,7 +390,7 @@ impl Parse for SetStatement {
stream.expect(Token::Equals)?;
let expr = stream.parse()?;
stream.expect(Token::Semi)?;
Ok(Self(ident, expr))
Ok(Self(ident, expr, stream.get_range().unwrap()))
} else {
Err(stream.expected_err("identifier")?)?
}

View File

@ -70,11 +70,22 @@ impl ast::Block {
s_let.0.clone(),
s_let.4.into(),
),
s_let.2,
s_let.3.process(),
),
s_let.4,
),
ast::BlockLevelStatement::Set(_, expression) => todo!(),
ast::BlockLevelStatement::Set(name, expression, range) => (
StmtKind::Set(
VariableReference(
mir::TypeKind::Vague(mir::VagueType::Unknown),
name.clone(),
(*range).into(),
),
expression.process(),
),
*range,
),
ast::BlockLevelStatement::Import { _i } => todo!(),
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),

View File

@ -1,11 +1,12 @@
use std::{collections::HashMap, mem};
use llvm_sys::core::LLVMBuildStore;
use reid_lib::{
Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, TerminatorKind as Term,
Type, builder::InstructionValue,
builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module,
TerminatorKind as Term, Type,
};
use crate::mir::{self, TypeKind, VariableReference, types::ReturnType};
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
/// Context that contains all of the given modules as complete codegenerated
/// LLIR that can then be finally compiled into LLVM IR.
@ -73,8 +74,14 @@ impl mir::Module {
let mut entry = function.block("entry");
let mut stack_values = HashMap::new();
for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() {
stack_values.insert(p_name.clone(), entry.build(Instr::Param(i)).unwrap());
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
stack_values.insert(
p_name.clone(),
StackValue(
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
p_ty.get_type(),
),
);
}
let mut scope = Scope {
@ -114,7 +121,16 @@ pub struct Scope<'ctx, 'a> {
function: &'ctx Function<'ctx>,
block: Block<'ctx>,
functions: &'a HashMap<String, Function<'ctx>>,
stack_values: HashMap<String, InstructionValue>,
stack_values: HashMap<String, StackValue>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StackValue(StackValueKind, Type);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StackValueKind {
Immutable(InstructionValue),
Mutable(InstructionValue),
}
impl<'ctx, 'a> Scope<'ctx, 'a> {
@ -141,11 +157,33 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
impl mir::Statement {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
match &self.0 {
mir::StmtKind::Let(VariableReference(_, name, _), expression) => {
mir::StmtKind::Let(VariableReference(ty, name, _), mutable, expression) => {
let value = expression.codegen(scope).unwrap();
scope.stack_values.insert(name.clone(), value);
scope.stack_values.insert(
name.clone(),
StackValue(
match mutable {
true => StackValueKind::Mutable(value),
false => StackValueKind::Immutable(value),
},
ty.get_type(),
),
);
None
}
mir::StmtKind::Set(var, val) => {
if let Some(StackValue(kind, ty)) = scope.stack_values.get(&var.1).cloned() {
match kind {
StackValueKind::Immutable(ptr) => {
let expression = val.codegen(scope).unwrap();
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
}
StackValueKind::Mutable(_) => panic!(""),
}
} else {
panic!("")
}
}
// mir::StmtKind::If(if_expression) => if_expression.codegen(scope),
mir::StmtKind::Import(_) => todo!(),
mir::StmtKind::Expression(expression) => expression.codegen(scope),
@ -218,7 +256,12 @@ impl mir::Expression {
.stack_values
.get(&varref.1)
.expect("Variable reference not found?!");
Some(v.clone())
Some(match v.0 {
StackValueKind::Immutable(val) => val.clone(),
StackValueKind::Mutable(val) => {
scope.block.build(Instr::Load(val, v.1.clone())).unwrap()
}
})
}
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {

View File

@ -94,7 +94,16 @@ impl Display for Statement {
impl Display for StmtKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Let(var, block) => write!(f, "let {} = {}", var, block),
Self::Let(var, mutable, block) => {
write!(
f,
"let{} {} = {}",
if *mutable { " mut" } else { "" },
var,
block
)
}
Self::Set(var, expr) => write!(f, "{} = {}", var, expr),
Self::Import(n) => write!(f, "import {}", n),
Self::Expression(exp) => Display::fmt(exp, f),
}

View File

@ -257,8 +257,9 @@ pub struct Statement(pub StmtKind, pub Metadata);
#[derive(Debug)]
pub enum StmtKind {
/// Variable name+type, evaluation
Let(VariableReference, Expression),
/// Variable name++mutability+type, evaluation
Let(VariableReference, bool, Expression),
Set(VariableReference, Expression),
Import(Import),
Expression(Expression),
}

View File

@ -253,9 +253,10 @@ impl Block {
impl Statement {
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
match &mut self.0 {
StmtKind::Let(_, expression) => {
StmtKind::Let(_, mutable, expression) => {
expression.pass(pass, state, scope);
}
StmtKind::Set(variable_reference, expression) => {} // TODO
StmtKind::Import(_) => todo!(),
StmtKind::Expression(expression) => {
expression.pass(pass, state, scope);
@ -265,10 +266,11 @@ impl Statement {
pass.stmt(self, PassState::from(state, scope));
match &mut self.0 {
StmtKind::Let(variable_reference, _) => scope
StmtKind::Let(variable_reference, mutable, _) => scope
.variables
.set(variable_reference.1.clone(), variable_reference.0)
.ok(),
StmtKind::Set(variable_reference, expression) => None, // TODO
StmtKind::Import(_) => todo!(),
StmtKind::Expression(_) => None,
};

View File

@ -93,7 +93,8 @@ impl Block {
for statement in &mut self.statements {
let ret = match &mut statement.0 {
StmtKind::Let(variable_reference, expression) => {
// TODO
StmtKind::Let(variable_reference, mutable, expression) => {
let res = expression.typecheck(&mut state, Some(variable_reference.0));
// If expression resolution itself was erronous, resolve as
@ -125,6 +126,7 @@ impl Block {
state.ok(res, variable_reference.2);
None
}
StmtKind::Set(variable_reference, expression) => None, // TODO
StmtKind::Import(_) => todo!(),
StmtKind::Expression(expression) => {
let res = expression.typecheck(&mut state, None);

View File

@ -26,8 +26,9 @@ impl ReturnType for Statement {
use StmtKind::*;
match &self.0 {
Expression(e) => e.return_type(),
Set(_, _) => todo!(),
Import(_) => Err(ReturnTypeOther::Import(self.1.range)),
Let(_, _) => Err(ReturnTypeOther::Let(self.1.range)),
Let(_, _, _) => Err(ReturnTypeOther::Let(self.1.range)),
}
}
}