Compare commits

..

2 commits

Author SHA1 Message Date
62b78ddad2 hmm 2025-12-16 02:46:45 +05:30
216ef6b45a disappointment 2025-12-16 02:06:58 +05:30
5 changed files with 188 additions and 26 deletions

View file

@ -1,5 +1,6 @@
use crate::ast::*;
use crate::c_ir::*;
use crate::typechecker::Type;
pub struct StatementsTranspiler;
@ -16,16 +17,32 @@ impl StatementsTranspiler {
TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())),
TypedExprKind::Variable(name) => Ok(CExpr::Var(name.clone())),
TypedExprKind::Call(func, args) => {
let func_expr = self.transpile_expr(func)?;
let func_name = match func_expr {
CExpr::Var(name) => name,
_ => return Err("Function calls must be on variables for now".to_string()),
};
let c_args = args
.iter()
.map(|arg| self.transpile_expr(arg))
.collect::<Result<Vec<_>, _>>()?;
Ok(CExpr::Call(func_name, c_args))
if let TypedExprKind::Dot(obj, method) = &func.kind {
// Method call
let obj_type = &obj.ty;
let type_name = if let Type::Struct(name, _) = obj_type {
name
} else {
return Err("Method call on non-struct".to_string());
};
let func_name = format!("{}_{}", type_name, method);
let c_args = args
.iter()
.map(|arg| self.transpile_expr(arg))
.collect::<Result<Vec<_>, _>>()?;
Ok(CExpr::Call(func_name, c_args))
} else {
let func_expr = self.transpile_expr(func)?;
let func_name = match func_expr {
CExpr::Var(name) => name,
_ => return Err("Function calls must be on variables for now".to_string()),
};
let c_args = args
.iter()
.map(|arg| self.transpile_expr(arg))
.collect::<Result<Vec<_>, _>>()?;
Ok(CExpr::Call(func_name, c_args))
}
}
TypedExprKind::BinOp(lhs, op, rhs) => {
let c_lhs = self.transpile_expr(lhs)?;
@ -205,7 +222,7 @@ impl StatementsTranspiler {
}
Ok(c_stmts)
}
_ => Ok(vec![self.transpile_stmt(expr)?]),
_ => Ok(vec![CStmt::Return(Some(self.transpile_expr(expr)?))]),
}
}

View file

