c-next 0.1.65 → 0.1.67

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 (73) hide show
  1. package/package.json +5 -1
  2. package/src/transpiler/Transpiler.ts +49 -42
  3. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +129 -0
  4. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +27 -3
  5. package/src/transpiler/output/codegen/CodeGenerator.ts +131 -186
  6. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  7. package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
  8. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1087 -0
  9. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
  10. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
  11. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
  12. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
  13. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  14. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  15. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
  16. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
  17. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
  18. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
  19. package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
  20. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
  21. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
  22. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
  23. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
  24. package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
  25. package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
  26. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
  27. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
  28. package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
  29. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
  30. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
  31. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
  32. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
  33. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
  35. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
  36. package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
  37. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
  38. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +618 -12
  39. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
  40. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +1 -1
  41. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
  42. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
  43. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
  44. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  45. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
  46. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
  47. package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
  48. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
  49. package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
  50. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  51. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
  52. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
  53. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
  54. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
  55. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
  56. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
  57. package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
  58. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
  59. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
  60. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
  61. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
  62. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
  63. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
  64. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
  65. package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
  66. package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
  67. package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
  68. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
  69. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
  70. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
  71. package/src/transpiler/{output/codegen → state}/CodeGenState.ts +46 -26
  72. package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +12 -2
  73. package/src/transpiler/output/codegen/assignment/handlers/IHandlerDeps.ts +0 -161
@@ -10,56 +10,22 @@
10
10
  */
11
11
  import AssignmentKind from "../AssignmentKind";
12
12
  import IAssignmentContext from "../IAssignmentContext";
13
- import IHandlerDeps from "./IHandlerDeps";
14
13
  import BitUtils from "../../../../../utils/BitUtils";
15
- import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
16
14
  import TAssignmentHandler from "./TAssignmentHandler";
17
15
  import RegisterUtils from "./RegisterUtils";
18
16
  import AssignmentHandlerUtils from "./AssignmentHandlerUtils";
17
+ import CodeGenState from "../../../../state/CodeGenState";
18
+ import type ICodeGenApi from "../../types/ICodeGenApi";
19
19
 
