Compare commits

...

7 commits

Author SHA1 Message Date
2d4bbaa174 Merge remote-tracking branch 'origin/main' 2025-12-16 12:13:18 +02:00
554db13c08 Fully implement needed for loop logic 2025-12-16 12:13:11 +02:00
12fee4b213 Correct For loop behavior and add a name to Trait
TODO: implement Trait and Use
2025-12-16 12:12:33 +02:00
21e37cd4f2 Add PreInc 2025-12-16 12:12:08 +02:00
bc1e2a2b21 Add PreInc 2025-12-16 12:11:51 +02:00
d45531ce44 Add PlusPlus 2025-12-16 12:11:31 +02:00
d247aa46eb Add PreInc 2025-12-16 12:11:19 +02:00
8 changed files with 231 additions and 75 deletions

View file

@ -273,6 +273,7 @@ pub enum UnOp {
Not, Not,
Ref, Ref,
Deref, Deref,
PreInc
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -122,6 +122,7 @@ pub enum CUnaryOp {
Not, Not,
Ref, Ref,
Deref, Deref,
PreInc
} }
impl CUnaryOp { impl CUnaryOp {
@ -131,6 +132,7 @@ impl CUnaryOp {
CUnaryOp::Not => "!", CUnaryOp::Not => "!",
CUnaryOp::Ref => "&", CUnaryOp::Ref => "&",
CUnaryOp::Deref => "*", CUnaryOp::Deref => "*",
CUnaryOp::PreInc => "++"
} }
} }
} }

View file

