c-next 0.1.69 → 0.1.71
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/lib/__tests__/parseCHeader.mocked.test.ts +69 -54
- package/src/lib/parseCHeader.ts +56 -23
- package/src/lib/parseWithSymbols.ts +195 -53
- package/src/transpiler/Transpiler.ts +173 -60
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -205
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +1 -2
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +742 -0
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +102 -15
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +9 -9
- package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +5 -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/logic/symbols/SymbolTable.ts +676 -258
- package/src/transpiler/logic/symbols/SymbolUtils.ts +2 -2
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +290 -782
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +573 -0
- package/src/transpiler/logic/symbols/c/__tests__/testHelpers.ts +20 -0
- package/src/transpiler/logic/symbols/c/collectors/EnumCollector.ts +82 -0
- package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +106 -0
- package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +173 -0
- package/src/transpiler/logic/symbols/c/collectors/TypedefCollector.ts +35 -0
- package/src/transpiler/logic/symbols/c/collectors/VariableCollector.ts +80 -0
- package/src/transpiler/logic/symbols/c/index.ts +333 -0
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +269 -0
- package/src/transpiler/logic/symbols/cnext/__tests__/BitmapCollector.test.ts +50 -11
- package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +45 -34
- package/src/transpiler/logic/symbols/cnext/__tests__/EnumCollector.test.ts +30 -13
- package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +279 -64
- package/src/transpiler/logic/symbols/cnext/__tests__/RegisterCollector.test.ts +60 -13
- package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +40 -37
- package/src/transpiler/logic/symbols/cnext/__tests__/StructCollector.test.ts +131 -45
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +223 -139
- package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +79 -25
- package/src/transpiler/logic/symbols/cnext/__tests__/testUtils.ts +53 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +83 -43
- package/src/transpiler/logic/symbols/cnext/collectors/BitmapCollector.ts +14 -13
- package/src/transpiler/logic/symbols/cnext/collectors/EnumCollector.ts +11 -10
- package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +83 -34
- package/src/transpiler/logic/symbols/cnext/collectors/RegisterCollector.ts +22 -18
- package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +53 -35
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +30 -23
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +18 -19
- package/src/transpiler/logic/symbols/cnext/index.ts +36 -14
- package/src/transpiler/logic/symbols/cnext/types/IScopeCollectorResult.ts +2 -2
- package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +27 -0
- package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +270 -0
- package/src/transpiler/logic/symbols/cpp/__tests__/testHelpers.ts +20 -0
- package/src/transpiler/logic/symbols/cpp/collectors/ClassCollector.ts +317 -0
- package/src/transpiler/logic/symbols/cpp/collectors/EnumCollector.ts +71 -0
- package/src/transpiler/logic/symbols/cpp/collectors/FunctionCollector.ts +155 -0
- package/src/transpiler/logic/symbols/cpp/collectors/NamespaceCollector.ts +65 -0
- package/src/transpiler/logic/symbols/cpp/collectors/TypeAliasCollector.ts +46 -0
- package/src/transpiler/logic/symbols/cpp/collectors/VariableCollector.ts +54 -0
- package/src/transpiler/logic/symbols/cpp/index.ts +366 -0
- package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +248 -0
- package/src/transpiler/logic/symbols/shared/IExtractedParameter.ts +18 -0
- package/src/transpiler/logic/symbols/shared/ParameterExtractorUtils.ts +73 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +310 -2288
- 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__/CodeGenerator.test.ts +7 -1
- 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 +13 -12
- 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/AssignmentHandlerUtils.ts +7 -1
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +3 -3
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +9 -5
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +2 -1
- 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/declarationGenerators/ScopeGenerator.ts +21 -8
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +3 -2
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
- package/src/transpiler/output/codegen/generators/expressions/CallExprUtils.ts +9 -3
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +24 -8
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprUtils.test.ts +4 -8
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
- package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +236 -0
- 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/CppConstructorHelper.ts +3 -3
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +435 -0
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
- package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +203 -0
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +8 -12
- package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +520 -0
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +735 -0
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ArgumentGenerator.test.ts +521 -0
- 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__/CppConstructorHelper.test.ts +4 -5
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
- package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +983 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
- package/src/transpiler/output/codegen/helpers/__tests__/StringOperationsHelper.test.ts +269 -0
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +31 -32
- package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +186 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +460 -0
- package/src/transpiler/output/codegen/helpers/types/IArgumentGeneratorCallbacks.ts +32 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +7 -3
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
- package/src/transpiler/output/codegen/types/IFunctionContextCallbacks.ts +12 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +1 -1
- package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +114 -0
- package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +183 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +4 -4
- package/src/transpiler/output/headers/ExternalTypeHeaderBuilder.ts +7 -7
- package/src/transpiler/output/headers/HeaderGenerator.ts +9 -7
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +19 -20
- package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +15 -18
- package/src/transpiler/output/headers/__tests__/CHeaderGenerator.test.ts +63 -64
- package/src/transpiler/output/headers/__tests__/CppHeaderGenerator.test.ts +36 -32
- package/src/transpiler/output/headers/__tests__/ExternalTypeHeaderBuilder.test.ts +26 -26
- package/src/transpiler/output/headers/__tests__/HeaderGenerator.test.ts +87 -59
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +57 -58
- package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +222 -0
- package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +538 -0
- package/src/transpiler/output/headers/types/IGroupedSymbols.ts +8 -8
- package/src/transpiler/output/headers/types/IHeaderSymbol.ts +62 -0
- package/src/transpiler/state/CodeGenState.ts +109 -4
- package/src/transpiler/state/SymbolRegistry.ts +181 -0
- package/src/transpiler/{types → state}/TranspilerState.ts +1 -1
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +277 -1
- package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +249 -0
- package/src/transpiler/{types → state}/__tests__/TranspilerState.test.ts +1 -1
- package/src/transpiler/types/ICachedFileEntry.ts +1 -1
- package/src/transpiler/types/IConflict.ts +14 -0
- package/src/transpiler/types/ISerializedSymbol.ts +11 -0
- package/src/transpiler/types/TPrimitiveKind.ts +20 -0
- package/src/transpiler/types/TType.ts +103 -0
- package/src/transpiler/types/TVisibility.ts +6 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKind.ts +10 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKindC.ts +12 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKindCNext.ts +16 -0
- package/src/transpiler/types/symbol-kinds/TSymbolKindCpp.ts +14 -0
- package/src/transpiler/types/symbols/IBaseSymbol.ts +31 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IBitmapFieldInfo.ts +2 -2
- package/src/transpiler/types/symbols/IBitmapSymbol.ts +21 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IEnumSymbol.ts +5 -6
- package/src/transpiler/types/symbols/IFieldInfo.ts +26 -0
- package/src/transpiler/types/symbols/IFunctionSymbol.ts +30 -0
- package/src/transpiler/types/symbols/IParameterInfo.ts +26 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IRegisterMemberInfo.ts +4 -4
- package/src/transpiler/types/symbols/IRegisterSymbol.ts +18 -0
- package/src/transpiler/types/symbols/IScopeSymbol.ts +32 -0
- package/src/transpiler/{logic/symbols/types → types/symbols}/IStructFieldInfo.ts +2 -1
- package/src/transpiler/types/symbols/IStructSymbol.ts +15 -0
- package/src/transpiler/types/symbols/IVariableSymbol.ts +30 -0
- package/src/transpiler/types/symbols/SymbolGuards.ts +43 -0
- package/src/transpiler/types/symbols/TAnySymbol.ts +22 -0
- package/src/transpiler/types/symbols/TSymbol.ts +32 -0
- package/src/transpiler/types/symbols/__tests__/IBaseSymbol.test.ts +56 -0
- package/src/transpiler/types/symbols/__tests__/SymbolGuards.test.ts +57 -0
- package/src/transpiler/types/symbols/c/ICBaseSymbol.ts +28 -0
- package/src/transpiler/types/symbols/c/ICEnumMemberSymbol.ts +17 -0
- package/src/transpiler/types/symbols/c/ICEnumSymbol.ts +17 -0
- package/src/transpiler/types/symbols/c/ICFieldInfo.ts +16 -0
- package/src/transpiler/types/symbols/c/ICFunctionSymbol.ts +21 -0
- package/src/transpiler/types/symbols/c/ICParameterInfo.ts +19 -0
- package/src/transpiler/types/symbols/c/ICStructSymbol.ts +21 -0
- package/src/transpiler/types/symbols/c/ICTypedefSymbol.ts +14 -0
- package/src/transpiler/types/symbols/c/ICVariableSymbol.ts +26 -0
- package/src/transpiler/types/symbols/c/TCSymbol.ts +26 -0
- package/src/transpiler/types/symbols/cpp/ICppBaseSymbol.ts +31 -0
- package/src/transpiler/types/symbols/cpp/ICppClassSymbol.ts +15 -0
- package/src/transpiler/types/symbols/cpp/ICppEnumMemberSymbol.ts +14 -0
- package/src/transpiler/types/symbols/cpp/ICppEnumSymbol.ts +14 -0
- package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +16 -0
- package/src/transpiler/types/symbols/cpp/ICppFunctionSymbol.ts +21 -0
- package/src/transpiler/types/symbols/cpp/ICppNamespaceSymbol.ts +11 -0
- package/src/transpiler/types/symbols/cpp/ICppParameterInfo.ts +19 -0
- package/src/transpiler/types/symbols/cpp/ICppStructSymbol.ts +16 -0
- package/src/transpiler/types/symbols/cpp/ICppTypeAliasSymbol.ts +14 -0
- package/src/transpiler/types/symbols/cpp/ICppVariableSymbol.ts +23 -0
- package/src/transpiler/types/symbols/cpp/TCppSymbol.ts +30 -0
- package/src/utils/CppNamespaceUtils.ts +3 -4
- package/src/utils/FunctionUtils.ts +92 -0
- package/src/utils/ParameterUtils.ts +55 -0
- package/src/utils/PrimitiveKindUtils.ts +33 -0
- package/src/utils/ScopeUtils.ts +105 -0
- package/src/utils/TTypeUtils.ts +159 -0
- package/src/utils/TypeResolver.ts +132 -0
- package/src/utils/__tests__/CppNamespaceUtils.test.ts +92 -99
- package/src/utils/__tests__/FunctionUtils.test.ts +284 -0
- package/src/utils/__tests__/ParameterUtils.test.ts +174 -0
- package/src/utils/__tests__/PrimitiveKindUtils.test.ts +59 -0
- package/src/utils/__tests__/ScopeUtils.test.ts +53 -0
- package/src/utils/__tests__/TTypeUtils.test.ts +245 -0
- package/src/utils/__tests__/TypeResolver.test.ts +332 -0
- package/src/utils/cache/CacheManager.ts +91 -50
- package/src/utils/cache/__tests__/CacheManager.test.ts +180 -114
- package/src/transpiler/logic/symbols/AutoConstUpdater.ts +0 -93
- package/src/transpiler/logic/symbols/CSymbolCollector.ts +0 -648
- package/src/transpiler/logic/symbols/CppSymbolCollector.ts +0 -874
- package/src/transpiler/logic/symbols/SymbolCollectorContext.ts +0 -68
- package/src/transpiler/logic/symbols/__tests__/AutoConstUpdater.test.ts +0 -418
- package/src/transpiler/logic/symbols/__tests__/CSymbolCollector.test.ts +0 -685
- package/src/transpiler/logic/symbols/__tests__/CppSymbolCollector.test.ts +0 -1146
- package/src/transpiler/logic/symbols/__tests__/SymbolCollectorContext.test.ts +0 -290
- package/src/transpiler/logic/symbols/__tests__/cTestHelpers.ts +0 -43
- package/src/transpiler/logic/symbols/__tests__/cppTestHelpers.ts +0 -40
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +0 -595
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +0 -345
- package/src/transpiler/logic/symbols/types/IBaseSymbol.ts +0 -27
- package/src/transpiler/logic/symbols/types/IBitmapSymbol.ts +0 -23
- package/src/transpiler/logic/symbols/types/ICollectorContext.ts +0 -19
- package/src/transpiler/logic/symbols/types/IConflict.ts +0 -20
- package/src/transpiler/logic/symbols/types/IFieldInfo.ts +0 -18
- package/src/transpiler/logic/symbols/types/IFunctionSymbol.ts +0 -25
- package/src/transpiler/logic/symbols/types/IParameterInfo.ts +0 -24
- package/src/transpiler/logic/symbols/types/IRegisterSymbol.ts +0 -20
- package/src/transpiler/logic/symbols/types/IScopeSymbol.ts +0 -19
- package/src/transpiler/logic/symbols/types/IStructSymbol.ts +0 -16
- package/src/transpiler/logic/symbols/types/IVariableSymbol.ts +0 -30
- package/src/transpiler/logic/symbols/types/TSymbol.ts +0 -36
- package/src/transpiler/logic/symbols/types/__tests__/SymbolGuards.test.ts +0 -244
- package/src/transpiler/logic/symbols/types/typeGuards.ts +0 -44
- package/src/utils/types/ESymbolKind.ts +0 -19
- package/src/utils/types/ISymbol.ts +0 -64
- /package/src/transpiler/{types → constants}/BITMAP_BACKING_TYPE.ts +0 -0
- /package/src/transpiler/{types → constants}/BITMAP_SIZE.ts +0 -0
- /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
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import { CommonTokenStream, ParserRuleContext } from "antlr4ng";
|
|
7
7
|
import * as Parser from "../../logic/parser/grammar/CNextParser";
|
|
8
8
|
|
|
9
|
-
import ESymbolKind from "../../../utils/types/ESymbolKind";
|
|
10
9
|
import CommentExtractor from "../../logic/analysis/CommentExtractor";
|
|
10
|
+
import TypeRegistrationEngine from "./helpers/TypeRegistrationEngine";
|
|
11
11
|
import CommentFormatter from "./CommentFormatter";
|
|
12
12
|
import IncludeDiscovery from "../../data/IncludeDiscovery";
|
|
13
13
|
import IComment from "../../types/IComment";
|
|
@@ -17,12 +17,10 @@ import TYPE_LIMITS from "./types/TYPE_LIMITS";
|
|
|
17
17
|
// Issue #60: BITMAP_SIZE and BITMAP_BACKING_TYPE moved to SymbolCollector
|
|
18
18
|
import TTypeInfo from "./types/TTypeInfo";
|
|
19
19
|
import TParameterInfo from "./types/TParameterInfo";
|
|
20
|
-
import TOverflowBehavior from "./types/TOverflowBehavior";
|
|
21
20
|
import ICodeGeneratorOptions from "./types/ICodeGeneratorOptions";
|
|
22
21
|
import TypeResolver from "./TypeResolver";
|
|
23
22
|
import ICodeGenSymbols from "../../types/ICodeGenSymbols";
|
|
24
23
|
import TypeValidator from "./TypeValidator";
|
|
25
|
-
import TypeRegistrationUtils from "./TypeRegistrationUtils";
|
|
26
24
|
import IOrchestrator from "./generators/IOrchestrator";
|
|
27
25
|
import IGeneratorInput from "./generators/IGeneratorInput";
|
|
28
26
|
import IGeneratorState from "./generators/IGeneratorState";
|
|
@@ -81,11 +79,13 @@ import MemberChainAnalyzer from "./analysis/MemberChainAnalyzer";
|
|
|
81
79
|
// Issue #644: Float bit write helper for shadow variable pattern
|
|
82
80
|
import FloatBitHelper from "./helpers/FloatBitHelper";
|
|
83
81
|
// Issue #644: String declaration helper for bounded/array/concat strings
|
|
84
|
-
|
|
82
|
+
// Note: StringDeclHelper is now used via VariableDeclHelper
|
|
83
|
+
// Issue #794: Argument generation helper for ADR-006 semantics
|
|
84
|
+
import ArgumentGenerator from "./helpers/ArgumentGenerator";
|
|
85
85
|
// Issue #644: Enum assignment validator for type-safe enum assignments
|
|
86
86
|
import EnumAssignmentValidator from "./helpers/EnumAssignmentValidator";
|
|
87
87
|
// Issue #644: Array initialization helper for size inference and fill-all
|
|
88
|
-
|
|
88
|
+
// Note: ArrayInitHelper is now used via VariableDeclHelper
|
|
89
89
|
// Issue #644: Assignment expected type resolution helper
|
|
90
90
|
import AssignmentExpectedTypeResolver from "./helpers/AssignmentExpectedTypeResolver";
|
|
91
91
|
// PR #715: C++ member conversion helper for improved testability
|
|
@@ -102,7 +102,11 @@ import SymbolLookupHelper from "./helpers/SymbolLookupHelper";
|
|
|
102
102
|
// Issue #644: Assignment validation coordinator helper
|
|
103
103
|
import AssignmentValidator from "./helpers/AssignmentValidator";
|
|
104
104
|
// Issue #696: Variable modifier extraction helper
|
|
105
|
-
|
|
105
|
+
// Note: VariableModifierBuilder is now used via VariableDeclHelper
|
|
106
|
+
// Issue #792: Variable declaration helper
|
|
107
|
+
import VariableDeclHelper from "./helpers/VariableDeclHelper";
|
|
108
|
+
// String operation detection and extraction
|
|
109
|
+
import StringOperationsHelper from "./helpers/StringOperationsHelper";
|
|
106
110
|
// PR #681: Extracted separator and dereference resolution utilities
|
|
107
111
|
import MemberSeparatorResolver from "./helpers/MemberSeparatorResolver";
|
|
108
112
|
import ParameterDereferenceResolver from "./helpers/ParameterDereferenceResolver";
|
|
@@ -120,20 +124,19 @@ import CodegenParserUtils from "./utils/CodegenParserUtils";
|
|
|
120
124
|
import IMemberSeparatorDeps from "./types/IMemberSeparatorDeps";
|
|
121
125
|
import IParameterDereferenceDeps from "./types/IParameterDereferenceDeps";
|
|
122
126
|
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";
|
|
127
|
+
// Issue #269: Transitive modification propagation for const inference (used by analyzeModificationsOnly)
|
|
128
|
+
import TransitiveModificationPropagator from "../../logic/analysis/helpers/TransitiveModificationPropagator";
|
|
131
129
|
// Phase 3: Type generation helper for improved testability
|
|
132
130
|
import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
|
|
133
131
|
// Phase 5: Cast validation helper for improved testability
|
|
134
132
|
import CastValidator from "./helpers/CastValidator";
|
|
133
|
+
// Issue #793: Function context lifecycle and parameter processing helper
|
|
134
|
+
import FunctionContextManager from "./helpers/FunctionContextManager";
|
|
135
|
+
import IFunctionContextCallbacks from "./types/IFunctionContextCallbacks";
|
|
135
136
|
// Global state for code generation (simplifies debugging, eliminates DI complexity)
|
|
136
137
|
import CodeGenState from "../../state/CodeGenState";
|
|
138
|
+
// Issue #269: Pass-by-value analysis extracted from CodeGenerator
|
|
139
|
+
import PassByValueAnalyzer from "../../logic/analysis/PassByValueAnalyzer";
|
|
137
140
|
// Unified parameter generation (Phase 1)
|
|
138
141
|
import ParameterInputAdapter from "./helpers/ParameterInputAdapter";
|
|
139
142
|
import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
|
|
@@ -141,6 +144,8 @@ import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
|
|
|
141
144
|
import SizeofResolver from "./resolution/SizeofResolver";
|
|
142
145
|
import EnumTypeResolver from "./resolution/EnumTypeResolver";
|
|
143
146
|
import ScopeResolver from "./resolution/ScopeResolver";
|
|
147
|
+
// Issue #797: Centralized C-style name generation
|
|
148
|
+
import QualifiedNameGenerator from "./utils/QualifiedNameGenerator";
|
|
144
149
|
|
|
145
150
|
const {
|
|
146
151
|
generateOverflowHelpers: helperGenerateOverflowHelpers,
|
|
@@ -387,7 +392,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
387
392
|
return {
|
|
388
393
|
symbolTable: CodeGenState.symbolTable,
|
|
389
394
|
symbols: CodeGenState.symbols,
|
|
390
|
-
typeRegistry: CodeGenState.
|
|
395
|
+
typeRegistry: CodeGenState.getTypeRegistryView(),
|
|
391
396
|
functionSignatures: CodeGenState.functionSignatures,
|
|
392
397
|
knownFunctions: CodeGenState.knownFunctions,
|
|
393
398
|
knownStructs: CodeGenState.symbols?.knownStructs ?? new Set(),
|
|
@@ -451,7 +456,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
451
456
|
|
|
452
457
|
// Type registration effects
|
|
453
458
|
case "register-type":
|
|
454
|
-
CodeGenState.
|
|
459
|
+
CodeGenState.setVariableTypeInfo(effect.name, effect.info);
|
|
455
460
|
break;
|
|
456
461
|
case "register-local":
|
|
457
462
|
CodeGenState.localVariables.add(effect.name);
|
|
@@ -727,7 +732,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
727
732
|
|
|
728
733
|
// Check if it's a simple variable of string type
|
|
729
734
|
if (/^[a-zA-Z_]\w*$/.exec(text)) {
|
|
730
|
-
const typeInfo = CodeGenState.
|
|
735
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(text);
|
|
731
736
|
if (typeInfo?.isString) {
|
|
732
737
|
return true;
|
|
733
738
|
}
|
|
@@ -759,7 +764,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
759
764
|
}
|
|
760
765
|
|
|
761
766
|
const arrayName = arrayAccessMatch[1];
|
|
762
|
-
const typeInfo = CodeGenState.
|
|
767
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(arrayName);
|
|
763
768
|
if (!typeInfo) {
|
|
764
769
|
return false;
|
|
765
770
|
}
|
|
@@ -864,13 +869,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
864
869
|
|
|
865
870
|
/**
|
|
866
871
|
* Generate function argument with pass-by-reference handling.
|
|
867
|
-
* Part of IOrchestrator interface - delegates to
|
|
872
|
+
* Part of IOrchestrator interface - delegates to ArgumentGenerator.
|
|
868
873
|
*/
|
|
869
874
|
generateFunctionArg(
|
|
870
875
|
ctx: Parser.ExpressionContext,
|
|
871
876
|
targetParamBaseType?: string,
|
|
872
877
|
): string {
|
|
873
|
-
|
|
878
|
+
const simpleId = CodegenParserUtils.getSimpleIdentifier(ctx);
|
|
879
|
+
return ArgumentGenerator.generateArg(ctx, simpleId, targetParamBaseType, {
|
|
880
|
+
getLvalueType: (c) => this.getLvalueType(c),
|
|
881
|
+
getMemberAccessArrayStatus: (c) => this.getMemberAccessArrayStatus(c),
|
|
882
|
+
needsCppMemberConversion: (c, t) => this.needsCppMemberConversion(c, t),
|
|
883
|
+
isStringSubscriptAccess: (c) => this.isStringSubscriptAccess(c),
|
|
884
|
+
generateExpression: (c) => this.generateExpression(c),
|
|
885
|
+
});
|
|
874
886
|
}
|
|
875
887
|
|
|
876
888
|
/**
|
|
@@ -1360,21 +1372,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1360
1372
|
|
|
1361
1373
|
/** Get the capacity of a string expression */
|
|
1362
1374
|
getStringExprCapacity(exprCode: string): number | null {
|
|
1363
|
-
|
|
1364
|
-
if (exprCode.startsWith('"') && exprCode.endsWith('"')) {
|
|
1365
|
-
return StringUtils.literalLength(exprCode);
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
// Variable - check type registry
|
|
1369
|
-
const identifierRegex = /^[a-zA-Z_]\w*$/;
|
|
1370
|
-
if (identifierRegex.test(exprCode)) {
|
|
1371
|
-
const typeInfo = CodeGenState.typeRegistry.get(exprCode);
|
|
1372
|
-
if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
|
|
1373
|
-
return typeInfo.stringCapacity;
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
return null;
|
|
1375
|
+
return StringOperationsHelper.getStringExprCapacity(exprCode);
|
|
1378
1376
|
}
|
|
1379
1377
|
|
|
1380
1378
|
// === Parameter Management (IOrchestrator A4) ===
|
|
@@ -1433,25 +1431,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1433
1431
|
|
|
1434
1432
|
// === Function Body Management (A4) ===
|
|
1435
1433
|
|
|
1434
|
+
/**
|
|
1435
|
+
* Enter function body - clears local variables and sets inFunctionBody flag.
|
|
1436
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
1437
|
+
*/
|
|
1436
1438
|
enterFunctionBody(): void {
|
|
1437
|
-
|
|
1438
|
-
CodeGenState.floatBitShadows.clear();
|
|
1439
|
-
CodeGenState.floatShadowCurrent.clear();
|
|
1440
|
-
// Issue #558: modifiedParameters tracking removed - uses analysis-phase results
|
|
1441
|
-
CodeGenState.inFunctionBody = true;
|
|
1442
|
-
// Sync with CodeGenState
|
|
1443
|
-
CodeGenState.enterFunctionBody();
|
|
1439
|
+
FunctionContextManager.enterFunctionBody();
|
|
1444
1440
|
}
|
|
1445
1441
|
|
|
1442
|
+
/**
|
|
1443
|
+
* Exit function body - clears local variables and inFunctionBody flag.
|
|
1444
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
1445
|
+
*/
|
|
1446
1446
|
exitFunctionBody(): void {
|
|
1447
|
-
|
|
1448
|
-
CodeGenState.localVariables.clear();
|
|
1449
|
-
CodeGenState.floatBitShadows.clear();
|
|
1450
|
-
CodeGenState.floatShadowCurrent.clear();
|
|
1451
|
-
CodeGenState.mainArgsName = null;
|
|
1452
|
-
// Sync with CodeGenState
|
|
1453
|
-
CodeGenState.exitFunctionBody();
|
|
1454
|
-
CodeGenState.mainArgsName = null;
|
|
1447
|
+
FunctionContextManager.exitFunctionBody();
|
|
1455
1448
|
}
|
|
1456
1449
|
|
|
1457
1450
|
setMainArgsName(name: string | null): void {
|
|
@@ -1604,7 +1597,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1604
1597
|
const injectedFuncs = new Set(crossFileModifications?.keys() ?? []);
|
|
1605
1598
|
|
|
1606
1599
|
// Run modification analysis on the tree (adds to what was injected)
|
|
1607
|
-
|
|
1600
|
+
PassByValueAnalyzer.collectFunctionParametersAndModifications(tree);
|
|
1608
1601
|
|
|
1609
1602
|
// Issue #565: Run transitive propagation with full context
|
|
1610
1603
|
TransitiveModificationPropagator.propagate(
|
|
@@ -1951,7 +1944,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1951
1944
|
isKnownPrimitive: (typeName: string) => this._isKnownPrimitive(typeName),
|
|
1952
1945
|
knownEnums: CodeGenState.symbols!.knownEnums,
|
|
1953
1946
|
isParameterPassByValue: (funcName: string, paramName: string) =>
|
|
1954
|
-
|
|
1947
|
+
PassByValueAnalyzer.isParameterPassByValueByName(funcName, paramName),
|
|
1955
1948
|
currentFunctionName: CodeGenState.currentFunctionName,
|
|
1956
1949
|
maybeDereference: (id: string) => CppModeHelper.maybeDereference(id),
|
|
1957
1950
|
};
|
|
@@ -2171,19 +2164,18 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2171
2164
|
}
|
|
2172
2165
|
|
|
2173
2166
|
// Issue #461: Initialize constValues from symbol table
|
|
2167
|
+
// Only C-Next TSymbols have initialValue property
|
|
2174
2168
|
CodeGenState.constValues = new Map();
|
|
2175
2169
|
if (CodeGenState.symbolTable) {
|
|
2176
|
-
for (const symbol of CodeGenState.symbolTable.
|
|
2170
|
+
for (const symbol of CodeGenState.symbolTable.getAllTSymbols()) {
|
|
2177
2171
|
if (
|
|
2178
|
-
symbol.kind ===
|
|
2172
|
+
symbol.kind === "variable" &&
|
|
2179
2173
|
symbol.isConst &&
|
|
2180
2174
|
symbol.initialValue !== undefined
|
|
2181
2175
|
) {
|
|
2182
2176
|
const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
|
|
2183
2177
|
if (value !== undefined) {
|
|
2184
2178
|
CodeGenState.constValues.set(symbol.name, value);
|
|
2185
|
-
// Also populate CodeGenState
|
|
2186
|
-
CodeGenState.constValues.set(symbol.name, value);
|
|
2187
2179
|
}
|
|
2188
2180
|
}
|
|
2189
2181
|
}
|
|
@@ -2196,7 +2188,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2196
2188
|
private initializeHelperObjects(tree: Parser.ProgramContext): void {
|
|
2197
2189
|
// Collect function/callback information
|
|
2198
2190
|
this.collectFunctionsAndCallbacks(tree);
|
|
2199
|
-
|
|
2191
|
+
PassByValueAnalyzer.analyze(tree);
|
|
2200
2192
|
}
|
|
2201
2193
|
|
|
2202
2194
|
/**
|
|
@@ -2491,7 +2483,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2491
2483
|
const funcDecl = member.functionDeclaration()!;
|
|
2492
2484
|
const funcName = funcDecl.IDENTIFIER().getText();
|
|
2493
2485
|
// Track fully qualified function name: Scope_function
|
|
2494
|
-
const fullName =
|
|
2486
|
+
const fullName = QualifiedNameGenerator.forFunctionStrings(
|
|
2487
|
+
scopeName,
|
|
2488
|
+
funcName,
|
|
2489
|
+
);
|
|
2495
2490
|
CodeGenState.knownFunctions.add(fullName);
|
|
2496
2491
|
// ADR-013: Track function signature for const checking
|
|
2497
2492
|
const sig = this.extractFunctionSignature(
|
|
@@ -2556,66 +2551,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2556
2551
|
* SonarCloud S3776: Refactored to use helper methods.
|
|
2557
2552
|
*/
|
|
2558
2553
|
private registerAllVariableTypes(tree: Parser.ProgramContext): void {
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
// Register scope member variable types
|
|
2566
|
-
if (decl.scopeDeclaration()) {
|
|
2567
|
-
this.registerScopeMemberTypes(decl.scopeDeclaration()!);
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
|
-
// Note: Function parameters are registered per-function during generation
|
|
2571
|
-
// since they're scoped to the function body
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
|
|
2575
|
-
/**
|
|
2576
|
-
* Register a global variable type and track const values.
|
|
2577
|
-
* SonarCloud S3776: Extracted from registerAllVariableTypes().
|
|
2578
|
-
*/
|
|
2579
|
-
private registerGlobalVariableType(
|
|
2580
|
-
varDecl: Parser.VariableDeclarationContext,
|
|
2581
|
-
): void {
|
|
2582
|
-
this.trackVariableType(varDecl);
|
|
2583
|
-
|
|
2584
|
-
// Bug #8: Track const values for array size resolution at file scope
|
|
2585
|
-
if (varDecl.constModifier() && varDecl.expression()) {
|
|
2586
|
-
const constName = varDecl.IDENTIFIER().getText();
|
|
2587
|
-
const constValue = this.tryEvaluateConstant(varDecl.expression()!);
|
|
2588
|
-
if (constValue !== undefined) {
|
|
2589
|
-
CodeGenState.constValues.set(constName, constValue);
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
/**
|
|
2595
|
-
* Register scope member variable types.
|
|
2596
|
-
* SonarCloud S3776: Extracted from registerAllVariableTypes().
|
|
2597
|
-
*/
|
|
2598
|
-
private registerScopeMemberTypes(
|
|
2599
|
-
scopeDecl: Parser.ScopeDeclarationContext,
|
|
2600
|
-
): void {
|
|
2601
|
-
const scopeName = scopeDecl.IDENTIFIER().getText();
|
|
2602
|
-
|
|
2603
|
-
// Set currentScope so that this.Type references resolve correctly
|
|
2604
|
-
const savedScope = CodeGenState.currentScope;
|
|
2605
|
-
this.setCurrentScope(scopeName);
|
|
2606
|
-
|
|
2607
|
-
for (const member of scopeDecl.scopeMember()) {
|
|
2608
|
-
if (member.variableDeclaration()) {
|
|
2609
|
-
const varDecl = member.variableDeclaration()!;
|
|
2610
|
-
const varName = varDecl.IDENTIFIER().getText();
|
|
2611
|
-
const fullName = `${scopeName}_${varName}`;
|
|
2612
|
-
// Register with mangled name (Scope_variable)
|
|
2613
|
-
this.trackVariableTypeWithName(varDecl, fullName);
|
|
2614
|
-
}
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
// Restore previous scope
|
|
2618
|
-
this.setCurrentScope(savedScope);
|
|
2554
|
+
TypeRegistrationEngine.register(tree, {
|
|
2555
|
+
tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
|
|
2556
|
+
requireInclude: (header) => this.requireInclude(header),
|
|
2557
|
+
resolveQualifiedType: (ids) => this.resolveQualifiedType(ids),
|
|
2558
|
+
});
|
|
2619
2559
|
}
|
|
2620
2560
|
|
|
2621
2561
|
// Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
|
|
@@ -2623,1530 +2563,209 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2623
2563
|
// Issue #63: validateBitmapFieldLiteral moved to TypeValidator
|
|
2624
2564
|
// Issue #60: evaluateConstantExpression method removed - now in SymbolCollector
|
|
2625
2565
|
|
|
2626
|
-
//
|
|
2627
|
-
// Issue #269: Pass-by-value analysis for small unmodified parameters
|
|
2628
|
-
// ========================================================================
|
|
2566
|
+
// Issue #269: Pass-by-value analysis extracted to PassByValueAnalyzer
|
|
2629
2567
|
|
|
2630
2568
|
/**
|
|
2631
|
-
*
|
|
2632
|
-
*
|
|
2633
|
-
*
|
|
2569
|
+
* Issue #269: Check if a parameter should be passed by value (by index).
|
|
2570
|
+
* Part of IOrchestrator interface - used by CallExprGenerator.
|
|
2571
|
+
* Delegates to PassByValueAnalyzer.
|
|
2634
2572
|
*/
|
|
2635
|
-
|
|
2636
|
-
|
|
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();
|
|
2573
|
+
isParameterPassByValue(funcName: string, paramIndex: number): boolean {
|
|
2574
|
+
return PassByValueAnalyzer.isParameterPassByValue(funcName, paramIndex);
|
|
2658
2575
|
}
|
|
2659
2576
|
|
|
2660
2577
|
/**
|
|
2661
|
-
*
|
|
2662
|
-
*
|
|
2578
|
+
* Issue #269: Get all pass-by-value parameters.
|
|
2579
|
+
* Returns a Map from function name to Set of parameter names that should be pass-by-value.
|
|
2580
|
+
* Used by HeaderGenerator to ensure header and implementation signatures match.
|
|
2663
2581
|
*/
|
|
2664
|
-
|
|
2665
|
-
|
|
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
|
|
2582
|
+
getPassByValueParams(): ReadonlyMap<string, ReadonlySet<string>> {
|
|
2583
|
+
return CodeGenState.passByValueParams;
|
|
2681
2584
|
}
|
|
2682
2585
|
|
|
2683
2586
|
/**
|
|
2684
|
-
*
|
|
2685
|
-
*
|
|
2587
|
+
* Issue #322: Check if a type name is a user-defined struct
|
|
2588
|
+
* Part of IOrchestrator interface.
|
|
2686
2589
|
*/
|
|
2687
|
-
|
|
2688
|
-
|
|
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
|
|
2590
|
+
isStructType(typeName: string): boolean {
|
|
2591
|
+
return TypeResolver.isStructType(typeName);
|
|
2696
2592
|
}
|
|
2697
2593
|
|
|
2698
2594
|
/**
|
|
2699
|
-
*
|
|
2700
|
-
*
|
|
2701
|
-
* - Direct modifications (param <- value)
|
|
2702
|
-
* - Function calls where params are passed as arguments
|
|
2595
|
+
* Set up parameter tracking for a function.
|
|
2596
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
2703
2597
|
*/
|
|
2704
|
-
private
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
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
|
-
}
|
|
2598
|
+
private _setParameters(params: Parser.ParameterListContext | null): void {
|
|
2599
|
+
FunctionContextManager.processParameterList(
|
|
2600
|
+
params,
|
|
2601
|
+
this._getFunctionContextCallbacks(),
|
|
2602
|
+
);
|
|
2730
2603
|
}
|
|
2731
2604
|
|
|
2732
2605
|
/**
|
|
2733
|
-
*
|
|
2606
|
+
* Clear parameter tracking when leaving a function.
|
|
2607
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
2734
2608
|
*/
|
|
2735
|
-
private
|
|
2736
|
-
|
|
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
|
-
}
|
|
2609
|
+
private _clearParameters(): void {
|
|
2610
|
+
FunctionContextManager.clearParameters();
|
|
2760
2611
|
}
|
|
2761
2612
|
|
|
2762
2613
|
/**
|
|
2763
|
-
*
|
|
2614
|
+
* ADR-013: Extract function signature from parameter list
|
|
2764
2615
|
*/
|
|
2765
|
-
private
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2616
|
+
private extractFunctionSignature(
|
|
2617
|
+
name: string,
|
|
2618
|
+
params: Parser.ParameterListContext | null,
|
|
2619
|
+
): FunctionSignature {
|
|
2620
|
+
const parameters: Array<{
|
|
2621
|
+
name: string;
|
|
2622
|
+
baseType: string;
|
|
2623
|
+
isConst: boolean;
|
|
2624
|
+
isArray: boolean;
|
|
2625
|
+
}> = [];
|
|
2771
2626
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2627
|
+
if (params) {
|
|
2628
|
+
for (const param of params.parameter()) {
|
|
2629
|
+
const paramName = param.IDENTIFIER().getText();
|
|
2630
|
+
const isConst = param.constModifier() !== null;
|
|
2631
|
+
// arrayDimension() returns an array (due to grammar's *), so check length
|
|
2632
|
+
// Also check C-Next style array type (e.g., u8[8] param)
|
|
2633
|
+
const isArray =
|
|
2634
|
+
param.arrayDimension().length > 0 ||
|
|
2635
|
+
param.type().arrayType() !== null;
|
|
2636
|
+
const baseType = this.getTypeName(param.type());
|
|
2637
|
+
parameters.push({ name: paramName, baseType, isConst, isArray });
|
|
2638
|
+
}
|
|
2774
2639
|
}
|
|
2640
|
+
|
|
2641
|
+
return { name, parameters };
|
|
2775
2642
|
}
|
|
2776
2643
|
|
|
2777
2644
|
/**
|
|
2778
|
-
*
|
|
2779
|
-
*
|
|
2645
|
+
* ADR-029: Register a function as a callback type
|
|
2646
|
+
* The function name becomes both a callable function and a type for callback fields
|
|
2780
2647
|
*/
|
|
2781
|
-
private
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
stmt: Parser.StatementContext,
|
|
2648
|
+
private registerCallbackType(
|
|
2649
|
+
name: string,
|
|
2650
|
+
funcDecl: Parser.FunctionDeclarationContext,
|
|
2785
2651
|
): void {
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2652
|
+
const returnType = this.generateType(funcDecl.type());
|
|
2653
|
+
const parameters: Array<{
|
|
2654
|
+
name: string;
|
|
2655
|
+
type: string;
|
|
2656
|
+
isConst: boolean;
|
|
2657
|
+
isPointer: boolean;
|
|
2658
|
+
isArray: boolean;
|
|
2659
|
+
arrayDims: string;
|
|
2660
|
+
}> = [];
|
|
2790
2661
|
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2662
|
+
if (funcDecl.parameterList()) {
|
|
2663
|
+
for (const param of funcDecl.parameterList()!.parameter()) {
|
|
2664
|
+
const paramName = param.IDENTIFIER().getText();
|
|
2665
|
+
const typeName = this.getTypeName(param.type());
|
|
2666
|
+
const isConst = param.constModifier() !== null;
|
|
2667
|
+
const dims = param.arrayDimension();
|
|
2668
|
+
const arrayTypeCtx = param.type().arrayType();
|
|
2669
|
+
const isArray = dims.length > 0 || arrayTypeCtx !== null;
|
|
2797
2670
|
|
|
2798
|
-
|
|
2799
|
-
|
|
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
|
-
}
|
|
2671
|
+
// ADR-029: Check if parameter type is itself a callback type
|
|
2672
|
+
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
2807
2673
|
|
|
2808
|
-
|
|
2809
|
-
|
|
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();
|
|
2674
|
+
let paramType: string;
|
|
2675
|
+
let isPointer: boolean;
|
|
2819
2676
|
|
|
2820
|
-
|
|
2821
|
-
|
|
2677
|
+
if (isCallbackParam) {
|
|
2678
|
+
// Use the callback typedef name
|
|
2679
|
+
const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
2680
|
+
paramType = cbInfo.typedefName;
|
|
2681
|
+
isPointer = false; // Function pointers are already pointers
|
|
2682
|
+
} else {
|
|
2683
|
+
paramType = this.generateType(param.type());
|
|
2684
|
+
// ADR-006: Non-array parameters become pointers
|
|
2685
|
+
isPointer = !isArray;
|
|
2686
|
+
}
|
|
2822
2687
|
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2688
|
+
let arrayDims: string;
|
|
2689
|
+
if (dims.length > 0) {
|
|
2690
|
+
arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
2691
|
+
} else if (arrayTypeCtx) {
|
|
2692
|
+
// Generate all dimensions from arrayType (supports multi-dimensional)
|
|
2693
|
+
arrayDims = arrayTypeCtx
|
|
2694
|
+
.arrayTypeDimension()
|
|
2695
|
+
.map((d) => {
|
|
2696
|
+
const expr = d.expression();
|
|
2697
|
+
return expr ? `[${this.generateExpression(expr)}]` : "[]";
|
|
2698
|
+
})
|
|
2699
|
+
.join("");
|
|
2700
|
+
} else {
|
|
2701
|
+
arrayDims = "";
|
|
2702
|
+
}
|
|
2703
|
+
parameters.push({
|
|
2704
|
+
name: paramName,
|
|
2705
|
+
type: paramType,
|
|
2706
|
+
isConst,
|
|
2707
|
+
isPointer,
|
|
2708
|
+
isArray,
|
|
2709
|
+
arrayDims,
|
|
2710
|
+
});
|
|
2711
|
+
}
|
|
2832
2712
|
}
|
|
2833
2713
|
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2714
|
+
CodeGenState.callbackTypes.set(name, {
|
|
2715
|
+
functionName: name,
|
|
2716
|
+
returnType,
|
|
2717
|
+
parameters,
|
|
2718
|
+
typedefName: `${name}_fp`,
|
|
2719
|
+
});
|
|
2838
2720
|
}
|
|
2839
2721
|
|
|
2840
2722
|
/**
|
|
2841
|
-
*
|
|
2842
|
-
* Uses recursive descent through the expression hierarchy.
|
|
2723
|
+
* ADR-029: Check if a function is used as a callback type (field type in a struct)
|
|
2843
2724
|
*/
|
|
2844
|
-
|
|
2845
|
-
|
|
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
|
-
}
|
|
2725
|
+
// Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
|
|
2726
|
+
// and validateBareIdentifierInScope moved to TypeValidator
|
|
2858
2727
|
|
|
2728
|
+
// EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
|
|
2729
|
+
// _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
|
|
2730
|
+
// _getExpressionEnumType, _getFunctionCallEnumType
|
|
2859
2731
|
/**
|
|
2860
|
-
*
|
|
2861
|
-
*
|
|
2862
|
-
* Parameters with subscript access must become pointers.
|
|
2732
|
+
* ADR-017: Check if an expression represents an integer literal or numeric type.
|
|
2733
|
+
* Used to detect comparisons between enums and integers.
|
|
2863
2734
|
*/
|
|
2864
|
-
private
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
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
|
-
}
|
|
2735
|
+
private _isIntegerExpression(
|
|
2736
|
+
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
2737
|
+
): boolean {
|
|
2738
|
+
return EnumAssignmentValidator.isIntegerExpression(ctx);
|
|
2877
2739
|
}
|
|
2878
2740
|
|
|
2879
2741
|
/**
|
|
2880
|
-
*
|
|
2881
|
-
*
|
|
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.
|
|
2742
|
+
* ADR-045: Check if an expression is a string concatenation.
|
|
2743
|
+
* Delegates to StringOperationsHelper.
|
|
2884
2744
|
*/
|
|
2885
|
-
private
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
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
|
-
}
|
|
2745
|
+
private _getStringConcatOperands(ctx: Parser.ExpressionContext): {
|
|
2746
|
+
left: string;
|
|
2747
|
+
right: string;
|
|
2748
|
+
leftCapacity: number;
|
|
2749
|
+
rightCapacity: number;
|
|
2750
|
+
} | null {
|
|
2751
|
+
return StringOperationsHelper.getStringConcatOperands(ctx);
|
|
2910
2752
|
}
|
|
2911
2753
|
|
|
2912
2754
|
/**
|
|
2913
|
-
*
|
|
2914
|
-
*
|
|
2915
|
-
* Used by both function call tracking and subscript access tracking.
|
|
2755
|
+
* ADR-045: Check if an expression is a substring extraction.
|
|
2756
|
+
* Delegates to StringOperationsHelper.
|
|
2916
2757
|
*/
|
|
2917
|
-
private
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
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);
|
|
2758
|
+
private _getSubstringOperands(ctx: Parser.ExpressionContext): {
|
|
2759
|
+
source: string;
|
|
2760
|
+
start: string;
|
|
2761
|
+
length: string;
|
|
2762
|
+
sourceCapacity: number;
|
|
2763
|
+
} | null {
|
|
2764
|
+
return StringOperationsHelper.getSubstringOperands(ctx, {
|
|
2765
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
2945
2766
|
});
|
|
2946
2767
|
}
|
|
2947
2768
|
|
|
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
|
-
}
|
|
3189
|
-
|
|
3190
|
-
/**
|
|
3191
|
-
* Issue #269: Check if a parameter should be passed by value (by index).
|
|
3192
|
-
* Part of IOrchestrator interface - used by CallExprGenerator.
|
|
3193
|
-
*/
|
|
3194
|
-
isParameterPassByValue(funcName: string, paramIndex: number): boolean {
|
|
3195
|
-
const paramList = CodeGenState.functionParamLists.get(funcName);
|
|
3196
|
-
if (!paramList || paramIndex < 0 || paramIndex >= paramList.length) {
|
|
3197
|
-
return false;
|
|
3198
|
-
}
|
|
3199
|
-
const paramName = paramList[paramIndex];
|
|
3200
|
-
return this._isParameterPassByValueByName(funcName, paramName);
|
|
3201
|
-
}
|
|
3202
|
-
|
|
3203
|
-
/**
|
|
3204
|
-
* Issue #269: Get all pass-by-value parameters.
|
|
3205
|
-
* Returns a Map from function name to Set of parameter names that should be pass-by-value.
|
|
3206
|
-
* Used by HeaderGenerator to ensure header and implementation signatures match.
|
|
3207
|
-
*/
|
|
3208
|
-
getPassByValueParams(): ReadonlyMap<string, ReadonlySet<string>> {
|
|
3209
|
-
return CodeGenState.passByValueParams;
|
|
3210
|
-
}
|
|
3211
|
-
|
|
3212
|
-
/**
|
|
3213
|
-
* ADR-036: Try to evaluate an expression as a compile-time constant.
|
|
3214
|
-
* Returns the numeric value if constant, undefined if not evaluable.
|
|
3215
|
-
* Bug #8: Extended to resolve const variable references for file-scope array sizes.
|
|
3216
|
-
* Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
|
|
3217
|
-
*/
|
|
3218
|
-
// Issue #63: checkArrayBounds moved to TypeValidator
|
|
3219
|
-
|
|
3220
|
-
/**
|
|
3221
|
-
* Evaluate array dimensions from ArrayDimensionContext[] to number[].
|
|
3222
|
-
* Used for bitmap array registration.
|
|
3223
|
-
* Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
|
|
3224
|
-
*/
|
|
3225
|
-
private _evaluateArrayDimensions(
|
|
3226
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3227
|
-
): number[] | undefined {
|
|
3228
|
-
return ArrayDimensionParser.parseAllDimensions(arrayDim, {
|
|
3229
|
-
constValues: CodeGenState.constValues,
|
|
3230
|
-
typeWidths: TYPE_WIDTH,
|
|
3231
|
-
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
3232
|
-
});
|
|
3233
|
-
}
|
|
3234
|
-
|
|
3235
|
-
/**
|
|
3236
|
-
* Try to register a type as enum or bitmap. Returns true if handled.
|
|
3237
|
-
* Extracted to reduce duplication across type contexts (ADR-017, ADR-034).
|
|
3238
|
-
*/
|
|
3239
|
-
private _tryRegisterEnumOrBitmapType(
|
|
3240
|
-
name: string,
|
|
3241
|
-
baseType: string,
|
|
3242
|
-
isConst: boolean,
|
|
3243
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3244
|
-
overflowBehavior: TOverflowBehavior,
|
|
3245
|
-
isAtomic: boolean,
|
|
3246
|
-
): boolean {
|
|
3247
|
-
// Common options for type registration
|
|
3248
|
-
const registrationOptions = {
|
|
3249
|
-
name,
|
|
3250
|
-
baseType,
|
|
3251
|
-
isConst,
|
|
3252
|
-
overflowBehavior,
|
|
3253
|
-
isAtomic,
|
|
3254
|
-
};
|
|
3255
|
-
|
|
3256
|
-
// ADR-017: Check if this is an enum type
|
|
3257
|
-
if (
|
|
3258
|
-
TypeRegistrationUtils.tryRegisterEnumType(
|
|
3259
|
-
CodeGenState.typeRegistry,
|
|
3260
|
-
CodeGenState.symbols!,
|
|
3261
|
-
registrationOptions,
|
|
3262
|
-
)
|
|
3263
|
-
) {
|
|
3264
|
-
return true;
|
|
3265
|
-
}
|
|
3266
|
-
|
|
3267
|
-
// ADR-034: Check if this is a bitmap type
|
|
3268
|
-
const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
|
|
3269
|
-
if (
|
|
3270
|
-
TypeRegistrationUtils.tryRegisterBitmapType(
|
|
3271
|
-
CodeGenState.typeRegistry,
|
|
3272
|
-
CodeGenState.symbols!,
|
|
3273
|
-
registrationOptions,
|
|
3274
|
-
bitmapDimensions,
|
|
3275
|
-
)
|
|
3276
|
-
) {
|
|
3277
|
-
return true;
|
|
3278
|
-
}
|
|
3279
|
-
|
|
3280
|
-
return false;
|
|
3281
|
-
}
|
|
3282
|
-
|
|
3283
|
-
/**
|
|
3284
|
-
* Extract type info from a variable declaration and register it.
|
|
3285
|
-
* Delegates to trackVariableTypeWithName using the variable's identifier.
|
|
3286
|
-
*/
|
|
3287
|
-
private trackVariableType(varDecl: Parser.VariableDeclarationContext): void {
|
|
3288
|
-
const name = varDecl.IDENTIFIER().getText();
|
|
3289
|
-
this.trackVariableTypeWithName(varDecl, name);
|
|
3290
|
-
}
|
|
3291
|
-
|
|
3292
|
-
// =========================================================================
|
|
3293
|
-
// Type Registration Helpers - Extracted to reduce cognitive complexity
|
|
3294
|
-
// =========================================================================
|
|
3295
|
-
|
|
3296
|
-
/**
|
|
3297
|
-
* Extract array dimensions from ArrayDimensionContext array (simple parseInt version)
|
|
3298
|
-
* Used for string array dimensions where const evaluation is not needed.
|
|
3299
|
-
* Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
|
|
3300
|
-
*/
|
|
3301
|
-
private extractArrayDimensionsSimple(
|
|
3302
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3303
|
-
): number[] {
|
|
3304
|
-
return ArrayDimensionParser.parseSimpleDimensions(arrayDim);
|
|
3305
|
-
}
|
|
3306
|
-
|
|
3307
|
-
/**
|
|
3308
|
-
* Register a string type in the type registry
|
|
3309
|
-
* Returns true if registration was successful
|
|
3310
|
-
*/
|
|
3311
|
-
private tryRegisterStringType(
|
|
3312
|
-
registryName: string,
|
|
3313
|
-
typeCtx: Parser.TypeContext,
|
|
3314
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3315
|
-
isConst: boolean,
|
|
3316
|
-
overflowBehavior: TOverflowBehavior,
|
|
3317
|
-
isAtomic: boolean,
|
|
3318
|
-
): boolean {
|
|
3319
|
-
const stringCtx = typeCtx.stringType();
|
|
3320
|
-
if (!stringCtx) {
|
|
3321
|
-
return false;
|
|
3322
|
-
}
|
|
3323
|
-
|
|
3324
|
-
const intLiteral = stringCtx.INTEGER_LITERAL();
|
|
3325
|
-
if (!intLiteral) {
|
|
3326
|
-
return false;
|
|
3327
|
-
}
|
|
3328
|
-
|
|
3329
|
-
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
3330
|
-
this.requireInclude("string");
|
|
3331
|
-
const stringDim = capacity + 1;
|
|
3332
|
-
|
|
3333
|
-
// Check if there are additional array dimensions (e.g., [4] in string<64> arr[4])
|
|
3334
|
-
const additionalDims = this.extractArrayDimensionsSimple(arrayDim);
|
|
3335
|
-
const allDims =
|
|
3336
|
-
additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
|
|
3337
|
-
|
|
3338
|
-
CodeGenState.typeRegistry.set(registryName, {
|
|
3339
|
-
baseType: "char",
|
|
3340
|
-
bitWidth: 8,
|
|
3341
|
-
isArray: true,
|
|
3342
|
-
arrayDimensions: allDims,
|
|
3343
|
-
isConst,
|
|
3344
|
-
isString: true,
|
|
3345
|
-
stringCapacity: capacity,
|
|
3346
|
-
overflowBehavior,
|
|
3347
|
-
isAtomic,
|
|
3348
|
-
});
|
|
3349
|
-
return true;
|
|
3350
|
-
}
|
|
3351
|
-
|
|
3352
|
-
/**
|
|
3353
|
-
* Resolve base type name from a type context
|
|
3354
|
-
* Handles scoped, global, qualified, and user types
|
|
3355
|
-
*/
|
|
3356
|
-
private resolveBaseTypeFromContext(
|
|
3357
|
-
typeCtx: Parser.TypeContext,
|
|
3358
|
-
): string | null {
|
|
3359
|
-
if (typeCtx.primitiveType()) {
|
|
3360
|
-
return typeCtx.primitiveType()!.getText();
|
|
3361
|
-
}
|
|
3362
|
-
|
|
3363
|
-
if (typeCtx.scopedType()) {
|
|
3364
|
-
// ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
|
|
3365
|
-
const typeName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
3366
|
-
return CodeGenState.currentScope
|
|
3367
|
-
? `${CodeGenState.currentScope}_${typeName}`
|
|
3368
|
-
: typeName;
|
|
3369
|
-
}
|
|
3370
|
-
|
|
3371
|
-
if (typeCtx.globalType()) {
|
|
3372
|
-
// Issue #478: Handle global.Type for global types inside scope
|
|
3373
|
-
return typeCtx.globalType()!.IDENTIFIER().getText();
|
|
3374
|
-
}
|
|
3375
|
-
|
|
3376
|
-
if (typeCtx.qualifiedType()) {
|
|
3377
|
-
// ADR-016: Handle Scope.Type from outside scope
|
|
3378
|
-
// Issue #388: Also handles C++ namespace types
|
|
3379
|
-
const identifiers = typeCtx.qualifiedType()!.IDENTIFIER();
|
|
3380
|
-
const identifierNames = identifiers.map((id) => id.getText());
|
|
3381
|
-
return this.resolveQualifiedType(identifierNames);
|
|
3382
|
-
}
|
|
3383
|
-
|
|
3384
|
-
if (typeCtx.userType()) {
|
|
3385
|
-
return typeCtx.userType()!.getText();
|
|
3386
|
-
}
|
|
3387
|
-
|
|
3388
|
-
return null;
|
|
3389
|
-
}
|
|
3390
|
-
|
|
3391
|
-
/**
|
|
3392
|
-
* Track variable type with a specific name (for namespace/class members)
|
|
3393
|
-
* This allows tracking with mangled names for proper scope resolution
|
|
3394
|
-
*/
|
|
3395
|
-
private trackVariableTypeWithName(
|
|
3396
|
-
varDecl: Parser.VariableDeclarationContext,
|
|
3397
|
-
registryName: string,
|
|
3398
|
-
): void {
|
|
3399
|
-
const typeCtx = varDecl.type();
|
|
3400
|
-
const arrayDim = varDecl.arrayDimension();
|
|
3401
|
-
const isConst = varDecl.constModifier() !== null;
|
|
3402
|
-
|
|
3403
|
-
// ADR-044: Extract overflow modifier (clamp is default)
|
|
3404
|
-
const overflowMod = varDecl.overflowModifier();
|
|
3405
|
-
const overflowBehavior: TOverflowBehavior =
|
|
3406
|
-
overflowMod?.getText() === "wrap" ? "wrap" : "clamp";
|
|
3407
|
-
|
|
3408
|
-
// ADR-049: Extract atomic modifier
|
|
3409
|
-
const isAtomic = varDecl.atomicModifier() !== null;
|
|
3410
|
-
|
|
3411
|
-
// ADR-045: Handle bounded string type first (special case)
|
|
3412
|
-
if (
|
|
3413
|
-
this.tryRegisterStringType(
|
|
3414
|
-
registryName,
|
|
3415
|
-
typeCtx,
|
|
3416
|
-
arrayDim,
|
|
3417
|
-
isConst,
|
|
3418
|
-
overflowBehavior,
|
|
3419
|
-
isAtomic,
|
|
3420
|
-
)
|
|
3421
|
-
) {
|
|
3422
|
-
return;
|
|
3423
|
-
}
|
|
3424
|
-
|
|
3425
|
-
// Handle array type syntax: u8[10]
|
|
3426
|
-
if (typeCtx.arrayType()) {
|
|
3427
|
-
this._registerArrayTypeVariable(
|
|
3428
|
-
registryName,
|
|
3429
|
-
typeCtx.arrayType()!,
|
|
3430
|
-
arrayDim,
|
|
3431
|
-
isConst,
|
|
3432
|
-
overflowBehavior,
|
|
3433
|
-
isAtomic,
|
|
3434
|
-
);
|
|
3435
|
-
return;
|
|
3436
|
-
}
|
|
3437
|
-
|
|
3438
|
-
// Resolve base type from context (handles scoped, global, qualified, user types)
|
|
3439
|
-
const baseType = this.resolveBaseTypeFromContext(typeCtx);
|
|
3440
|
-
if (!baseType) {
|
|
3441
|
-
return;
|
|
3442
|
-
}
|
|
3443
|
-
|
|
3444
|
-
// ADR-017/ADR-034: Check if enum or bitmap type (reuse existing helper)
|
|
3445
|
-
if (
|
|
3446
|
-
this._tryRegisterEnumOrBitmapType(
|
|
3447
|
-
registryName,
|
|
3448
|
-
baseType,
|
|
3449
|
-
isConst,
|
|
3450
|
-
arrayDim,
|
|
3451
|
-
overflowBehavior,
|
|
3452
|
-
isAtomic,
|
|
3453
|
-
)
|
|
3454
|
-
) {
|
|
3455
|
-
return;
|
|
3456
|
-
}
|
|
3457
|
-
|
|
3458
|
-
// Standard type registration
|
|
3459
|
-
this._registerStandardType(
|
|
3460
|
-
registryName,
|
|
3461
|
-
baseType,
|
|
3462
|
-
arrayDim,
|
|
3463
|
-
isConst,
|
|
3464
|
-
overflowBehavior,
|
|
3465
|
-
isAtomic,
|
|
3466
|
-
);
|
|
3467
|
-
}
|
|
3468
|
-
|
|
3469
|
-
/**
|
|
3470
|
-
* Register an array type variable (u8[10] syntax)
|
|
3471
|
-
*/
|
|
3472
|
-
private _registerArrayTypeVariable(
|
|
3473
|
-
registryName: string,
|
|
3474
|
-
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
3475
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3476
|
-
isConst: boolean,
|
|
3477
|
-
overflowBehavior: TOverflowBehavior,
|
|
3478
|
-
isAtomic: boolean,
|
|
3479
|
-
): void {
|
|
3480
|
-
let baseType = "";
|
|
3481
|
-
let bitWidth = 0;
|
|
3482
|
-
|
|
3483
|
-
if (arrayTypeCtx.primitiveType()) {
|
|
3484
|
-
baseType = arrayTypeCtx.primitiveType()!.getText();
|
|
3485
|
-
bitWidth = TYPE_WIDTH[baseType] || 0;
|
|
3486
|
-
} else if (arrayTypeCtx.userType()) {
|
|
3487
|
-
// Handle user types (structs, enums, bitmaps)
|
|
3488
|
-
baseType = arrayTypeCtx.userType()!.getText();
|
|
3489
|
-
|
|
3490
|
-
const combinedArrayDim = arrayDim ?? [];
|
|
3491
|
-
|
|
3492
|
-
// Check if this is an enum or bitmap type and delegate to proper registration
|
|
3493
|
-
if (
|
|
3494
|
-
this._tryRegisterEnumOrBitmapType(
|
|
3495
|
-
registryName,
|
|
3496
|
-
baseType,
|
|
3497
|
-
isConst,
|
|
3498
|
-
combinedArrayDim,
|
|
3499
|
-
overflowBehavior,
|
|
3500
|
-
isAtomic,
|
|
3501
|
-
)
|
|
3502
|
-
) {
|
|
3503
|
-
// Enum/bitmap was registered, but we need to update with arrayType dimension
|
|
3504
|
-
const existingInfo = CodeGenState.typeRegistry.get(registryName);
|
|
3505
|
-
if (existingInfo) {
|
|
3506
|
-
const arrayTypeDim =
|
|
3507
|
-
this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
|
|
3508
|
-
const allDims = arrayTypeDim
|
|
3509
|
-
? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
|
|
3510
|
-
: existingInfo.arrayDimensions;
|
|
3511
|
-
CodeGenState.typeRegistry.set(registryName, {
|
|
3512
|
-
...existingInfo,
|
|
3513
|
-
isArray: true,
|
|
3514
|
-
arrayDimensions: allDims,
|
|
3515
|
-
});
|
|
3516
|
-
}
|
|
3517
|
-
return;
|
|
3518
|
-
}
|
|
3519
|
-
|
|
3520
|
-
// Not an enum/bitmap - register as regular user type (struct)
|
|
3521
|
-
// bitWidth already initialized to 0, no reassignment needed
|
|
3522
|
-
}
|
|
3523
|
-
|
|
3524
|
-
if (!baseType) {
|
|
3525
|
-
return;
|
|
3526
|
-
}
|
|
3527
|
-
|
|
3528
|
-
const arrayDimensions = this._collectArrayDimensions(
|
|
3529
|
-
arrayTypeCtx,
|
|
3530
|
-
arrayDim,
|
|
3531
|
-
);
|
|
3532
|
-
|
|
3533
|
-
CodeGenState.typeRegistry.set(registryName, {
|
|
3534
|
-
baseType,
|
|
3535
|
-
bitWidth,
|
|
3536
|
-
isArray: true,
|
|
3537
|
-
arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
|
|
3538
|
-
isConst,
|
|
3539
|
-
overflowBehavior,
|
|
3540
|
-
isAtomic,
|
|
3541
|
-
});
|
|
3542
|
-
}
|
|
3543
|
-
|
|
3544
|
-
/**
|
|
3545
|
-
* Parse array dimension from arrayType context.
|
|
3546
|
-
*/
|
|
3547
|
-
private _parseArrayTypeDimensionFromCtx(
|
|
3548
|
-
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
3549
|
-
): number | undefined {
|
|
3550
|
-
// Get first dimension for backwards compatibility
|
|
3551
|
-
const dims = arrayTypeCtx.arrayTypeDimension();
|
|
3552
|
-
if (dims.length === 0) {
|
|
3553
|
-
return undefined;
|
|
3554
|
-
}
|
|
3555
|
-
const sizeExpr = dims[0].expression();
|
|
3556
|
-
if (!sizeExpr) {
|
|
3557
|
-
return undefined;
|
|
3558
|
-
}
|
|
3559
|
-
const size = Number.parseInt(sizeExpr.getText(), 10);
|
|
3560
|
-
return Number.isNaN(size) ? undefined : size;
|
|
3561
|
-
}
|
|
3562
|
-
|
|
3563
|
-
/**
|
|
3564
|
-
* Collect array dimensions from array type and additional dimensions
|
|
3565
|
-
*/
|
|
3566
|
-
private _collectArrayDimensions(
|
|
3567
|
-
arrayTypeCtx: Parser.ArrayTypeContext,
|
|
3568
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3569
|
-
): number[] {
|
|
3570
|
-
const arrayDimensions: number[] = [];
|
|
3571
|
-
|
|
3572
|
-
// Get all dimensions from array type syntax (supports multi-dimensional)
|
|
3573
|
-
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
3574
|
-
const sizeExpr = dim.expression();
|
|
3575
|
-
if (sizeExpr) {
|
|
3576
|
-
const size = Number.parseInt(sizeExpr.getText(), 10);
|
|
3577
|
-
if (!Number.isNaN(size)) {
|
|
3578
|
-
arrayDimensions.push(size);
|
|
3579
|
-
}
|
|
3580
|
-
}
|
|
3581
|
-
}
|
|
3582
|
-
|
|
3583
|
-
// Add additional dimensions using const evaluation
|
|
3584
|
-
const additionalDims = this._evaluateArrayDimensions(arrayDim);
|
|
3585
|
-
if (additionalDims) {
|
|
3586
|
-
arrayDimensions.push(...additionalDims);
|
|
3587
|
-
}
|
|
3588
|
-
|
|
3589
|
-
return arrayDimensions;
|
|
3590
|
-
}
|
|
3591
|
-
|
|
3592
|
-
/**
|
|
3593
|
-
* Register a standard (non-array-syntax, non-special) type
|
|
3594
|
-
*/
|
|
3595
|
-
private _registerStandardType(
|
|
3596
|
-
registryName: string,
|
|
3597
|
-
baseType: string,
|
|
3598
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3599
|
-
isConst: boolean,
|
|
3600
|
-
overflowBehavior: TOverflowBehavior,
|
|
3601
|
-
isAtomic: boolean,
|
|
3602
|
-
): void {
|
|
3603
|
-
const bitWidth = TYPE_WIDTH[baseType] || 0;
|
|
3604
|
-
// Issue #665: Check array syntax presence first, then try to resolve dimensions
|
|
3605
|
-
// This matches the pattern in trackVariableType() - unresolved dimensions (e.g., enum
|
|
3606
|
-
// members like EIndex.COUNT) should still mark the variable as an array
|
|
3607
|
-
const isArray = arrayDim !== null && arrayDim.length > 0;
|
|
3608
|
-
const arrayDimensions = isArray
|
|
3609
|
-
? this._evaluateArrayDimensions(arrayDim)
|
|
3610
|
-
: undefined;
|
|
3611
|
-
|
|
3612
|
-
CodeGenState.typeRegistry.set(registryName, {
|
|
3613
|
-
baseType,
|
|
3614
|
-
bitWidth,
|
|
3615
|
-
isArray,
|
|
3616
|
-
arrayDimensions: isArray ? arrayDimensions : undefined,
|
|
3617
|
-
isConst,
|
|
3618
|
-
overflowBehavior,
|
|
3619
|
-
isAtomic,
|
|
3620
|
-
});
|
|
3621
|
-
}
|
|
3622
|
-
|
|
3623
|
-
/**
|
|
3624
|
-
* Issue #322: Check if a type name is a user-defined struct
|
|
3625
|
-
* Part of IOrchestrator interface.
|
|
3626
|
-
*/
|
|
3627
|
-
isStructType(typeName: string): boolean {
|
|
3628
|
-
return TypeResolver.isStructType(typeName);
|
|
3629
|
-
}
|
|
3630
|
-
|
|
3631
|
-
/**
|
|
3632
|
-
* Set up parameter tracking for a function
|
|
3633
|
-
*/
|
|
3634
|
-
private _setParameters(params: Parser.ParameterListContext | null): void {
|
|
3635
|
-
CodeGenState.currentParameters.clear();
|
|
3636
|
-
CodeGenState.currentParameters.clear();
|
|
3637
|
-
if (!params) return;
|
|
3638
|
-
|
|
3639
|
-
for (const param of params.parameter()) {
|
|
3640
|
-
this._processParameter(param);
|
|
3641
|
-
}
|
|
3642
|
-
}
|
|
3643
|
-
|
|
3644
|
-
/**
|
|
3645
|
-
* Process a single parameter declaration
|
|
3646
|
-
*/
|
|
3647
|
-
private _processParameter(param: Parser.ParameterContext): void {
|
|
3648
|
-
const name = param.IDENTIFIER().getText();
|
|
3649
|
-
// Check both C-Next style (u8[8] param) and legacy style (u8 param[8])
|
|
3650
|
-
const isArray =
|
|
3651
|
-
param.arrayDimension().length > 0 || param.type().arrayType() !== null;
|
|
3652
|
-
const isConst = param.constModifier() !== null;
|
|
3653
|
-
const typeCtx = param.type();
|
|
3654
|
-
|
|
3655
|
-
// Resolve type information
|
|
3656
|
-
const typeInfo = this._resolveParameterTypeInfo(typeCtx);
|
|
3657
|
-
|
|
3658
|
-
// Register in currentParameters
|
|
3659
|
-
const paramInfo = {
|
|
3660
|
-
name,
|
|
3661
|
-
baseType: typeInfo.typeName,
|
|
3662
|
-
isArray,
|
|
3663
|
-
isStruct: typeInfo.isStruct,
|
|
3664
|
-
isConst,
|
|
3665
|
-
isCallback: typeInfo.isCallback,
|
|
3666
|
-
isString: typeInfo.isString,
|
|
3667
|
-
};
|
|
3668
|
-
CodeGenState.currentParameters.set(name, paramInfo);
|
|
3669
|
-
|
|
3670
|
-
// Register in typeRegistry
|
|
3671
|
-
this._registerParameterType(name, typeInfo, param, isArray, isConst);
|
|
3672
|
-
}
|
|
3673
|
-
|
|
3674
|
-
/**
|
|
3675
|
-
* Resolve type name and flags from a type context
|
|
3676
|
-
*/
|
|
3677
|
-
private _resolveParameterTypeInfo(typeCtx: Parser.TypeContext): {
|
|
3678
|
-
typeName: string;
|
|
3679
|
-
isStruct: boolean;
|
|
3680
|
-
isCallback: boolean;
|
|
3681
|
-
isString: boolean;
|
|
3682
|
-
} {
|
|
3683
|
-
if (typeCtx.primitiveType()) {
|
|
3684
|
-
return {
|
|
3685
|
-
typeName: typeCtx.primitiveType()!.getText(),
|
|
3686
|
-
isStruct: false,
|
|
3687
|
-
isCallback: false,
|
|
3688
|
-
isString: false,
|
|
3689
|
-
};
|
|
3690
|
-
}
|
|
3691
|
-
|
|
3692
|
-
if (typeCtx.userType()) {
|
|
3693
|
-
const typeName = typeCtx.userType()!.getText();
|
|
3694
|
-
return {
|
|
3695
|
-
typeName,
|
|
3696
|
-
isStruct: this.isStructType(typeName),
|
|
3697
|
-
isCallback: CodeGenState.callbackTypes.has(typeName),
|
|
3698
|
-
isString: false,
|
|
3699
|
-
};
|
|
3700
|
-
}
|
|
3701
|
-
|
|
3702
|
-
if (typeCtx.qualifiedType()) {
|
|
3703
|
-
const identifierNames = typeCtx
|
|
3704
|
-
.qualifiedType()!
|
|
3705
|
-
.IDENTIFIER()
|
|
3706
|
-
.map((id) => id.getText());
|
|
3707
|
-
const typeName = this.resolveQualifiedType(identifierNames);
|
|
3708
|
-
return {
|
|
3709
|
-
typeName,
|
|
3710
|
-
isStruct: this.isStructType(typeName),
|
|
3711
|
-
isCallback: false,
|
|
3712
|
-
isString: false,
|
|
3713
|
-
};
|
|
3714
|
-
}
|
|
3715
|
-
|
|
3716
|
-
if (typeCtx.scopedType()) {
|
|
3717
|
-
const localTypeName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
3718
|
-
const typeName = CodeGenState.currentScope
|
|
3719
|
-
? `${CodeGenState.currentScope}_${localTypeName}`
|
|
3720
|
-
: localTypeName;
|
|
3721
|
-
return {
|
|
3722
|
-
typeName,
|
|
3723
|
-
isStruct: this.isStructType(typeName),
|
|
3724
|
-
isCallback: false,
|
|
3725
|
-
isString: false,
|
|
3726
|
-
};
|
|
3727
|
-
}
|
|
3728
|
-
|
|
3729
|
-
if (typeCtx.globalType()) {
|
|
3730
|
-
const typeName = typeCtx.globalType()!.IDENTIFIER().getText();
|
|
3731
|
-
return {
|
|
3732
|
-
typeName,
|
|
3733
|
-
isStruct: this.isStructType(typeName),
|
|
3734
|
-
isCallback: false,
|
|
3735
|
-
isString: false,
|
|
3736
|
-
};
|
|
3737
|
-
}
|
|
3738
|
-
|
|
3739
|
-
if (typeCtx.stringType()) {
|
|
3740
|
-
return {
|
|
3741
|
-
typeName: "string",
|
|
3742
|
-
isStruct: false,
|
|
3743
|
-
isCallback: false,
|
|
3744
|
-
isString: true,
|
|
3745
|
-
};
|
|
3746
|
-
}
|
|
3747
|
-
|
|
3748
|
-
// Handle C-Next style array type (u8[8] param) - extract base type
|
|
3749
|
-
if (typeCtx.arrayType()) {
|
|
3750
|
-
const arrayTypeCtx = typeCtx.arrayType()!;
|
|
3751
|
-
if (arrayTypeCtx.primitiveType()) {
|
|
3752
|
-
return {
|
|
3753
|
-
typeName: arrayTypeCtx.primitiveType()!.getText(),
|
|
3754
|
-
isStruct: false,
|
|
3755
|
-
isCallback: false,
|
|
3756
|
-
isString: false,
|
|
3757
|
-
};
|
|
3758
|
-
}
|
|
3759
|
-
if (arrayTypeCtx.userType()) {
|
|
3760
|
-
const typeName = arrayTypeCtx.userType()!.getText();
|
|
3761
|
-
return {
|
|
3762
|
-
typeName,
|
|
3763
|
-
isStruct: this.isStructType(typeName),
|
|
3764
|
-
isCallback: CodeGenState.callbackTypes.has(typeName),
|
|
3765
|
-
isString: false,
|
|
3766
|
-
};
|
|
3767
|
-
}
|
|
3768
|
-
// Handle string array type (string<32>[5] param)
|
|
3769
|
-
if (arrayTypeCtx.stringType()) {
|
|
3770
|
-
const stringCtx = arrayTypeCtx.stringType()!;
|
|
3771
|
-
return {
|
|
3772
|
-
typeName: stringCtx.getText(), // "string<32>"
|
|
3773
|
-
isStruct: false,
|
|
3774
|
-
isCallback: false,
|
|
3775
|
-
isString: true,
|
|
3776
|
-
};
|
|
3777
|
-
}
|
|
3778
|
-
}
|
|
3779
|
-
|
|
3780
|
-
// Fallback
|
|
3781
|
-
return {
|
|
3782
|
-
typeName: typeCtx.getText(),
|
|
3783
|
-
isStruct: false,
|
|
3784
|
-
isCallback: false,
|
|
3785
|
-
isString: false,
|
|
3786
|
-
};
|
|
3787
|
-
}
|
|
3788
|
-
|
|
3789
|
-
/**
|
|
3790
|
-
* Extract array dimensions from parameter (C-style or C-Next style).
|
|
3791
|
-
*/
|
|
3792
|
-
private _extractParamArrayDimensions(
|
|
3793
|
-
param: Parser.ParameterContext,
|
|
3794
|
-
typeCtx: Parser.TypeContext,
|
|
3795
|
-
isArray: boolean,
|
|
3796
|
-
): number[] {
|
|
3797
|
-
if (!isArray) return [];
|
|
3798
|
-
|
|
3799
|
-
// Try C-style first (param.arrayDimension())
|
|
3800
|
-
if (param.arrayDimension().length > 0) {
|
|
3801
|
-
return ArrayDimensionParser.parseForParameters(param.arrayDimension());
|
|
3802
|
-
}
|
|
3803
|
-
|
|
3804
|
-
// C-Next style: get dimensions from arrayType
|
|
3805
|
-
const arrayTypeCtx = typeCtx.arrayType();
|
|
3806
|
-
if (!arrayTypeCtx) return [];
|
|
3807
|
-
|
|
3808
|
-
const dimensions: number[] = [];
|
|
3809
|
-
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
3810
|
-
const expr = dim.expression();
|
|
3811
|
-
if (!expr) continue;
|
|
3812
|
-
const size = Number.parseInt(expr.getText(), 10);
|
|
3813
|
-
if (!Number.isNaN(size)) {
|
|
3814
|
-
dimensions.push(size);
|
|
3815
|
-
}
|
|
3816
|
-
}
|
|
3817
|
-
return dimensions;
|
|
3818
|
-
}
|
|
3819
|
-
|
|
3820
|
-
/**
|
|
3821
|
-
* Register a parameter in the type registry
|
|
3822
|
-
*/
|
|
3823
|
-
private _registerParameterType(
|
|
3824
|
-
name: string,
|
|
3825
|
-
typeInfo: { typeName: string; isString: boolean },
|
|
3826
|
-
param: Parser.ParameterContext,
|
|
3827
|
-
isArray: boolean,
|
|
3828
|
-
isConst: boolean,
|
|
3829
|
-
): void {
|
|
3830
|
-
const { typeName, isString } = typeInfo;
|
|
3831
|
-
const typeCtx = param.type();
|
|
3832
|
-
|
|
3833
|
-
const isEnum = CodeGenState.symbols!.knownEnums.has(typeName);
|
|
3834
|
-
const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
|
|
3835
|
-
|
|
3836
|
-
// Extract array dimensions
|
|
3837
|
-
const arrayDimensions = this._extractParamArrayDimensions(
|
|
3838
|
-
param,
|
|
3839
|
-
typeCtx,
|
|
3840
|
-
isArray,
|
|
3841
|
-
);
|
|
3842
|
-
|
|
3843
|
-
// Add string capacity dimension if applicable
|
|
3844
|
-
const stringCapacity = this._getStringCapacity(typeCtx, isString);
|
|
3845
|
-
if (isArray && stringCapacity !== undefined) {
|
|
3846
|
-
arrayDimensions.push(stringCapacity + 1);
|
|
3847
|
-
}
|
|
3848
|
-
|
|
3849
|
-
const registeredType = {
|
|
3850
|
-
baseType: typeName,
|
|
3851
|
-
bitWidth: isBitmap
|
|
3852
|
-
? CodeGenState.symbols!.bitmapBitWidth.get(typeName) || 0
|
|
3853
|
-
: TYPE_WIDTH[typeName] || 0,
|
|
3854
|
-
isArray,
|
|
3855
|
-
arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
|
|
3856
|
-
isConst,
|
|
3857
|
-
isEnum,
|
|
3858
|
-
enumTypeName: isEnum ? typeName : undefined,
|
|
3859
|
-
isBitmap,
|
|
3860
|
-
bitmapTypeName: isBitmap ? typeName : undefined,
|
|
3861
|
-
isString,
|
|
3862
|
-
stringCapacity,
|
|
3863
|
-
isParameter: true,
|
|
3864
|
-
};
|
|
3865
|
-
CodeGenState.typeRegistry.set(name, registeredType);
|
|
3866
|
-
}
|
|
3867
|
-
|
|
3868
|
-
/**
|
|
3869
|
-
* Extract string capacity from a string type context
|
|
3870
|
-
*/
|
|
3871
|
-
private _getStringCapacity(
|
|
3872
|
-
typeCtx: Parser.TypeContext,
|
|
3873
|
-
isString: boolean,
|
|
3874
|
-
): number | undefined {
|
|
3875
|
-
if (!isString) return undefined;
|
|
3876
|
-
|
|
3877
|
-
// Check direct stringType (e.g., string<32> param)
|
|
3878
|
-
if (typeCtx.stringType()) {
|
|
3879
|
-
const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
|
|
3880
|
-
if (intLiteral) {
|
|
3881
|
-
return Number.parseInt(intLiteral.getText(), 10);
|
|
3882
|
-
}
|
|
3883
|
-
}
|
|
3884
|
-
|
|
3885
|
-
// Check arrayType with stringType (e.g., string<32>[5] param)
|
|
3886
|
-
if (typeCtx.arrayType()?.stringType()) {
|
|
3887
|
-
const intLiteral = typeCtx.arrayType()!.stringType()!.INTEGER_LITERAL();
|
|
3888
|
-
if (intLiteral) {
|
|
3889
|
-
return Number.parseInt(intLiteral.getText(), 10);
|
|
3890
|
-
}
|
|
3891
|
-
}
|
|
3892
|
-
|
|
3893
|
-
return undefined;
|
|
3894
|
-
}
|
|
3895
|
-
|
|
3896
|
-
/**
|
|
3897
|
-
* Clear parameter tracking when leaving a function
|
|
3898
|
-
*/
|
|
3899
|
-
private _clearParameters(): void {
|
|
3900
|
-
// ADR-025: Remove parameter types from typeRegistry
|
|
3901
|
-
for (const name of CodeGenState.currentParameters.keys()) {
|
|
3902
|
-
CodeGenState.typeRegistry.delete(name);
|
|
3903
|
-
CodeGenState.typeRegistry.delete(name);
|
|
3904
|
-
}
|
|
3905
|
-
CodeGenState.currentParameters.clear();
|
|
3906
|
-
CodeGenState.localArrays.clear();
|
|
3907
|
-
CodeGenState.currentParameters.clear();
|
|
3908
|
-
CodeGenState.localArrays.clear();
|
|
3909
|
-
}
|
|
3910
|
-
|
|
3911
|
-
/**
|
|
3912
|
-
* ADR-013: Extract function signature from parameter list
|
|
3913
|
-
*/
|
|
3914
|
-
private extractFunctionSignature(
|
|
3915
|
-
name: string,
|
|
3916
|
-
params: Parser.ParameterListContext | null,
|
|
3917
|
-
): FunctionSignature {
|
|
3918
|
-
const parameters: Array<{
|
|
3919
|
-
name: string;
|
|
3920
|
-
baseType: string;
|
|
3921
|
-
isConst: boolean;
|
|
3922
|
-
isArray: boolean;
|
|
3923
|
-
}> = [];
|
|
3924
|
-
|
|
3925
|
-
if (params) {
|
|
3926
|
-
for (const param of params.parameter()) {
|
|
3927
|
-
const paramName = param.IDENTIFIER().getText();
|
|
3928
|
-
const isConst = param.constModifier() !== null;
|
|
3929
|
-
// arrayDimension() returns an array (due to grammar's *), so check length
|
|
3930
|
-
// Also check C-Next style array type (e.g., u8[8] param)
|
|
3931
|
-
const isArray =
|
|
3932
|
-
param.arrayDimension().length > 0 ||
|
|
3933
|
-
param.type().arrayType() !== null;
|
|
3934
|
-
const baseType = this.getTypeName(param.type());
|
|
3935
|
-
parameters.push({ name: paramName, baseType, isConst, isArray });
|
|
3936
|
-
}
|
|
3937
|
-
}
|
|
3938
|
-
|
|
3939
|
-
return { name, parameters };
|
|
3940
|
-
}
|
|
3941
|
-
|
|
3942
|
-
/**
|
|
3943
|
-
* ADR-029: Register a function as a callback type
|
|
3944
|
-
* The function name becomes both a callable function and a type for callback fields
|
|
3945
|
-
*/
|
|
3946
|
-
private registerCallbackType(
|
|
3947
|
-
name: string,
|
|
3948
|
-
funcDecl: Parser.FunctionDeclarationContext,
|
|
3949
|
-
): void {
|
|
3950
|
-
const returnType = this.generateType(funcDecl.type());
|
|
3951
|
-
const parameters: Array<{
|
|
3952
|
-
name: string;
|
|
3953
|
-
type: string;
|
|
3954
|
-
isConst: boolean;
|
|
3955
|
-
isPointer: boolean;
|
|
3956
|
-
isArray: boolean;
|
|
3957
|
-
arrayDims: string;
|
|
3958
|
-
}> = [];
|
|
3959
|
-
|
|
3960
|
-
if (funcDecl.parameterList()) {
|
|
3961
|
-
for (const param of funcDecl.parameterList()!.parameter()) {
|
|
3962
|
-
const paramName = param.IDENTIFIER().getText();
|
|
3963
|
-
const typeName = this.getTypeName(param.type());
|
|
3964
|
-
const isConst = param.constModifier() !== null;
|
|
3965
|
-
const dims = param.arrayDimension();
|
|
3966
|
-
const arrayTypeCtx = param.type().arrayType();
|
|
3967
|
-
const isArray = dims.length > 0 || arrayTypeCtx !== null;
|
|
3968
|
-
|
|
3969
|
-
// ADR-029: Check if parameter type is itself a callback type
|
|
3970
|
-
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
3971
|
-
|
|
3972
|
-
let paramType: string;
|
|
3973
|
-
let isPointer: boolean;
|
|
3974
|
-
|
|
3975
|
-
if (isCallbackParam) {
|
|
3976
|
-
// Use the callback typedef name
|
|
3977
|
-
const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
3978
|
-
paramType = cbInfo.typedefName;
|
|
3979
|
-
isPointer = false; // Function pointers are already pointers
|
|
3980
|
-
} else {
|
|
3981
|
-
paramType = this.generateType(param.type());
|
|
3982
|
-
// ADR-006: Non-array parameters become pointers
|
|
3983
|
-
isPointer = !isArray;
|
|
3984
|
-
}
|
|
3985
|
-
|
|
3986
|
-
let arrayDims: string;
|
|
3987
|
-
if (dims.length > 0) {
|
|
3988
|
-
arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
3989
|
-
} else if (arrayTypeCtx) {
|
|
3990
|
-
// Generate all dimensions from arrayType (supports multi-dimensional)
|
|
3991
|
-
arrayDims = arrayTypeCtx
|
|
3992
|
-
.arrayTypeDimension()
|
|
3993
|
-
.map((d) => {
|
|
3994
|
-
const expr = d.expression();
|
|
3995
|
-
return expr ? `[${this.generateExpression(expr)}]` : "[]";
|
|
3996
|
-
})
|
|
3997
|
-
.join("");
|
|
3998
|
-
} else {
|
|
3999
|
-
arrayDims = "";
|
|
4000
|
-
}
|
|
4001
|
-
parameters.push({
|
|
4002
|
-
name: paramName,
|
|
4003
|
-
type: paramType,
|
|
4004
|
-
isConst,
|
|
4005
|
-
isPointer,
|
|
4006
|
-
isArray,
|
|
4007
|
-
arrayDims,
|
|
4008
|
-
});
|
|
4009
|
-
}
|
|
4010
|
-
}
|
|
4011
|
-
|
|
4012
|
-
CodeGenState.callbackTypes.set(name, {
|
|
4013
|
-
functionName: name,
|
|
4014
|
-
returnType,
|
|
4015
|
-
parameters,
|
|
4016
|
-
typedefName: `${name}_fp`,
|
|
4017
|
-
});
|
|
4018
|
-
}
|
|
4019
|
-
|
|
4020
|
-
/**
|
|
4021
|
-
* ADR-029: Check if a function is used as a callback type (field type in a struct)
|
|
4022
|
-
*/
|
|
4023
|
-
// Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
|
|
4024
|
-
// and validateBareIdentifierInScope moved to TypeValidator
|
|
4025
|
-
|
|
4026
|
-
// EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
|
|
4027
|
-
// _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
|
|
4028
|
-
// _getExpressionEnumType, _getFunctionCallEnumType
|
|
4029
|
-
/**
|
|
4030
|
-
* ADR-017: Check if an expression represents an integer literal or numeric type.
|
|
4031
|
-
* Used to detect comparisons between enums and integers.
|
|
4032
|
-
*/
|
|
4033
|
-
private _isIntegerExpression(
|
|
4034
|
-
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
4035
|
-
): boolean {
|
|
4036
|
-
return EnumAssignmentValidator.isIntegerExpression(ctx);
|
|
4037
|
-
}
|
|
4038
|
-
|
|
4039
|
-
/**
|
|
4040
|
-
* ADR-045: Check if an expression is a string concatenation (contains + with string operands).
|
|
4041
|
-
* Returns the operand expressions if it is, null otherwise.
|
|
4042
|
-
*/
|
|
4043
|
-
private _getStringConcatOperands(ctx: Parser.ExpressionContext): {
|
|
4044
|
-
left: string;
|
|
4045
|
-
right: string;
|
|
4046
|
-
leftCapacity: number;
|
|
4047
|
-
rightCapacity: number;
|
|
4048
|
-
} | null {
|
|
4049
|
-
// Navigate to the additive expression level using ExpressionUnwrapper
|
|
4050
|
-
// Issue #707: Deduplicated expression tree navigation
|
|
4051
|
-
const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
|
|
4052
|
-
if (!add) return null;
|
|
4053
|
-
const multExprs = add.multiplicativeExpression();
|
|
4054
|
-
|
|
4055
|
-
// Need exactly 2 operands for simple concatenation
|
|
4056
|
-
if (multExprs.length !== 2) return null;
|
|
4057
|
-
|
|
4058
|
-
// Check if this is addition (not subtraction)
|
|
4059
|
-
const text = add.getText();
|
|
4060
|
-
if (text.includes("-")) return null;
|
|
4061
|
-
|
|
4062
|
-
// Get the operand texts
|
|
4063
|
-
const leftText = multExprs[0].getText();
|
|
4064
|
-
const rightText = multExprs[1].getText();
|
|
4065
|
-
|
|
4066
|
-
// Check if at least one operand is a string
|
|
4067
|
-
const leftCapacity = this.getStringExprCapacity(leftText);
|
|
4068
|
-
const rightCapacity = this.getStringExprCapacity(rightText);
|
|
4069
|
-
|
|
4070
|
-
if (leftCapacity === null && rightCapacity === null) {
|
|
4071
|
-
return null; // Neither is a string
|
|
4072
|
-
}
|
|
4073
|
-
|
|
4074
|
-
// If one is null, it's not a valid string concatenation
|
|
4075
|
-
if (leftCapacity === null || rightCapacity === null) {
|
|
4076
|
-
return null;
|
|
4077
|
-
}
|
|
4078
|
-
|
|
4079
|
-
return {
|
|
4080
|
-
left: leftText,
|
|
4081
|
-
right: rightText,
|
|
4082
|
-
leftCapacity,
|
|
4083
|
-
rightCapacity,
|
|
4084
|
-
};
|
|
4085
|
-
}
|
|
4086
|
-
|
|
4087
|
-
/**
|
|
4088
|
-
* ADR-045: Get the capacity of a string expression.
|
|
4089
|
-
* For string literals, capacity is the literal length.
|
|
4090
|
-
* For string variables, capacity is from the type registry.
|
|
4091
|
-
*/
|
|
4092
|
-
/**
|
|
4093
|
-
* ADR-045: Check if an expression is a substring extraction (string[start, length]).
|
|
4094
|
-
* Returns the source string, start, length, and source capacity if it is.
|
|
4095
|
-
* Issue #707: Uses ExpressionUnwrapper for tree navigation.
|
|
4096
|
-
*/
|
|
4097
|
-
private _getSubstringOperands(ctx: Parser.ExpressionContext): {
|
|
4098
|
-
source: string;
|
|
4099
|
-
start: string;
|
|
4100
|
-
length: string;
|
|
4101
|
-
sourceCapacity: number;
|
|
4102
|
-
} | null {
|
|
4103
|
-
// Navigate to the postfix expression level using shared utility
|
|
4104
|
-
const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
|
|
4105
|
-
if (!postfix) return null;
|
|
4106
|
-
|
|
4107
|
-
const primary = postfix.primaryExpression();
|
|
4108
|
-
const ops = postfix.postfixOp();
|
|
4109
|
-
|
|
4110
|
-
// Need exactly one postfix operation (the [start, length])
|
|
4111
|
-
if (ops.length !== 1) return null;
|
|
4112
|
-
|
|
4113
|
-
const op = ops[0];
|
|
4114
|
-
const exprs = op.expression();
|
|
4115
|
-
|
|
4116
|
-
// Get the source variable name first
|
|
4117
|
-
const sourceId = primary.IDENTIFIER();
|
|
4118
|
-
if (!sourceId) return null;
|
|
4119
|
-
|
|
4120
|
-
const sourceName = sourceId.getText();
|
|
4121
|
-
|
|
4122
|
-
// Check if source is a string type
|
|
4123
|
-
const typeInfo = CodeGenState.typeRegistry.get(sourceName);
|
|
4124
|
-
if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
|
|
4125
|
-
return null;
|
|
4126
|
-
}
|
|
4127
|
-
|
|
4128
|
-
// Issue #140: Handle both [start, length] pattern (2 expressions)
|
|
4129
|
-
// and single-character access [index] pattern (1 expression, treated as [index, 1])
|
|
4130
|
-
if (exprs.length === 2) {
|
|
4131
|
-
return {
|
|
4132
|
-
source: sourceName,
|
|
4133
|
-
start: this.generateExpression(exprs[0]),
|
|
4134
|
-
length: this.generateExpression(exprs[1]),
|
|
4135
|
-
sourceCapacity: typeInfo.stringCapacity,
|
|
4136
|
-
};
|
|
4137
|
-
} else if (exprs.length === 1) {
|
|
4138
|
-
// Single-character access: source[i] is sugar for source[i, 1]
|
|
4139
|
-
return {
|
|
4140
|
-
source: sourceName,
|
|
4141
|
-
start: this.generateExpression(exprs[0]),
|
|
4142
|
-
length: "1",
|
|
4143
|
-
sourceCapacity: typeInfo.stringCapacity,
|
|
4144
|
-
};
|
|
4145
|
-
}
|
|
4146
|
-
|
|
4147
|
-
return null;
|
|
4148
|
-
}
|
|
4149
|
-
|
|
4150
2769
|
// ========================================================================
|
|
4151
2770
|
// ADR-024: Type Classification and Validation Helpers
|
|
4152
2771
|
// ========================================================================
|
|
@@ -4307,7 +2926,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4307
2926
|
baseId: string,
|
|
4308
2927
|
targetParamBaseType: string,
|
|
4309
2928
|
): boolean {
|
|
4310
|
-
const typeInfo = CodeGenState.
|
|
2929
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
4311
2930
|
return CppMemberHelper.needsComplexMemberConversion(
|
|
4312
2931
|
this._toPostfixOps(ops),
|
|
4313
2932
|
typeInfo,
|
|
@@ -4334,7 +2953,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4334
2953
|
const baseId = primary.IDENTIFIER()?.getText();
|
|
4335
2954
|
if (!baseId) return false;
|
|
4336
2955
|
|
|
4337
|
-
const typeInfo = CodeGenState.
|
|
2956
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
4338
2957
|
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
4339
2958
|
|
|
4340
2959
|
return CppMemberHelper.isStringSubscriptPattern(
|
|
@@ -4370,225 +2989,46 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4370
2989
|
if (!postfix) return "not-array";
|
|
4371
2990
|
|
|
4372
2991
|
const ops = postfix.postfixOp();
|
|
4373
|
-
if (ops.length === 0) return "not-array";
|
|
4374
|
-
|
|
4375
|
-
// Last operator must be member access (.identifier)
|
|
4376
|
-
const lastOp = ops.at(-1)!;
|
|
4377
|
-
const memberName = lastOp.IDENTIFIER()?.getText();
|
|
4378
|
-
if (!memberName) return "not-array";
|
|
4379
|
-
|
|
4380
|
-
// Get the base identifier to find the struct type
|
|
4381
|
-
const primary = postfix.primaryExpression();
|
|
4382
|
-
if (!primary) return "not-array";
|
|
4383
|
-
const baseId = primary.IDENTIFIER()?.getText();
|
|
4384
|
-
if (!baseId) return "not-array";
|
|
4385
|
-
|
|
4386
|
-
// Look up the struct type from either:
|
|
4387
|
-
// 1. Local variable: typeRegistry.get(baseId).baseType
|
|
4388
|
-
// 2. Parameter: currentParameters.get(baseId).baseType
|
|
4389
|
-
let structType: string | undefined;
|
|
4390
|
-
|
|
4391
|
-
const typeInfo = CodeGenState.typeRegistry.get(baseId);
|
|
4392
|
-
if (typeInfo) {
|
|
4393
|
-
structType = typeInfo.baseType;
|
|
4394
|
-
} else {
|
|
4395
|
-
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
4396
|
-
if (paramInfo) {
|
|
4397
|
-
structType = paramInfo.baseType;
|
|
4398
|
-
}
|
|
4399
|
-
}
|
|
4400
|
-
|
|
4401
|
-
if (!structType) return "not-array";
|
|
4402
|
-
|
|
4403
|
-
// Check if this struct member is an array
|
|
4404
|
-
const memberInfo = this.getMemberTypeInfo(structType, memberName);
|
|
4405
|
-
|
|
4406
|
-
// Issue #355: If memberInfo is undefined, we don't have struct field info
|
|
4407
|
-
// This could mean the header wasn't parsed - return "unknown" for defensive generation
|
|
4408
|
-
if (!memberInfo) {
|
|
4409
|
-
return "unknown";
|
|
4410
|
-
}
|
|
4411
|
-
|
|
4412
|
-
return memberInfo.isArray ? "array" : "not-array";
|
|
4413
|
-
}
|
|
4414
|
-
|
|
4415
|
-
/**
|
|
4416
|
-
* Generate a function argument with proper ADR-006 semantics.
|
|
4417
|
-
* - Local variables get & (address-of)
|
|
4418
|
-
* - Member access (cursor.x) gets & (address-of)
|
|
4419
|
-
* - Array access (arr[i]) gets & (address-of)
|
|
4420
|
-
* - Parameters are passed as-is (already pointers)
|
|
4421
|
-
* - Arrays are passed as-is (naturally decay to pointers)
|
|
4422
|
-
* - Literals use compound literals for pointer params: &(type){value}
|
|
4423
|
-
* - Complex expressions are passed as-is
|
|
4424
|
-
*/
|
|
4425
|
-
private _generateFunctionArg(
|
|
4426
|
-
ctx: Parser.ExpressionContext,
|
|
4427
|
-
targetParamBaseType?: string,
|
|
4428
|
-
): string {
|
|
4429
|
-
const id = CodegenParserUtils.getSimpleIdentifier(ctx);
|
|
4430
|
-
if (id) {
|
|
4431
|
-
return this._handleIdentifierArg(id);
|
|
4432
|
-
}
|
|
4433
|
-
|
|
4434
|
-
const lvalueType = this.getLvalueType(ctx);
|
|
4435
|
-
if (lvalueType) {
|
|
4436
|
-
return this._handleLvalueArg(ctx, lvalueType, targetParamBaseType);
|
|
4437
|
-
}
|
|
4438
|
-
|
|
4439
|
-
return this._handleRvalueArg(ctx, targetParamBaseType);
|
|
4440
|
-
}
|
|
4441
|
-
|
|
4442
|
-
/**
|
|
4443
|
-
* Handle simple identifier argument (parameter, local array, scope member, or variable)
|
|
4444
|
-
*/
|
|
4445
|
-
private _handleIdentifierArg(id: string): string {
|
|
4446
|
-
// Parameters are already pointers
|
|
4447
|
-
if (CodeGenState.currentParameters.get(id)) {
|
|
4448
|
-
return id;
|
|
4449
|
-
}
|
|
4450
|
-
|
|
4451
|
-
// Local arrays decay to pointers
|
|
4452
|
-
if (CodeGenState.localArrays.has(id)) {
|
|
4453
|
-
return id;
|
|
4454
|
-
}
|
|
4455
|
-
|
|
4456
|
-
// Global arrays also decay to pointers (check typeRegistry)
|
|
4457
|
-
// But NOT strings - strings need & (they're char arrays but passed by reference)
|
|
4458
|
-
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
4459
|
-
if (typeInfo?.isArray && !typeInfo.isString) {
|
|
4460
|
-
return id;
|
|
4461
|
-
}
|
|
4462
|
-
|
|
4463
|
-
// Scope member - may need prefixing
|
|
4464
|
-
if (CodeGenState.currentScope) {
|
|
4465
|
-
const members = CodeGenState.getScopeMembers(CodeGenState.currentScope);
|
|
4466
|
-
if (members?.has(id)) {
|
|
4467
|
-
const scopedName = `${CodeGenState.currentScope}_${id}`;
|
|
4468
|
-
return CppModeHelper.maybeAddressOf(scopedName);
|
|
4469
|
-
}
|
|
4470
|
-
}
|
|
4471
|
-
|
|
4472
|
-
// Local variable - add & (except in C++ mode)
|
|
4473
|
-
return CppModeHelper.maybeAddressOf(id);
|
|
4474
|
-
}
|
|
4475
|
-
|
|
4476
|
-
/**
|
|
4477
|
-
* Handle lvalue argument (member access or array access)
|
|
4478
|
-
*/
|
|
4479
|
-
private _handleLvalueArg(
|
|
4480
|
-
ctx: Parser.ExpressionContext,
|
|
4481
|
-
lvalueType: string,
|
|
4482
|
-
targetParamBaseType?: string,
|
|
4483
|
-
): string {
|
|
4484
|
-
// Member access to array field - arrays decay to pointers
|
|
4485
|
-
if (lvalueType === "member") {
|
|
4486
|
-
const memberResult = this._handleMemberAccessArg(
|
|
4487
|
-
ctx,
|
|
4488
|
-
targetParamBaseType,
|
|
4489
|
-
);
|
|
4490
|
-
if (memberResult) return memberResult;
|
|
4491
|
-
}
|
|
4492
|
-
|
|
4493
|
-
// Generate expression with address-of
|
|
4494
|
-
const generatedExpr = this.generateExpression(ctx);
|
|
4495
|
-
const expr = CppModeHelper.maybeAddressOf(generatedExpr);
|
|
4496
|
-
|
|
4497
|
-
// String subscript access may need cast
|
|
4498
|
-
if (lvalueType === "array") {
|
|
4499
|
-
return this._maybeCastStringSubscript(ctx, expr, targetParamBaseType);
|
|
4500
|
-
}
|
|
4501
|
-
|
|
4502
|
-
return expr;
|
|
4503
|
-
}
|
|
4504
|
-
|
|
4505
|
-
/**
|
|
4506
|
-
* Handle member access argument - may need special handling for arrays or C++ conversions
|
|
4507
|
-
*/
|
|
4508
|
-
private _handleMemberAccessArg(
|
|
4509
|
-
ctx: Parser.ExpressionContext,
|
|
4510
|
-
targetParamBaseType?: string,
|
|
4511
|
-
): string | null {
|
|
4512
|
-
const arrayStatus = this.getMemberAccessArrayStatus(ctx);
|
|
4513
|
-
|
|
4514
|
-
// Array member - no address-of needed
|
|
4515
|
-
if (arrayStatus === "array") {
|
|
4516
|
-
return this.generateExpression(ctx);
|
|
4517
|
-
}
|
|
4518
|
-
|
|
4519
|
-
// C++ mode may need temp variable for type conversion
|
|
4520
|
-
if (
|
|
4521
|
-
arrayStatus === "not-array" &&
|
|
4522
|
-
this.needsCppMemberConversion(ctx, targetParamBaseType)
|
|
4523
|
-
) {
|
|
4524
|
-
return this._createCppMemberConversionTemp(ctx, targetParamBaseType!);
|
|
4525
|
-
}
|
|
4526
|
-
|
|
4527
|
-
return null; // Fall through to default lvalue handling
|
|
4528
|
-
}
|
|
4529
|
-
|
|
4530
|
-
/**
|
|
4531
|
-
* Create temp variable for C++ member conversion
|
|
4532
|
-
*/
|
|
4533
|
-
private _createCppMemberConversionTemp(
|
|
4534
|
-
ctx: Parser.ExpressionContext,
|
|
4535
|
-
targetParamBaseType: string,
|
|
4536
|
-
): string {
|
|
4537
|
-
const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
|
|
4538
|
-
const value = this.generateExpression(ctx);
|
|
4539
|
-
const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
|
|
4540
|
-
const castExpr = CppModeHelper.cast(cType, value);
|
|
4541
|
-
CodeGenState.pendingTempDeclarations.push(
|
|
4542
|
-
`${cType} ${tempName} = ${castExpr};`,
|
|
4543
|
-
);
|
|
4544
|
-
return CppModeHelper.maybeAddressOf(tempName);
|
|
4545
|
-
}
|
|
2992
|
+
if (ops.length === 0) return "not-array";
|
|
4546
2993
|
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
ctx: Parser.ExpressionContext,
|
|
4552
|
-
expr: string,
|
|
4553
|
-
targetParamBaseType?: string,
|
|
4554
|
-
): string {
|
|
4555
|
-
if (!targetParamBaseType || !this.isStringSubscriptAccess(ctx)) {
|
|
4556
|
-
return expr;
|
|
4557
|
-
}
|
|
2994
|
+
// Last operator must be member access (.identifier)
|
|
2995
|
+
const lastOp = ops.at(-1)!;
|
|
2996
|
+
const memberName = lastOp.IDENTIFIER()?.getText();
|
|
2997
|
+
if (!memberName) return "not-array";
|
|
4558
2998
|
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
2999
|
+
// Get the base identifier to find the struct type
|
|
3000
|
+
const primary = postfix.primaryExpression();
|
|
3001
|
+
if (!primary) return "not-array";
|
|
3002
|
+
const baseId = primary.IDENTIFIER()?.getText();
|
|
3003
|
+
if (!baseId) return "not-array";
|
|
4563
3004
|
|
|
4564
|
-
|
|
4565
|
-
|
|
3005
|
+
// Look up the struct type from either:
|
|
3006
|
+
// 1. Local variable: typeRegistry.get(baseId).baseType
|
|
3007
|
+
// 2. Parameter: currentParameters.get(baseId).baseType
|
|
3008
|
+
let structType: string | undefined;
|
|
4566
3009
|
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
return this.generateExpression(ctx);
|
|
3010
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
3011
|
+
if (typeInfo) {
|
|
3012
|
+
structType = typeInfo.baseType;
|
|
3013
|
+
} else {
|
|
3014
|
+
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
3015
|
+
if (paramInfo) {
|
|
3016
|
+
structType = paramInfo.baseType;
|
|
3017
|
+
}
|
|
4576
3018
|
}
|
|
4577
3019
|
|
|
4578
|
-
|
|
4579
|
-
if (!cType || cType === "void") {
|
|
4580
|
-
return this.generateExpression(ctx);
|
|
4581
|
-
}
|
|
3020
|
+
if (!structType) return "not-array";
|
|
4582
3021
|
|
|
4583
|
-
|
|
3022
|
+
// Check if this struct member is an array
|
|
3023
|
+
const memberInfo = this.getMemberTypeInfo(structType, memberName);
|
|
4584
3024
|
|
|
4585
|
-
//
|
|
4586
|
-
|
|
4587
|
-
|
|
3025
|
+
// Issue #355: If memberInfo is undefined, we don't have struct field info
|
|
3026
|
+
// This could mean the header wasn't parsed - return "unknown" for defensive generation
|
|
3027
|
+
if (!memberInfo) {
|
|
3028
|
+
return "unknown";
|
|
4588
3029
|
}
|
|
4589
3030
|
|
|
4590
|
-
|
|
4591
|
-
return `&(${cType}){${value}}`;
|
|
3031
|
+
return memberInfo.isArray ? "array" : "not-array";
|
|
4592
3032
|
}
|
|
4593
3033
|
|
|
4594
3034
|
// ========================================================================
|
|
@@ -4711,7 +3151,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4711
3151
|
): void {
|
|
4712
3152
|
const type = this.generateType(varDecl.type());
|
|
4713
3153
|
const varName = varDecl.IDENTIFIER().getText();
|
|
4714
|
-
const fullName =
|
|
3154
|
+
const fullName = QualifiedNameGenerator.forMember(scopeName, varName);
|
|
4715
3155
|
const prefix = isPrivate ? "static " : "";
|
|
4716
3156
|
|
|
4717
3157
|
const arrayDims = varDecl.arrayDimension();
|
|
@@ -4722,7 +3162,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4722
3162
|
|
|
4723
3163
|
// Handle arrayType dimension (C-Next style: u8[16] data)
|
|
4724
3164
|
if (hasArrayTypeSyntax) {
|
|
4725
|
-
decl +=
|
|
3165
|
+
decl += VariableDeclHelper.getArrayTypeDimension(varDecl.type(), {
|
|
3166
|
+
tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
|
|
3167
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
3168
|
+
});
|
|
4726
3169
|
}
|
|
4727
3170
|
|
|
4728
3171
|
// Handle arrayDimension (C-style or additional dimensions)
|
|
@@ -4764,7 +3207,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4764
3207
|
): void {
|
|
4765
3208
|
const returnType = this.generateType(funcDecl.type());
|
|
4766
3209
|
const funcName = funcDecl.IDENTIFIER().getText();
|
|
4767
|
-
const fullName =
|
|
3210
|
+
const fullName = QualifiedNameGenerator.forFunctionStrings(
|
|
3211
|
+
scopeName,
|
|
3212
|
+
funcName,
|
|
3213
|
+
);
|
|
4768
3214
|
const prefix = isPrivate ? "static " : "";
|
|
4769
3215
|
|
|
4770
3216
|
// Issue #269: Set current function name for pass-by-value lookup
|
|
@@ -5159,32 +3605,34 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5159
3605
|
}
|
|
5160
3606
|
|
|
5161
3607
|
/**
|
|
5162
|
-
* Set up context for function generation
|
|
3608
|
+
* Set up context for function generation.
|
|
3609
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
5163
3610
|
*/
|
|
5164
3611
|
private _setupFunctionContext(
|
|
5165
3612
|
name: string,
|
|
5166
3613
|
ctx: Parser.FunctionDeclarationContext,
|
|
5167
3614
|
): void {
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
CodeGenState.currentFunctionReturnType = ctx.type().getText();
|
|
5175
|
-
|
|
5176
|
-
// Track parameters for ADR-006 pointer semantics
|
|
5177
|
-
this._setParameters(ctx.parameterList() ?? null);
|
|
3615
|
+
FunctionContextManager.setupFunctionContext(
|
|
3616
|
+
name,
|
|
3617
|
+
ctx,
|
|
3618
|
+
this._getFunctionContextCallbacks(),
|
|
3619
|
+
);
|
|
3620
|
+
}
|
|
5178
3621
|
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
3622
|
+
/**
|
|
3623
|
+
* Issue #793: Create callbacks for FunctionContextManager.
|
|
3624
|
+
*/
|
|
3625
|
+
private _getFunctionContextCallbacks(): IFunctionContextCallbacks {
|
|
3626
|
+
return {
|
|
3627
|
+
isStructType: (typeName: string) => this.isStructType(typeName),
|
|
3628
|
+
resolveQualifiedType: (identifiers: string[]) =>
|
|
3629
|
+
this.resolveQualifiedType(identifiers),
|
|
3630
|
+
};
|
|
5184
3631
|
}
|
|
5185
3632
|
|
|
5186
3633
|
/**
|
|
5187
|
-
* Resolve return type and initial params for function
|
|
3634
|
+
* Resolve return type and initial params for function.
|
|
3635
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
5188
3636
|
*/
|
|
5189
3637
|
private _resolveReturnTypeAndParams(
|
|
5190
3638
|
name: string,
|
|
@@ -5192,33 +3640,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5192
3640
|
isMainWithArgs: boolean,
|
|
5193
3641
|
ctx: Parser.FunctionDeclarationContext,
|
|
5194
3642
|
): { actualReturnType: string; initialParams: string } {
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
initialParams: "int argc, char *argv[]",
|
|
5202
|
-
};
|
|
5203
|
-
}
|
|
5204
|
-
|
|
5205
|
-
// For main() without args, always use int return type for C++ compatibility
|
|
5206
|
-
const actualReturnType = name === "main" ? "int" : returnType;
|
|
5207
|
-
return { actualReturnType, initialParams: "" };
|
|
3643
|
+
return FunctionContextManager.resolveReturnTypeAndParams(
|
|
3644
|
+
name,
|
|
3645
|
+
returnType,
|
|
3646
|
+
isMainWithArgs,
|
|
3647
|
+
ctx,
|
|
3648
|
+
);
|
|
5208
3649
|
}
|
|
5209
3650
|
|
|
5210
3651
|
/**
|
|
5211
|
-
* Clean up context after function generation
|
|
3652
|
+
* Clean up context after function generation.
|
|
3653
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
5212
3654
|
*/
|
|
5213
3655
|
private _cleanupFunctionContext(): void {
|
|
5214
|
-
|
|
5215
|
-
CodeGenState.localVariables.clear();
|
|
5216
|
-
CodeGenState.floatBitShadows.clear();
|
|
5217
|
-
CodeGenState.floatShadowCurrent.clear();
|
|
5218
|
-
CodeGenState.mainArgsName = null;
|
|
5219
|
-
CodeGenState.currentFunctionName = null;
|
|
5220
|
-
CodeGenState.currentFunctionReturnType = null;
|
|
5221
|
-
this._clearParameters();
|
|
3656
|
+
FunctionContextManager.cleanupFunctionContext();
|
|
5222
3657
|
}
|
|
5223
3658
|
|
|
5224
3659
|
/**
|
|
@@ -5325,7 +3760,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5325
3760
|
// Small unmodified primitives
|
|
5326
3761
|
if (
|
|
5327
3762
|
CodeGenState.currentFunctionName &&
|
|
5328
|
-
|
|
3763
|
+
PassByValueAnalyzer.isParameterPassByValueByName(
|
|
3764
|
+
CodeGenState.currentFunctionName,
|
|
3765
|
+
name,
|
|
3766
|
+
)
|
|
5329
3767
|
) {
|
|
5330
3768
|
return true;
|
|
5331
3769
|
}
|
|
@@ -5338,74 +3776,27 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5338
3776
|
// ========================================================================
|
|
5339
3777
|
|
|
5340
3778
|
private generateVariableDecl(ctx: Parser.VariableDeclarationContext): string {
|
|
5341
|
-
// Issue #
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
this._trackLocalVariable(ctx, name);
|
|
5363
|
-
|
|
5364
|
-
// ADR-045: Handle bounded string type specially - early return
|
|
5365
|
-
const stringResult = StringDeclHelper.generateStringDecl(
|
|
5366
|
-
typeCtx,
|
|
5367
|
-
name,
|
|
5368
|
-
ctx.expression() ?? null,
|
|
5369
|
-
ctx.arrayDimension(),
|
|
5370
|
-
modifiers,
|
|
5371
|
-
ctx.constModifier() !== null,
|
|
5372
|
-
{
|
|
5373
|
-
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
5374
|
-
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
5375
|
-
getStringConcatOperands: (concatCtx) =>
|
|
5376
|
-
this._getStringConcatOperands(concatCtx),
|
|
5377
|
-
getSubstringOperands: (substrCtx) =>
|
|
5378
|
-
this._getSubstringOperands(substrCtx),
|
|
5379
|
-
getStringExprCapacity: (exprCode) =>
|
|
5380
|
-
this.getStringExprCapacity(exprCode),
|
|
5381
|
-
requireStringInclude: () => this.requireInclude("string"),
|
|
5382
|
-
},
|
|
5383
|
-
);
|
|
5384
|
-
if (stringResult.handled) {
|
|
5385
|
-
return stringResult.code;
|
|
5386
|
-
}
|
|
5387
|
-
|
|
5388
|
-
// Build base declaration
|
|
5389
|
-
const modifierPrefix = VariableModifierBuilder.toPrefix(modifiers);
|
|
5390
|
-
let decl = `${modifierPrefix}${type} ${name}`;
|
|
5391
|
-
|
|
5392
|
-
// Handle array declarations - early return if array init handled
|
|
5393
|
-
const arrayResult = this._handleArrayDeclaration(ctx, typeCtx, name, decl);
|
|
5394
|
-
if (arrayResult.handled) {
|
|
5395
|
-
return arrayResult.code;
|
|
5396
|
-
}
|
|
5397
|
-
decl = arrayResult.decl;
|
|
5398
|
-
|
|
5399
|
-
// Handle initialization
|
|
5400
|
-
decl = this._generateVariableInitializer(
|
|
5401
|
-
ctx,
|
|
5402
|
-
typeCtx,
|
|
5403
|
-
decl,
|
|
5404
|
-
arrayResult.isArray,
|
|
5405
|
-
);
|
|
5406
|
-
|
|
5407
|
-
// Handle pending C++ class field assignments
|
|
5408
|
-
return this._finalizeCppClassAssignments(ctx, typeCtx, name, decl);
|
|
3779
|
+
// Issue #792: Delegate to VariableDeclHelper
|
|
3780
|
+
return VariableDeclHelper.generateVariableDecl(ctx, {
|
|
3781
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
3782
|
+
generateType: (typeCtx) => this.generateType(typeCtx),
|
|
3783
|
+
getTypeName: (typeCtx) => this.getTypeName(typeCtx),
|
|
3784
|
+
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
3785
|
+
tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
|
|
3786
|
+
getZeroInitializer: (typeCtx, isArray) =>
|
|
3787
|
+
this.getZeroInitializer(typeCtx, isArray),
|
|
3788
|
+
getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
|
|
3789
|
+
inferVariableType: (varCtx, name) =>
|
|
3790
|
+
this._inferVariableType(varCtx, name),
|
|
3791
|
+
trackLocalVariable: (varCtx, name) =>
|
|
3792
|
+
this._trackLocalVariable(varCtx, name),
|
|
3793
|
+
getStringConcatOperands: (concatCtx) =>
|
|
3794
|
+
this._getStringConcatOperands(concatCtx),
|
|
3795
|
+
getSubstringOperands: (substrCtx) =>
|
|
3796
|
+
this._getSubstringOperands(substrCtx),
|
|
3797
|
+
getStringExprCapacity: (exprCode) => this.getStringExprCapacity(exprCode),
|
|
3798
|
+
requireStringInclude: () => this.requireInclude("string"),
|
|
3799
|
+
});
|
|
5409
3800
|
}
|
|
5410
3801
|
|
|
5411
3802
|
/**
|
|
@@ -5442,7 +3833,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5442
3833
|
return;
|
|
5443
3834
|
}
|
|
5444
3835
|
|
|
5445
|
-
|
|
3836
|
+
TypeRegistrationEngine.trackVariable(ctx, {
|
|
3837
|
+
tryEvaluateConstant: (expr) => this.tryEvaluateConstant(expr),
|
|
3838
|
+
requireInclude: (header) => this.requireInclude(header),
|
|
3839
|
+
resolveQualifiedType: (ids) => this.resolveQualifiedType(ids),
|
|
3840
|
+
});
|
|
5446
3841
|
CodeGenState.localVariables.add(name);
|
|
5447
3842
|
|
|
5448
3843
|
// Bug #8: Track local const values for array size and bit index resolution
|
|
@@ -5454,383 +3849,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
5454
3849
|
}
|
|
5455
3850
|
}
|
|
5456
3851
|
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
private _handleArrayDeclaration(
|
|
5462
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5463
|
-
typeCtx: Parser.TypeContext,
|
|
5464
|
-
name: string,
|
|
5465
|
-
decl: string,
|
|
5466
|
-
): { handled: boolean; code: string; decl: string; isArray: boolean } {
|
|
5467
|
-
const arrayDims = ctx.arrayDimension();
|
|
5468
|
-
const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
|
|
5469
|
-
const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
|
|
5470
|
-
|
|
5471
|
-
if (!isArray) {
|
|
5472
|
-
return { handled: false, code: "", decl, isArray: false };
|
|
5473
|
-
}
|
|
5474
|
-
|
|
5475
|
-
// Generate dimension string from arrayType syntax (u16[8] myArray)
|
|
5476
|
-
const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
|
|
5477
|
-
|
|
5478
|
-
const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
|
|
5479
|
-
const declaredSize =
|
|
5480
|
-
this._parseArrayTypeDimension(typeCtx) ??
|
|
5481
|
-
this._parseFirstArrayDimension(arrayDims);
|
|
5482
|
-
|
|
5483
|
-
// ADR-035: Handle array initializers with size inference
|
|
5484
|
-
if (ctx.expression()) {
|
|
5485
|
-
const arrayInitResult = ArrayInitHelper.processArrayInit(
|
|
5486
|
-
name,
|
|
5487
|
-
typeCtx,
|
|
5488
|
-
ctx.expression()!,
|
|
5489
|
-
arrayDims,
|
|
5490
|
-
hasEmptyArrayDim,
|
|
5491
|
-
declaredSize,
|
|
5492
|
-
{
|
|
5493
|
-
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
5494
|
-
getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
|
|
5495
|
-
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
5496
|
-
},
|
|
5497
|
-
);
|
|
5498
|
-
if (arrayInitResult) {
|
|
5499
|
-
// Track as local array for type resolution
|
|
5500
|
-
CodeGenState.localArrays.add(name);
|
|
5501
|
-
// Include arrayType dimension before arrayDimension dimensions
|
|
5502
|
-
const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
|
|
5503
|
-
return {
|
|
5504
|
-
handled: true,
|
|
5505
|
-
code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
|
|
5506
|
-
decl,
|
|
5507
|
-
isArray: true,
|
|
5508
|
-
};
|
|
5509
|
-
}
|
|
5510
|
-
}
|
|
5511
|
-
|
|
5512
|
-
// Generate dimensions: arrayType dimension first, then arrayDimension dimensions
|
|
5513
|
-
const newDecl =
|
|
5514
|
-
decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
|
|
5515
|
-
CodeGenState.localArrays.add(name);
|
|
5516
|
-
|
|
5517
|
-
return { handled: false, code: "", decl: newDecl, isArray: true };
|
|
5518
|
-
}
|
|
5519
|
-
|
|
5520
|
-
/**
|
|
5521
|
-
* Get array dimension string from arrayType syntax (u16[8] -> "[8]", u16[4][4] -> "[4][4]").
|
|
5522
|
-
* Evaluates const expressions to their numeric values for C compatibility.
|
|
5523
|
-
*/
|
|
5524
|
-
private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
|
|
5525
|
-
if (!typeCtx.arrayType()) {
|
|
5526
|
-
return "";
|
|
5527
|
-
}
|
|
5528
|
-
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
5529
|
-
let result = "";
|
|
5530
|
-
for (const dim of dims) {
|
|
5531
|
-
const sizeExpr = dim.expression();
|
|
5532
|
-
if (!sizeExpr) {
|
|
5533
|
-
result += "[]";
|
|
5534
|
-
continue;
|
|
5535
|
-
}
|
|
5536
|
-
// Try to evaluate as constant first (required for C file-scope arrays)
|
|
5537
|
-
// Fall back to expression text for macros, enums, etc.
|
|
5538
|
-
const dimValue =
|
|
5539
|
-
this.tryEvaluateConstant(sizeExpr) ?? this.generateExpression(sizeExpr);
|
|
5540
|
-
result += `[${dimValue}]`;
|
|
5541
|
-
}
|
|
5542
|
-
return result;
|
|
5543
|
-
}
|
|
5544
|
-
|
|
5545
|
-
/**
|
|
5546
|
-
* Parse first array dimension from arrayType syntax for size validation.
|
|
5547
|
-
*/
|
|
5548
|
-
private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
|
|
5549
|
-
if (!typeCtx.arrayType()) {
|
|
5550
|
-
return null;
|
|
5551
|
-
}
|
|
5552
|
-
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
5553
|
-
if (dims.length === 0) {
|
|
5554
|
-
return null;
|
|
5555
|
-
}
|
|
5556
|
-
const sizeExpr = dims[0].expression();
|
|
5557
|
-
if (!sizeExpr) {
|
|
5558
|
-
return null;
|
|
5559
|
-
}
|
|
5560
|
-
const sizeText = sizeExpr.getText();
|
|
5561
|
-
const digitRegex = /^\d+$/;
|
|
5562
|
-
if (digitRegex.exec(sizeText)) {
|
|
5563
|
-
return Number.parseInt(sizeText, 10);
|
|
5564
|
-
}
|
|
5565
|
-
return null;
|
|
5566
|
-
}
|
|
5567
|
-
|
|
5568
|
-
/**
|
|
5569
|
-
* Issue #696: Parse first array dimension for validation.
|
|
5570
|
-
*/
|
|
5571
|
-
private _parseFirstArrayDimension(
|
|
5572
|
-
arrayDims: Parser.ArrayDimensionContext[],
|
|
5573
|
-
): number | null {
|
|
5574
|
-
if (arrayDims.length === 0 || !arrayDims[0].expression()) {
|
|
5575
|
-
return null;
|
|
5576
|
-
}
|
|
5577
|
-
const sizeText = arrayDims[0].expression()!.getText();
|
|
5578
|
-
if (/^\d+$/.exec(sizeText)) {
|
|
5579
|
-
return Number.parseInt(sizeText, 10);
|
|
5580
|
-
}
|
|
5581
|
-
return null;
|
|
5582
|
-
}
|
|
5583
|
-
|
|
5584
|
-
/**
|
|
5585
|
-
* Validate array declaration syntax - reject C-style, require C-Next style.
|
|
5586
|
-
* C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
|
|
5587
|
-
* C-Next style: u16[8] arr (first dimension in type) - REQUIRED
|
|
5588
|
-
* Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
|
|
5589
|
-
* Exceptions (grammar limitations):
|
|
5590
|
-
* - Empty dimensions for size inference: u8 arr[] <- [...]
|
|
5591
|
-
* - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
|
|
5592
|
-
* - Scoped/global types: this.Type arr[3], global.Type arr[3]
|
|
5593
|
-
* - String types: string<N> arr[3]
|
|
5594
|
-
*/
|
|
5595
|
-
private _validateArrayDeclarationSyntax(
|
|
5596
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5597
|
-
typeCtx: Parser.TypeContext,
|
|
5598
|
-
name: string,
|
|
5599
|
-
): void {
|
|
5600
|
-
const arrayDims = ctx.arrayDimension();
|
|
5601
|
-
if (arrayDims.length === 0) {
|
|
5602
|
-
return; // Not an array declaration
|
|
5603
|
-
}
|
|
5604
|
-
|
|
5605
|
-
// If type already has arrayType, additional dimensions are allowed (multi-dim)
|
|
5606
|
-
if (typeCtx.arrayType()) {
|
|
5607
|
-
return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
|
|
5608
|
-
}
|
|
5609
|
-
|
|
5610
|
-
// Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
|
|
5611
|
-
// The grammar doesn't support u8[] arr syntax, so this is the only way
|
|
5612
|
-
if (arrayDims.length === 1 && !arrayDims[0].expression()) {
|
|
5613
|
-
return; // Size inference pattern allowed
|
|
5614
|
-
}
|
|
5615
|
-
|
|
5616
|
-
// Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
|
|
5617
|
-
// The arrayType grammar only supports single dimension, so multi-dim needs C-style
|
|
5618
|
-
if (arrayDims.length > 1) {
|
|
5619
|
-
return; // Multi-dimensional arrays need C-style
|
|
5620
|
-
}
|
|
5621
|
-
|
|
5622
|
-
// Allow C-style for types that don't support arrayType syntax:
|
|
5623
|
-
// - Qualified types (Scope.Type, Namespace::Type)
|
|
5624
|
-
// - Scoped types (this.Type)
|
|
5625
|
-
// - Global types (global.Type)
|
|
5626
|
-
// - String types (string<N>)
|
|
5627
|
-
// - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
|
|
5628
|
-
if (
|
|
5629
|
-
typeCtx.qualifiedType() ||
|
|
5630
|
-
typeCtx.scopedType() ||
|
|
5631
|
-
typeCtx.globalType() ||
|
|
5632
|
-
typeCtx.stringType()
|
|
5633
|
-
) {
|
|
5634
|
-
return; // Grammar limitation - these can't use arrayType
|
|
5635
|
-
}
|
|
5636
|
-
|
|
5637
|
-
// C-style array declaration detected - reject with helpful error
|
|
5638
|
-
const baseType = this._extractBaseTypeName(typeCtx);
|
|
5639
|
-
const dimensions = arrayDims
|
|
5640
|
-
.map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
|
|
5641
|
-
.join("");
|
|
5642
|
-
const line = ctx.start?.line ?? 0;
|
|
5643
|
-
const col = ctx.start?.column ?? 0;
|
|
5644
|
-
|
|
5645
|
-
throw new Error(
|
|
5646
|
-
`${line}:${col} C-style array declaration is not allowed. ` +
|
|
5647
|
-
`Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
|
|
5648
|
-
);
|
|
5649
|
-
}
|
|
5650
|
-
|
|
5651
|
-
/**
|
|
5652
|
-
* Extract base type name from type context for error messages.
|
|
5653
|
-
*/
|
|
5654
|
-
private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
|
|
5655
|
-
if (typeCtx.primitiveType()) {
|
|
5656
|
-
return typeCtx.primitiveType()!.getText();
|
|
5657
|
-
}
|
|
5658
|
-
if (typeCtx.userType()) {
|
|
5659
|
-
return typeCtx.userType()!.getText();
|
|
5660
|
-
}
|
|
5661
|
-
if (typeCtx.arrayType()) {
|
|
5662
|
-
const arrCtx = typeCtx.arrayType()!;
|
|
5663
|
-
if (arrCtx.primitiveType()) {
|
|
5664
|
-
return arrCtx.primitiveType()!.getText();
|
|
5665
|
-
}
|
|
5666
|
-
if (arrCtx.userType()) {
|
|
5667
|
-
return arrCtx.userType()!.getText();
|
|
5668
|
-
}
|
|
5669
|
-
}
|
|
5670
|
-
return typeCtx.getText();
|
|
5671
|
-
}
|
|
5672
|
-
|
|
5673
|
-
/**
|
|
5674
|
-
* Issue #696: Generate variable initializer with validation.
|
|
5675
|
-
*/
|
|
5676
|
-
private _generateVariableInitializer(
|
|
5677
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5678
|
-
typeCtx: Parser.TypeContext,
|
|
5679
|
-
decl: string,
|
|
5680
|
-
isArray: boolean,
|
|
5681
|
-
): string {
|
|
5682
|
-
if (!ctx.expression()) {
|
|
5683
|
-
// ADR-015: Zero initialization for uninitialized variables
|
|
5684
|
-
return `${decl} = ${this.getZeroInitializer(typeCtx, isArray)}`;
|
|
5685
|
-
}
|
|
5686
|
-
|
|
5687
|
-
const typeName = this.getTypeName(typeCtx);
|
|
5688
|
-
const savedExpectedType = CodeGenState.expectedType;
|
|
5689
|
-
CodeGenState.expectedType = typeName;
|
|
5690
|
-
|
|
5691
|
-
// ADR-017: Validate enum type for initialization
|
|
5692
|
-
EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
|
|
5693
|
-
|
|
5694
|
-
// ADR-024: Validate integer literals and type conversions
|
|
5695
|
-
this._validateIntegerInitializer(ctx, typeName);
|
|
5696
|
-
|
|
5697
|
-
const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
|
|
5698
|
-
CodeGenState.expectedType = savedExpectedType;
|
|
5699
|
-
|
|
5700
|
-
return result;
|
|
5701
|
-
}
|
|
5702
|
-
|
|
5703
|
-
/**
|
|
5704
|
-
* Issue #696: Validate integer initializer using helper.
|
|
5705
|
-
*/
|
|
5706
|
-
private _validateIntegerInitializer(
|
|
5707
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5708
|
-
typeName: string,
|
|
5709
|
-
): void {
|
|
5710
|
-
if (!this._isIntegerType(typeName)) {
|
|
5711
|
-
return;
|
|
5712
|
-
}
|
|
5713
|
-
|
|
5714
|
-
const exprText = ctx.expression()!.getText().trim();
|
|
5715
|
-
const line = ctx.start?.line ?? 0;
|
|
5716
|
-
const col = ctx.start?.column ?? 0;
|
|
5717
|
-
const isLiteral = LiteralUtils.parseIntegerLiteral(exprText) !== undefined;
|
|
5718
|
-
|
|
5719
|
-
try {
|
|
5720
|
-
if (isLiteral) {
|
|
5721
|
-
// Direct literal - validate it fits in the target type
|
|
5722
|
-
this._validateLiteralFitsType(exprText, typeName);
|
|
5723
|
-
} else {
|
|
5724
|
-
// Not a literal - check for narrowing/sign conversions
|
|
5725
|
-
const sourceType = this.getExpressionType(ctx.expression()!);
|
|
5726
|
-
this._validateTypeConversion(typeName, sourceType);
|
|
5727
|
-
}
|
|
5728
|
-
} catch (validationError) {
|
|
5729
|
-
const msg =
|
|
5730
|
-
validationError instanceof Error
|
|
5731
|
-
? validationError.message
|
|
5732
|
-
: String(validationError);
|
|
5733
|
-
throw new Error(`${line}:${col} ${msg}`, { cause: validationError });
|
|
5734
|
-
}
|
|
5735
|
-
}
|
|
5736
|
-
|
|
5737
|
-
/**
|
|
5738
|
-
* Issue #696: Handle pending C++ class field assignments.
|
|
5739
|
-
*/
|
|
5740
|
-
private _finalizeCppClassAssignments(
|
|
5741
|
-
_ctx: Parser.VariableDeclarationContext,
|
|
5742
|
-
typeCtx: Parser.TypeContext,
|
|
5743
|
-
name: string,
|
|
5744
|
-
decl: string,
|
|
5745
|
-
): string {
|
|
5746
|
-
if (CodeGenState.pendingCppClassAssignments.length === 0) {
|
|
5747
|
-
return `${decl};`;
|
|
5748
|
-
}
|
|
5749
|
-
|
|
5750
|
-
if (CodeGenState.inFunctionBody) {
|
|
5751
|
-
const assignments = CodeGenState.pendingCppClassAssignments
|
|
5752
|
-
.map((a) => `${name}.${a}`)
|
|
5753
|
-
.join("\n");
|
|
5754
|
-
CodeGenState.pendingCppClassAssignments = [];
|
|
5755
|
-
return `${decl};\n${assignments}`;
|
|
5756
|
-
}
|
|
5757
|
-
|
|
5758
|
-
// At global scope, we can't emit assignment statements.
|
|
5759
|
-
CodeGenState.pendingCppClassAssignments = [];
|
|
5760
|
-
throw new Error(
|
|
5761
|
-
`Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
|
|
5762
|
-
`syntax at global scope. Use constructor syntax or initialize fields separately.`,
|
|
5763
|
-
);
|
|
5764
|
-
}
|
|
5765
|
-
|
|
5766
|
-
/**
|
|
5767
|
-
* Issue #375: Generate C++ constructor-style declaration
|
|
5768
|
-
* Validates that all arguments are const variables.
|
|
5769
|
-
* Example: `Adafruit_MAX31856 thermocouple(pinConst);` -> `Adafruit_MAX31856 thermocouple(pinConst);`
|
|
5770
|
-
*/
|
|
5771
|
-
private _generateConstructorDecl(
|
|
5772
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5773
|
-
argListCtx: Parser.ConstructorArgumentListContext,
|
|
5774
|
-
): string {
|
|
5775
|
-
const type = this.generateType(ctx.type());
|
|
5776
|
-
const name = ctx.IDENTIFIER().getText();
|
|
5777
|
-
const line = ctx.start?.line ?? 0;
|
|
5778
|
-
|
|
5779
|
-
// Collect and validate all arguments
|
|
5780
|
-
const argIdentifiers = argListCtx.IDENTIFIER();
|
|
5781
|
-
const resolvedArgs: string[] = [];
|
|
5782
|
-
|
|
5783
|
-
for (const argNode of argIdentifiers) {
|
|
5784
|
-
const argName = argNode.getText();
|
|
5785
|
-
|
|
5786
|
-
// Check if it exists in type registry
|
|
5787
|
-
const typeInfo = CodeGenState.typeRegistry.get(argName);
|
|
5788
|
-
|
|
5789
|
-
// Also check scoped variables if inside a scope
|
|
5790
|
-
let scopedArgName = argName;
|
|
5791
|
-
let scopedTypeInfo = typeInfo;
|
|
5792
|
-
if (!typeInfo && CodeGenState.currentScope) {
|
|
5793
|
-
scopedArgName = `${CodeGenState.currentScope}_${argName}`;
|
|
5794
|
-
scopedTypeInfo = CodeGenState.typeRegistry.get(scopedArgName);
|
|
5795
|
-
}
|
|
5796
|
-
|
|
5797
|
-
if (!typeInfo && !scopedTypeInfo) {
|
|
5798
|
-
throw new Error(
|
|
5799
|
-
`Error at line ${line}: Constructor argument '${argName}' is not declared`,
|
|
5800
|
-
);
|
|
5801
|
-
}
|
|
5802
|
-
|
|
5803
|
-
const finalTypeInfo = typeInfo ?? scopedTypeInfo!;
|
|
5804
|
-
const finalArgName = typeInfo ? argName : scopedArgName;
|
|
5805
|
-
|
|
5806
|
-
// Check if it's const
|
|
5807
|
-
if (!finalTypeInfo.isConst) {
|
|
5808
|
-
throw new Error(
|
|
5809
|
-
`Error at line ${line}: Constructor argument '${argName}' must be const. ` +
|
|
5810
|
-
`C++ constructors in C-Next only accept const variables.`,
|
|
5811
|
-
);
|
|
5812
|
-
}
|
|
5813
|
-
|
|
5814
|
-
resolvedArgs.push(finalArgName);
|
|
5815
|
-
}
|
|
5816
|
-
|
|
5817
|
-
// Track the variable in type registry (as an external C++ type)
|
|
5818
|
-
CodeGenState.typeRegistry.set(name, {
|
|
5819
|
-
baseType: type,
|
|
5820
|
-
bitWidth: 0, // Unknown for C++ types
|
|
5821
|
-
isArray: false,
|
|
5822
|
-
arrayDimensions: [],
|
|
5823
|
-
isConst: false,
|
|
5824
|
-
isExternalCppType: true,
|
|
5825
|
-
});
|
|
5826
|
-
|
|
5827
|
-
// Track as local variable if inside function body
|
|
5828
|
-
if (CodeGenState.inFunctionBody) {
|
|
5829
|
-
CodeGenState.localVariables.add(name);
|
|
5830
|
-
}
|
|
5831
|
-
|
|
5832
|
-
return `${type} ${name}(${resolvedArgs.join(", ")});`;
|
|
5833
|
-
}
|
|
3852
|
+
// Issue #792: Methods _handleArrayDeclaration, _getArrayTypeDimension, _parseArrayTypeDimension,
|
|
3853
|
+
// _parseFirstArrayDimension, _validateArrayDeclarationSyntax, _extractBaseTypeName,
|
|
3854
|
+
// _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
|
|
3855
|
+
// and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
|
|
5834
3856
|
|
|
5835
3857
|
/**
|
|
5836
3858
|
* Get zero initializer for array types.
|
|
@@ -6055,7 +4077,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6055
4077
|
// ADR-109: Dispatch to assignment handlers
|
|
6056
4078
|
// Build context, classify, and dispatch - all patterns handled by handlers
|
|
6057
4079
|
const assignCtx = buildAssignmentContext(ctx, {
|
|
6058
|
-
typeRegistry: CodeGenState.
|
|
4080
|
+
typeRegistry: CodeGenState.getTypeRegistryView(),
|
|
6059
4081
|
generateExpression: () => value,
|
|
6060
4082
|
generateAssignmentTarget: (targetCtx) =>
|
|
6061
4083
|
this.generateAssignmentTarget(targetCtx),
|