All files / TRANSPILE/3-Render/codegen/generators/declarationGenerators FunctionGenerator.ts

100% Statements 13/13
100% Branches 4/4
100% Functions 1/1
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103                                                                    46x           1042x         1042x                         1042x             1042x                       1042x     1042x     1042x 1038x         1039x   1039x   1039x   1039x              
/**
 * FunctionGenerator - Function Declaration Generation
 *
 * Generates C function declarations from C-Next function syntax.
 *
 * Example:
 *   fn add(i32 a, i32 b) -> i32 { return a + b; }
 *   ->
 *   int32_t add(int32_t* a, int32_t* b) { return *a + *b; }
 *
 * ADR-006: Pass-by-reference semantics for non-array, non-float parameters.
 * ADR-029: Callback typedef generation for functions used as types.
 *
 * #1445 box 3: takes `IPlannedFunction`, not the node. What this generator
 * does is SEQUENCE -- enter, body, auto-const, signature, exit -- and it read
 * the node only to hand each piece straight to the orchestrator.
 */
import IGeneratorInput from "../IGeneratorInput";
import IGeneratorState from "../IGeneratorState";
import IGeneratorOutput from "../IGeneratorOutput";
import IOrchestrator from "../IOrchestrator";
import TGeneratorFn from "../TGeneratorFn";
import FunctionContextManager from "../../helpers/FunctionContextManager";
import type IPlannedFunction from "../../types/IPlannedFunction";
 
/**
 * Generate a C function from a C-Next function declaration.
 *
 * Handles:
 * - Return type generation
 * - Parameter generation with ADR-006 pointer semantics
 * - Main function special cases (args parameter, int return type)
 * - Callback typedef generation (ADR-029)
 */
const generateFunction: TGeneratorFn<IPlannedFunction> = (
  planned: IPlannedFunction,
  _input: IGeneratorInput,
  _state: IGeneratorState,
  orchestrator: IOrchestrator,
): IGeneratorOutput => {
  const { name, isMainWithArgs } = planned;
 
  // Issues #269/#477, ADR-016: name for pass-by-value lookup, return type for
  // typing `return` expressions, parameters for ADR-006 pointer semantics, and
  // the fresh local registers -- one call, shared with ScopeGenerator.
  orchestrator.enterFunctionContext(
    name,
    planned.returnTypeText,
    planned.parameters,
  );
 
  // #1445: this decision was written out here AND in
  // `FunctionContextManager.resolveReturnTypeAndParams`, byte-identical. That
  // method had no caller at all -- not production, not even inside its own
  // file -- so knip could not report it: its three TEST callers count as usage
  // (#1418). One copy was live and inline, the other dead and named. Unified
  // onto the named one, which is the half that has a unit test.
  const { actualReturnType, initialParams } =
    FunctionContextManager.resolveReturnTypeAndParams(
      name,
      planned.returnType,
      isMainWithArgs,
      planned.firstParameterName,
      orchestrator.state,
    );
  let params: string = initialParams;
 
  // Issue #268: render the body FIRST, so the parameter list can see which
  // parameters it modified. That ordering is this generator's whole job,
  // which is why the two renders arrive as thunks rather than as strings.
  //
  // #1641: inverting it reddens 0 of 1259 fixtures -- `ModificationFacts`
  // derives `modifiedParameters` whole-program in 1.4, before any render, so
  // the fact this ordering establishes is already in hand. Kept unchanged:
  // codegen still writes to those maps while it renders, and deleting a
  // constraint on the strength of fixtures that cannot observe it is the
  // reasoning presence-is-not-proof warns about. Filed, not acted on.
  const body = planned.renderBody();
 
  // Issue #268: Update symbol's parameter info with auto-const before clearing
  orchestrator.updateFunctionParamsAutoConst(name);
 
  // Now generate parameter list (can use modifiedParameters for auto-const)
  if (!isMainWithArgs) {
    params = planned.renderParameterList
      ? planned.renderParameterList()
      : "void";
  }
 
  orchestrator.exitFunctionContext();
 
  const functionCode = `${actualReturnType} ${name}(${params}) ${body}\n`;
 
  orchestrator.recordCallbackTypedef(name);
 
  return {
    code: functionCode,
    effects: [],
  };
};
 
export default generateFunction;