c-next 0.2.4 → 0.2.6
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/dist/index.js +561 -78
- package/dist/index.js.map +3 -3
- package/package.json +3 -1
- package/src/transpiler/Transpiler.ts +1 -1
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +194 -8
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +140 -0
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +41 -0
- package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +11 -5
- package/src/transpiler/output/codegen/CodeGenerator.ts +195 -17
- package/src/transpiler/output/codegen/TypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +129 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +30 -5
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +4 -4
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +4 -4
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +8 -8
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +5 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +4 -4
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +8 -1
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +15 -3
- package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +5 -0
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +63 -10
- package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +28 -6
- package/src/transpiler/output/codegen/helpers/ParameterDereferenceResolver.ts +12 -0
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +30 -2
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +15 -7
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +8 -1
- package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +220 -0
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +11 -0
- package/src/transpiler/output/codegen/helpers/VariableModifierBuilder.ts +16 -1
- package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +5 -5
- package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +48 -36
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +37 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +63 -0
- package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +209 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableModifierBuilder.test.ts +34 -2
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
- package/src/transpiler/output/codegen/types/IParameterInput.ts +13 -0
- package/src/transpiler/output/codegen/types/ISeparatorContext.ts +7 -0
- package/src/transpiler/output/codegen/types/TParameterInfo.ts +12 -0
- package/src/transpiler/output/codegen/types/TTypeInfo.ts +1 -0
- package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +1 -1
- package/src/transpiler/state/CodeGenState.ts +21 -2
- package/src/utils/BitUtils.ts +17 -13
- package/src/{transpiler/output/codegen/utils → utils}/ExpressionUnwrapper.ts +1 -1
- package/src/utils/__tests__/BitUtils.test.ts +56 -56
- package/src/{transpiler/output/codegen/utils → utils}/__tests__/ExpressionUnwrapper.test.ts +2 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for TypedefParamParser
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import TypedefParamParser from "../TypedefParamParser";
|
|
7
|
+
|
|
8
|
+
describe("TypedefParamParser", () => {
|
|
9
|
+
describe("parse", () => {
|
|
10
|
+
it("should parse simple callback with pointer params", () => {
|
|
11
|
+
const result = TypedefParamParser.parse(
|
|
12
|
+
"void (*)(widget_t *, const rect_t *, uint8_t *)",
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
expect(result).not.toBeNull();
|
|
16
|
+
expect(result!.returnType).toBe("void");
|
|
17
|
+
expect(result!.params).toHaveLength(3);
|
|
18
|
+
|
|
19
|
+
expect(result!.params[0].isPointer).toBe(true);
|
|
20
|
+
expect(result!.params[0].isConst).toBe(false);
|
|
21
|
+
expect(result!.params[0].baseType).toBe("widget_t");
|
|
22
|
+
|
|
23
|
+
expect(result!.params[1].isPointer).toBe(true);
|
|
24
|
+
expect(result!.params[1].isConst).toBe(true);
|
|
25
|
+
expect(result!.params[1].baseType).toBe("rect_t");
|
|
26
|
+
|
|
27
|
+
expect(result!.params[2].isPointer).toBe(true);
|
|
28
|
+
expect(result!.params[2].isConst).toBe(false);
|
|
29
|
+
expect(result!.params[2].baseType).toBe("uint8_t");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should parse callback without spaces (C grammar format)", () => {
|
|
33
|
+
// This is the actual format from CResolver - getText() may strip spaces
|
|
34
|
+
const result = TypedefParamParser.parse(
|
|
35
|
+
"void (*)(widget_t*,const rect_t*,uint8_t*)",
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(result).not.toBeNull();
|
|
39
|
+
expect(result!.returnType).toBe("void");
|
|
40
|
+
expect(result!.params).toHaveLength(3);
|
|
41
|
+
|
|
42
|
+
expect(result!.params[0].isPointer).toBe(true);
|
|
43
|
+
expect(result!.params[0].isConst).toBe(false);
|
|
44
|
+
expect(result!.params[0].baseType).toBe("widget_t");
|
|
45
|
+
|
|
46
|
+
expect(result!.params[1].isPointer).toBe(true);
|
|
47
|
+
expect(result!.params[1].isConst).toBe(true);
|
|
48
|
+
expect(result!.params[1].baseType).toBe("rect_t");
|
|
49
|
+
|
|
50
|
+
expect(result!.params[2].isPointer).toBe(true);
|
|
51
|
+
expect(result!.params[2].isConst).toBe(false);
|
|
52
|
+
expect(result!.params[2].baseType).toBe("uint8_t");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should parse callback with value params", () => {
|
|
56
|
+
const result = TypedefParamParser.parse("void (*)(Point p)");
|
|
57
|
+
|
|
58
|
+
expect(result).not.toBeNull();
|
|
59
|
+
expect(result!.returnType).toBe("void");
|
|
60
|
+
expect(result!.params).toHaveLength(1);
|
|
61
|
+
|
|
62
|
+
expect(result!.params[0].isPointer).toBe(false);
|
|
63
|
+
expect(result!.params[0].isConst).toBe(false);
|
|
64
|
+
expect(result!.params[0].baseType).toBe("Point");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should parse callback with no params", () => {
|
|
68
|
+
const result = TypedefParamParser.parse("void (*)(void)");
|
|
69
|
+
|
|
70
|
+
expect(result).not.toBeNull();
|
|
71
|
+
expect(result!.returnType).toBe("void");
|
|
72
|
+
expect(result!.params).toHaveLength(0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should parse callback with primitive return type", () => {
|
|
76
|
+
const result = TypedefParamParser.parse("int (*)(int x, int y)");
|
|
77
|
+
|
|
78
|
+
expect(result).not.toBeNull();
|
|
79
|
+
expect(result!.returnType).toBe("int");
|
|
80
|
+
expect(result!.params).toHaveLength(2);
|
|
81
|
+
|
|
82
|
+
expect(result!.params[0].isPointer).toBe(false);
|
|
83
|
+
expect(result!.params[0].baseType).toBe("int");
|
|
84
|
+
|
|
85
|
+
expect(result!.params[1].isPointer).toBe(false);
|
|
86
|
+
expect(result!.params[1].baseType).toBe("int");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should return null for invalid typedef", () => {
|
|
90
|
+
expect(TypedefParamParser.parse("not a typedef")).toBeNull();
|
|
91
|
+
expect(TypedefParamParser.parse("void foo()")).toBeNull();
|
|
92
|
+
expect(TypedefParamParser.parse("")).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should handle mixed pointer and value params", () => {
|
|
96
|
+
const result = TypedefParamParser.parse(
|
|
97
|
+
"void (*)(Point* p, int count, Rect r)",
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(result).not.toBeNull();
|
|
101
|
+
expect(result!.params).toHaveLength(3);
|
|
102
|
+
|
|
103
|
+
expect(result!.params[0].isPointer).toBe(true);
|
|
104
|
+
expect(result!.params[0].baseType).toBe("Point");
|
|
105
|
+
|
|
106
|
+
expect(result!.params[1].isPointer).toBe(false);
|
|
107
|
+
expect(result!.params[1].baseType).toBe("int");
|
|
108
|
+
|
|
109
|
+
expect(result!.params[2].isPointer).toBe(false);
|
|
110
|
+
expect(result!.params[2].baseType).toBe("Rect");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should parse callback with nested function pointer param", () => {
|
|
114
|
+
// Nested function pointer: void (*)(void (*)(int))
|
|
115
|
+
const result = TypedefParamParser.parse("void (*)(void (*)(int))");
|
|
116
|
+
|
|
117
|
+
expect(result).not.toBeNull();
|
|
118
|
+
expect(result!.returnType).toBe("void");
|
|
119
|
+
expect(result!.params).toHaveLength(1);
|
|
120
|
+
|
|
121
|
+
// The param is itself a function pointer
|
|
122
|
+
expect(result!.params[0].type).toBe("void (*)(int)");
|
|
123
|
+
expect(result!.params[0].isPointer).toBe(true); // Function pointers are pointers
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should parse callback with deeply nested function pointer", () => {
|
|
127
|
+
// Two levels of nesting: void (*)(void (*)(void (*)(int)))
|
|
128
|
+
const result = TypedefParamParser.parse(
|
|
129
|
+
"void (*)(void (*)(void (*)(int)))",
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(result).not.toBeNull();
|
|
133
|
+
expect(result!.returnType).toBe("void");
|
|
134
|
+
expect(result!.params).toHaveLength(1);
|
|
135
|
+
expect(result!.params[0].type).toBe("void (*)(void (*)(int))");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should parse callback with mixed nested and regular params", () => {
|
|
139
|
+
// Mix of nested function pointer and regular params
|
|
140
|
+
const result = TypedefParamParser.parse(
|
|
141
|
+
"void (*)(int x, void (*)(int), char* str)",
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(result).not.toBeNull();
|
|
145
|
+
expect(result!.returnType).toBe("void");
|
|
146
|
+
expect(result!.params).toHaveLength(3);
|
|
147
|
+
|
|
148
|
+
expect(result!.params[0].baseType).toBe("int");
|
|
149
|
+
expect(result!.params[0].isPointer).toBe(false);
|
|
150
|
+
|
|
151
|
+
expect(result!.params[1].type).toBe("void (*)(int)");
|
|
152
|
+
expect(result!.params[1].isPointer).toBe(true);
|
|
153
|
+
|
|
154
|
+
expect(result!.params[2].baseType).toBe("char");
|
|
155
|
+
expect(result!.params[2].isPointer).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("shouldBePointer", () => {
|
|
160
|
+
it("should return true for pointer params", () => {
|
|
161
|
+
const typedef = "void (*)(widget_t *, uint8_t *)";
|
|
162
|
+
|
|
163
|
+
expect(TypedefParamParser.shouldBePointer(typedef, 0)).toBe(true);
|
|
164
|
+
expect(TypedefParamParser.shouldBePointer(typedef, 1)).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should return false for value params", () => {
|
|
168
|
+
const typedef = "void (*)(Point p, int count)";
|
|
169
|
+
|
|
170
|
+
expect(TypedefParamParser.shouldBePointer(typedef, 0)).toBe(false);
|
|
171
|
+
expect(TypedefParamParser.shouldBePointer(typedef, 1)).toBe(false);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should return null for out of bounds index", () => {
|
|
175
|
+
const typedef = "void (*)(Point p)";
|
|
176
|
+
|
|
177
|
+
expect(TypedefParamParser.shouldBePointer(typedef, 1)).toBeNull();
|
|
178
|
+
expect(TypedefParamParser.shouldBePointer(typedef, 99)).toBeNull();
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("should return null for invalid typedef", () => {
|
|
182
|
+
expect(TypedefParamParser.shouldBePointer("invalid", 0)).toBeNull();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("shouldBeConst", () => {
|
|
187
|
+
it("should return true for const params", () => {
|
|
188
|
+
const typedef = "void (*)(const Point* p, const char* s)";
|
|
189
|
+
|
|
190
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 0)).toBe(true);
|
|
191
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 1)).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("should return false for non-const params", () => {
|
|
195
|
+
const typedef = "void (*)(Point* p, uint8_t* buf)";
|
|
196
|
+
|
|
197
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 0)).toBe(false);
|
|
198
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 1)).toBe(false);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should handle mixed const params", () => {
|
|
202
|
+
const typedef = "void (*)(widget_t* w, const rect_t* area, uint8_t* buf)";
|
|
203
|
+
|
|
204
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 0)).toBe(false);
|
|
205
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 1)).toBe(true);
|
|
206
|
+
expect(TypedefParamParser.shouldBeConst(typedef, 2)).toBe(false);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
@@ -54,14 +54,46 @@ describe("VariableModifierBuilder", () => {
|
|
|
54
54
|
expect(result.volatile).toBe("volatile ");
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
it("returns extern for const at file scope", () => {
|
|
57
|
+
it("returns extern for const at file scope (declaration without initializer, C mode)", () => {
|
|
58
58
|
const ctx = {
|
|
59
59
|
constModifier: () => ({}),
|
|
60
60
|
atomicModifier: () => null,
|
|
61
61
|
volatileModifier: () => null,
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
// Declaration (no initializer) in C mode - should have extern
|
|
65
|
+
const result = VariableModifierBuilder.build(ctx, false, false, false);
|
|
66
|
+
|
|
67
|
+
expect(result.extern).toBe("extern ");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("does not return extern for const at file scope with initializer in C mode (MISRA 8.5)", () => {
|
|
71
|
+
// MISRA Rule 8.5: External object/function shall be declared once in one file only.
|
|
72
|
+
// When a variable has an initializer, it's a DEFINITION, not a declaration.
|
|
73
|
+
// The extern declaration comes from the header; the .c file should not duplicate it.
|
|
74
|
+
const ctx = {
|
|
75
|
+
constModifier: () => ({}),
|
|
76
|
+
atomicModifier: () => null,
|
|
77
|
+
volatileModifier: () => null,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Definition (has initializer) in C mode - should NOT have extern
|
|
81
|
+
const result = VariableModifierBuilder.build(ctx, false, true, false);
|
|
82
|
+
|
|
83
|
+
expect(result.extern).toBe("");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("returns extern for const at file scope with initializer in C++ mode (Issue #525)", () => {
|
|
87
|
+
// In C++, const at file scope has internal linkage by default.
|
|
88
|
+
// extern is needed for cross-file access, even for definitions.
|
|
89
|
+
const ctx = {
|
|
90
|
+
constModifier: () => ({}),
|
|
91
|
+
atomicModifier: () => null,
|
|
92
|
+
volatileModifier: () => null,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Definition (has initializer) in C++ mode - SHOULD have extern for external linkage
|
|
96
|
+
const result = VariableModifierBuilder.build(ctx, false, true, true);
|
|
65
97
|
|
|
66
98
|
expect(result.extern).toBe("extern ");
|
|
67
99
|
});
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import * as Parser from "../../../logic/parser/grammar/CNextParser";
|
|
18
18
|
import CodeGenState from "../../../state/CodeGenState";
|
|
19
19
|
import TypeResolver from "../TypeResolver";
|
|
20
|
-
import ExpressionUnwrapper from "
|
|
20
|
+
import ExpressionUnwrapper from "../../../../utils/ExpressionUnwrapper";
|
|
21
21
|
import QualifiedNameGenerator from "../utils/QualifiedNameGenerator";
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import * as Parser from "../../../logic/parser/grammar/CNextParser";
|
|
13
13
|
import CodeGenState from "../../../state/CodeGenState";
|
|
14
|
-
import ExpressionUnwrapper from "
|
|
14
|
+
import ExpressionUnwrapper from "../../../../utils/ExpressionUnwrapper";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Callbacks for operations that require CodeGenerator context.
|
|
@@ -53,6 +53,19 @@ interface IParameterInput {
|
|
|
53
53
|
|
|
54
54
|
/** Whether to use pass-by-reference semantics (known struct or known primitive) */
|
|
55
55
|
isPassByReference: boolean;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Issue #895: Force pointer syntax even in C++ mode.
|
|
59
|
+
* Required for callback-compatible functions because C callback typedefs
|
|
60
|
+
* expect pointers, not C++ references.
|
|
61
|
+
*/
|
|
62
|
+
forcePointerSyntax?: boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Issue #895: Force const qualifier from callback typedef signature.
|
|
66
|
+
* When the C typedef has `const T*`, this preserves const on the generated param.
|
|
67
|
+
*/
|
|
68
|
+
forceConst?: boolean;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
export default IParameterInput;
|
|
@@ -23,6 +23,13 @@ interface ISeparatorContext {
|
|
|
23
23
|
|
|
24
24
|
/** Whether scopedRegName refers to a known register */
|
|
25
25
|
readonly isScopedRegister: boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Issue #895: Force pointer semantics even in C++ mode.
|
|
29
|
+
* When true, struct params use -> instead of . because they're part of
|
|
30
|
+
* a callback-compatible function that must match C typedef signatures.
|
|
31
|
+
*/
|
|
32
|
+
readonly forcePointerSemantics?: boolean;
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
export default ISeparatorContext;
|
|
@@ -14,6 +14,18 @@ type TParameterInfo = {
|
|
|
14
14
|
isConst: boolean; // ADR-013
|
|
15
15
|
isCallback: boolean; // ADR-029
|
|
16
16
|
isString: boolean; // ADR-045
|
|
17
|
+
/**
|
|
18
|
+
* Issue #895: True when a primitive param becomes a pointer due to callback typedef.
|
|
19
|
+
* When used as a value in expressions, these params need dereferencing (*param).
|
|
20
|
+
*/
|
|
21
|
+
isCallbackPointerPrimitive?: boolean;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Issue #895: True when a param needs pointer semantics due to callback typedef.
|
|
25
|
+
* In C++ mode, this forces -> member access instead of . (reference access).
|
|
26
|
+
* Applies to both struct and primitive callback-compatible params.
|
|
27
|
+
*/
|
|
28
|
+
forcePointerSemantics?: boolean;
|
|
17
29
|
};
|
|
18
30
|
|
|
19
31
|
export default TParameterInfo;
|
|
@@ -19,6 +19,7 @@ type TTypeInfo = {
|
|
|
19
19
|
isAtomic?: boolean;
|
|
20
20
|
isExternalCppType?: boolean; // Issue #375: C++ types instantiated via constructor
|
|
21
21
|
isParameter?: boolean; // Issue #579: Track if this is a function parameter (becomes pointer in C)
|
|
22
|
+
isPointer?: boolean; // Issue #895 Bug B: Track if variable is a pointer (inferred from C function return type)
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
export default TTypeInfo;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { ParserRuleContext, TerminalNode } from "antlr4ng";
|
|
9
9
|
import * as Parser from "../../../logic/parser/grammar/CNextParser";
|
|
10
|
-
import ExpressionUnwrapper from "
|
|
10
|
+
import ExpressionUnwrapper from "../../../../utils/ExpressionUnwrapper";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Static utility methods for parser context operations in code generation.
|
|
@@ -128,8 +128,12 @@ export default class CodeGenState {
|
|
|
128
128
|
/** Callback field types: "Struct.field" -> callbackTypeName */
|
|
129
129
|
static callbackFieldTypes: Map<string, string> = new Map();
|
|
130
130
|
|
|
131
|
-
/**
|
|
132
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Functions that are assigned to C callback typedefs.
|
|
133
|
+
* Maps function name -> typedef name (e.g., "my_flush" -> "flush_cb_t")
|
|
134
|
+
* Issue #895: We need the typedef name to look up parameter types.
|
|
135
|
+
*/
|
|
136
|
+
static callbackCompatibleFunctions: Map<string, string> = new Map();
|
|
133
137
|
|
|
134
138
|
// ===========================================================================
|
|
135
139
|
// PASS-BY-VALUE ANALYSIS (Issue #269)
|
|
@@ -624,6 +628,21 @@ export default class CodeGenState {
|
|
|
624
628
|
return this.callbackTypes.get(name);
|
|
625
629
|
}
|
|
626
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Issue #895: Get the typedef type string for a C typedef by name.
|
|
633
|
+
* Used to look up function pointer typedef signatures for callback-compatible functions.
|
|
634
|
+
*
|
|
635
|
+
* @param typedefName - Name of the typedef (e.g., "flush_cb_t")
|
|
636
|
+
* @returns The type string (e.g., "void (*)(widget_t *, const rect_t *, uint8_t *)") or undefined
|
|
637
|
+
*/
|
|
638
|
+
static getTypedefType(typedefName: string): string | undefined {
|
|
639
|
+
const symbol = this.symbolTable.getCSymbol(typedefName);
|
|
640
|
+
if (symbol?.kind === "type") {
|
|
641
|
+
return symbol.type;
|
|
642
|
+
}
|
|
643
|
+
return undefined;
|
|
644
|
+
}
|
|
645
|
+
|
|
627
646
|
/**
|
|
628
647
|
* Check if a type name is a known C-Next function.
|
|
629
648
|
*/
|
package/src/utils/BitUtils.ts
CHANGED
|
@@ -6,16 +6,17 @@
|
|
|
6
6
|
*/
|
|
7
7
|
class BitUtils {
|
|
8
8
|
/**
|
|
9
|
-
* Convert a boolean expression to an integer (
|
|
9
|
+
* Convert a boolean expression to an unsigned integer (0U or 1U).
|
|
10
10
|
* Handles literal "true"/"false" and generates ternary for expressions.
|
|
11
|
+
* Uses unsigned literals for MISRA C:2012 Rule 10.1 compliance.
|
|
11
12
|
*
|
|
12
13
|
* @param expr - The expression to convert
|
|
13
|
-
* @returns C code string representing the integer value
|
|
14
|
+
* @returns C code string representing the unsigned integer value
|
|
14
15
|
*/
|
|
15
16
|
static boolToInt(expr: string): string {
|
|
16
|
-
if (expr === "true") return "
|
|
17
|
-
if (expr === "false") return "
|
|
18
|
-
return `(${expr} ?
|
|
17
|
+
if (expr === "true") return "1U";
|
|
18
|
+
if (expr === "false") return "0U";
|
|
19
|
+
return `(${expr} ? 1U : 0U)`;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -78,25 +79,27 @@ class BitUtils {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
81
|
-
* Return the appropriate "1" literal for a given type.
|
|
82
|
-
* Uses "1ULL" for 64-bit types
|
|
82
|
+
* Return the appropriate unsigned "1" literal for a given type.
|
|
83
|
+
* Uses "1ULL" for 64-bit types, "1U" for others.
|
|
84
|
+
* MISRA C:2012 Rule 10.1 requires unsigned operands for bitwise operations.
|
|
83
85
|
*
|
|
84
86
|
* @param typeName - The C-Next type name (e.g., "u64", "i32")
|
|
85
|
-
* @returns "1ULL" for 64-bit types, "
|
|
87
|
+
* @returns "1ULL" for 64-bit types, "1U" otherwise
|
|
86
88
|
*/
|
|
87
89
|
static oneForType(typeName: string): string {
|
|
88
|
-
return typeName === "u64" || typeName === "i64" ? "1ULL" : "
|
|
90
|
+
return typeName === "u64" || typeName === "i64" ? "1ULL" : "1U";
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
/**
|
|
92
|
-
* Format a number as an uppercase hex string (e.g., 255 -> "
|
|
94
|
+
* Format a number as an unsigned uppercase hex string (e.g., 255 -> "0xFFU").
|
|
93
95
|
* Used for generating hex mask literals in generated C code.
|
|
96
|
+
* Includes U suffix for MISRA C:2012 Rule 10.1 compliance.
|
|
94
97
|
*
|
|
95
98
|
* @param value - The numeric value to format
|
|
96
|
-
* @returns Hex string like "
|
|
99
|
+
* @returns Hex string like "0xFFU" or "0x1FU"
|
|
97
100
|
*/
|
|
98
101
|
static formatHex(value: number): string {
|
|
99
|
-
return `0x${value.toString(16).toUpperCase()}`;
|
|
102
|
+
return `0x${value.toString(16).toUpperCase()}U`;
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
/**
|
|
@@ -154,7 +157,7 @@ class BitUtils {
|
|
|
154
157
|
): string {
|
|
155
158
|
const intValue = BitUtils.boolToInt(value);
|
|
156
159
|
const is64Bit = targetType === "u64" || targetType === "i64";
|
|
157
|
-
const one = is64Bit ? "1ULL" : "
|
|
160
|
+
const one = is64Bit ? "1ULL" : "1U";
|
|
158
161
|
// For 64-bit types, cast the value to ensure shift doesn't overflow
|
|
159
162
|
const valueShift = is64Bit
|
|
160
163
|
? `((uint64_t)${intValue} << ${offset})`
|
|
@@ -203,6 +206,7 @@ class BitUtils {
|
|
|
203
206
|
): string {
|
|
204
207
|
const intValue = BitUtils.boolToInt(value);
|
|
205
208
|
// For 64-bit types, cast to ensure correct shift width
|
|
209
|
+
// boolToInt already returns unsigned values (1U/0U) for MISRA 10.1 compliance
|
|
206
210
|
const castPrefix =
|
|
207
211
|
targetType === "u64" || targetType === "i64" ? "(uint64_t)" : "";
|
|
208
212
|
return `${target} = (${castPrefix}${intValue} << ${offset});`;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* eliminate code duplication.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import * as Parser from "
|
|
19
|
+
import * as Parser from "../transpiler/logic/parser/grammar/CNextParser";
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Utility class for navigating expression tree hierarchy
|