Skip to main content

CodeGenerator

Struct CodeGenerator 

Source
pub struct CodeGenerator { /* private fields */ }
Expand description

Code generator for converting HIR to Rust source code.

Implementations§

Source§

impl CodeGenerator

Source

pub fn new() -> Self

Create a new code generator.

§Examples
use decy_codegen::CodeGenerator;

let codegen = CodeGenerator::new();
Source

pub fn generate_macro(&self, macro_def: &HirMacroDefinition) -> Result<String>

Generate Rust code for a macro definition.

Transforms C #define macros to Rust const declarations (for object-like macros) or inline functions (for function-like macros).

§Supported Macro Types (DECY-098c)

Object-like macros (constants) are fully supported:

  • #define MAX 100const MAX: i32 = 100;
  • #define PI 3.14159const PI: f64 = 3.14159;
  • #define GREETING "Hello"const GREETING: &str = "Hello";

Function-like macros are not yet supported (DECY-098d):

  • #define SQR(x) ((x) * (x)) → Error
§Type Inference

Types are automatically inferred from the macro body:

  • String literals → &str
  • Character literals → char
  • Floating point → f64
  • Integers (including hex/octal) → i32
§Edge Cases
  • Empty macros generate comments: #define EMPTY// Empty macro: EMPTY
  • Macro names are preserved exactly (SCREAMING_SNAKE_CASE maintained)
§Errors

Returns an error if:

  • The macro is function-like (not yet implemented)
§Examples
use decy_codegen::CodeGenerator;
use decy_hir::HirMacroDefinition;

let generator = CodeGenerator::new();
let macro_def = HirMacroDefinition::new_object_like("MAX".to_string(), "100".to_string());
let rust_code = generator.generate_macro(&macro_def).unwrap();
assert!(rust_code.contains("const MAX"));
§Reference
  • K&R §4.11: Macro Substitution
  • ISO C99 §6.10.3: Macro replacement
Source

pub fn box_transformer(&self) -> &BoxTransformer

Get the Box transformer.

Source

pub fn map_type(hir_type: &HirType) -> String

Map HIR type to Rust type string.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::HirType;

assert_eq!(CodeGenerator::map_type(&HirType::Int), "i32");
assert_eq!(CodeGenerator::map_type(&HirType::Float), "f32");
assert_eq!(CodeGenerator::map_type(&HirType::Box(Box::new(HirType::Int))), "Box<i32>");
Source

pub fn generate_expression(&self, expr: &HirExpression) -> String

Generate code for an expression.

Source

pub fn generate_statement(&self, stmt: &HirStatement) -> String

Generate code for a statement.

Source

pub fn generate_signature(&self, func: &HirFunction) -> String

Generate a function signature from HIR.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirFunction, HirType};

let func = HirFunction::new("test".to_string(), HirType::Void, vec![]);
let codegen = CodeGenerator::new();
let sig = codegen.generate_signature(&func);

assert_eq!(sig, "fn test()");
Source

pub fn get_string_iteration_params( &self, func: &HirFunction, ) -> Vec<(usize, bool)>

DECY-134b: Get all string iteration params for a function.

Returns a list of (param_index, is_mutable) for each char* param that uses pointer arithmetic. Used by decy-core to build string_iter_funcs info for call site transformation.

Source

pub fn generate_annotated_signature(&self, sig: &AnnotatedSignature) -> String

Generate a function signature with lifetime annotations.

Takes an AnnotatedSignature with lifetime information and generates the complete Rust function signature including lifetime parameters.

§Examples
use decy_codegen::CodeGenerator;
use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedParameter, AnnotatedType, LifetimeParam};
use decy_hir::HirType;

let sig = AnnotatedSignature {
    name: "get_first".to_string(),
    lifetimes: vec![LifetimeParam::standard(0)], // 'a
    parameters: vec![
        AnnotatedParameter {
            name: "items".to_string(),
            param_type: AnnotatedType::Reference {
                inner: Box::new(AnnotatedType::Simple(HirType::Int)),
                mutable: false,
                lifetime: Some(LifetimeParam::standard(0)),
            },
        },
    ],
    return_type: AnnotatedType::Reference {
        inner: Box::new(AnnotatedType::Simple(HirType::Int)),
        mutable: false,
        lifetime: Some(LifetimeParam::standard(0)),
    },
};

let codegen = CodeGenerator::new();
let rust_sig = codegen.generate_annotated_signature(&sig);

assert!(rust_sig.contains("<'a>"));
assert!(rust_sig.contains("&'a i32"));
Source

pub fn generate_annotated_signature_with_func( &self, sig: &AnnotatedSignature, func: Option<&HirFunction>, ) -> String

Generate a function signature from an annotated signature with optional function body access.

When func is provided, pointer arithmetic detection is enabled (DECY-123). DECY-084: Also detects output parameters for transformation to return values.

Source

pub fn annotated_type_to_string(&self, annotated_type: &AnnotatedType) -> String

Convert an AnnotatedType to Rust type string with lifetime annotations.

§Examples
use decy_codegen::CodeGenerator;
use decy_ownership::lifetime_gen::{AnnotatedType, LifetimeParam};
use decy_hir::HirType;

