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.
Files changed (104) hide show
  1. package/README.md +86 -63
  2. package/grammar/CNext.g4 +3 -17
  3. package/package.json +1 -1
  4. package/src/cli/serve/ServeCommand.ts +57 -45
  5. package/src/lib/__tests__/parseCHeader.mocked.test.ts +145 -0
  6. package/src/transpiler/Transpiler.ts +603 -613
  7. package/src/transpiler/__tests__/DualCodePaths.test.ts +5 -1
  8. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -99
  9. package/src/transpiler/__tests__/Transpiler.test.ts +3 -26
  10. package/src/transpiler/data/IncludeTreeWalker.ts +1 -1
  11. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +23 -52
  12. package/src/transpiler/logic/parser/grammar/CNext.interp +1 -3
  13. package/src/transpiler/logic/parser/grammar/CNextListener.ts +0 -22
  14. package/src/transpiler/logic/parser/grammar/CNextParser.ts +665 -1084
  15. package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +0 -14
  16. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +67 -43
  17. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  18. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  19. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  20. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  21. package/src/transpiler/output/codegen/CodeGenerator.ts +1410 -2587
  22. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  23. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  24. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  25. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +2082 -52
  26. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  27. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  28. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  29. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  30. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +227 -66
  31. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +55 -58
  32. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +288 -275
  33. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  34. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +195 -133
  35. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +24 -74
  36. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +3 -0
  37. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +3 -0
  38. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +290 -320
  39. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +42 -0
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +76 -2
  41. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  42. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -1
  43. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  44. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  45. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterGenerator.ts +11 -24
  46. package/src/transpiler/output/codegen/generators/declarationGenerators/RegisterMacroGenerator.ts +64 -0
  47. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +137 -61
  48. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +18 -27
  49. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  50. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  51. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  52. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +5 -1
  53. package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +1 -17
  54. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  55. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +129 -0
  56. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  57. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +40 -44
  58. package/src/transpiler/output/codegen/helpers/AssignmentTargetExtractor.ts +17 -45
  59. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +83 -78
  60. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  61. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  62. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  63. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +10 -3
  64. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  65. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +44 -0
  66. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  67. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +479 -0
  68. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  69. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  70. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  71. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  72. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  73. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  74. package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +1 -0
  75. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  76. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +201 -0
  77. package/src/transpiler/output/codegen/helpers/__tests__/TypeGenerationHelper.test.ts +50 -0
  78. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  79. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  80. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  81. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  82. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  83. package/src/transpiler/output/codegen/types/IArrayAccessDeps.ts +23 -0
  84. package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +26 -0
  85. package/src/transpiler/output/codegen/types/IMemberSeparatorDeps.ts +7 -0
  86. package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +98 -0
  87. package/src/transpiler/output/codegen/utils/ExpressionUnwrapper.ts +22 -22
  88. package/src/transpiler/output/codegen/utils/__tests__/CodegenParserUtils.test.ts +228 -0
  89. package/src/transpiler/types/IFileResult.ts +0 -4
  90. package/src/transpiler/types/IPipelineFile.ts +27 -0
  91. package/src/transpiler/types/IPipelineInput.ts +23 -0
  92. package/src/transpiler/types/TranspilerState.ts +1 -1
  93. package/src/utils/FormatUtils.ts +28 -2
  94. package/src/utils/MapUtils.ts +25 -0
  95. package/src/utils/PostfixAnalysisUtils.ts +48 -0
  96. package/src/utils/__tests__/FormatUtils.test.ts +42 -0
  97. package/src/utils/__tests__/MapUtils.test.ts +85 -0
  98. package/src/utils/constants/OperatorMappings.ts +19 -0
  99. package/src/transpiler/logic/StandaloneContextBuilder.ts +0 -150
  100. package/src/transpiler/logic/__tests__/StandaloneContextBuilder.test.ts +0 -647
  101. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  102. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
  103. package/src/transpiler/types/ITranspileContext.ts +0 -49
  104. package/src/transpiler/types/ITranspileContribution.ts +0 -32
