c-next 0.1.62 → 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 (55) hide show
  1. package/README.md +86 -63
  2. package/package.json +1 -1
  3. package/src/transpiler/Transpiler.ts +3 -2
  4. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
  6. package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
  7. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
  8. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
  9. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
  10. package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +817 -1377
  12. package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
  13. package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
  14. package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +326 -60
  16. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
  18. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
  20. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
  21. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
  22. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
  25. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
  26. package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
  27. package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
  28. package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
  29. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
  30. package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
  31. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
  33. package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
  34. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
  35. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
  36. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
  37. package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
  38. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
  39. package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
  40. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
  41. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
  42. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
  43. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
  44. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
  45. package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
  46. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
  47. package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
  48. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
  49. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
  50. package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
  51. package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
  52. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
  53. package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
  54. package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
  55. package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
@@ -0,0 +1,229 @@
1
+ /**
2
+ * EnumTypeResolver - Handles enum type inference from expressions
3
+ *
4
+ * Extracted from CodeGenerator to reduce complexity.
5
+ * Uses CodeGenState for all state access.
6
+ *
7
+ * ADR-017: Extract enum type from expressions for type-safe comparisons.
8
+ * Handles patterns:
9
+ * - Variable of enum type: `currentState` -> 'State'
10
+ * - Enum member access: `State.IDLE` -> 'State'
11
+ * - Scoped enum member: `Motor.State.IDLE` -> 'Motor_State'
12
+ * - ADR-016: this.State.IDLE -> 'CurrentScope_State'
13
+ * - ADR-016: this.variable -> enum type if variable is of enum type
14
+ * - Function calls returning enum types
15
+ */
16
+
17
+ import * as Parser from "../../../logic/parser/grammar/CNextParser";
18
+ import CodeGenState from "../CodeGenState";
19
+ import TypeResolver from "../TypeResolver";
20
+ import ExpressionUnwrapper from "../utils/ExpressionUnwrapper";
21
+
22
+ /**
23
+ * Resolves enum types from expressions.
24
+ * All methods are static - uses CodeGenState for state access.
25
+ */
26
+ export default class EnumTypeResolver {
27
+ /**
28
+ * Extract enum type from an expression.
29
+ * Returns the enum type name if the expression is an enum value, null otherwise.
30
+ */
31
+ static resolve(
32
+ ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
33
+ ): string | null {
34
+ const text = ctx.getText();
35
+
36
+ // Check if it's a function call returning an enum
37
+ const enumReturnType = this.getFunctionCallEnumType(text);
38
+ if (enumReturnType) {
39
+ return enumReturnType;
40
+ }
41
+
42
+ // Check if it's a simple identifier that's an enum variable
43
+ if (/^[a-zA-Z_]\w*$/.exec(text)) {
44
+ const typeInfo = CodeGenState.typeRegistry.get(text);
45
+ if (typeInfo?.isEnum && typeInfo.enumTypeName) {
46
+ return typeInfo.enumTypeName;
47
+ }
48
+ }
49
+
50
+ // Check member access patterns: EnumType.MEMBER, Scope.EnumType.MEMBER, etc.
51
+ const memberResult = this.getEnumTypeFromMemberAccess(text.split("."));
52
+ if (memberResult) {
53
+ return memberResult;
54
+ }
55
+
56
+ // Fallback: use TypeResolver to resolve the full expression type through
57
+ // struct member chains (e.g. global.config.inputs[0].assignedValue -> EValueId)
58
+ return this.resolveViaTypeResolver(ctx);
59
+ }
60
+
61
+ /**
62
+ * Fallback resolution via TypeResolver for complex expressions.
63
+ * Handles struct member chains like global.struct.field that resolve to enum types.
64
+ */
65
+ private static resolveViaTypeResolver(
66
+ ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
67
+ ): string | null {
68
+ // ExpressionContext has getPostfixExpression, RelationalExpressionContext does not
69
+ if (!("ternaryExpression" in ctx)) {
70
+ return null;
71
+ }
72
+ const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
73
+ if (!postfix) {
74
+ return null;
75
+ }
76
+ const resolvedType = TypeResolver.getPostfixExpressionType(postfix);
77
+ if (resolvedType && CodeGenState.isKnownEnum(resolvedType)) {
78
+ return resolvedType;
79
+ }
80
+ return null;
81
+ }
82
+
83
+ /**
84
+ * Check if parts represent an enum member access and return the enum type.
85
+ */
86
+ private static getEnumTypeFromMemberAccess(parts: string[]): string | null {
87
+ if (parts.length < 2) {
88
+ return null;
89
+ }
90
+
91
+ // ADR-016: Check this.State.IDLE pattern
92
+ const thisEnumType = this.getEnumTypeFromThisEnum(parts);
93
+ if (thisEnumType) return thisEnumType;
94
+
95
+ // Issue #478: Check global.Enum.Member pattern
96
+ const globalEnumType = this.getEnumTypeFromGlobalEnum(parts);
97
+ if (globalEnumType) return globalEnumType;
98
+
99
+ // ADR-016: Check this.variable pattern
100
+ const thisVarType = this.getEnumTypeFromThisVariable(parts);
101
+ if (thisVarType) return thisVarType;
102
+
103
+ // Check simple enum: State.IDLE
104
+ const possibleEnum = parts[0];
105
+ if (CodeGenState.isKnownEnum(possibleEnum)) {
106
+ return possibleEnum;
107
+ }
108
+
109
+ // Check scoped enum: Motor.State.IDLE -> Motor_State
110
+ return this.getEnumTypeFromScopedEnum(parts);
111
+ }
112
+
113
+ /**
114
+ * ADR-016: Check this.State.IDLE pattern (this.Enum.Member inside scope)
115
+ */
116
+ private static getEnumTypeFromThisEnum(parts: string[]): string | null {
117
+ if (parts[0] !== "this" || !CodeGenState.currentScope || parts.length < 3) {
118
+ return null;
119
+ }
120
+ const enumName = parts[1];
121
+ const scopedEnumName = `${CodeGenState.currentScope}_${enumName}`;
122
+ return CodeGenState.isKnownEnum(scopedEnumName) ? scopedEnumName : null;
123
+ }
124
+
125
+ /**
126
+ * Issue #478: Check global.Enum.Member pattern (global.ECategory.CAT_A)
127
+ */
128
+ private static getEnumTypeFromGlobalEnum(parts: string[]): string | null {
129
+ if (parts[0] !== "global" || parts.length < 3) {
130
+ return null;
131
+ }
132
+ const enumName = parts[1];
133
+ return CodeGenState.isKnownEnum(enumName) ? enumName : null;
134
+ }
135
+
136
+ /**
137
+ * ADR-016: Check this.variable pattern (this.varName where varName is enum type)
138
+ */
139
+ private static getEnumTypeFromThisVariable(parts: string[]): string | null {
140
+ if (
141
+ parts[0] !== "this" ||
142
+ !CodeGenState.currentScope ||
143
+ parts.length !== 2
144
+ ) {
145
+ return null;
146
+ }
147
+ const varName = parts[1];
148
+ const scopedVarName = `${CodeGenState.currentScope}_${varName}`;
149
+ const typeInfo = CodeGenState.typeRegistry.get(scopedVarName);
150
+ if (typeInfo?.isEnum && typeInfo.enumTypeName) {
151
+ return typeInfo.enumTypeName;
152
+ }
153
+ return null;
154
+ }
155
+
156
+ /**
157
+ * Check scoped enum: Motor.State.IDLE -> Motor_State
158
+ */
159
+ private static getEnumTypeFromScopedEnum(parts: string[]): string | null {
160
+ if (parts.length < 3) {
161
+ return null;
162
+ }
163
+ const scopeName = parts[0];
164
+ const enumName = parts[1];
165
+ const scopedEnumName = `${scopeName}_${enumName}`;
166
+ return CodeGenState.isKnownEnum(scopedEnumName) ? scopedEnumName : null;
167
+ }
168
+
169
+ /**
170
+ * Check if an expression is a function call returning an enum type.
171
+ * Handles patterns:
172
+ * - func() or func(args) - global function
173
+ * - Scope.method() or Scope.method(args) - scope method from outside
174
+ * - this.method() or this.method(args) - scope method from inside
175
+ * - global.func() or global.func(args) - global function from inside scope
176
+ * - global.Scope.method() or global.Scope.method(args) - scope method from inside another scope
177
+ */
178
+ private static getFunctionCallEnumType(text: string): string | null {
179
+ // Check if this looks like a function call (contains parentheses)
180
+ const parenIndex = text.indexOf("(");
181
+ if (parenIndex === -1) {
182
+ return null;
183
+ }
184
+
185
+ // Extract the function reference (everything before the opening paren)
186
+ const funcRef = text.substring(0, parenIndex);
187
+ const parts = funcRef.split(".");
188
+
189
+ let fullFuncName: string | null = null;
190
+
191
+ if (parts.length === 1) {
192
+ // Simple function call: func()
193
+ fullFuncName = parts[0];
194
+ } else if (parts.length === 2) {
195
+ if (parts[0] === "this" && CodeGenState.currentScope) {
196
+ // this.method() -> Scope_method
197
+ fullFuncName = `${CodeGenState.currentScope}_${parts[1]}`;
198
+ } else if (parts[0] === "global") {
199
+ // global.func() -> func
200
+ fullFuncName = parts[1];
201
+ } else if (CodeGenState.isKnownScope(parts[0])) {
202
+ // Scope.method() -> Scope_method
203
+ fullFuncName = `${parts[0]}_${parts[1]}`;
204
+ }
205
+ } else if (parts.length === 3) {
206
+ if (parts[0] === "global" && CodeGenState.isKnownScope(parts[1])) {
207
+ // global.Scope.method() -> Scope_method
208
+ fullFuncName = `${parts[1]}_${parts[2]}`;
209
+ }
210
+ }
211
+
212
+ if (!fullFuncName) {
213
+ return null;
214
+ }
215
+
216
+ // Look up the function's return type
217
+ const returnType = CodeGenState.getFunctionReturnType(fullFuncName);
218
+ if (!returnType) {
219
+ return null;
220
+ }
221
+
222
+ // Check if the return type is an enum
223
+ if (CodeGenState.isKnownEnum(returnType)) {
224
+ return returnType;
225
+ }
226
+
227
+ return null;
228
+ }
229
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * ScopeResolver - Handles scope visibility and access validation
3
+ *
4
+ * Extracted from CodeGenerator to reduce complexity.
5
+ * Uses CodeGenState for all state access.
6
+ *
7
+ * ADR-016: Validates cross-scope member access visibility rules.
8
+ * Issue #165: Enforces that:
9
+ * - Cannot reference own scope by name (must use this. prefix)
10
+ * - Cannot access private members from outside the scope
11
+ * - Exception: global.Scope.member is allowed for explicit qualification
12
+ */
13
+
14
+ import CodeGenState from "../CodeGenState";
15
+
16
+ /**
17
+ * Resolves scope visibility and validates cross-scope access.
18
+ * All methods are static - uses CodeGenState for state access.
19
+ */
20
+ export default class ScopeResolver {
21
+ /**
22
+ * Validate cross-scope visibility for member access.
23
+ * Throws an error if the access violates visibility rules.
24
+ *
25
+ * @param scopeName - The scope being accessed
26
+ * @param memberName - The member being accessed
27
+ * @param isGlobalAccess - Whether this is a global.Scope.member access
28
+ */
29
+ static validateCrossScopeVisibility(
30
+ scopeName: string,
31
+ memberName: string,
32
+ isGlobalAccess: boolean = false,
33
+ ): void {
34
+ // Error if referencing own scope by name (must use this. prefix)
35
+ // Exception: global.Scope.member is allowed for explicit qualification
36
+ if (!isGlobalAccess && CodeGenState.currentScope === scopeName) {
37
+ throw new Error(
38
+ `Error: Cannot reference own scope '${scopeName}' by name. ` +
39
+ `Use 'this.${memberName}' instead of '${scopeName}.${memberName}'`,
40
+ );
41
+ }
42
+
43
+ // Check private member access (skip for own scope - we can access our own privates)
44
+ const isOwnScope = CodeGenState.currentScope === scopeName;
45
+ if (!isOwnScope) {
46
+ const visibility = CodeGenState.symbols?.scopeMemberVisibility
47
+ .get(scopeName)
48
+ ?.get(memberName);
49
+ if (visibility === "private") {
50
+ const context = CodeGenState.currentScope
51
+ ? `from scope '${CodeGenState.currentScope}'`
52
+ : "from outside the scope";
53
+ throw new Error(
54
+ `Cannot access private member '${memberName}' of scope '${scopeName}' ${context}. ` +
55
+ `Only public members are accessible outside their scope.`,
56
+ );
57
+ }
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * SizeofResolver - Handles sizeof expression generation
3
+ *
4
+ * Extracted from CodeGenerator to reduce complexity.
5
+ * Uses CodeGenState for all state access.
6
+ *
7
+ * ADR-023: sizeof expression handling with safety checks:
8
+ * - E0601: sizeof on array parameter is error (returns pointer size)
9
+ * - E0602: Side effects in sizeof are error (MISRA C:2012 Rule 13.6)
10
+ */
11
+
12
+ import * as Parser from "../../../logic/parser/grammar/CNextParser";
13
+ import CodeGenState from "../CodeGenState";
14
+ import ExpressionUnwrapper from "../utils/ExpressionUnwrapper";
15
+
16
+ /**
17
+ * Callbacks for operations that require CodeGenerator context.
18
+ * These are the minimal dependencies that can't be replaced with CodeGenState.
19
+ */
20
+ interface ISizeofCallbacks {
21
+ generateType: (ctx: Parser.TypeContext) => string;
22
+ generateExpression: (ctx: Parser.ExpressionContext) => string;
23
+ hasSideEffects: (ctx: Parser.ExpressionContext) => boolean;
24
+ }
25
+
26
+ /**
27
+ * Resolves sizeof expressions to C code.
28
+ */
29
+ export default class SizeofResolver {
30
+ /**
31
+ * Generate sizeof expression.
32
+ * sizeof(type) -> sizeof(c_type)
33
+ * sizeof(variable) -> sizeof(variable)
34
+ */
35
+ static generate(
36
+ ctx: Parser.SizeofExpressionContext,
37
+ callbacks: ISizeofCallbacks,
38
+ ): string {
39
+ // Check if it's sizeof(type) or sizeof(expression)
40
+ // Note: Due to grammar ambiguity, sizeof(variable) may parse as sizeof(type)
41
+ // when the variable name matches userType (just an identifier)
42
+ if (ctx.type()) {
43
+ return this.sizeofType(ctx.type()!, callbacks);
44
+ }
45
+ return this.sizeofExpression(ctx.expression()!, callbacks);
46
+ }
47
+
48
+ /**
49
+ * Handle sizeof(type) - may actually be sizeof(variable) due to grammar ambiguity
50
+ */
51
+ private static sizeofType(
52
+ typeCtx: Parser.TypeContext,
53
+ callbacks: ISizeofCallbacks,
54
+ ): string {
55
+ // qualifiedType matches IDENTIFIER.IDENTIFIER, could be struct.member
56
+ if (typeCtx.qualifiedType()) {
57
+ const result = this.sizeofQualifiedType(typeCtx.qualifiedType()!);
58
+ if (result) return result;
59
+ // Fall through to generateType for actual type references (Scope.Type)
60
+ }
61
+
62
+ // userType is just IDENTIFIER, could be a variable reference
63
+ if (typeCtx.userType()) {
64
+ return this.sizeofUserType(typeCtx.getText());
65
+ }
66
+
67
+ // It's a primitive or other type - generate normally
68
+ return `sizeof(${callbacks.generateType(typeCtx)})`;
69
+ }
70
+
71
+ /**
72
+ * Handle sizeof(qualified.type) - may be struct.member access
73
+ * Returns null if this is actually a type reference (Scope.Type)
74
+ */
75
+ private static sizeofQualifiedType(
76
+ qualifiedCtx: Parser.QualifiedTypeContext,
77
+ ): string | null {
78
+ const identifiers = qualifiedCtx.IDENTIFIER();
79
+ const firstName = identifiers[0].getText();
80
+ const memberName = identifiers[1].getText();
81
+
82
+ // Check if first identifier is a local variable (struct instance)
83
+ if (CodeGenState.localVariables.has(firstName)) {
84
+ return `sizeof(${firstName}.${memberName})`;
85
+ }
86
+
87
+ // Check if first identifier is a parameter (struct parameter)
88
+ const paramInfo = CodeGenState.currentParameters.get(firstName);
89
+ if (paramInfo) {
90
+ const sep = paramInfo.isStruct ? "->" : ".";
91
+ return `sizeof(${firstName}${sep}${memberName})`;
92
+ }
93
+
94
+ // Check if first identifier is a global variable
95
+ // If not a scope or enum, it's likely a global struct variable
96
+ if (
97
+ !CodeGenState.isKnownScope(firstName) &&
98
+ !CodeGenState.isKnownEnum(firstName)
99
+ ) {
100
+ return `sizeof(${firstName}.${memberName})`;
101
+ }
102
+
103
+ // It's an actual type reference (Scope.Type), return null to fall through
104
+ return null;
105
+ }
106
+
107
+ /**
108
+ * Handle sizeof(identifier) - could be variable or type name
109
+ */
110
+ private static sizeofUserType(varName: string): string {
111
+ // Check if it's a known parameter
112
+ const paramInfo = CodeGenState.currentParameters.get(varName);
113
+ if (paramInfo) {
114
+ return this.sizeofParameter(varName, paramInfo);
115
+ }
116
+
117
+ // Check if it's a known local variable, struct type, or enum type
118
+ // For all these cases, generate sizeof(name) directly
119
+ // Unknown identifiers are also treated as variables for safety
120
+ return `sizeof(${varName})`;
121
+ }
122
+
123
+ /**
124
+ * Handle sizeof on a parameter - validates and generates appropriate code
125
+ */
126
+ private static sizeofParameter(
127
+ varName: string,
128
+ paramInfo: { isArray?: boolean; isCallback?: boolean; isStruct?: boolean },
129
+ ): string {
130
+ // E0601: Array parameters decay to pointers
131
+ if (paramInfo.isArray) {
132
+ this.throwArrayParamSizeofError(varName);
133
+ }
134
+ // For pass-by-reference parameters (non-array, non-callback, non-struct),
135
+ // use pointer dereference
136
+ if (!paramInfo.isCallback && !paramInfo.isStruct) {
137
+ return `sizeof(*${varName})`;
138
+ }
139
+ return `sizeof(${varName})`;
140
+ }
141
+
142
+ /**
143
+ * Throw E0601 error for sizeof on array parameter
144
+ */
145
+ private static throwArrayParamSizeofError(varName: string): never {
146
+ throw new Error(
147
+ `Error[E0601]: sizeof() on array parameter '${varName}' returns pointer size. ` +
148
+ `Use ${varName}.length for element count or sizeof(elementType) * ${varName}.length for bytes`,
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Handle sizeof(expression) with validation
154
+ */
155
+ private static sizeofExpression(
156
+ expr: Parser.ExpressionContext,
157
+ callbacks: ISizeofCallbacks,
158
+ ): string {
159
+ // E0601: Check if expression is an array parameter
160
+ const varName = ExpressionUnwrapper.getSimpleIdentifier(expr);
161
+ if (varName) {
162
+ const paramInfo = CodeGenState.currentParameters.get(varName);
163
+ if (paramInfo?.isArray) {
164
+ this.throwArrayParamSizeofError(varName);
165
+ }
166
+ }
167
+
168
+ // E0602: Check for side effects
169
+ if (callbacks.hasSideEffects(expr)) {
170
+ throw new Error(
171
+ `Error[E0602]: sizeof() operand must not have side effects (MISRA C:2012 Rule 13.6)`,
172
+ );
173
+ }
174
+
175
+ return `sizeof(${callbacks.generateExpression(expr)})`;
176
+ }
177
+ }