let codegen = CodeGenerator::new();

// Simple type
let simple = AnnotatedType::Simple(HirType::Int);
assert_eq!(codegen.annotated_type_to_string(&simple), "i32");

// Reference with lifetime
let ref_type = AnnotatedType::Reference {
    inner: Box::new(AnnotatedType::Simple(HirType::Int)),
    mutable: false,
    lifetime: Some(LifetimeParam::standard(0)),
};
assert_eq!(codegen.annotated_type_to_string(&ref_type), "&'a i32");
Source

pub fn generate_return(&self, return_type: &HirType) -> String

Generate a default return statement for a type.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::HirType;

let codegen = CodeGenerator::new();
assert!(codegen.generate_return(&HirType::Int).contains("return 0"));
Source

pub fn generate_function(&self, func: &HirFunction) -> String

Generate a complete function from HIR.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirFunction, HirType, HirParameter};

let func = HirFunction::new(
    "add".to_string(),
    HirType::Int,
    vec![
        HirParameter::new("a".to_string(), HirType::Int),
        HirParameter::new("b".to_string(), HirType::Int),
    ],
);

let codegen = CodeGenerator::new();
let code = codegen.generate_function(&func);

assert!(code.contains("fn add(mut a: i32, mut b: i32) -> i32"));
assert!(code.contains("{"));
assert!(code.contains("}"));
Source

pub fn generate_function_with_structs( &self, func: &HirFunction, structs: &[HirStruct], ) -> String

Generate a complete function from HIR with struct definitions for type inference.

This is useful for testing when struct fields need proper type inference. DECY-165: Enables proper raw pointer detection for struct field access.

Source

pub fn generate_function_with_lifetimes( &self, func: &HirFunction, sig: &AnnotatedSignature, ) -> String

Generate a complete function from HIR with lifetime annotations.

Takes both the HIR function and its annotated signature to generate Rust code with proper lifetime annotations.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirFunction, HirType, HirParameter};
use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedParameter, AnnotatedType, LifetimeParam};

let func = HirFunction::new(
    "identity".to_string(),
    HirType::Reference {
        inner: Box::new(HirType::Int),
        mutable: false,
    },
    vec![
        HirParameter::new("x".to_string(), HirType::Reference {
            inner: Box::new(HirType::Int),
            mutable: false,
        }),
    ],
);

let sig = AnnotatedSignature {
    name: "identity".to_string(),
    lifetimes: vec![LifetimeParam::standard(0)],
    parameters: vec![
        AnnotatedParameter {
            name: "x".to_string(),
            param_type: AnnotatedType::Reference {
                inner: Box::new(AnnotatedType::Simple(HirType::Int)),
                mutable: false,
                lifetime: Some(LifetimeParam::standard(0)),
            },
        },
    ],
    return_type: AnnotatedType::Reference {
        inner: Box::new(AnnotatedType::Simple(HirType::Int)),
        mutable: false,
        lifetime: Some(LifetimeParam::standard(0)),
    },
};

let codegen = CodeGenerator::new();
let code = codegen.generate_function_with_lifetimes(&func, &sig);

assert!(code.contains("<'a>"));
assert!(code.contains("&'a i32"));
Source

pub fn generate_function_with_lifetimes_and_structs( &self, func: &HirFunction, sig: &AnnotatedSignature, structs: &[HirStruct], all_functions: &[(String, Vec<HirType>)], slice_func_args: &[(String, Vec<(usize, usize)>)], string_iter_funcs: &[(String, Vec<(usize, bool)>)], globals: &[(String, HirType)], ) -> String

Generate a complete function from HIR with lifetime annotations and struct definitions.

Takes the HIR function, its annotated signature, struct definitions, and all function signatures for call site reference mutability.

§Arguments
  • func - The HIR function to generate
  • sig - The annotated signature with lifetime annotations
  • structs - Struct definitions for field type awareness
  • all_functions - All function signatures for DECY-117 call site mutability
  • slice_func_args - DECY-116: func_name -> [(array_idx, len_idx)] for call site transformation
  • string_iter_funcs - DECY-134b: func_name -> [(param_idx, is_mutable)] for string iteration
  • globals - DECY-220/233: Global variable names and types for unsafe access and type inference
Source

pub fn generate_function_with_box_transform( &self, func: &HirFunction, candidates: &[BoxCandidate], ) -> String

Generate a function with Box transformations applied.

This method analyzes the function for malloc/free patterns and transforms them into safe Box::new() expressions.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirFunction, HirType, HirStatement, HirExpression};
use decy_analyzer::patterns::PatternDetector;

let func = HirFunction::new_with_body(
    "test".to_string(),
    HirType::Void,
    vec![],
    vec![
        HirStatement::VariableDeclaration {
            name: "ptr".to_string(),
            var_type: HirType::Pointer(Box::new(HirType::Int)),
            initializer: Some(HirExpression::FunctionCall {
                function: "malloc".to_string(),
                arguments: vec![HirExpression::IntLiteral(100)],
            }),
        },
    ],
);

