diff --git a/src/ast.rs b/src/ast.rs index e2ecb67..518c18d 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -240,6 +240,7 @@ pub enum ExprKind { Return(Option>), Break, Continue, + Defer(Box), } #[derive(Debug, Clone, PartialEq)] @@ -273,7 +274,7 @@ pub enum UnOp { Not, Ref, Deref, - PreInc + PreInc, } #[derive(Debug, Clone)] @@ -429,6 +430,7 @@ pub enum TypedExprKind { Return(Option>), Break, Continue, + Defer(Box), } #[derive(Debug, Clone)] diff --git a/src/c_ir.rs b/src/c_ir.rs index a132d42..87ac418 100644 --- a/src/c_ir.rs +++ b/src/c_ir.rs @@ -122,7 +122,7 @@ pub enum CUnaryOp { Not, Ref, Deref, - PreInc + PreInc, } impl CUnaryOp { @@ -132,7 +132,7 @@ impl CUnaryOp { CUnaryOp::Not => "!", CUnaryOp::Ref => "&", CUnaryOp::Deref => "*", - CUnaryOp::PreInc => "++" + CUnaryOp::PreInc => "++", } } } diff --git a/src/c_lowerer/mod.rs b/src/c_lowerer/mod.rs index 72605cf..a6f32a4 100644 --- a/src/c_lowerer/mod.rs +++ b/src/c_lowerer/mod.rs @@ -1,2 +1,2 @@ pub mod declaration_transpiler; -pub mod statements_transpiler; \ No newline at end of file +pub mod statements_transpiler; diff --git a/src/c_lowerer/statements_transpiler.rs b/src/c_lowerer/statements_transpiler.rs index bb1e1dd..e277af3 100644 --- a/src/c_lowerer/statements_transpiler.rs +++ b/src/c_lowerer/statements_transpiler.rs @@ -187,8 +187,20 @@ impl StatementsTranspiler { } TypedExprKind::Do(exprs) => { let mut stmts = Vec::new(); + let mut defers = Vec::new(); for expr in exprs { - stmts.push(self.transpile_stmt(expr)?); + match &expr.kind { + TypedExprKind::Defer(defer_expr) => { + defers.push(self.transpile_stmt(defer_expr)?); + } + _ => { + stmts.push(self.transpile_stmt(expr)?); + } + } + } + // Execute defers in reverse order at the end + for defer_stmt in defers.into_iter().rev() { + stmts.push(defer_stmt); } Ok(CStmt::Block(stmts)) } @@ -211,10 +223,8 @@ impl StatementsTranspiler { Box::new(end_expr), ); - let incr = CExpr::UnOp( - CUnaryOp::PreInc, - Box::new(CExpr::Var(var_name.clone())), - ); + 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, incr, body_stmts)) @@ -224,32 +234,26 @@ impl StatementsTranspiler { 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 - )), + _ => { + 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 (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(), - )), + 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 incr = + CExpr::UnOp(CUnaryOp::PreInc, Box::new(CExpr::Var(idx_name.clone()))); // let x = array.data[i] let bind = CStmt::VarDecl(CVarDecl { @@ -292,11 +296,8 @@ impl StatementsTranspiler { ); // i = 0 - let (idx_name, idx_decl) = self.fresh_tmp_var( - "_i", - CType::Int, - Some(CExpr::IntLit(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())), @@ -304,10 +305,8 @@ impl StatementsTranspiler { Box::new(CExpr::IntLit(arr_len as i64)), ); - let incr = CExpr::UnOp( - CUnaryOp::PreInc, - Box::new(CExpr::Var(idx_name.clone())), - ); + let incr = + CExpr::UnOp(CUnaryOp::PreInc, Box::new(CExpr::Var(idx_name.clone()))); let bind = CStmt::VarDecl(CVarDecl { name: var_name.clone(), @@ -332,6 +331,7 @@ impl StatementsTranspiler { } TypedExprKind::Break => Ok(CStmt::Break), TypedExprKind::Continue => Ok(CStmt::Continue), + TypedExprKind::Defer(_) => Err("Defer should be handled in Do blocks".to_string()), _ => { // For other expressions, treat as expression statements let c_expr = self.transpile_expr(expr)?; @@ -344,21 +344,36 @@ impl StatementsTranspiler { match &expr.kind { TypedExprKind::Do(stmts) => { let mut c_stmts = Vec::new(); + let mut defers = Vec::new(); + let mut last_stmt = None; for (i, stmt) in stmts.iter().enumerate() { - if i == stmts.len() - 1 { - // Last expression in a block should be returned - match &stmt.kind { - TypedExprKind::Return(_) => { + match &stmt.kind { + TypedExprKind::Defer(defer_expr) => { + defers.push(self.transpile_stmt(defer_expr)?); + } + _ => { + if i == stmts.len() - 1 { + last_stmt = Some(stmt); + } else { c_stmts.push(self.transpile_stmt(stmt)?); } - _ => { - // Convert to return statement - let c_expr = self.transpile_expr(stmt)?; - c_stmts.push(CStmt::Return(Some(c_expr))); - } } - } else { - c_stmts.push(self.transpile_stmt(stmt)?); + } + } + // Execute defers in reverse order before the last statement + for defer_stmt in defers.into_iter().rev() { + c_stmts.push(defer_stmt); + } + if let Some(last) = last_stmt { + match &last.kind { + TypedExprKind::Return(_) => { + c_stmts.push(self.transpile_stmt(last)?); + } + _ => { + // Convert to return statement + let c_expr = self.transpile_expr(last)?; + c_stmts.push(CStmt::Return(Some(c_expr))); + } } } Ok(c_stmts) @@ -402,12 +417,8 @@ impl StatementsTranspiler { 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)?))) - } - Type::Array(inner) => { - Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))) - } + Type::Ptr(inner) => Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))), + Type::Array(inner) => Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))), Type::Struct(name, _) => Ok(CType::Struct(name.clone())), Type::Enum(name, _) => Ok(CType::Struct(name.clone())), Type::Tuple(types) => { @@ -480,8 +491,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)), } } } diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index ed9dfaf..fdebb90 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1 +1 @@ -pub mod transpiler; \ No newline at end of file +pub mod transpiler; diff --git a/src/codegen/transpiler.rs b/src/codegen/transpiler.rs index c13424e..dbb7855 100644 --- a/src/codegen/transpiler.rs +++ b/src/codegen/transpiler.rs @@ -1,8 +1,8 @@ use crate::ast::*; use crate::c_ir::*; -use std::collections::HashMap; use crate::c_lowerer::declaration_transpiler::DeclarationTranspiler; use crate::c_lowerer::statements_transpiler::StatementsTranspiler; +use std::collections::HashMap; pub struct Transpiler { structs: HashMap, @@ -99,7 +99,7 @@ impl Transpiler { // But for now, skip as they're handled differently } TypedASTNodeKind::Load(_) => {} - TypedASTNodeKind::Trait(typed_trait ) => {} + TypedASTNodeKind::Trait(typed_trait) => {} TypedASTNodeKind::Use(_) => {} } Ok(()) @@ -227,19 +227,20 @@ impl Transpiler { } 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 { output.push_str(&format!(" {}", self.generate_stmt(stmt))); } output.push_str(" }\n"); output } - CStmt::Break => { - "break;\n".to_string() - } - CStmt::Continue => { - "continue;\n".to_string() - } + CStmt::Break => "break;\n".to_string(), + CStmt::Continue => "continue;\n".to_string(), } } @@ -313,7 +314,10 @@ impl Transpiler { } CExpr::ArrayLit(array_lit) => { - let vec = array_lit.iter().map(|expr| self.generate_expr(expr)).collect::>(); + let vec = array_lit + .iter() + .map(|expr| self.generate_expr(expr)) + .collect::>(); let len = vec.len(); format!("{}[{}]{{ {} }}", vec[0], len, vec.join(", ")) } diff --git a/src/lambda_lower.rs b/src/lambda_lower.rs index 6ccc465..b9996b1 100644 --- a/src/lambda_lower.rs +++ b/src/lambda_lower.rs @@ -145,6 +145,9 @@ impl LambdaLowerer { self.collect_free_vars_expr(start, lambda_params, free_vars, local_scope); self.collect_free_vars_expr(end, lambda_params, free_vars, local_scope); } + ExprKind::Defer(expr) => { + self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope); + } // Terminal expressions don't contain variables ExprKind::Int(_) | ExprKind::Float(_) @@ -372,6 +375,7 @@ impl LambdaLowerer { | ExprKind::Variable(_) | ExprKind::Break | ExprKind::Continue => expr.kind.clone(), + ExprKind::Defer(inner) => ExprKind::Defer(Box::new(self.lower_expr(inner)?)), }; Ok(Expr { diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 85bf92b..a64b756 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -150,6 +150,9 @@ pub enum Token { #[token("continue")] KeywordContinue, + #[token("defer")] + KeywordDefer, + #[token("+")] Plus, diff --git a/src/lib.rs b/src/lib.rs index 8260c34..6da9abc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,8 @@ pub const EXTENSION: &str = ".sui"; pub mod ast; pub mod c_ir; -pub mod codegen; pub mod c_lowerer; +pub mod codegen; pub mod lambda_lower; pub mod lexer; pub mod monomorphize; diff --git a/src/monomorphize.rs b/src/monomorphize.rs index a064b15..f97a196 100644 --- a/src/monomorphize.rs +++ b/src/monomorphize.rs @@ -327,6 +327,11 @@ impl Monomorphizer { | TypedExprKind::String(_) | TypedExprKind::Break | TypedExprKind::Continue => expr.kind.clone(), + TypedExprKind::Defer(inner) => { + let (new_inner, mut inner_needs) = self.monomorphize_expr(inner)?; + needs.append(&mut inner_needs); + TypedExprKind::Defer(Box::new(new_inner)) + } TypedExprKind::Array(elems) => { let mut new_elems = Vec::new(); diff --git a/src/parser.rs b/src/parser.rs index eb87645..b06654a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1720,7 +1720,18 @@ impl Parser { self.next(); break; } - exprs.push(self.parse_expr()?); + if matches!(self.peek(), Some(Token::KeywordDefer)) { + self.next(); + let expr = self.parse_expr()?; + let end = expr.span.end; + exprs.push(Expr { + kind: ExprKind::Defer(Box::new(expr)), + span: Span::new(&(start..end), self.file.clone()), + attributes: Vec::new(), + }); + } else { + exprs.push(self.parse_expr()?); + } if matches!(self.peek(), Some(Token::Semicolon)) { self.next(); diff --git a/src/typechecker.rs b/src/typechecker.rs index f0ad2be..9e7481e 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1410,6 +1410,11 @@ impl TypeChecker { ExprKind::Break => (TypedExprKind::Break, Type::Never), ExprKind::Continue => (TypedExprKind::Continue, Type::Never), + ExprKind::Defer(expr) => { + let typed_expr = self.typecheck_expr(expr)?; + (TypedExprKind::Defer(Box::new(typed_expr)), Type::Unit) + } + ExprKind::EarlyReturn(value) => { let typed_value = if let Some(v) = value { Some(Box::new(self.typecheck_expr(v)?)) diff --git a/tests/basic_types.c b/tests/basic_types.c index 85ba69b..a916271 100644 --- a/tests/basic_types.c +++ b/tests/basic_types.c @@ -2,7 +2,6 @@ #include #include #include - int main(void);