c-next 0.1.69 → 0.1.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -204
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +693 -0
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +86 -5
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/AssignmentTargetExtractor.ts +1 -1
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/ChildStatementCollector.ts +1 -1
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/StatementExpressionCollector.ts +1 -1
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/AssignmentTargetExtractor.test.ts +2 -2
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/ChildStatementCollector.test.ts +2 -2
- package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/StatementExpressionCollector.test.ts +2 -2
- package/src/transpiler/output/codegen/CodeGenerator.ts +35 -607
- package/src/transpiler/output/codegen/TypeRegistrationUtils.ts +4 -6
- package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/TypeValidator.ts +5 -5
- package/src/transpiler/output/codegen/__tests__/TypeRegistrationUtils.test.ts +36 -51
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +20 -17
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +3 -3
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +9 -9
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +12 -12
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +11 -11
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +23 -17
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +3 -3
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +3 -3
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +4 -4
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +5 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +23 -25
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +20 -36
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +18 -18
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +42 -32
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +5 -4
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +21 -4
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +2 -1
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +3 -3
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +7 -7
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +7 -7
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
- package/src/transpiler/state/CodeGenState.ts +122 -4
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +269 -1
- /package/src/transpiler/{output/codegen → logic/analysis}/helpers/TransitiveModificationPropagator.ts +0 -0
- /package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/TransitiveModificationPropagator.test.ts +0 -0
|
@@ -120,20 +120,16 @@ import CodegenParserUtils from "./utils/CodegenParserUtils";
|
|
|
120
120
|
import IMemberSeparatorDeps from "./types/IMemberSeparatorDeps";
|
|
121
121
|
import IParameterDereferenceDeps from "./types/IParameterDereferenceDeps";
|
|
122
122
|
import ISeparatorContext from "./types/ISeparatorContext";
|
|
123
|
-
// Issue #
|
|
124
|
-
import
|
|
125
|
-
// Issue #269: Transitive modification propagation for const inference
|
|
126
|
-
import TransitiveModificationPropagator from "./helpers/TransitiveModificationPropagator";
|
|
127
|
-
// Issue #566: Child statement/block collection for const inference
|
|
128
|
-
import ChildStatementCollector from "./helpers/ChildStatementCollector";
|
|
129
|
-
// SonarCloud S3776: Assignment target extraction for walkStatementForModifications
|
|
130
|
-
import AssignmentTargetExtractor from "./helpers/AssignmentTargetExtractor";
|
|
123
|
+
// Issue #269: Transitive modification propagation for const inference (used by analyzeModificationsOnly)
|
|
124
|
+
import TransitiveModificationPropagator from "../../logic/analysis/helpers/TransitiveModificationPropagator";
|
|
131
125
|
// Phase 3: Type generation helper for improved testability
|
|
132
126
|
import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
|
|
133
127
|
// Phase 5: Cast validation helper for improved testability
|
|
134
128
|
import CastValidator from "./helpers/CastValidator";
|
|
135
129
|
// Global state for code generation (simplifies debugging, eliminates DI complexity)
|
|
136
130
|
import CodeGenState from "../../state/CodeGenState";
|
|
131
|
+
// Issue #269: Pass-by-value analysis extracted from CodeGenerator
|
|
132
|
+
import PassByValueAnalyzer from "../../logic/analysis/PassByValueAnalyzer";
|
|
137
133
|
// Unified parameter generation (Phase 1)
|
|
138
134
|
import ParameterInputAdapter from "./helpers/ParameterInputAdapter";
|
|
139
135
|
import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
|
|
@@ -387,7 +383,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
387
383
|
return {
|
|
388
384
|
symbolTable: CodeGenState.symbolTable,
|
|
389
385
|
symbols: CodeGenState.symbols,
|
|
390
|
-
typeRegistry: CodeGenState.
|
|
386
|
+
typeRegistry: CodeGenState.getTypeRegistryView(),
|
|
391
387
|
functionSignatures: CodeGenState.functionSignatures,
|
|
392
388
|
knownFunctions: CodeGenState.knownFunctions,
|
|
393
389
|
knownStructs: CodeGenState.symbols?.knownStructs ?? new Set(),
|
|
@@ -451,7 +447,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
451
447
|
|
|
452
448
|
// Type registration effects
|
|
453
449
|
case "register-type":
|
|
454
|
-
CodeGenState.
|
|
450
|
+
CodeGenState.setVariableTypeInfo(effect.name, effect.info);
|
|
455
451
|
break;
|
|
456
452
|
case "register-local":
|
|
457
453
|
CodeGenState.localVariables.add(effect.name);
|
|
@@ -727,7 +723,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
727
723
|
|
|
728
724
|
// Check if it's a simple variable of string type
|
|
729
725
|
if (/^[a-zA-Z_]\w*$/.exec(text)) {
|
|
730
|
-
const typeInfo = CodeGenState.
|
|
726
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(text);
|
|
731
727
|
if (typeInfo?.isString) {
|
|
732
728
|
return true;
|
|
733
729
|
}
|
|
@@ -759,7 +755,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
759
755
|
}
|
|
760
756
|
|
|
761
757
|
const arrayName = arrayAccessMatch[1];
|
|
762
|
-
const typeInfo = CodeGenState.
|
|
758
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(arrayName);
|
|
763
759
|
if (!typeInfo) {
|
|
764
760
|
return false;
|
|
765
761
|
}
|
|
@@ -1368,7 +1364,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1368
1364
|
// Variable - check type registry
|
|
1369
1365
|
const identifierRegex = /^[a-zA-Z_]\w*$/;
|
|
1370
1366
|
if (identifierRegex.test(exprCode)) {
|
|
1371
|
-
const typeInfo = CodeGenState.
|
|
1367
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(exprCode);
|
|
1372
1368
|
if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
|
|
1373
1369
|
return typeInfo.stringCapacity;
|
|
1374
1370
|
}
|
|
@@ -1604,7 +1600,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1604
1600
|
const injectedFuncs = new Set(crossFileModifications?.keys() ?? []);
|
|
1605
1601
|
|
|
1606
1602
|
// Run modification analysis on the tree (adds to what was injected)
|
|
1607
|
-
|
|
1603
|
+
PassByValueAnalyzer.collectFunctionParametersAndModifications(tree);
|
|
1608
1604
|
|
|
1609
1605
|
// Issue #565: Run transitive propagation with full context
|
|
1610
1606
|
TransitiveModificationPropagator.propagate(
|
|
@@ -1951,7 +1947,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1951
1947
|
isKnownPrimitive: (typeName: string) => this._isKnownPrimitive(typeName),
|
|
1952
1948
|
knownEnums: CodeGenState.symbols!.knownEnums,
|
|
1953
1949
|
isParameterPassByValue: (funcName: string, paramName: string) =>
|
|
1954
|
-
|
|
1950
|
+
PassByValueAnalyzer.isParameterPassByValueByName(funcName, paramName),
|
|
1955
1951
|
currentFunctionName: CodeGenState.currentFunctionName,
|
|
1956
1952
|
maybeDereference: (id: string) => CppModeHelper.maybeDereference(id),
|
|
1957
1953
|
};
|
|
@@ -2196,7 +2192,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2196
2192
|
private initializeHelperObjects(tree: Parser.ProgramContext): void {
|
|
2197
2193
|
// Collect function/callback information
|
|
2198
2194
|
this.collectFunctionsAndCallbacks(tree);
|
|
2199
|
-
|
|
2195
|
+
PassByValueAnalyzer.analyze(tree);
|
|
2200
2196
|
}
|
|
2201
2197
|
|
|
2202
2198
|
/**
|
|
@@ -2623,581 +2619,15 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2623
2619
|
// Issue #63: validateBitmapFieldLiteral moved to TypeValidator
|
|
2624
2620
|
// Issue #60: evaluateConstantExpression method removed - now in SymbolCollector
|
|
2625
2621
|
|
|
2626
|
-
//
|
|
2627
|
-
// Issue #269: Pass-by-value analysis for small unmodified parameters
|
|
2628
|
-
// ========================================================================
|
|
2629
|
-
|
|
2630
|
-
/**
|
|
2631
|
-
* Analyze all functions to determine which parameters should pass by value.
|
|
2632
|
-
* This runs before code generation and populates passByValueParams.
|
|
2633
|
-
* SonarCloud S3776: Refactored to use helper methods.
|
|
2634
|
-
*/
|
|
2635
|
-
private analyzePassByValue(tree: Parser.ProgramContext): void {
|
|
2636
|
-
// Reset analysis state
|
|
2637
|
-
CodeGenState.modifiedParameters.clear();
|
|
2638
|
-
CodeGenState.passByValueParams.clear();
|
|
2639
|
-
CodeGenState.functionCallGraph.clear();
|
|
2640
|
-
CodeGenState.functionParamLists.clear();
|
|
2641
|
-
|
|
2642
|
-
// Phase 1: Collect function parameter lists and direct modifications
|
|
2643
|
-
this.collectFunctionParametersAndModifications(tree);
|
|
2644
|
-
|
|
2645
|
-
// Issue #558: Inject cross-file data before transitive propagation
|
|
2646
|
-
this.injectCrossFileModifications();
|
|
2647
|
-
this.injectCrossFileParamLists();
|
|
2648
|
-
|
|
2649
|
-
// Phase 2: Fixed-point iteration for transitive modifications
|
|
2650
|
-
TransitiveModificationPropagator.propagate(
|
|
2651
|
-
CodeGenState.functionCallGraph,
|
|
2652
|
-
CodeGenState.functionParamLists,
|
|
2653
|
-
CodeGenState.modifiedParameters,
|
|
2654
|
-
);
|
|
2655
|
-
|
|
2656
|
-
// Phase 3: Determine which parameters can pass by value
|
|
2657
|
-
this.computePassByValueParams();
|
|
2658
|
-
}
|
|
2659
|
-
|
|
2660
|
-
/**
|
|
2661
|
-
* Inject cross-file modification data into modifiedParameters.
|
|
2662
|
-
* SonarCloud S3776: Extracted from analyzePassByValue().
|
|
2663
|
-
*/
|
|
2664
|
-
private injectCrossFileModifications(): void {
|
|
2665
|
-
if (!CodeGenState.pendingCrossFileModifications) return;
|
|
2666
|
-
|
|
2667
|
-
for (const [
|
|
2668
|
-
funcName,
|
|
2669
|
-
params,
|
|
2670
|
-
] of CodeGenState.pendingCrossFileModifications) {
|
|
2671
|
-
const existing = CodeGenState.modifiedParameters.get(funcName);
|
|
2672
|
-
if (existing) {
|
|
2673
|
-
for (const param of params) {
|
|
2674
|
-
existing.add(param);
|
|
2675
|
-
}
|
|
2676
|
-
} else {
|
|
2677
|
-
CodeGenState.modifiedParameters.set(funcName, new Set(params));
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
CodeGenState.pendingCrossFileModifications = null; // Clear after use
|
|
2681
|
-
}
|
|
2682
|
-
|
|
2683
|
-
/**
|
|
2684
|
-
* Inject cross-file parameter lists into functionParamLists.
|
|
2685
|
-
* SonarCloud S3776: Extracted from analyzePassByValue().
|
|
2686
|
-
*/
|
|
2687
|
-
private injectCrossFileParamLists(): void {
|
|
2688
|
-
if (!CodeGenState.pendingCrossFileParamLists) return;
|
|
2689
|
-
|
|
2690
|
-
for (const [funcName, params] of CodeGenState.pendingCrossFileParamLists) {
|
|
2691
|
-
if (!CodeGenState.functionParamLists.has(funcName)) {
|
|
2692
|
-
CodeGenState.functionParamLists.set(funcName, [...params]);
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
CodeGenState.pendingCrossFileParamLists = null; // Clear after use
|
|
2696
|
-
}
|
|
2697
|
-
|
|
2698
|
-
/**
|
|
2699
|
-
* Phase 1: Walk all functions to collect:
|
|
2700
|
-
* - Parameter lists (for call graph resolution)
|
|
2701
|
-
* - Direct modifications (param <- value)
|
|
2702
|
-
* - Function calls where params are passed as arguments
|
|
2703
|
-
*/
|
|
2704
|
-
private collectFunctionParametersAndModifications(
|
|
2705
|
-
tree: Parser.ProgramContext,
|
|
2706
|
-
): void {
|
|
2707
|
-
for (const decl of tree.declaration()) {
|
|
2708
|
-
// Handle scope-level functions
|
|
2709
|
-
if (decl.scopeDeclaration()) {
|
|
2710
|
-
const scopeDecl = decl.scopeDeclaration()!;
|
|
2711
|
-
const scopeName = scopeDecl.IDENTIFIER().getText();
|
|
2712
|
-
|
|
2713
|
-
for (const member of scopeDecl.scopeMember()) {
|
|
2714
|
-
if (member.functionDeclaration()) {
|
|
2715
|
-
const funcDecl = member.functionDeclaration()!;
|
|
2716
|
-
const funcName = funcDecl.IDENTIFIER().getText();
|
|
2717
|
-
const fullName = `${scopeName}_${funcName}`;
|
|
2718
|
-
this.analyzeFunctionForModifications(fullName, funcDecl);
|
|
2719
|
-
}
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
|
|
2723
|
-
// Handle top-level functions
|
|
2724
|
-
if (decl.functionDeclaration()) {
|
|
2725
|
-
const funcDecl = decl.functionDeclaration()!;
|
|
2726
|
-
const name = funcDecl.IDENTIFIER().getText();
|
|
2727
|
-
this.analyzeFunctionForModifications(name, funcDecl);
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2731
|
-
|
|
2732
|
-
/**
|
|
2733
|
-
* Analyze a single function for parameter modifications and call graph edges.
|
|
2734
|
-
*/
|
|
2735
|
-
private analyzeFunctionForModifications(
|
|
2736
|
-
funcName: string,
|
|
2737
|
-
funcDecl: Parser.FunctionDeclarationContext,
|
|
2738
|
-
): void {
|
|
2739
|
-
// Collect parameter names
|
|
2740
|
-
const paramNames: string[] = [];
|
|
2741
|
-
const paramList = funcDecl.parameterList();
|
|
2742
|
-
if (paramList) {
|
|
2743
|
-
for (const param of paramList.parameter()) {
|
|
2744
|
-
paramNames.push(param.IDENTIFIER().getText());
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
CodeGenState.functionParamLists.set(funcName, paramNames);
|
|
2748
|
-
|
|
2749
|
-
// Initialize modified set
|
|
2750
|
-
CodeGenState.modifiedParameters.set(funcName, new Set());
|
|
2751
|
-
// Issue #579: Initialize subscript access tracking
|
|
2752
|
-
CodeGenState.subscriptAccessedParameters.set(funcName, new Set());
|
|
2753
|
-
CodeGenState.functionCallGraph.set(funcName, []);
|
|
2754
|
-
|
|
2755
|
-
// Walk the function body to find modifications and calls
|
|
2756
|
-
const block = funcDecl.block();
|
|
2757
|
-
if (block) {
|
|
2758
|
-
this.walkBlockForModifications(funcName, paramNames, block);
|
|
2759
|
-
}
|
|
2760
|
-
}
|
|
2761
|
-
|
|
2762
|
-
/**
|
|
2763
|
-
* Walk a block to find parameter modifications and function calls.
|
|
2764
|
-
*/
|
|
2765
|
-
private walkBlockForModifications(
|
|
2766
|
-
funcName: string,
|
|
2767
|
-
paramNames: string[],
|
|
2768
|
-
block: Parser.BlockContext,
|
|
2769
|
-
): void {
|
|
2770
|
-
const paramSet = new Set(paramNames);
|
|
2771
|
-
|
|
2772
|
-
for (const stmt of block.statement()) {
|
|
2773
|
-
this.walkStatementForModifications(funcName, paramSet, stmt);
|
|
2774
|
-
}
|
|
2775
|
-
}
|
|
2776
|
-
|
|
2777
|
-
/**
|
|
2778
|
-
* Walk a statement recursively looking for modifications and calls.
|
|
2779
|
-
* Issue #566: Refactored to use helper methods for expression and child collection.
|
|
2780
|
-
*/
|
|
2781
|
-
private walkStatementForModifications(
|
|
2782
|
-
funcName: string,
|
|
2783
|
-
paramSet: Set<string>,
|
|
2784
|
-
stmt: Parser.StatementContext,
|
|
2785
|
-
): void {
|
|
2786
|
-
// 1. Check for parameter modifications via assignment targets
|
|
2787
|
-
if (stmt.assignmentStatement()) {
|
|
2788
|
-
this.trackAssignmentModifications(funcName, paramSet, stmt);
|
|
2789
|
-
}
|
|
2790
|
-
|
|
2791
|
-
// 2. Walk all expressions in this statement for function calls and subscript access
|
|
2792
|
-
for (const expr of StatementExpressionCollector.collectAll(stmt)) {
|
|
2793
|
-
this.walkExpressionForCalls(funcName, paramSet, expr);
|
|
2794
|
-
// Issue #579: Also track subscript read access on parameters
|
|
2795
|
-
this.walkExpressionForSubscriptAccess(funcName, paramSet, expr);
|
|
2796
|
-
}
|
|
2797
|
-
|
|
2798
|
-
// 3. Recurse into child statements and blocks
|
|
2799
|
-
const { statements, blocks } = ChildStatementCollector.collectAll(stmt);
|
|
2800
|
-
for (const childStmt of statements) {
|
|
2801
|
-
this.walkStatementForModifications(funcName, paramSet, childStmt);
|
|
2802
|
-
}
|
|
2803
|
-
for (const block of blocks) {
|
|
2804
|
-
this.walkBlockForModifications(funcName, [...paramSet], block);
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
/**
|
|
2809
|
-
* Track assignment modifications for parameter const inference.
|
|
2810
|
-
* SonarCloud S3776: Extracted from walkStatementForModifications().
|
|
2811
|
-
*/
|
|
2812
|
-
private trackAssignmentModifications(
|
|
2813
|
-
funcName: string,
|
|
2814
|
-
paramSet: Set<string>,
|
|
2815
|
-
stmt: Parser.StatementContext,
|
|
2816
|
-
): void {
|
|
2817
|
-
const assign = stmt.assignmentStatement()!;
|
|
2818
|
-
const target = assign.assignmentTarget();
|
|
2819
|
-
|
|
2820
|
-
const { baseIdentifier, hasSingleIndexSubscript } =
|
|
2821
|
-
AssignmentTargetExtractor.extract(target);
|
|
2822
|
-
|
|
2823
|
-
// Issue #579: Track subscript access on parameters (for write path)
|
|
2824
|
-
if (
|
|
2825
|
-
hasSingleIndexSubscript &&
|
|
2826
|
-
baseIdentifier &&
|
|
2827
|
-
paramSet.has(baseIdentifier)
|
|
2828
|
-
) {
|
|
2829
|
-
CodeGenState.subscriptAccessedParameters
|
|
2830
|
-
.get(funcName)!
|
|
2831
|
-
.add(baseIdentifier);
|
|
2832
|
-
}
|
|
2833
|
-
|
|
2834
|
-
// Track as modified parameter
|
|
2835
|
-
if (baseIdentifier && paramSet.has(baseIdentifier)) {
|
|
2836
|
-
CodeGenState.modifiedParameters.get(funcName)!.add(baseIdentifier);
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
/**
|
|
2841
|
-
* Walk an expression tree to find function calls where parameters are passed.
|
|
2842
|
-
* Uses recursive descent through the expression hierarchy.
|
|
2843
|
-
*/
|
|
2844
|
-
private walkExpressionForCalls(
|
|
2845
|
-
funcName: string,
|
|
2846
|
-
paramSet: Set<string>,
|
|
2847
|
-
expr: Parser.ExpressionContext,
|
|
2848
|
-
): void {
|
|
2849
|
-
// Expression -> TernaryExpression -> OrExpression -> ... -> PostfixExpression
|
|
2850
|
-
const ternary = expr.ternaryExpression();
|
|
2851
|
-
if (ternary) {
|
|
2852
|
-
// Walk all orExpression children
|
|
2853
|
-
for (const orExpr of ternary.orExpression()) {
|
|
2854
|
-
this.walkOrExpressionForCalls(funcName, paramSet, orExpr);
|
|
2855
|
-
}
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
|
|
2859
|
-
/**
|
|
2860
|
-
* Issue #579: Walk an expression tree to find subscript access on parameters.
|
|
2861
|
-
* This tracks read access like `buf[i]` where buf is a parameter.
|
|
2862
|
-
* Parameters with subscript access must become pointers.
|
|
2863
|
-
*/
|
|
2864
|
-
private walkExpressionForSubscriptAccess(
|
|
2865
|
-
funcName: string,
|
|
2866
|
-
paramSet: Set<string>,
|
|
2867
|
-
expr: Parser.ExpressionContext,
|
|
2868
|
-
): void {
|
|
2869
|
-
const ternary = expr.ternaryExpression();
|
|
2870
|
-
if (ternary) {
|
|
2871
|
-
for (const orExpr of ternary.orExpression()) {
|
|
2872
|
-
this.walkOrExpression(orExpr, (unaryExpr) => {
|
|
2873
|
-
this.handleSubscriptAccess(funcName, paramSet, unaryExpr);
|
|
2874
|
-
});
|
|
2875
|
-
}
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
|
|
2879
|
-
/**
|
|
2880
|
-
* Issue #579: Handle subscript access on a unary expression.
|
|
2881
|
-
* Only tracks single-index subscript access (which could be array access).
|
|
2882
|
-
* Two-index subscript (e.g., value[start, width]) is always bit extraction,
|
|
2883
|
-
* so it doesn't require the parameter to become a pointer.
|
|
2884
|
-
*/
|
|
2885
|
-
private handleSubscriptAccess(
|
|
2886
|
-
funcName: string,
|
|
2887
|
-
paramSet: Set<string>,
|
|
2888
|
-
unaryExpr: Parser.UnaryExpressionContext,
|
|
2889
|
-
): void {
|
|
2890
|
-
const postfixExpr = unaryExpr.postfixExpression();
|
|
2891
|
-
if (!postfixExpr) return;
|
|
2892
|
-
|
|
2893
|
-
const primary = postfixExpr.primaryExpression();
|
|
2894
|
-
const ops = postfixExpr.postfixOp();
|
|
2895
|
-
|
|
2896
|
-
// Check if primary is a parameter and there's subscript access
|
|
2897
|
-
const primaryId = primary.IDENTIFIER()?.getText();
|
|
2898
|
-
if (!primaryId || !paramSet.has(primaryId)) {
|
|
2899
|
-
return;
|
|
2900
|
-
}
|
|
2901
|
-
|
|
2902
|
-
// Only track SINGLE-index subscript access (potential array access)
|
|
2903
|
-
// Two-index subscript like value[0, 8] is bit extraction, not array access
|
|
2904
|
-
const hasSingleIndexSubscript = ops.some(
|
|
2905
|
-
(op) => op.expression().length === 1,
|
|
2906
|
-
);
|
|
2907
|
-
if (hasSingleIndexSubscript) {
|
|
2908
|
-
CodeGenState.subscriptAccessedParameters.get(funcName)!.add(primaryId);
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
|
|
2912
|
-
/**
|
|
2913
|
-
* Generic walker for orExpression trees.
|
|
2914
|
-
* Walks through the expression hierarchy and calls the handler for each unaryExpression.
|
|
2915
|
-
* Used by both function call tracking and subscript access tracking.
|
|
2916
|
-
*/
|
|
2917
|
-
private walkOrExpression(
|
|
2918
|
-
orExpr: Parser.OrExpressionContext,
|
|
2919
|
-
handler: (unaryExpr: Parser.UnaryExpressionContext) => void,
|
|
2920
|
-
): void {
|
|
2921
|
-
orExpr
|
|
2922
|
-
.andExpression()
|
|
2923
|
-
.flatMap((and) => and.equalityExpression())
|
|
2924
|
-
.flatMap((eq) => eq.relationalExpression())
|
|
2925
|
-
.flatMap((rel) => rel.bitwiseOrExpression())
|
|
2926
|
-
.flatMap((bor) => bor.bitwiseXorExpression())
|
|
2927
|
-
.flatMap((bxor) => bxor.bitwiseAndExpression())
|
|
2928
|
-
.flatMap((band) => band.shiftExpression())
|
|
2929
|
-
.flatMap((shift) => shift.additiveExpression())
|
|
2930
|
-
.flatMap((add) => add.multiplicativeExpression())
|
|
2931
|
-
.flatMap((mul) => mul.unaryExpression())
|
|
2932
|
-
.forEach(handler);
|
|
2933
|
-
}
|
|
2934
|
-
|
|
2935
|
-
/**
|
|
2936
|
-
* Walk an orExpression tree for function calls.
|
|
2937
|
-
*/
|
|
2938
|
-
private walkOrExpressionForCalls(
|
|
2939
|
-
funcName: string,
|
|
2940
|
-
paramSet: Set<string>,
|
|
2941
|
-
orExpr: Parser.OrExpressionContext,
|
|
2942
|
-
): void {
|
|
2943
|
-
this.walkOrExpression(orExpr, (unaryExpr) => {
|
|
2944
|
-
this.walkUnaryExpressionForCalls(funcName, paramSet, unaryExpr);
|
|
2945
|
-
});
|
|
2946
|
-
}
|
|
2947
|
-
|
|
2948
|
-
/**
|
|
2949
|
-
* Walk a unaryExpression tree for function calls.
|
|
2950
|
-
*/
|
|
2951
|
-
private walkUnaryExpressionForCalls(
|
|
2952
|
-
funcName: string,
|
|
2953
|
-
paramSet: Set<string>,
|
|
2954
|
-
unaryExpr: Parser.UnaryExpressionContext,
|
|
2955
|
-
): void {
|
|
2956
|
-
// Recurse into nested unary
|
|
2957
|
-
if (unaryExpr.unaryExpression()) {
|
|
2958
|
-
this.walkUnaryExpressionForCalls(
|
|
2959
|
-
funcName,
|
|
2960
|
-
paramSet,
|
|
2961
|
-
unaryExpr.unaryExpression()!,
|
|
2962
|
-
);
|
|
2963
|
-
return;
|
|
2964
|
-
}
|
|
2965
|
-
|
|
2966
|
-
// Check postfix expression
|
|
2967
|
-
const postfix = unaryExpr.postfixExpression();
|
|
2968
|
-
if (postfix) {
|
|
2969
|
-
this.walkPostfixExpressionForCalls(funcName, paramSet, postfix);
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2972
|
-
|
|
2973
|
-
/**
|
|
2974
|
-
* Walk a postfixExpression for function calls.
|
|
2975
|
-
* This is where function calls are found: primaryExpr followed by '(' args ')'
|
|
2976
|
-
*/
|
|
2977
|
-
private walkPostfixExpressionForCalls(
|
|
2978
|
-
funcName: string,
|
|
2979
|
-
paramSet: Set<string>,
|
|
2980
|
-
postfix: Parser.PostfixExpressionContext,
|
|
2981
|
-
): void {
|
|
2982
|
-
const primary = postfix.primaryExpression();
|
|
2983
|
-
const postfixOps = postfix.postfixOp();
|
|
2984
|
-
|
|
2985
|
-
// Handle simple function calls: IDENTIFIER followed by '(' ... ')'
|
|
2986
|
-
this.handleSimpleFunctionCall(funcName, paramSet, primary, postfixOps);
|
|
2987
|
-
|
|
2988
|
-
// Issue #365: Handle scope-qualified calls: Scope.method(...) or global.Scope.method(...)
|
|
2989
|
-
this.handleScopeQualifiedCalls(funcName, paramSet, primary, postfixOps);
|
|
2990
|
-
|
|
2991
|
-
// Recurse into primary expression if it's a parenthesized expression
|
|
2992
|
-
if (primary.expression()) {
|
|
2993
|
-
this.walkExpressionForCalls(funcName, paramSet, primary.expression()!);
|
|
2994
|
-
}
|
|
2995
|
-
|
|
2996
|
-
// Walk arguments in any postfix function call ops (for nested calls)
|
|
2997
|
-
this.walkPostfixOpsRecursively(funcName, paramSet, postfixOps);
|
|
2998
|
-
}
|
|
2999
|
-
|
|
3000
|
-
/**
|
|
3001
|
-
* Handle simple function calls: IDENTIFIER followed by '(' ... ')'
|
|
3002
|
-
*/
|
|
3003
|
-
private handleSimpleFunctionCall(
|
|
3004
|
-
funcName: string,
|
|
3005
|
-
paramSet: Set<string>,
|
|
3006
|
-
primary: Parser.PrimaryExpressionContext,
|
|
3007
|
-
postfixOps: Parser.PostfixOpContext[],
|
|
3008
|
-
): void {
|
|
3009
|
-
if (!primary.IDENTIFIER() || postfixOps.length === 0) return;
|
|
3010
|
-
|
|
3011
|
-
const firstOp = postfixOps[0];
|
|
3012
|
-
if (!firstOp.LPAREN()) return;
|
|
3013
|
-
|
|
3014
|
-
const calleeName = primary.IDENTIFIER()!.getText();
|
|
3015
|
-
this.recordCallsFromArgList(funcName, paramSet, calleeName, firstOp);
|
|
3016
|
-
}
|
|
3017
|
-
|
|
3018
|
-
/**
|
|
3019
|
-
* Handle scope-qualified calls: Scope.method(...) or global.Scope.method(...)
|
|
3020
|
-
* Track member accesses to build the mangled callee name (e.g., Storage_load)
|
|
3021
|
-
*/
|
|
3022
|
-
private handleScopeQualifiedCalls(
|
|
3023
|
-
funcName: string,
|
|
3024
|
-
paramSet: Set<string>,
|
|
3025
|
-
primary: Parser.PrimaryExpressionContext,
|
|
3026
|
-
postfixOps: Parser.PostfixOpContext[],
|
|
3027
|
-
): void {
|
|
3028
|
-
if (postfixOps.length === 0) return;
|
|
3029
|
-
|
|
3030
|
-
const memberNames = this.collectInitialMemberNames(funcName, primary);
|
|
3031
|
-
|
|
3032
|
-
for (const op of postfixOps) {
|
|
3033
|
-
if (op.IDENTIFIER()) {
|
|
3034
|
-
memberNames.push(op.IDENTIFIER()!.getText());
|
|
3035
|
-
} else if (op.LPAREN() && memberNames.length >= 1) {
|
|
3036
|
-
const calleeName = memberNames.join("_");
|
|
3037
|
-
this.recordCallsFromArgList(funcName, paramSet, calleeName, op);
|
|
3038
|
-
memberNames.length = 0; // Reset for potential chained calls
|
|
3039
|
-
} else if (op.expression().length > 0) {
|
|
3040
|
-
memberNames.length = 0; // Array subscript breaks scope chain
|
|
3041
|
-
}
|
|
3042
|
-
}
|
|
3043
|
-
}
|
|
3044
|
-
|
|
3045
|
-
/**
|
|
3046
|
-
* Collect initial member names from primary expression for scope resolution.
|
|
3047
|
-
* Issue #561: When 'this' is used, resolve to the current scope name from funcName.
|
|
3048
|
-
*/
|
|
3049
|
-
private collectInitialMemberNames(
|
|
3050
|
-
funcName: string,
|
|
3051
|
-
primary: Parser.PrimaryExpressionContext,
|
|
3052
|
-
): string[] {
|
|
3053
|
-
const memberNames: string[] = [];
|
|
3054
|
-
const primaryId = primary.IDENTIFIER()?.getText();
|
|
3055
|
-
|
|
3056
|
-
if (primaryId && primaryId !== "global") {
|
|
3057
|
-
memberNames.push(primaryId);
|
|
3058
|
-
} else if (primary.THIS()) {
|
|
3059
|
-
const scopeName = funcName.split("_")[0];
|
|
3060
|
-
if (scopeName && scopeName !== funcName) {
|
|
3061
|
-
memberNames.push(scopeName);
|
|
3062
|
-
}
|
|
3063
|
-
}
|
|
3064
|
-
return memberNames;
|
|
3065
|
-
}
|
|
3066
|
-
|
|
3067
|
-
/**
|
|
3068
|
-
* Record function calls to the call graph from an argument list.
|
|
3069
|
-
* Also recurses into argument expressions.
|
|
3070
|
-
*/
|
|
3071
|
-
private recordCallsFromArgList(
|
|
3072
|
-
funcName: string,
|
|
3073
|
-
paramSet: Set<string>,
|
|
3074
|
-
calleeName: string,
|
|
3075
|
-
op: Parser.PostfixOpContext,
|
|
3076
|
-
): void {
|
|
3077
|
-
const argList = op.argumentList();
|
|
3078
|
-
if (!argList) return;
|
|
3079
|
-
|
|
3080
|
-
const args = argList.expression();
|
|
3081
|
-
for (let i = 0; i < args.length; i++) {
|
|
3082
|
-
const arg = args[i];
|
|
3083
|
-
const argName = ExpressionUtils.extractIdentifier(arg);
|
|
3084
|
-
if (argName && paramSet.has(argName)) {
|
|
3085
|
-
CodeGenState.functionCallGraph.get(funcName)!.push({
|
|
3086
|
-
callee: calleeName,
|
|
3087
|
-
paramIndex: i,
|
|
3088
|
-
argParamName: argName,
|
|
3089
|
-
});
|
|
3090
|
-
}
|
|
3091
|
-
this.walkExpressionForCalls(funcName, paramSet, arg);
|
|
3092
|
-
}
|
|
3093
|
-
}
|
|
3094
|
-
|
|
3095
|
-
/**
|
|
3096
|
-
* Walk postfix ops recursively for nested calls and array subscripts.
|
|
3097
|
-
*/
|
|
3098
|
-
private walkPostfixOpsRecursively(
|
|
3099
|
-
funcName: string,
|
|
3100
|
-
paramSet: Set<string>,
|
|
3101
|
-
postfixOps: Parser.PostfixOpContext[],
|
|
3102
|
-
): void {
|
|
3103
|
-
for (const op of postfixOps) {
|
|
3104
|
-
if (op.argumentList()) {
|
|
3105
|
-
for (const argExpr of op.argumentList()!.expression()) {
|
|
3106
|
-
this.walkExpressionForCalls(funcName, paramSet, argExpr);
|
|
3107
|
-
}
|
|
3108
|
-
}
|
|
3109
|
-
for (const expr of op.expression()) {
|
|
3110
|
-
this.walkExpressionForCalls(funcName, paramSet, expr);
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
|
|
3115
|
-
/**
|
|
3116
|
-
* Phase 3: Determine which parameters can pass by value.
|
|
3117
|
-
* A parameter passes by value if:
|
|
3118
|
-
* 1. It's a small primitive type (u8, i8, u16, i16, u32, i32, u64, i64, bool)
|
|
3119
|
-
* 2. It's not modified (directly or transitively)
|
|
3120
|
-
* 3. It's not an array, struct, string, or callback
|
|
3121
|
-
*/
|
|
3122
|
-
private computePassByValueParams(): void {
|
|
3123
|
-
const smallPrimitives = new Set([
|
|
3124
|
-
"u8",
|
|
3125
|
-
"i8",
|
|
3126
|
-
"u16",
|
|
3127
|
-
"i16",
|
|
3128
|
-
"u32",
|
|
3129
|
-
"i32",
|
|
3130
|
-
"u64",
|
|
3131
|
-
"i64",
|
|
3132
|
-
"bool",
|
|
3133
|
-
]);
|
|
3134
|
-
|
|
3135
|
-
for (const [funcName, paramNames] of CodeGenState.functionParamLists) {
|
|
3136
|
-
const passByValue = new Set<string>();
|
|
3137
|
-
const modified =
|
|
3138
|
-
CodeGenState.modifiedParameters.get(funcName) ?? new Set();
|
|
3139
|
-
|
|
3140
|
-
// Get function declaration to check parameter types
|
|
3141
|
-
const funcSig = CodeGenState.functionSignatures.get(funcName);
|
|
3142
|
-
if (funcSig) {
|
|
3143
|
-
for (let i = 0; i < paramNames.length; i++) {
|
|
3144
|
-
const paramName = paramNames[i];
|
|
3145
|
-
const paramSig = funcSig.parameters[i];
|
|
3146
|
-
|
|
3147
|
-
if (!paramSig) continue;
|
|
3148
|
-
|
|
3149
|
-
// Check if eligible for pass-by-value:
|
|
3150
|
-
// - Is a small primitive type
|
|
3151
|
-
// - Not an array
|
|
3152
|
-
// - Not modified
|
|
3153
|
-
// - Not accessed via subscript (Issue #579)
|
|
3154
|
-
const isSmallPrimitive = smallPrimitives.has(paramSig.baseType);
|
|
3155
|
-
const isArray = paramSig.isArray ?? false;
|
|
3156
|
-
const isModified = modified.has(paramName);
|
|
3157
|
-
// Issue #579: Parameters with subscript access must become pointers
|
|
3158
|
-
const hasSubscriptAccess =
|
|
3159
|
-
CodeGenState.subscriptAccessedParameters
|
|
3160
|
-
.get(funcName)
|
|
3161
|
-
?.has(paramName) ?? false;
|
|
3162
|
-
|
|
3163
|
-
if (
|
|
3164
|
-
isSmallPrimitive &&
|
|
3165
|
-
!isArray &&
|
|
3166
|
-
!isModified &&
|
|
3167
|
-
!hasSubscriptAccess
|
|
3168
|
-
) {
|
|
3169
|
-
passByValue.add(paramName);
|
|
3170
|
-
}
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
|
|
3174
|
-
CodeGenState.passByValueParams.set(funcName, passByValue);
|
|
3175
|
-
}
|
|
3176
|
-
}
|
|
3177
|
-
|
|
3178
|
-
/**
|
|
3179
|
-
* Check if a parameter should be passed by value (by name).
|
|
3180
|
-
* Used internally during code generation.
|
|
3181
|
-
*/
|
|
3182
|
-
private _isParameterPassByValueByName(
|
|
3183
|
-
funcName: string,
|
|
3184
|
-
paramName: string,
|
|
3185
|
-
): boolean {
|
|
3186
|
-
const passByValue = CodeGenState.passByValueParams.get(funcName);
|
|
3187
|
-
return passByValue?.has(paramName) ?? false;
|
|
3188
|
-
}
|
|
2622
|
+
// Issue #269: Pass-by-value analysis extracted to PassByValueAnalyzer
|
|
3189
2623
|
|
|
3190
2624
|
/**
|
|
3191
2625
|
* Issue #269: Check if a parameter should be passed by value (by index).
|
|
3192
2626
|
* Part of IOrchestrator interface - used by CallExprGenerator.
|
|
2627
|
+
* Delegates to PassByValueAnalyzer.
|
|
3193
2628
|
*/
|
|
3194
2629
|
isParameterPassByValue(funcName: string, paramIndex: number): boolean {
|
|
3195
|
-
|
|
3196
|
-
if (!paramList || paramIndex < 0 || paramIndex >= paramList.length) {
|
|
3197
|
-
return false;
|
|
3198
|
-
}
|
|
3199
|
-
const paramName = paramList[paramIndex];
|
|
3200
|
-
return this._isParameterPassByValueByName(funcName, paramName);
|
|
2630
|
+
return PassByValueAnalyzer.isParameterPassByValue(funcName, paramIndex);
|
|
3201
2631
|
}
|
|
3202
2632
|
|
|
3203
2633
|
/**
|
|
@@ -3256,7 +2686,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3256
2686
|
// ADR-017: Check if this is an enum type
|
|
3257
2687
|
if (
|
|
3258
2688
|
TypeRegistrationUtils.tryRegisterEnumType(
|
|
3259
|
-
CodeGenState.typeRegistry,
|
|
3260
2689
|
CodeGenState.symbols!,
|
|
3261
2690
|
registrationOptions,
|
|
3262
2691
|
)
|
|
@@ -3268,7 +2697,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3268
2697
|
const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
|
|
3269
2698
|
if (
|
|
3270
2699
|
TypeRegistrationUtils.tryRegisterBitmapType(
|
|
3271
|
-
CodeGenState.typeRegistry,
|
|
3272
2700
|
CodeGenState.symbols!,
|
|
3273
2701
|
registrationOptions,
|
|
3274
2702
|
bitmapDimensions,
|
|
@@ -3335,7 +2763,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3335
2763
|
const allDims =
|
|
3336
2764
|
additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
|
|
3337
2765
|
|
|
3338
|
-
CodeGenState.
|
|
2766
|
+
CodeGenState.setVariableTypeInfo(registryName, {
|
|
3339
2767
|
baseType: "char",
|
|
3340
2768
|
bitWidth: 8,
|
|
3341
2769
|
isArray: true,
|
|
@@ -3501,14 +2929,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3501
2929
|
)
|
|
3502
2930
|
) {
|
|
3503
2931
|
// Enum/bitmap was registered, but we need to update with arrayType dimension
|
|
3504
|
-
const existingInfo = CodeGenState.
|
|
2932
|
+
const existingInfo = CodeGenState.getVariableTypeInfo(registryName);
|
|
3505
2933
|
if (existingInfo) {
|
|
3506
2934
|
const arrayTypeDim =
|
|
3507
2935
|
this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
|
|
3508
2936
|
const allDims = arrayTypeDim
|
|
3509
2937
|
? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
|
|
3510
2938
|
: existingInfo.arrayDimensions;
|
|
3511
|
-
CodeGenState.
|
|
2939
|
+
CodeGenState.setVariableTypeInfo(registryName, {
|
|
3512
2940
|
...existingInfo,
|
|
3513
2941
|
isArray: true,
|
|
3514
2942
|
arrayDimensions: allDims,
|
|
@@ -3530,7 +2958,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3530
2958
|
arrayDim,
|
|
3531
2959
|
);
|
|
3532
2960
|
|
|
3533
|
-
CodeGenState.
|
|
2961
|
+
CodeGenState.setVariableTypeInfo(registryName, {
|
|
3534
2962
|
baseType,
|
|
3535
2963
|
bitWidth,
|
|
3536
2964
|
isArray: true,
|
|
@@ -3609,7 +3037,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3609
3037
|
? this._evaluateArrayDimensions(arrayDim)
|
|
3610
3038
|
: undefined;
|
|
3611
3039
|
|
|
3612
|
-
CodeGenState.
|
|
3040
|
+
CodeGenState.setVariableTypeInfo(registryName, {
|
|
3613
3041
|
baseType,
|
|
3614
3042
|
bitWidth,
|
|
3615
3043
|
isArray,
|
|
@@ -3862,7 +3290,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3862
3290
|
stringCapacity,
|
|
3863
3291
|
isParameter: true,
|
|
3864
3292
|
};
|
|
3865
|
-
CodeGenState.
|
|
3293
|
+
CodeGenState.setVariableTypeInfo(name, registeredType);
|
|
3866
3294
|
}
|
|
3867
3295
|
|
|
3868
3296
|
/**
|
|
@@ -3899,13 +3327,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3899
3327
|
private _clearParameters(): void {
|
|
3900
3328
|
// ADR-025: Remove parameter types from typeRegistry
|
|
3901
3329
|
for (const name of CodeGenState.currentParameters.keys()) {
|
|
3902
|
-
CodeGenState.
|
|
3903
|
-
CodeGenState.typeRegistry.delete(name);
|
|
3330
|
+
CodeGenState.deleteVariableTypeInfo(name);
|
|
3904
3331
|
}
|
|
3905
3332
|
CodeGenState.currentParameters.clear();
|
|
3906
3333
|
CodeGenState.localArrays.clear();
|
|
3907
|
-
CodeGenState.currentParameters.clear();
|
|
3908
|
-
CodeGenState.localArrays.clear();
|
|
3909
3334
|
}
|
|
3910
3335
|
|
|
3911
3336
|
/**
|
|
@@ -4120,7 +3545,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4120
3545
|
const sourceName = sourceId.getText();
|
|
4121
3546
|
|
|
4122
3547
|
// Check if source is a string type
|
|
4123
|
-
const typeInfo = CodeGenState.
|
|
3548
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(sourceName);
|
|
4124
3549
|
if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
|
|
4125
3550
|
return null;
|
|
4126
3551
|
}
|
|
@@ -4307,7 +3732,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4307
3732
|
baseId: string,
|
|
4308
3733
|
targetParamBaseType: string,
|
|
4309
3734
|
): boolean {
|
|
4310
|
-
const typeInfo = CodeGenState.
|
|
3735
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
4311
3736
|
return CppMemberHelper.needsComplexMemberConversion(
|
|
4312
3737
|
this._toPostfixOps(ops),
|
|
4313
3738
|
typeInfo,
|
|
@@ -4334,7 +3759,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4334
3759
|
const baseId = primary.IDENTIFIER()?.getText();
|
|
4335
3760
|
if (!baseId) return false;
|
|
4336
3761
|
|
|
4337
|
-
const typeInfo = CodeGenState.
|
|
3762
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
4338
3763
|
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
4339
3764
|
|
|
4340
3765
|
return CppMemberHelper.isStringSubscriptPattern(
|
|
@@ -4388,7 +3813,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4388
3813
|
// 2. Parameter: currentParameters.get(baseId).baseType
|
|
4389
3814
|
let structType: string | undefined;
|
|
4390
3815
|
|
|
4391
|
-
const typeInfo = CodeGenState.
|
|
3816
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
4392
3817
|
if (typeInfo) {
|
|
4393
3818
|
structType = typeInfo.baseType;
|
|
4394
3819
|
} else {
|
|
@@ -4455,7 +3880,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4455
3880
|
|
|
4456
3881
|
// Global arrays also decay to pointers (check typeRegistry)
|
|
4457
3882
|
// But NOT strings - strings need & (they're char arrays but passed by reference)
|
|
4458
|
-
const typeInfo = CodeGenState.
|
|
3883
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(id);
|
|
4459
3884
|
if (typeInfo?.isArray && !typeInfo.isString) {
|
|
4460
3885
|
return id;
|
|
4461
3886
|
}
|
|
@@ -5325,7 +4750,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5325
4750
|
// Small unmodified primitives
|
|
5326
4751
|
if (
|
|
5327
4752
|
CodeGenState.currentFunctionName &&
|
|
5328
|
-
|
|
4753
|
+
PassByValueAnalyzer.isParameterPassByValueByName(
|
|
4754
|
+
CodeGenState.currentFunctionName,
|
|
4755
|
+
name,
|
|
4756
|
+
)
|
|
5329
4757
|
) {
|
|
5330
4758
|
return true;
|
|
5331
4759
|
}
|
|
@@ -5784,14 +5212,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5784
5212
|
const argName = argNode.getText();
|
|
5785
5213
|
|
|
5786
5214
|
// Check if it exists in type registry
|
|
5787
|
-
const typeInfo = CodeGenState.
|
|
5215
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(argName);
|
|
5788
5216
|
|
|
5789
5217
|
// Also check scoped variables if inside a scope
|
|
5790
5218
|
let scopedArgName = argName;
|
|
5791
5219
|
let scopedTypeInfo = typeInfo;
|
|
5792
5220
|
if (!typeInfo && CodeGenState.currentScope) {
|
|
5793
5221
|
scopedArgName = `${CodeGenState.currentScope}_${argName}`;
|
|
5794
|
-
scopedTypeInfo = CodeGenState.
|
|
5222
|
+
scopedTypeInfo = CodeGenState.getVariableTypeInfo(scopedArgName);
|
|
5795
5223
|
}
|
|
5796
5224
|
|
|
5797
5225
|
if (!typeInfo && !scopedTypeInfo) {
|
|
@@ -5815,7 +5243,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5815
5243
|
}
|
|
5816
5244
|
|
|
5817
5245
|
// Track the variable in type registry (as an external C++ type)
|
|
5818
|
-
CodeGenState.
|
|
5246
|
+
CodeGenState.setVariableTypeInfo(name, {
|
|
5819
5247
|
baseType: type,
|
|
5820
5248
|
bitWidth: 0, // Unknown for C++ types
|
|
5821
5249
|
isArray: false,
|
|
@@ -6055,7 +5483,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6055
5483
|
// ADR-109: Dispatch to assignment handlers
|
|
6056
5484
|
// Build context, classify, and dispatch - all patterns handled by handlers
|
|
6057
5485
|
const assignCtx = buildAssignmentContext(ctx, {
|
|
6058
|
-
typeRegistry: CodeGenState.
|
|
5486
|
+
typeRegistry: CodeGenState.getTypeRegistryView(),
|
|
6059
5487
|
generateExpression: () => value,
|
|
6060
5488
|
generateAssignmentTarget: (targetCtx) =>
|
|
6061
5489
|
this.generateAssignmentTarget(targetCtx),
|