let codegen = CodeGenerator::new();
let detector = PatternDetector::new();
let candidates = detector.find_box_candidates(&func);
let code = codegen.generate_function_with_box_transform(&func, &candidates);

assert!(code.contains("Box::new"));
Source

pub fn generate_function_with_vec_transform( &self, func: &HirFunction, candidates: &[VecCandidate], ) -> String

Generate a function with Vec transformations applied.

This method analyzes the function for malloc(n * sizeof(T)) patterns and transforms them into safe Vec::with_capacity(n) expressions.

Source

pub fn generate_function_with_box_and_vec_transform( &self, func: &HirFunction, box_candidates: &[BoxCandidate], vec_candidates: &[VecCandidate], ) -> String

Generate a function with both Box and Vec transformations applied.

This method combines both Box and Vec transformations, applying them to their respective patterns.

Source

pub fn generate_struct(&self, hir_struct: &HirStruct) -> String

Generate a struct definition from HIR.

Generates Rust struct code with automatic derives for Debug, Clone, PartialEq, Eq. Handles lifetimes automatically for structs with reference fields.

Source

pub fn generate_enum(&self, hir_enum: &HirEnum) -> String

DECY-240: Generate an enum definition from HIR.

Generates Rust const declarations for C enum values. C enums create integer constants that can be used directly (without prefix), so we generate const i32 values rather than Rust enums.

§Example

C: enum day { MONDAY = 1, TUESDAY, WEDNESDAY }; Rust:

pub const MONDAY: i32 = 1;
pub const TUESDAY: i32 = 2;
pub const WEDNESDAY: i32 = 3;
Source

pub fn generate_typedef(&self, typedef: &HirTypedef) -> Result<String>

Generate a typedef (type alias) from HIR.

Generates Rust type alias code using the type keyword. Handles redundant typedefs (where name matches underlying struct/enum name) as comments.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirTypedef, HirType};

let codegen = CodeGenerator::new();

// Simple typedef: typedef int Integer;
let typedef = HirTypedef::new("Integer".to_string(), HirType::Int);
let code = codegen.generate_typedef(&typedef).unwrap();
assert!(code.contains("type Integer = i32"));

// Pointer typedef: typedef int* IntPtr;
let typedef = HirTypedef::new("IntPtr".to_string(), HirType::Pointer(Box::new(HirType::Int)));
let code = codegen.generate_typedef(&typedef).unwrap();
assert!(code.contains("type IntPtr = *mut i32"));
Source

pub fn generate_constant(&self, constant: &HirConstant) -> String

Generate a constant declaration from HIR.

Transforms C #define macro constants to Rust const declarations. C #define constants are compile-time text substitutions that map naturally to Rust’s const with compile-time evaluation.

§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirConstant, HirType, HirExpression};

let codegen = CodeGenerator::new();

// Integer constant: #define MAX 100 → const MAX: i32 = 100;
let constant = HirConstant::new(
    "MAX".to_string(),
    HirType::Int,
    HirExpression::IntLiteral(100),
);
let code = codegen.generate_constant(&constant);
assert!(code.contains("const MAX: i32 = 100"));

// String constant: #define MSG "Hello" → const MSG: &str = "Hello";
let constant = HirConstant::new(
    "MSG".to_string(),
    HirType::Pointer(Box::new(HirType::Char)),
    HirExpression::StringLiteral("Hello".to_string()),
);
let code = codegen.generate_constant(&constant);
assert!(code.contains("const MSG: &str = \"Hello\""));
§Safety

This transformation introduces 0 unsafe blocks, maintaining the goal of <5 unsafe blocks per 1000 LOC.

Reference: K&R §4.11, ISO C99 §6.10.3

Source

pub fn generate_global_variable( &self, variable: &HirConstant, _is_static: bool, is_extern: bool, is_const: bool, ) -> String

Generate a global variable declaration with storage class specifiers.

Transforms C global variables with storage classes to appropriate Rust declarations:

  • staticstatic mut (mutable static)
  • externextern "C" { static }
  • constconst
  • static constconst (const is stronger than static)
  • Plain global → static mut (default to mutable)
§Examples
use decy_codegen::CodeGenerator;
use decy_hir::{HirConstant, HirType, HirExpression};

let codegen = CodeGenerator::new();

// static int counter = 0; → static mut counter: i32 = 0;
let global = HirConstant::new(
    "counter".to_string(),
    HirType::Int,
    HirExpression::IntLiteral(0),
);
let code = codegen.generate_global_variable(&global, true, false, false);
assert!(code.contains("static mut counter: i32 = 0"));
§Arguments
  • variable - The HIR constant representing the global variable
  • is_static - Whether the variable has static storage class
  • is_extern - Whether the variable has extern storage class
  • is_const - Whether the variable has const qualifier
§Safety

Note: static mut in Rust requires unsafe blocks to access, which increases unsafe usage. However, this is necessary to preserve C semantics for mutable globals.

Reference: ISO C99 §6.7.1 (Storage-class specifiers), K&R §4.2

Trait Implementations§

Source§

impl Clone for CodeGenerator

Source§

fn clone(&self) -> CodeGenerator

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CodeGenerator

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CodeGenerator

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.