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

100% Statements 29/29
93.75% Branches 15/16
100% Functions 1/1
100% Lines 29/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                                                          13x           799x 799x     799x   799x     799x     799x     799x         799x         799x   1x 1x   1x 1x     798x       799x     799x     799x 780x           775x 775x 775x 775x   775x     775x 4x 4x 4x             771x              
/**
 * 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`;
 
  // 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;