c-next 0.1.61 → 0.1.63
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/README.md +86 -63
- package/grammar/CNext.g4 +3 -17
- package/package.json +1 -1
- package/src/cli/serve/ServeCommand.ts +57 -45
- package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
- package/src/transpiler/Transpiler.ts +603 -613
- package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
- package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
- package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
- package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
- package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
- package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
- package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
- package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +1410 -2587
- package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
- package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
- package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +2082 -52
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +227 -66
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
- package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
- package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
- package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
- package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
- package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
- package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterGenerator.ts +11 -24
- package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
- package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +5 -1
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
- package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
- package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
- package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
- package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +10 -3
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
- package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +1 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
- package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
- package/src/transpiler/output/codegen/types/IArrayAccessDeps.ts +23 -0
- package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
- package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
- package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
- package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
- package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
- package/src/transpiler/types/IFileResult.ts +0 -4
- package/src/transpiler/types/IPipelineFile.ts +27 -0
- package/src/transpiler/types/IPipelineInput.ts +23 -0
- package/src/transpiler/types/TranspilerState.ts +1 -1
- package/src/utils/FormatUtils.ts +28 -2
- package/src/utils/MapUtils.ts +25 -0
- package/src/utils/PostfixAnalysisUtils.ts +48 -0
- package/src/utils/__tests__/FormatUtils.test.ts +42 -0
- package/src/utils/__tests__/MapUtils.test.ts +85 -0
- package/src/utils/constants/OperatorMappings.ts +19 -0
- package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
- package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
- package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
- package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
- package/src/transpiler/types/ITranspileContext.ts +0 -49
- package/src/transpiler/types/ITranspileContribution.ts +0 -32
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper utilities for generating array access code.
|
|
3
|
+
* Extracted from CodeGenerator to improve testability.
|
|
4
|
+
*/
|
|
5
|
+
import IArrayAccessInfo from "../types/IArrayAccessInfo";
|
|
6
|
+
import IArrayAccessDeps from "../types/IArrayAccessDeps";
|
|
7
|
+
import BitRangeHelper from "./BitRangeHelper";
|
|
8
|
+
import CodeGenErrors from "./CodeGenErrors";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Helper class for array access code generation.
|
|
12
|
+
* Works with an intermediate representation (IArrayAccessInfo)
|
|
13
|
+
* instead of ANTLR parser contexts for testability.
|
|
14
|
+
*/
|
|
15
|
+
class ArrayAccessHelper {
|
|
16
|
+
/**
|
|
17
|
+
* Generate the complete array access expression.
|
|
18
|
+
* Routes to single-index or bit-range based on accessType.
|
|
19
|
+
*/
|
|
20
|
+
static generate(info: IArrayAccessInfo, deps: IArrayAccessDeps): string {
|
|
21
|
+
if (info.accessType === "single-index") {
|
|
22
|
+
return ArrayAccessHelper.generateSingleIndex(info);
|
|
23
|
+
}
|
|
24
|
+
return ArrayAccessHelper.generateBitRange(info, deps);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate single-index access: array[i]
|
|
29
|
+
* Validates that bitmap types don't use bracket notation.
|
|
30
|
+
*/
|
|
31
|
+
static generateSingleIndex(info: IArrayAccessInfo): string {
|
|
32
|
+
ArrayAccessHelper.validateNotBitmap(info);
|
|
33
|
+
return `${info.resolvedName}[${info.indexExpr}]`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Validate bitmap access is not using bracket notation.
|
|
38
|
+
* Bitmaps must use named field access (e.g., flags.FIELD_NAME).
|
|
39
|
+
* @throws Error if attempting bracket indexing on a bitmap type
|
|
40
|
+
*/
|
|
41
|
+
static validateNotBitmap(info: IArrayAccessInfo): void {
|
|
42
|
+
if (info.typeInfo?.isBitmap && info.typeInfo.bitmapTypeName) {
|
|
43
|
+
throw CodeGenErrors.bitmapBracketIndexing(
|
|
44
|
+
info.line,
|
|
45
|
+
info.typeInfo.bitmapTypeName,
|
|
46
|
+
info.rawName,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generate bit range access: value[start, width]
|
|
53
|
+
* Handles both integer and float types.
|
|
54
|
+
*/
|
|
55
|
+
static generateBitRange(
|
|
56
|
+
info: IArrayAccessInfo,
|
|
57
|
+
deps: IArrayAccessDeps,
|
|
58
|
+
): string {
|
|
59
|
+
if (ArrayAccessHelper.isFloatBitRange(info.typeInfo)) {
|
|
60
|
+
return ArrayAccessHelper.generateFloatBitRange(info, deps);
|
|
61
|
+
}
|
|
62
|
+
return ArrayAccessHelper.generateIntegerBitRange(info, deps);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Determine if this is a float bit range (needs shadow variable).
|
|
67
|
+
*/
|
|
68
|
+
static isFloatBitRange(typeInfo: { baseType?: string } | undefined): boolean {
|
|
69
|
+
return typeInfo?.baseType === "f32" || typeInfo?.baseType === "f64";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Generate float bit range read with shadow variable.
|
|
74
|
+
* Uses memcpy pattern to safely reinterpret float bits.
|
|
75
|
+
*/
|
|
76
|
+
static generateFloatBitRange(
|
|
77
|
+
info: IArrayAccessInfo,
|
|
78
|
+
deps: IArrayAccessDeps,
|
|
79
|
+
): string {
|
|
80
|
+
if (!deps.isInFunctionBody()) {
|
|
81
|
+
throw CodeGenErrors.floatBitIndexingAtGlobalScope(
|
|
82
|
+
info.rawName,
|
|
83
|
+
info.startExpr ?? "0",
|
|
84
|
+
info.widthExpr ?? "0",
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
deps.requireInclude("string");
|
|
89
|
+
deps.requireInclude("float_static_assert");
|
|
90
|
+
|
|
91
|
+
const isF64 = info.typeInfo?.baseType === "f64";
|
|
92
|
+
const shadowType = BitRangeHelper.getShadowType(
|
|
93
|
+
info.typeInfo?.baseType ?? "f32",
|
|
94
|
+
);
|
|
95
|
+
const shadowName = BitRangeHelper.getShadowVarName(info.rawName);
|
|
96
|
+
const mask = deps.generateBitMask(info.widthExpr ?? "0", isF64);
|
|
97
|
+
|
|
98
|
+
// Register shadow variable if not already declared
|
|
99
|
+
deps.registerFloatShadow(shadowName, shadowType);
|
|
100
|
+
|
|
101
|
+
const shadowIsCurrent = deps.isShadowCurrent(shadowName);
|
|
102
|
+
deps.markShadowCurrent(shadowName);
|
|
103
|
+
|
|
104
|
+
return BitRangeHelper.buildFloatBitReadExpr({
|
|
105
|
+
shadowName,
|
|
106
|
+
varName: info.resolvedName,
|
|
107
|
+
start: info.startExpr ?? "0",
|
|
108
|
+
mask,
|
|
109
|
+
shadowIsCurrent,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Generate integer bit range read: ((value >> start) & mask)
|
|
115
|
+
*/
|
|
116
|
+
static generateIntegerBitRange(
|
|
117
|
+
info: IArrayAccessInfo,
|
|
118
|
+
deps: IArrayAccessDeps,
|
|
119
|
+
): string {
|
|
120
|
+
const mask = deps.generateBitMask(info.widthExpr ?? "0");
|
|
121
|
+
return BitRangeHelper.buildIntegerBitReadExpr({
|
|
122
|
+
varName: info.resolvedName,
|
|
123
|
+
start: info.startExpr ?? "0",
|
|
124
|
+
mask,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default ArrayAccessHelper;
|
|
@@ -7,18 +7,12 @@
|
|
|
7
7
|
* - Array initializers with size inference: u8 data[] <- [1, 2, 3]
|
|
8
8
|
* - Fill-all syntax: u8 data[10] <- [0*]
|
|
9
9
|
* - Array size validation
|
|
10
|
+
*
|
|
11
|
+
* Migrated to use CodeGenState instead of constructor DI.
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Array initialization tracking state.
|
|
17
|
-
*/
|
|
18
|
-
interface IArrayInitState {
|
|
19
|
-
lastArrayInitCount: number;
|
|
20
|
-
lastArrayFillValue: string | undefined;
|
|
21
|
-
}
|
|
15
|
+
import CodeGenState from "../CodeGenState.js";
|
|
22
16
|
|
|
23
17
|
/**
|
|
24
18
|
* Result from processing array initialization.
|
|
@@ -33,18 +27,10 @@ interface IArrayInitResult {
|
|
|
33
27
|
}
|
|
34
28
|
|
|
35
29
|
/**
|
|
36
|
-
*
|
|
30
|
+
* Callbacks required for array initialization.
|
|
31
|
+
* These need CodeGenerator context and cannot be replaced with static state.
|
|
37
32
|
*/
|
|
38
|
-
interface
|
|
39
|
-
/** Type registry for updating inferred dimensions */
|
|
40
|
-
typeRegistry: Map<string, TTypeInfo>;
|
|
41
|
-
/** Local arrays set for tracking */
|
|
42
|
-
localArrays: Set<string>;
|
|
43
|
-
/** Array initialization tracking state */
|
|
44
|
-
arrayInitState: IArrayInitState;
|
|
45
|
-
/** Get/set expected type context */
|
|
46
|
-
getExpectedType: () => string | null;
|
|
47
|
-
setExpectedType: (type: string | null) => void;
|
|
33
|
+
interface IArrayInitCallbacks {
|
|
48
34
|
/** Generate expression code */
|
|
49
35
|
generateExpression: (ctx: Parser.ExpressionContext) => string;
|
|
50
36
|
/** Get type name from type context */
|
|
@@ -57,12 +43,6 @@ interface IArrayInitHelperDeps {
|
|
|
57
43
|
* Handles array initialization with size inference and fill-all syntax.
|
|
58
44
|
*/
|
|
59
45
|
class ArrayInitHelper {
|
|
60
|
-
private readonly deps: IArrayInitHelperDeps;
|
|
61
|
-
|
|
62
|
-
constructor(deps: IArrayInitHelperDeps) {
|
|
63
|
-
this.deps = deps;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
46
|
/**
|
|
67
47
|
* Process array initialization expression.
|
|
68
48
|
* Returns null if not an array initializer pattern.
|
|
@@ -73,33 +53,46 @@ class ArrayInitHelper {
|
|
|
73
53
|
* @param arrayDims - Array dimension contexts
|
|
74
54
|
* @param hasEmptyArrayDim - Whether any dimension is empty (for inference)
|
|
75
55
|
* @param declaredSize - First dimension size if explicit, null otherwise
|
|
56
|
+
* @param callbacks - Callbacks to CodeGenerator methods
|
|
76
57
|
*/
|
|
77
|
-
processArrayInit(
|
|
58
|
+
static processArrayInit(
|
|
78
59
|
name: string,
|
|
79
60
|
typeCtx: Parser.TypeContext,
|
|
80
61
|
expression: Parser.ExpressionContext,
|
|
81
62
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
82
63
|
hasEmptyArrayDim: boolean,
|
|
83
64
|
declaredSize: number | null,
|
|
65
|
+
callbacks: IArrayInitCallbacks,
|
|
84
66
|
): IArrayInitResult | null {
|
|
85
67
|
// Reset and generate initializer
|
|
86
|
-
|
|
87
|
-
|
|
68
|
+
CodeGenState.lastArrayInitCount = 0;
|
|
69
|
+
CodeGenState.lastArrayFillValue = undefined;
|
|
88
70
|
|
|
89
|
-
const initValue =
|
|
71
|
+
const initValue = ArrayInitHelper._generateArrayInitValue(
|
|
72
|
+
typeCtx,
|
|
73
|
+
expression,
|
|
74
|
+
callbacks,
|
|
75
|
+
);
|
|
90
76
|
|
|
91
77
|
// Check if it was an array initializer
|
|
92
|
-
if (!
|
|
78
|
+
if (!ArrayInitHelper._isArrayInitializer()) {
|
|
93
79
|
return null;
|
|
94
80
|
}
|
|
95
81
|
|
|
96
|
-
|
|
82
|
+
CodeGenState.localArrays.add(name);
|
|
97
83
|
|
|
98
84
|
const dimensionSuffix = hasEmptyArrayDim
|
|
99
|
-
?
|
|
100
|
-
:
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
? ArrayInitHelper._processSizeInference(name)
|
|
86
|
+
: ArrayInitHelper._processExplicitSize(
|
|
87
|
+
arrayDims,
|
|
88
|
+
declaredSize,
|
|
89
|
+
callbacks,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const finalInitValue = ArrayInitHelper._expandFillAllSyntax(
|
|
93
|
+
initValue,
|
|
94
|
+
declaredSize,
|
|
95
|
+
);
|
|
103
96
|
|
|
104
97
|
return { isArrayInit: true, dimensionSuffix, initValue: finalInitValue };
|
|
105
98
|
}
|
|
@@ -107,66 +100,66 @@ class ArrayInitHelper {
|
|
|
107
100
|
/**
|
|
108
101
|
* Generate the array initializer value with proper expected type
|
|
109
102
|
*/
|
|
110
|
-
private _generateArrayInitValue(
|
|
103
|
+
private static _generateArrayInitValue(
|
|
111
104
|
typeCtx: Parser.TypeContext,
|
|
112
105
|
expression: Parser.ExpressionContext,
|
|
106
|
+
callbacks: IArrayInitCallbacks,
|
|
113
107
|
): string {
|
|
114
|
-
const typeName =
|
|
115
|
-
const savedExpectedType =
|
|
116
|
-
|
|
117
|
-
const initValue =
|
|
118
|
-
|
|
108
|
+
const typeName = callbacks.getTypeName(typeCtx);
|
|
109
|
+
const savedExpectedType = CodeGenState.expectedType;
|
|
110
|
+
CodeGenState.expectedType = typeName;
|
|
111
|
+
const initValue = callbacks.generateExpression(expression);
|
|
112
|
+
CodeGenState.expectedType = savedExpectedType;
|
|
119
113
|
return initValue;
|
|
120
114
|
}
|
|
121
115
|
|
|
122
116
|
/**
|
|
123
117
|
* Check if the last expression was an array initializer
|
|
124
118
|
*/
|
|
125
|
-
private _isArrayInitializer(): boolean {
|
|
119
|
+
private static _isArrayInitializer(): boolean {
|
|
126
120
|
return (
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
CodeGenState.lastArrayInitCount > 0 ||
|
|
122
|
+
CodeGenState.lastArrayFillValue !== undefined
|
|
129
123
|
);
|
|
130
124
|
}
|
|
131
125
|
|
|
132
126
|
/**
|
|
133
127
|
* Process size inference for empty array dimension (u8 data[] <- [1, 2, 3])
|
|
134
128
|
*/
|
|
135
|
-
private _processSizeInference(name: string): string {
|
|
136
|
-
if (
|
|
129
|
+
private static _processSizeInference(name: string): string {
|
|
130
|
+
if (CodeGenState.lastArrayFillValue !== undefined) {
|
|
137
131
|
throw new Error(
|
|
138
|
-
`Error: Fill-all syntax [${
|
|
132
|
+
`Error: Fill-all syntax [${CodeGenState.lastArrayFillValue}*] requires explicit array size`,
|
|
139
133
|
);
|
|
140
134
|
}
|
|
141
135
|
|
|
142
136
|
// Update type registry with inferred size for .length support
|
|
143
|
-
const existingType =
|
|
137
|
+
const existingType = CodeGenState.typeRegistry.get(name);
|
|
144
138
|
if (existingType) {
|
|
145
|
-
existingType.arrayDimensions = [
|
|
146
|
-
this.deps.arrayInitState.lastArrayInitCount,
|
|
147
|
-
];
|
|
139
|
+
existingType.arrayDimensions = [CodeGenState.lastArrayInitCount];
|
|
148
140
|
}
|
|
149
141
|
|
|
150
|
-
return `[${
|
|
142
|
+
return `[${CodeGenState.lastArrayInitCount}]`;
|
|
151
143
|
}
|
|
152
144
|
|
|
153
145
|
/**
|
|
154
146
|
* Process explicit array size with validation
|
|
155
147
|
*/
|
|
156
|
-
private _processExplicitSize(
|
|
148
|
+
private static _processExplicitSize(
|
|
157
149
|
arrayDims: Parser.ArrayDimensionContext[],
|
|
158
150
|
declaredSize: number | null,
|
|
151
|
+
callbacks: IArrayInitCallbacks,
|
|
159
152
|
): string {
|
|
160
|
-
const dimensionSuffix =
|
|
153
|
+
const dimensionSuffix = callbacks.generateArrayDimensions(arrayDims);
|
|
161
154
|
|
|
162
155
|
// Validate size matches if not using fill-all
|
|
163
156
|
if (
|
|
164
157
|
declaredSize !== null &&
|
|
165
|
-
|
|
166
|
-
|
|
158
|
+
CodeGenState.lastArrayFillValue === undefined &&
|
|
159
|
+
CodeGenState.lastArrayInitCount !== declaredSize
|
|
167
160
|
) {
|
|
168
161
|
throw new Error(
|
|
169
|
-
`Error: Array size mismatch - declared [${declaredSize}] but got ${
|
|
162
|
+
`Error: Array size mismatch - declared [${declaredSize}] but got ${CodeGenState.lastArrayInitCount} elements`,
|
|
170
163
|
);
|
|
171
164
|
}
|
|
172
165
|
|
|
@@ -176,18 +169,18 @@ class ArrayInitHelper {
|
|
|
176
169
|
/**
|
|
177
170
|
* Expand fill-all syntax (e.g., [0*] with size 5 -> {0, 0, 0, 0, 0})
|
|
178
171
|
*/
|
|
179
|
-
private _expandFillAllSyntax(
|
|
172
|
+
private static _expandFillAllSyntax(
|
|
180
173
|
initValue: string,
|
|
181
174
|
declaredSize: number | null,
|
|
182
175
|
): string {
|
|
183
176
|
if (
|
|
184
|
-
|
|
177
|
+
CodeGenState.lastArrayFillValue === undefined ||
|
|
185
178
|
declaredSize === null
|
|
186
179
|
) {
|
|
187
180
|
return initValue;
|
|
188
181
|
}
|
|
189
182
|
|
|
190
|
-
const fillVal =
|
|
183
|
+
const fillVal = CodeGenState.lastArrayFillValue;
|
|
191
184
|
// C handles {0} correctly, no need to expand
|
|
192
185
|
if (fillVal === "0") {
|
|
193
186
|
return initValue;
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Sets up expectedType and assignmentContext for expression generation,
|
|
7
7
|
* enabling type-aware resolution of unqualified enum members and overflow behavior.
|
|
8
|
+
*
|
|
9
|
+
* Migrated to use CodeGenState instead of constructor DI.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
|
|
11
|
-
import TTypeInfo from "../types/TTypeInfo.js";
|
|
12
13
|
import TOverflowBehavior from "../types/TOverflowBehavior.js";
|
|
14
|
+
import analyzePostfixOps from "../../../../utils/PostfixAnalysisUtils.js";
|
|
15
|
+
import CodeGenState from "../CodeGenState.js";
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* Result of resolving expected type for an assignment target.
|
|
@@ -30,58 +33,51 @@ interface IAssignmentContext {
|
|
|
30
33
|
overflowBehavior: TOverflowBehavior;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
/**
|
|
34
|
-
* Dependencies required for expected type resolution.
|
|
35
|
-
*/
|
|
36
|
-
interface IExpectedTypeResolverDeps {
|
|
37
|
-
/** Type registry for looking up variable types */
|
|
38
|
-
readonly typeRegistry: ReadonlyMap<string, TTypeInfo>;
|
|
39
|
-
/** Struct field types: structName -> (fieldName -> fieldType) */
|
|
40
|
-
readonly structFields: ReadonlyMap<string, ReadonlyMap<string, string>>;
|
|
41
|
-
/** Check if a type is a known struct */
|
|
42
|
-
isKnownStruct: (typeName: string) => boolean;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
36
|
/**
|
|
46
37
|
* Resolves expected type for assignment targets.
|
|
47
38
|
*/
|
|
48
39
|
class AssignmentExpectedTypeResolver {
|
|
49
|
-
private readonly deps: IExpectedTypeResolverDeps;
|
|
50
|
-
|
|
51
|
-
constructor(deps: IExpectedTypeResolverDeps) {
|
|
52
|
-
this.deps = deps;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
40
|
/**
|
|
56
41
|
* Resolve expected type for an assignment target.
|
|
57
42
|
*
|
|
58
43
|
* @param targetCtx - The assignment target context
|
|
59
44
|
* @returns The resolved expected type and assignment context
|
|
60
45
|
*/
|
|
61
|
-
resolve(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
|
|
46
|
+
static resolve(
|
|
47
|
+
targetCtx: Parser.AssignmentTargetContext,
|
|
48
|
+
): IExpectedTypeResult {
|
|
49
|
+
const postfixOps = targetCtx.postfixTargetOp();
|
|
50
|
+
const baseId = targetCtx.IDENTIFIER()?.getText();
|
|
51
|
+
|
|
52
|
+
// Case 1: Simple identifier (x <- value) - no postfix ops
|
|
53
|
+
if (baseId && postfixOps.length === 0) {
|
|
54
|
+
return AssignmentExpectedTypeResolver.resolveForSimpleIdentifier(baseId);
|
|
69
55
|
}
|
|
70
56
|
|
|
71
|
-
// Case 2:
|
|
72
|
-
if (
|
|
73
|
-
|
|
57
|
+
// Case 2: Has member access - extract identifiers from postfix chain
|
|
58
|
+
if (baseId && postfixOps.length > 0) {
|
|
59
|
+
const { identifiers, hasSubscript } = analyzePostfixOps(
|
|
60
|
+
baseId,
|
|
61
|
+
postfixOps,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// If we have member access (multiple identifiers), resolve for member chain
|
|
65
|
+
if (identifiers.length >= 2 && !hasSubscript) {
|
|
66
|
+
return AssignmentExpectedTypeResolver.resolveForMemberChain(
|
|
67
|
+
identifiers,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
74
70
|
}
|
|
75
71
|
|
|
76
|
-
// Case 3: Array access - no expected type resolution
|
|
72
|
+
// Case 3: Array access or complex patterns - no expected type resolution
|
|
77
73
|
return { expectedType: null, assignmentContext: null };
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
/**
|
|
81
77
|
* Resolve expected type for a simple identifier target.
|
|
82
78
|
*/
|
|
83
|
-
private resolveForSimpleIdentifier(id: string): IExpectedTypeResult {
|
|
84
|
-
const typeInfo =
|
|
79
|
+
private static resolveForSimpleIdentifier(id: string): IExpectedTypeResult {
|
|
80
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
85
81
|
if (!typeInfo) {
|
|
86
82
|
return { expectedType: null, assignmentContext: null };
|
|
87
83
|
}
|
|
@@ -97,24 +93,23 @@ class AssignmentExpectedTypeResolver {
|
|
|
97
93
|
}
|
|
98
94
|
|
|
99
95
|
/**
|
|
100
|
-
* Resolve expected type for a member access
|
|
96
|
+
* Resolve expected type for a member access chain.
|
|
101
97
|
* Walks the chain of struct types to find the final field's type.
|
|
102
98
|
*
|
|
103
99
|
* Issue #452: Enables type-aware resolution of unqualified enum members
|
|
104
100
|
* for nested access (e.g., config.nested.field).
|
|
105
101
|
*/
|
|
106
|
-
private
|
|
107
|
-
|
|
102
|
+
private static resolveForMemberChain(
|
|
103
|
+
identifiers: string[],
|
|
108
104
|
): IExpectedTypeResult {
|
|
109
|
-
const identifiers = memberAccessCtx.IDENTIFIER();
|
|
110
105
|
if (identifiers.length < 2) {
|
|
111
106
|
return { expectedType: null, assignmentContext: null };
|
|
112
107
|
}
|
|
113
108
|
|
|
114
|
-
const rootName = identifiers[0]
|
|
115
|
-
const rootTypeInfo =
|
|
109
|
+
const rootName = identifiers[0];
|
|
110
|
+
const rootTypeInfo = CodeGenState.typeRegistry.get(rootName);
|
|
116
111
|
|
|
117
|
-
if (!rootTypeInfo || !
|
|
112
|
+
if (!rootTypeInfo || !CodeGenState.isKnownStruct(rootTypeInfo.baseType)) {
|
|
118
113
|
return { expectedType: null, assignmentContext: null };
|
|
119
114
|
}
|
|
120
115
|
|
|
@@ -122,19 +117,20 @@ class AssignmentExpectedTypeResolver {
|
|
|
122
117
|
|
|
123
118
|
// Walk through each member in the chain to find the final field's type
|
|
124
119
|
for (let i = 1; i < identifiers.length && currentStructType; i++) {
|
|
125
|
-
const memberName = identifiers[i]
|
|
126
|
-
const structFieldTypes =
|
|
120
|
+
const memberName = identifiers[i];
|
|
121
|
+
const structFieldTypes: ReadonlyMap<string, string> | undefined =
|
|
122
|
+
CodeGenState.symbols?.structFields.get(currentStructType);
|
|
127
123
|
|
|
128
124
|
if (!structFieldTypes?.has(memberName)) {
|
|
129
125
|
break;
|
|
130
126
|
}
|
|
131
127
|
|
|
132
|
-
const memberType = structFieldTypes.get(memberName)!;
|
|
128
|
+
const memberType: string = structFieldTypes.get(memberName)!;
|
|
133
129
|
|
|
134
130
|
if (i === identifiers.length - 1) {
|
|
135
131
|
// Last field in chain - this is the assignment target's type
|
|
136
132
|
return { expectedType: memberType, assignmentContext: null };
|
|
137
|
-
} else if (
|
|
133
|
+
} else if (CodeGenState.isKnownStruct(memberType)) {
|
|
138
134
|
// Intermediate field - continue walking if it's a struct
|
|
139
135
|
currentStructType = memberType;
|
|
140
136
|
} else {
|
|
@@ -16,6 +16,7 @@ interface IAssignmentTargetResult {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Extracts base identifier from various assignment target patterns.
|
|
19
|
+
* With unified grammar, all patterns use IDENTIFIER postfixTargetOp*.
|
|
19
20
|
*/
|
|
20
21
|
class AssignmentTargetExtractor {
|
|
21
22
|
/**
|
|
@@ -33,53 +34,24 @@ class AssignmentTargetExtractor {
|
|
|
33
34
|
return { baseIdentifier: null, hasSingleIndexSubscript: false };
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
// All patterns have base IDENTIFIER
|
|
38
|
+
const baseIdentifier = target.IDENTIFIER()?.getText() ?? null;
|
|
39
|
+
|
|
40
|
+
// Check postfixTargetOp for subscripts
|
|
41
|
+
const postfixOps = target.postfixTargetOp();
|
|
42
|
+
let hasSingleIndexSubscript = false;
|
|
43
|
+
|
|
44
|
+
for (const op of postfixOps) {
|
|
45
|
+
const exprs = op.expression();
|
|
46
|
+
if (exprs.length === 1) {
|
|
47
|
+
// Single-index subscript (array access)
|
|
48
|
+
hasSingleIndexSubscript = true;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
// Two-index subscript (bit extraction) doesn't set the flag
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
if (target.memberAccess()) {
|
|
46
|
-
return this.extractFromMemberAccess(target.memberAccess()!);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Array access: x[i] <- value
|
|
50
|
-
if (target.arrayAccess()) {
|
|
51
|
-
return this.extractFromArrayAccess(target.arrayAccess()!);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return { baseIdentifier: null, hasSingleIndexSubscript: false };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Extract from member access pattern.
|
|
59
|
-
*/
|
|
60
|
-
private static extractFromMemberAccess(
|
|
61
|
-
memberAccess: Parser.MemberAccessContext,
|
|
62
|
-
): IAssignmentTargetResult {
|
|
63
|
-
const identifiers = memberAccess.IDENTIFIER();
|
|
64
|
-
return {
|
|
65
|
-
baseIdentifier: identifiers.length > 0 ? identifiers[0].getText() : null,
|
|
66
|
-
hasSingleIndexSubscript: false,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Extract from array access pattern.
|
|
72
|
-
* Single-index subscript (x[i]) is array access.
|
|
73
|
-
* Two-index subscript (x[0, 8]) is bit extraction.
|
|
74
|
-
*/
|
|
75
|
-
private static extractFromArrayAccess(
|
|
76
|
-
arrayAccess: Parser.ArrayAccessContext,
|
|
77
|
-
): IAssignmentTargetResult {
|
|
78
|
-
const isSingleIndex = arrayAccess.expression().length === 1;
|
|
79
|
-
return {
|
|
80
|
-
baseIdentifier: arrayAccess.IDENTIFIER()?.getText() ?? null,
|
|
81
|
-
hasSingleIndexSubscript: isSingleIndex,
|
|
82
|
-
};
|
|
54
|
+
return { baseIdentifier, hasSingleIndexSubscript };
|
|
83
55
|
}
|
|
84
56
|
}
|
|
85
57
|
|