@@ -10,33 +10,21 @@
10
10
  * - Array bounds checking
11
11
  * - Read-only register members
12
12
  * - Callback field assignments
13
+ *
14
+ * Migrated to use CodeGenState instead of constructor DI.
13
15
  */
14
16
 
15
17
  import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
16
18
  import TypeValidator from "../TypeValidator.js";
17
19
  import EnumAssignmentValidator from "./EnumAssignmentValidator.js";
18
- import TTypeInfo from "../types/TTypeInfo.js";
20
+ import CodeGenState from "../CodeGenState.js";
21
+ import TypeCheckUtils from "../../../../utils/TypeCheckUtils.js";
19
22
 
20
23
  /**
21
- * Dependencies required for assignment validation.
24
+ * Callbacks required for assignment validation.
25
+ * These need CodeGenerator context and cannot be replaced with static state.
22
26
  */
23
- interface IAssignmentValidatorDeps {
24
- /** TypeValidator for const and callback validation */
25
- readonly typeValidator: TypeValidator;
26
- /** EnumAssignmentValidator for enum type validation */
27
- readonly enumValidator: EnumAssignmentValidator;
28
- /** Type registry for looking up variable types */
29
- readonly typeRegistry: ReadonlyMap<string, TTypeInfo>;
30
- /** Float shadow tracking state for invalidation */
31
- readonly floatShadowCurrent: Set<string>;
32
- /** Register member access modifiers for read-only checks */
33
- readonly registerMemberAccess: ReadonlyMap<string, string>;
34
- /** Callback field types for nominal typing validation */
35
- readonly callbackFieldTypes: ReadonlyMap<string, string>;
36
- /** Check if a type is a known struct */
37
- isKnownStruct: (typeName: string) => boolean;
38
- /** Check if a type is an integer type */
39
- isIntegerType: (typeName: string) => boolean;
27
+ interface IAssignmentValidatorCallbacks {
40
28
  /** Get the type of an expression */
41
29
  getExpressionType: (ctx: Parser.ExpressionContext) => string | null;
42
30
  /** Try to evaluate a constant expression */
@@ -49,12 +37,6 @@ interface IAssignmentValidatorDeps {
49
37
  * Coordinates all assignment validations.
50
38
  */
51
39
  class AssignmentValidator {
52
- private readonly deps: IAssignmentValidatorDeps;
53
-
54
- constructor(deps: IAssignmentValidatorDeps) {
55
- this.deps = deps;
56
- }
57
-
58
40
  /**
59
41
  * Validate an assignment target.
60
42
  *
@@ -62,87 +44,114 @@ class AssignmentValidator {
62
44
  * @param expression - The expression being assigned
63
45
  * @param isCompound - Whether this is a compound assignment (+<-, -<-, etc.)
64
46
  * @param line - Line number for error messages
47
+ * @param callbacks - Callbacks to CodeGenerator methods
65
48
  */
66
- validate(
49
+ static validate(
67
50
  targetCtx: Parser.AssignmentTargetContext,
68
51
  expression: Parser.ExpressionContext,
69
52
  isCompound: boolean,
70
53
  line: number,
54
+ callbacks: IAssignmentValidatorCallbacks,
71
55
  ): void {
72
- // Case 1: Simple identifier assignment
73
- if (
74
- targetCtx.IDENTIFIER() &&
75
- !targetCtx.memberAccess() &&
76
- !targetCtx.arrayAccess()
77
- ) {
78
- this.validateSimpleIdentifier(
79
- targetCtx.IDENTIFIER()!.getText(),
56
+ const postfixOps = targetCtx.postfixTargetOp();
57
+ const baseId = targetCtx.IDENTIFIER()?.getText();
58
+
59
+ // Case 1: Simple identifier assignment (no postfix ops)
60
+ if (baseId && postfixOps.length === 0) {
61
+ AssignmentValidator.validateSimpleIdentifier(
62
+ baseId,
80
63
  expression,
81
64
  isCompound,
65
+ callbacks,
82
66
  );
83
67
  return;
84
68
  }
85
69
 
86
- // Case 2: Array element assignment
87
- if (targetCtx.arrayAccess()) {
88
- this.validateArrayElement(targetCtx.arrayAccess()!, line);
89
- return;
70
+ // Analyze postfix ops for member/array patterns
71
+ const identifiers: string[] = baseId ? [baseId] : [];
72
+ const subscriptExprs: Parser.ExpressionContext[] = [];
73
+
74
+ for (const op of postfixOps) {
75
+ if (op.IDENTIFIER()) {
76
+ identifiers.push(op.IDENTIFIER()!.getText());
77
+ } else {
78
+ for (const expr of op.expression()) {
79
+ subscriptExprs.push(expr);
80
+ }
81
+ }
90
82
  }
91
83
 
92
- // Case 3: Member access assignment
93
- if (targetCtx.memberAccess()) {
94
- this.validateMemberAccess(targetCtx.memberAccess()!, expression);
84
+ // Case 2: Has subscripts - validate array bounds
85
+ if (subscriptExprs.length > 0 && identifiers.length > 0) {
86
+ AssignmentValidator.validateArrayElement(
87
+ identifiers[0],
88
+ subscriptExprs,
89
+ line,
90
+ callbacks,
91
+ );
92
+ }
93
+
94
+ // Case 3: Has member access - validate member access
95
+ if (identifiers.length >= 2) {
96
+ AssignmentValidator.validateMemberAccess(
97
+ identifiers,
98
+ expression,
99
+ callbacks,
100
+ );
95
101
  }
96
102
  }
97
103
 
98
104
  /**
99
105
  * Validate simple identifier assignment.
100
106
  */
101
- private validateSimpleIdentifier(
107
+ private static validateSimpleIdentifier(
102
108
  id: string,
103
109
  expression: Parser.ExpressionContext,
104
110
  isCompound: boolean,
111
+ callbacks: IAssignmentValidatorCallbacks,
105
112
  ): void {
106
113
  // ADR-013: Validate const assignment
107
- const constError = this.deps.typeValidator.checkConstAssignment(id);
114
+ const constError = TypeValidator.checkConstAssignment(id);
108
115
  if (constError) {
109
116
  throw new Error(constError);
110
117
  }
111
118
 
112
119
  // Invalidate float shadow when variable is assigned directly
113
120
  const shadowName = `__bits_${id}`;
114
- this.deps.floatShadowCurrent.delete(shadowName);
121
+ CodeGenState.floatShadowCurrent.delete(shadowName);
115
122
 
116
- const targetTypeInfo = this.deps.typeRegistry.get(id);
123
+ const targetTypeInfo = CodeGenState.typeRegistry.get(id);
117
124
  if (!targetTypeInfo) {
118
125
  return;
119
126
  }
120
127
 
121
- // ADR-017: Validate enum type assignment
128
+ // ADR-017: Validate enum assignment for enum-typed variable
122
129
  if (targetTypeInfo.isEnum && targetTypeInfo.enumTypeName) {
123
- this.deps.enumValidator.validateEnumAssignment(
130
+ EnumAssignmentValidator.validateEnumAssignment(
124
131
  targetTypeInfo.enumTypeName,
125
132
  expression,
126
133
  );
127
134
  }
128
135
 
129
136
  // ADR-024: Validate integer type conversions
130
- if (this.deps.isIntegerType(targetTypeInfo.baseType)) {
137
+ if (TypeCheckUtils.isInteger(targetTypeInfo.baseType)) {
131
138
  try {
132
- this.deps.typeValidator.validateIntegerAssignment(
139
+ TypeValidator.validateIntegerAssignment(
133
140
  targetTypeInfo.baseType,
134
141
  expression.getText(),
135
- this.deps.getExpressionType(expression),
142
+ callbacks.getExpressionType(expression),
136
143
  isCompound,
137
144
  );
138
145
  } catch (validationError) {
139
- const line = expression.start?.line ?? 0;
146
+ const errorLine = expression.start?.line ?? 0;
140
147
  const col = expression.start?.column ?? 0;
141
148
  const msg =
142
149
  validationError instanceof Error
143
150
  ? validationError.message
144
151
  : String(validationError);
145
- throw new Error(`${line}:${col} ${msg}`, { cause: validationError });
152
+ throw new Error(`${errorLine}:${col} ${msg}`, {
153
+ cause: validationError,
154
+ });
146
155
  }
147
156
  }
148
157
  }
@@ -150,27 +159,27 @@ class AssignmentValidator {
150
159
  /**
151
160
  * Validate array element assignment.
152
161
  */
153
- private validateArrayElement(
154
- arrayAccessCtx: Parser.ArrayAccessContext,
162
+ private static validateArrayElement(
163
+ arrayName: string,
164
+ subscriptExprs: Parser.ExpressionContext[],
155
165
  line: number,
166
+ callbacks: IAssignmentValidatorCallbacks,
156
167
  ): void {
157
- const arrayName = arrayAccessCtx.IDENTIFIER().getText();
158
-
159
168
  // ADR-013: Validate const assignment on array
160
- const constError = this.deps.typeValidator.checkConstAssignment(arrayName);
169
+ const constError = TypeValidator.checkConstAssignment(arrayName);
161
170
  if (constError) {
162
171
  throw new Error(`${constError} (array element)`);
163
172
  }
164
173
 
165
174
  // ADR-036: Compile-time bounds checking
166
- const typeInfo = this.deps.typeRegistry.get(arrayName);
175
+ const typeInfo = CodeGenState.typeRegistry.get(arrayName);
167
176
  if (typeInfo?.isArray && typeInfo.arrayDimensions) {
168
- this.deps.typeValidator.checkArrayBounds(
177
+ TypeValidator.checkArrayBounds(
169
178
  arrayName,
170
179
  typeInfo.arrayDimensions,
171
- arrayAccessCtx.expression(),
180
+ subscriptExprs,
172
181
  line,
173
- this.deps.tryEvaluateConstant,
182
+ callbacks.tryEvaluateConstant,
174
183
  );
175
184
  }
176
185
  }
@@ -178,32 +187,28 @@ class AssignmentValidator {
178
187
  /**
179
188
  * Validate member access assignment.
180
189
  */
181
- private validateMemberAccess(
182
- memberAccessCtx: Parser.MemberAccessContext,
190
+ private static validateMemberAccess(
191
+ identifiers: string[],
183
192
  expression: Parser.ExpressionContext,
193
+ callbacks: IAssignmentValidatorCallbacks,
184
194
  ): void {
185
- const identifiers = memberAccessCtx.IDENTIFIER();
186
- if (identifiers.length === 0) {
195
+ if (identifiers.length < 2) {
187
196
  return;
188
197
  }
189
198
 
190
- const rootName = identifiers[0].getText();
199
+ const rootName = identifiers[0];
200
+ const memberName = identifiers[1];
191
201
 
192
202
  // ADR-013: Validate const assignment on struct root
193
- const constError = this.deps.typeValidator.checkConstAssignment(rootName);
203
+ const constError = TypeValidator.checkConstAssignment(rootName);
194
204
  if (constError) {
195
205
  throw new Error(`${constError} (member access)`);
196
206
  }
197
207
 
198
- if (identifiers.length < 2) {
199
- return;
200
- }
201
-
202
- const memberName = identifiers[1].getText();
203
208
  const fullName = `${rootName}_${memberName}`;
204
209
 
205
210
  // ADR-013: Check for read-only register members
206
- const accessMod = this.deps.registerMemberAccess.get(fullName);
211
+ const accessMod = CodeGenState.symbols?.registerMemberAccess.get(fullName);
207
212
  if (accessMod === "ro") {
208
213
  throw new Error(
209
214
  `cannot assign to read-only register member '${memberName}' ` +
@@ -212,19 +217,19 @@ class AssignmentValidator {
212
217
  }
213
218
 
214
219
  // ADR-029: Validate callback field assignments with nominal typing
215
- const rootTypeInfo = this.deps.typeRegistry.get(rootName);
216
- if (rootTypeInfo && this.deps.isKnownStruct(rootTypeInfo.baseType)) {
220
+ const rootTypeInfo = CodeGenState.typeRegistry.get(rootName);
221
+ if (rootTypeInfo && CodeGenState.isKnownStruct(rootTypeInfo.baseType)) {
217
222
  const structType = rootTypeInfo.baseType;
218
223
  const callbackFieldKey = `${structType}.${memberName}`;
219
224
  const expectedCallbackType =
220
- this.deps.callbackFieldTypes.get(callbackFieldKey);
225
+ CodeGenState.callbackFieldTypes.get(callbackFieldKey);
221
226
 
222
227
  if (expectedCallbackType) {
223
- this.deps.typeValidator.validateCallbackAssignment(
228
+ TypeValidator.validateCallbackAssignment(
224
229
  expectedCallbackType,
225
230
  expression,
226
231
  memberName,
227
- this.deps.isCallbackTypeUsedAsFieldType,
232
+ callbacks.isCallbackTypeUsedAsFieldType,
228
233
  );
229
234
  }
230
235
  }
@@ -5,26 +5,16 @@
5
5
  *
6
6
  * In C mode, struct parameters are passed by pointer (need & for address, * for type).
7
7
  * In C++ mode, struct parameters are passed by reference (no & needed, & for type).
8
+ *
9
+ * Migrated to use CodeGenState instead of constructor DI.
8
10
  */
9
11
 
10
- /**
11
- * Options for C/C++ mode helpers.
12
- */
13
- interface CppModeOptions {
14
- /** Whether we're generating C++ code */
15
- cppMode: boolean;
16
- }
12
+ import CodeGenState from "../CodeGenState";
17
13
 
18
14
  /**
19
- * Helper class for C/C++ mode-specific code generation patterns.
15
+ * Static helper class for C/C++ mode-specific code generation patterns.
20
16
  */
21
17
  class CppModeHelper {
22
- private readonly cppMode: boolean;
23
-
24
- constructor(options: CppModeOptions) {
25
- this.cppMode = options.cppMode;
26
- }
27
-
28
18
  /**
29
19
  * Get address-of expression for struct parameter passing.
30
20
  * C mode: `&expr` (pass pointer to struct)
@@ -33,8 +23,8 @@ class CppModeHelper {
33
23
  * @param expr - The expression to potentially wrap
34
24
  * @returns The expression with address-of operator in C mode
35
25
  */
36
- maybeAddressOf(expr: string): string {
37
- return this.cppMode ? expr : `&${expr}`;
26
+ static maybeAddressOf(expr: string): string {
27
+ return CodeGenState.cppMode ? expr : `&${expr}`;
38
28
  }
39
29
 
40
30
  /**
@@ -45,8 +35,8 @@ class CppModeHelper {
45
35
  * @param expr - The expression to potentially dereference
46
36
  * @returns The expression with dereference in C mode
47
37
  */
48
- maybeDereference(expr: string): string {
49
- return this.cppMode ? expr : `(*${expr})`;
38
+ static maybeDereference(expr: string): string {
39
+ return CodeGenState.cppMode ? expr : `(*${expr})`;
50
40
  }
51
41
 
52
42
  /**
@@ -56,8 +46,8 @@ class CppModeHelper {
56
46
  *
57
47
  * @returns The type modifier character
58
48
  */
59
- refOrPtr(): string {
60
- return this.cppMode ? "&" : "*";
49
+ static refOrPtr(): string {
50
+ return CodeGenState.cppMode ? "&" : "*";
61
51
  }
62
52
 
63
53
  /**
@@ -67,8 +57,8 @@ class CppModeHelper {
67
57
  *
68
58
  * @returns The member access separator
69
59
  */
70
- memberSeparator(): string {
71
- return this.cppMode ? "." : "->";
60
+ static memberSeparator(): string {
61
+ return CodeGenState.cppMode ? "." : "->";
72
62
  }
73
63
 
74
64
  /**
@@ -78,8 +68,8 @@ class CppModeHelper {
78
68
  *
79
69
  * @returns The null pointer literal
80
70
  */
81
- nullLiteral(): string {
82
- return this.cppMode ? "nullptr" : "NULL";
71
+ static nullLiteral(): string {
72
+ return CodeGenState.cppMode ? "nullptr" : "NULL";
83
73
  }
84
74
 
85
75
  /**
@@ -91,8 +81,10 @@ class CppModeHelper {
91
81
  * @param expr - The expression to cast
92
82
  * @returns The cast expression
93
83
  */
94
- cast(type: string, expr: string): string {
95
- return this.cppMode ? `static_cast<${type}>(${expr})` : `(${type})${expr}`;
84
+ static cast(type: string, expr: string): string {
85
+ return CodeGenState.cppMode
86
+ ? `static_cast<${type}>(${expr})`
87
+ : `(${type})${expr}`;
96
88
  }
97
89
 
98
90
  /**
@@ -104,8 +96,8 @@ class CppModeHelper {
104
96
  * @param expr - The expression to cast
105
97
  * @returns The cast expression
106
98
  */
107
- reinterpretCast(type: string, expr: string): string {
108
- return this.cppMode
99
+ static reinterpretCast(type: string, expr: string): string {
100
+ return CodeGenState.cppMode
109
101
  ? `reinterpret_cast<${type}>(${expr})`
110
102
  : `(${type})${expr}`;
111
103
  }
@@ -115,8 +107,8 @@ class CppModeHelper {
115
107
  *
116
108
  * @returns True if generating C++ code
117
109
  */
118
- isCppMode(): boolean {
119
- return this.cppMode;
110
+ static isCppMode(): boolean {
111
+ return CodeGenState.cppMode;
120
112
  }
121
113
  }
122
114
 
@@ -2,6 +2,7 @@
2
2
  * EnumAssignmentValidator - Validates enum type assignments
3
3
  *
4
4
  * Issue #644: Extracted from CodeGenerator to reduce file size.
5
+ * Static class using CodeGenState for all state access.
5
6
  *
6
7
  * Validates that enum assignments are type-safe:
7
8
  * - Cannot assign different enum types to each other
@@ -11,31 +12,15 @@
11
12
  */
12
13
 
13
14
  import * as Parser from "../../../logic/parser/grammar/CNextParser.js";
14
-
15
- /**
16
- * Dependencies required for enum validation.
17
- */
18
- interface IEnumValidatorDeps {
19
- /** Set of known enum type names */
20
- knownEnums: ReadonlySet<string>;
21
- /** Get the current scope name (for this. prefix handling) */
22
- getCurrentScope: () => string | null;
23
- /** Get the enum type of an expression */
24
- getExpressionEnumType: (ctx: Parser.ExpressionContext) => string | null;
25
- /** Check if expression is an integer literal or variable */
26
- isIntegerExpression: (ctx: Parser.ExpressionContext) => boolean;
27
- }
15
+ import CodeGenState from "../CodeGenState.js";
16
+ import EnumTypeResolver from "../resolution/EnumTypeResolver.js";
17
+ import TypeCheckUtils from "../../../../utils/TypeCheckUtils.js";
28
18
 
29
19
  /**
30
20
  * Validates enum type assignments.
21
+ * All methods are static - uses CodeGenState for state access.
31
22
  */
32
23
  class EnumAssignmentValidator {
33
- private readonly deps: IEnumValidatorDeps;
34
-
35
- constructor(deps: IEnumValidatorDeps) {
36
- this.deps = deps;
37
- }
38
-
39
24
  /**
40
25
  * Validate that an expression can be assigned to an enum-typed variable.
41
26
  * Throws an error if the assignment is invalid.
@@ -43,16 +28,16 @@ class EnumAssignmentValidator {
43
28
  * @param typeName - The target enum type name
44
29
  * @param expression - The expression being assigned
45
30
  */
46
- validateEnumAssignment(
31
+ static validateEnumAssignment(
47
32
  typeName: string,
48
33
  expression: Parser.ExpressionContext,
49
34
  ): void {
50
35
  // Only validate if the target type is a known enum
51
- if (!this.deps.knownEnums.has(typeName)) {
36
+ if (!CodeGenState.isKnownEnum(typeName)) {
52
37
  return;
53
38
  }
54
39
 
55
- const valueEnumType = this.deps.getExpressionEnumType(expression);
40
+ const valueEnumType = EnumTypeResolver.resolve(expression);
56
41
 
57
42
  // Check if assigning from a different enum type
58
43
  if (valueEnumType && valueEnumType !== typeName) {
@@ -62,53 +47,74 @@ class EnumAssignmentValidator {
62
47
  }
63
48
 
64
49
  // Check if assigning integer to enum
65
- if (this.deps.isIntegerExpression(expression)) {
50
+ if (EnumAssignmentValidator.isIntegerExpression(expression)) {
66
51
  throw new Error(`Error: Cannot assign integer to ${typeName} enum`);
67
52
  }
68
53
 
69
54
  // Check if assigning a non-enum, non-integer expression
70
55
  if (!valueEnumType) {
71
56
  const exprText = expression.getText();
72
- this.validateNonEnumExpression(exprText, typeName);
57
+ EnumAssignmentValidator.validateNonEnumExpression(exprText, typeName);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Check if an expression is an integer literal or integer-typed variable.
63
+ * Used to detect comparisons between enums and integers.
64
+ */
65
+ static isIntegerExpression(
66
+ ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
67
+ ): boolean {
68
+ const text = ctx.getText();
69
+
70
+ // Check for integer literals
71
+ if (
72
+ /^-?\d+$/.exec(text) ||
73
+ /^0[xX][0-9a-fA-F]+$/.exec(text) ||
74
+ /^0[bB][01]+$/.exec(text)
75
+ ) {
76
+ return true;
77
+ }
78
+
79
+ // Check if it's a variable of primitive integer type
80
+ if (/^[a-zA-Z_]\w*$/.exec(text)) {
81
+ const typeInfo = CodeGenState.typeRegistry.get(text);
82
+ if (
83
+ typeInfo &&
84
+ !typeInfo.isEnum &&
85
+ TypeCheckUtils.isInteger(typeInfo.baseType)
86
+ ) {
87
+ return true;
88
+ }
73
89
  }
90
+
91
+ return false;
74
92
  }
75
93
 
76
94
  /**
77
95
  * Validate a non-enum expression being assigned to an enum type.
78
96
  * Handles various access patterns like this.Enum.MEMBER, global.Enum.MEMBER, etc.
79
97
  */
80
- private validateNonEnumExpression(exprText: string, typeName: string): void {
98
+ private static validateNonEnumExpression(
99
+ exprText: string,
100
+ typeName: string,
101
+ ): void {
81
102
  const parts = exprText.split(".");
82
- const currentScope = this.deps.getCurrentScope();
83
103
 
84
104
  // ADR-016: Handle this.State.MEMBER pattern
85
- if (parts[0] === "this" && currentScope && parts.length >= 3) {
86
- const scopedEnumName = `${currentScope}_${parts[1]}`;
87
- if (scopedEnumName === typeName) {
88
- // Valid this.Enum.Member access
89
- return;
90
- }
91
- throw new Error(
92
- `Error: Cannot assign non-enum value to ${typeName} enum`,
93
- );
105
+ if (parts[0] === "this" && parts.length >= 3) {
106
+ EnumAssignmentValidator.validateThisEnumPattern(parts, typeName);
107
+ return;
94
108
  }
95
109
 
96
- // Issue #478: Handle global.Enum.MEMBER pattern
110
+ // Issue #478: Handle global.Enum.MEMBER or global.struct.field pattern
97
111
  if (parts[0] === "global" && parts.length >= 3) {
98
- // global.ECategory.CAT_A -> ECategory
99
- const globalEnumName = parts[1];
100
- if (globalEnumName === typeName) {
101
- // Valid global.Enum.Member access
102
- return;
103
- }
104
- throw new Error(
105
- `Error: Cannot assign non-enum value to ${typeName} enum`,
106
- );
112
+ EnumAssignmentValidator.validateGlobalEnumPattern(parts, typeName);
113
+ return;
107
114
  }
108
115
 
109
116
  // Allow if it's an enum member access of the correct type
110
117
  if (exprText.startsWith(typeName + ".")) {
111
- // Direct enum member access: EnumType.MEMBER
112
118
  return;
113
119
  }
114
120
 
@@ -124,17 +130,69 @@ class EnumAssignmentValidator {
124
130
  }
125
131
 
126
132
  // parts.length === 2: Could be Enum.Member or variable.field
127
- // Allow if it's a known enum type (even if different - getExpressionEnumType would catch mismatches)
133
+ // Allow if it's a known enum type (even if different - resolve would catch mismatches)
128
134
  if (
129
135
  parts.length === 2 &&
130
- parts[0] !== typeName &&
131
- !this.deps.knownEnums.has(parts[0])
136
+ !EnumAssignmentValidator.isMatchingEnum(parts[0], typeName)
132
137
  ) {
133
138
  throw new Error(
134
139
  `Error: Cannot assign non-enum value to ${typeName} enum`,
135
140
  );
136
141
  }
137
142
  }
143
+
144
+ /**
145
+ * ADR-016: Validate this.Enum.MEMBER pattern inside a scope.
146
+ */
147
+ private static validateThisEnumPattern(
148
+ parts: string[],
149
+ typeName: string,
150
+ ): void {
151
+ if (!CodeGenState.currentScope) {
152
+ throw new Error(
153
+ `Error: Cannot assign non-enum value to ${typeName} enum`,
154
+ );
155
+ }
156
+ const scopedEnumName = `${CodeGenState.currentScope}_${parts[1]}`;
157
+ if (scopedEnumName !== typeName) {
158
+ throw new Error(
159
+ `Error: Cannot assign non-enum value to ${typeName} enum`,
160
+ );
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Issue #478: Validate global.X.Y pattern.
166
+ * If X is a known enum, validates it matches the target type.
167
+ * If X is not an enum (e.g. struct variable), allows through since
168
+ * EnumTypeResolver.resolve() with TypeResolver fallback handles the chain.
169
+ */
170
+ private static validateGlobalEnumPattern(
171
+ parts: string[],
172
+ typeName: string,
173
+ ): void {
174
+ const name = parts[1];
175
+
176
+ // Not an enum (e.g. struct variable like global.input.field) — allow through
177
+ // since EnumTypeResolver.resolve() with TypeResolver fallback handles the chain
178
+ if (!CodeGenState.isKnownEnum(name)) {
179
+ return;
180
+ }
181
+
182
+ // Known enum that doesn't match target type
183
+ if (name !== typeName) {
184
+ throw new Error(
185
+ `Error: Cannot assign non-enum value to ${typeName} enum`,
186
+ );
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Check if an identifier is the target enum type or a known enum type.
192
+ */
193
+ private static isMatchingEnum(identifier: string, typeName: string): boolean {
194
+ return identifier === typeName || CodeGenState.isKnownEnum(identifier);
195
+ }
138
196
  }
139
197
 
140
198
  export default EnumAssignmentValidator;