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

86.2% Statements 25/29
87.5% Branches 14/16
100% Functions 1/1
86.2% Lines 25/29

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 104 105 106 107 108 109 110 111 112                                                          12x           694x 694x     694x   694x     694x     694x     694x         694x         694x                 694x       694x     694x     694x 678x           678x 678x 678x 678x   678x     678x 3x 3x 3x             675x              
/**
 * 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
  Iif (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`;
 
  // ADR-029: Generate callback typedef only if this function is used as a type
  if (name !== "main" && orchestrator.isCallbackTypeUsedAsFieldType(name)) {
    const typedef = orchestrator.generateCallbackTypedef(name);
    Eif (typedef) {
      return {
        code: functionCode + typedef,
        effects: [],
      };
    }
  }
 
  return {
    code: functionCode,
    effects: [],
  };
};
 
export default generateFunction;