c-next 0.1.70 → 0.1.72
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 +180 -63
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +1 -2
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +1 -2
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +51 -2
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +18 -12
- 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/logic/symbols/SymbolTable.ts +729 -265
- package/src/transpiler/logic/symbols/SymbolUtils.ts +2 -2
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +415 -751
- 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 +268 -1674
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +7 -1
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +2 -1
- package/src/transpiler/output/codegen/assignment/handlers/AssignmentHandlerUtils.ts +7 -1
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +6 -2
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +2 -1
- 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/CallExprUtils.ts +9 -3
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +3 -4
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprUtils.test.ts +4 -8
- package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +236 -0
- package/src/transpiler/output/codegen/helpers/CppConstructorHelper.ts +3 -3
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +435 -0
- 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__/CppConstructorHelper.test.ts +4 -5
- package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +983 -0
- 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 +5 -1
- 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 +20 -33
- 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 +67 -59
- 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/IPipelineInput.ts +0 -3
- 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
|
@@ -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";
|
|
@@ -126,6 +130,9 @@ import TransitiveModificationPropagator from "../../logic/analysis/helpers/Trans
|
|
|
126
130
|
import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
|
|
127
131
|
// Phase 5: Cast validation helper for improved testability
|
|
128
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";
|
|
129
136
|
// Global state for code generation (simplifies debugging, eliminates DI complexity)
|
|
130
137
|
import CodeGenState from "../../state/CodeGenState";
|
|
131
138
|
// Issue #269: Pass-by-value analysis extracted from CodeGenerator
|
|
@@ -137,6 +144,8 @@ import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
|
|
|
137
144
|
import SizeofResolver from "./resolution/SizeofResolver";
|
|
138
145
|
import EnumTypeResolver from "./resolution/EnumTypeResolver";
|
|
139
146
|
import ScopeResolver from "./resolution/ScopeResolver";
|
|
147
|
+
// Issue #797: Centralized C-style name generation
|
|
148
|
+
import QualifiedNameGenerator from "./utils/QualifiedNameGenerator";
|
|
140
149
|
|
|
141
150
|
const {
|
|
142
151
|
generateOverflowHelpers: helperGenerateOverflowHelpers,
|
|
@@ -860,13 +869,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
860
869
|
|
|
861
870
|
/**
|
|
862
871
|
* Generate function argument with pass-by-reference handling.
|
|
863
|
-
* Part of IOrchestrator interface - delegates to
|
|
872
|
+
* Part of IOrchestrator interface - delegates to ArgumentGenerator.
|
|
864
873
|
*/
|
|
865
874
|
generateFunctionArg(
|
|
866
875
|
ctx: Parser.ExpressionContext,
|
|
867
876
|
targetParamBaseType?: string,
|
|
868
877
|
): string {
|
|
869
|
-
|
|
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
|
+
});
|
|
870
886
|
}
|
|
871
887
|
|
|
872
888
|
/**
|
|
@@ -1356,21 +1372,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1356
1372
|
|
|
1357
1373
|
/** Get the capacity of a string expression */
|
|
1358
1374
|
getStringExprCapacity(exprCode: string): number | null {
|
|
1359
|
-
|
|
1360
|
-
if (exprCode.startsWith('"') && exprCode.endsWith('"')) {
|
|
1361
|
-
return StringUtils.literalLength(exprCode);
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1364
|
-
// Variable - check type registry
|
|
1365
|
-
const identifierRegex = /^[a-zA-Z_]\w*$/;
|
|
1366
|
-
if (identifierRegex.test(exprCode)) {
|
|
1367
|
-
const typeInfo = CodeGenState.getVariableTypeInfo(exprCode);
|
|
1368
|
-
if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
|
|
1369
|
-
return typeInfo.stringCapacity;
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
return null;
|
|
1375
|
+
return StringOperationsHelper.getStringExprCapacity(exprCode);
|
|
1374
1376
|
}
|
|
1375
1377
|
|
|
1376
1378
|
// === Parameter Management (IOrchestrator A4) ===
|
|
@@ -1429,25 +1431,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1429
1431
|
|
|
1430
1432
|
// === Function Body Management (A4) ===
|
|
1431
1433
|
|
|
1434
|
+
/**
|
|
1435
|
+
* Enter function body - clears local variables and sets inFunctionBody flag.
|
|
1436
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
1437
|
+
*/
|
|
1432
1438
|
enterFunctionBody(): void {
|
|
1433
|
-
|
|
1434
|
-
CodeGenState.floatBitShadows.clear();
|
|
1435
|
-
CodeGenState.floatShadowCurrent.clear();
|
|
1436
|
-
// Issue #558: modifiedParameters tracking removed - uses analysis-phase results
|
|
1437
|
-
CodeGenState.inFunctionBody = true;
|
|
1438
|
-
// Sync with CodeGenState
|
|
1439
|
-
CodeGenState.enterFunctionBody();
|
|
1439
|
+
FunctionContextManager.enterFunctionBody();
|
|
1440
1440
|
}
|
|
1441
1441
|
|
|
1442
|
+
/**
|
|
1443
|
+
* Exit function body - clears local variables and inFunctionBody flag.
|
|
1444
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
1445
|
+
*/
|
|
1442
1446
|
exitFunctionBody(): void {
|
|
1443
|
-
|
|
1444
|
-
CodeGenState.localVariables.clear();
|
|
1445
|
-
CodeGenState.floatBitShadows.clear();
|
|
1446
|
-
CodeGenState.floatShadowCurrent.clear();
|
|
1447
|
-
CodeGenState.mainArgsName = null;
|
|
1448
|
-
// Sync with CodeGenState
|
|
1449
|
-
CodeGenState.exitFunctionBody();
|
|
1450
|
-
CodeGenState.mainArgsName = null;
|
|
1447
|
+
FunctionContextManager.exitFunctionBody();
|
|
1451
1448
|
}
|
|
1452
1449
|
|
|
1453
1450
|
setMainArgsName(name: string | null): void {
|
|
@@ -2167,19 +2164,18 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2167
2164
|
}
|
|
2168
2165
|
|
|
2169
2166
|
// Issue #461: Initialize constValues from symbol table
|
|
2167
|
+
// Only C-Next TSymbols have initialValue property
|
|
2170
2168
|
CodeGenState.constValues = new Map();
|
|
2171
2169
|
if (CodeGenState.symbolTable) {
|
|
2172
|
-
for (const symbol of CodeGenState.symbolTable.
|
|
2170
|
+
for (const symbol of CodeGenState.symbolTable.getAllTSymbols()) {
|
|
2173
2171
|
if (
|
|
2174
|
-
symbol.kind ===
|
|
2172
|
+
symbol.kind === "variable" &&
|
|
2175
2173
|
symbol.isConst &&
|
|
2176
2174
|
symbol.initialValue !== undefined
|
|
2177
2175
|
) {
|
|
2178
2176
|
const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
|
|
2179
2177
|
if (value !== undefined) {
|
|
2180
2178
|
CodeGenState.constValues.set(symbol.name, value);
|
|
2181
|
-
// Also populate CodeGenState
|
|
2182
|
-
CodeGenState.constValues.set(symbol.name, value);
|
|
2183
2179
|
}
|
|
2184
2180
|
}
|
|
2185
2181
|
}
|
|
@@ -2487,7 +2483,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2487
2483
|
const funcDecl = member.functionDeclaration()!;
|
|
2488
2484
|
const funcName = funcDecl.IDENTIFIER().getText();
|
|
2489
2485
|
// Track fully qualified function name: Scope_function
|
|
2490
|
-
const fullName =
|
|
2486
|
+
const fullName = QualifiedNameGenerator.forFunctionStrings(
|
|
2487
|
+
scopeName,
|
|
2488
|
+
funcName,
|
|
2489
|
+
);
|
|
2491
2490
|
CodeGenState.knownFunctions.add(fullName);
|
|
2492
2491
|
// ADR-013: Track function signature for const checking
|
|
2493
2492
|
const sig = this.extractFunctionSignature(
|
|
@@ -2552,66 +2551,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2552
2551
|
* SonarCloud S3776: Refactored to use helper methods.
|
|
2553
2552
|
*/
|
|
2554
2553
|
private registerAllVariableTypes(tree: Parser.ProgramContext): void {
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
// Register scope member variable types
|
|
2562
|
-
if (decl.scopeDeclaration()) {
|
|
2563
|
-
this.registerScopeMemberTypes(decl.scopeDeclaration()!);
|
|
2564
|
-
}
|
|
2565
|
-
|
|
2566
|
-
// Note: Function parameters are registered per-function during generation
|
|
2567
|
-
// since they're scoped to the function body
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
/**
|
|
2572
|
-
* Register a global variable type and track const values.
|
|
2573
|
-
* SonarCloud S3776: Extracted from registerAllVariableTypes().
|
|
2574
|
-
*/
|
|
2575
|
-
private registerGlobalVariableType(
|
|
2576
|
-
varDecl: Parser.VariableDeclarationContext,
|
|
2577
|
-
): void {
|
|
2578
|
-
this.trackVariableType(varDecl);
|
|
2579
|
-
|
|
2580
|
-
// Bug #8: Track const values for array size resolution at file scope
|
|
2581
|
-
if (varDecl.constModifier() && varDecl.expression()) {
|
|
2582
|
-
const constName = varDecl.IDENTIFIER().getText();
|
|
2583
|
-
const constValue = this.tryEvaluateConstant(varDecl.expression()!);
|
|
2584
|
-
if (constValue !== undefined) {
|
|
2585
|
-
CodeGenState.constValues.set(constName, constValue);
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
|
|
2590
|
-
/**
|
|
2591
|
-
* Register scope member variable types.
|
|
2592
|
-
* SonarCloud S3776: Extracted from registerAllVariableTypes().
|
|
2593
|
-
*/
|
|
2594
|
-
private registerScopeMemberTypes(
|
|
2595
|
-
scopeDecl: Parser.ScopeDeclarationContext,
|
|
2596
|
-
): void {
|
|
2597
|
-
const scopeName = scopeDecl.IDENTIFIER().getText();
|
|
2598
|
-
|
|
2599
|
-
// Set currentScope so that this.Type references resolve correctly
|
|
2600
|
-
const savedScope = CodeGenState.currentScope;
|
|
2601
|
-
this.setCurrentScope(scopeName);
|
|
2602
|
-
|
|
2603
|
-
for (const member of scopeDecl.scopeMember()) {
|
|
2604
|
-
if (member.variableDeclaration()) {
|
|
2605
|
-
const varDecl = member.variableDeclaration()!;
|
|
2606
|
-
const varName = varDecl.IDENTIFIER().getText();
|
|
2607
|
-
const fullName = `${scopeName}_${varName}`;
|
|
2608
|
-
// Register with mangled name (Scope_variable)
|
|
2609
|
-
this.trackVariableTypeWithName(varDecl, fullName);
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
|
|
2613
|
-
// Restore previous scope
|
|
2614
|
-
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
|
+
});
|
|
2615
2559
|
}
|
|
2616
2560
|
|
|
2617
2561
|
// Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
|
|
@@ -2640,830 +2584,163 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2640
2584
|
}
|
|
2641
2585
|
|
|
2642
2586
|
/**
|
|
2643
|
-
*
|
|
2644
|
-
*
|
|
2645
|
-
* Bug #8: Extended to resolve const variable references for file-scope array sizes.
|
|
2646
|
-
* Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
|
|
2647
|
-
*/
|
|
2648
|
-
// Issue #63: checkArrayBounds moved to TypeValidator
|
|
2649
|
-
|
|
2650
|
-
/**
|
|
2651
|
-
* Evaluate array dimensions from ArrayDimensionContext[] to number[].
|
|
2652
|
-
* Used for bitmap array registration.
|
|
2653
|
-
* Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
|
|
2654
|
-
*/
|
|
2655
|
-
private _evaluateArrayDimensions(
|
|
2656
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
2657
|
-
): number[] | undefined {
|
|
2658
|
-
return ArrayDimensionParser.parseAllDimensions(arrayDim, {
|
|
2659
|
-
constValues: CodeGenState.constValues,
|
|
2660
|
-
typeWidths: TYPE_WIDTH,
|
|
2661
|
-
isKnownStruct: (name) => this.isKnownStruct(name),
|
|
2662
|
-
});
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
|
-
/**
|
|
2666
|
-
* Try to register a type as enum or bitmap. Returns true if handled.
|
|
2667
|
-
* Extracted to reduce duplication across type contexts (ADR-017, ADR-034).
|
|
2668
|
-
*/
|
|
2669
|
-
private _tryRegisterEnumOrBitmapType(
|
|
2670
|
-
name: string,
|
|
2671
|
-
baseType: string,
|
|
2672
|
-
isConst: boolean,
|
|
2673
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
2674
|
-
overflowBehavior: TOverflowBehavior,
|
|
2675
|
-
isAtomic: boolean,
|
|
2676
|
-
): boolean {
|
|
2677
|
-
// Common options for type registration
|
|
2678
|
-
const registrationOptions = {
|
|
2679
|
-
name,
|
|
2680
|
-
baseType,
|
|
2681
|
-
isConst,
|
|
2682
|
-
overflowBehavior,
|
|
2683
|
-
isAtomic,
|
|
2684
|
-
};
|
|
2685
|
-
|
|
2686
|
-
// ADR-017: Check if this is an enum type
|
|
2687
|
-
if (
|
|
2688
|
-
TypeRegistrationUtils.tryRegisterEnumType(
|
|
2689
|
-
CodeGenState.symbols!,
|
|
2690
|
-
registrationOptions,
|
|
2691
|
-
)
|
|
2692
|
-
) {
|
|
2693
|
-
return true;
|
|
2694
|
-
}
|
|
2695
|
-
|
|
2696
|
-
// ADR-034: Check if this is a bitmap type
|
|
2697
|
-
const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
|
|
2698
|
-
if (
|
|
2699
|
-
TypeRegistrationUtils.tryRegisterBitmapType(
|
|
2700
|
-
CodeGenState.symbols!,
|
|
2701
|
-
registrationOptions,
|
|
2702
|
-
bitmapDimensions,
|
|
2703
|
-
)
|
|
2704
|
-
) {
|
|
2705
|
-
return true;
|
|
2706
|
-
}
|
|
2707
|
-
|
|
2708
|
-
return false;
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
/**
|
|
2712
|
-
* Extract type info from a variable declaration and register it.
|
|
2713
|
-
* Delegates to trackVariableTypeWithName using the variable's identifier.
|
|
2587
|
+
* Issue #322: Check if a type name is a user-defined struct
|
|
2588
|
+
* Part of IOrchestrator interface.
|
|
2714
2589
|
*/
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
this.trackVariableTypeWithName(varDecl, name);
|
|
2590
|
+
isStructType(typeName: string): boolean {
|
|
2591
|
+
return TypeResolver.isStructType(typeName);
|
|
2718
2592
|
}
|
|
2719
2593
|
|
|
2720
|
-
// =========================================================================
|
|
2721
|
-
// Type Registration Helpers - Extracted to reduce cognitive complexity
|
|
2722
|
-
// =========================================================================
|
|
2723
|
-
|
|
2724
2594
|
/**
|
|
2725
|
-
*
|
|
2726
|
-
*
|
|
2727
|
-
* Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
|
|
2595
|
+
* Set up parameter tracking for a function.
|
|
2596
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
2728
2597
|
*/
|
|
2729
|
-
private
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2598
|
+
private _setParameters(params: Parser.ParameterListContext | null): void {
|
|
2599
|
+
FunctionContextManager.processParameterList(
|
|
2600
|
+
params,
|
|
2601
|
+
this._getFunctionContextCallbacks(),
|
|
2602
|
+
);
|
|
2733
2603
|
}
|
|
2734
2604
|
|
|
2735
2605
|
/**
|
|
2736
|
-
*
|
|
2737
|
-
*
|
|
2606
|
+
* Clear parameter tracking when leaving a function.
|
|
2607
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
2738
2608
|
*/
|
|
2739
|
-
private
|
|
2740
|
-
|
|
2741
|
-
typeCtx: Parser.TypeContext,
|
|
2742
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
2743
|
-
isConst: boolean,
|
|
2744
|
-
overflowBehavior: TOverflowBehavior,
|
|
2745
|
-
isAtomic: boolean,
|
|
2746
|
-
): boolean {
|
|
2747
|
-
const stringCtx = typeCtx.stringType();
|
|
2748
|
-
if (!stringCtx) {
|
|
2749
|
-
return false;
|
|
2750
|
-
}
|
|
2751
|
-
|
|
2752
|
-
const intLiteral = stringCtx.INTEGER_LITERAL();
|
|
2753
|
-
if (!intLiteral) {
|
|
2754
|
-
return false;
|
|
2755
|
-
}
|
|
2756
|
-
|
|
2757
|
-
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
2758
|
-
this.requireInclude("string");
|
|
2759
|
-
const stringDim = capacity + 1;
|
|
2760
|
-
|
|
2761
|
-
// Check if there are additional array dimensions (e.g., [4] in string<64> arr[4])
|
|
2762
|
-
const additionalDims = this.extractArrayDimensionsSimple(arrayDim);
|
|
2763
|
-
const allDims =
|
|
2764
|
-
additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
|
|
2765
|
-
|
|
2766
|
-
CodeGenState.setVariableTypeInfo(registryName, {
|
|
2767
|
-
baseType: "char",
|
|
2768
|
-
bitWidth: 8,
|
|
2769
|
-
isArray: true,
|
|
2770
|
-
arrayDimensions: allDims,
|
|
2771
|
-
isConst,
|
|
2772
|
-
isString: true,
|
|
2773
|
-
stringCapacity: capacity,
|
|
2774
|
-
overflowBehavior,
|
|
2775
|
-
isAtomic,
|
|
2776
|
-
});
|
|
2777
|
-
return true;
|
|
2609
|
+
private _clearParameters(): void {
|
|
2610
|
+
FunctionContextManager.clearParameters();
|
|
2778
2611
|
}
|
|
2779
2612
|
|
|
2780
2613
|
/**
|
|
2781
|
-
*
|
|
2782
|
-
* Handles scoped, global, qualified, and user types
|
|
2614
|
+
* ADR-013: Extract function signature from parameter list
|
|
2783
2615
|
*/
|
|
2784
|
-
private
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
return CodeGenState.currentScope
|
|
2795
|
-
? `${CodeGenState.currentScope}_${typeName}`
|
|
2796
|
-
: typeName;
|
|
2797
|
-
}
|
|
2798
|
-
|
|
2799
|
-
if (typeCtx.globalType()) {
|
|
2800
|
-
// Issue #478: Handle global.Type for global types inside scope
|
|
2801
|
-
return typeCtx.globalType()!.IDENTIFIER().getText();
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
if (typeCtx.qualifiedType()) {
|
|
2805
|
-
// ADR-016: Handle Scope.Type from outside scope
|
|
2806
|
-
// Issue #388: Also handles C++ namespace types
|
|
2807
|
-
const identifiers = typeCtx.qualifiedType()!.IDENTIFIER();
|
|
2808
|
-
const identifierNames = identifiers.map((id) => id.getText());
|
|
2809
|
-
return this.resolveQualifiedType(identifierNames);
|
|
2810
|
-
}
|
|
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
|
+
}> = [];
|
|
2811
2626
|
|
|
2812
|
-
if (
|
|
2813
|
-
|
|
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
|
+
}
|
|
2814
2639
|
}
|
|
2815
2640
|
|
|
2816
|
-
return
|
|
2641
|
+
return { name, parameters };
|
|
2817
2642
|
}
|
|
2818
2643
|
|
|
2819
2644
|
/**
|
|
2820
|
-
*
|
|
2821
|
-
*
|
|
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
|
|
2822
2647
|
*/
|
|
2823
|
-
private
|
|
2824
|
-
|
|
2825
|
-
|
|
2648
|
+
private registerCallbackType(
|
|
2649
|
+
name: string,
|
|
2650
|
+
funcDecl: Parser.FunctionDeclarationContext,
|
|
2826
2651
|
): void {
|
|
2827
|
-
const
|
|
2828
|
-
const
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
// ADR-049: Extract atomic modifier
|
|
2837
|
-
const isAtomic = varDecl.atomicModifier() !== null;
|
|
2838
|
-
|
|
2839
|
-
// ADR-045: Handle bounded string type first (special case)
|
|
2840
|
-
if (
|
|
2841
|
-
this.tryRegisterStringType(
|
|
2842
|
-
registryName,
|
|
2843
|
-
typeCtx,
|
|
2844
|
-
arrayDim,
|
|
2845
|
-
isConst,
|
|
2846
|
-
overflowBehavior,
|
|
2847
|
-
isAtomic,
|
|
2848
|
-
)
|
|
2849
|
-
) {
|
|
2850
|
-
return;
|
|
2851
|
-
}
|
|
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
|
+
}> = [];
|
|
2852
2661
|
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
isAtomic,
|
|
2862
|
-
);
|
|
2863
|
-
return;
|
|
2864
|
-
}
|
|
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;
|
|
2865
2670
|
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
if (!baseType) {
|
|
2869
|
-
return;
|
|
2870
|
-
}
|
|
2671
|
+
// ADR-029: Check if parameter type is itself a callback type
|
|
2672
|
+
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
2871
2673
|
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
this._tryRegisterEnumOrBitmapType(
|
|
2875
|
-
registryName,
|
|
2876
|
-
baseType,
|
|
2877
|
-
isConst,
|
|
2878
|
-
arrayDim,
|
|
2879
|
-
overflowBehavior,
|
|
2880
|
-
isAtomic,
|
|
2881
|
-
)
|
|
2882
|
-
) {
|
|
2883
|
-
return;
|
|
2884
|
-
}
|
|
2674
|
+
let paramType: string;
|
|
2675
|
+
let isPointer: boolean;
|
|
2885
2676
|
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
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
|
+
}
|
|
2896
2687
|
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
if (arrayTypeCtx.primitiveType()) {
|
|
2912
|
-
baseType = arrayTypeCtx.primitiveType()!.getText();
|
|
2913
|
-
bitWidth = TYPE_WIDTH[baseType] || 0;
|
|
2914
|
-
} else if (arrayTypeCtx.userType()) {
|
|
2915
|
-
// Handle user types (structs, enums, bitmaps)
|
|
2916
|
-
baseType = arrayTypeCtx.userType()!.getText();
|
|
2917
|
-
|
|
2918
|
-
const combinedArrayDim = arrayDim ?? [];
|
|
2919
|
-
|
|
2920
|
-
// Check if this is an enum or bitmap type and delegate to proper registration
|
|
2921
|
-
if (
|
|
2922
|
-
this._tryRegisterEnumOrBitmapType(
|
|
2923
|
-
registryName,
|
|
2924
|
-
baseType,
|
|
2925
|
-
isConst,
|
|
2926
|
-
combinedArrayDim,
|
|
2927
|
-
overflowBehavior,
|
|
2928
|
-
isAtomic,
|
|
2929
|
-
)
|
|
2930
|
-
) {
|
|
2931
|
-
// Enum/bitmap was registered, but we need to update with arrayType dimension
|
|
2932
|
-
const existingInfo = CodeGenState.getVariableTypeInfo(registryName);
|
|
2933
|
-
if (existingInfo) {
|
|
2934
|
-
const arrayTypeDim =
|
|
2935
|
-
this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
|
|
2936
|
-
const allDims = arrayTypeDim
|
|
2937
|
-
? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
|
|
2938
|
-
: existingInfo.arrayDimensions;
|
|
2939
|
-
CodeGenState.setVariableTypeInfo(registryName, {
|
|
2940
|
-
...existingInfo,
|
|
2941
|
-
isArray: true,
|
|
2942
|
-
arrayDimensions: allDims,
|
|
2943
|
-
});
|
|
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 = "";
|
|
2944
2702
|
}
|
|
2945
|
-
|
|
2703
|
+
parameters.push({
|
|
2704
|
+
name: paramName,
|
|
2705
|
+
type: paramType,
|
|
2706
|
+
isConst,
|
|
2707
|
+
isPointer,
|
|
2708
|
+
isArray,
|
|
2709
|
+
arrayDims,
|
|
2710
|
+
});
|
|
2946
2711
|
}
|
|
2947
|
-
|
|
2948
|
-
// Not an enum/bitmap - register as regular user type (struct)
|
|
2949
|
-
// bitWidth already initialized to 0, no reassignment needed
|
|
2950
|
-
}
|
|
2951
|
-
|
|
2952
|
-
if (!baseType) {
|
|
2953
|
-
return;
|
|
2954
2712
|
}
|
|
2955
2713
|
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
CodeGenState.setVariableTypeInfo(registryName, {
|
|
2962
|
-
baseType,
|
|
2963
|
-
bitWidth,
|
|
2964
|
-
isArray: true,
|
|
2965
|
-
arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
|
|
2966
|
-
isConst,
|
|
2967
|
-
overflowBehavior,
|
|
2968
|
-
isAtomic,
|
|
2714
|
+
CodeGenState.callbackTypes.set(name, {
|
|
2715
|
+
functionName: name,
|
|
2716
|
+
returnType,
|
|
2717
|
+
parameters,
|
|
2718
|
+
typedefName: `${name}_fp`,
|
|
2969
2719
|
});
|
|
2970
2720
|
}
|
|
2971
2721
|
|
|
2972
2722
|
/**
|
|
2973
|
-
*
|
|
2723
|
+
* ADR-029: Check if a function is used as a callback type (field type in a struct)
|
|
2974
2724
|
*/
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
): number | undefined {
|
|
2978
|
-
// Get first dimension for backwards compatibility
|
|
2979
|
-
const dims = arrayTypeCtx.arrayTypeDimension();
|
|
2980
|
-
if (dims.length === 0) {
|
|
2981
|
-
return undefined;
|
|
2982
|
-
}
|
|
2983
|
-
const sizeExpr = dims[0].expression();
|
|
2984
|
-
if (!sizeExpr) {
|
|
2985
|
-
return undefined;
|
|
2986
|
-
}
|
|
2987
|
-
const size = Number.parseInt(sizeExpr.getText(), 10);
|
|
2988
|
-
return Number.isNaN(size) ? undefined : size;
|
|
2989
|
-
}
|
|
2725
|
+
// Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
|
|
2726
|
+
// and validateBareIdentifierInScope moved to TypeValidator
|
|
2990
2727
|
|
|
2728
|
+
// EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
|
|
2729
|
+
// _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
|
|
2730
|
+
// _getExpressionEnumType, _getFunctionCallEnumType
|
|
2991
2731
|
/**
|
|
2992
|
-
*
|
|
2732
|
+
* ADR-017: Check if an expression represents an integer literal or numeric type.
|
|
2733
|
+
* Used to detect comparisons between enums and integers.
|
|
2993
2734
|
*/
|
|
2994
|
-
private
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
const arrayDimensions: number[] = [];
|
|
2999
|
-
|
|
3000
|
-
// Get all dimensions from array type syntax (supports multi-dimensional)
|
|
3001
|
-
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
3002
|
-
const sizeExpr = dim.expression();
|
|
3003
|
-
if (sizeExpr) {
|
|
3004
|
-
const size = Number.parseInt(sizeExpr.getText(), 10);
|
|
3005
|
-
if (!Number.isNaN(size)) {
|
|
3006
|
-
arrayDimensions.push(size);
|
|
3007
|
-
}
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
|
-
|
|
3011
|
-
// Add additional dimensions using const evaluation
|
|
3012
|
-
const additionalDims = this._evaluateArrayDimensions(arrayDim);
|
|
3013
|
-
if (additionalDims) {
|
|
3014
|
-
arrayDimensions.push(...additionalDims);
|
|
3015
|
-
}
|
|
3016
|
-
|
|
3017
|
-
return arrayDimensions;
|
|
2735
|
+
private _isIntegerExpression(
|
|
2736
|
+
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
2737
|
+
): boolean {
|
|
2738
|
+
return EnumAssignmentValidator.isIntegerExpression(ctx);
|
|
3018
2739
|
}
|
|
3019
2740
|
|
|
3020
2741
|
/**
|
|
3021
|
-
*
|
|
3022
|
-
|
|
3023
|
-
private _registerStandardType(
|
|
3024
|
-
registryName: string,
|
|
3025
|
-
baseType: string,
|
|
3026
|
-
arrayDim: Parser.ArrayDimensionContext[] | null,
|
|
3027
|
-
isConst: boolean,
|
|
3028
|
-
overflowBehavior: TOverflowBehavior,
|
|
3029
|
-
isAtomic: boolean,
|
|
3030
|
-
): void {
|
|
3031
|
-
const bitWidth = TYPE_WIDTH[baseType] || 0;
|
|
3032
|
-
// Issue #665: Check array syntax presence first, then try to resolve dimensions
|
|
3033
|
-
// This matches the pattern in trackVariableType() - unresolved dimensions (e.g., enum
|
|
3034
|
-
// members like EIndex.COUNT) should still mark the variable as an array
|
|
3035
|
-
const isArray = arrayDim !== null && arrayDim.length > 0;
|
|
3036
|
-
const arrayDimensions = isArray
|
|
3037
|
-
? this._evaluateArrayDimensions(arrayDim)
|
|
3038
|
-
: undefined;
|
|
3039
|
-
|
|
3040
|
-
CodeGenState.setVariableTypeInfo(registryName, {
|
|
3041
|
-
baseType,
|
|
3042
|
-
bitWidth,
|
|
3043
|
-
isArray,
|
|
3044
|
-
arrayDimensions: isArray ? arrayDimensions : undefined,
|
|
3045
|
-
isConst,
|
|
3046
|
-
overflowBehavior,
|
|
3047
|
-
isAtomic,
|
|
3048
|
-
});
|
|
3049
|
-
}
|
|
3050
|
-
|
|
3051
|
-
/**
|
|
3052
|
-
* Issue #322: Check if a type name is a user-defined struct
|
|
3053
|
-
* Part of IOrchestrator interface.
|
|
3054
|
-
*/
|
|
3055
|
-
isStructType(typeName: string): boolean {
|
|
3056
|
-
return TypeResolver.isStructType(typeName);
|
|
3057
|
-
}
|
|
3058
|
-
|
|
3059
|
-
/**
|
|
3060
|
-
* Set up parameter tracking for a function
|
|
3061
|
-
*/
|
|
3062
|
-
private _setParameters(params: Parser.ParameterListContext | null): void {
|
|
3063
|
-
CodeGenState.currentParameters.clear();
|
|
3064
|
-
CodeGenState.currentParameters.clear();
|
|
3065
|
-
if (!params) return;
|
|
3066
|
-
|
|
3067
|
-
for (const param of params.parameter()) {
|
|
3068
|
-
this._processParameter(param);
|
|
3069
|
-
}
|
|
3070
|
-
}
|
|
3071
|
-
|
|
3072
|
-
/**
|
|
3073
|
-
* Process a single parameter declaration
|
|
3074
|
-
*/
|
|
3075
|
-
private _processParameter(param: Parser.ParameterContext): void {
|
|
3076
|
-
const name = param.IDENTIFIER().getText();
|
|
3077
|
-
// Check both C-Next style (u8[8] param) and legacy style (u8 param[8])
|
|
3078
|
-
const isArray =
|
|
3079
|
-
param.arrayDimension().length > 0 || param.type().arrayType() !== null;
|
|
3080
|
-
const isConst = param.constModifier() !== null;
|
|
3081
|
-
const typeCtx = param.type();
|
|
3082
|
-
|
|
3083
|
-
// Resolve type information
|
|
3084
|
-
const typeInfo = this._resolveParameterTypeInfo(typeCtx);
|
|
3085
|
-
|
|
3086
|
-
// Register in currentParameters
|
|
3087
|
-
const paramInfo = {
|
|
3088
|
-
name,
|
|
3089
|
-
baseType: typeInfo.typeName,
|
|
3090
|
-
isArray,
|
|
3091
|
-
isStruct: typeInfo.isStruct,
|
|
3092
|
-
isConst,
|
|
3093
|
-
isCallback: typeInfo.isCallback,
|
|
3094
|
-
isString: typeInfo.isString,
|
|
3095
|
-
};
|
|
3096
|
-
CodeGenState.currentParameters.set(name, paramInfo);
|
|
3097
|
-
|
|
3098
|
-
// Register in typeRegistry
|
|
3099
|
-
this._registerParameterType(name, typeInfo, param, isArray, isConst);
|
|
3100
|
-
}
|
|
3101
|
-
|
|
3102
|
-
/**
|
|
3103
|
-
* Resolve type name and flags from a type context
|
|
3104
|
-
*/
|
|
3105
|
-
private _resolveParameterTypeInfo(typeCtx: Parser.TypeContext): {
|
|
3106
|
-
typeName: string;
|
|
3107
|
-
isStruct: boolean;
|
|
3108
|
-
isCallback: boolean;
|
|
3109
|
-
isString: boolean;
|
|
3110
|
-
} {
|
|
3111
|
-
if (typeCtx.primitiveType()) {
|
|
3112
|
-
return {
|
|
3113
|
-
typeName: typeCtx.primitiveType()!.getText(),
|
|
3114
|
-
isStruct: false,
|
|
3115
|
-
isCallback: false,
|
|
3116
|
-
isString: false,
|
|
3117
|
-
};
|
|
3118
|
-
}
|
|
3119
|
-
|
|
3120
|
-
if (typeCtx.userType()) {
|
|
3121
|
-
const typeName = typeCtx.userType()!.getText();
|
|
3122
|
-
return {
|
|
3123
|
-
typeName,
|
|
3124
|
-
isStruct: this.isStructType(typeName),
|
|
3125
|
-
isCallback: CodeGenState.callbackTypes.has(typeName),
|
|
3126
|
-
isString: false,
|
|
3127
|
-
};
|
|
3128
|
-
}
|
|
3129
|
-
|
|
3130
|
-
if (typeCtx.qualifiedType()) {
|
|
3131
|
-
const identifierNames = typeCtx
|
|
3132
|
-
.qualifiedType()!
|
|
3133
|
-
.IDENTIFIER()
|
|
3134
|
-
.map((id) => id.getText());
|
|
3135
|
-
const typeName = this.resolveQualifiedType(identifierNames);
|
|
3136
|
-
return {
|
|
3137
|
-
typeName,
|
|
3138
|
-
isStruct: this.isStructType(typeName),
|
|
3139
|
-
isCallback: false,
|
|
3140
|
-
isString: false,
|
|
3141
|
-
};
|
|
3142
|
-
}
|
|
3143
|
-
|
|
3144
|
-
if (typeCtx.scopedType()) {
|
|
3145
|
-
const localTypeName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
3146
|
-
const typeName = CodeGenState.currentScope
|
|
3147
|
-
? `${CodeGenState.currentScope}_${localTypeName}`
|
|
3148
|
-
: localTypeName;
|
|
3149
|
-
return {
|
|
3150
|
-
typeName,
|
|
3151
|
-
isStruct: this.isStructType(typeName),
|
|
3152
|
-
isCallback: false,
|
|
3153
|
-
isString: false,
|
|
3154
|
-
};
|
|
3155
|
-
}
|
|
3156
|
-
|
|
3157
|
-
if (typeCtx.globalType()) {
|
|
3158
|
-
const typeName = typeCtx.globalType()!.IDENTIFIER().getText();
|
|
3159
|
-
return {
|
|
3160
|
-
typeName,
|
|
3161
|
-
isStruct: this.isStructType(typeName),
|
|
3162
|
-
isCallback: false,
|
|
3163
|
-
isString: false,
|
|
3164
|
-
};
|
|
3165
|
-
}
|
|
3166
|
-
|
|
3167
|
-
if (typeCtx.stringType()) {
|
|
3168
|
-
return {
|
|
3169
|
-
typeName: "string",
|
|
3170
|
-
isStruct: false,
|
|
3171
|
-
isCallback: false,
|
|
3172
|
-
isString: true,
|
|
3173
|
-
};
|
|
3174
|
-
}
|
|
3175
|
-
|
|
3176
|
-
// Handle C-Next style array type (u8[8] param) - extract base type
|
|
3177
|
-
if (typeCtx.arrayType()) {
|
|
3178
|
-
const arrayTypeCtx = typeCtx.arrayType()!;
|
|
3179
|
-
if (arrayTypeCtx.primitiveType()) {
|
|
3180
|
-
return {
|
|
3181
|
-
typeName: arrayTypeCtx.primitiveType()!.getText(),
|
|
3182
|
-
isStruct: false,
|
|
3183
|
-
isCallback: false,
|
|
3184
|
-
isString: false,
|
|
3185
|
-
};
|
|
3186
|
-
}
|
|
3187
|
-
if (arrayTypeCtx.userType()) {
|
|
3188
|
-
const typeName = arrayTypeCtx.userType()!.getText();
|
|
3189
|
-
return {
|
|
3190
|
-
typeName,
|
|
3191
|
-
isStruct: this.isStructType(typeName),
|
|
3192
|
-
isCallback: CodeGenState.callbackTypes.has(typeName),
|
|
3193
|
-
isString: false,
|
|
3194
|
-
};
|
|
3195
|
-
}
|
|
3196
|
-
// Handle string array type (string<32>[5] param)
|
|
3197
|
-
if (arrayTypeCtx.stringType()) {
|
|
3198
|
-
const stringCtx = arrayTypeCtx.stringType()!;
|
|
3199
|
-
return {
|
|
3200
|
-
typeName: stringCtx.getText(), // "string<32>"
|
|
3201
|
-
isStruct: false,
|
|
3202
|
-
isCallback: false,
|
|
3203
|
-
isString: true,
|
|
3204
|
-
};
|
|
3205
|
-
}
|
|
3206
|
-
}
|
|
3207
|
-
|
|
3208
|
-
// Fallback
|
|
3209
|
-
return {
|
|
3210
|
-
typeName: typeCtx.getText(),
|
|
3211
|
-
isStruct: false,
|
|
3212
|
-
isCallback: false,
|
|
3213
|
-
isString: false,
|
|
3214
|
-
};
|
|
3215
|
-
}
|
|
3216
|
-
|
|
3217
|
-
/**
|
|
3218
|
-
* Extract array dimensions from parameter (C-style or C-Next style).
|
|
3219
|
-
*/
|
|
3220
|
-
private _extractParamArrayDimensions(
|
|
3221
|
-
param: Parser.ParameterContext,
|
|
3222
|
-
typeCtx: Parser.TypeContext,
|
|
3223
|
-
isArray: boolean,
|
|
3224
|
-
): number[] {
|
|
3225
|
-
if (!isArray) return [];
|
|
3226
|
-
|
|
3227
|
-
// Try C-style first (param.arrayDimension())
|
|
3228
|
-
if (param.arrayDimension().length > 0) {
|
|
3229
|
-
return ArrayDimensionParser.parseForParameters(param.arrayDimension());
|
|
3230
|
-
}
|
|
3231
|
-
|
|
3232
|
-
// C-Next style: get dimensions from arrayType
|
|
3233
|
-
const arrayTypeCtx = typeCtx.arrayType();
|
|
3234
|
-
if (!arrayTypeCtx) return [];
|
|
3235
|
-
|
|
3236
|
-
const dimensions: number[] = [];
|
|
3237
|
-
for (const dim of arrayTypeCtx.arrayTypeDimension()) {
|
|
3238
|
-
const expr = dim.expression();
|
|
3239
|
-
if (!expr) continue;
|
|
3240
|
-
const size = Number.parseInt(expr.getText(), 10);
|
|
3241
|
-
if (!Number.isNaN(size)) {
|
|
3242
|
-
dimensions.push(size);
|
|
3243
|
-
}
|
|
3244
|
-
}
|
|
3245
|
-
return dimensions;
|
|
3246
|
-
}
|
|
3247
|
-
|
|
3248
|
-
/**
|
|
3249
|
-
* Register a parameter in the type registry
|
|
3250
|
-
*/
|
|
3251
|
-
private _registerParameterType(
|
|
3252
|
-
name: string,
|
|
3253
|
-
typeInfo: { typeName: string; isString: boolean },
|
|
3254
|
-
param: Parser.ParameterContext,
|
|
3255
|
-
isArray: boolean,
|
|
3256
|
-
isConst: boolean,
|
|
3257
|
-
): void {
|
|
3258
|
-
const { typeName, isString } = typeInfo;
|
|
3259
|
-
const typeCtx = param.type();
|
|
3260
|
-
|
|
3261
|
-
const isEnum = CodeGenState.symbols!.knownEnums.has(typeName);
|
|
3262
|
-
const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
|
|
3263
|
-
|
|
3264
|
-
// Extract array dimensions
|
|
3265
|
-
const arrayDimensions = this._extractParamArrayDimensions(
|
|
3266
|
-
param,
|
|
3267
|
-
typeCtx,
|
|
3268
|
-
isArray,
|
|
3269
|
-
);
|
|
3270
|
-
|
|
3271
|
-
// Add string capacity dimension if applicable
|
|
3272
|
-
const stringCapacity = this._getStringCapacity(typeCtx, isString);
|
|
3273
|
-
if (isArray && stringCapacity !== undefined) {
|
|
3274
|
-
arrayDimensions.push(stringCapacity + 1);
|
|
3275
|
-
}
|
|
3276
|
-
|
|
3277
|
-
const registeredType = {
|
|
3278
|
-
baseType: typeName,
|
|
3279
|
-
bitWidth: isBitmap
|
|
3280
|
-
? CodeGenState.symbols!.bitmapBitWidth.get(typeName) || 0
|
|
3281
|
-
: TYPE_WIDTH[typeName] || 0,
|
|
3282
|
-
isArray,
|
|
3283
|
-
arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
|
|
3284
|
-
isConst,
|
|
3285
|
-
isEnum,
|
|
3286
|
-
enumTypeName: isEnum ? typeName : undefined,
|
|
3287
|
-
isBitmap,
|
|
3288
|
-
bitmapTypeName: isBitmap ? typeName : undefined,
|
|
3289
|
-
isString,
|
|
3290
|
-
stringCapacity,
|
|
3291
|
-
isParameter: true,
|
|
3292
|
-
};
|
|
3293
|
-
CodeGenState.setVariableTypeInfo(name, registeredType);
|
|
3294
|
-
}
|
|
3295
|
-
|
|
3296
|
-
/**
|
|
3297
|
-
* Extract string capacity from a string type context
|
|
3298
|
-
*/
|
|
3299
|
-
private _getStringCapacity(
|
|
3300
|
-
typeCtx: Parser.TypeContext,
|
|
3301
|
-
isString: boolean,
|
|
3302
|
-
): number | undefined {
|
|
3303
|
-
if (!isString) return undefined;
|
|
3304
|
-
|
|
3305
|
-
// Check direct stringType (e.g., string<32> param)
|
|
3306
|
-
if (typeCtx.stringType()) {
|
|
3307
|
-
const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
|
|
3308
|
-
if (intLiteral) {
|
|
3309
|
-
return Number.parseInt(intLiteral.getText(), 10);
|
|
3310
|
-
}
|
|
3311
|
-
}
|
|
3312
|
-
|
|
3313
|
-
// Check arrayType with stringType (e.g., string<32>[5] param)
|
|
3314
|
-
if (typeCtx.arrayType()?.stringType()) {
|
|
3315
|
-
const intLiteral = typeCtx.arrayType()!.stringType()!.INTEGER_LITERAL();
|
|
3316
|
-
if (intLiteral) {
|
|
3317
|
-
return Number.parseInt(intLiteral.getText(), 10);
|
|
3318
|
-
}
|
|
3319
|
-
}
|
|
3320
|
-
|
|
3321
|
-
return undefined;
|
|
3322
|
-
}
|
|
3323
|
-
|
|
3324
|
-
/**
|
|
3325
|
-
* Clear parameter tracking when leaving a function
|
|
3326
|
-
*/
|
|
3327
|
-
private _clearParameters(): void {
|
|
3328
|
-
// ADR-025: Remove parameter types from typeRegistry
|
|
3329
|
-
for (const name of CodeGenState.currentParameters.keys()) {
|
|
3330
|
-
CodeGenState.deleteVariableTypeInfo(name);
|
|
3331
|
-
}
|
|
3332
|
-
CodeGenState.currentParameters.clear();
|
|
3333
|
-
CodeGenState.localArrays.clear();
|
|
3334
|
-
}
|
|
3335
|
-
|
|
3336
|
-
/**
|
|
3337
|
-
* ADR-013: Extract function signature from parameter list
|
|
3338
|
-
*/
|
|
3339
|
-
private extractFunctionSignature(
|
|
3340
|
-
name: string,
|
|
3341
|
-
params: Parser.ParameterListContext | null,
|
|
3342
|
-
): FunctionSignature {
|
|
3343
|
-
const parameters: Array<{
|
|
3344
|
-
name: string;
|
|
3345
|
-
baseType: string;
|
|
3346
|
-
isConst: boolean;
|
|
3347
|
-
isArray: boolean;
|
|
3348
|
-
}> = [];
|
|
3349
|
-
|
|
3350
|
-
if (params) {
|
|
3351
|
-
for (const param of params.parameter()) {
|
|
3352
|
-
const paramName = param.IDENTIFIER().getText();
|
|
3353
|
-
const isConst = param.constModifier() !== null;
|
|
3354
|
-
// arrayDimension() returns an array (due to grammar's *), so check length
|
|
3355
|
-
// Also check C-Next style array type (e.g., u8[8] param)
|
|
3356
|
-
const isArray =
|
|
3357
|
-
param.arrayDimension().length > 0 ||
|
|
3358
|
-
param.type().arrayType() !== null;
|
|
3359
|
-
const baseType = this.getTypeName(param.type());
|
|
3360
|
-
parameters.push({ name: paramName, baseType, isConst, isArray });
|
|
3361
|
-
}
|
|
3362
|
-
}
|
|
3363
|
-
|
|
3364
|
-
return { name, parameters };
|
|
3365
|
-
}
|
|
3366
|
-
|
|
3367
|
-
/**
|
|
3368
|
-
* ADR-029: Register a function as a callback type
|
|
3369
|
-
* The function name becomes both a callable function and a type for callback fields
|
|
3370
|
-
*/
|
|
3371
|
-
private registerCallbackType(
|
|
3372
|
-
name: string,
|
|
3373
|
-
funcDecl: Parser.FunctionDeclarationContext,
|
|
3374
|
-
): void {
|
|
3375
|
-
const returnType = this.generateType(funcDecl.type());
|
|
3376
|
-
const parameters: Array<{
|
|
3377
|
-
name: string;
|
|
3378
|
-
type: string;
|
|
3379
|
-
isConst: boolean;
|
|
3380
|
-
isPointer: boolean;
|
|
3381
|
-
isArray: boolean;
|
|
3382
|
-
arrayDims: string;
|
|
3383
|
-
}> = [];
|
|
3384
|
-
|
|
3385
|
-
if (funcDecl.parameterList()) {
|
|
3386
|
-
for (const param of funcDecl.parameterList()!.parameter()) {
|
|
3387
|
-
const paramName = param.IDENTIFIER().getText();
|
|
3388
|
-
const typeName = this.getTypeName(param.type());
|
|
3389
|
-
const isConst = param.constModifier() !== null;
|
|
3390
|
-
const dims = param.arrayDimension();
|
|
3391
|
-
const arrayTypeCtx = param.type().arrayType();
|
|
3392
|
-
const isArray = dims.length > 0 || arrayTypeCtx !== null;
|
|
3393
|
-
|
|
3394
|
-
// ADR-029: Check if parameter type is itself a callback type
|
|
3395
|
-
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
3396
|
-
|
|
3397
|
-
let paramType: string;
|
|
3398
|
-
let isPointer: boolean;
|
|
3399
|
-
|
|
3400
|
-
if (isCallbackParam) {
|
|
3401
|
-
// Use the callback typedef name
|
|
3402
|
-
const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
|
|
3403
|
-
paramType = cbInfo.typedefName;
|
|
3404
|
-
isPointer = false; // Function pointers are already pointers
|
|
3405
|
-
} else {
|
|
3406
|
-
paramType = this.generateType(param.type());
|
|
3407
|
-
// ADR-006: Non-array parameters become pointers
|
|
3408
|
-
isPointer = !isArray;
|
|
3409
|
-
}
|
|
3410
|
-
|
|
3411
|
-
let arrayDims: string;
|
|
3412
|
-
if (dims.length > 0) {
|
|
3413
|
-
arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
|
|
3414
|
-
} else if (arrayTypeCtx) {
|
|
3415
|
-
// Generate all dimensions from arrayType (supports multi-dimensional)
|
|
3416
|
-
arrayDims = arrayTypeCtx
|
|
3417
|
-
.arrayTypeDimension()
|
|
3418
|
-
.map((d) => {
|
|
3419
|
-
const expr = d.expression();
|
|
3420
|
-
return expr ? `[${this.generateExpression(expr)}]` : "[]";
|
|
3421
|
-
})
|
|
3422
|
-
.join("");
|
|
3423
|
-
} else {
|
|
3424
|
-
arrayDims = "";
|
|
3425
|
-
}
|
|
3426
|
-
parameters.push({
|
|
3427
|
-
name: paramName,
|
|
3428
|
-
type: paramType,
|
|
3429
|
-
isConst,
|
|
3430
|
-
isPointer,
|
|
3431
|
-
isArray,
|
|
3432
|
-
arrayDims,
|
|
3433
|
-
});
|
|
3434
|
-
}
|
|
3435
|
-
}
|
|
3436
|
-
|
|
3437
|
-
CodeGenState.callbackTypes.set(name, {
|
|
3438
|
-
functionName: name,
|
|
3439
|
-
returnType,
|
|
3440
|
-
parameters,
|
|
3441
|
-
typedefName: `${name}_fp`,
|
|
3442
|
-
});
|
|
3443
|
-
}
|
|
3444
|
-
|
|
3445
|
-
/**
|
|
3446
|
-
* ADR-029: Check if a function is used as a callback type (field type in a struct)
|
|
3447
|
-
*/
|
|
3448
|
-
// Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
|
|
3449
|
-
// and validateBareIdentifierInScope moved to TypeValidator
|
|
3450
|
-
|
|
3451
|
-
// EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
|
|
3452
|
-
// _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
|
|
3453
|
-
// _getExpressionEnumType, _getFunctionCallEnumType
|
|
3454
|
-
/**
|
|
3455
|
-
* ADR-017: Check if an expression represents an integer literal or numeric type.
|
|
3456
|
-
* Used to detect comparisons between enums and integers.
|
|
3457
|
-
*/
|
|
3458
|
-
private _isIntegerExpression(
|
|
3459
|
-
ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
|
|
3460
|
-
): boolean {
|
|
3461
|
-
return EnumAssignmentValidator.isIntegerExpression(ctx);
|
|
3462
|
-
}
|
|
3463
|
-
|
|
3464
|
-
/**
|
|
3465
|
-
* ADR-045: Check if an expression is a string concatenation (contains + with string operands).
|
|
3466
|
-
* Returns the operand expressions if it is, null otherwise.
|
|
2742
|
+
* ADR-045: Check if an expression is a string concatenation.
|
|
2743
|
+
* Delegates to StringOperationsHelper.
|
|
3467
2744
|
*/
|
|
3468
2745
|
private _getStringConcatOperands(ctx: Parser.ExpressionContext): {
|
|
3469
2746
|
left: string;
|
|
@@ -3471,53 +2748,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3471
2748
|
leftCapacity: number;
|
|
3472
2749
|
rightCapacity: number;
|
|
3473
2750
|
} | null {
|
|
3474
|
-
|
|
3475
|
-
// Issue #707: Deduplicated expression tree navigation
|
|
3476
|
-
const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
|
|
3477
|
-
if (!add) return null;
|
|
3478
|
-
const multExprs = add.multiplicativeExpression();
|
|
3479
|
-
|
|
3480
|
-
// Need exactly 2 operands for simple concatenation
|
|
3481
|
-
if (multExprs.length !== 2) return null;
|
|
3482
|
-
|
|
3483
|
-
// Check if this is addition (not subtraction)
|
|
3484
|
-
const text = add.getText();
|
|
3485
|
-
if (text.includes("-")) return null;
|
|
3486
|
-
|
|
3487
|
-
// Get the operand texts
|
|
3488
|
-
const leftText = multExprs[0].getText();
|
|
3489
|
-
const rightText = multExprs[1].getText();
|
|
3490
|
-
|
|
3491
|
-
// Check if at least one operand is a string
|
|
3492
|
-
const leftCapacity = this.getStringExprCapacity(leftText);
|
|
3493
|
-
const rightCapacity = this.getStringExprCapacity(rightText);
|
|
3494
|
-
|
|
3495
|
-
if (leftCapacity === null && rightCapacity === null) {
|
|
3496
|
-
return null; // Neither is a string
|
|
3497
|
-
}
|
|
3498
|
-
|
|
3499
|
-
// If one is null, it's not a valid string concatenation
|
|
3500
|
-
if (leftCapacity === null || rightCapacity === null) {
|
|
3501
|
-
return null;
|
|
3502
|
-
}
|
|
3503
|
-
|
|
3504
|
-
return {
|
|
3505
|
-
left: leftText,
|
|
3506
|
-
right: rightText,
|
|
3507
|
-
leftCapacity,
|
|
3508
|
-
rightCapacity,
|
|
3509
|
-
};
|
|
2751
|
+
return StringOperationsHelper.getStringConcatOperands(ctx);
|
|
3510
2752
|
}
|
|
3511
2753
|
|
|
3512
2754
|
/**
|
|
3513
|
-
* ADR-045:
|
|
3514
|
-
*
|
|
3515
|
-
* For string variables, capacity is from the type registry.
|
|
3516
|
-
*/
|
|
3517
|
-
/**
|
|
3518
|
-
* ADR-045: Check if an expression is a substring extraction (string[start, length]).
|
|
3519
|
-
* Returns the source string, start, length, and source capacity if it is.
|
|
3520
|
-
* Issue #707: Uses ExpressionUnwrapper for tree navigation.
|
|
2755
|
+
* ADR-045: Check if an expression is a substring extraction.
|
|
2756
|
+
* Delegates to StringOperationsHelper.
|
|
3521
2757
|
*/
|
|
3522
2758
|
private _getSubstringOperands(ctx: Parser.ExpressionContext): {
|
|
3523
2759
|
source: string;
|
|
@@ -3525,51 +2761,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3525
2761
|
length: string;
|
|
3526
2762
|
sourceCapacity: number;
|
|
3527
2763
|
} | null {
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
const primary = postfix.primaryExpression();
|
|
3533
|
-
const ops = postfix.postfixOp();
|
|
3534
|
-
|
|
3535
|
-
// Need exactly one postfix operation (the [start, length])
|
|
3536
|
-
if (ops.length !== 1) return null;
|
|
3537
|
-
|
|
3538
|
-
const op = ops[0];
|
|
3539
|
-
const exprs = op.expression();
|
|
3540
|
-
|
|
3541
|
-
// Get the source variable name first
|
|
3542
|
-
const sourceId = primary.IDENTIFIER();
|
|
3543
|
-
if (!sourceId) return null;
|
|
3544
|
-
|
|
3545
|
-
const sourceName = sourceId.getText();
|
|
3546
|
-
|
|
3547
|
-
// Check if source is a string type
|
|
3548
|
-
const typeInfo = CodeGenState.getVariableTypeInfo(sourceName);
|
|
3549
|
-
if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
|
|
3550
|
-
return null;
|
|
3551
|
-
}
|
|
3552
|
-
|
|
3553
|
-
// Issue #140: Handle both [start, length] pattern (2 expressions)
|
|
3554
|
-
// and single-character access [index] pattern (1 expression, treated as [index, 1])
|
|
3555
|
-
if (exprs.length === 2) {
|
|
3556
|
-
return {
|
|
3557
|
-
source: sourceName,
|
|
3558
|
-
start: this.generateExpression(exprs[0]),
|
|
3559
|
-
length: this.generateExpression(exprs[1]),
|
|
3560
|
-
sourceCapacity: typeInfo.stringCapacity,
|
|
3561
|
-
};
|
|
3562
|
-
} else if (exprs.length === 1) {
|
|
3563
|
-
// Single-character access: source[i] is sugar for source[i, 1]
|
|
3564
|
-
return {
|
|
3565
|
-
source: sourceName,
|
|
3566
|
-
start: this.generateExpression(exprs[0]),
|
|
3567
|
-
length: "1",
|
|
3568
|
-
sourceCapacity: typeInfo.stringCapacity,
|
|
3569
|
-
};
|
|
3570
|
-
}
|
|
3571
|
-
|
|
3572
|
-
return null;
|
|
2764
|
+
return StringOperationsHelper.getSubstringOperands(ctx, {
|
|
2765
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
2766
|
+
});
|
|
3573
2767
|
}
|
|
3574
2768
|
|
|
3575
2769
|
// ========================================================================
|
|
@@ -3794,226 +2988,47 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3794
2988
|
const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
|
|
3795
2989
|
if (!postfix) return "not-array";
|
|
3796
2990
|
|
|
3797
|
-
const ops = postfix.postfixOp();
|
|
3798
|
-
if (ops.length === 0) return "not-array";
|
|
3799
|
-
|
|
3800
|
-
// Last operator must be member access (.identifier)
|
|
3801
|
-
const lastOp = ops.at(-1)!;
|
|
3802
|
-
const memberName = lastOp.IDENTIFIER()?.getText();
|
|
3803
|
-
if (!memberName) return "not-array";
|
|
3804
|
-
|
|
3805
|
-
// Get the base identifier to find the struct type
|
|
3806
|
-
const primary = postfix.primaryExpression();
|
|
3807
|
-
if (!primary) return "not-array";
|
|
3808
|
-
const baseId = primary.IDENTIFIER()?.getText();
|
|
3809
|
-
if (!baseId) return "not-array";
|
|
3810
|
-
|
|
3811
|
-
// Look up the struct type from either:
|
|
3812
|
-
// 1. Local variable: typeRegistry.get(baseId).baseType
|
|
3813
|
-
// 2. Parameter: currentParameters.get(baseId).baseType
|
|
3814
|
-
let structType: string | undefined;
|
|
3815
|
-
|
|
3816
|
-
const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
|
|
3817
|
-
if (typeInfo) {
|
|
3818
|
-
structType = typeInfo.baseType;
|
|
3819
|
-
} else {
|
|
3820
|
-
const paramInfo = CodeGenState.currentParameters.get(baseId);
|
|
3821
|
-
if (paramInfo) {
|
|
3822
|
-
structType = paramInfo.baseType;
|
|
3823
|
-
}
|
|
3824
|
-
}
|
|
3825
|
-
|
|
3826
|
-
if (!structType) return "not-array";
|
|
3827
|
-
|
|
3828
|
-
// Check if this struct member is an array
|
|
3829
|
-
const memberInfo = this.getMemberTypeInfo(structType, memberName);
|
|
3830
|
-
|
|
3831
|
-
// Issue #355: If memberInfo is undefined, we don't have struct field info
|
|
3832
|
-
// This could mean the header wasn't parsed - return "unknown" for defensive generation
|
|
3833
|
-
if (!memberInfo) {
|
|
3834
|
-
return "unknown";
|
|
3835
|
-
}
|
|
3836
|
-
|
|
3837
|
-
return memberInfo.isArray ? "array" : "not-array";
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
/**
|
|
3841
|
-
* Generate a function argument with proper ADR-006 semantics.
|
|
3842
|
-
* - Local variables get & (address-of)
|
|
3843
|
-
* - Member access (cursor.x) gets & (address-of)
|
|
3844
|
-
* - Array access (arr[i]) gets & (address-of)
|
|
3845
|
-
* - Parameters are passed as-is (already pointers)
|
|
3846
|
-
* - Arrays are passed as-is (naturally decay to pointers)
|
|
3847
|
-
* - Literals use compound literals for pointer params: &(type){value}
|
|
3848
|
-
* - Complex expressions are passed as-is
|
|
3849
|
-
*/
|
|
3850
|
-
private _generateFunctionArg(
|
|
3851
|
-
ctx: Parser.ExpressionContext,
|
|
3852
|
-
targetParamBaseType?: string,
|
|
3853
|
-
): string {
|
|
3854
|
-
const id = CodegenParserUtils.getSimpleIdentifier(ctx);
|
|
3855
|
-
if (id) {
|
|
3856
|
-
return this._handleIdentifierArg(id);
|
|
3857
|
-
}
|
|
3858
|
-
|
|
3859
|
-
const lvalueType = this.getLvalueType(ctx);
|
|
3860
|
-
if (lvalueType) {
|
|
3861
|
-
return this._handleLvalueArg(ctx, lvalueType, targetParamBaseType);
|
|
3862
|
-
}
|
|
3863
|
-
|
|
3864
|
-
return this._handleRvalueArg(ctx, targetParamBaseType);
|
|
3865
|
-
}
|
|
3866
|
-
|
|
3867
|
-
/**
|
|
3868
|
-
* Handle simple identifier argument (parameter, local array, scope member, or variable)
|
|
3869
|
-
*/
|
|
3870
|
-
private _handleIdentifierArg(id: string): string {
|
|
3871
|
-
// Parameters are already pointers
|
|
3872
|
-
if (CodeGenState.currentParameters.get(id)) {
|
|
3873
|
-
return id;
|
|
3874
|
-
}
|
|
3875
|
-
|
|
3876
|
-
// Local arrays decay to pointers
|
|
3877
|
-
if (CodeGenState.localArrays.has(id)) {
|
|
3878
|
-
return id;
|
|
3879
|
-
}
|
|
3880
|
-
|
|
3881
|
-
// Global arrays also decay to pointers (check typeRegistry)
|
|
3882
|
-
// But NOT strings - strings need & (they're char arrays but passed by reference)
|
|
3883
|
-
const typeInfo = CodeGenState.getVariableTypeInfo(id);
|
|
3884
|
-
if (typeInfo?.isArray && !typeInfo.isString) {
|
|
3885
|
-
return id;
|
|
3886
|
-
}
|
|
3887
|
-
|
|
3888
|
-
// Scope member - may need prefixing
|
|
3889
|
-
if (CodeGenState.currentScope) {
|
|
3890
|
-
const members = CodeGenState.getScopeMembers(CodeGenState.currentScope);
|
|
3891
|
-
if (members?.has(id)) {
|
|
3892
|
-
const scopedName = `${CodeGenState.currentScope}_${id}`;
|
|
3893
|
-
return CppModeHelper.maybeAddressOf(scopedName);
|
|
3894
|
-
}
|
|
3895
|
-
}
|
|
3896
|
-
|
|
3897
|
-
// Local variable - add & (except in C++ mode)
|
|
3898
|
-
return CppModeHelper.maybeAddressOf(id);
|
|
3899
|
-
}
|
|
3900
|
-
|
|
3901
|
-
/**
|
|
3902
|
-
* Handle lvalue argument (member access or array access)
|
|
3903
|
-
*/
|
|
3904
|
-
private _handleLvalueArg(
|
|
3905
|
-
ctx: Parser.ExpressionContext,
|
|
3906
|
-
lvalueType: string,
|
|
3907
|
-
targetParamBaseType?: string,
|
|
3908
|
-
): string {
|
|
3909
|
-
// Member access to array field - arrays decay to pointers
|
|
3910
|
-
if (lvalueType === "member") {
|
|
3911
|
-
const memberResult = this._handleMemberAccessArg(
|
|
3912
|
-
ctx,
|
|
3913
|
-
targetParamBaseType,
|
|
3914
|
-
);
|
|
3915
|
-
if (memberResult) return memberResult;
|
|
3916
|
-
}
|
|
3917
|
-
|
|
3918
|
-
// Generate expression with address-of
|
|
3919
|
-
const generatedExpr = this.generateExpression(ctx);
|
|
3920
|
-
const expr = CppModeHelper.maybeAddressOf(generatedExpr);
|
|
3921
|
-
|
|
3922
|
-
// String subscript access may need cast
|
|
3923
|
-
if (lvalueType === "array") {
|
|
3924
|
-
return this._maybeCastStringSubscript(ctx, expr, targetParamBaseType);
|
|
3925
|
-
}
|
|
3926
|
-
|
|
3927
|
-
return expr;
|
|
3928
|
-
}
|
|
3929
|
-
|
|
3930
|
-
/**
|
|
3931
|
-
* Handle member access argument - may need special handling for arrays or C++ conversions
|
|
3932
|
-
*/
|
|
3933
|
-
private _handleMemberAccessArg(
|
|
3934
|
-
ctx: Parser.ExpressionContext,
|
|
3935
|
-
targetParamBaseType?: string,
|
|
3936
|
-
): string | null {
|
|
3937
|
-
const arrayStatus = this.getMemberAccessArrayStatus(ctx);
|
|
3938
|
-
|
|
3939
|
-
// Array member - no address-of needed
|
|
3940
|
-
if (arrayStatus === "array") {
|
|
3941
|
-
return this.generateExpression(ctx);
|
|
3942
|
-
}
|
|
3943
|
-
|
|
3944
|
-
// C++ mode may need temp variable for type conversion
|
|
3945
|
-
if (
|
|
3946
|
-
arrayStatus === "not-array" &&
|
|
3947
|
-
this.needsCppMemberConversion(ctx, targetParamBaseType)
|
|
3948
|
-
) {
|
|
3949
|
-
return this._createCppMemberConversionTemp(ctx, targetParamBaseType!);
|
|
3950
|
-
}
|
|
3951
|
-
|
|
3952
|
-
return null; // Fall through to default lvalue handling
|
|
3953
|
-
}
|
|
3954
|
-
|
|
3955
|
-
/**
|
|
3956
|
-
* Create temp variable for C++ member conversion
|
|
3957
|
-
*/
|
|
3958
|
-
private _createCppMemberConversionTemp(
|
|
3959
|
-
ctx: Parser.ExpressionContext,
|
|
3960
|
-
targetParamBaseType: string,
|
|
3961
|
-
): string {
|
|
3962
|
-
const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
|
|
3963
|
-
const value = this.generateExpression(ctx);
|
|
3964
|
-
const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
|
|
3965
|
-
const castExpr = CppModeHelper.cast(cType, value);
|
|
3966
|
-
CodeGenState.pendingTempDeclarations.push(
|
|
3967
|
-
`${cType} ${tempName} = ${castExpr};`,
|
|
3968
|
-
);
|
|
3969
|
-
return CppModeHelper.maybeAddressOf(tempName);
|
|
3970
|
-
}
|
|
3971
|
-
|
|
3972
|
-
/**
|
|
3973
|
-
* Maybe cast string subscript access for integer pointer parameters
|
|
3974
|
-
*/
|
|
3975
|
-
private _maybeCastStringSubscript(
|
|
3976
|
-
ctx: Parser.ExpressionContext,
|
|
3977
|
-
expr: string,
|
|
3978
|
-
targetParamBaseType?: string,
|
|
3979
|
-
): string {
|
|
3980
|
-
if (!targetParamBaseType || !this.isStringSubscriptAccess(ctx)) {
|
|
3981
|
-
return expr;
|
|
3982
|
-
}
|
|
2991
|
+
const ops = postfix.postfixOp();
|
|
2992
|
+
if (ops.length === 0) return "not-array";
|
|
3983
2993
|
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
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";
|
|
3988
2998
|
|
|
3989
|
-
|
|
3990
|
-
|
|
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";
|
|
3991
3004
|
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
ctx: Parser.ExpressionContext,
|
|
3997
|
-
targetParamBaseType?: string,
|
|
3998
|
-
): string {
|
|
3999
|
-
if (!targetParamBaseType) {
|
|
4000
|
-
return this.generateExpression(ctx);
|
|
4001
|
-
}
|
|
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;
|
|
4002
3009
|
|
|
4003
|
-
const
|
|
4004
|
-
if (
|
|
4005
|
-
|
|
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
|
+
}
|
|
4006
3018
|
}
|
|
4007
3019
|
|
|
4008
|
-
|
|
3020
|
+
if (!structType) return "not-array";
|
|
3021
|
+
|
|
3022
|
+
// Check if this struct member is an array
|
|
3023
|
+
const memberInfo = this.getMemberTypeInfo(structType, memberName);
|
|
4009
3024
|
|
|
4010
|
-
//
|
|
4011
|
-
|
|
4012
|
-
|
|
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";
|
|
4013
3029
|
}
|
|
4014
3030
|
|
|
4015
|
-
|
|
4016
|
-
return `&(${cType}){${value}}`;
|
|
3031
|
+
return memberInfo.isArray ? "array" : "not-array";
|
|
4017
3032
|
}
|
|
4018
3033
|
|
|
4019
3034
|
// ========================================================================
|
|
@@ -4136,7 +3151,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4136
3151
|
): void {
|
|
4137
3152
|
const type = this.generateType(varDecl.type());
|
|
4138
3153
|
const varName = varDecl.IDENTIFIER().getText();
|
|
4139
|
-
const fullName =
|
|
3154
|
+
const fullName = QualifiedNameGenerator.forMember(scopeName, varName);
|
|
4140
3155
|
const prefix = isPrivate ? "static " : "";
|
|
4141
3156
|
|
|
4142
3157
|
const arrayDims = varDecl.arrayDimension();
|
|
@@ -4147,7 +3162,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4147
3162
|
|
|
4148
3163
|
// Handle arrayType dimension (C-Next style: u8[16] data)
|
|
4149
3164
|
if (hasArrayTypeSyntax) {
|
|
4150
|
-
decl +=
|
|
3165
|
+
decl += VariableDeclHelper.getArrayTypeDimension(varDecl.type(), {
|
|
3166
|
+
tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
|
|
3167
|
+
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
3168
|
+
});
|
|
4151
3169
|
}
|
|
4152
3170
|
|
|
4153
3171
|
// Handle arrayDimension (C-style or additional dimensions)
|
|
@@ -4189,7 +3207,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4189
3207
|
): void {
|
|
4190
3208
|
const returnType = this.generateType(funcDecl.type());
|
|
4191
3209
|
const funcName = funcDecl.IDENTIFIER().getText();
|
|
4192
|
-
const fullName =
|
|
3210
|
+
const fullName = QualifiedNameGenerator.forFunctionStrings(
|
|
3211
|
+
scopeName,
|
|
3212
|
+
funcName,
|
|
3213
|
+
);
|
|
4193
3214
|
const prefix = isPrivate ? "static " : "";
|
|
4194
3215
|
|
|
4195
3216
|
// Issue #269: Set current function name for pass-by-value lookup
|
|
@@ -4584,32 +3605,34 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4584
3605
|
}
|
|
4585
3606
|
|
|
4586
3607
|
/**
|
|
4587
|
-
* Set up context for function generation
|
|
3608
|
+
* Set up context for function generation.
|
|
3609
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
4588
3610
|
*/
|
|
4589
3611
|
private _setupFunctionContext(
|
|
4590
3612
|
name: string,
|
|
4591
3613
|
ctx: Parser.FunctionDeclarationContext,
|
|
4592
3614
|
): void {
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
CodeGenState.currentFunctionReturnType = ctx.type().getText();
|
|
4600
|
-
|
|
4601
|
-
// Track parameters for ADR-006 pointer semantics
|
|
4602
|
-
this._setParameters(ctx.parameterList() ?? null);
|
|
3615
|
+
FunctionContextManager.setupFunctionContext(
|
|
3616
|
+
name,
|
|
3617
|
+
ctx,
|
|
3618
|
+
this._getFunctionContextCallbacks(),
|
|
3619
|
+
);
|
|
3620
|
+
}
|
|
4603
3621
|
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
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
|
+
};
|
|
4609
3631
|
}
|
|
4610
3632
|
|
|
4611
3633
|
/**
|
|
4612
|
-
* Resolve return type and initial params for function
|
|
3634
|
+
* Resolve return type and initial params for function.
|
|
3635
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
4613
3636
|
*/
|
|
4614
3637
|
private _resolveReturnTypeAndParams(
|
|
4615
3638
|
name: string,
|
|
@@ -4617,33 +3640,20 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4617
3640
|
isMainWithArgs: boolean,
|
|
4618
3641
|
ctx: Parser.FunctionDeclarationContext,
|
|
4619
3642
|
): { actualReturnType: string; initialParams: string } {
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
initialParams: "int argc, char *argv[]",
|
|
4627
|
-
};
|
|
4628
|
-
}
|
|
4629
|
-
|
|
4630
|
-
// For main() without args, always use int return type for C++ compatibility
|
|
4631
|
-
const actualReturnType = name === "main" ? "int" : returnType;
|
|
4632
|
-
return { actualReturnType, initialParams: "" };
|
|
3643
|
+
return FunctionContextManager.resolveReturnTypeAndParams(
|
|
3644
|
+
name,
|
|
3645
|
+
returnType,
|
|
3646
|
+
isMainWithArgs,
|
|
3647
|
+
ctx,
|
|
3648
|
+
);
|
|
4633
3649
|
}
|
|
4634
3650
|
|
|
4635
3651
|
/**
|
|
4636
|
-
* Clean up context after function generation
|
|
3652
|
+
* Clean up context after function generation.
|
|
3653
|
+
* Issue #793: Delegates to FunctionContextManager.
|
|
4637
3654
|
*/
|
|
4638
3655
|
private _cleanupFunctionContext(): void {
|
|
4639
|
-
|
|
4640
|
-
CodeGenState.localVariables.clear();
|
|
4641
|
-
CodeGenState.floatBitShadows.clear();
|
|
4642
|
-
CodeGenState.floatShadowCurrent.clear();
|
|
4643
|
-
CodeGenState.mainArgsName = null;
|
|
4644
|
-
CodeGenState.currentFunctionName = null;
|
|
4645
|
-
CodeGenState.currentFunctionReturnType = null;
|
|
4646
|
-
this._clearParameters();
|
|
3656
|
+
FunctionContextManager.cleanupFunctionContext();
|
|
4647
3657
|
}
|
|
4648
3658
|
|
|
4649
3659
|
/**
|
|
@@ -4766,74 +3776,27 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4766
3776
|
// ========================================================================
|
|
4767
3777
|
|
|
4768
3778
|
private generateVariableDecl(ctx: Parser.VariableDeclarationContext): string {
|
|
4769
|
-
// Issue #
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
this._trackLocalVariable(ctx, name);
|
|
4791
|
-
|
|
4792
|
-
// ADR-045: Handle bounded string type specially - early return
|
|
4793
|
-
const stringResult = StringDeclHelper.generateStringDecl(
|
|
4794
|
-
typeCtx,
|
|
4795
|
-
name,
|
|
4796
|
-
ctx.expression() ?? null,
|
|
4797
|
-
ctx.arrayDimension(),
|
|
4798
|
-
modifiers,
|
|
4799
|
-
ctx.constModifier() !== null,
|
|
4800
|
-
{
|
|
4801
|
-
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
4802
|
-
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
4803
|
-
getStringConcatOperands: (concatCtx) =>
|
|
4804
|
-
this._getStringConcatOperands(concatCtx),
|
|
4805
|
-
getSubstringOperands: (substrCtx) =>
|
|
4806
|
-
this._getSubstringOperands(substrCtx),
|
|
4807
|
-
getStringExprCapacity: (exprCode) =>
|
|
4808
|
-
this.getStringExprCapacity(exprCode),
|
|
4809
|
-
requireStringInclude: () => this.requireInclude("string"),
|
|
4810
|
-
},
|
|
4811
|
-
);
|
|
4812
|
-
if (stringResult.handled) {
|
|
4813
|
-
return stringResult.code;
|
|
4814
|
-
}
|
|
4815
|
-
|
|
4816
|
-
// Build base declaration
|
|
4817
|
-
const modifierPrefix = VariableModifierBuilder.toPrefix(modifiers);
|
|
4818
|
-
let decl = `${modifierPrefix}${type} ${name}`;
|
|
4819
|
-
|
|
4820
|
-
// Handle array declarations - early return if array init handled
|
|
4821
|
-
const arrayResult = this._handleArrayDeclaration(ctx, typeCtx, name, decl);
|
|
4822
|
-
if (arrayResult.handled) {
|
|
4823
|
-
return arrayResult.code;
|
|
4824
|
-
}
|
|
4825
|
-
decl = arrayResult.decl;
|
|
4826
|
-
|
|
4827
|
-
// Handle initialization
|
|
4828
|
-
decl = this._generateVariableInitializer(
|
|
4829
|
-
ctx,
|
|
4830
|
-
typeCtx,
|
|
4831
|
-
decl,
|
|
4832
|
-
arrayResult.isArray,
|
|
4833
|
-
);
|
|
4834
|
-
|
|
4835
|
-
// Handle pending C++ class field assignments
|
|
4836
|
-
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
|
+
});
|
|
4837
3800
|
}
|
|
4838
3801
|
|
|
4839
3802
|
/**
|
|
@@ -4870,7 +3833,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4870
3833
|
return;
|
|
4871
3834
|
}
|
|
4872
3835
|
|
|
4873
|
-
|
|
3836
|
+
TypeRegistrationEngine.trackVariable(ctx, {
|
|
3837
|
+
tryEvaluateConstant: (expr) => this.tryEvaluateConstant(expr),
|
|
3838
|
+
requireInclude: (header) => this.requireInclude(header),
|
|
3839
|
+
resolveQualifiedType: (ids) => this.resolveQualifiedType(ids),
|
|
3840
|
+
});
|
|
4874
3841
|
CodeGenState.localVariables.add(name);
|
|
4875
3842
|
|
|
4876
3843
|
// Bug #8: Track local const values for array size and bit index resolution
|
|
@@ -4882,383 +3849,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4882
3849
|
}
|
|
4883
3850
|
}
|
|
4884
3851
|
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
private _handleArrayDeclaration(
|
|
4890
|
-
ctx: Parser.VariableDeclarationContext,
|
|
4891
|
-
typeCtx: Parser.TypeContext,
|
|
4892
|
-
name: string,
|
|
4893
|
-
decl: string,
|
|
4894
|
-
): { handled: boolean; code: string; decl: string; isArray: boolean } {
|
|
4895
|
-
const arrayDims = ctx.arrayDimension();
|
|
4896
|
-
const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
|
|
4897
|
-
const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
|
|
4898
|
-
|
|
4899
|
-
if (!isArray) {
|
|
4900
|
-
return { handled: false, code: "", decl, isArray: false };
|
|
4901
|
-
}
|
|
4902
|
-
|
|
4903
|
-
// Generate dimension string from arrayType syntax (u16[8] myArray)
|
|
4904
|
-
const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
|
|
4905
|
-
|
|
4906
|
-
const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
|
|
4907
|
-
const declaredSize =
|
|
4908
|
-
this._parseArrayTypeDimension(typeCtx) ??
|
|
4909
|
-
this._parseFirstArrayDimension(arrayDims);
|
|
4910
|
-
|
|
4911
|
-
// ADR-035: Handle array initializers with size inference
|
|
4912
|
-
if (ctx.expression()) {
|
|
4913
|
-
const arrayInitResult = ArrayInitHelper.processArrayInit(
|
|
4914
|
-
name,
|
|
4915
|
-
typeCtx,
|
|
4916
|
-
ctx.expression()!,
|
|
4917
|
-
arrayDims,
|
|
4918
|
-
hasEmptyArrayDim,
|
|
4919
|
-
declaredSize,
|
|
4920
|
-
{
|
|
4921
|
-
generateExpression: (exprCtx) => this.generateExpression(exprCtx),
|
|
4922
|
-
getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
|
|
4923
|
-
generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
|
|
4924
|
-
},
|
|
4925
|
-
);
|
|
4926
|
-
if (arrayInitResult) {
|
|
4927
|
-
// Track as local array for type resolution
|
|
4928
|
-
CodeGenState.localArrays.add(name);
|
|
4929
|
-
// Include arrayType dimension before arrayDimension dimensions
|
|
4930
|
-
const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
|
|
4931
|
-
return {
|
|
4932
|
-
handled: true,
|
|
4933
|
-
code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
|
|
4934
|
-
decl,
|
|
4935
|
-
isArray: true,
|
|
4936
|
-
};
|
|
4937
|
-
}
|
|
4938
|
-
}
|
|
4939
|
-
|
|
4940
|
-
// Generate dimensions: arrayType dimension first, then arrayDimension dimensions
|
|
4941
|
-
const newDecl =
|
|
4942
|
-
decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
|
|
4943
|
-
CodeGenState.localArrays.add(name);
|
|
4944
|
-
|
|
4945
|
-
return { handled: false, code: "", decl: newDecl, isArray: true };
|
|
4946
|
-
}
|
|
4947
|
-
|
|
4948
|
-
/**
|
|
4949
|
-
* Get array dimension string from arrayType syntax (u16[8] -> "[8]", u16[4][4] -> "[4][4]").
|
|
4950
|
-
* Evaluates const expressions to their numeric values for C compatibility.
|
|
4951
|
-
*/
|
|
4952
|
-
private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
|
|
4953
|
-
if (!typeCtx.arrayType()) {
|
|
4954
|
-
return "";
|
|
4955
|
-
}
|
|
4956
|
-
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
4957
|
-
let result = "";
|
|
4958
|
-
for (const dim of dims) {
|
|
4959
|
-
const sizeExpr = dim.expression();
|
|
4960
|
-
if (!sizeExpr) {
|
|
4961
|
-
result += "[]";
|
|
4962
|
-
continue;
|
|
4963
|
-
}
|
|
4964
|
-
// Try to evaluate as constant first (required for C file-scope arrays)
|
|
4965
|
-
// Fall back to expression text for macros, enums, etc.
|
|
4966
|
-
const dimValue =
|
|
4967
|
-
this.tryEvaluateConstant(sizeExpr) ?? this.generateExpression(sizeExpr);
|
|
4968
|
-
result += `[${dimValue}]`;
|
|
4969
|
-
}
|
|
4970
|
-
return result;
|
|
4971
|
-
}
|
|
4972
|
-
|
|
4973
|
-
/**
|
|
4974
|
-
* Parse first array dimension from arrayType syntax for size validation.
|
|
4975
|
-
*/
|
|
4976
|
-
private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
|
|
4977
|
-
if (!typeCtx.arrayType()) {
|
|
4978
|
-
return null;
|
|
4979
|
-
}
|
|
4980
|
-
const dims = typeCtx.arrayType()!.arrayTypeDimension();
|
|
4981
|
-
if (dims.length === 0) {
|
|
4982
|
-
return null;
|
|
4983
|
-
}
|
|
4984
|
-
const sizeExpr = dims[0].expression();
|
|
4985
|
-
if (!sizeExpr) {
|
|
4986
|
-
return null;
|
|
4987
|
-
}
|
|
4988
|
-
const sizeText = sizeExpr.getText();
|
|
4989
|
-
const digitRegex = /^\d+$/;
|
|
4990
|
-
if (digitRegex.exec(sizeText)) {
|
|
4991
|
-
return Number.parseInt(sizeText, 10);
|
|
4992
|
-
}
|
|
4993
|
-
return null;
|
|
4994
|
-
}
|
|
4995
|
-
|
|
4996
|
-
/**
|
|
4997
|
-
* Issue #696: Parse first array dimension for validation.
|
|
4998
|
-
*/
|
|
4999
|
-
private _parseFirstArrayDimension(
|
|
5000
|
-
arrayDims: Parser.ArrayDimensionContext[],
|
|
5001
|
-
): number | null {
|
|
5002
|
-
if (arrayDims.length === 0 || !arrayDims[0].expression()) {
|
|
5003
|
-
return null;
|
|
5004
|
-
}
|
|
5005
|
-
const sizeText = arrayDims[0].expression()!.getText();
|
|
5006
|
-
if (/^\d+$/.exec(sizeText)) {
|
|
5007
|
-
return Number.parseInt(sizeText, 10);
|
|
5008
|
-
}
|
|
5009
|
-
return null;
|
|
5010
|
-
}
|
|
5011
|
-
|
|
5012
|
-
/**
|
|
5013
|
-
* Validate array declaration syntax - reject C-style, require C-Next style.
|
|
5014
|
-
* C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
|
|
5015
|
-
* C-Next style: u16[8] arr (first dimension in type) - REQUIRED
|
|
5016
|
-
* Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
|
|
5017
|
-
* Exceptions (grammar limitations):
|
|
5018
|
-
* - Empty dimensions for size inference: u8 arr[] <- [...]
|
|
5019
|
-
* - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
|
|
5020
|
-
* - Scoped/global types: this.Type arr[3], global.Type arr[3]
|
|
5021
|
-
* - String types: string<N> arr[3]
|
|
5022
|
-
*/
|
|
5023
|
-
private _validateArrayDeclarationSyntax(
|
|
5024
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5025
|
-
typeCtx: Parser.TypeContext,
|
|
5026
|
-
name: string,
|
|
5027
|
-
): void {
|
|
5028
|
-
const arrayDims = ctx.arrayDimension();
|
|
5029
|
-
if (arrayDims.length === 0) {
|
|
5030
|
-
return; // Not an array declaration
|
|
5031
|
-
}
|
|
5032
|
-
|
|
5033
|
-
// If type already has arrayType, additional dimensions are allowed (multi-dim)
|
|
5034
|
-
if (typeCtx.arrayType()) {
|
|
5035
|
-
return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
|
|
5036
|
-
}
|
|
5037
|
-
|
|
5038
|
-
// Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
|
|
5039
|
-
// The grammar doesn't support u8[] arr syntax, so this is the only way
|
|
5040
|
-
if (arrayDims.length === 1 && !arrayDims[0].expression()) {
|
|
5041
|
-
return; // Size inference pattern allowed
|
|
5042
|
-
}
|
|
5043
|
-
|
|
5044
|
-
// Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
|
|
5045
|
-
// The arrayType grammar only supports single dimension, so multi-dim needs C-style
|
|
5046
|
-
if (arrayDims.length > 1) {
|
|
5047
|
-
return; // Multi-dimensional arrays need C-style
|
|
5048
|
-
}
|
|
5049
|
-
|
|
5050
|
-
// Allow C-style for types that don't support arrayType syntax:
|
|
5051
|
-
// - Qualified types (Scope.Type, Namespace::Type)
|
|
5052
|
-
// - Scoped types (this.Type)
|
|
5053
|
-
// - Global types (global.Type)
|
|
5054
|
-
// - String types (string<N>)
|
|
5055
|
-
// - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
|
|
5056
|
-
if (
|
|
5057
|
-
typeCtx.qualifiedType() ||
|
|
5058
|
-
typeCtx.scopedType() ||
|
|
5059
|
-
typeCtx.globalType() ||
|
|
5060
|
-
typeCtx.stringType()
|
|
5061
|
-
) {
|
|
5062
|
-
return; // Grammar limitation - these can't use arrayType
|
|
5063
|
-
}
|
|
5064
|
-
|
|
5065
|
-
// C-style array declaration detected - reject with helpful error
|
|
5066
|
-
const baseType = this._extractBaseTypeName(typeCtx);
|
|
5067
|
-
const dimensions = arrayDims
|
|
5068
|
-
.map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
|
|
5069
|
-
.join("");
|
|
5070
|
-
const line = ctx.start?.line ?? 0;
|
|
5071
|
-
const col = ctx.start?.column ?? 0;
|
|
5072
|
-
|
|
5073
|
-
throw new Error(
|
|
5074
|
-
`${line}:${col} C-style array declaration is not allowed. ` +
|
|
5075
|
-
`Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
|
|
5076
|
-
);
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
|
-
/**
|
|
5080
|
-
* Extract base type name from type context for error messages.
|
|
5081
|
-
*/
|
|
5082
|
-
private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
|
|
5083
|
-
if (typeCtx.primitiveType()) {
|
|
5084
|
-
return typeCtx.primitiveType()!.getText();
|
|
5085
|
-
}
|
|
5086
|
-
if (typeCtx.userType()) {
|
|
5087
|
-
return typeCtx.userType()!.getText();
|
|
5088
|
-
}
|
|
5089
|
-
if (typeCtx.arrayType()) {
|
|
5090
|
-
const arrCtx = typeCtx.arrayType()!;
|
|
5091
|
-
if (arrCtx.primitiveType()) {
|
|
5092
|
-
return arrCtx.primitiveType()!.getText();
|
|
5093
|
-
}
|
|
5094
|
-
if (arrCtx.userType()) {
|
|
5095
|
-
return arrCtx.userType()!.getText();
|
|
5096
|
-
}
|
|
5097
|
-
}
|
|
5098
|
-
return typeCtx.getText();
|
|
5099
|
-
}
|
|
5100
|
-
|
|
5101
|
-
/**
|
|
5102
|
-
* Issue #696: Generate variable initializer with validation.
|
|
5103
|
-
*/
|
|
5104
|
-
private _generateVariableInitializer(
|
|
5105
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5106
|
-
typeCtx: Parser.TypeContext,
|
|
5107
|
-
decl: string,
|
|
5108
|
-
isArray: boolean,
|
|
5109
|
-
): string {
|
|
5110
|
-
if (!ctx.expression()) {
|
|
5111
|
-
// ADR-015: Zero initialization for uninitialized variables
|
|
5112
|
-
return `${decl} = ${this.getZeroInitializer(typeCtx, isArray)}`;
|
|
5113
|
-
}
|
|
5114
|
-
|
|
5115
|
-
const typeName = this.getTypeName(typeCtx);
|
|
5116
|
-
const savedExpectedType = CodeGenState.expectedType;
|
|
5117
|
-
CodeGenState.expectedType = typeName;
|
|
5118
|
-
|
|
5119
|
-
// ADR-017: Validate enum type for initialization
|
|
5120
|
-
EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
|
|
5121
|
-
|
|
5122
|
-
// ADR-024: Validate integer literals and type conversions
|
|
5123
|
-
this._validateIntegerInitializer(ctx, typeName);
|
|
5124
|
-
|
|
5125
|
-
const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
|
|
5126
|
-
CodeGenState.expectedType = savedExpectedType;
|
|
5127
|
-
|
|
5128
|
-
return result;
|
|
5129
|
-
}
|
|
5130
|
-
|
|
5131
|
-
/**
|
|
5132
|
-
* Issue #696: Validate integer initializer using helper.
|
|
5133
|
-
*/
|
|
5134
|
-
private _validateIntegerInitializer(
|
|
5135
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5136
|
-
typeName: string,
|
|
5137
|
-
): void {
|
|
5138
|
-
if (!this._isIntegerType(typeName)) {
|
|
5139
|
-
return;
|
|
5140
|
-
}
|
|
5141
|
-
|
|
5142
|
-
const exprText = ctx.expression()!.getText().trim();
|
|
5143
|
-
const line = ctx.start?.line ?? 0;
|
|
5144
|
-
const col = ctx.start?.column ?? 0;
|
|
5145
|
-
const isLiteral = LiteralUtils.parseIntegerLiteral(exprText) !== undefined;
|
|
5146
|
-
|
|
5147
|
-
try {
|
|
5148
|
-
if (isLiteral) {
|
|
5149
|
-
// Direct literal - validate it fits in the target type
|
|
5150
|
-
this._validateLiteralFitsType(exprText, typeName);
|
|
5151
|
-
} else {
|
|
5152
|
-
// Not a literal - check for narrowing/sign conversions
|
|
5153
|
-
const sourceType = this.getExpressionType(ctx.expression()!);
|
|
5154
|
-
this._validateTypeConversion(typeName, sourceType);
|
|
5155
|
-
}
|
|
5156
|
-
} catch (validationError) {
|
|
5157
|
-
const msg =
|
|
5158
|
-
validationError instanceof Error
|
|
5159
|
-
? validationError.message
|
|
5160
|
-
: String(validationError);
|
|
5161
|
-
throw new Error(`${line}:${col} ${msg}`, { cause: validationError });
|
|
5162
|
-
}
|
|
5163
|
-
}
|
|
5164
|
-
|
|
5165
|
-
/**
|
|
5166
|
-
* Issue #696: Handle pending C++ class field assignments.
|
|
5167
|
-
*/
|
|
5168
|
-
private _finalizeCppClassAssignments(
|
|
5169
|
-
_ctx: Parser.VariableDeclarationContext,
|
|
5170
|
-
typeCtx: Parser.TypeContext,
|
|
5171
|
-
name: string,
|
|
5172
|
-
decl: string,
|
|
5173
|
-
): string {
|
|
5174
|
-
if (CodeGenState.pendingCppClassAssignments.length === 0) {
|
|
5175
|
-
return `${decl};`;
|
|
5176
|
-
}
|
|
5177
|
-
|
|
5178
|
-
if (CodeGenState.inFunctionBody) {
|
|
5179
|
-
const assignments = CodeGenState.pendingCppClassAssignments
|
|
5180
|
-
.map((a) => `${name}.${a}`)
|
|
5181
|
-
.join("\n");
|
|
5182
|
-
CodeGenState.pendingCppClassAssignments = [];
|
|
5183
|
-
return `${decl};\n${assignments}`;
|
|
5184
|
-
}
|
|
5185
|
-
|
|
5186
|
-
// At global scope, we can't emit assignment statements.
|
|
5187
|
-
CodeGenState.pendingCppClassAssignments = [];
|
|
5188
|
-
throw new Error(
|
|
5189
|
-
`Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
|
|
5190
|
-
`syntax at global scope. Use constructor syntax or initialize fields separately.`,
|
|
5191
|
-
);
|
|
5192
|
-
}
|
|
5193
|
-
|
|
5194
|
-
/**
|
|
5195
|
-
* Issue #375: Generate C++ constructor-style declaration
|
|
5196
|
-
* Validates that all arguments are const variables.
|
|
5197
|
-
* Example: `Adafruit_MAX31856 thermocouple(pinConst);` -> `Adafruit_MAX31856 thermocouple(pinConst);`
|
|
5198
|
-
*/
|
|
5199
|
-
private _generateConstructorDecl(
|
|
5200
|
-
ctx: Parser.VariableDeclarationContext,
|
|
5201
|
-
argListCtx: Parser.ConstructorArgumentListContext,
|
|
5202
|
-
): string {
|
|
5203
|
-
const type = this.generateType(ctx.type());
|
|
5204
|
-
const name = ctx.IDENTIFIER().getText();
|
|
5205
|
-
const line = ctx.start?.line ?? 0;
|
|
5206
|
-
|
|
5207
|
-
// Collect and validate all arguments
|
|
5208
|
-
const argIdentifiers = argListCtx.IDENTIFIER();
|
|
5209
|
-
const resolvedArgs: string[] = [];
|
|
5210
|
-
|
|
5211
|
-
for (const argNode of argIdentifiers) {
|
|
5212
|
-
const argName = argNode.getText();
|
|
5213
|
-
|
|
5214
|
-
// Check if it exists in type registry
|
|
5215
|
-
const typeInfo = CodeGenState.getVariableTypeInfo(argName);
|
|
5216
|
-
|
|
5217
|
-
// Also check scoped variables if inside a scope
|
|
5218
|
-
let scopedArgName = argName;
|
|
5219
|
-
let scopedTypeInfo = typeInfo;
|
|
5220
|
-
if (!typeInfo && CodeGenState.currentScope) {
|
|
5221
|
-
scopedArgName = `${CodeGenState.currentScope}_${argName}`;
|
|
5222
|
-
scopedTypeInfo = CodeGenState.getVariableTypeInfo(scopedArgName);
|
|
5223
|
-
}
|
|
5224
|
-
|
|
5225
|
-
if (!typeInfo && !scopedTypeInfo) {
|
|
5226
|
-
throw new Error(
|
|
5227
|
-
`Error at line ${line}: Constructor argument '${argName}' is not declared`,
|
|
5228
|
-
);
|
|
5229
|
-
}
|
|
5230
|
-
|
|
5231
|
-
const finalTypeInfo = typeInfo ?? scopedTypeInfo!;
|
|
5232
|
-
const finalArgName = typeInfo ? argName : scopedArgName;
|
|
5233
|
-
|
|
5234
|
-
// Check if it's const
|
|
5235
|
-
if (!finalTypeInfo.isConst) {
|
|
5236
|
-
throw new Error(
|
|
5237
|
-
`Error at line ${line}: Constructor argument '${argName}' must be const. ` +
|
|
5238
|
-
`C++ constructors in C-Next only accept const variables.`,
|
|
5239
|
-
);
|
|
5240
|
-
}
|
|
5241
|
-
|
|
5242
|
-
resolvedArgs.push(finalArgName);
|
|
5243
|
-
}
|
|
5244
|
-
|
|
5245
|
-
// Track the variable in type registry (as an external C++ type)
|
|
5246
|
-
CodeGenState.setVariableTypeInfo(name, {
|
|
5247
|
-
baseType: type,
|
|
5248
|
-
bitWidth: 0, // Unknown for C++ types
|
|
5249
|
-
isArray: false,
|
|
5250
|
-
arrayDimensions: [],
|
|
5251
|
-
isConst: false,
|
|
5252
|
-
isExternalCppType: true,
|
|
5253
|
-
});
|
|
5254
|
-
|
|
5255
|
-
// Track as local variable if inside function body
|
|
5256
|
-
if (CodeGenState.inFunctionBody) {
|
|
5257
|
-
CodeGenState.localVariables.add(name);
|
|
5258
|
-
}
|
|
5259
|
-
|
|
5260
|
-
return `${type} ${name}(${resolvedArgs.join(", ")});`;
|
|
5261
|
-
}
|
|
3852
|
+
// Issue #792: Methods _handleArrayDeclaration, _getArrayTypeDimension, _parseArrayTypeDimension,
|
|
3853
|
+
// _parseFirstArrayDimension, _validateArrayDeclarationSyntax, _extractBaseTypeName,
|
|
3854
|
+
// _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
|
|
3855
|
+
// and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
|
|
5262
3856
|
|
|
5263
3857
|
/**
|
|
5264
3858
|
* Get zero initializer for array types.
|