Fully implement needed for loop logic

This commit is contained in:
flameyosflow 2025-12-16 12:13:11 +02:00
commit 554db13c08
2 changed files with 201 additions and 73 deletions

View file

@ -18,7 +18,7 @@ impl DeclarationTranspiler {
let mut fields = Vec::new();
for field in &struct_.fields {
let field_type = self.type_annot_to_ctype(&Some(field.field_type.clone()))?;
let field_type = self.type_annot_to_c_type(&Some(field.field_type.clone()))?;
fields.push(CVarDecl {
name: field.name.clone(),
ty: field_type,
@ -34,14 +34,14 @@ impl DeclarationTranspiler {
pub fn transpile_function(&self, func: &TypedFunction) -> Result<CFuncDecl, String> {
let return_type = match &func.return_type {
Some(type_annot) => self.type_annot_to_ctype(&Some(type_annot.clone()))?,
Some(type_annot) => self.type_annot_to_c_type(&Some(type_annot.clone()))?,
None => CType::Void,
};
let mut params = Vec::new();
for (_binding_id, name, type_annot) in &func.args {
let param_type = match type_annot {
Some(annot) => self.type_annot_to_ctype(&Some(annot.clone()))?,
Some(annot) => self.type_annot_to_c_type(&Some(annot.clone()))?,
None => {
return Err(format!(
"Function parameter {} missing type annotation",
@ -69,14 +69,14 @@ impl DeclarationTranspiler {
let mut structs = Vec::new();
// For each variant, create a struct
for (i, variant) in enum_.variants.iter().enumerate() {
for variant in enum_.variants.iter() {
let struct_name = format!("{}_{}", enum_.name, variant.name);
let mut fields = Vec::new();
// Add variant fields (no discriminant in variant struct)
for (j, field_type) in variant.fields.iter().enumerate() {
let field_name = format!("field_{}", j);
let c_type = self.type_annot_to_ctype(&Some(field_type.clone()))?;
let c_type = self.type_annot_to_c_type(&Some(field_type.clone()))?;
fields.push(CVarDecl {
name: field_name,
ty: c_type,
@ -131,38 +131,26 @@ impl DeclarationTranspiler {
Ok(structs)
}
fn type_annot_to_ctype(&self, annot: &Option<TypeAnnot>) -> Result<CType, String> {
fn type_annot_to_c_type(&self, annot: &Option<TypeAnnot>) -> Result<CType, String> {
match annot {
Some(TypeAnnot::Var(name)) => match name.as_str() {
"int" => Ok(CType::Int),
"float" => Ok(CType::Float),
"bool" => Ok(CType::Bool),
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
_ => Ok(CType::Struct(name.clone())), // Assume struct
},
Some(TypeAnnot::Cons(name, args)) if args.is_empty() => match name.as_str() {
"int" => Ok(CType::Int),
"float" => Ok(CType::Float),
"bool" => Ok(CType::Bool),
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
_ => Ok(CType::Struct(name.clone())), // Assume struct
},
Some(TypeAnnot::Var(name)) => convert_to_c_type(name),
Some(TypeAnnot::Cons(name, args)) if args.is_empty() => convert_to_c_type(name),
Some(TypeAnnot::Cons(name, _args)) => {
// Generic types - for now just use the base name
Ok(CType::Struct(name.clone()))
}
Some(TypeAnnot::Ptr(inner)) => {
let inner_type = self.type_annot_to_ctype(&Some(*inner.clone()))?;
let inner_type = self.type_annot_to_c_type(&Some(*inner.clone()))?;
Ok(CType::Ptr(Box::new(inner_type)))
}
Some(TypeAnnot::Array(inner)) => {
let inner_type = self.type_annot_to_ctype(&Some(*inner.clone()))?;
let inner_type = self.type_annot_to_c_type(&Some(*inner.clone()))?;
Ok(CType::Ptr(Box::new(inner_type)))
}
Some(TypeAnnot::Tuple(fields)) => {
let mut c_fields = Vec::new();
for (i, field_annot) in fields.iter().enumerate() {
let field_type = self.type_annot_to_ctype(&Some(field_annot.clone()))?;
let field_type = self.type_annot_to_c_type(&Some(field_annot.clone()))?;
c_fields.push(CVarDecl {
name: format!("field{}", i),
ty: field_type,
@ -174,12 +162,22 @@ impl DeclarationTranspiler {
Some(TypeAnnot::Function(args, ret)) => {
let mut c_args = Vec::new();
for arg in args {
c_args.push(self.type_annot_to_ctype(&Some(arg.clone()))?);
c_args.push(self.type_annot_to_c_type(&Some(arg.clone()))?);
}
let c_ret = self.type_annot_to_ctype(&Some(*ret.clone()))?;
let c_ret = self.type_annot_to_c_type(&Some(*ret.clone()))?;
Ok(CType::Func(c_args, Box::new(c_ret)))
}
_ => Ok(CType::Void), // Default
}
}
}
pub fn convert_to_c_type(name: &String) -> Result<CType, String> {
match String::as_str(name) {
"int" => Ok(CType::Int),
"float" => Ok(CType::Float),
"bool" => Ok(CType::Bool),
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
_ => Ok(CType::Struct(name.clone())), // Assume struct
}
}

View file

@ -1,12 +1,48 @@
use crate::ast::*;
use crate::c_ir::*;
use crate::c_lowerer::declaration_transpiler::convert_to_c_type;
use crate::typechecker::Type;
pub struct StatementsTranspiler;
pub struct StatementsTranspiler {
tmp_counter: usize,
}
impl StatementsTranspiler {
pub fn new() -> Self {
StatementsTranspiler
Self { tmp_counter: 0 }
}
fn fresh_tmp_name(&mut self, prefix: &str) -> String {
let name = format!("{}_{}", prefix, self.tmp_counter);
self.tmp_counter += 1;
name
}
pub fn fresh_tmp_var(
&mut self,
prefix: &str,
ty: CType,
initializer: Option<CExpr>,
) -> (String, CVarDecl) {
let name = self.fresh_tmp_name(prefix);
let decl = CVarDecl {
name: name.clone(),
ty,
initializer,
};
(name, decl)
}
pub fn fresh_tmp_expr(
&mut self,
prefix: &str,
ty: CType,
initializer: Option<CExpr>,
) -> (CExpr, CVarDecl) {
let (name, decl) = self.fresh_tmp_var(prefix, ty, initializer);
(CExpr::Var(name), decl)
}
pub fn transpile_expr(&self, expr: &TypedExpr) -> Result<CExpr, String> {
@ -111,7 +147,7 @@ impl StatementsTranspiler {
}
}
pub fn transpile_stmt(&self, expr: &TypedExpr) -> Result<CStmt, String> {
pub fn transpile_stmt(&mut self, expr: &TypedExpr) -> Result<CStmt, String> {
match &expr.kind {
TypedExprKind::Let(_binding_id, name, _kind, _type_annot, init_expr) => {
let c_type = self.type_to_ctype(&expr.ty)?;
@ -157,36 +193,141 @@ impl StatementsTranspiler {
Ok(CStmt::Block(stmts))
}
TypedExprKind::For(_binding_id, var_name, iterable, body) => {
// Simplified for loop handling
// For now, assume range iteration
match &iterable.kind {
// for i in start..end
TypedExprKind::Range(start, end) => {
let start_expr = self.transpile_expr(start)?;
let end_expr = self.transpile_expr(end)?;
// Create a simple for loop: for(int i = start; i < end; i++)
let init = CVarDecl {
name: var_name.clone(),
ty: CType::Int,
initializer: Some(start_expr),
};
let cond = CExpr::BinOp(
Box::new(CExpr::Var(var_name.clone())),
CBinaryOp::Lt,
Box::new(end_expr),
);
let incr = CExpr::UnOp(CUnaryOp::Neg, Box::new(CExpr::IntLit(-1))); // i++
let incr_stmt = CStmt::Assign(
CExpr::Var(var_name.clone()),
CExpr::BinOp(
Box::new(CExpr::Var(var_name.clone())),
CBinaryOp::Add,
Box::new(CExpr::IntLit(1)),
),
let incr = CExpr::UnOp(
CUnaryOp::PreInc,
Box::new(CExpr::Var(var_name.clone())),
);
let body_stmts = self.expr_to_stmts(body)?;
Ok(CStmt::For(init, cond, CExpr::IntLit(1), body_stmts))
Ok(CStmt::For(init, cond, incr, body_stmts))
}
_ => Err("Only range iteration supported for for loops".to_string()),
// for x in array_var
TypedExprKind::Variable(var) => {
let elem_ty = match &iterable.ty {
Type::Array(inner) => self.type_to_ctype(inner)?,
_ => return Err(format!(
"Cannot iterate over non-array variable `{}`",
var
)),
};
// i = 0
let (idx_name, idx_decl) = self.fresh_tmp_var(
"_i",
CType::Int,
Some(CExpr::IntLit(0)),
);
let cond = CExpr::BinOp(
Box::new(CExpr::Var(idx_name.clone())),
CBinaryOp::Lt,
Box::new(CExpr::Dot(
Box::new(CExpr::Var(var.clone())),
"len".into(),
)),
);
let incr = CExpr::UnOp(
CUnaryOp::PreInc,
Box::new(CExpr::Var(idx_name.clone())),
);
// let x = array.data[i]
let bind = CStmt::VarDecl(CVarDecl {
name: var_name.clone(),
ty: elem_ty,
initializer: Some(CExpr::Index(
Box::new(CExpr::Dot(
Box::new(CExpr::Var(var.clone())),
"data".into(),
)),
Box::new(CExpr::Var(idx_name.clone())),
)),
});
let mut body_stmts = vec![bind];
body_stmts.extend(self.expr_to_stmts(body)?);
Ok(CStmt::For(idx_decl, cond, incr, body_stmts))
}
// for x in [a, b, c]
TypedExprKind::Array(array) => {
let elem_ty = match &iterable.ty {
Type::Array(inner) => self.type_to_ctype(inner)?,
_ => return Err("For-loop iterable is not an array".to_string()),
};
let c_elems = array
.iter()
.map(|e| self.transpile_expr(e))
.collect::<Result<Vec<_>, _>>()?;
let arr_len = c_elems.len();
// tmp_arr = { ... }
let (arr_name, arr_decl) = self.fresh_tmp_var(
"_arr",
CType::Array(Box::new(elem_ty.clone()), arr_len),
Some(CExpr::ArrayLit(c_elems)),
);
// i = 0
let (idx_name, idx_decl) = self.fresh_tmp_var(
"_i",
CType::Int,
Some(CExpr::IntLit(0)),
);
let cond = CExpr::BinOp(
Box::new(CExpr::Var(idx_name.clone())),
CBinaryOp::Lt,
Box::new(CExpr::IntLit(arr_len as i64)),
);
let incr = CExpr::UnOp(
CUnaryOp::PreInc,
Box::new(CExpr::Var(idx_name.clone())),
);
let bind = CStmt::VarDecl(CVarDecl {
name: var_name.clone(),
ty: elem_ty,
initializer: Some(CExpr::Index(
Box::new(CExpr::Var(arr_name.clone())),
Box::new(CExpr::Var(idx_name.clone())),
)),
});
let mut body_stmts = vec![bind];
body_stmts.extend(self.expr_to_stmts(body)?);
Ok(CStmt::Block(vec![
CStmt::VarDecl(arr_decl),
CStmt::For(idx_decl, cond, incr, body_stmts),
]))
}
_ => Err("Unsupported iterable in for loop".to_string()),
}
}
TypedExprKind::Break => Ok(CStmt::Break),
@ -199,7 +340,7 @@ impl StatementsTranspiler {
}
}
pub fn expr_to_stmts(&self, expr: &TypedExpr) -> Result<Vec<CStmt>, String> {
pub fn expr_to_stmts(&mut self, expr: &TypedExpr) -> Result<Vec<CStmt>, String> {
match &expr.kind {
TypedExprKind::Do(stmts) => {
let mut c_stmts = Vec::new();
@ -250,25 +391,26 @@ impl StatementsTranspiler {
UnOp::Not => Ok(CUnaryOp::Not),
UnOp::Ref => Ok(CUnaryOp::Ref),
UnOp::Deref => Ok(CUnaryOp::Deref),
UnOp::PreInc => Ok(CUnaryOp::PreInc),
}
}
fn type_to_ctype(&self, ty: &crate::typechecker::Type) -> Result<CType, String> {
fn type_to_ctype(&self, ty: &Type) -> Result<CType, String> {
match ty {
crate::typechecker::Type::Int => Ok(CType::Int),
crate::typechecker::Type::Float => Ok(CType::Float),
crate::typechecker::Type::Bool => Ok(CType::Bool),
crate::typechecker::Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
crate::typechecker::Type::Unit => Ok(CType::Void),
crate::typechecker::Type::Ptr(inner) => {
Type::Int => Ok(CType::Int),
Type::Float => Ok(CType::Float),
Type::Bool => Ok(CType::Bool),
Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
Type::Unit => Ok(CType::Void),
Type::Ptr(inner) => {
Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?)))
}
crate::typechecker::Type::Array(inner) => {
Type::Array(inner) => {
Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?)))
}
crate::typechecker::Type::Struct(name, _) => Ok(CType::Struct(name.clone())),
crate::typechecker::Type::Enum(name, _) => Ok(CType::Struct(name.clone())),
crate::typechecker::Type::Tuple(types) => {
Type::Struct(name, _) => Ok(CType::Struct(name.clone())),
Type::Enum(name, _) => Ok(CType::Struct(name.clone())),
Type::Tuple(types) => {
let mut fields = Vec::new();
for (i, inner_ty) in types.iter().enumerate() {
let c_type = self.type_to_ctype(inner_ty)?;
@ -280,7 +422,7 @@ impl StatementsTranspiler {
}
Ok(CType::UnnamedStruct(fields))
}
crate::typechecker::Type::Function(args, ret) => {
Type::Function(args, ret) => {
let mut c_args = Vec::new();
for arg in args {
c_args.push(self.type_to_ctype(arg)?);
@ -288,37 +430,25 @@ impl StatementsTranspiler {
let c_ret = self.type_to_ctype(ret)?;
Ok(CType::Func(c_args, Box::new(c_ret)))
}
crate::typechecker::Type::Generic(name, _args) => {
Type::Generic(name, _args) => {
// Generic types should have been monomorphized away,
// but if they remain, treat them as struct types
// For now, just use the base name
Ok(CType::Struct(name.clone()))
}
crate::typechecker::Type::TypeVar(name) => {
Type::TypeVar(name) => {
// Type variables should have been resolved during monomorphization
Err(format!("Unresolved type variable: {}", name))
}
crate::typechecker::Type::Never => Ok(CType::Void),
crate::typechecker::Type::Unknown => Err("Unknown type".to_string()),
Type::Never => Ok(CType::Void),
Type::Unknown => Err("Unknown type".to_string()),
}
}
fn type_annot_to_ctype(&self, annot: &TypeAnnot) -> Result<CType, String> {
match annot {
TypeAnnot::Var(name) => match name.as_str() {
"int" => Ok(CType::Int),
"float" => Ok(CType::Float),
"bool" => Ok(CType::Bool),
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
_ => Ok(CType::Struct(name.clone())),
},
TypeAnnot::Cons(name, args) if args.is_empty() => match name.as_str() {
"int" => Ok(CType::Int),
"float" => Ok(CType::Float),
"bool" => Ok(CType::Bool),
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
_ => Ok(CType::Struct(name.clone())),
},
TypeAnnot::Var(name) => convert_to_c_type(name),
TypeAnnot::Cons(name, args) if args.is_empty() => convert_to_c_type(name),
TypeAnnot::Cons(name, _args) => {
// Generic types - for now just use the base name
Ok(CType::Struct(name.clone()))
@ -351,7 +481,7 @@ impl StatementsTranspiler {
let c_ret = self.type_annot_to_ctype(ret)?;
Ok(CType::Func(c_args, Box::new(c_ret)))
}
_ => Err(format!("Unsupported type annotation: {:?}", annot)),
//_ => Err(format!("Unsupported type annotation: {:?}", annot)),
}
}
}