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.
- package/package.json +5 -1
- package/src/transpiler/Transpiler.ts +49 -42
- package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +129 -0
- package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +27 -3
- package/src/transpiler/output/codegen/CodeGenerator.ts +131 -186
- package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
- package/src/transpiler/output/codegen/TypeValidator.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +1087 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +665 -1315
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -1
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +1 -1
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +1 -1
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +24 -27
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +27 -33
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +39 -42
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +39 -97
- package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +75 -0
- package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +9 -6
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +30 -22
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +42 -50
- package/src/transpiler/output/codegen/assignment/handlers/TAssignmentHandler.ts +6 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +81 -134
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +85 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +82 -124
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +135 -297
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +105 -227
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterUtils.test.ts +214 -1
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +66 -127
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +37 -83
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +162 -0
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +618 -12
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +819 -0
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +337 -0
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +135 -0
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +118 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +426 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +315 -0
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +1 -1
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclarationFormatter.test.ts +333 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +1 -1
- package/src/transpiler/output/codegen/types/ICodeGenApi.ts +57 -0
- package/src/transpiler/output/codegen/types/IParameterInput.ts +58 -0
- package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +51 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +20 -35
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +21 -48
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +0 -64
- package/src/transpiler/{output/codegen → state}/CodeGenState.ts +46 -26
- package/src/transpiler/{output/codegen → state}/__tests__/CodeGenState.test.ts +12 -2
- 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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
38
|
+
(name) => CodeGenState.isKnownScope(name),
|
|
73
39
|
);
|
|
74
|
-
const accessMod =
|
|
40
|
+
const accessMod = CodeGenState.symbols!.registerMemberAccess.get(fullName);
|
|
75
41
|
const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
|
|
76
42
|
|
|
77
|
-
const bitIndex =
|
|
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
|
-
|
|
71
|
+
(name) => CodeGenState.isKnownScope(name),
|
|
109
72
|
);
|
|
110
|
-
const accessMod =
|
|
73
|
+
const accessMod = CodeGenState.symbols!.registerMemberAccess.get(fullName);
|
|
111
74
|
const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
|
|
112
75
|
|
|
113
|
-
const start =
|
|
114
|
-
|
|
115
|
-
|
|
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
|
|
127
|
-
const widthConst = deps.tryEvaluateConstant(ctx.subscripts[1]);
|
|
128
|
-
const mmio = tryGenerateMMIO(
|
|
89
|
+
const mmio = RegisterUtils.tryGenerateMMIO(
|
|
129
90
|
fullName,
|
|
130
91
|
regName,
|
|
131
|
-
|
|
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(
|
|
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
|
-
|
|
130
|
+
CodeGenState.currentScope!,
|
|
175
131
|
ctx.identifiers,
|
|
176
132
|
);
|
|
177
133
|
|
|
178
|
-
const accessMod =
|
|
134
|
+
const accessMod = CodeGenState.symbols!.registerMemberAccess.get(regName);
|
|
179
135
|
const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
|
|
180
136
|
|
|
181
|
-
const bitIndex =
|
|
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(
|
|
157
|
+
AssignmentHandlerUtils.validateScopeContext(CodeGenState.currentScope);
|
|
205
158
|
AssignmentHandlerUtils.validateNoCompoundForBitAccess(
|
|
206
159
|
ctx.isCompound,
|
|
207
160
|
ctx.cnextOp,
|
|
208
161
|
);
|
|
209
162
|
|
|
210
|
-
const scopeName =
|
|
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 =
|
|
171
|
+
const accessMod = CodeGenState.symbols!.registerMemberAccess.get(regName);
|
|
219
172
|
const isWriteOnly = RegisterUtils.isWriteOnlyRegister(accessMod);
|
|
220
173
|
|
|
221
|
-
const start =
|
|
222
|
-
|
|
223
|
-
|
|
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
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
27
|
-
|
|
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:
|
|
39
|
+
return { typeInfo: CodeGenState.typeRegistry.get(id) };
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
// this.member: lookup using scoped name
|
|
37
|
-
if (ctx.isSimpleThisAccess &&
|
|
38
|
-
const scopedName = `${
|
|
39
|
-
return { typeInfo:
|
|
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:
|
|
50
|
+
return { typeInfo: CodeGenState.typeRegistry.get(id) };
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
// Fallback to direct lookup
|
|
48
|
-
return { typeInfo:
|
|
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
|
|
58
|
-
const { typeInfo } = getTargetTypeInfo(ctx
|
|
59
|
-
const target =
|
|
63
|
+
function handleAtomicRMW(ctx: IAssignmentContext): string {
|
|
64
|
+
const { typeInfo } = getTargetTypeInfo(ctx);
|
|
65
|
+
const target = gen().generateAssignmentTarget(ctx.targetCtx);
|
|
60
66
|
|
|
61
|
-
return
|
|
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
|
|
72
|
-
|
|
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
|
-
|
|
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 =
|
|
45
|
+
const typeInfo = CodeGenState.typeRegistry.get(id);
|
|
43
46
|
const capacity = typeInfo!.stringCapacity!;
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
CodeGenState.needsString = true;
|
|
46
49
|
|
|
47
|
-
const target =
|
|
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
|
|
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 =
|
|
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
|
|
73
|
-
const structTypeInfo =
|
|
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
|
-
|
|
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 = `${
|
|
92
|
-
const typeInfo =
|
|
87
|
+
const scopedName = `${CodeGenState.currentScope}_${memberName}`;
|
|
88
|
+
const typeInfo = CodeGenState.typeRegistry.get(scopedName);
|
|
93
89
|
const capacity = typeInfo!.stringCapacity!;
|
|
94
90
|
|
|
95
|
-
|
|
91
|
+
CodeGenState.needsString = true;
|
|
96
92
|
|
|
97
|
-
const target =
|
|
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
|
|
106
|
+
const fieldType = getStructFieldType(structName, fieldName);
|
|
114
107
|
const capacity = TypeCheckUtils.getStringCapacity(fieldType)!;
|
|
115
108
|
|
|
116
|
-
|
|
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 =
|
|
126
|
+
const typeInfo = CodeGenState.typeRegistry.get(name);
|
|
137
127
|
const capacity = typeInfo!.stringCapacity!;
|
|
138
128
|
|
|
139
|
-
|
|
129
|
+
CodeGenState.needsString = true;
|
|
140
130
|
|
|
141
|
-
const index =
|
|
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
|
|
163
|
-
const dimensions =
|
|
164
|
-
.get(structType)
|
|
165
|
-
|
|
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
|
|
161
|
+
const capacity = dimensions.at(-1)! - 1;
|
|
170
162
|
|
|
171
|
-
|
|
163
|
+
CodeGenState.needsString = true;
|
|
172
164
|
|
|
173
|
-
const index =
|
|
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;
|