All files / transpiler/output/codegen/generators/declarationGenerators FunctionGenerator.ts

100% Statements 26/26
100% Branches 10/10
100% Functions 1/1
100% Lines 26/26

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                                                          28x           949x 949x     949x   949x     949x     949x     949x         949x         949x   1x 1x   1x 1x     948x       949x     949x     949x 920x           915x 915x 915x 915x   915x   915x   915x              
/**
 * 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.
 */
import * as Parser from "../../../../logic/parser/grammar/CNextParser";
import IGeneratorInput from "../IGeneratorInput";
import IGeneratorState from "../IGeneratorState";
import IGeneratorOutput from "../IGeneratorOutput";
import IOrchestrator from "../IOrchestrator";
import TGeneratorFn from "../TGeneratorFn";
 
/**
 * 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<Parser.FunctionDeclarationContext> = (
  node: Parser.FunctionDeclarationContext,
  _input: IGeneratorInput,
  _state: IGeneratorState,
  orchestrator: IOrchestrator,
): IGeneratorOutput => {
  const returnType = orchestrator.generateType(node.type());
  const name = node.IDENTIFIER().getText();
 
  // Issue #269: Set current function name for pass-by-value lookup
  orchestrator.setCurrentFunctionName(name);
  // Issue #477: Set return type for enum inference in return statements
  orchestrator.setCurrentFunctionReturnType(node.type().getText());
 
  // Track parameters for ADR-006 pointer semantics
  orchestrator.setParameters(node.parameterList() ?? null);
 
  // ADR-016: Clear local variables and mark that we're in a function body
  orchestrator.enterFunctionBody();
 
  // Check for main function with args parameter (u8 args[][] or string args[])
  const isMainWithArgs = orchestrator.isMainFunctionWithArgs(
    name,
    node.parameterList(),
  );
 
  let params: string = ""; // Will be set below
  let actualReturnType: string;
 
  // Issue #268: Generate body FIRST to track parameter modifications,
  // then generate parameter list using that tracking info
  if (isMainWithArgs) {
    // Special case: main(u8 args[][]) -> int main(int argc, char *argv[])
    actualReturnType = "int";
    params = "int argc, char *argv[]";
    // Store the args parameter name for translation in the body
    const argsParam = node.parameterList()!.parameter()[0];
    orchestrator.setMainArgsName(argsParam.IDENTIFIER().getText());
  } else {
    // For main() without args, always use int return type for C++ compatibility
    actualReturnType = name === "main" ? "int" : returnType;
  }
 
  // Generate body first (this populates modifiedParameters)
  const body = orchestrator.generateBlock(node.block());
 
  // 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 = node.parameterList()
      ? orchestrator.generateParameterList(node.parameterList()!)
      : "void";
  }
 
  // ADR-016: Clear local variables and mark that we're no longer in a function body
  orchestrator.exitFunctionBody();
  orchestrator.setCurrentFunctionName(null); // Issue #269: Clear function name
  orchestrator.setCurrentFunctionReturnType(null); // Issue #477: Clear return type
  orchestrator.clearParameters();
 
  const functionCode = `${actualReturnType} ${name}(${params}) ${body}\n`;
 
  orchestrator.recordCallbackTypedef(name);
 
  return {
    code: functionCode,
    effects: [],
  };
};
 
export default generateFunction;