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::ast::*;
|
||||||
use crate::c_ir::*;
|
use crate::c_ir::*;
|
||||||
|
use crate::typechecker::Type;
|
||||||
|
|
||||||
pub struct StatementsTranspiler;
|
pub struct StatementsTranspiler;
|
||||||
|
|
||||||
|
|
@ -16,6 +17,21 @@ impl StatementsTranspiler {
|
||||||
TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())),
|
TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())),
|
||||||
TypedExprKind::Variable(name) => Ok(CExpr::Var(name.clone())),
|
TypedExprKind::Variable(name) => Ok(CExpr::Var(name.clone())),
|
||||||
TypedExprKind::Call(func, args) => {
|
TypedExprKind::Call(func, 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_expr = self.transpile_expr(func)?;
|
||||||
let func_name = match func_expr {
|
let func_name = match func_expr {
|
||||||
CExpr::Var(name) => name,
|
CExpr::Var(name) => name,
|
||||||
|
|
@ -27,6 +43,7 @@ impl StatementsTranspiler {
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
Ok(CExpr::Call(func_name, c_args))
|
Ok(CExpr::Call(func_name, c_args))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
TypedExprKind::BinOp(lhs, op, rhs) => {
|
TypedExprKind::BinOp(lhs, op, rhs) => {
|
||||||
let c_lhs = self.transpile_expr(lhs)?;
|
let c_lhs = self.transpile_expr(lhs)?;
|
||||||
let c_rhs = self.transpile_expr(rhs)?;
|
let c_rhs = self.transpile_expr(rhs)?;
|
||||||
|
|
@ -205,7 +222,7 @@ impl StatementsTranspiler {
|
||||||
}
|
}
|
||||||
Ok(c_stmts)
|
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());
|
func_decl.body = Some(Vec::new());
|
||||||
self.functions.push(func_decl);
|
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) => {
|
TypedASTNodeKind::Extern(e) => {
|
||||||
// For externs, we might need to add function prototypes
|
// For externs, we might need to add function prototypes
|
||||||
// But for now, skip as they're handled differently
|
// But for now, skip as they're handled differently
|
||||||
|
|
@ -101,13 +109,28 @@ impl Transpiler {
|
||||||
|
|
||||||
fn transpile_function_bodies(&mut self, nodes: &[TypedASTNode]) -> Result<(), String> {
|
fn transpile_function_bodies(&mut self, nodes: &[TypedASTNode]) -> Result<(), String> {
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
if let TypedASTNodeKind::Function(f) = &node.kind {
|
match &node.kind {
|
||||||
|
TypedASTNodeKind::Function(f) => {
|
||||||
// Find the corresponding function declaration
|
// Find the corresponding function declaration
|
||||||
if let Some(func_decl) = self.functions.iter_mut().find(|fd| fd.name == f.name) {
|
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)?;
|
let body_stmts = self.stmt_transpiler.expr_to_stmts(&f.body)?;
|
||||||
func_decl.body = Some(body_stmts);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -546,7 +546,15 @@ impl TypeChecker {
|
||||||
ASTNodeKind::Impl(impl_def) => {
|
ASTNodeKind::Impl(impl_def) => {
|
||||||
let mut typed_methods = Vec::new();
|
let mut typed_methods = Vec::new();
|
||||||
for method in &impl_def.methods {
|
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 {
|
return Ok(TypedASTNode {
|
||||||
kind: TypedASTNodeKind::Impl(TypedImpl {
|
kind: TypedASTNodeKind::Impl(TypedImpl {
|
||||||
|
|
@ -832,12 +840,27 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Call(func_expr, args) => {
|
ExprKind::Call(func_expr, args) => {
|
||||||
let typed_func = self.typecheck_expr(func_expr)?;
|
let (typed_func, typed_args) = if let ExprKind::Dot(_, _) = &func_expr.kind {
|
||||||
let mut typed_args = Vec::new();
|
// 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 {
|
for arg in args {
|
||||||
typed_args.push(self.typecheck_expr(arg)?);
|
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 {
|
let return_type = match &typed_func.ty {
|
||||||
Type::Function(param_types, ret) => {
|
Type::Function(param_types, ret) => {
|
||||||
|
|
@ -860,7 +883,10 @@ impl TypeChecker {
|
||||||
expected.clone(),
|
expected.clone(),
|
||||||
actual.ty.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, _) => {
|
Type::Struct(name, _) => {
|
||||||
if let Some(type_info) = self.env.get_type(name) {
|
if let Some(type_info) = self.env.get_type(name) {
|
||||||
if let TypeInfoKind::Struct(fields) = &type_info.kind {
|
if let TypeInfoKind::Struct(fields) = &type_info.kind {
|
||||||
fields
|
if let Some(field_ty) = fields
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(f, _)| f == field)
|
.find(|(f, _)| f == field)
|
||||||
.map(|(_, ty)| self.type_annot_to_type(ty))
|
.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(
|
kind: TypeErrorKind::UndefinedField(
|
||||||
field.clone(),
|
field.clone(),
|
||||||
typed_obj.ty.clone(),
|
typed_obj.ty.clone(),
|
||||||
),
|
),
|
||||||
span: expr.span.clone(),
|
span: expr.span.clone(),
|
||||||
})?
|
})?
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(TypeError {
|
return Err(TypeError {
|
||||||
kind: TypeErrorKind::NotAStruct(typed_obj.ty.clone()),
|
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