20
- /**
21
- * Try to generate MMIO-optimized memory access for byte-aligned writes.
22
- * Returns null if optimization not applicable.
23
- */
24
- function tryGenerateMMIO(
25
- fullName: string,
26
- regName: string,
27
- startExpr: ReturnType<IHandlerDeps["tryEvaluateConstant"]>,
28
- widthExpr: ReturnType<IHandlerDeps["tryEvaluateConstant"]>,
29
- value: string,
30
- deps: IHandlerDeps,
31
- ): string | null {
32
- if (
33
- startExpr === undefined ||
34
- widthExpr === undefined ||
35
- startExpr % 8 !== 0 ||
36
- !TypeCheckUtils.isStandardWidth(widthExpr)
37
- ) {
38
- return null;
39
- }
40
-
41
- const baseAddr = deps.symbols.registerBaseAddresses.get(regName);
42
- const memberOffset = deps.symbols.registerMemberOffsets.get(fullName);
43
-
44
- if (baseAddr === undefined || memberOffset === undefined) {
45
- return null;
46
- }
47
-
48
- const byteOffset = startExpr / 8;
49
- const accessType = `uint${widthExpr}_t`;
50
- const totalOffset =
51
- byteOffset === 0 ? memberOffset : `${memberOffset} + ${byteOffset}`;
52
-
53
- return `*((volatile ${accessType}*)(${baseAddr} + ${totalOffset})) = (${value});`;
20
+ /** Get typed generator reference */
21
+ function gen(): ICodeGenApi {
22
+ return CodeGenState.generator as ICodeGenApi;
54
23
  }
55
24
 
56
25
  /**
57
26
  * Handle register single bit: GPIO7.DR_SET[LED_BIT] <- true
58
27
  */
59
- function handleRegisterBit(
60
- ctx: IAssignmentContext,
61
- deps: IHandlerDeps,
62
- ): string {
28
+ function handleRegisterBit(ctx: IAssignmentContext): string {
63
29
  // Issue #707: Use shared validation utility
64
30
  AssignmentHandlerUtils.validateNoCompoundForBitAccess(
65
31
  ctx.isCompound,
@@ -69,12 +35,12 @@ function handleRegisterBit(
69
35
  const { fullName } =
70
36
  AssignmentHandlerUtils.buildRegisterNameWithScopeDetection(
71
37
  ctx.identifiers,
72
- deps.isKnownScope,
38
+ (name) => CodeGenState.isKnownScope(name),
73
39
  );
74
- const accessMod = deps.symbols.registerMemberAccess.get(fullName);
40
+ const accessMod = CodeGenState.symbols!.registerMemberAccess.get(fullName);
75
41
  const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
76
42
 
77
- const bitIndex = deps.generateExpression(ctx.subscripts[0]);
43
+ const bitIndex = gen().generateExpression(ctx.subscripts[0]);
78
44
 
79
45
  if (isWriteOnly) {
80
46
  AssignmentHandlerUtils.validateWriteOnlyValue(
@@ -92,10 +58,7 @@ function handleRegisterBit(
92
58
  /**
93
59
  * Handle register bit range: GPIO7.DR_SET[0, 8] <- value
94
60
  */
95
- function handleRegisterBitRange(
96
- ctx: IAssignmentContext,
97
- deps: IHandlerDeps,
98
- ): string {
61
+ function handleRegisterBitRange(ctx: IAssignmentContext): string {
99
62
  // Issue #707: Use shared validation utility
100
63
  AssignmentHandlerUtils.validateNoCompoundForBitAccess(
101
64
  ctx.isCompound,
@@ -105,14 +68,14 @@ function handleRegisterBitRange(
105
68
  const { fullName, regName } =
106
69
  AssignmentHandlerUtils.buildRegisterNameWithScopeDetection(
107
70
  ctx.identifiers,
108
- deps.isKnownScope,
71
+ (name) => CodeGenState.isKnownScope(name),
109
72
  );
110
- const accessMod = deps.symbols.registerMemberAccess.get(fullName);
73
+ const accessMod = CodeGenState.symbols!.registerMemberAccess.get(fullName);
111
74
  const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
112
75
 
113
- const start = deps.generateExpression(ctx.subscripts[0]);
114
- const width = deps.generateExpression(ctx.subscripts[1]);
115
- const mask = BitUtils.generateMask(width);
76
+ const { start, width, mask } = RegisterUtils.extractBitRangeParams(
77
+ ctx.subscripts,
78
+ );
116
79
 
117
80
  if (isWriteOnly) {
118
81
  AssignmentHandlerUtils.validateWriteOnlyValue(
@@ -123,18 +86,14 @@ function handleRegisterBitRange(
123
86
  );
124
87
 
125
88
  // Try MMIO optimization
126
- const startConst = deps.tryEvaluateConstant(ctx.subscripts[0]);
127
- const widthConst = deps.tryEvaluateConstant(ctx.subscripts[1]);
128
- const mmio = tryGenerateMMIO(
89
+ const mmio = RegisterUtils.tryGenerateMMIO(
129
90
  fullName,
130
91
  regName,
131
- startConst,
132
- widthConst,
92
+ ctx.subscripts,
133
93
  ctx.generatedValue,
134
- deps,
135
94
  );
136
- if (mmio) {
137
- return mmio;
95
+ if (mmio.success) {
96
+ return mmio.statement!;
138
97
  }
139
98
 
140
99
  // Fallback: write shifted value
@@ -158,12 +117,9 @@ function handleRegisterBitRange(
158
117
  /**
159
118
  * Handle scoped register single bit: this.GPIO7.DR_SET[bit] <- true
160
119
  */
161
- function handleScopedRegisterBit(
162
- ctx: IAssignmentContext,
163
- deps: IHandlerDeps,
164
- ): string {
120
+ function handleScopedRegisterBit(ctx: IAssignmentContext): string {
165
121
  // Issue #707: Use shared validation utilities
166
- AssignmentHandlerUtils.validateScopeContext(deps.currentScope);
122
+ AssignmentHandlerUtils.validateScopeContext(CodeGenState.currentScope);
167
123
  AssignmentHandlerUtils.validateNoCompoundForBitAccess(
168
124
  ctx.isCompound,
169
125
  ctx.cnextOp,
@@ -171,14 +127,14 @@ function handleScopedRegisterBit(
171
127
 
172
128
  // Build scoped name: Scope_Register_Member
173
129
  const regName = AssignmentHandlerUtils.buildScopedRegisterName(
174
- deps.currentScope!,
130
+ CodeGenState.currentScope!,
175
131
  ctx.identifiers,
176
132
  );
177
133
 
178
- const accessMod = deps.symbols.registerMemberAccess.get(regName);
134
+ const accessMod = CodeGenState.symbols!.registerMemberAccess.get(regName);
179
135
  const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
180
136
 
181
- const bitIndex = deps.generateExpression(ctx.subscripts[0]);
137
+ const bitIndex = gen().generateExpression(ctx.subscripts[0]);
182
138
 
183
139
  if (isWriteOnly) {
184
140
  AssignmentHandlerUtils.validateWriteOnlyValue(
@@ -196,18 +152,15 @@ function handleScopedRegisterBit(
196
152
  /**
197
153
  * Handle scoped register bit range: this.GPIO7.ICR1[6, 2] <- value
198
154
  */
199
- function handleScopedRegisterBitRange(
200
- ctx: IAssignmentContext,
201
- deps: IHandlerDeps,
202
- ): string {
155
+ function handleScopedRegisterBitRange(ctx: IAssignmentContext): string {
203
156
  // Issue #707: Use shared validation utilities
204
- AssignmentHandlerUtils.validateScopeContext(deps.currentScope);
157
+ AssignmentHandlerUtils.validateScopeContext(CodeGenState.currentScope);
205
158
  AssignmentHandlerUtils.validateNoCompoundForBitAccess(
206
159
  ctx.isCompound,
207
160
  ctx.cnextOp,
208
161
  );
209
162
 
210
- const scopeName = deps.currentScope!;
163
+ const scopeName = CodeGenState.currentScope!;
211
164
  const parts = ctx.identifiers;
212
165
  const regName = AssignmentHandlerUtils.buildScopedRegisterName(
213
166
  scopeName,
@@ -215,12 +168,12 @@ function handleScopedRegisterBitRange(
215
168
  );
216
169
  const scopedRegName = `${scopeName}_${parts[0]}`;
217
170
 
218
- const accessMod = deps.symbols.registerMemberAccess.get(regName);
171
+ const accessMod = CodeGenState.symbols!.registerMemberAccess.get(regName);
219
172
  const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
220
173
 
221
- const start = deps.generateExpression(ctx.subscripts[0]);
222
- const width = deps.generateExpression(ctx.subscripts[1]);
223
- const mask = `((1U << ${width}) - 1)`;
174
+ const { start, width, mask } = RegisterUtils.extractBitRangeParams(
175
+ ctx.subscripts,
176
+ );
224
177
 
225
178
  if (isWriteOnly) {
226
179
  AssignmentHandlerUtils.validateWriteOnlyValue(
@@ -231,25 +184,14 @@ function handleScopedRegisterBitRange(
231
184
  );
232
185
 
233
186
  // Try MMIO optimization
234
- const startConst = deps.tryEvaluateConstant(ctx.subscripts[0]);
235
- const widthConst = deps.tryEvaluateConstant(ctx.subscripts[1]);
236
-
237
- if (
238
- startConst !== undefined &&
239
- widthConst !== undefined &&
240
- startConst % 8 === 0 &&
241
- TypeCheckUtils.isStandardWidth(widthConst)
242
- ) {
243
- const baseAddr = deps.symbols.registerBaseAddresses.get(scopedRegName);
244
- const memberOffset = deps.symbols.registerMemberOffsets.get(regName);
245
-
246
- if (baseAddr !== undefined && memberOffset !== undefined) {
247
- const byteOffset = startConst / 8;
248
- const accessType = `uint${widthConst}_t`;
249
- const totalOffset =
250
- byteOffset === 0 ? memberOffset : `${memberOffset} + ${byteOffset}`;
251
- return `*((volatile ${accessType}*)(${baseAddr} + ${totalOffset})) = (${ctx.generatedValue});`;
252
- }
187
+ const mmio = RegisterUtils.tryGenerateMMIO(
188
+ regName,
189
+ scopedRegName,
190
+ ctx.subscripts,
191
+ ctx.generatedValue,
192
+ );
193
+ if (mmio.success) {
194
+ return mmio.statement!;
253
195
  }
254
196
 
255
197
  return RegisterUtils.generateWriteOnlyBitRange(
@@ -4,11 +4,86 @@
4
4
  *
5
5
  * Extracted from AccessPatternHandlers.ts and RegisterHandlers.ts to reduce duplication.
6
6
  */
7
+ import BitUtils from "../../../../../utils/BitUtils";
8
+ import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
9
+ import CodeGenState from "../../../../state/CodeGenState";
10
+ import type ICodeGenApi from "../../types/ICodeGenApi";
11
+
12
+ /** Get typed generator reference */
13
+ function gen(): ICodeGenApi {
14
+ return CodeGenState.generator as ICodeGenApi;
15
+ }
16
+
17
+ /** Result from extracting bit range expressions */
18
+ interface IBitRangeParams {
19
+ start: string;
20
+ width: string;
21
+ mask: string;
22
+ }
23
+
24
+ /** Result from MMIO optimization attempt */
25
+ interface IOptimizationResult {
26
+ success: boolean;
27
+ statement?: string;
28
+ }
7
29
 
8
30
  /**
9
31
  * Utilities for register access patterns
10
32
  */
11
33
  class RegisterUtils {
34
+ /**
35
+ * Extract start, width, and mask from bit range subscripts.
36
+ * Consolidates the common pattern of getting expressions and generating mask.
37
+ */
38
+ static extractBitRangeParams(
39
+ subscripts: readonly unknown[],
40
+ ): IBitRangeParams {
41
+ const start = gen().generateExpression(subscripts[0]);
42
+ const width = gen().generateExpression(subscripts[1]);
43
+ const mask = BitUtils.generateMask(width);
44
+ return { start, width, mask };
45
+ }
46
+
47
+ /**
48
+ * Try to generate MMIO-optimized memory access for byte-aligned writes.
49
+ * Returns success: true with statement if optimization applicable, false otherwise.
50
+ */
51
+ static tryGenerateMMIO(
52
+ fullName: string,
53
+ regName: string,
54
+ subscripts: readonly unknown[],
55
+ value: string,
56
+ ): IOptimizationResult {
57
+ const startConst = gen().tryEvaluateConstant(subscripts[0]);
58
+ const widthConst = gen().tryEvaluateConstant(subscripts[1]);
59
+
60
+ if (
61
+ startConst === undefined ||
62
+ widthConst === undefined ||
63
+ startConst % 8 !== 0 ||
64
+ !TypeCheckUtils.isStandardWidth(widthConst)
65
+ ) {
66
+ return { success: false };
67
+ }
68
+
69
+ const baseAddr = CodeGenState.symbols!.registerBaseAddresses.get(regName);
70
+ const memberOffset =
71
+ CodeGenState.symbols!.registerMemberOffsets.get(fullName);
72
+
73
+ if (baseAddr === undefined || memberOffset === undefined) {
74
+ return { success: false };
75
+ }
76
+
77
+ const byteOffset = startConst / 8;
78
+ const accessType = `uint${widthConst}_t`;
79
+ const totalOffset =
80
+ byteOffset === 0 ? memberOffset : `${memberOffset} + ${byteOffset}`;
81
+
82
+ return {
83
+ success: true,
84
+ statement: `*((volatile ${accessType}*)(${baseAddr} + ${totalOffset})) = (${value});`,
85
+ };
86
+ }
12
87
  /**
13
88
  * Check if register is write-only based on access modifier.
14
89
  *
@@ -5,7 +5,13 @@
5
5
  * Used when no special handling is needed.
6
6
  */
7
7
  import IAssignmentContext from "../IAssignmentContext";
8
- import IHandlerDeps from "./IHandlerDeps";
8
+ import CodeGenState from "../../../../state/CodeGenState";
9
+ import type ICodeGenApi from "../../types/ICodeGenApi";
10
+
11
+ /** Get typed generator reference */
12
+ function gen(): ICodeGenApi {
13
+ return CodeGenState.generator as ICodeGenApi;
14
+ }
9
15
 
10
16
  /**
11
17
  * Handle simple variable assignment.
@@ -14,11 +20,8 @@ import IHandlerDeps from "./IHandlerDeps";
14
20
  * x <- 5 => x = 5;
15
21
  * counter +<- 1 => counter += 1;
16
22
  */
17
- function handleSimpleAssignment(
18
- ctx: IAssignmentContext,
19
- deps: IHandlerDeps,
20
- ): string {
21
- const target = deps.generateAssignmentTarget(ctx.targetCtx);
23
+ function handleSimpleAssignment(ctx: IAssignmentContext): string {
24
+ const target = gen().generateAssignmentTarget(ctx.targetCtx);
22
25
  return `${target} ${ctx.cOp} ${ctx.generatedValue};`;
23
26
  }
24
27
 
@@ -7,9 +7,16 @@
7
7
  */
8
8
  import AssignmentKind from "../AssignmentKind";
9
9
  import IAssignmentContext from "../IAssignmentContext";
10
- import IHandlerDeps from "./IHandlerDeps";
11
10
  import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
12
11
  import TAssignmentHandler from "./TAssignmentHandler";
12
+ import CodeGenState from "../../../../state/CodeGenState";
13
+ import TTypeInfo from "../../types/TTypeInfo";
14
+ import type ICodeGenApi from "../../types/ICodeGenApi";
15
+
16
+ /** Get typed generator reference */
17
+ function gen(): ICodeGenApi {
18
+ return CodeGenState.generator as ICodeGenApi;
19
+ }
13
20
 
14
21
  /** Maps C operators to clamp helper operation names */
15
22
  const CLAMP_OP_MAP: Record<string, string> = {
@@ -22,30 +29,29 @@ const CLAMP_OP_MAP: Record<string, string> = {
22
29
  * Get typeInfo for assignment target.
23
30
  * Handles simple identifiers, this.member, and global.member patterns.
24
31
  */
25
- function getTargetTypeInfo(
26
- ctx: IAssignmentContext,
27
- deps: IHandlerDeps,
28
- ): { typeInfo: ReturnType<typeof deps.typeRegistry.get> } {
32
+ function getTargetTypeInfo(ctx: IAssignmentContext): {
33
+ typeInfo: TTypeInfo | undefined;
34
+ } {
29
35
  const id = ctx.identifiers[0];
30
36
 
31
37
  // Simple identifier
32
38
  if (ctx.isSimpleIdentifier) {
33
- return { typeInfo: deps.typeRegistry.get(id) };
39
+ return { typeInfo: CodeGenState.typeRegistry.get(id) };
34
40
  }
35
41
 
36
42
  // this.member: lookup using scoped name
37
- if (ctx.isSimpleThisAccess && deps.currentScope) {
38
- const scopedName = `${deps.currentScope}_${id}`;
39
- return { typeInfo: deps.typeRegistry.get(scopedName) };
43
+ if (ctx.isSimpleThisAccess && CodeGenState.currentScope) {
44
+ const scopedName = `${CodeGenState.currentScope}_${id}`;
45
+ return { typeInfo: CodeGenState.typeRegistry.get(scopedName) };
40
46
  }
41
47
 
42
48
  // global.member: lookup using direct name
43
49
  if (ctx.isSimpleGlobalAccess) {
44
- return { typeInfo: deps.typeRegistry.get(id) };
50
+ return { typeInfo: CodeGenState.typeRegistry.get(id) };
45
51
  }
46
52
 
47
53
  // Fallback to direct lookup
48
- return { typeInfo: deps.typeRegistry.get(id) };
54
+ return { typeInfo: CodeGenState.typeRegistry.get(id) };
49
55
  }
50
56
 
51
57
  /**
@@ -54,11 +60,16 @@ function getTargetTypeInfo(
54
60
  * Delegates to CodeGenerator's generateAtomicRMW which uses
55
61
  * LDREX/STREX on supported platforms or PRIMASK otherwise.
56
62
  */
57
- function handleAtomicRMW(ctx: IAssignmentContext, deps: IHandlerDeps): string {
58
- const { typeInfo } = getTargetTypeInfo(ctx, deps);
59
- const target = deps.generateAssignmentTarget(ctx.targetCtx);
63
+ function handleAtomicRMW(ctx: IAssignmentContext): string {
64
+ const { typeInfo } = getTargetTypeInfo(ctx);
65
+ const target = gen().generateAssignmentTarget(ctx.targetCtx);
60
66
 
61
- return deps.generateAtomicRMW(target, ctx.cOp, ctx.generatedValue, typeInfo!);
67
+ return gen().generateAtomicRMW(
68
+ target,
69
+ ctx.cOp,
70
+ ctx.generatedValue,
71
+ typeInfo!,
72
+ );
62
73
  }
63
74
 
64
75
  /**
@@ -67,12 +78,9 @@ function handleAtomicRMW(ctx: IAssignmentContext, deps: IHandlerDeps): string {
67
78
  * Generates calls to cnx_clamp_add_u8, cnx_clamp_sub_u8, etc.
68
79
  * Only applies to integers (floats use native C arithmetic with infinity).
69
80
  */
70
- function handleOverflowClamp(
71
- ctx: IAssignmentContext,
72
- deps: IHandlerDeps,
73
- ): string {
74
- const { typeInfo } = getTargetTypeInfo(ctx, deps);
75
- const target = deps.generateAssignmentTarget(ctx.targetCtx);
81
+ function handleOverflowClamp(ctx: IAssignmentContext): string {
82
+ const { typeInfo } = getTargetTypeInfo(ctx);
83
+ const target = gen().generateAssignmentTarget(ctx.targetCtx);
76
84
 
77
85
  // Floats use native C arithmetic (overflow to infinity)
78
86
  if (TypeCheckUtils.usesNativeArithmetic(typeInfo!.baseType)) {
@@ -82,7 +90,7 @@ function handleOverflowClamp(
82
90
  const helperOp = CLAMP_OP_MAP[ctx.cOp];
83
91
 
84
92
  if (helperOp) {
85
- deps.markClampOpUsed(helperOp, typeInfo!.baseType);
93
+ CodeGenState.markClampOpUsed(helperOp, typeInfo!.baseType);
86
94
  return `${target} = cnx_clamp_${helperOp}_${typeInfo!.baseType}(${target}, ${ctx.generatedValue});`;
87
95
  }
88
96
 
@@ -11,10 +11,16 @@
11
11
  */
12
12
  import AssignmentKind from "../AssignmentKind";
13
13
  import IAssignmentContext from "../IAssignmentContext";
14
- import IHandlerDeps from "./IHandlerDeps";
15
14
  import StringUtils from "../../../../../utils/StringUtils";
16
15
  import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
17
16
  import TAssignmentHandler from "./TAssignmentHandler";
17
+ import CodeGenState from "../../../../state/CodeGenState";
18
+ import type ICodeGenApi from "../../types/ICodeGenApi";
19
+
20
+ /** Get typed generator reference */
21
+ function gen(): ICodeGenApi {
22
+ return CodeGenState.generator as ICodeGenApi;
23
+ }
18
24
 
19
25
  /**
20
26
  * Validate compound operators are not used with strings.
@@ -32,19 +38,16 @@ function validateNotCompound(ctx: IAssignmentContext): void {
32
38
  *
33
39
  * Gets capacity from typeRegistry and generates strncpy with null terminator.
34
40
  */
35
- function handleSimpleStringAssignment(
36
- ctx: IAssignmentContext,
37
- deps: IHandlerDeps,
38
- ): string {
41
+ function handleSimpleStringAssignment(ctx: IAssignmentContext): string {
39
42
  validateNotCompound(ctx);
40
43
 
41
44
  const id = ctx.identifiers[0];
42
- const typeInfo = deps.typeRegistry.get(id);
45
+ const typeInfo = CodeGenState.typeRegistry.get(id);
43
46
  const capacity = typeInfo!.stringCapacity!;
44
47
 
45
- deps.markNeedsString();
48
+ CodeGenState.needsString = true;
46
49
 
47
- const target = deps.generateAssignmentTarget(ctx.targetCtx);
50
+ const target = gen().generateAssignmentTarget(ctx.targetCtx);
48
51
  return StringUtils.copyWithNull(target, ctx.generatedValue, capacity);
49
52
  }
50
53
 
@@ -53,14 +56,10 @@ function handleSimpleStringAssignment(
53
56
  *
54
57
  * Shared helper for struct field string handlers.
55
58
  */
56
- function getStructFieldType(
57
- structName: string,
58
- fieldName: string,
59
- deps: IHandlerDeps,
60
- ): string {
61
- const structTypeInfo = deps.typeRegistry.get(structName);
59
+ function getStructFieldType(structName: string, fieldName: string): string {
60
+ const structTypeInfo = CodeGenState.typeRegistry.get(structName);
62
61
  const structType = structTypeInfo!.baseType;
63
- const structFields = deps.symbols.structFields.get(structType);
62
+ const structFields = CodeGenState.symbols!.structFields.get(structType);
64
63
  return structFields!.get(fieldName)!;
65
64
  }
66
65
 
@@ -69,51 +68,45 @@ function getStructFieldType(
69
68
  *
70
69
  * Shared helper for struct field handlers.
71
70
  */
72
- function getStructType(structName: string, deps: IHandlerDeps): string {
73
- const structTypeInfo = deps.typeRegistry.get(structName);
71
+ function getStructType(structName: string): string {
72
+ const structTypeInfo = CodeGenState.typeRegistry.get(structName);
74
73
  return structTypeInfo!.baseType;
75
74
  }
76
75
 
77
76
  /**
78
77
  * Handle this.member string: this.name <- "value"
79
78
  */
80
- function handleStringThisMember(
81
- ctx: IAssignmentContext,
82
- deps: IHandlerDeps,
83
- ): string {
84
- if (!deps.currentScope) {
79
+ function handleStringThisMember(ctx: IAssignmentContext): string {
80
+ if (!CodeGenState.currentScope) {
85
81
  throw new Error("Error: 'this' can only be used inside a scope");
86
82
  }
87
83
 
88
84
  validateNotCompound(ctx);
89
85
 
90
86
  const memberName = ctx.identifiers[0];
91
- const scopedName = `${deps.currentScope}_${memberName}`;
92
- const typeInfo = deps.typeRegistry.get(scopedName);
87
+ const scopedName = `${CodeGenState.currentScope}_${memberName}`;
88
+ const typeInfo = CodeGenState.typeRegistry.get(scopedName);
93
89
  const capacity = typeInfo!.stringCapacity!;
94
90
 
95
- deps.markNeedsString();
91
+ CodeGenState.needsString = true;
96
92
 
97
- const target = deps.generateAssignmentTarget(ctx.targetCtx);
93
+ const target = gen().generateAssignmentTarget(ctx.targetCtx);
98
94
  return StringUtils.copyWithNull(target, ctx.generatedValue, capacity);
99
95
  }
100
96
 
101
97
  /**
102
98
  * Handle struct.field string: person.name <- "Alice"
103
99
  */
104
- function handleStringStructField(
105
- ctx: IAssignmentContext,
106
- deps: IHandlerDeps,
107
- ): string {
100
+ function handleStringStructField(ctx: IAssignmentContext): string {
108
101
  validateNotCompound(ctx);
109
102
 
110
103
  const structName = ctx.identifiers[0];
111
104
  const fieldName = ctx.identifiers[1];
112
105
 
113
- const fieldType = getStructFieldType(structName, fieldName, deps);
106
+ const fieldType = getStructFieldType(structName, fieldName);
114
107
  const capacity = TypeCheckUtils.getStringCapacity(fieldType)!;
115
108
 
116
- deps.markNeedsString();
109
+ CodeGenState.needsString = true;
117
110
 
118
111
  return StringUtils.copyToStructField(
119
112
  structName,
@@ -126,19 +119,16 @@ function handleStringStructField(
126
119
  /**
127
120
  * Handle string array element: names[0] <- "first"
128
121
  */
129
- function handleStringArrayElement(
130
- ctx: IAssignmentContext,
131
- deps: IHandlerDeps,
132
- ): string {
122
+ function handleStringArrayElement(ctx: IAssignmentContext): string {
133
123
  validateNotCompound(ctx);
134
124
 
135
125
  const name = ctx.identifiers[0];
136
- const typeInfo = deps.typeRegistry.get(name);
126
+ const typeInfo = CodeGenState.typeRegistry.get(name);
137
127
  const capacity = typeInfo!.stringCapacity!;
138
128
 
139
- deps.markNeedsString();
129
+ CodeGenState.needsString = true;
140
130
 
141
- const index = deps.generateExpression(ctx.subscripts[0]);
131
+ const index = gen().generateExpression(ctx.subscripts[0]);
142
132
  return StringUtils.copyToArrayElement(
143
133
  name,
144
134
  index,
@@ -150,27 +140,29 @@ function handleStringArrayElement(
150
140
  /**
151
141
  * Handle struct field string array element: config.items[0] <- "value"
152
142
  */
153
- function handleStringStructArrayElement(
154
- ctx: IAssignmentContext,
155
- deps: IHandlerDeps,
156
- ): string {
143
+ function handleStringStructArrayElement(ctx: IAssignmentContext): string {
157
144
  validateNotCompound(ctx);
158
145
 
159
146
  const structName = ctx.identifiers[0];
160
147
  const fieldName = ctx.identifiers[1];
161
148
 
162
- const structType = getStructType(structName, deps);
163
- const dimensions = deps.symbols.structFieldDimensions
164
- .get(structType)
165
- ?.get(fieldName);
149
+ const structType = getStructType(structName);
150
+ const dimensions =
151
+ CodeGenState.symbols!.structFieldDimensions.get(structType)?.get(fieldName);
152
+
153
+ if (!dimensions || dimensions.length === 0) {
154
+ throw new Error(
155
+ `Error: Cannot determine string capacity for struct field '${structType}.${fieldName}'`,
156
+ );
157
+ }
166
158
 
167
159
  // String arrays: dimensions are [array_size, string_capacity+1]
168
160
  // -1 because we added +1 for null terminator during symbol collection
169
- const capacity = dimensions![dimensions!.length - 1] - 1;
161
+ const capacity = dimensions.at(-1)! - 1;
170
162
 
171
- deps.markNeedsString();
163
+ CodeGenState.needsString = true;
172
164
 
173
- const index = deps.generateExpression(ctx.subscripts[0]);
165
+ const index = gen().generateExpression(ctx.subscripts[0]);
174
166
  return StringUtils.copyToStructFieldArrayElement(
175
167
  structName,
176
168
  fieldName,
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * Type for assignment handler functions (ADR-109).
3
+ *
4
+ * Handlers access state via CodeGenState and CodeGenState.generator
5
+ * instead of receiving deps as a parameter.
3
6
  */
4
7
  import IAssignmentContext from "../IAssignmentContext";
5
- import IHandlerDeps from "./IHandlerDeps";
6
8
 
7
9
  /**
8
10
  * Handler function that generates C code for an assignment kind.
11
+ * Accesses CodeGenState directly for symbol information and
12
+ * CodeGenState.generator for CodeGenerator methods.
9
13
  */
10
- type TAssignmentHandler = (
11
- ctx: IAssignmentContext,
12
- deps: IHandlerDeps,
13
- ) => string;
14
+ type TAssignmentHandler = (ctx: IAssignmentContext) => string;
14
15
 
15
16
  export default TAssignmentHandler;