Compare commits
2 commits
c9a7493006
...
62b78ddad2
| Author | SHA1 | Date | |
|---|---|---|---|
| 62b78ddad2 | |||
| 216ef6b45a |
5 changed files with 188 additions and 26 deletions
|
|
@ -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)?))]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
|
|
|
|||
60
tests/generics_comprehensive.c
Normal file
60
tests/generics_comprehensive.c
Normal 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
19
tests/traits.c
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue