Compare commits
2 commits
dde1da8656
...
c9a7493006
| Author | SHA1 | Date | |
|---|---|---|---|
| c9a7493006 | |||
| a62432bfbb |
16 changed files with 1253 additions and 49 deletions
18
simple_test.c
Normal file
18
simple_test.c
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
int simple_add(int x, int y);
|
||||
int main(void);
|
||||
|
||||
|
||||
int simple_add(int x, int y) {
|
||||
(x + y);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int result = simple_add(5, 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
157
src/c_ir.rs
157
src/c_ir.rs
|
|
@ -0,0 +1,157 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum CType {
|
||||
Void,
|
||||
Int,
|
||||
Float,
|
||||
Bool,
|
||||
Char,
|
||||
Ptr(Box<CType>),
|
||||
Struct(String),
|
||||
UnnamedStruct(Vec<CVarDecl>),
|
||||
Array(Box<CType>, usize), // type and size
|
||||
Func(Vec<CType>, Box<CType>), // args and return
|
||||
}
|
||||
|
||||
impl CType {
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
CType::Void => "void".to_string(),
|
||||
CType::Int => "int".to_string(),
|
||||
CType::Float => "float".to_string(),
|
||||
CType::Bool => "bool".to_string(),
|
||||
CType::Char => "char".to_string(),
|
||||
CType::Ptr(inner) => format!("{}*", inner.to_string()),
|
||||
CType::Struct(name) => format!("struct {}", name),
|
||||
CType::UnnamedStruct(fields) => {
|
||||
let field_strs: Vec<String> = fields
|
||||
.iter()
|
||||
.map(|f| format!(" {} {};", f.ty.to_string(), f.name))
|
||||
.collect();
|
||||
format!("struct {{\n{}\n}}", field_strs.join("\n"))
|
||||
}
|
||||
CType::Array(inner, size) => format!("{}[{}]", inner.to_string(), size),
|
||||
CType::Func(args, ret) => {
|
||||
let arg_strs: Vec<String> = args.iter().map(|t| t.to_string()).collect();
|
||||
format!("{} (*)({})", ret.to_string(), arg_strs.join(", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CVarDecl {
|
||||
pub name: String,
|
||||
pub ty: CType,
|
||||
pub initializer: Option<CExpr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CStructDecl {
|
||||
pub name: String,
|
||||
pub fields: Vec<CVarDecl>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CFuncDecl {
|
||||
pub name: String,
|
||||
pub return_type: CType,
|
||||
pub params: Vec<CVarDecl>,
|
||||
pub body: Option<Vec<CStmt>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CExpr {
|
||||
IntLit(i64),
|
||||
FloatLit(f64),
|
||||
BoolLit(bool),
|
||||
StringLit(String),
|
||||
Var(String),
|
||||
Call(String, Vec<CExpr>),
|
||||
BinOp(Box<CExpr>, CBinaryOp, Box<CExpr>),
|
||||
UnOp(CUnaryOp, Box<CExpr>),
|
||||
Cast(Box<CExpr>, CType),
|
||||
StructLit(String, Vec<(String, CExpr)>),
|
||||
EnumLit(String, String, Vec<CExpr>), // enum_name, variant_name, args
|
||||
ArrayLit(Vec<CExpr>),
|
||||
Index(Box<CExpr>, Box<CExpr>),
|
||||
Dot(Box<CExpr>, String),
|
||||
AddrOf(Box<CExpr>),
|
||||
Deref(Box<CExpr>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CBinaryOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Eq,
|
||||
Neq,
|
||||
Lt,
|
||||
Gt,
|
||||
Leq,
|
||||
Geq,
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
impl CBinaryOp {
|
||||
pub fn to_string(&self) -> &'static str {
|
||||
match self {
|
||||
CBinaryOp::Add => "+",
|
||||
CBinaryOp::Sub => "-",
|
||||
CBinaryOp::Mul => "*",
|
||||
CBinaryOp::Div => "/",
|
||||
CBinaryOp::Mod => "%",
|
||||
CBinaryOp::Eq => "==",
|
||||
CBinaryOp::Neq => "!=",
|
||||
CBinaryOp::Lt => "<",
|
||||
CBinaryOp::Gt => ">",
|
||||
CBinaryOp::Leq => "<=",
|
||||
CBinaryOp::Geq => ">=",
|
||||
CBinaryOp::And => "&&",
|
||||
CBinaryOp::Or => "||",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CUnaryOp {
|
||||
Neg,
|
||||
Not,
|
||||
Ref,
|
||||
Deref,
|
||||
}
|
||||
|
||||
impl CUnaryOp {
|
||||
pub fn to_string(&self) -> &'static str {
|
||||
match self {
|
||||
CUnaryOp::Neg => "-",
|
||||
CUnaryOp::Not => "!",
|
||||
CUnaryOp::Ref => "&",
|
||||
CUnaryOp::Deref => "*",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CStmt {
|
||||
VarDecl(CVarDecl),
|
||||
Expr(CExpr),
|
||||
Assign(CExpr, CExpr),
|
||||
If(CExpr, Vec<CStmt>, Option<Vec<CStmt>>),
|
||||
While(CExpr, Vec<CStmt>),
|
||||
For(CVarDecl, CExpr, CExpr, Vec<CStmt>), // init, cond, incr, body
|
||||
Return(Option<CExpr>),
|
||||
Break,
|
||||
Continue,
|
||||
Block(Vec<CStmt>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CToplevel {
|
||||
StructDecl(CStructDecl),
|
||||
FuncDecl(CFuncDecl),
|
||||
VarDecl(CVarDecl),
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
use crate::ast::*;
|
||||
use crate::c_ir::*;
|
||||
use crate::typechecker::Type;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct DeclarationTranspiler {
|
||||
type_map: HashMap<String, Type>,
|
||||
}
|
||||
|
||||
impl DeclarationTranspiler {
|
||||
pub fn new() -> Self {
|
||||
DeclarationTranspiler {
|
||||
type_map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transpile_struct(&self, struct_: &TypedStruct) -> Result<CStructDecl, String> {
|
||||
let mut fields = Vec::new();
|
||||
|
||||
for field in &struct_.fields {
|
||||
let field_type = self.type_annot_to_ctype(&Some(field.field_type.clone()))?;
|
||||
fields.push(CVarDecl {
|
||||
name: field.name.clone(),
|
||||
ty: field_type,
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(CStructDecl {
|
||||
name: struct_.name.clone(),
|
||||
fields,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn transpile_function(&self, func: &TypedFunction) -> Result<CFuncDecl, String> {
|
||||
let return_type = match &func.return_type {
|
||||
Some(type_annot) => self.type_annot_to_ctype(&Some(type_annot.clone()))?,
|
||||
None => CType::Void,
|
||||
};
|
||||
|
||||
let mut params = Vec::new();
|
||||
for (_binding_id, name, type_annot) in &func.args {
|
||||
let param_type = match type_annot {
|
||||
Some(annot) => self.type_annot_to_ctype(&Some(annot.clone()))?,
|
||||
None => {
|
||||
return Err(format!(
|
||||
"Function parameter {} missing type annotation",
|
||||
name
|
||||
));
|
||||
}
|
||||
};
|
||||
params.push(CVarDecl {
|
||||
name: name.clone(),
|
||||
ty: param_type,
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
|
||||
// Note: body will be transpiled separately by statements transpiler
|
||||
Ok(CFuncDecl {
|
||||
name: func.name.clone(),
|
||||
return_type,
|
||||
params,
|
||||
body: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn transpile_enum(&self, enum_: &TypedEnum) -> Result<Vec<CStructDecl>, String> {
|
||||
let mut structs = Vec::new();
|
||||
|
||||
// For each variant, create a struct
|
||||
for (i, variant) in enum_.variants.iter().enumerate() {
|
||||
let struct_name = format!("{}_{}", enum_.name, variant.name);
|
||||
let mut fields = Vec::new();
|
||||
|
||||
// Add variant fields (no discriminant in variant struct)
|
||||
for (j, field_type) in variant.fields.iter().enumerate() {
|
||||
let field_name = format!("field_{}", j);
|
||||
let c_type = self.type_annot_to_ctype(&Some(field_type.clone()))?;
|
||||
fields.push(CVarDecl {
|
||||
name: field_name,
|
||||
ty: c_type,
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
|
||||
structs.push(CStructDecl {
|
||||
name: struct_name,
|
||||
fields,
|
||||
});
|
||||
}
|
||||
|
||||
// Create union of all variants
|
||||
let union_name = format!("{}_union", enum_.name);
|
||||
let mut union_fields = Vec::new();
|
||||
for variant in &enum_.variants {
|
||||
let field_name = variant.name.to_lowercase();
|
||||
let struct_name = format!("{}_{}", enum_.name, variant.name);
|
||||
union_fields.push(CVarDecl {
|
||||
name: field_name,
|
||||
ty: CType::Struct(struct_name),
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
|
||||
let union_name_clone = union_name.clone();
|
||||
structs.push(CStructDecl {
|
||||
name: union_name,
|
||||
fields: union_fields,
|
||||
});
|
||||
|
||||
// Create main enum struct
|
||||
let enum_fields = vec![
|
||||
CVarDecl {
|
||||
name: "discriminant".to_string(),
|
||||
ty: CType::Int,
|
||||
initializer: None,
|
||||
},
|
||||
CVarDecl {
|
||||
name: "data".to_string(),
|
||||
ty: CType::Struct(union_name_clone),
|
||||
initializer: None,
|
||||
},
|
||||
];
|
||||
|
||||
structs.push(CStructDecl {
|
||||
name: enum_.name.clone(),
|
||||
fields: enum_fields,
|
||||
});
|
||||
|
||||
Ok(structs)
|
||||
}
|
||||
|
||||
fn type_annot_to_ctype(&self, annot: &Option<TypeAnnot>) -> Result<CType, String> {
|
||||
match annot {
|
||||
Some(TypeAnnot::Var(name)) => match name.as_str() {
|
||||
"int" => Ok(CType::Int),
|
||||
"float" => Ok(CType::Float),
|
||||
"bool" => Ok(CType::Bool),
|
||||
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
_ => Ok(CType::Struct(name.clone())), // Assume struct
|
||||
},
|
||||
Some(TypeAnnot::Cons(name, args)) if args.is_empty() => match name.as_str() {
|
||||
"int" => Ok(CType::Int),
|
||||
"float" => Ok(CType::Float),
|
||||
"bool" => Ok(CType::Bool),
|
||||
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
_ => Ok(CType::Struct(name.clone())), // Assume struct
|
||||
},
|
||||
Some(TypeAnnot::Cons(name, _args)) => {
|
||||
// Generic types - for now just use the base name
|
||||
Ok(CType::Struct(name.clone()))
|
||||
}
|
||||
Some(TypeAnnot::Ptr(inner)) => {
|
||||
let inner_type = self.type_annot_to_ctype(&Some(*inner.clone()))?;
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
Some(TypeAnnot::Array(inner)) => {
|
||||
let inner_type = self.type_annot_to_ctype(&Some(*inner.clone()))?;
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
Some(TypeAnnot::Tuple(fields)) => {
|
||||
let mut c_fields = Vec::new();
|
||||
for (i, field_annot) in fields.iter().enumerate() {
|
||||
let field_type = self.type_annot_to_ctype(&Some(field_annot.clone()))?;
|
||||
c_fields.push(CVarDecl {
|
||||
name: format!("field{}", i),
|
||||
ty: field_type,
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
Ok(CType::UnnamedStruct(c_fields))
|
||||
}
|
||||
Some(TypeAnnot::Function(args, ret)) => {
|
||||
let mut c_args = Vec::new();
|
||||
for arg in args {
|
||||
c_args.push(self.type_annot_to_ctype(&Some(arg.clone()))?);
|
||||
}
|
||||
let c_ret = self.type_annot_to_ctype(&Some(*ret.clone()))?;
|
||||
Ok(CType::Func(c_args, Box::new(c_ret)))
|
||||
}
|
||||
_ => Ok(CType::Void), // Default
|
||||
}
|
||||
}
|
||||
}
|
||||
3
src/codegen/mod.rs
Normal file
3
src/codegen/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub mod declaration_transpiler;
|
||||
pub mod statements_transpiler;
|
||||
pub mod transpiler;
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
use crate::ast::*;
|
||||
use crate::c_ir::*;
|
||||
|
||||
pub struct StatementsTranspiler;
|
||||
|
||||
impl StatementsTranspiler {
|
||||
pub fn new() -> Self {
|
||||
StatementsTranspiler
|
||||
}
|
||||
|
||||
pub fn transpile_expr(&self, expr: &TypedExpr) -> Result<CExpr, String> {
|
||||
match &expr.kind {
|
||||
TypedExprKind::Int(i) => Ok(CExpr::IntLit(*i)),
|
||||
TypedExprKind::Float(f) => Ok(CExpr::FloatLit(*f)),
|
||||
TypedExprKind::Bool(b) => Ok(CExpr::BoolLit(*b)),
|
||||
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))
|
||||
}
|
||||
TypedExprKind::BinOp(lhs, op, rhs) => {
|
||||
let c_lhs = self.transpile_expr(lhs)?;
|
||||
let c_rhs = self.transpile_expr(rhs)?;
|
||||
let c_op = self.binop_to_c_binop(op)?;
|
||||
Ok(CExpr::BinOp(Box::new(c_lhs), c_op, Box::new(c_rhs)))
|
||||
}
|
||||
TypedExprKind::UnOp(op, expr) => {
|
||||
let c_expr = self.transpile_expr(expr)?;
|
||||
let c_op = self.unop_to_c_unop(op)?;
|
||||
Ok(CExpr::UnOp(c_op, Box::new(c_expr)))
|
||||
}
|
||||
TypedExprKind::Index(array, index) => {
|
||||
let c_array = self.transpile_expr(array)?;
|
||||
let c_index = self.transpile_expr(index)?;
|
||||
Ok(CExpr::Index(Box::new(c_array), Box::new(c_index)))
|
||||
}
|
||||
TypedExprKind::Dot(obj, field) => {
|
||||
let c_obj = self.transpile_expr(obj)?;
|
||||
Ok(CExpr::Dot(Box::new(c_obj), field.clone()))
|
||||
}
|
||||
TypedExprKind::StructLit(struct_name, fields) => {
|
||||
let c_fields = fields
|
||||
.iter()
|
||||
.map(|(name, expr)| {
|
||||
let c_expr = self.transpile_expr(expr)?;
|
||||
Ok::<(String, CExpr), String>((name.clone(), c_expr))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(CExpr::StructLit(struct_name.clone(), c_fields))
|
||||
}
|
||||
TypedExprKind::Array(array_exprs) => {
|
||||
let c_exprs = array_exprs
|
||||
.iter()
|
||||
.map(|expr| self.transpile_expr(expr))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(CExpr::ArrayLit(c_exprs))
|
||||
}
|
||||
TypedExprKind::Cast(expr, type_annot) => {
|
||||
let c_expr = self.transpile_expr(expr)?;
|
||||
// Simplified: assuming we can map type annotations to C types
|
||||
let c_type = self.type_annot_to_ctype(type_annot)?;
|
||||
Ok(CExpr::Cast(Box::new(c_expr), c_type))
|
||||
}
|
||||
TypedExprKind::Tuple(_) => {
|
||||
// Simplified: treat as void for now
|
||||
Ok(CExpr::IntLit(0))
|
||||
}
|
||||
TypedExprKind::EnumLit(enum_name, variant_name, args) => {
|
||||
let c_args = args
|
||||
.iter()
|
||||
.map(|arg| self.transpile_expr(arg))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(CExpr::EnumLit(
|
||||
enum_name.clone(),
|
||||
variant_name.clone(),
|
||||
c_args,
|
||||
))
|
||||
}
|
||||
TypedExprKind::If(cond, then_expr, else_expr) => {
|
||||
// Conditional expressions - for now, simplify to function call
|
||||
// This is not ideal but works for basic cases
|
||||
Err("Conditional expressions not yet supported".to_string())
|
||||
}
|
||||
_ => Err(format!("Unsupported expression: {:?}", expr.kind)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transpile_stmt(&self, expr: &TypedExpr) -> Result<CStmt, String> {
|
||||
match &expr.kind {
|
||||
TypedExprKind::Let(_binding_id, name, _kind, _type_annot, init_expr) => {
|
||||
let c_type = self.type_to_ctype(&expr.ty)?;
|
||||
let initializer = Some(self.transpile_expr(init_expr)?);
|
||||
let var_decl = CVarDecl {
|
||||
name: name.clone(),
|
||||
ty: c_type,
|
||||
initializer,
|
||||
};
|
||||
Ok(CStmt::VarDecl(var_decl))
|
||||
}
|
||||
TypedExprKind::Assign(lhs, rhs) => {
|
||||
let c_lhs = self.transpile_expr(lhs)?;
|
||||
let c_rhs = self.transpile_expr(rhs)?;
|
||||
Ok(CStmt::Assign(c_lhs, c_rhs))
|
||||
}
|
||||
TypedExprKind::Return(ret_expr) => {
|
||||
let c_ret = match ret_expr {
|
||||
Some(expr) => Some(self.transpile_expr(expr)?),
|
||||
None => None,
|
||||
};
|
||||
Ok(CStmt::Return(c_ret))
|
||||
}
|
||||
TypedExprKind::If(cond, then_expr, else_expr) => {
|
||||
let c_cond = self.transpile_expr(cond)?;
|
||||
let then_stmts = self.expr_to_stmts(then_expr)?;
|
||||
let else_stmts = match else_expr {
|
||||
Some(else_expr) => Some(self.expr_to_stmts(else_expr)?),
|
||||
None => None,
|
||||
};
|
||||
Ok(CStmt::If(c_cond, then_stmts, else_stmts))
|
||||
}
|
||||
TypedExprKind::While(cond, body) => {
|
||||
let c_cond = self.transpile_expr(cond)?;
|
||||
let body_stmts = self.expr_to_stmts(body)?;
|
||||
Ok(CStmt::While(c_cond, body_stmts))
|
||||
}
|
||||
TypedExprKind::Do(exprs) => {
|
||||
let mut stmts = Vec::new();
|
||||
for expr in exprs {
|
||||
stmts.push(self.transpile_stmt(expr)?);
|
||||
}
|
||||
Ok(CStmt::Block(stmts))
|
||||
}
|
||||
TypedExprKind::For(_binding_id, var_name, iterable, body) => {
|
||||
// Simplified for loop handling
|
||||
// For now, assume range iteration
|
||||
match &iterable.kind {
|
||||
TypedExprKind::Range(start, end) => {
|
||||
let start_expr = self.transpile_expr(start)?;
|
||||
let end_expr = self.transpile_expr(end)?;
|
||||
// Create a simple for loop: for(int i = start; i < end; i++)
|
||||
let init = CVarDecl {
|
||||
name: var_name.clone(),
|
||||
ty: CType::Int,
|
||||
initializer: Some(start_expr),
|
||||
};
|
||||
let cond = CExpr::BinOp(
|
||||
Box::new(CExpr::Var(var_name.clone())),
|
||||
CBinaryOp::Lt,
|
||||
Box::new(end_expr),
|
||||
);
|
||||
let incr = CExpr::UnOp(CUnaryOp::Neg, Box::new(CExpr::IntLit(-1))); // i++
|
||||
let incr_stmt = CStmt::Assign(
|
||||
CExpr::Var(var_name.clone()),
|
||||
CExpr::BinOp(
|
||||
Box::new(CExpr::Var(var_name.clone())),
|
||||
CBinaryOp::Add,
|
||||
Box::new(CExpr::IntLit(1)),
|
||||
),
|
||||
);
|
||||
let body_stmts = self.expr_to_stmts(body)?;
|
||||
Ok(CStmt::For(init, cond, CExpr::IntLit(1), body_stmts))
|
||||
}
|
||||
_ => Err("Only range iteration supported for for loops".to_string()),
|
||||
}
|
||||
}
|
||||
TypedExprKind::Break => Ok(CStmt::Break),
|
||||
TypedExprKind::Continue => Ok(CStmt::Continue),
|
||||
_ => {
|
||||
// For other expressions, treat as expression statements
|
||||
let c_expr = self.transpile_expr(expr)?;
|
||||
Ok(CStmt::Expr(c_expr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr_to_stmts(&self, expr: &TypedExpr) -> Result<Vec<CStmt>, String> {
|
||||
match &expr.kind {
|
||||
TypedExprKind::Do(stmts) => {
|
||||
let mut c_stmts = Vec::new();
|
||||
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(_) => {
|
||||
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)?);
|
||||
}
|
||||
}
|
||||
Ok(c_stmts)
|
||||
}
|
||||
_ => Ok(vec![self.transpile_stmt(expr)?]),
|
||||
}
|
||||
}
|
||||
|
||||
fn binop_to_c_binop(&self, op: &BinOp) -> Result<CBinaryOp, String> {
|
||||
match op {
|
||||
BinOp::Add => Ok(CBinaryOp::Add),
|
||||
BinOp::Sub => Ok(CBinaryOp::Sub),
|
||||
BinOp::Mul => Ok(CBinaryOp::Mul),
|
||||
BinOp::Div => Ok(CBinaryOp::Div),
|
||||
BinOp::Mod => Ok(CBinaryOp::Mod),
|
||||
BinOp::Eq => Ok(CBinaryOp::Eq),
|
||||
BinOp::Neq => Ok(CBinaryOp::Neq),
|
||||
BinOp::Lt => Ok(CBinaryOp::Lt),
|
||||
BinOp::Gt => Ok(CBinaryOp::Gt),
|
||||
BinOp::Leq => Ok(CBinaryOp::Leq),
|
||||
BinOp::Geq => Ok(CBinaryOp::Geq),
|
||||
BinOp::And => Ok(CBinaryOp::And),
|
||||
BinOp::Or => Ok(CBinaryOp::Or),
|
||||
}
|
||||
}
|
||||
|
||||
fn unop_to_c_unop(&self, op: &UnOp) -> Result<CUnaryOp, String> {
|
||||
match op {
|
||||
UnOp::Neg => Ok(CUnaryOp::Neg),
|
||||
UnOp::Not => Ok(CUnaryOp::Not),
|
||||
UnOp::Ref => Ok(CUnaryOp::Ref),
|
||||
UnOp::Deref => Ok(CUnaryOp::Deref),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_to_ctype(&self, ty: &crate::typechecker::Type) -> Result<CType, String> {
|
||||
match ty {
|
||||
crate::typechecker::Type::Int => Ok(CType::Int),
|
||||
crate::typechecker::Type::Float => Ok(CType::Float),
|
||||
crate::typechecker::Type::Bool => Ok(CType::Bool),
|
||||
crate::typechecker::Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
crate::typechecker::Type::Unit => Ok(CType::Void),
|
||||
crate::typechecker::Type::Ptr(inner) => {
|
||||
Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?)))
|
||||
}
|
||||
crate::typechecker::Type::Array(inner) => {
|
||||
Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?)))
|
||||
}
|
||||
crate::typechecker::Type::Struct(name, _) => Ok(CType::Struct(name.clone())),
|
||||
crate::typechecker::Type::Enum(name, _) => Ok(CType::Struct(name.clone())),
|
||||
crate::typechecker::Type::Tuple(types) => {
|
||||
let mut fields = Vec::new();
|
||||
for (i, inner_ty) in types.iter().enumerate() {
|
||||
let c_type = self.type_to_ctype(inner_ty)?;
|
||||
fields.push(CVarDecl {
|
||||
name: format!("field{}", i),
|
||||
ty: c_type,
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
Ok(CType::UnnamedStruct(fields))
|
||||
}
|
||||
crate::typechecker::Type::Function(args, ret) => {
|
||||
let mut c_args = Vec::new();
|
||||
for arg in args {
|
||||
c_args.push(self.type_to_ctype(arg)?);
|
||||
}
|
||||
let c_ret = self.type_to_ctype(ret)?;
|
||||
Ok(CType::Func(c_args, Box::new(c_ret)))
|
||||
}
|
||||
crate::typechecker::Type::Generic(name, _args) => {
|
||||
// Generic types should have been monomorphized away,
|
||||
// but if they remain, treat them as struct types
|
||||
// For now, just use the base name
|
||||
Ok(CType::Struct(name.clone()))
|
||||
}
|
||||
crate::typechecker::Type::TypeVar(name) => {
|
||||
// Type variables should have been resolved during monomorphization
|
||||
Err(format!("Unresolved type variable: {}", name))
|
||||
}
|
||||
crate::typechecker::Type::Never => Ok(CType::Void),
|
||||
crate::typechecker::Type::Unknown => Err("Unknown type".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_annot_to_ctype(&self, annot: &TypeAnnot) -> Result<CType, String> {
|
||||
match annot {
|
||||
TypeAnnot::Var(name) => match name.as_str() {
|
||||
"int" => Ok(CType::Int),
|
||||
"float" => Ok(CType::Float),
|
||||
"bool" => Ok(CType::Bool),
|
||||
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
_ => Ok(CType::Struct(name.clone())),
|
||||
},
|
||||
TypeAnnot::Cons(name, args) if args.is_empty() => match name.as_str() {
|
||||
"int" => Ok(CType::Int),
|
||||
"float" => Ok(CType::Float),
|
||||
"bool" => Ok(CType::Bool),
|
||||
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
_ => Ok(CType::Struct(name.clone())),
|
||||
},
|
||||
TypeAnnot::Cons(name, _args) => {
|
||||
// Generic types - for now just use the base name
|
||||
Ok(CType::Struct(name.clone()))
|
||||
}
|
||||
TypeAnnot::Ptr(inner) => {
|
||||
let inner_type = self.type_annot_to_ctype(inner)?;
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
TypeAnnot::Array(inner) => {
|
||||
let inner_type = self.type_annot_to_ctype(inner)?;
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
TypeAnnot::Tuple(fields) => {
|
||||
let mut c_fields = Vec::new();
|
||||
for (i, field_annot) in fields.iter().enumerate() {
|
||||
let field_type = self.type_annot_to_ctype(field_annot)?;
|
||||
c_fields.push(CVarDecl {
|
||||
name: format!("field{}", i),
|
||||
ty: field_type,
|
||||
initializer: None,
|
||||
});
|
||||
}
|
||||
Ok(CType::UnnamedStruct(c_fields))
|
||||
}
|
||||
TypeAnnot::Function(args, ret) => {
|
||||
let mut c_args = Vec::new();
|
||||
for arg in args {
|
||||
c_args.push(self.type_annot_to_ctype(arg)?);
|
||||
}
|
||||
let c_ret = self.type_annot_to_ctype(ret)?;
|
||||
Ok(CType::Func(c_args, Box::new(c_ret)))
|
||||
}
|
||||
_ => Err(format!("Unsupported type annotation: {:?}", annot)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
use crate::ast::*;
|
||||
use crate::c_ir::*;
|
||||
use crate::codegen::declaration_transpiler::DeclarationTranspiler;
|
||||
use crate::codegen::statements_transpiler::StatementsTranspiler;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Transpiler {
|
||||
structs: HashMap<String, CStructDecl>,
|
||||
functions: Vec<CFuncDecl>,
|
||||
globals: Vec<CVarDecl>,
|
||||
decl_transpiler: DeclarationTranspiler,
|
||||
stmt_transpiler: StatementsTranspiler,
|
||||
}
|
||||
|
||||
impl Transpiler {
|
||||
pub fn new() -> Self {
|
||||
Transpiler {
|
||||
structs: HashMap::new(),
|
||||
functions: Vec::new(),
|
||||
globals: Vec::new(),
|
||||
decl_transpiler: DeclarationTranspiler::new(),
|
||||
stmt_transpiler: StatementsTranspiler::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transpile_program(&mut self, nodes: &[TypedASTNode]) -> Result<String, String> {
|
||||
// First pass: collect declarations
|
||||
for node in nodes {
|
||||
self.collect_declaration(node)?;
|
||||
}
|
||||
|
||||
// Second pass: transpile function bodies
|
||||
self.transpile_function_bodies(nodes)?;
|
||||
|
||||
// Generate C code
|
||||
let mut output = String::new();
|
||||
|
||||
// Add includes
|
||||
output.push_str("#include <stdio.h>\n");
|
||||
output.push_str("#include <stdlib.h>\n");
|
||||
output.push_str("#include <stdbool.h>\n");
|
||||
output.push_str("#include <string.h>\n\n");
|
||||
|
||||
// Generate struct declarations
|
||||
for struct_decl in self.structs.values() {
|
||||
output.push_str(&self.generate_struct_decl(struct_decl));
|
||||
output.push_str(";\n\n");
|
||||
}
|
||||
|
||||
// Generate function declarations (prototypes)
|
||||
for func in &self.functions {
|
||||
output.push_str(&self.generate_func_proto(func));
|
||||
output.push_str(";\n");
|
||||
}
|
||||
output.push_str("\n");
|
||||
|
||||
// Generate global variables
|
||||
for global in &self.globals {
|
||||
output.push_str(&self.generate_var_decl(global));
|
||||
output.push_str(";\n");
|
||||
}
|
||||
output.push_str("\n");
|
||||
|
||||
// Generate function definitions
|
||||
for func in &self.functions {
|
||||
output.push_str(&self.generate_func_def(func));
|
||||
output.push_str("\n");
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn collect_declaration(&mut self, node: &TypedASTNode) -> Result<(), String> {
|
||||
match &node.kind {
|
||||
TypedASTNodeKind::Struct(s) => {
|
||||
let struct_decl = self.decl_transpiler.transpile_struct(s)?;
|
||||
self.structs.insert(s.name.clone(), struct_decl);
|
||||
}
|
||||
TypedASTNodeKind::Enum(e) => {
|
||||
let enum_structs = self.decl_transpiler.transpile_enum(e)?;
|
||||
for struct_decl in enum_structs {
|
||||
self.structs.insert(struct_decl.name.clone(), struct_decl);
|
||||
}
|
||||
}
|
||||
TypedASTNodeKind::Function(f) => {
|
||||
let mut func_decl = self.decl_transpiler.transpile_function(f)?;
|
||||
// Body will be filled later
|
||||
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
|
||||
}
|
||||
_ => {
|
||||
// Other node types (traits, etc.) - handle later
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_struct_decl(&self, struct_decl: &CStructDecl) -> String {
|
||||
let mut output = format!("struct {} {{\n", struct_decl.name);
|
||||
for field in &struct_decl.fields {
|
||||
output.push_str(&format!(" {} {};\n", field.ty.to_string(), field.name));
|
||||
}
|
||||
output.push_str("}");
|
||||
output
|
||||
}
|
||||
|
||||
fn generate_func_proto(&self, func: &CFuncDecl) -> String {
|
||||
let params_str = if func.params.is_empty() {
|
||||
"void".to_string()
|
||||
} else {
|
||||
func.params
|
||||
.iter()
|
||||
.map(|p| format!("{} {}", p.ty.to_string(), p.name))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
};
|
||||
format!(
|
||||
"{} {}({})",
|
||||
func.return_type.to_string(),
|
||||
func.name,
|
||||
params_str
|
||||
)
|
||||
}
|
||||
|
||||
fn generate_func_def(&self, func: &CFuncDecl) -> String {
|
||||
let proto = self.generate_func_proto(func);
|
||||
let mut output = format!("{} {{\n", proto);
|
||||
|
||||
if let Some(body) = &func.body {
|
||||
for stmt in body {
|
||||
output.push_str(&self.generate_stmt(stmt));
|
||||
}
|
||||
}
|
||||
|
||||
output.push_str("}\n");
|
||||
output
|
||||
}
|
||||
|
||||
fn generate_var_decl(&self, var: &CVarDecl) -> String {
|
||||
let mut output = format!("{} {}", var.ty.to_string(), var.name);
|
||||
if let Some(init) = &var.initializer {
|
||||
output.push_str(&format!(" = {}", self.generate_expr(init)));
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
fn generate_stmt(&self, stmt: &CStmt) -> String {
|
||||
match stmt {
|
||||
CStmt::VarDecl(var) => format!(" {};\n", self.generate_var_decl(var)),
|
||||
CStmt::Expr(expr) => format!(" {};\n", self.generate_expr(expr)),
|
||||
CStmt::Assign(lhs, rhs) => format!(
|
||||
" {} = {};\n",
|
||||
self.generate_expr(lhs),
|
||||
self.generate_expr(rhs)
|
||||
),
|
||||
CStmt::Return(Some(expr)) => format!(" return {};\n", self.generate_expr(expr)),
|
||||
CStmt::Return(None) => " return;\n".to_string(),
|
||||
CStmt::If(cond, then_stmts, else_stmts) => {
|
||||
let mut output = format!(" if ({}) {{\n", self.generate_expr(cond));
|
||||
for stmt in then_stmts {
|
||||
output.push_str(&format!(" {}", self.generate_stmt(stmt)));
|
||||
}
|
||||
output.push_str(" }");
|
||||
if let Some(else_stmts) = else_stmts {
|
||||
output.push_str(" else {\n");
|
||||
for stmt in else_stmts {
|
||||
output.push_str(&format!(" {}", self.generate_stmt(stmt)));
|
||||
}
|
||||
output.push_str(" }");
|
||||
}
|
||||
output.push_str("\n");
|
||||
output
|
||||
}
|
||||
CStmt::While(cond, body) => {
|
||||
let mut output = format!(" while ({}) {{\n", self.generate_expr(cond));
|
||||
for stmt in body {
|
||||
output.push_str(&format!(" {}", self.generate_stmt(stmt)));
|
||||
}
|
||||
output.push_str(" }\n");
|
||||
output
|
||||
}
|
||||
CStmt::Block(stmts) => {
|
||||
let mut output = " {\n".to_string();
|
||||
for stmt in stmts {
|
||||
output.push_str(&format!(" {}", self.generate_stmt(stmt)));
|
||||
}
|
||||
output.push_str(" }\n");
|
||||
output
|
||||
}
|
||||
_ => "// TODO: unimplemented stmt\n".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_expr(&self, expr: &CExpr) -> String {
|
||||
match expr {
|
||||
CExpr::IntLit(i) => format!("{}", i),
|
||||
CExpr::FloatLit(f) => format!("{:.6}", f),
|
||||
CExpr::BoolLit(b) => format!("{}", b),
|
||||
CExpr::StringLit(s) => format!("\"{}\"", s),
|
||||
CExpr::Var(name) => name.clone(),
|
||||
CExpr::Call(func, args) => {
|
||||
let args_str = args
|
||||
.iter()
|
||||
.map(|arg| self.generate_expr(arg))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("{}({})", func, args_str)
|
||||
}
|
||||
CExpr::BinOp(lhs, op, rhs) => {
|
||||
format!(
|
||||
"({} {} {})",
|
||||
self.generate_expr(lhs),
|
||||
op.to_string(),
|
||||
self.generate_expr(rhs)
|
||||
)
|
||||
}
|
||||
CExpr::UnOp(op, expr) => {
|
||||
format!("{}{}", op.to_string(), self.generate_expr(expr))
|
||||
}
|
||||
CExpr::Cast(expr, ty) => {
|
||||
format!("({}) {}", ty.to_string(), self.generate_expr(expr))
|
||||
}
|
||||
CExpr::AddrOf(expr) => format!("&{}", self.generate_expr(expr)),
|
||||
CExpr::Deref(expr) => format!("*{}", self.generate_expr(expr)),
|
||||
CExpr::Dot(expr, field) => format!("{}.{}", self.generate_expr(expr), field),
|
||||
CExpr::Index(array, index) => format!(
|
||||
"{}[{}]",
|
||||
self.generate_expr(array),
|
||||
self.generate_expr(index)
|
||||
),
|
||||
CExpr::StructLit(struct_name, fields) => {
|
||||
let field_inits: Vec<String> = fields
|
||||
.iter()
|
||||
.map(|(name, expr)| format!(".{} = {}", name, self.generate_expr(expr)))
|
||||
.collect();
|
||||
format!("(struct {}){{ {} }}", struct_name, field_inits.join(", "))
|
||||
}
|
||||
CExpr::EnumLit(enum_name, variant_name, args) => {
|
||||
// Find the variant index - for simplicity, assume variants are in order
|
||||
// TODO: This should be stored properly
|
||||
let variant_index = 0; // Placeholder - need to map variant name to index
|
||||
|
||||
let variant_struct_name = format!("{}_{}", enum_name, variant_name);
|
||||
let union_field_name = variant_name.to_lowercase();
|
||||
|
||||
let struct_init = if args.is_empty() {
|
||||
"{}".to_string()
|
||||
} else {
|
||||
let field_inits: Vec<String> = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| format!(".field_{} = {}", i, self.generate_expr(arg)))
|
||||
.collect();
|
||||
format!("{{ {} }}", field_inits.join(", "))
|
||||
};
|
||||
|
||||
format!(
|
||||
"({}){{ .discriminant = {}, .data = {{ .{} = ({}{}) }} }}",
|
||||
enum_name, variant_index, union_field_name, variant_struct_name, struct_init
|
||||
)
|
||||
}
|
||||
_ => "// TODO: unimplemented expr".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,14 +17,24 @@ impl LambdaLowerer {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_free_vars(&self, expr: &Expr, lambda_params: &[String]) -> std::collections::HashSet<String> {
|
||||
fn collect_free_vars(
|
||||
&self,
|
||||
expr: &Expr,
|
||||
lambda_params: &[String],
|
||||
) -> std::collections::HashSet<String> {
|
||||
let mut free_vars = std::collections::HashSet::new();
|
||||
let mut local_scope = std::collections::HashSet::new();
|
||||
self.collect_free_vars_expr(expr, lambda_params, &mut free_vars, &mut local_scope);
|
||||
free_vars
|
||||
}
|
||||
|
||||
fn collect_free_vars_expr(&self, expr: &Expr, lambda_params: &[String], free_vars: &mut std::collections::HashSet<String>, local_scope: &mut std::collections::HashSet<String>) {
|
||||
fn collect_free_vars_expr(
|
||||
&self,
|
||||
expr: &Expr,
|
||||
lambda_params: &[String],
|
||||
free_vars: &mut std::collections::HashSet<String>,
|
||||
local_scope: &mut std::collections::HashSet<String>,
|
||||
) {
|
||||
match &expr.kind {
|
||||
ExprKind::Variable(name) => {
|
||||
if !lambda_params.contains(name) && !local_scope.contains(name) {
|
||||
|
|
@ -136,7 +146,12 @@ impl LambdaLowerer {
|
|||
self.collect_free_vars_expr(end, lambda_params, free_vars, local_scope);
|
||||
}
|
||||
// Terminal expressions don't contain variables
|
||||
ExprKind::Int(_) | ExprKind::Float(_) | ExprKind::Bool(_) | ExprKind::String(_) | ExprKind::Break | ExprKind::Continue => {}
|
||||
ExprKind::Int(_)
|
||||
| ExprKind::Float(_)
|
||||
| ExprKind::Bool(_)
|
||||
| ExprKind::String(_)
|
||||
| ExprKind::Break
|
||||
| ExprKind::Continue => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +198,8 @@ impl LambdaLowerer {
|
|||
let new_kind = match &expr.kind {
|
||||
ExprKind::Lambda(args, body) => {
|
||||
// Collect free variables (captured variables)
|
||||
let lambda_params: Vec<String> = args.iter().map(|(name, _)| name.clone()).collect();
|
||||
let lambda_params: Vec<String> =
|
||||
args.iter().map(|(name, _)| name.clone()).collect();
|
||||
let free_vars = self.collect_free_vars(body, &lambda_params);
|
||||
|
||||
if free_vars.is_empty() {
|
||||
|
|
@ -212,9 +228,7 @@ impl LambdaLowerer {
|
|||
};
|
||||
|
||||
// Store the generated function
|
||||
self.generated_functions
|
||||
.borrow_mut()
|
||||
.push(lambda_func);
|
||||
self.generated_functions.borrow_mut().push(lambda_func);
|
||||
|
||||
// Replace the lambda with a reference to the generated function
|
||||
ExprKind::Variable(lambda_name)
|
||||
|
|
@ -244,10 +258,7 @@ impl LambdaLowerer {
|
|||
ExprKind::If(cond, then_expr, else_expr) => {
|
||||
let lowered_cond = self.lower_expr(cond)?;
|
||||
let lowered_then = self.lower_expr(then_expr)?;
|
||||
let lowered_else = else_expr
|
||||
.as_ref()
|
||||
.map(|e| self.lower_expr(e))
|
||||
.transpose()?;
|
||||
let lowered_else = else_expr.as_ref().map(|e| self.lower_expr(e)).transpose()?;
|
||||
ExprKind::If(
|
||||
Box::new(lowered_cond),
|
||||
Box::new(lowered_then),
|
||||
|
|
@ -308,10 +319,7 @@ impl LambdaLowerer {
|
|||
ExprKind::Dot(Box::new(lowered_obj), field.clone())
|
||||
}
|
||||
ExprKind::EarlyReturn(expr) => {
|
||||
let lowered_expr = expr
|
||||
.as_ref()
|
||||
.map(|e| self.lower_expr(e))
|
||||
.transpose()?;
|
||||
let lowered_expr = expr.as_ref().map(|e| self.lower_expr(e)).transpose()?;
|
||||
ExprKind::EarlyReturn(lowered_expr.map(Box::new))
|
||||
}
|
||||
ExprKind::OptionalChain(obj, field) => {
|
||||
|
|
@ -319,10 +327,7 @@ impl LambdaLowerer {
|
|||
ExprKind::OptionalChain(lowered_obj.map(Box::new), field.clone())
|
||||
}
|
||||
ExprKind::Return(expr) => {
|
||||
let lowered_expr = expr
|
||||
.as_ref()
|
||||
.map(|e| self.lower_expr(e))
|
||||
.transpose()?;
|
||||
let lowered_expr = expr.as_ref().map(|e| self.lower_expr(e)).transpose()?;
|
||||
ExprKind::Return(lowered_expr.map(Box::new))
|
||||
}
|
||||
ExprKind::Array(exprs) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
pub const EXTENSION: &str = ".sui";
|
||||
|
||||
pub mod ast;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod c_ir;
|
||||
pub mod codegen;
|
||||
pub mod lambda_lower;
|
||||
pub mod typechecker;
|
||||
pub mod lexer;
|
||||
pub mod monomorphize;
|
||||
pub mod parser;
|
||||
pub mod typechecker;
|
||||
|
|
|
|||
132
src/main.rs
132
src/main.rs
|
|
@ -1,8 +1,12 @@
|
|||
use logos::Logos;
|
||||
use std::fs;
|
||||
use suicmez::{
|
||||
lexer::Token, parser::Parser, lambda_lower::LambdaLowerer, typechecker::TypeChecker,
|
||||
codegen::transpiler::Transpiler,
|
||||
lambda_lower::LambdaLowerer,
|
||||
lexer::Token,
|
||||
monomorphize::{Monomorphizer, check_no_typevars},
|
||||
parser::Parser,
|
||||
typechecker::TypeChecker,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
|
|
@ -45,7 +49,6 @@ fn run_test_suite() {
|
|||
}
|
||||
|
||||
fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> String {
|
||||
|
||||
// Find the line containing the error
|
||||
let lines: Vec<&str> = source.lines().collect();
|
||||
let mut current_pos = 0;
|
||||
|
|
@ -69,7 +72,10 @@ fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> Stri
|
|||
let line_end_col = (error.span.end - line_start).min(line.len());
|
||||
|
||||
// Print spaces and squiggly line for the span
|
||||
result.push_str(&format!("{} | ", " ".repeat((line_idx + 1).to_string().len())));
|
||||
result.push_str(&format!(
|
||||
"{} | ",
|
||||
" ".repeat((line_idx + 1).to_string().len())
|
||||
));
|
||||
for _ in 0..line_start_col {
|
||||
result.push(' ');
|
||||
}
|
||||
|
|
@ -79,7 +85,10 @@ fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> Stri
|
|||
result.push('\n');
|
||||
|
||||
// Print caret at the start position
|
||||
result.push_str(&format!("{} | ", " ".repeat((line_idx + 1).to_string().len())));
|
||||
result.push_str(&format!(
|
||||
"{} | ",
|
||||
" ".repeat((line_idx + 1).to_string().len())
|
||||
));
|
||||
for _ in 0..line_start_col {
|
||||
result.push(' ');
|
||||
}
|
||||
|
|
@ -92,7 +101,66 @@ fn format_parse_error(source: &str, error: &suicmez::parser::ParseError) -> Stri
|
|||
}
|
||||
|
||||
// Fallback if we can't find the line
|
||||
format!("Parse error: {} (at byte {})", error.message, error.span.start)
|
||||
format!(
|
||||
"Parse error: {} (at byte {})",
|
||||
error.message, error.span.start
|
||||
)
|
||||
}
|
||||
|
||||
fn format_type_error(source: &str, error: &suicmez::typechecker::TypeError) -> String {
|
||||
// Find the line containing the error
|
||||
let lines: Vec<&str> = source.lines().collect();
|
||||
let mut current_pos = 0;
|
||||
|
||||
for (line_idx, line) in lines.iter().enumerate() {
|
||||
let line_start = current_pos;
|
||||
let line_end = current_pos + line.len();
|
||||
|
||||
// Check if the error span intersects with this line
|
||||
if error.span.start < line_end && error.span.end > line_start {
|
||||
let mut result = String::new();
|
||||
|
||||
// Print the error message
|
||||
result.push_str(&format!("Type error: {}\n", error.kind));
|
||||
|
||||
// Print the line number and content
|
||||
result.push_str(&format!("{} | {}\n", line_idx + 1, line));
|
||||
|
||||
// Calculate column positions within the line
|
||||
let line_start_col = error.span.start.saturating_sub(line_start);
|
||||
let line_end_col = (error.span.end - line_start).min(line.len());
|
||||
|
||||
// Print spaces and squiggly line for the span
|
||||
result.push_str(&format!(
|
||||
"{} | ",
|
||||
" ".repeat((line_idx + 1).to_string().len())
|
||||
));
|
||||
for _ in 0..line_start_col {
|
||||
result.push(' ');
|
||||
}
|
||||
for _ in line_start_col..line_end_col {
|
||||
result.push('~');
|
||||
}
|
||||
result.push('\n');
|
||||
|
||||
// Print caret at the start position
|
||||
result.push_str(&format!(
|
||||
"{} | ",
|
||||
" ".repeat((line_idx + 1).to_string().len())
|
||||
));
|
||||
for _ in 0..line_start_col {
|
||||
result.push(' ');
|
||||
}
|
||||
result.push('^');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
current_pos = line_end + 1; // +1 for the newline character
|
||||
}
|
||||
|
||||
// Fallback if we can't find the line
|
||||
format!("Type error: {} (at byte {})", error.kind, error.span.start)
|
||||
}
|
||||
|
||||
fn run_file(filename: &str) -> Result<(), String> {
|
||||
|
|
@ -126,19 +194,20 @@ fn run_file(filename: &str) -> Result<(), String> {
|
|||
|
||||
// Lower lambdas to generated functions
|
||||
let lowerer = LambdaLowerer::new();
|
||||
let lowered_nodes = lowerer.lower_program(&ast_nodes)
|
||||
let lowered_nodes = lowerer
|
||||
.lower_program(&ast_nodes)
|
||||
.map_err(|e| format!("Lambda lowering error: {}", e))?;
|
||||
|
||||
println!("Lambda lowering passed! {} nodes after lowering.", lowered_nodes.len());
|
||||
println!(
|
||||
"Lambda lowering passed! {} nodes after lowering.",
|
||||
lowered_nodes.len()
|
||||
);
|
||||
|
||||
// Typecheck the AST
|
||||
let mut typechecker = TypeChecker::new();
|
||||
let typed_nodes = typechecker.typecheck_program(&lowered_nodes).map_err(|e| {
|
||||
format!(
|
||||
"Type error at {}:{}: {:?}",
|
||||
e.span.file, e.span.start, e.kind
|
||||
)
|
||||
})?;
|
||||
let typed_nodes = typechecker
|
||||
.typecheck_program(&lowered_nodes)
|
||||
.map_err(|e| format_type_error(&source, &e))?;
|
||||
|
||||
println!(
|
||||
"Type checking passed! {} nodes typechecked.",
|
||||
|
|
@ -179,17 +248,19 @@ fn run_file(filename: &str) -> Result<(), String> {
|
|||
|
||||
// Monomorphize the AST
|
||||
let monomorphizer = Monomorphizer::new();
|
||||
let mono_nodes = monomorphizer.monomorphize_program(&typed_nodes).map_err(|e| {
|
||||
format!(
|
||||
"Monomorphization error: {}{}",
|
||||
e.message,
|
||||
if let Some(span) = &e.span {
|
||||
format!(" at {}:{}", span.file, span.start)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
)
|
||||
})?;
|
||||
let mono_nodes = monomorphizer
|
||||
.monomorphize_program(&typed_nodes)
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"Monomorphization error: {}{}",
|
||||
e.message,
|
||||
if let Some(span) = &e.span {
|
||||
format!(" at {}:{}", span.file, span.start)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
)
|
||||
})?;
|
||||
|
||||
println!(
|
||||
"Monomorphization passed! {} nodes after specialization.",
|
||||
|
|
@ -243,5 +314,18 @@ fn run_file(filename: &str) -> Result<(), String> {
|
|||
|
||||
println!("Type variable check passed! No type variables remain in AST.");
|
||||
|
||||
// Generate C code
|
||||
let mut transpiler = Transpiler::new();
|
||||
let c_code = transpiler
|
||||
.transpile_program(&mono_nodes)
|
||||
.map_err(|e| format!("Code generation error: {}", e))?;
|
||||
|
||||
// Write C code to file
|
||||
let c_filename = filename.replace(".sui", ".c");
|
||||
fs::write(&c_filename, &c_code)
|
||||
.map_err(|e| format!("Error writing C file {}: {}", c_filename, e))?;
|
||||
|
||||
println!("C code generated successfully: {}", c_filename);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// src/typechecker.rs
|
||||
use crate::ast::*;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
|
|
@ -86,6 +87,75 @@ pub enum TypeErrorKind {
|
|||
Other(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for TypeErrorKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TypeErrorKind::TypeMismatch(expected, actual) => {
|
||||
write!(
|
||||
f,
|
||||
"Type mismatch: expected {}, found {}",
|
||||
expected.to_string(),
|
||||
actual.to_string()
|
||||
)
|
||||
}
|
||||
TypeErrorKind::UndefinedVariable(name) => {
|
||||
write!(f, "Undefined variable '{}'", name)
|
||||
}
|
||||
TypeErrorKind::UndefinedType(name) => {
|
||||
write!(f, "Undefined type '{}'", name)
|
||||
}
|
||||
TypeErrorKind::UndefinedFunction(name) => {
|
||||
write!(f, "Undefined function '{}'", name)
|
||||
}
|
||||
TypeErrorKind::UndefinedField(field, ty) => {
|
||||
write!(f, "Undefined field '{}' on type {}", field, ty.to_string())
|
||||
}
|
||||
TypeErrorKind::UndefinedVariant(enum_name, variant) => {
|
||||
write!(f, "Undefined variant '{}' in enum '{}'", variant, enum_name)
|
||||
}
|
||||
TypeErrorKind::ArityMismatch(expected, actual) => {
|
||||
write!(
|
||||
f,
|
||||
"Function expects {} arguments, but {} were provided",
|
||||
expected, actual
|
||||
)
|
||||
}
|
||||
TypeErrorKind::NotAFunction(ty) => {
|
||||
write!(f, "Expected a function, but found {}", ty.to_string())
|
||||
}
|
||||
TypeErrorKind::NotAnArray(ty) => {
|
||||
write!(f, "Expected an array, but found {}", ty.to_string())
|
||||
}
|
||||
TypeErrorKind::NotAStruct(ty) => {
|
||||
write!(f, "Expected a struct, but found {}", ty.to_string())
|
||||
}
|
||||
TypeErrorKind::NotAnEnum(ty) => {
|
||||
write!(f, "Expected an enum, but found {}", ty.to_string())
|
||||
}
|
||||
TypeErrorKind::InvalidCast(from, to) => {
|
||||
write!(
|
||||
f,
|
||||
"Invalid cast from {} to {}",
|
||||
from.to_string(),
|
||||
to.to_string()
|
||||
)
|
||||
}
|
||||
TypeErrorKind::InvalidPattern(msg) => {
|
||||
write!(f, "Invalid pattern: {}", msg)
|
||||
}
|
||||
TypeErrorKind::MutableityError(msg) => {
|
||||
write!(f, "Mutability error: {}", msg)
|
||||
}
|
||||
TypeErrorKind::LinearityError(msg) => {
|
||||
write!(f, "Linearity error: {}", msg)
|
||||
}
|
||||
TypeErrorKind::Other(msg) => {
|
||||
write!(f, "{}", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct VarInfo {
|
||||
ty: Type,
|
||||
|
|
|
|||
16
tests/basic_types.c
Normal file
16
tests/basic_types.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void);
|
||||
|
||||
|
||||
int main(void) {
|
||||
int x = 5;
|
||||
float y = 10.500000;
|
||||
bool z = true;
|
||||
char* s = "hello";
|
||||
return x;
|
||||
}
|
||||
|
||||
21
tests/control_flow.c
Normal file
21
tests/control_flow.c
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void);
|
||||
|
||||
|
||||
int main(void) {
|
||||
if (true) {
|
||||
1;
|
||||
} else {
|
||||
0;
|
||||
}
|
||||
int i = 0;
|
||||
while ((i < 5)) {
|
||||
i = (i + 1);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ fn main() -> int do
|
|||
else
|
||||
0
|
||||
|
||||
let i = 0;
|
||||
let mut i = 0;
|
||||
while i < 5
|
||||
i = i + 1;
|
||||
i
|
||||
|
|
|
|||
19
tests/structs.c
Normal file
19
tests/structs.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
int main(void);
|
||||
|
||||
|
||||
int main(void) {
|
||||
struct Point p = (struct Point){ .x = 5, .y = 10 };
|
||||
struct Person person = (struct Person){ .name = "Alice", .age = 30 };
|
||||
return (p.x + person.age);
|
||||
}
|
||||
|
||||
|
|
@ -9,8 +9,8 @@ struct Person<T>
|
|||
age: T,
|
||||
end
|
||||
|
||||
fn main() -> int do
|
||||
fn main() -> int do
|
||||
let p = Point { x: 5, y: 10 };
|
||||
let person = Person { name: "Alice", age: 30 };
|
||||
p.x
|
||||
p.x + person.age
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,5 +13,7 @@ impl Number : Show
|
|||
end
|
||||
|
||||
fn main() -> int do
|
||||
42
|
||||
let number = Number {value: 40};
|
||||
number.show();
|
||||
0
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue