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 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 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_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], ) -> String

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

Takes the HIR function, its annotated signature, and struct definitions to generate Rust code with proper lifetime annotations and field type awareness for null pointer detection.

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

Generate an enum definition from HIR.

Generates Rust enum code with automatic derives for Debug, Clone, Copy, PartialEq, Eq. Supports both simple enums and enums with explicit integer values.

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.