@ -18,7 +18,7 @@ impl DeclarationTranspiler {
let mut fields = Vec::new(); let mut fields = Vec::new();
for field in &struct_.fields { 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 { fields.push(CVarDecl {
name: field.name.clone(), name: field.name.clone(),
ty: field_type, ty: field_type,
@ -34,14 +34,14 @@ impl DeclarationTranspiler {
pub fn transpile_function(&self, func: &TypedFunction) -> Result<CFuncDecl, String> { pub fn transpile_function(&self, func: &TypedFunction) -> Result<CFuncDecl, String> {
let return_type = match &func.return_type { 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, None => CType::Void,
}; };
let mut params = Vec::new(); let mut params = Vec::new();
for (_binding_id, name, type_annot) in &func.args { for (_binding_id, name, type_annot) in &func.args {
let param_type = match type_annot { 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 => { None => {
return Err(format!( return Err(format!(
"Function parameter {} missing type annotation", "Function parameter {} missing type annotation",
@ -69,14 +69,14 @@ impl DeclarationTranspiler {
let mut structs = Vec::new(); let mut structs = Vec::new();
// For each variant, create a struct // 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 struct_name = format!("{}_{}", enum_.name, variant.name);
let mut fields = Vec::new(); let mut fields = Vec::new();
// Add variant fields (no discriminant in variant struct) // Add variant fields (no discriminant in variant struct)
for (j, field_type) in variant.fields.iter().enumerate() { for (j, field_type) in variant.fields.iter().enumerate() {
let field_name = format!("field_{}", j); 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 { fields.push(CVarDecl {
name: field_name, name: field_name,
ty: c_type, ty: c_type,
@ -131,38 +131,26 @@ impl DeclarationTranspiler {
Ok(structs) 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 { match annot {
Some(TypeAnnot::Var(name)) => match name.as_str() { Some(TypeAnnot::Var(name)) => convert_to_c_type(name),
"int" => Ok(CType::Int), Some(TypeAnnot::Cons(name, args)) if args.is_empty() => convert_to_c_type(name),
"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::Cons(name, _args)) => { Some(TypeAnnot::Cons(name, _args)) => {
// Generic types - for now just use the base name // Generic types - for now just use the base name
Ok(CType::Struct(name.clone())) Ok(CType::Struct(name.clone()))
} }
Some(TypeAnnot::Ptr(inner)) => { 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))) Ok(CType::Ptr(Box::new(inner_type)))
} }
Some(TypeAnnot::Array(inner)) => { 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))) Ok(CType::Ptr(Box::new(inner_type)))
} }
Some(TypeAnnot::Tuple(fields)) => { Some(TypeAnnot::Tuple(fields)) => {
let mut c_fields = Vec::new(); let mut c_fields = Vec::new();
for (i, field_annot) in fields.iter().enumerate() { 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 { c_fields.push(CVarDecl {
name: format!("field{}", i), name: format!("field{}", i),
ty: field_type, ty: field_type,
@ -174,12 +162,22 @@ impl DeclarationTranspiler {
Some(TypeAnnot::Function(args, ret)) => { Some(TypeAnnot::Function(args, ret)) => {
let mut c_args = Vec::new(); let mut c_args = Vec::new();
for arg in args { 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::Func(c_args, Box::new(c_ret)))
} }
_ => Ok(CType::Void), // Default _ => 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::ast::*;
use crate::c_ir::*; use crate::c_ir::*;
use crate::c_lowerer::declaration_transpiler::convert_to_c_type;
use crate::typechecker::Type; use crate::typechecker::Type;
pub struct StatementsTranspiler; pub struct StatementsTranspiler {
tmp_counter: usize,
}
impl StatementsTranspiler { impl StatementsTranspiler {
pub fn new() -> Self { 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> { 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 { match &expr.kind {
TypedExprKind::Let(_binding_id, name, _kind, _type_annot, init_expr) => { TypedExprKind::Let(_binding_id, name, _kind, _type_annot, init_expr) => {
let c_type = self.type_to_ctype(&expr.ty)?; let c_type = self.type_to_ctype(&expr.ty)?;
@ -157,36 +193,141 @@ impl StatementsTranspiler {
Ok(CStmt::Block(stmts)) Ok(CStmt::Block(stmts))
} }
TypedExprKind::For(_binding_id, var_name, iterable, body) => { TypedExprKind::For(_binding_id, var_name, iterable, body) => {
// Simplified for loop handling
// For now, assume range iteration
match &iterable.kind { match &iterable.kind {
// for i in start..end
TypedExprKind::Range(start, end) => { TypedExprKind::Range(start, end) => {
let start_expr = self.transpile_expr(start)?; let start_expr = self.transpile_expr(start)?;
let end_expr = self.transpile_expr(end)?; let end_expr = self.transpile_expr(end)?;
// Create a simple for loop: for(int i = start; i < end; i++)
let init = CVarDecl { let init = CVarDecl {
name: var_name.clone(), name: var_name.clone(),
ty: CType::Int, ty: CType::Int,
initializer: Some(start_expr), initializer: Some(start_expr),
}; };
let cond = CExpr::BinOp( let cond = CExpr::BinOp(
Box::new(CExpr::Var(var_name.clone())), Box::new(CExpr::Var(var_name.clone())),
CBinaryOp::Lt, CBinaryOp::Lt,
Box::new(end_expr), Box::new(end_expr),
); );
let incr = CExpr::UnOp(CUnaryOp::Neg, Box::new(CExpr::IntLit(-1))); // i++
let incr_stmt = CStmt::Assign( let incr = CExpr::UnOp(
CExpr::Var(var_name.clone()), CUnaryOp::PreInc,
CExpr::BinOp( Box::new(CExpr::Var(var_name.clone())),
Box::new(CExpr::Var(var_name.clone())),
CBinaryOp::Add,
Box::new(CExpr::IntLit(1)),
),
); );
let body_stmts = self.expr_to_stmts(body)?; 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), 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 { match &expr.kind {
TypedExprKind::Do(stmts) => { TypedExprKind::Do(stmts) => {
let mut c_stmts = Vec::new(); let mut c_stmts = Vec::new();
@ -250,25 +391,26 @@ impl StatementsTranspiler {
UnOp::Not => Ok(CUnaryOp::Not), UnOp::Not => Ok(CUnaryOp::Not),
UnOp::Ref => Ok(CUnaryOp::Ref), UnOp::Ref => Ok(CUnaryOp::Ref),
UnOp::Deref => Ok(CUnaryOp::Deref), 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 { match ty {
crate::typechecker::Type::Int => Ok(CType::Int), Type::Int => Ok(CType::Int),
crate::typechecker::Type::Float => Ok(CType::Float), Type::Float => Ok(CType::Float),
crate::typechecker::Type::Bool => Ok(CType::Bool), Type::Bool => Ok(CType::Bool),
crate::typechecker::Type::String => Ok(CType::Ptr(Box::new(CType::Char))), Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
crate::typechecker::Type::Unit => Ok(CType::Void), Type::Unit => Ok(CType::Void),
crate::typechecker::Type::Ptr(inner) => { Type::Ptr(inner) => {
Ok(CType::Ptr(Box::new(self.type_to_ctype(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)?))) Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?)))
} }
crate::typechecker::Type::Struct(name, _) => Ok(CType::Struct(name.clone())), Type::Struct(name, _) => Ok(CType::Struct(name.clone())),
crate::typechecker::Type::Enum(name, _) => Ok(CType::Struct(name.clone())), Type::Enum(name, _) => Ok(CType::Struct(name.clone())),
crate::typechecker::Type::Tuple(types) => { Type::Tuple(types) => {
let mut fields = Vec::new(); let mut fields = Vec::new();
for (i, inner_ty) in types.iter().enumerate() { for (i, inner_ty) in types.iter().enumerate() {
let c_type = self.type_to_ctype(inner_ty)?; let c_type = self.type_to_ctype(inner_ty)?;
@ -280,7 +422,7 @@ impl StatementsTranspiler {
} }
Ok(CType::UnnamedStruct(fields)) Ok(CType::UnnamedStruct(fields))
} }
crate::typechecker::Type::Function(args, ret) => { Type::Function(args, ret) => {
let mut c_args = Vec::new(); let mut c_args = Vec::new();
for arg in args { for arg in args {
c_args.push(self.type_to_ctype(arg)?); c_args.push(self.type_to_ctype(arg)?);
@ -288,37 +430,25 @@ impl StatementsTranspiler {
let c_ret = self.type_to_ctype(ret)?; let c_ret = self.type_to_ctype(ret)?;
Ok(CType::Func(c_args, Box::new(c_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, // Generic types should have been monomorphized away,
// but if they remain, treat them as struct types // but if they remain, treat them as struct types
// For now, just use the base name // For now, just use the base name
Ok(CType::Struct(name.clone())) Ok(CType::Struct(name.clone()))
} }
crate::typechecker::Type::TypeVar(name) => { Type::TypeVar(name) => {
// Type variables should have been resolved during monomorphization // Type variables should have been resolved during monomorphization
Err(format!("Unresolved type variable: {}", name)) Err(format!("Unresolved type variable: {}", name))
} }
crate::typechecker::Type::Never => Ok(CType::Void), Type::Never => Ok(CType::Void),
crate::typechecker::Type::Unknown => Err("Unknown type".to_string()), Type::Unknown => Err("Unknown type".to_string()),
} }
} }
fn type_annot_to_ctype(&self, annot: &TypeAnnot) -> Result<CType, String> { fn type_annot_to_ctype(&self, annot: &TypeAnnot) -> Result<CType, String> {
match annot { match annot {
TypeAnnot::Var(name) => match name.as_str() { TypeAnnot::Var(name) => convert_to_c_type(name),
"int" => Ok(CType::Int), TypeAnnot::Cons(name, args) if args.is_empty() => convert_to_c_type(name),
"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::Cons(name, _args) => { TypeAnnot::Cons(name, _args) => {
// Generic types - for now just use the base name // Generic types - for now just use the base name
Ok(CType::Struct(name.clone())) Ok(CType::Struct(name.clone()))
@ -351,7 +481,7 @@ impl StatementsTranspiler {
let c_ret = self.type_annot_to_ctype(ret)?; let c_ret = self.type_annot_to_ctype(ret)?;
Ok(CType::Func(c_args, Box::new(c_ret))) Ok(CType::Func(c_args, Box::new(c_ret)))
} }
_ => Err(format!("Unsupported type annotation: {:?}", annot)), //_ => Err(format!("Unsupported type annotation: {:?}", annot)),
} }
} }
} }

View file

@ -99,7 +99,7 @@ impl Transpiler {
// But for now, skip as they're handled differently // But for now, skip as they're handled differently
} }
TypedASTNodeKind::Load(_) => {} TypedASTNodeKind::Load(_) => {}
TypedASTNodeKind::Trait(_) => {} TypedASTNodeKind::Trait(typed_trait ) => {}
TypedASTNodeKind::Use(_) => {} TypedASTNodeKind::Use(_) => {}
} }
Ok(()) Ok(())
@ -227,7 +227,7 @@ impl Transpiler {
} }
CStmt::For(init, cond, incr, body) => { CStmt::For(init, cond, incr, body) => {
let mut output = format!("for ({}, {}, {}) {{", self.generate_var_decl(init), self.generate_expr(cond), self.generate_expr(incr)); let mut output = format!("for ({}; {}; {}) {{", self.generate_var_decl(init), self.generate_expr(cond), self.generate_expr(incr));
for stmt in body { for stmt in body {
output.push_str(&format!(" {}", self.generate_stmt(stmt))); output.push_str(&format!(" {}", self.generate_stmt(stmt)));
} }

View file

@ -288,4 +288,7 @@ pub enum Token {
#[token("%=")] #[token("%=")]
ModAssign, ModAssign,
#[token("++")]
PlusPlus,
} }

View file

@ -1273,6 +1273,16 @@ impl Parser {
attributes: Vec::new(), attributes: Vec::new(),
}) })
} }
Some(Token::PlusPlus) => {
self.next();
let expr = self.parse_unary_expr()?;
let end = expr.span.end;
Ok(Expr {
kind: ExprKind::UnOp(UnOp::PreInc, Box::new(expr)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
})
}
_ => self.parse_postfix_expr(), _ => self.parse_postfix_expr(),
} }
} }

View file

@ -832,6 +832,18 @@ impl TypeChecker {
} }
} }
} }
UnOp::PreInc => {
if !matches!(typed_inner.ty, Type::Int | Type::Float) {
return Err(TypeError {
kind: TypeErrorKind::TypeMismatch(
Type::Int,
typed_inner.ty.clone(),
),
span: inner.span.clone(),
});
}
typed_inner.ty.clone()
}
}; };
( (
TypedExprKind::UnOp(op.clone(), Box::new(typed_inner)), TypedExprKind::UnOp(op.clone(), Box::new(typed_inner)),