updated compiler IR codegen. still broken but getting there. next job is figuring out how we handle Lvalues.

This commit is contained in:
2026-08-25 00:49:23 +01:00
parent 97e43b8b85
commit a130ef2cf6
6 changed files with 555 additions and 556 deletions
+127 -126
View File
@@ -2,8 +2,8 @@ use super::instruction::InsBlock as IB;
use super::registers::RegisterAllocator;
use crate::model::CompilerError;
use crate::model::ast::{
AssignmentOperator, BinaryOperator, Call, ConstExpr, Declaration, Dependency, Expression,
Number, Program, Statement, TypeId, UnaryOperator, Variable,
BinaryOperator, Call, ConstExpr, Declaration, Dependency, Number, Program, RValue, Statement,
TypeId, UnaryOperator, Variable,
};
use crate::model::instruction::Comparison::{
Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual,
@@ -240,7 +240,7 @@ impl CodeGenerator {
let mut code = IB::new();
match stmt {
Statement::Declaration { var, value } => {
Statement::Declaration { var, value, .. } => {
if let Some(expr) = value {
// Evaluate expression
let (result_reg, expr_code) =
@@ -263,116 +263,117 @@ impl CodeGenerator {
Statement::Continue => unimplemented!("need scope tracking first!"),
Statement::Defer(_func) => unimplemented!("we need scope tracking first!"),
Statement::PtrWrite { ptr, value } => {
let (result_reg, expr_code) = self.generate_expression(value, true, func_body)?;
code.append(expr_code);
_ => todo!(),
let (ptr_reg, ptr_code) = self.generate_expression(ptr, true, func_body)?;
code.append(ptr_code);
code.push(I::stw_reg(result_reg, ptr_reg));
self.allocator.free_temp(result_reg);
self.allocator.free_temp(ptr_reg);
}
Statement::Assign {
varname,
value,
operator,
} => {
// Evaluate expression
let (result_reg, expr_code) = self.generate_expression(value, true, func_body)?;
code.append(expr_code);
if *operator == AssignmentOperator::Assign {
// Check if this is a global variable
if self.is_global(varname) {
// Store to global label
code.push(I::stw_label(result_reg, varname.clone()))
} else {
// Store result in local variable
let store_code = self.allocator.store_var(varname, &result_reg);
code.append(store_code);
}
// Free temporary register
self.allocator.free_temp(result_reg);
return Ok(code);
}
// for more complex assignment cases we need an intermediate register.
let (temp_reg, temp_code) = self.allocator.alloc_temp()?;
code.append(temp_code);
// fetch the value of the variable
let var_reg = if self.is_global(varname) {
let instruction = I::ldw_label(varname.clone(), temp_reg);
code.push(instruction);
temp_reg
} else {
let (rg, block) = self.allocator.load_var(varname)?;
code.append(block);
rg
};
let assign_code = match operator {
AssignmentOperator::Assign => {
unreachable!("assignment was already checked earlier.")
}
AssignmentOperator::AddAssign => I::add(var_reg, result_reg, temp_reg),
AssignmentOperator::SubAssign => I::sub(var_reg, result_reg, temp_reg),
AssignmentOperator::MulAssign => {
return Err(CompilerError::Unimplemented(
"TODO: implement multiplication for assignment".to_string(),
));
}
AssignmentOperator::DivAssign => {
return Err(CompilerError::Unimplemented(
"TODO: write proper div function for DSA".to_string(),
));
}
AssignmentOperator::ModAssign => {
return Err(CompilerError::Unimplemented(
"TODO: write proper mod function for DSA".to_string(),
));
}
AssignmentOperator::AndAssign => I::and(var_reg, result_reg, temp_reg),
AssignmentOperator::OrAssign => I::or(var_reg, result_reg, temp_reg),
AssignmentOperator::XorAssign => I::xor(var_reg, result_reg, temp_reg),
AssignmentOperator::LeftShiftAssign => {
// this is only useful if we optimise out the register allocation
// inside value.
// if let Expression::Number { value, .. } = *value {
// I::shl(var_reg, value, temp_reg)
// }
I::shl(var_reg, result_reg, 0, temp_reg)
}
AssignmentOperator::RightShiftAssign => {
// this is only useful if we optimise out the register allocation
// if let Expression::Number { value, .. } = *value {
// I::shr(var_reg, value, temp_reg)
// }
I::shr(var_reg, result_reg, 0, temp_reg)
}
};
code.push(assign_code);
// Check if this is a global variable
if self.is_global(varname) {
// Store to global label
code.push(I::stw_label(temp_reg, varname.clone()))
} else {
// Store result in local variable
let store_code = self.allocator.store_var(varname, &temp_reg);
code.append(store_code);
}
self.allocator.free_temp(result_reg);
self.allocator.free_temp(temp_reg);
}
// Statement::PtrWrite { ptr, value } => {
// let (result_reg, expr_code) = self.generate_expression(value, true, func_body)?;
// code.append(expr_code);
//
// let (ptr_reg, ptr_code) = self.generate_expression(ptr, true, func_body)?;
// code.append(ptr_code);
//
// code.push(I::stw_reg(result_reg, ptr_reg));
//
// self.allocator.free_temp(result_reg);
// self.allocator.free_temp(ptr_reg);
// }
// Statement::Assign {
// varname,
// value,
// operator,
// } => {
// // Evaluate expression
// let (result_reg, expr_code) = self.generate_expression(value, true, func_body)?;
// code.append(expr_code);
//
// if *operator == AssignmentOperator::Assign {
// // Check if this is a global variable
// if self.is_global(varname) {
// // Store to global label
// code.push(I::stw_label(result_reg, varname.clone()))
// } else {
// // Store result in local variable
// let store_code = self.allocator.store_var(varname, &result_reg);
// code.append(store_code);
// }
//
// // Free temporary register
// self.allocator.free_temp(result_reg);
//
// return Ok(code);
// }
//
// // for more complex assignment cases we need an intermediate register.
// let (temp_reg, temp_code) = self.allocator.alloc_temp()?;
// code.append(temp_code);
//
// // fetch the value of the variable
// let var_reg = if self.is_global(varname) {
// let instruction = I::ldw_label(varname.clone(), temp_reg);
// code.push(instruction);
// temp_reg
// } else {
// let (rg, block) = self.allocator.load_var(varname)?;
// code.append(block);
// rg
// };
//
// let assign_code = match operator {
// AssignmentOperator::Assign => {
// unreachable!("assignment was already checked earlier.")
// }
// AssignmentOperator::AddAssign => I::add(var_reg, result_reg, temp_reg),
// AssignmentOperator::SubAssign => I::sub(var_reg, result_reg, temp_reg),
// AssignmentOperator::MulAssign => {
// return Err(CompilerError::Unimplemented(
// "TODO: implement multiplication for assignment".to_string(),
// ));
// }
// AssignmentOperator::DivAssign => {
// return Err(CompilerError::Unimplemented(
// "TODO: write proper div function for DSA".to_string(),
// ));
// }
// AssignmentOperator::ModAssign => {
// return Err(CompilerError::Unimplemented(
// "TODO: write proper mod function for DSA".to_string(),
// ));
// }
// AssignmentOperator::AndAssign => I::and(var_reg, result_reg, temp_reg),
// AssignmentOperator::OrAssign => I::or(var_reg, result_reg, temp_reg),
// AssignmentOperator::XorAssign => I::xor(var_reg, result_reg, temp_reg),
// AssignmentOperator::LeftShiftAssign => {
// // this is only useful if we optimise out the register allocation
// // inside value.
// // if let Expression::Number { value, .. } = *value {
// // I::shl(var_reg, value, temp_reg)
// // }
// I::shl(var_reg, result_reg, 0, temp_reg)
// }
// AssignmentOperator::RightShiftAssign => {
// // this is only useful if we optimise out the register allocation
// // if let Expression::Number { value, .. } = *value {
// // I::shr(var_reg, value, temp_reg)
// // }
// I::shr(var_reg, result_reg, 0, temp_reg)
// }
// };
// code.push(assign_code);
//
// // Check if this is a global variable
// if self.is_global(varname) {
// // Store to global label
// code.push(I::stw_label(temp_reg, varname.clone()))
// } else {
// // Store result in local variable
// let store_code = self.allocator.store_var(varname, &temp_reg);
// code.append(store_code);
// }
//
// self.allocator.free_temp(result_reg);
// self.allocator.free_temp(temp_reg);
// }
Statement::Return(expr) => {
if let Some(e) = expr {
let (result_reg, expr_code) = self.generate_expression(e, true, func_body)?;
@@ -479,16 +480,16 @@ impl CodeGenerator {
// Returns (register containing result, assembly code)
fn generate_expression(
&mut self,
expr: &Expression,
expr: &RValue,
use_result: bool,
func_body: &mut IB,
) -> Result<(Register, IB), CompilerError> {
let mut code = IB::new();
match expr {
Expression::Empty => Ok((Register::Null, code)),
RValue::Empty => Ok((Register::Null, code)),
Expression::Number(n) => match n {
RValue::Number(n) => match n {
Number::Signed(value, _) => {
let (reg, alloc_code) = self.allocator.alloc_temp()?;
code.append(alloc_code);
@@ -509,7 +510,7 @@ impl CodeGenerator {
}
},
Expression::CharLiteral(value) => {
RValue::CharLiteral(value) => {
let (reg, alloc_code) = self.allocator.alloc_temp()?;
code.append(alloc_code);
@@ -520,7 +521,7 @@ impl CodeGenerator {
Ok((reg, code))
}
Expression::StringLiteral(value) => {
RValue::StringLiteral(value) => {
let (reg, alloc_code) = self.allocator.alloc_temp()?;
code.append(alloc_code);
@@ -535,14 +536,14 @@ impl CodeGenerator {
Ok((reg, code))
}
Expression::ArrayLiteral { elements, type_id } => todo!(),
Expression::StructLiteral {
RValue::ArrayLiteral { elements, type_id } => todo!(),
RValue::StructLiteral {
name,
fields,
type_id,
} => todo!(),
Expression::Variable { name, .. } => {
RValue::Variable { name, .. } => {
if self.is_global(&name.name) {
// Allocate a temporary register for the global
let (reg, alloc_code) = self.allocator.alloc_temp()?;
@@ -560,7 +561,7 @@ impl CodeGenerator {
}
}
Expression::Binary {
RValue::Binary {
op, left, right, ..
} => {
// Evaluate left operand
@@ -669,7 +670,7 @@ impl CodeGenerator {
Ok((result_reg, code))
}
Expression::UnaryPostfix { op, operand, .. } => {
RValue::UnaryPostfix { op, operand, .. } => {
let (operand_reg, operand_code) =
self.generate_expression(operand, true, func_body)?;
code.append(operand_code);
@@ -695,7 +696,7 @@ impl CodeGenerator {
Ok((result_reg, code))
}
Expression::Unary { op, operand, .. } => {
RValue::Unary { op, operand, .. } => {
let (operand_reg, operand_code) =
self.generate_expression(operand, true, func_body)?;
code.append(operand_code);
@@ -759,7 +760,7 @@ impl CodeGenerator {
Ok((result_reg, code))
}
Expression::Call {
RValue::Call {
func: Call { name, args },
..
} => {
@@ -829,7 +830,7 @@ impl CodeGenerator {
Ok((result_reg, code))
}
Expression::IndexAccess {
RValue::IndexAccess {
expr,
index,
type_id,
@@ -853,7 +854,7 @@ impl CodeGenerator {
Ok((result_reg, code))
}
Expression::MemberAccess {
RValue::MemberAccess {
expr,
field_name,
type_id,
@@ -861,7 +862,7 @@ impl CodeGenerator {
"Structs are not yet implemented!".to_string(),
)),
Expression::TypeCast {
RValue::TypeCast {
expr,
target_type,
type_id,
@@ -1,8 +1,14 @@
use std::any::Any;
use dsa_tasks::ProcessAgent;
use std::rc::Rc;
use crate::model::ast::{BinaryOperator, Block, Call, Declaration, Expression, Number, Program, Statement, TypeId, UnaryOperator, Variable};
use crate::model::dsa_ir::{BasicBlock, IRProgram, Label, Literal, PrimitiveOperation, PrimitiveUnaryOperation, Terminator, VirtualReg};
use crate::model::ast::{
AssignmentOperator, BinaryOperator, Block, Call, Declaration, LValue, Number, Program, RValue,
Statement, TypeId, UnaryOperator, Variable,
};
use crate::model::dsa_ir::{
BasicBlock, IRProgram, Label, Literal, PrimitiveOperation, PrimitiveUnaryOperation, Terminator,
VirtualReg,
};
use crate::model::{CompilerError, dsa_ir as IR};
pub struct IrLoweringCodeGenerator {
@@ -71,7 +77,7 @@ impl IrLoweringCodeGenerator {
) -> Result<IR::Function, CompilerError> {
let mut context = FunctionContext::new(Label::new(function_name.to_string()));
let params = (0..params.len()).map(|_| context.new_vreg()).collect();
let params = (0..params.len()).map(|_| context.allocate_vreg()).collect();
self.collapse_block(body, &mut context)?;
@@ -125,8 +131,8 @@ impl IrLoweringCodeGenerator {
let else_label = Label::new_with_id("else", id);
let end_label = Label::new_with_id("endif", id);
let eval_result = ctx.new_vreg();
self.collapse_expression(condition, ctx, eval_result)?;
let eval_result = ctx.allocate_vreg();
self.collapse_rvalue(condition, ctx, eval_result.clone())?;
ctx.next_block(
Terminator::ConditionalJump {
@@ -157,8 +163,8 @@ impl IrLoweringCodeGenerator {
Statement::Return(expr) => {
// return stmt. calls relevant defer methods and expands the body of the return statement.
let result = if let Some(value) = expr {
let result_reg = ctx.new_vreg();
self.collapse_expression(value, ctx, result_reg)?;
let result_reg = ctx.allocate_vreg();
self.collapse_rvalue(value, ctx, result_reg.clone())?;
result_reg
} else {
VirtualReg::void()
@@ -177,7 +183,7 @@ impl IrLoweringCodeGenerator {
Statement::Expression { expr } => {
// generate the code for the expression but discard the result
// let the optimiser remove it if it provably has no side effects.
self.collapse_expression(expr, ctx, VirtualReg::void())?;
self.collapse_rvalue(expr, ctx, VirtualReg::void())?;
Ok(())
}
@@ -226,8 +232,8 @@ impl IrLoweringCodeGenerator {
ctx.next_block(Terminator::Jump(check_label.clone()), check_label.clone());
let if_flag = ctx.new_vreg();
self.collapse_expression(condition, ctx, if_flag)?;
let if_flag = ctx.allocate_vreg();
self.collapse_rvalue(condition, ctx, if_flag.clone())?;
ctx.next_block(
Terminator::ConditionalJump {
@@ -271,48 +277,81 @@ impl IrLoweringCodeGenerator {
Ok(())
}
Statement::Declaration { var, value } => {
let Some(expr) = value else {
ctx.new_local(VirtualReg::void(), var.clone());
return Ok(());
};
Statement::Declaration { var, value, .. } => {
// TODO: How do we name this without duplicating the string?
let decl_reg = ctx.allocate_vreg();
// tell the IR to allocate a stack slot for the var
ctx.push_stmt(IR::Statement::Alloca(decl_reg.clone(), var.type_id.size()));
// register the new local var with the current context.
let local_var =
LocalVar::on_stack(&var.name, decl_reg.clone(), var.type_id.clone());
ctx.new_local(local_var);
if let Some(expr) = value {
self.collapse_rvalue(expr, ctx, decl_reg)?;
}
let v_reg = ctx.new_vreg();
self.collapse_expression(expr, ctx, v_reg)?;
ctx.new_local(v_reg, var.clone());
Ok(())
}
Statement::Assign {
varname,
value,
left,
right,
operator,
} => {
let Some(v_reg) = ctx.find_local(varname) else {
} => self.collapse_assignment(left, right, operator, ctx), // TODO: support full range of assignment operators!
}
}
fn collapse_assignment(
&self,
left: &LValue,
right: &RValue,
operator: &AssignmentOperator,
ctx: &mut FunctionContext,
) -> Result<(), CompilerError> {
// evaluate right hand side of assignment
let value = ctx.allocate_vreg();
self.collapse_rvalue(right, ctx, value.clone())?;
// TODO: make use of the alternative assignment operators!
// TODO: (assuming always '=' for now)
match left {
LValue::Variable(var) => {
let Some(write_to) = ctx.find_local(&var.name) else {
return Err(CompilerError::generic(format!(
"Variable not defined: {varname}"
"Variable not defined: {}",
var.name
)));
};
self.collapse_expression(value, ctx, v_reg)?;
Ok(())
} // todo!!!!
let cmd = match write_to {
VarLoc::Stack(address) => IR::Statement::Store { value, address },
VarLoc::Register(register) => IR::Statement::Copy {
src: value,
dst: register,
},
};
Statement::PtrWrite { ptr, value } => {
let ptr_reg = ctx.new_vreg();
self.collapse_expression(&ptr, ctx, ptr_reg)?;
ctx.push_stmt(cmd);
}
let value_reg = ctx.new_vreg();
self.collapse_expression(&value, ctx, value_reg)?;
LValue::Pointer(var) => {
todo!();
}
ctx.push_stmt(IR::Statement::Store {
value: value_reg,
address: ptr_reg,
});
LValue::ArrayIndex(array, index) => {
let index_vreg = ctx.allocate_vreg();
self.collapse_rvalue(index, ctx, value.clone())?;
}
Ok(())
LValue::StructField(lvalue, field) => {
todo!();
}
}
Ok(())
}
fn collapse_call(
@@ -325,8 +364,9 @@ impl IrLoweringCodeGenerator {
.args
.iter()
.map(|arg| {
let v_reg = ctx.new_vreg();
self.collapse_expression(&arg, ctx, v_reg).map(|_| v_reg)
let v_reg = ctx.allocate_vreg();
self.collapse_rvalue(&arg, ctx, v_reg.clone())
.map(|_| v_reg)
})
.collect::<Result<Vec<VirtualReg>, _>>()?;
@@ -339,23 +379,23 @@ impl IrLoweringCodeGenerator {
Ok(())
}
fn collapse_expression(
fn collapse_rvalue(
&self,
expr: &Expression,
expr: &RValue,
ctx: &mut FunctionContext,
v_reg: VirtualReg,
) -> Result<(), CompilerError> {
match expr {
Expression::Empty => Ok(()),
Expression::Call { func, .. } => {
RValue::Empty => Ok(()),
RValue::Call { func, .. } => {
self.collapse_call(func, ctx, v_reg)?;
Ok(())
}
Expression::CharLiteral(c) => {
RValue::CharLiteral(c) => {
ctx.push_stmt(IR::Statement::Const(v_reg, Literal::Char(*c)));
Ok(())
}
Expression::Number(num) => {
RValue::Number(num) => {
match num {
Number::Signed(val, ..) => {
ctx.push_stmt(IR::Statement::Const(v_reg, Literal::Int(*val as isize)));
@@ -366,49 +406,60 @@ impl IrLoweringCodeGenerator {
}
Ok(())
}
Expression::Variable { name, expr_type } => {
RValue::Variable { name, expr_type } => {
let Some(var) = ctx.find_local(&name.name) else {
return Err(CompilerError::generic(format!(
"Variable not defined: {name}"
)));
};
ctx.push_stmt(IR::Statement::Copy {
src: var,
dst: v_reg,
});
let statement = match var {
VarLoc::Stack(address) => IR::Statement::Load {
address,
result: v_reg,
},
VarLoc::Register(src) => IR::Statement::Copy { dst: v_reg, src },
};
ctx.push_stmt(statement);
Ok(())
}
// TODO! all of the below:
Expression::Binary { op, left, right, .. } => self.collapse_binary_expr(left, right, op, ctx, v_reg),
Expression::Unary { op, operand, .. } => self.collapse_unary_op(operand, op, ctx, v_reg),
Expression::UnaryPostfix { .. } => Ok(()),
Expression::TypeCast { .. } => Ok(()),
Expression::IndexAccess { .. } => Ok(()),
Expression::MemberAccess { .. } => Ok(()),
Expression::StringLiteral(_) => Ok(()),
Expression::ArrayLiteral { .. } => Ok(()),
Expression::StructLiteral { .. } => Ok(()),
RValue::Binary {
op, left, right, ..
} => self.collapse_binary_expr(left, right, op, ctx, v_reg),
RValue::Unary { op, operand, .. } => self.collapse_unary_op(operand, op, ctx, v_reg),
RValue::UnaryPostfix {
op,
operand,
type_id,
} => Ok(()),
RValue::TypeCast { .. } => Ok(()),
RValue::IndexAccess { .. } => Ok(()),
RValue::MemberAccess { .. } => Ok(()),
RValue::StringLiteral(_) => Ok(()),
RValue::ArrayLiteral { .. } => Ok(()),
RValue::StructLiteral { .. } => Ok(()),
}
}
fn collapse_unary_op(
&self,
expr: &Expression,
expr: &RValue,
op: &UnaryOperator,
ctx: &mut FunctionContext,
result_reg: VirtualReg,
) -> Result<(), CompilerError> {
let intermediate_reg = ctx.new_vreg();
self.collapse_expression(expr, ctx, intermediate_reg)?;
let intermediate_reg = ctx.allocate_vreg();
self.collapse_rvalue(expr, ctx, intermediate_reg.clone())?;
let ir_stmt = match op {
UnaryOperator::Plus => IR::Statement::UnaryOp {
// use the identity operation as '+x' on an integer 'x' is a no-op
op: PrimitiveUnaryOperation::Identity,
operand: intermediate_reg,
operand: intermediate_reg.clone(),
result: result_reg,
},
@@ -420,25 +471,25 @@ impl IrLoweringCodeGenerator {
// allocating a vreg for an incrementation isn't very elegant but it can be easily optimised out.
UnaryOperator::Increment => {
let right_vreg = ctx.new_vreg();
ctx.push_stmt(IR::Statement::Const(right_vreg, Literal::Int(1)));
let right_vreg = ctx.allocate_vreg();
ctx.push_stmt(IR::Statement::Const(right_vreg.clone(), Literal::Int(1)));
IR::Statement::BinaryOp {
left: intermediate_reg,
op: PrimitiveOperation::Add,
right: right_vreg,
result: result_reg,
}
},
}
UnaryOperator::Decrement => {
let right_vreg = ctx.new_vreg();
ctx.push_stmt(IR::Statement::Const(right_vreg, Literal::Int(1)));
let right_vreg = ctx.allocate_vreg();
ctx.push_stmt(IR::Statement::Const(right_vreg.clone(), Literal::Int(1)));
IR::Statement::BinaryOp {
left: intermediate_reg,
op: PrimitiveOperation::Sub,
right: right_vreg,
result: result_reg,
}
},
}
// TODO: for now we assume all values are primitives.
// hence this implementation is *not correct* for structs and will produce UB.
@@ -448,15 +499,18 @@ impl IrLoweringCodeGenerator {
},
// TODO: this may be quite complex as we have to guarantee ahead of time that this value has a memory address!
UnaryOperator::AddressOf => todo!(),
UnaryOperator::AddressOf => IR::Statement::NoOp,
// TODO: if the expression is pure, we don't need to evaluate it to know the size.
UnaryOperator::SizeOf => {
let size = expr.type_id()
.map_err(|_| CompilerError::generic("All types are expected to be sized at this stage"))?
let size = expr
.type_id()
.map_err(|_| {
CompilerError::generic("All types are expected to be sized at this stage")
})?
.size();
IR::Statement::Const(result_reg, Literal::Int(size as isize))
},
}
UnaryOperator::BitwiseNot => IR::Statement::UnaryOp {
op: PrimitiveUnaryOperation::Not,
@@ -465,7 +519,7 @@ impl IrLoweringCodeGenerator {
},
// TODO: the IR can't represent boolean operators yet. do we add it to the IR or do something here instead?
UnaryOperator::LogicalNot => todo!(),
UnaryOperator::LogicalNot => IR::Statement::NoOp,
};
ctx.push_stmt(ir_stmt);
@@ -475,17 +529,17 @@ impl IrLoweringCodeGenerator {
fn collapse_binary_expr(
&self,
left: &Expression,
right: &Expression,
left: &RValue,
right: &RValue,
op: &BinaryOperator,
ctx: &mut FunctionContext,
result_vreg: VirtualReg,
) -> Result<(), CompilerError> {
let left_vreg = ctx.new_vreg();
self.collapse_expression(left, ctx, left_vreg)?;
let left_vreg = ctx.allocate_vreg();
self.collapse_rvalue(left, ctx, left_vreg.clone())?;
let right_vreg = ctx.new_vreg();
self.collapse_expression(right, ctx, right_vreg)?;
let right_vreg = ctx.allocate_vreg();
self.collapse_rvalue(right, ctx, right_vreg.clone())?;
let primitive_operation = match op {
// arithmetic
@@ -562,12 +616,53 @@ impl BasicBlockBuilder {
}
}
#[derive(Debug, Clone)]
enum VarLoc {
Register(VirtualReg),
Stack(VirtualReg),
}
#[derive(Debug, Clone)]
struct LocalVar {
location: VarLoc,
name: Rc<String>,
type_id: TypeId,
}
impl LocalVar {
pub fn on_stack(name: impl Into<String>, stack_loc: VirtualReg, type_id: TypeId) -> Self {
Self {
name: Rc::new(name.into()),
location: VarLoc::Stack(stack_loc),
type_id,
}
}
pub fn new(ctx: &mut FunctionContext, name: impl Into<String>, type_id: TypeId) -> Self {
let name = Rc::new(name.into());
let v_reg = ctx.allocate_vreg().named(name.clone());
Self {
name,
location: VarLoc::Stack(v_reg),
type_id,
}
}
pub fn location(&self) -> VarLoc {
self.location.clone()
}
pub fn name(&self) -> &str {
self.name.as_str()
}
}
pub struct Scope {
start: Label,
end: Label,
defers: Vec<Call>,
locals: Vec<(VirtualReg, Variable)>,
locals: Vec<LocalVar>,
}
impl Scope {
@@ -602,21 +697,17 @@ impl FunctionContext {
}
}
pub fn new_vreg(&mut self) -> VirtualReg {
pub fn allocate_vreg(&mut self) -> VirtualReg {
self.v_register_idx += 1;
VirtualReg(self.v_register_idx as isize - 1)
VirtualReg::Anonymous(self.v_register_idx as isize - 1)
}
pub fn defer(&mut self, call: Call) {
self.scopes.last_mut().unwrap().defers.push(call);
}
pub fn new_local(&mut self, v_reg: VirtualReg, variable: Variable) {
self.scopes
.last_mut()
.unwrap()
.locals
.push((v_reg, variable));
pub fn new_local(&mut self, var: LocalVar) {
self.scopes.last_mut().unwrap().locals.push(var);
}
pub fn enter_scope(&mut self, scope: Scope) {
@@ -635,11 +726,11 @@ impl FunctionContext {
.collect()
}
pub fn find_local(&self, var: &String) -> Option<VirtualReg> {
pub fn find_local(&self, var: &String) -> Option<VarLoc> {
for scope in self.scopes.iter().rev() {
for local in &scope.locals {
if local.1.name == *var {
return Some(local.0);
if local.name.as_str() == var {
return Some(local.location.clone());
}
}
}
+103 -136
View File
@@ -1,7 +1,7 @@
use crate::model::CompilerError;
use crate::model::ast::{
AssignmentOperator, BinaryOperator, Block, Call, ConstExpr, Declaration, Dependency,
Expression, Number, Program, Statement, TypeId, UnaryOperator, Variable,
AssignmentOperator, BinaryOperator, Block, Call, ConstExpr, Declaration, Dependency, LValue,
Number, Program, RValue, Statement, TypeId, UnaryOperator, Variable,
};
use crate::model::tokens::Token;
use crate::{expect_tt, expect_value};
@@ -192,7 +192,7 @@ impl Parser {
if expect_tt!(self.peek_next()?, If).accepted() {
self.next()?;
let condition = self.parse_expression()?;
let condition = self.parse_rvalue()?;
let then_stmt = self.parse_block()?;
@@ -220,7 +220,7 @@ impl Parser {
self.next()?;
// expect valid expression
let expr = self.parse_expression()?;
let expr = self.parse_rvalue()?;
// expect valid block after
let block = self.parse_block()?;
@@ -248,7 +248,7 @@ impl Parser {
return ParseResult::Accept(Statement::Return(None));
}
let expr = self.parse_expression()?;
let expr = self.parse_rvalue()?;
expect_tt!(self.next()?, Semicolon)?;
return ParseResult::Accept(Statement::Return(Some(expr)));
@@ -274,45 +274,6 @@ impl Parser {
return ParseResult::Accept(Statement::Continue);
}
// handle writes to pointers!
if expect_tt!(self.peek_next()?, Star).accepted() {
self.next()?;
let left = if expect_tt!(self.peek_next()?, Identifier).accepted() {
let identifier = expect_value!(self.next()?, Identifier)?;
Expression::Variable {
name: identifier,
expr_type: None,
}
} else if expect_tt!(self.peek_next()?, LeftParen).accepted() {
self.next()?;
let expr = self.parse_expression()?;
let _ = expect_tt!(self.next()?, RightParen).accepted();
expr
} else {
return ParseResult::Reject(CompilerError::UnexpectedToken(
self.peek_next()?.tt().to_string(),
));
};
let _ = expect_tt!(self.next()?, Assign)?;
let right = self.parse_expression()?;
// expect semicolon
expect_tt!(self.next()?, Semicolon)?;
// return result
return ParseResult::Accept(Statement::PtrWrite {
ptr: left,
value: right,
});
}
// handle let statements (declarations)
if expect_tt!(self.peek_next()?, Let).accepted() {
self.next();
@@ -325,6 +286,7 @@ impl Parser {
self.next();
return ParseResult::Accept(Statement::Declaration {
var: name,
mutable: false,
value: None,
});
}
@@ -334,83 +296,88 @@ impl Parser {
let _ = expect_tt!(self.next()?, Assign)?;
// expect a valid expression
let expr = self.parse_expression()?;
let expr = self.parse_rvalue()?;
let _ = expect_tt!(self.next()?, Semicolon);
// return statement
return ParseResult::Accept(Statement::Declaration {
var: name,
mutable: false, // TODO: add mutability check
value: Some(expr),
});
}
// handle an in-place function call
if let ParseResult::Accept(name) = expect_value!(self.peek_next()?, Identifier)
&& let ParseResult::Accept(operator) = expect_tt!(
self.peek(1)?,
Assign,
PlusEqual,
MinusEqual,
StarEqual,
SlashEqual,
PercentEqual,
AndEqual,
OrEqual,
XorEqual,
ShlEqual,
ShrEqual
)
{
// consume name token
let expr = self.parse_rvalue()?;
let assignment_operator = match self.peek_next()? {
Token::Assign => Some(AssignmentOperator::Assign),
Token::PlusEqual => Some(AssignmentOperator::AddAssign),
Token::MinusEqual => Some(AssignmentOperator::SubAssign),
Token::StarEqual => Some(AssignmentOperator::MulAssign),
Token::SlashEqual => Some(AssignmentOperator::DivAssign),
Token::PercentEqual => Some(AssignmentOperator::ModAssign),
Token::AndEqual => Some(AssignmentOperator::AndAssign),
Token::OrEqual => Some(AssignmentOperator::OrAssign),
Token::XorEqual => Some(AssignmentOperator::XorAssign),
Token::ShlEqual => Some(AssignmentOperator::LeftShiftAssign),
Token::ShrEqual => Some(AssignmentOperator::RightShiftAssign),
_ => None,
};
if let Some(operator) = assignment_operator {
self.next()?;
// pattern match to find operator
let operator = match operator {
Token::Assign => AssignmentOperator::Assign,
Token::PlusEqual => AssignmentOperator::AddAssign,
Token::MinusEqual => AssignmentOperator::SubAssign,
Token::StarEqual => AssignmentOperator::MulAssign,
Token::SlashEqual => AssignmentOperator::DivAssign,
Token::PercentEqual => AssignmentOperator::ModAssign,
Token::AndEqual => AssignmentOperator::AndAssign,
Token::OrEqual => AssignmentOperator::OrAssign,
Token::XorEqual => AssignmentOperator::XorAssign,
Token::ShlEqual => AssignmentOperator::LeftShiftAssign,
Token::ShrEqual => AssignmentOperator::RightShiftAssign,
_ => {
return ParseResult::Reject(CompilerError::UnexpectedToken(
self.peek_next()?.tt().to_string(),
));
}
};
// consume operator token
self.next()?;
let value = self.parse_expression()?;
let _ = expect_tt!(self.next()?, Semicolon);
let left = Self::rvalue_to_lvalue(expr)?;
let right = self.parse_rvalue()?;
let _ = expect_tt!(self.next()?, Semicolon)?;
return ParseResult::Accept(Statement::Assign {
varname: name.name,
left,
operator,
value,
right,
});
}
// parse an expression and a semicolon
let expr = self.parse_expression()?;
let _ = expect_tt!(self.next()?, Semicolon)?;
ParseResult::Accept(Statement::Expression { expr })
}
fn parse_expression(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_lvalue(&mut self) -> ParseResult<LValue, CompilerError> {
Self::rvalue_to_lvalue(self.parse_rvalue()?)
}
fn parse_rvalue(&mut self) -> ParseResult<RValue, CompilerError> {
self.parse_logical_or()
}
fn parse_logical_or(&mut self) -> ParseResult<Expression, CompilerError> {
fn rvalue_to_lvalue(expr: RValue) -> ParseResult<LValue, CompilerError> {
match expr {
RValue::Variable { name, .. } => ParseResult::Accept(LValue::Variable(name)),
RValue::MemberAccess {
expr, field_name, ..
} => {
let base = Self::rvalue_to_lvalue(*expr)?;
ParseResult::Accept(LValue::StructField(Box::new(base), field_name))
}
RValue::IndexAccess { expr, index, .. } => {
let base = Self::rvalue_to_lvalue(*expr)?;
ParseResult::Accept(LValue::ArrayIndex(Box::new(base), *index))
}
RValue::Unary {
op: UnaryOperator::Dereference,
operand,
..
} => {
let base = Self::rvalue_to_lvalue(*operand)?;
ParseResult::Accept(LValue::Pointer(Box::new(base)))
}
other => ParseResult::Reject(CompilerError::Generic(format!(
"not a valid assignment target: {:?}",
other
))),
}
}
fn parse_logical_or(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_logical_and()?;
let op = match self.peek_next()? {
@@ -419,7 +386,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_logical_or()?),
@@ -427,7 +394,7 @@ impl Parser {
})
}
fn parse_logical_and(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_logical_and(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_bitwise_or()?;
let op = match self.peek_next()? {
@@ -436,7 +403,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_logical_and()?),
@@ -444,7 +411,7 @@ impl Parser {
})
}
fn parse_bitwise_or(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_bitwise_or(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_bitwise_xor()?;
let op = match self.peek_next()? {
@@ -453,7 +420,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_bitwise_or()?),
@@ -461,7 +428,7 @@ impl Parser {
})
}
fn parse_bitwise_xor(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_bitwise_xor(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_bitwise_and()?;
let op = match self.peek_next()? {
@@ -470,7 +437,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_bitwise_xor()?),
@@ -478,7 +445,7 @@ impl Parser {
})
}
fn parse_bitwise_and(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_bitwise_and(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_comparison()?;
let op = match self.peek_next()? {
@@ -487,7 +454,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_bitwise_and()?),
@@ -495,7 +462,7 @@ impl Parser {
})
}
fn parse_comparison(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_comparison(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_shift()?;
let op = match self.peek_next()? {
@@ -509,7 +476,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_comparison()?),
@@ -517,7 +484,7 @@ impl Parser {
})
}
fn parse_shift(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_shift(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_additive()?;
let op = match self.peek_next()? {
@@ -527,7 +494,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_shift()?),
@@ -535,7 +502,7 @@ impl Parser {
})
}
fn parse_additive(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_additive(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_multiplicative()?;
let op = match self.peek_next()? {
@@ -545,7 +512,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_additive()?),
@@ -553,7 +520,7 @@ impl Parser {
})
}
fn parse_multiplicative(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_multiplicative(&mut self) -> ParseResult<RValue, CompilerError> {
let left = self.parse_unary()?;
let op = match self.peek_next()? {
@@ -563,7 +530,7 @@ impl Parser {
};
self.next()?;
ParseResult::Accept(Expression::Binary {
ParseResult::Accept(RValue::Binary {
op,
left: Box::new(left),
right: Box::new(self.parse_multiplicative()?),
@@ -571,7 +538,7 @@ impl Parser {
})
}
fn parse_unary(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_unary(&mut self) -> ParseResult<RValue, CompilerError> {
let op = match self.peek_next()? {
// prefix inc/dec
Token::PlusPlus => UnaryOperator::Increment,
@@ -598,21 +565,21 @@ impl Parser {
self.next()?;
let operand = Box::new(self.parse_unary()?);
ParseResult::Accept(Expression::Unary {
ParseResult::Accept(RValue::Unary {
op,
operand,
type_id: None,
})
}
fn parse_postfix(&mut self, mut expr: Expression) -> ParseResult<Expression, CompilerError> {
fn parse_postfix(&mut self, mut expr: RValue) -> ParseResult<RValue, CompilerError> {
loop {
match self.peek_next()? {
// Type cast: expr as Type
Token::As => {
self.next()?; // consume 'as'
let target_type = self.parse_type()?;
expr = Expression::TypeCast {
expr = RValue::TypeCast {
expr: Box::new(expr),
target_type,
type_id: None,
@@ -622,7 +589,7 @@ impl Parser {
// Postfix increment/decrement
Token::PlusPlus => {
self.next()?;
expr = Expression::UnaryPostfix {
expr = RValue::UnaryPostfix {
op: UnaryOperator::Increment,
operand: Box::new(expr),
type_id: None,
@@ -630,7 +597,7 @@ impl Parser {
}
Token::MinusMinus => {
self.next()?;
expr = Expression::UnaryPostfix {
expr = RValue::UnaryPostfix {
op: UnaryOperator::Decrement,
operand: Box::new(expr),
type_id: None,
@@ -640,11 +607,11 @@ impl Parser {
// Array indexing: expr[index]
Token::LeftBracket => {
self.next()?; // consume '['
let index = Box::new(self.parse_expression()?);
let index = Box::new(self.parse_rvalue()?);
let _ = expect_tt!(self.next()?, RightBracket)?;
expr = Expression::IndexAccess {
expr = RValue::IndexAccess {
expr: Box::new(expr),
index,
type_id: None,
@@ -658,7 +625,7 @@ impl Parser {
if !matches!(self.peek_next()?, Token::RightParen) {
loop {
args.push(self.parse_expression()?);
args.push(self.parse_rvalue()?);
if !matches!(self.peek_next()?, Token::Comma) {
break;
}
@@ -668,8 +635,8 @@ impl Parser {
let _ = expect_tt!(self.next()?, RightParen)?;
if let Expression::Variable { name, .. } = expr {
expr = Expression::Call {
if let RValue::Variable { name, .. } = expr {
expr = RValue::Call {
func: Call { name, args },
type_id: None,
};
@@ -680,7 +647,7 @@ impl Parser {
Token::Dot => {
self.next()?;
let field_name = expect_value!(self.next()?, Identifier)?;
expr = Expression::MemberAccess {
expr = RValue::MemberAccess {
expr: Box::new(expr),
field_name,
type_id: None,
@@ -695,23 +662,23 @@ impl Parser {
ParseResult::Accept(expr)
}
fn parse_primary(&mut self) -> ParseResult<Expression, CompilerError> {
fn parse_primary(&mut self) -> ParseResult<RValue, CompilerError> {
match self.peek_next()? {
Token::UnsignedInt(value, type_id) => {
self.next()?;
ParseResult::Accept(Expression::Number(Number::Unsigned(value, type_id)))
ParseResult::Accept(RValue::Number(Number::Unsigned(value, type_id)))
}
Token::SignedInt(value, type_id) => {
self.next()?;
ParseResult::Accept(Expression::Number(Number::Signed(value, type_id)))
ParseResult::Accept(RValue::Number(Number::Signed(value, type_id)))
}
Token::String(value) => {
self.next()?;
ParseResult::Accept(Expression::StringLiteral(value))
ParseResult::Accept(RValue::StringLiteral(value))
}
Token::Char(value) => {
self.next()?;
ParseResult::Accept(Expression::CharLiteral(value))
ParseResult::Accept(RValue::CharLiteral(value))
}
Token::Identifier(name) => {
@@ -726,7 +693,7 @@ impl Parser {
// });
// }
//
ParseResult::Accept(Expression::Variable {
ParseResult::Accept(RValue::Variable {
name,
expr_type: None,
})
@@ -762,7 +729,7 @@ impl Parser {
if !matches!(self.peek_next()?, Token::RightBracket) {
loop {
elements.push(self.parse_expression()?);
elements.push(self.parse_rvalue()?);
if !matches!(self.peek_next()?, Token::Comma) {
break;
}
@@ -771,14 +738,14 @@ impl Parser {
}
expect_tt!(self.next()?, RightBracket)?;
ParseResult::Accept(Expression::ArrayLiteral {
ParseResult::Accept(RValue::ArrayLiteral {
elements,
type_id: None,
})
}
Token::LeftParen => {
self.next()?;
let expr = self.parse_expression()?;
let expr = self.parse_rvalue()?;
let _ = expect_tt!(self.next()?, RightParen)?;
ParseResult::Accept(expr)
}
+57 -56
View File
@@ -175,34 +175,31 @@ pub enum Statement {
Block(Block),
Declaration {
var: Variable,
value: Option<Expression>,
mutable: bool,
value: Option<RValue>,
},
Assign {
varname: String,
left: LValue,
operator: AssignmentOperator,
value: Expression,
},
PtrWrite {
ptr: Expression,
value: Expression,
right: RValue,
},
Expression {
expr: Expression,
expr: RValue,
},
If {
condition: Expression,
condition: RValue,
then_stmt: Block,
else_stmt: Block,
},
While {
condition: Expression,
condition: RValue,
body: Vec<Statement>,
},
Loop(Block),
Defer(Call),
Break,
Continue,
Return(Option<Expression>),
Return(Option<RValue>),
}
#[derive(Debug, Clone)]
@@ -220,28 +217,36 @@ impl fmt::Display for ConstExpr {
}
}
#[derive(Debug, Clone)]
pub enum LValue {
Variable(Name),
ArrayIndex(Box<LValue>, RValue),
StructField(Box<LValue>, Name),
Pointer(Box<LValue>),
}
#[allow(unused)]
#[derive(Debug, Clone)]
pub enum Expression {
pub enum RValue {
Empty,
Binary {
op: BinaryOperator,
left: Box<Expression>,
right: Box<Expression>,
left: Box<RValue>,
right: Box<RValue>,
// Post-Semantic Analysis
type_id: Option<TypeId>,
},
Unary {
op: UnaryOperator,
operand: Box<Expression>,
operand: Box<RValue>,
// Post-Semantic Analysis
type_id: Option<TypeId>,
},
UnaryPostfix {
op: UnaryOperator,
operand: Box<Expression>,
operand: Box<RValue>,
// Post-Semantic Analysis
type_id: Option<TypeId>,
@@ -251,21 +256,21 @@ pub enum Expression {
expr_type: Option<TypeId>,
},
TypeCast {
expr: Box<Expression>,
expr: Box<RValue>,
target_type: TypeId,
// Post-Semantic Analysis
type_id: Option<TypeId>,
},
IndexAccess {
expr: Box<Expression>,
index: Box<Expression>,
expr: Box<RValue>,
index: Box<RValue>,
// Post-Semantic Analysis
type_id: Option<TypeId>,
},
MemberAccess {
expr: Box<Expression>,
expr: Box<RValue>,
field_name: Name,
// Post-Semantic Analysis
@@ -281,12 +286,12 @@ pub enum Expression {
StringLiteral(String),
CharLiteral(char),
ArrayLiteral {
elements: Vec<Expression>,
elements: Vec<RValue>,
type_id: Option<TypeId>,
},
StructLiteral {
name: Name,
fields: Vec<(Name, Expression)>,
fields: Vec<(Name, RValue)>,
type_id: Option<TypeId>,
},
}
@@ -300,56 +305,52 @@ pub enum Number {
#[derive(Debug, Clone)]
pub struct Call {
pub name: Name,
pub args: Vec<Expression>,
pub args: Vec<RValue>,
}
impl Expression {
impl RValue {
pub fn is_pure(&self) -> bool {
match self {
Expression::Number { .. } => true,
Expression::StringLiteral(_) => true,
Expression::CharLiteral(_) => true,
Expression::Call { .. } => false,
Expression::Binary { left, right, .. } => left.is_pure() && right.is_pure(),
Expression::Unary { operand, .. } => operand.is_pure(),
Expression::UnaryPostfix { operand, .. } => operand.is_pure(),
Expression::Empty => true,
Expression::Variable { .. } => true,
Expression::TypeCast { expr, .. } => expr.is_pure(),
Expression::IndexAccess { expr, index, .. } => expr.is_pure() && index.is_pure(),
Expression::MemberAccess { expr, .. } => expr.is_pure(),
Expression::ArrayLiteral { elements, .. } => {
RValue::Number { .. } => true,
RValue::StringLiteral(_) => true,
RValue::CharLiteral(_) => true,
RValue::Call { .. } => false,
RValue::Binary { left, right, .. } => left.is_pure() && right.is_pure(),
RValue::Unary { operand, .. } => operand.is_pure(),
RValue::UnaryPostfix { operand, .. } => operand.is_pure(),
RValue::Empty => true,
RValue::Variable { .. } => true,
RValue::TypeCast { expr, .. } => expr.is_pure(),
RValue::IndexAccess { expr, index, .. } => expr.is_pure() && index.is_pure(),
RValue::MemberAccess { expr, .. } => expr.is_pure(),
RValue::ArrayLiteral { elements, .. } => {
elements.iter().all(|element| element.is_pure())
}
Expression::StructLiteral { fields, .. } => {
fields.iter().all(|(_, expr)| expr.is_pure())
}
RValue::StructLiteral { fields, .. } => fields.iter().all(|(_, expr)| expr.is_pure()),
}
}
pub fn type_id(&self) -> Result<TypeId, CompilerError> {
match self {
Expression::Number(Number::Signed(_, type_id) | Number::Unsigned(_, type_id)) => {
RValue::Number(Number::Signed(_, type_id) | Number::Unsigned(_, type_id)) => {
type_id.clone().ok_or(CompilerError::UnknownType)
}
Expression::StringLiteral(_) => Ok(TypeId::Ptr(Box::new(TypeId::Char))),
Expression::CharLiteral(_) => Ok(TypeId::Char),
Expression::Call { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
Expression::Binary { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
Expression::Unary { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
Expression::UnaryPostfix { type_id, .. } => {
RValue::StringLiteral(_) => Ok(TypeId::Ptr(Box::new(TypeId::Char))),
RValue::CharLiteral(_) => Ok(TypeId::Char),
RValue::Call { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
RValue::Binary { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
RValue::Unary { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
RValue::UnaryPostfix { type_id, .. } => {
type_id.clone().ok_or(CompilerError::UnknownType)
}
Expression::Empty => Ok(TypeId::Void),
Expression::Variable { expr_type, .. } => {
RValue::Empty => Ok(TypeId::Void),
RValue::Variable { expr_type, .. } => {
expr_type.clone().ok_or(CompilerError::UnknownType)
}
Expression::TypeCast { type_id, .. } => {
type_id.clone().ok_or(CompilerError::UnknownType)
}
Expression::IndexAccess { expr, .. } => expr.type_id(),
Expression::MemberAccess { expr, .. } => expr.type_id(),
Expression::ArrayLiteral { elements, .. } => {
RValue::TypeCast { type_id, .. } => type_id.clone().ok_or(CompilerError::UnknownType),
RValue::IndexAccess { expr, .. } => expr.type_id(),
RValue::MemberAccess { expr, .. } => expr.type_id(),
RValue::ArrayLiteral { elements, .. } => {
let element_type = elements
.first()
.map_or(TypeId::Void, |e| e.type_id().unwrap_or(TypeId::Void));
@@ -358,7 +359,7 @@ impl Expression {
size: elements.len(),
})
}
Expression::StructLiteral { name, fields, .. } => {
RValue::StructLiteral { name, fields, .. } => {
let fields = fields
.iter()
.map(|(_, expr)| expr.type_id())
+34 -8
View File
@@ -5,6 +5,8 @@ use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Clone, Debug)]
pub enum Statement {
// this should always be optimised out.
NoOp,
Const(VirtualReg, Literal),
BinaryOp {
left: VirtualReg,
@@ -29,6 +31,7 @@ pub enum Statement {
address: VirtualReg,
result: VirtualReg,
},
// TODO: decide if these are actually needed. this is really just read+offset
GetStructField {
struct_addr: VirtualReg,
result: VirtualReg,
@@ -44,6 +47,7 @@ pub enum Statement {
func: FunctionName,
args: Vec<VirtualReg>,
},
Alloca(VirtualReg, usize), // usize = size in bytes of allocation
}
#[derive(Clone, Debug)]
@@ -113,12 +117,31 @@ impl fmt::Display for Label {
static LABEL_ID: AtomicUsize = AtomicUsize::new(0);
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct VirtualReg(pub isize);
// #[derive(Clone, Debug, PartialEq)]
// pub struct VirtualReg(pub isize, pub Option<Rc<String>>);
#[derive(Clone, Debug, PartialEq)]
pub enum VirtualReg {
Void,
Named(Rc<String>, isize),
Anonymous(isize),
}
impl VirtualReg {
pub fn void() -> Self {
Self(-1)
Self::Void
}
pub fn named(self, name: impl Into<Rc<String>>) -> Self {
match self {
Self::Void => todo!(
"we need to properly handle an error here. we should never be trying to name something assigned to void"
),
Self::Named(..) => {
todo!("v_reg's assigned to variables should never be reassigned. this is a bug!")
}
Self::Anonymous(val) => Self::Named(name.into(), val),
}
}
}
@@ -140,7 +163,6 @@ pub enum PrimitiveUnaryOperation {
Not,
}
#[derive(Clone, Debug)]
pub enum PrimitiveOperation {
Add,
@@ -164,10 +186,10 @@ pub enum PrimitiveOperation {
impl fmt::Display for VirtualReg {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.0 == -1 {
write!(f, "_")
} else {
write!(f, "v_{}", self.0)
match self {
Self::Void => write!(f, "_v"),
Self::Named(name, id) => write!(f, "v{id}_{name}"),
Self::Anonymous(val) => write!(f, "v{val}"),
}
}
}
@@ -219,7 +241,11 @@ impl fmt::Display for PrimitiveUnaryOperation {
impl fmt::Display for Statement {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Statement::NoOp => write!(f, "no-op"),
Statement::Const(dst, lit) => write!(f, "{} = literal {}", dst, lit),
Statement::Alloca(register, size) => {
write!(f, "Allocated {} ({} bytes)", register, size)
}
Statement::UnaryOp {
op,
operand,