Compare commits
No commits in common. "62b78ddad27aeac9e7525d7320d7b15aea262c78" and "c9a749300615ee63b998c5c9f15769bcd042ce05" have entirely different histories.
62b78ddad2
...
c9a7493006
5 changed files with 26 additions and 188 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::c_ir::*;
|
use crate::c_ir::*;
|
||||||
use crate::typechecker::Type;
|
|
||||||
|
|
||||||
pub struct StatementsTranspiler;
|
pub struct StatementsTranspiler;
|
||||||
|
|
||||||
|
|
@ -17,32 +16,16 @@ 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 {
|
let func_expr = self.transpile_expr(func)?;
|
||||||
// Method call
|
let func_name = match func_expr {
|
||||||
let obj_type = &obj.ty;
|
CExpr::Var(name) => name,
|
||||||
let type_name = if let Type::Struct(name, _) = obj_type {
|
_ => return Err("Function calls must be on variables for now".to_string()),
|
||||||
name
|
};
|
||||||
} else {
|
let c_args = args
|
||||||
return Err("Method call on non-struct".to_string());
|
.iter()
|
||||||
};
|
.map(|arg| self.transpile_expr(arg))
|
||||||
let func_name = format!("{}_{}", type_name, method);
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let c_args = args
|
Ok(CExpr::Call(func_name, c_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) => {
|
TypedExprKind::BinOp(lhs, op, rhs) => {
|
||||||
let c_lhs = self.transpile_expr(lhs)?;
|
let c_lhs = self.transpile_expr(lhs)?;
|
||||||
|
|
@ -222,7 +205,7 @@ impl StatementsTranspiler {
|
||||||
}
|
}
|
||||||
Ok(c_stmts)
|
Ok(c_stmts)
|
||||||
}
|
}
|
||||||
_ => Ok(vec![CStmt::Return(Some(self.transpile_expr(expr)?))]),
|
_ => Ok(vec![self.transpile_stmt(expr)?]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,14 +88,6 @@ 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
|
||||||
|
|
@ -109,27 +101,12 @@ 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 {
|
||||||
match &node.kind {
|
if let TypedASTNodeKind::Function(f) = &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)?;
|
||||||
{
|
func_decl.body = Some(body_stmts);
|
||||||
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(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -546,15 +546,7 @@ 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 {
|
||||||
let mut method_clone = method.clone();
|
typed_methods.push(self.typecheck_function(method)?);
|
||||||
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 {
|
||||||
|
|
@ -840,27 +832,12 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Call(func_expr, args) => {
|
ExprKind::Call(func_expr, args) => {
|
||||||
let (typed_func, typed_args) = if let ExprKind::Dot(_, _) = &func_expr.kind {
|
let typed_func = self.typecheck_expr(func_expr)?;
|
||||||
// Method call: insert self as first argument
|
let mut typed_args = Vec::new();
|
||||||
let typed_method = self.typecheck_expr(func_expr)?;
|
|
||||||
let typed_obj = if let TypedExprKind::Dot(obj, _) = &typed_method.kind {
|
for arg in args {
|
||||||
obj.as_ref().clone()
|
typed_args.push(self.typecheck_expr(arg)?);
|
||||||
} 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 {
|
let return_type = match &typed_func.ty {
|
||||||
Type::Function(param_types, ret) => {
|
Type::Function(param_types, ret) => {
|
||||||
|
|
@ -883,10 +860,7 @@ impl TypeChecker {
|
||||||
expected.clone(),
|
expected.clone(),
|
||||||
actual.ty.clone(),
|
actual.ty.clone(),
|
||||||
),
|
),
|
||||||
span: args
|
span: args[i].span.clone(),
|
||||||
.get(i)
|
|
||||||
.map(|a| a.span.clone())
|
|
||||||
.unwrap_or(expr.span.clone()),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1090,34 +1064,17 @@ 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 {
|
||||||
if let Some(field_ty) = fields
|
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()),
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#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