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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | 1315x 15477x 17501x 16894x 296x 163x 163x 1x 1x 3x 3x 107x 107x 2x 2x 2x 1x 1x 2x 2x 1x 1x 2x 2x 1x 1x 7x 7x 4x 4x 1x 1x 1x 1x 1666x 1x 4x 1212x 166x 17x 165x 154x 5428x 30x 159x 158x 1x 1x 1x 225x 86x 86x 86x 2x 2x 2x 2x 86x 2x 2x 84x 86x 16x 16x 2x 1228x 1225x 1297x 1225x 415x 810x 800x 10x 10x 9x 9x 810x 439x 2454x 333x 2455x 1228x 1228x 1228x 1228x 1225x 1225x 1225x 1225x 1231x 1228x 11x 11x 11x 2x 9x 301x 24x 24x 10x 14x 14x 87x 482x 1244x 220x 13x 43x 23x 25x 28x 27x 91x 153x 1225x 1228x 116x 130x 1x 1x 9x 9x 9x 9x | /**
* C-Next Code Generator
* Transforms C-Next AST to clean, readable C code
*/
import type IFloatBitWrite from "../../../types/IFloatBitWrite";
import ReservedCnxName from "../../../utils/ReservedCnxName";
// Issue #60: BITMAP_SIZE and BITMAP_BACKING_TYPE moved to SymbolCollector
import TTypeInfo from "../../../types/TTypeInfo";
import IOrchestrator from "./generators/IOrchestrator";
import IGeneratorInput from "./generators/IGeneratorInput";
import IGeneratorState from "./generators/IGeneratorState";
import TGeneratorEffect from "./generators/TGeneratorEffect";
// Expression generators
// Statement generators
import atomicGenerators from "./generators/statements/AtomicGenerator";
// Declaration generators
// ADR-065: Extracted utilities
import CppNamespaceUtils from "../../../utils/CppNamespaceUtils";
import FormatUtils from "../../../utils/FormatUtils";
import StringUtils from "../../../utils/StringUtils";
import invariant from "../../../utils/invariant";
// Support generators
// ADR-046: which nullable C functions return a struct pointer (#1322: a
// constant lookup, not an analyzer -- see the module header)
// ADR-006: Helper for building member access chains with proper separators
// ADR-065: Assignment decomposition (Phase 2)
// IHandlerDeps removed - handlers now use this.state.generator directly
// Issue #644: Extracted string length counter for strlen caching optimization
// Issue #644: C/C++ mode helper for consolidated mode-specific patterns
// Issue #644: Array dimension parsing helper for consolidation
// Issue #644: Member chain analyzer for bit access pattern detection
// Issue #644: Float bit write helper for shadow variable pattern
import FloatBitHelper from "./helpers/FloatBitHelper";
// Issue #644: String declaration helper for bounded/array/concat strings
// Note: StringDeclHelper is now used via VariableDeclHelper
// Issue #794: Argument generation helper for ADR-006 semantics
// Issue #644: Enum assignment validator for type-safe enum assignments
// Issue #644: Array initialization helper for size inference and fill-all
// Note: ArrayInitHelper is now used via VariableDeclHelper
// Issue #644: Assignment expected type resolution helper
// PR #715: C++ member conversion helper for improved testability
// PR #715: Boolean conversion helper for improved testability
// PR #715: C++ constructor detection helper for improved testability
// PR #715: Set/Map utilities for improved testability
// PR #715: Symbol lookup utilities for improved testability
import SymbolLookupHelper from "./helpers/SymbolLookupHelper";
// Issue #644: Assignment validation coordinator helper
// Issue #696: Variable modifier extraction helper
// Note: VariableModifierBuilder is now used via VariableDeclHelper
// Issue #792: Variable declaration helper
// String operation detection and extraction
// PR #681: Extracted separator and dereference resolution utilities
// SonarCloud S3776: Extracted helpers for assignment target generation
// Issue #707: Expression unwrapping utility for reducing duplication
// Stateless parser utilities extracted from CodeGenerator
// Phase 3: Type generation helper for improved testability
import type IPlannedFunctionParameter from "./types/IPlannedFunctionParameter";
// Phase 5: Cast validation helper for improved testability
// Issue #793: Function context lifecycle and parameter processing helper
import FunctionContextManager from "./helpers/FunctionContextManager";
import IFunctionContextCallbacks from "./types/IFunctionContextCallbacks";
// Global state for code generation (simplifies debugging, eliminates DI complexity)
import TypeCheckUtils from "../../../utils/TypeCheckUtils";
import CallbackTypedefFormatter from "./helpers/CallbackTypedefFormatter";
// Issue #269: Pass-by-value analysis extracted from CodeGenerator
import PassByValueAnalyzer from "../../2-Plan/PassByValueAnalyzer";
// Unified parameter generation (Phase 1)
// Issue #895: Parse typedef signatures to determine pointer vs value params
// Extracted resolvers that use CodeGenState
// Issue #797: Centralized C-style name generation
import type IRecordedRequirement from "../../../types/IRecordedRequirement";
import ToolchainRequirements from "../../../instrumentation/ToolchainRequirements";
import TranspileState from "../../TranspileState";
/**
* Code Generator - Transpiles C-Next to C
*
* Implements IOrchestrator to support modular generator extraction.
*/
export default class CodeGenerator implements IOrchestrator {
/**
* 2.3 Render's per-file working state (#1452 box 4). Owned here because the
* walker reaches this object as `this.host`, so one instance serves both
* without a global between them.
*/
readonly state = new TranspileState();
// ===========================================================================
// IOrchestrator Implementation
// ===========================================================================
/**
* Get read-only input context for generators.
* Contains all the information generators need to produce code.
*/
getInput(): IGeneratorInput {
return {
symbolTable: this.state.symbolTable,
symbols: this.state.symbols,
functionSignatures: this.state.functionSignatures,
knownFunctions: this.state.knownFunctions,
knownStructs: this.state.symbols?.knownStructs ?? new Set(),
callbackTypes: this.state.callbackTypes,
callbackFieldTypes: this.state.callbackFieldTypes,
debugMode: this.state.debugMode,
};
}
/**
* Get a snapshot of the current generation state.
* Represents where we are in the AST traversal.
*/
getState(): IGeneratorState {
return {
currentScopePath: this.state.currentScopePath,
indentLevel: this.state.indentLevel,
inFunctionBody: this.state.inFunctionBody,
currentParameters: this.state.currentParameters,
localVariables: this.state.localVariables,
expectedType: this.state.expectedType,
headerOwnsTypeDefinitions:
this.state.declarationPlan().headerOwnsTypeDefinitions, // #369/#1450
// Issue #644: Postfix expression state
scopeMembers: this.state.getAllScopeMembers(),
mainArgsName: this.state.mainArgsName,
floatBitShadows: this.state.floatBitShadows,
floatShadowCurrent: this.state.floatShadowCurrent,
lengthCache: this.state.lengthCache,
};
}
/**
* Process effects returned by generators, updating internal state.
* This centralizes all side-effect handling.
*/
applyEffects(effects: readonly TGeneratorEffect[]): void {
for (const effect of effects) {
switch (effect.type) {
// Include effects - delegate to requireInclude()
case "include":
this.state.requireInclude(effect.header, effect.line ?? null);
break;
case "isr":
this.state.requireInclude("isr");
break;
// Toolchain requirement effects (Issue #1143)
case "requires":
ToolchainRequirements.record(effect.key, [
{ sourcePath: this.state.sourcePath ?? "", line: effect.line },
]);
break;
// Helper function effects
case "helper":
// Route through the single marker rather than writing the set
// directly, so helper-op bookkeeping has one entry point (#1143).
this.state.markClampOpUsed(effect.operation, effect.cnxType);
break;
case "safe-div":
// Internal helper-op key, not a scope-qualified C name
this.state.usedSafeDivOps.add(
`${effect.operation}_${effect.cnxType}`,
);
// ADR-051 safe-div helpers return a bool error flag. Route that
// dependency through the single include path (#1108) rather than
// letting the helper emit its own #include <stdbool.h>.
this.state.requireInclude("stdbool");
break;
// #1452 box 2: three "type registration" effects stood here --
// `register-type`, `register-local`, `register-const-value` -- and NO
// generator emitted any of them (`grep` for each literal outside this
// switch and the union: 0). They were a render-side write path into the
// per-file type registry that never ran, so they read as 2.3 authoring
// a plan fact while authoring nothing at all. Removed with their union
// members; the two effects that ARE emitted keep their arms.
// Scope effects (ADR-016)
case "set-scope":
this.state.setCurrentScopeByPath(effect.name);
break;
// Function body effects
case "enter-function-body":
this.state.enterFunctionBody();
break;
case "exit-function-body":
this.state.exitFunctionBody();
break;
case "set-parameters":
this.state.currentParameters = new Map(effect.params);
break;
case "clear-parameters":
this.state.currentParameters.clear();
break;
// Callback effects
case "register-callback-field":
this.state.callbackFieldTypes.set(effect.key, effect.typeName);
break;
case "register-struct-init":
this.state.generatedStructInits.add(effect.structName);
break;
// Array initializer effects
case "set-array-init-count":
this.state.lastArrayInitCount = effect.count;
break;
case "set-array-fill-value":
this.state.lastArrayFillValue = effect.value;
break;
}
}
}
/**
* Issue #1143: Snapshot the toolchain requirements recorded during the last
* generate() call.
*
* Must be read before the next file's this.state.reset(), which clears the
* recording map.
*/
getToolchainRequirements(): readonly IRecordedRequirement[] {
return ToolchainRequirements.collect();
}
/**
* Get the current indentation string.
*/
getIndent(): string {
return FormatUtils.indent(this.state.indentLevel);
}
/**
* Resolve an identifier to its fully-scoped name.
* Part of IOrchestrator interface.
* ADR-016: Inside a scope, checks if the identifier is a scope member first.
* Otherwise returns the identifier unchanged (global scope).
*/
resolveIdentifier(identifier: string): string {
// Delegates to CodeGenState, which owns scope membership. This method used to
// be a byte-identical copy of this.state.resolveIdentifier, so the two
// could drift apart silently.
return this.state.resolveIdentifier(identifier);
}
// === Expression Generation ===
// === Type Utilities ===
/**
* Check if a type name is a known struct.
* Part of IOrchestrator interface.
*/
isKnownStruct(typeName: string): boolean {
return this.state.isKnownStruct(typeName);
}
/**
* Check if a type is a float type.
* Part of IOrchestrator interface - delegates to TypeCheckUtils.
*/
isFloatType(typeName: string): boolean {
return TypeCheckUtils.isFloat(typeName);
}
/**
* Check if a type is an integer type.
* Part of IOrchestrator interface - delegates to TypeCheckUtils.
*/
isIntegerType(typeName: string): boolean {
return TypeCheckUtils.isInteger(typeName);
}
/**
* Check if a function is defined in C-Next.
* Part of IOrchestrator interface.
*/
isCNextFunction(name: string): boolean {
return SymbolLookupHelper.isCNextFunctionCombined(
this.state.knownFunctions,
this.state.symbolTable,
name,
);
}
// === Expression Analysis ===
// === Validation ===
// === Function Call Helpers ===
/**
* Get known enums set for pass-by-value detection.
* Part of IOrchestrator interface.
*/
getKnownEnums(): ReadonlySet<string> {
return this.state.symbols!.knownEnums;
}
/**
* Issue #304: Check if we're generating C++ output.
* Part of IOrchestrator interface.
*/
isCppMode(): boolean {
return this.state.cppMode;
}
/**
* Issue #304: Check if a type is a C++ enum class (scoped enum).
* These require explicit casts to integer types in C++.
* Part of IOrchestrator interface.
*/
isCppEnumClass(typeName: string): boolean {
return SymbolLookupHelper.isCppEnumClass(this.state.symbolTable, typeName);
}
/**
* Issue #250: Flush pending temp variable declarations.
* Returns declarations as a single string and clears the pending list.
* Part of IOrchestrator interface.
*/
flushPendingTempDeclarations(): string {
if (this.state.pendingTempDeclarations.length === 0) {
return "";
}
const decls = this.state.pendingTempDeclarations.join("\n");
this.state.pendingTempDeclarations = [];
return decls;
}
/**
* Get indentation string for current level.
* Part of IOrchestrator interface.
*/
indent(text: string): string {
return FormatUtils.indentAllLines(text, this.state.indentLevel);
}
// === strlen Optimization ===
/**
* Setup length cache and return declarations.
* Part of IOrchestrator interface.
*/
setupLengthCache(counts: Map<string, number>): string {
const declarations: string[] = [];
const cache = new Map<string, string>();
for (const [varName, count] of counts) {
Eif (count >= 2) {
const tempVar = ReservedCnxName.stringLengthCache(varName);
cache.set(varName, tempVar);
declarations.push(`size_t ${tempVar} = strlen(${varName});`);
}
}
if (declarations.length > 0) {
this.state.lengthCache = cache;
return declarations.join("\n") + "\n";
}
return "";
}
/**
* Clear length cache.
* Part of IOrchestrator interface.
*/
clearLengthCache(): void {
this.state.lengthCache = null;
}
/**
* Register a local variable.
* Part of IOrchestrator interface.
*/
registerLocalVariable(name: string): string {
this.state.registerLocalVariable(name);
return this.state.emittedLocalName(name);
}
// === Declaration Generation ===
// #1322: the `Validation (IOrchestrator A4)` section that stood here held
// ADR-024's `validateLiteralFitsType` and `validateTypeConversion`. Both are
// E0868/E0869 in pass 2.1, and no generator asks the orchestrator for them.
// === String Helpers (IOrchestrator A4) ===
/** Get the length of a string literal */
getStringLiteralLength(literal: string): number {
return StringUtils.literalLength(literal);
}
// #1445 box 3: `getStringConcatOperands` and `getSubstringOperands` stood
// here as public delegates to the `_`-prefixed pair below. Their only
// reachable caller was `IOrchestrator`, and no generator ever called either
// -- so removing the declarations left them dead, which `knip` reported
// (#1556's `classMembers`, doing exactly what it was added for). The private
// originals keep their in-file callers.
// === Parameter Management (IOrchestrator A4) ===
/** Set current function parameters */
setParameters(parameters: readonly IPlannedFunctionParameter[] | null): void {
FunctionContextManager.processParameterList(
parameters,
this._getFunctionContextCallbacks(),
this.state,
);
}
/** Clear current function parameters */
clearParameters(): void {
this._clearParameters();
}
/**
* Issue #1200: the `_fp` typedef name for a callback type, or null if the
* name is not one. Exposed so renderers do not re-derive the `${name}_fp`
* convention that registerCallbackType owns.
*/
getCallbackTypedefName(typeName: string): string | null {
return this.state.callbackTypes.get(typeName)?.typedefName ?? null;
}
/**
* ADR-029 / Issues #1201, #1212: record that this function needs a callback
* `_fp` typedef, if it does.
*
* The single owner of that decision. It was previously spelled out at each of
* the four sites that emit a function -- two here, plus FunctionGenerator and
* ScopeGenerator -- so deferring the typedefs meant changing all four, and
* missing one left a whole construct still emitting inline. Every caller now
* states the intent ("this function was emitted") and nothing re-derives the
* consequences.
*/
recordCallbackTypedef(funcName: string): void {
if (funcName === "main") {
return;
}
if (!this.isCallbackTypeReferenced(funcName)) {
return;
}
const typedef = this.generateCallbackTypedef(funcName);
if (typedef) {
this.state.pendingCallbackTypedefs.push(typedef);
this.state.emittedCallbackTypedefs.add(funcName);
}
}
private isCallbackTypeReferenced(funcName: string): boolean {
return this.state.callbackTypeReferences.has(funcName);
}
// #1322: `isCallbackTypeUsedAsFieldType` stood here, answering ADR-029's
// nominal-typing question by scanning `this.state.callbackFieldTypes`.
// That map holds the structs emitted SO FAR in the current file, so a struct
// declared below the assignment, in an enclosing scope, or in an include did
// not count -- the identity of a type depending on emission order. Pass 2.1
// asks `this.state.symbols.structFields`, the per-file view, which holds
// every struct the file can see before any code is generated.
// === Scope Management (A4) ===
setCurrentScope(name: string | null): void {
// The assignment was written twice on main; the second was dead.
this.state.setCurrentScopeByPath(name);
}
/**
* Issue #269: Set the current function name for pass-by-value lookup.
* Part of IOrchestrator interface.
*/
setCurrentFunctionName(name: string | null): void {
this.state.currentFunctionName = name;
}
/**
* Issue #477: Get the current function's return type for enum inference.
* Used by return statement generation to set expectedType.
*/
getCurrentFunctionReturnType(): string | null {
return this.state.currentFunctionReturnType;
}
/**
* Issue #477: Set the current function's return type for enum inference.
*/
setCurrentFunctionReturnType(returnType: string | null): void {
this.state.currentFunctionReturnType = returnType;
}
/**
* #1277: the four facts a function body is generated against, set and
* cleared as one. See `IOrchestrator` for why this is a pair rather than
* four calls repeated at each site.
*/
enterFunctionContext(
name: string,
returnTypeText: string,
parameters: readonly IPlannedFunctionParameter[] | null,
): void {
this.setCurrentFunctionName(name);
this.setCurrentFunctionReturnType(returnTypeText);
this.setParameters(parameters);
this.enterFunctionBody();
}
exitFunctionContext(): void {
this.exitFunctionBody();
this.setCurrentFunctionName(null);
this.setCurrentFunctionReturnType(null);
this.clearParameters();
}
// === Function Body Management (A4) ===
/**
* Enter function body - clears local variables and sets inFunctionBody flag.
* Issue #793: Delegates to FunctionContextManager.
*/
enterFunctionBody(): void {
FunctionContextManager.enterFunctionBody(this.state);
}
/**
* Exit function body - clears local variables and inFunctionBody flag.
* Issue #793: Delegates to FunctionContextManager.
*/
exitFunctionBody(): void {
FunctionContextManager.exitFunctionBody(this.state);
}
/**
* ADR-029: Generate typedef for callback type
*/
generateCallbackTypedef(funcName: string): string | null {
const callbackInfo = this.state.callbackTypes.get(funcName);
Iif (!callbackInfo) {
return null;
}
// Issue #1164: the included header already declares this one.
if (
this.state.declarationPlan().headerOwnsTypeDefinitions &&
this.state.headerOwnsCallbackTypedef(funcName)
) {
return null;
}
// Bare, with no padding of its own: the splice in generateAllDeclarations
// decides the blank lines around the whole block, so one place owns the
// layout instead of each typedef guessing at it.
return CallbackTypedefFormatter.format(
callbackInfo.returnType,
callbackInfo.typedefName,
callbackInfo.parameters,
this.isCppMode(),
);
}
/**
* Issue #268: Get unmodified parameters info for all functions.
* Returns map of function name -> Set of unmodified parameter names.
* Computed on-demand from functionSignatures and modifiedParameters.
*/
getFunctionUnmodifiedParams(): ReadonlyMap<string, Set<string>> {
return this.state.getUnmodifiedParameters();
}
/**
* Issue #268: Update symbol parameters with auto-const info.
* Now a no-op - unmodified params are computed on-demand from this.state.
* Kept for IOrchestrator interface compatibility.
*/
updateFunctionParamsAutoConst(_functionName: string): void {
// No-op: Unmodified parameters are now computed on-demand from
// this.state.functionSignatures and this.state.modifiedParameters
// via this.state.getUnmodifiedParameters().
}
/**
* Issue #268: Mark a parameter as modified for auto-const tracking.
* Issue #558: Now a no-op - analysis phase handles all modification tracking
* including transitive propagation across function calls and files.
*/
markParameterModified(_paramName: string): void {
// No-op: Analysis phase (analyzePassByValue) now handles all modification
// tracking including cross-file and transitive propagation.
}
/**
* Issue #268: Check if a callee function's parameter at given index is modified.
* Returns true if the callee modifies that parameter (should not have const).
*/
isCalleeParameterModified(funcName: string, paramIndex: number): boolean {
// Get the parameter name at the given index from the function signature
const sig = this.state.functionSignatures.get(funcName);
if (!sig || paramIndex >= sig.parameters.length) {
// Callee not yet processed - conservatively return false (assume unmodified)
return false;
}
const paramName = sig.parameters[paramIndex].name;
// Check directly if the parameter is in the modified set
return this.state.isParameterModified(funcName, paramName);
}
/**
* Issue #268: Check if a name is a parameter of the current function.
*/
isCurrentParameter(name: string): boolean {
return this.state.currentParameters.has(name);
}
// === Postfix Expression Helpers (Issue #644) ===
/**
* Check if a name is a known scope.
* Part of IOrchestrator interface.
*/
isKnownScope(name: string): boolean {
return SymbolLookupHelper.isKnownScope(
this.state.symbols?.knownScopes,
this.state.symbolTable,
name,
);
}
/**
* Check if a symbol is a C++ scope symbol (namespace, class, enum).
* Part of IOrchestrator interface.
*/
isCppScopeSymbol(name: string): boolean {
return CppNamespaceUtils.isCppNamespace(
name,
this.state.symbolTable ?? undefined,
);
}
/**
* Get the separator for scope access (:: for C++, _ for C-Next).
* Part of IOrchestrator interface - delegates to FormatUtils.
*/
getScopeSeparator(isCppAccess: boolean): string {
return FormatUtils.getScopeSeparator(isCppAccess);
}
/**
* Get member type info for struct access chains.
* Part of IOrchestrator interface.
*
* Delegated for the same reason, plus #1127: this copy still dropped a
* non-numeric dimension with `filter(typeof d === "number")` instead of
* mapping it to `UNRESOLVED_DIMENSION`, which shifts every dimension after it
* -- so `u8[EColor.COUNT][3]` came back as `[3]` and put dimension 2's bound
* in dimension 1's slot. Both defects were fixed once on the state and left
* standing here.
*/
getMemberTypeInfo(structType: string, memberName: string): TTypeInfo | null {
return this.state.getMemberTypeInfo(structType, memberName);
}
/**
* Add a pending temp variable declaration (for float bit indexing).
* Part of IOrchestrator interface.
*/
addPendingTempDeclaration(declaration: string): void {
this.state.pendingTempDeclarations.push(declaration);
}
/**
* Register a float bit shadow variable.
* Part of IOrchestrator interface.
*/
registerFloatBitShadow(shadowName: string): void {
this.state.floatBitShadows.add(shadowName);
}
/**
* Mark a float shadow as having current value (skip redundant memcpy).
* Part of IOrchestrator interface.
*/
markFloatShadowCurrent(shadowName: string): void {
this.state.floatShadowCurrent.add(shadowName);
}
/**
* Check if a float shadow has been declared.
* Part of IOrchestrator interface.
*/
hasFloatBitShadow(shadowName: string): boolean {
return this.state.floatBitShadows.has(shadowName);
}
/**
* Check if a float shadow has current value.
* Part of IOrchestrator interface.
*/
isFloatShadowCurrent(shadowName: string): boolean {
return this.state.floatShadowCurrent.has(shadowName);
}
/**
* ADR-030: whether a declaration of this type is held through a pointer.
* Part of IOrchestrator interface.
*/
isHeldThroughPointer(typeName: string): boolean {
return this.state.isHeldThroughPointer(typeName);
}
// ===========================================================================
// End IOrchestrator Implementation
// ===========================================================================
// Issue #63: validateIncludeNotImplementationFile moved to TypeValidator
// Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
// Issue #63: validateBitmapFieldLiteral moved to TypeValidator
// Issue #60: evaluateConstantExpression method removed - now in SymbolCollector
// Issue #269: Pass-by-value analysis extracted to PassByValueAnalyzer
/**
* Issue #269: Check if a parameter should be passed by value (by index).
* Part of IOrchestrator interface - used by CallExprGenerator.
* Delegates to PassByValueAnalyzer.
*/
isParameterPassByValue(funcName: string, paramIndex: number): boolean {
return PassByValueAnalyzer.isParameterPassByValue(
funcName,
paramIndex,
this.state,
);
}
/**
* Clear parameter tracking when leaving a function.
* Issue #793: Delegates to FunctionContextManager.
*/
private _clearParameters(): void {
FunctionContextManager.clearParameters(this.state);
}
// ========================================================================
// ADR-024: Type Classification and Validation Helpers
// ========================================================================
// NOTE: Public isIntegerType and isFloatType moved to IOrchestrator interface
// Private versions kept for internal use
// ========================================================================
// Declarations
// ========================================================================
// ========================================================================
// Scope (ADR-016: Organization with visibility control)
// ========================================================================
// ========================================================================
// Register Bindings (ADR-004)
// ========================================================================
// ========================================================================
// Struct
// ========================================================================
// ========================================================================
// Enum (ADR-017: Type-safe enums)
// ========================================================================
// ========================================================================
// Functions
// ========================================================================
/**
* Issue #793: Create callbacks for FunctionContextManager.
*/
private _getFunctionContextCallbacks(): IFunctionContextCallbacks {
return {
isKnownStruct: (typeName: string) => this.isKnownStruct(typeName),
};
}
// ========================================================================
// Variables
// ========================================================================
// ========================================================================
// Variable declaration planning (#1445 box 3)
// ========================================================================
// Issue #792 extracted a batch of variable-declaration methods to
// `VariableDeclHelper`. #1445 box 3 split that batch again, by what each one
// does: the tree-reading half came back as the `plan*` methods above and the
// rendering half stayed there.
//
// The list this comment used to enumerate named nine methods, one of which
// (`_validateArrayDeclarationSyntax`) had not existed since its rejection
// moved to 2.1 as E0874. A list of names is wrong the moment anything moves,
// and nothing checks it -- which is why it is a sentence now.
/**
* Brace initializer that zero-initializes an aggregate (struct or array).
* Issue #379 / #1004: C++ uses value-initialization ({}), which is valid for
* any aggregate element type (POD, struct, class) including enum-first
* structs where {0} is an invalid int->enum narrowing; C uses {0}.
*/
getAggregateZeroInitBrace(): string {
return this.state.cppMode ? "{}" : "{0}";
}
/**
* Generate float bit write using shadow variable + memcpy.
* Issue #644: Delegates to FloatBitHelper.
*/
/** Public for handler access via this.state.generator */
/**
* Dispatched through `ICodeGenApi` via `this.state.requireGenerator()`, so
* no call site ever names this class. knip cannot follow that indirection.
*
* @public
*/
generateFloatBitWrite(bitWrite: IFloatBitWrite): string {
// Issue #644: FloatBitHelper is now static, pass callbacks
return FloatBitHelper.generateFloatBitWrite(
bitWrite,
{
requireInclude: (header) => this.state.requireInclude(header),
},
this.state,
);
}
// ADR-001: <- becomes = in C, with compound assignment operators
/**
* ADR-049: Generate atomic Read-Modify-Write operation
* Uses LDREX/STREX on platforms that support it, otherwise PRIMASK
*/
/** Public for handler access via this.state.generator */
/**
* Dispatched through `ICodeGenApi` via `this.state.requireGenerator()`, so
* no call site ever names this class. knip cannot follow that indirection.
*
* @public
*/
generateAtomicRMW(
target: string,
cOp: string,
value: string,
typeInfo: TTypeInfo,
clampOp: string | null,
): string {
invariant(
this.state.targetDescription,
"generate() sets the target before any statement is rendered",
);
const result = atomicGenerators.generateAtomicRMW(
target,
cOp,
value,
typeInfo,
clampOp,
this.state.targetDescription,
);
this.applyEffects(result.effects);
return result.code;
}
// #1322: ADR-016's access rules are E0435-E0437 in pass 2.1; `ScopeResolver`
// is gone with them.
// Issue #387: Dead methods removed (generateGlobalMemberAccess, generateGlobalArrayAccess,
// generateThisMemberAccess, generateThisArrayAccess) - now handled by unified doGenerateAssignmentTarget
// ========================================================================
// ADR-025/027/036/068 control-flow planning (#1445 box 3)
// ========================================================================
// ========================================================================
// Critical Statements (ADR-050)
// ========================================================================
// Issue #63: validateNoEarlyExits moved to TypeValidator
// ========================================================================
// Switch Statements (ADR-025)
// ========================================================================
// ========================================================================
// Expressions
// ========================================================================
// #1322: the shift-amount check (MISRA 12.2, E0873) that Issue #63 moved
// to TypeValidator is in pass 2.1, with the additive-type helpers that
// existed only to feed it.
// NOTE: generateMemberAccess and generateArrayAccess removed in grammar consolidation
// These methods referenced MemberAccessContext and ArrayAccessContext which no longer
// exist after unifying to assignmentTarget: IDENTIFIER postfixTargetOp*
// ========================================================================
// strlen Optimization - Cache repeated .length accesses
// Issue #644: Walker methods extracted to StringLengthCounter class
// ========================================================================
// ========================================================================
// Preprocessor Directive Handling (ADR-037)
// ========================================================================
// ========================================================================
// Comment Handling (ADR-043)
// Delegates to CommentUtils
// ========================================================================
}
|