@ -88,6 +88,14 @@ impl Transpiler {
func_decl.body = Some(Vec::new());
self.functions.push(func_decl);
}
TypedASTNodeKind::Impl(imp) => {
for method in &imp.methods {
let mut func_decl = self.decl_transpiler.transpile_function(method)?;
func_decl.name = format!("{}_{}", imp.target, method.name);
func_decl.body = Some(Vec::new());
self.functions.push(func_decl);
}
}
TypedASTNodeKind::Extern(e) => {
// For externs, we might need to add function prototypes
// But for now, skip as they're handled differently
@ -101,12 +109,27 @@ impl Transpiler {
fn transpile_function_bodies(&mut self, nodes: &[TypedASTNode]) -> Result<(), String> {
for node in nodes {
if let TypedASTNodeKind::Function(f) = &node.kind {
// Find the corresponding function declaration
if let Some(func_decl) = self.functions.iter_mut().find(|fd| fd.name == f.name) {
let body_stmts = self.stmt_transpiler.expr_to_stmts(&f.body)?;
func_decl.body = Some(body_stmts);
match &node.kind {
TypedASTNodeKind::Function(f) => {
// Find the corresponding function declaration
if let Some(func_decl) = self.functions.iter_mut().find(|fd| fd.name == f.name)
{
let body_stmts = self.stmt_transpiler.expr_to_stmts(&f.body)?;
func_decl.body = Some(body_stmts);
}
}
TypedASTNodeKind::Impl(imp) => {
for method in &imp.methods {
let method_name = format!("{}_{}", imp.target, method.name);
if let Some(func_decl) =
self.functions.iter_mut().find(|fd| fd.name == method_name)
{
let body_stmts = self.stmt_transpiler.expr_to_stmts(&method.body)?;
func_decl.body = Some(body_stmts);
}
}
}
_ => {}
}
}
Ok(())

View file

@ -546,7 +546,15 @@ impl TypeChecker {
ASTNodeKind::Impl(impl_def) => {
let mut typed_methods = Vec::new();
for method in &impl_def.methods {
typed_methods.push(self.typecheck_function(method)?);
let mut method_clone = method.clone();
if !method_clone.args.is_empty()
&& method_clone.args[0].0 == "self"
&& method_clone.args[0].1.is_none()
{
method_clone.args[0].1 =
Some(TypeAnnot::Cons(impl_def.target.clone(), vec![]));
}
typed_methods.push(self.typecheck_function(&method_clone)?);
}
return Ok(TypedASTNode {
kind: TypedASTNodeKind::Impl(TypedImpl {
@ -832,12 +840,27 @@ impl TypeChecker {
}
ExprKind::Call(func_expr, args) => {
let typed_func = self.typecheck_expr(func_expr)?;
let mut typed_args = Vec::new();
for arg in args {
typed_args.push(self.typecheck_expr(arg)?);
}
let (typed_func, typed_args) = if let ExprKind::Dot(_, _) = &func_expr.kind {
// Method call: insert self as first argument
let typed_method = self.typecheck_expr(func_expr)?;
let typed_obj = if let TypedExprKind::Dot(obj, _) = &typed_method.kind {
obj.as_ref().clone()
} else {
unreachable!()
};
let mut args_with_self = vec![typed_obj];
for arg in args {
args_with_self.push(self.typecheck_expr(arg)?);
}
(typed_method, args_with_self)
} else {
let typed_func = self.typecheck_expr(func_expr)?;
let typed_args = args
.iter()
.map(|arg| self.typecheck_expr(arg))
.collect::<Result<Vec<_>, _>>()?;
(typed_func, typed_args)
};
let return_type = match &typed_func.ty {
Type::Function(param_types, ret) => {
@ -860,7 +883,10 @@ impl TypeChecker {
expected.clone(),
actual.ty.clone(),
),
span: args[i].span.clone(),
span: args
.get(i)
.map(|a| a.span.clone())
.unwrap_or(expr.span.clone()),
});
}
}
@ -1064,17 +1090,34 @@ impl TypeChecker {
Type::Struct(name, _) => {
if let Some(type_info) = self.env.get_type(name) {
if let TypeInfoKind::Struct(fields) = &type_info.kind {
fields
if let Some(field_ty) = fields
.iter()
.find(|(f, _)| f == field)
.map(|(_, ty)| self.type_annot_to_type(ty))
.ok_or_else(|| TypeError {
{
field_ty
} else {
// Check for methods in impls
let mut method_type = None;
for impl_info in &self.env.impls {
if impl_info.target == *name {
if let Some(func_type) = impl_info.methods.get(field) {
method_type = Some(Type::Function(
func_type.params.clone(),
Box::new(func_type.return_type.clone()),
));
break;
}
}
}
method_type.ok_or_else(|| TypeError {
kind: TypeErrorKind::UndefinedField(
field.clone(),
typed_obj.ty.clone(),
),
span: expr.span.clone(),
})?
}
} else {
return Err(TypeError {
kind: TypeErrorKind::NotAStruct(typed_obj.ty.clone()),

View file

@ -0,0 +1,60 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct Box_string {
struct T value;
};
struct Option_bool_union {
struct Option_bool_Some some;
struct Option_bool_None none;
};
struct Option_int_union {
struct Option_int_Some some;
struct Option_int_None none;
};
struct Option_int_None {
};
struct Option_int {
int discriminant;
struct Option_int_union data;
};
struct Option_int_Some {
struct T field_0;
};
struct Option_bool_None {
};
struct Option_bool {
int discriminant;
struct Option_bool_union data;
};
struct Option_bool_Some {
struct T field_0;
};
struct Box_int {
struct T value;
};
int test_containers(void);
int test_containers(void) {
struct Box box_int = (struct Box){ .value = 42 };
struct Box box_string = (struct Box){ .value = "Fermented" };
struct Option some_int = (Option){ .discriminant = 0, .data = { .some = (Option_Some{ .field_0 = 10 }) } };
struct Option some_bool = (Option){ .discriminant = 0, .data = { .some = (Option_Some{ .field_0 = true }) } };
struct T unwrapped = unwrap(some_int);
struct T unwraped_bool = unwrap(some_bool);
return (box_int.value + unwrapped);
}

19
tests/traits.c Normal file
View file

@ -0,0 +1,19 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Number {
int value;
};
char *Number_show(struct Number self);
int main(void);
char *Number_show(struct Number self) { return "number"; }
int main(void) {
struct Number number = (struct Number){.value = 40};
Number_show(number);
return 0;
}