c-next 0.2.15 → 0.2.17
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/README.md +16 -0
- package/dist/index.js +1403 -427
- package/dist/index.js.map +3 -3
- package/grammar/CNext.g4 +4 -0
- package/package.json +5 -1
- package/src/transpiler/Transpiler.ts +90 -22
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +57 -10
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +186 -14
- package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +124 -12
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +200 -0
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +386 -1
- package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +211 -0
- package/src/transpiler/logic/parser/grammar/CNext.interp +1 -1
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +154 -86
- package/src/transpiler/logic/symbols/SymbolTable.ts +54 -12
- package/src/transpiler/logic/symbols/SymbolUtils.ts +21 -8
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +39 -4
- package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +2 -1
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +2 -1
- package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +5 -2
- package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +5 -2
- package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +7 -2
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +15 -2
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +64 -50
- package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +4 -2
- package/src/transpiler/output/codegen/CodeGenerator.ts +151 -94
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +167 -18
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +150 -34
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +11 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +32 -8
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +91 -1
- package/src/transpiler/output/codegen/generators/expressions/BinaryExprGenerator.ts +43 -24
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +48 -43
- package/src/transpiler/output/codegen/generators/expressions/ExpressionGenerator.ts +9 -2
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +44 -0
- package/src/transpiler/output/codegen/generators/expressions/__tests__/ExpressionGenerator.test.ts +82 -1
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +17 -3
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +17 -4
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +227 -32
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +0 -21
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +60 -39
- package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +170 -36
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +37 -39
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +117 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +94 -2
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +268 -1
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +0 -64
- package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +101 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +29 -5
- package/src/transpiler/output/codegen/types/ICallbackTypeInfo.ts +2 -1
- package/src/transpiler/output/codegen/types/IParameterInput.ts +7 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +8 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +75 -0
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +280 -0
- package/src/transpiler/output/headers/generators/IHeaderTypeInput.ts +13 -0
- package/src/transpiler/output/headers/generators/generateStructHeader.ts +48 -28
- package/src/transpiler/state/CodeGenState.ts +71 -6
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +253 -11
- package/src/transpiler/types/symbols/c/ICFieldInfo.ts +6 -2
- package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +5 -2
- package/src/utils/LiteralUtils.ts +23 -0
- package/src/utils/ScopeUtils.ts +19 -0
- package/src/utils/__tests__/LiteralUtils.test.ts +101 -0
- package/src/utils/__tests__/ScopeUtils.test.ts +10 -0
- package/src/utils/types/IParameterSymbol.ts +1 -0
|
@@ -376,6 +376,7 @@ describe("CodeGenState", () => {
|
|
|
376
376
|
isArray: false,
|
|
377
377
|
isConst: false,
|
|
378
378
|
isPointer: false,
|
|
379
|
+
isStruct: false,
|
|
379
380
|
arrayDims: "",
|
|
380
381
|
},
|
|
381
382
|
],
|
|
@@ -1011,25 +1012,35 @@ describe("CodeGenState", () => {
|
|
|
1011
1012
|
describe("Opaque Scope Variable Helpers (Issue #948)", () => {
|
|
1012
1013
|
it("markOpaqueScopeVariable adds to opaqueScopeVariables", () => {
|
|
1013
1014
|
CodeGenState.markOpaqueScopeVariable("MyScope_widget");
|
|
1014
|
-
expect(CodeGenState.
|
|
1015
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("MyScope_widget")).toBe(
|
|
1016
|
+
true,
|
|
1017
|
+
);
|
|
1015
1018
|
});
|
|
1016
1019
|
|
|
1017
|
-
it("
|
|
1018
|
-
expect(CodeGenState.
|
|
1020
|
+
it("isOpaqueScopeVariableAccess returns false for unknown variable", () => {
|
|
1021
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Unknown_var")).toBe(
|
|
1022
|
+
false,
|
|
1023
|
+
);
|
|
1019
1024
|
});
|
|
1020
1025
|
|
|
1021
|
-
it("
|
|
1026
|
+
it("isOpaqueScopeVariableAccess returns true for marked variable", () => {
|
|
1022
1027
|
CodeGenState.markOpaqueScopeVariable("Gui_display");
|
|
1023
|
-
expect(CodeGenState.
|
|
1028
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Gui_display")).toBe(
|
|
1029
|
+
true,
|
|
1030
|
+
);
|
|
1024
1031
|
});
|
|
1025
1032
|
|
|
1026
1033
|
it("reset clears opaqueScopeVariables", () => {
|
|
1027
1034
|
CodeGenState.markOpaqueScopeVariable("Test_opaque");
|
|
1028
|
-
expect(CodeGenState.
|
|
1035
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Test_opaque")).toBe(
|
|
1036
|
+
true,
|
|
1037
|
+
);
|
|
1029
1038
|
|
|
1030
1039
|
CodeGenState.reset();
|
|
1031
1040
|
|
|
1032
|
-
expect(CodeGenState.
|
|
1041
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Test_opaque")).toBe(
|
|
1042
|
+
false,
|
|
1043
|
+
);
|
|
1033
1044
|
});
|
|
1034
1045
|
|
|
1035
1046
|
it("handles multiple opaque scope variables", () => {
|
|
@@ -1037,10 +1048,241 @@ describe("CodeGenState", () => {
|
|
|
1037
1048
|
CodeGenState.markOpaqueScopeVariable("Scope1_display");
|
|
1038
1049
|
CodeGenState.markOpaqueScopeVariable("Scope2_handle");
|
|
1039
1050
|
|
|
1040
|
-
expect(CodeGenState.
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
expect(CodeGenState.
|
|
1051
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Scope1_widget")).toBe(
|
|
1052
|
+
true,
|
|
1053
|
+
);
|
|
1054
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Scope1_display")).toBe(
|
|
1055
|
+
true,
|
|
1056
|
+
);
|
|
1057
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Scope2_handle")).toBe(
|
|
1058
|
+
true,
|
|
1059
|
+
);
|
|
1060
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("Scope1_other")).toBe(
|
|
1061
|
+
false,
|
|
1062
|
+
);
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
// Issue #996: An element of an opaque-handle array is itself a pointer.
|
|
1066
|
+
it("isOpaqueScopeVariableAccess matches array-element access of an opaque array", () => {
|
|
1067
|
+
CodeGenState.markOpaqueScopeVariable("UI_widgets");
|
|
1068
|
+
|
|
1069
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("UI_widgets[i]")).toBe(
|
|
1070
|
+
true,
|
|
1071
|
+
);
|
|
1072
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("UI_widgets[0]")).toBe(
|
|
1073
|
+
true,
|
|
1074
|
+
);
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
it("isOpaqueScopeVariableAccess does not match subscript of a non-opaque array", () => {
|
|
1078
|
+
// Base array name was never marked opaque.
|
|
1079
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("UI_counts[i]")).toBe(
|
|
1080
|
+
false,
|
|
1081
|
+
);
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
it("isOpaqueScopeVariableAccess does not match a different array that shares a prefix", () => {
|
|
1085
|
+
CodeGenState.markOpaqueScopeVariable("UI_widgets");
|
|
1086
|
+
|
|
1087
|
+
// "UI_widgetsExtra" is a distinct variable, not a subscript of UI_widgets.
|
|
1088
|
+
expect(CodeGenState.isOpaqueScopeVariableAccess("UI_widgetsExtra")).toBe(
|
|
1089
|
+
false,
|
|
1090
|
+
);
|
|
1091
|
+
});
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
describe("withDeclarationInit()", () => {
|
|
1095
|
+
it("sets inDeclarationInit to true during callback", () => {
|
|
1096
|
+
CodeGenState.inDeclarationInit = false;
|
|
1097
|
+
let valueInside = false;
|
|
1098
|
+
|
|
1099
|
+
CodeGenState.withDeclarationInit(() => {
|
|
1100
|
+
valueInside = CodeGenState.inDeclarationInit;
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
expect(valueInside).toBe(true);
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
it("restores prior value after callback", () => {
|
|
1107
|
+
CodeGenState.inDeclarationInit = false;
|
|
1108
|
+
|
|
1109
|
+
CodeGenState.withDeclarationInit(() => {
|
|
1110
|
+
// inside: true
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
expect(CodeGenState.inDeclarationInit).toBe(false);
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
it("restores prior value even when already true", () => {
|
|
1117
|
+
CodeGenState.inDeclarationInit = true;
|
|
1118
|
+
|
|
1119
|
+
CodeGenState.withDeclarationInit(() => {
|
|
1120
|
+
expect(CodeGenState.inDeclarationInit).toBe(true);
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
expect(CodeGenState.inDeclarationInit).toBe(true);
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
it("returns the callback result", () => {
|
|
1127
|
+
const result = CodeGenState.withDeclarationInit(() => "hello");
|
|
1128
|
+
expect(result).toBe("hello");
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
it("restores prior value on exception", () => {
|
|
1132
|
+
CodeGenState.inDeclarationInit = false;
|
|
1133
|
+
|
|
1134
|
+
expect(() =>
|
|
1135
|
+
CodeGenState.withDeclarationInit(() => {
|
|
1136
|
+
throw new Error("test error");
|
|
1137
|
+
}),
|
|
1138
|
+
).toThrow("test error");
|
|
1139
|
+
|
|
1140
|
+
expect(CodeGenState.inDeclarationInit).toBe(false);
|
|
1141
|
+
});
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
describe("withoutDeclarationInit()", () => {
|
|
1145
|
+
it("sets inDeclarationInit to false during callback", () => {
|
|
1146
|
+
CodeGenState.inDeclarationInit = true;
|
|
1147
|
+
let valueInside = true;
|
|
1148
|
+
|
|
1149
|
+
CodeGenState.withoutDeclarationInit(() => {
|
|
1150
|
+
valueInside = CodeGenState.inDeclarationInit;
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
expect(valueInside).toBe(false);
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
it("restores prior value after callback", () => {
|
|
1157
|
+
CodeGenState.inDeclarationInit = true;
|
|
1158
|
+
|
|
1159
|
+
CodeGenState.withoutDeclarationInit(() => {
|
|
1160
|
+
// inside: false
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
expect(CodeGenState.inDeclarationInit).toBe(true);
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
it("restores prior value even when already false", () => {
|
|
1167
|
+
CodeGenState.inDeclarationInit = false;
|
|
1168
|
+
|
|
1169
|
+
CodeGenState.withoutDeclarationInit(() => {
|
|
1170
|
+
expect(CodeGenState.inDeclarationInit).toBe(false);
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
expect(CodeGenState.inDeclarationInit).toBe(false);
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
it("returns the callback result", () => {
|
|
1177
|
+
const result = CodeGenState.withoutDeclarationInit(() => 42);
|
|
1178
|
+
expect(result).toBe(42);
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
it("restores prior value on exception", () => {
|
|
1182
|
+
CodeGenState.inDeclarationInit = true;
|
|
1183
|
+
|
|
1184
|
+
expect(() =>
|
|
1185
|
+
CodeGenState.withoutDeclarationInit(() => {
|
|
1186
|
+
throw new Error("test error");
|
|
1187
|
+
}),
|
|
1188
|
+
).toThrow("test error");
|
|
1189
|
+
|
|
1190
|
+
expect(CodeGenState.inDeclarationInit).toBe(true);
|
|
1191
|
+
});
|
|
1192
|
+
|
|
1193
|
+
it("nests correctly with withDeclarationInit", () => {
|
|
1194
|
+
CodeGenState.inDeclarationInit = false;
|
|
1195
|
+
|
|
1196
|
+
CodeGenState.withDeclarationInit(() => {
|
|
1197
|
+
expect(CodeGenState.inDeclarationInit).toBe(true);
|
|
1198
|
+
|
|
1199
|
+
CodeGenState.withoutDeclarationInit(() => {
|
|
1200
|
+
expect(CodeGenState.inDeclarationInit).toBe(false);
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1203
|
+
expect(CodeGenState.inDeclarationInit).toBe(true);
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
expect(CodeGenState.inDeclarationInit).toBe(false);
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
describe("withoutExpectedType()", () => {
|
|
1211
|
+
it("clears expectedType during callback", () => {
|
|
1212
|
+
CodeGenState.expectedType = "u32";
|
|
1213
|
+
let typeInside: string | null = "notCleared";
|
|
1214
|
+
|
|
1215
|
+
CodeGenState.withoutExpectedType(() => {
|
|
1216
|
+
typeInside = CodeGenState.expectedType;
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
expect(typeInside).toBeNull();
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
it("clears suppressBareEnumResolution during callback", () => {
|
|
1223
|
+
CodeGenState.suppressBareEnumResolution = true;
|
|
1224
|
+
let suppressInside = true;
|
|
1225
|
+
|
|
1226
|
+
CodeGenState.withoutExpectedType(() => {
|
|
1227
|
+
suppressInside = CodeGenState.suppressBareEnumResolution;
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
expect(suppressInside).toBe(false);
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
it("restores expectedType after callback", () => {
|
|
1234
|
+
CodeGenState.expectedType = "i32";
|
|
1235
|
+
|
|
1236
|
+
CodeGenState.withoutExpectedType(() => {
|
|
1237
|
+
// inside: null
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
expect(CodeGenState.expectedType).toBe("i32");
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1243
|
+
it("restores suppressBareEnumResolution after callback", () => {
|
|
1244
|
+
CodeGenState.suppressBareEnumResolution = true;
|
|
1245
|
+
|
|
1246
|
+
CodeGenState.withoutExpectedType(() => {
|
|
1247
|
+
// inside: false
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
expect(CodeGenState.suppressBareEnumResolution).toBe(true);
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
it("returns the callback result", () => {
|
|
1254
|
+
const result = CodeGenState.withoutExpectedType(() => 123);
|
|
1255
|
+
expect(result).toBe(123);
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
it("restores values on exception", () => {
|
|
1259
|
+
CodeGenState.expectedType = "bool";
|
|
1260
|
+
CodeGenState.suppressBareEnumResolution = true;
|
|
1261
|
+
|
|
1262
|
+
expect(() =>
|
|
1263
|
+
CodeGenState.withoutExpectedType(() => {
|
|
1264
|
+
throw new Error("test error");
|
|
1265
|
+
}),
|
|
1266
|
+
).toThrow("test error");
|
|
1267
|
+
|
|
1268
|
+
expect(CodeGenState.expectedType).toBe("bool");
|
|
1269
|
+
expect(CodeGenState.suppressBareEnumResolution).toBe(true);
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
it("handles null expectedType correctly", () => {
|
|
1273
|
+
CodeGenState.expectedType = null;
|
|
1274
|
+
CodeGenState.suppressBareEnumResolution = false;
|
|
1275
|
+
|
|
1276
|
+
let executed = false;
|
|
1277
|
+
CodeGenState.withoutExpectedType(() => {
|
|
1278
|
+
executed = true;
|
|
1279
|
+
expect(CodeGenState.expectedType).toBeNull();
|
|
1280
|
+
expect(CodeGenState.suppressBareEnumResolution).toBe(false);
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
expect(executed).toBe(true);
|
|
1284
|
+
expect(CodeGenState.expectedType).toBeNull();
|
|
1285
|
+
expect(CodeGenState.suppressBareEnumResolution).toBe(false);
|
|
1044
1286
|
});
|
|
1045
1287
|
});
|
|
1046
1288
|
});
|
|
@@ -9,8 +9,12 @@ interface ICFieldInfo {
|
|
|
9
9
|
/** Field type as string (e.g., "int", "char*") */
|
|
10
10
|
readonly type: string;
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Array dimensions if this field is an array.
|
|
14
|
+
* Issue #981: Numbers for resolved dimensions, strings for macro names.
|
|
15
|
+
* Example: [8] for numeric, ["BUF_SIZE"] for macro-sized.
|
|
16
|
+
*/
|
|
17
|
+
readonly arrayDimensions?: ReadonlyArray<number | string>;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export default ICFieldInfo;
|
|
@@ -9,8 +9,11 @@ interface ICppFieldInfo {
|
|
|
9
9
|
/** Field type as string (e.g., "int", "std::string") */
|
|
10
10
|
readonly type: string;
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Array dimensions if this field is an array.
|
|
14
|
+
* Issue #981: Supports both numeric literals and macro names.
|
|
15
|
+
*/
|
|
16
|
+
readonly arrayDimensions?: ReadonlyArray<number | string>;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
export default ICppFieldInfo;
|
|
@@ -68,9 +68,32 @@ class LiteralUtils {
|
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// Issue #1010: Float literals (0.0, 0.0f, .0, etc.)
|
|
72
|
+
if (ctx.FLOAT_LITERAL()) {
|
|
73
|
+
return LiteralUtils.isFloatZero(text);
|
|
74
|
+
}
|
|
75
|
+
|
|
71
76
|
return false;
|
|
72
77
|
}
|
|
73
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Check if a float literal string represents zero.
|
|
81
|
+
* Issue #1010: Detect float zero for division-by-zero checking.
|
|
82
|
+
*
|
|
83
|
+
* Handles: 0.0, .0, 0., 0.0f, 0.0F, 0.0e0, 0.0E0, etc.
|
|
84
|
+
*
|
|
85
|
+
* @param text - The float literal text
|
|
86
|
+
* @returns true if the float is zero
|
|
87
|
+
*/
|
|
88
|
+
static isFloatZero(text: string): boolean {
|
|
89
|
+
// Remove optional float suffix (f, F)
|
|
90
|
+
const withoutSuffix = text.replace(/[fF]$/, "");
|
|
91
|
+
|
|
92
|
+
// Parse to number and check if zero
|
|
93
|
+
const value = Number.parseFloat(withoutSuffix);
|
|
94
|
+
return value === 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
/**
|
|
75
98
|
* Check if a literal is a floating-point number.
|
|
76
99
|
*
|
package/src/utils/ScopeUtils.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Provides utilities for creating and inspecting C-Next scopes.
|
|
5
5
|
*/
|
|
6
6
|
import type IScopeSymbol from "../transpiler/types/symbols/IScopeSymbol";
|
|
7
|
+
import type TVisibility from "../transpiler/types/TVisibility";
|
|
7
8
|
import ESourceLanguage from "./types/ESourceLanguage";
|
|
8
9
|
|
|
9
10
|
class ScopeUtils {
|
|
@@ -79,6 +80,24 @@ class ScopeUtils {
|
|
|
79
80
|
return scope.name === "" && scope.parent === scope;
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Visibility Utilities
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* ADR-016: Get the default visibility for a scope member based on its type.
|
|
89
|
+
*
|
|
90
|
+
* Member-type-aware defaults reduce boilerplate:
|
|
91
|
+
* - Functions: public by default (API surface)
|
|
92
|
+
* - Variables/types: private by default (internal state)
|
|
93
|
+
*
|
|
94
|
+
* @param isFunction - Whether the member is a function declaration
|
|
95
|
+
* @returns The default visibility for this member type
|
|
96
|
+
*/
|
|
97
|
+
static getDefaultVisibility(isFunction: boolean): TVisibility {
|
|
98
|
+
return isFunction ? "public" : "private";
|
|
99
|
+
}
|
|
100
|
+
|
|
82
101
|
// ============================================================================
|
|
83
102
|
// Path Utilities
|
|
84
103
|
// ============================================================================
|
|
@@ -306,6 +306,107 @@ describe("LiteralUtils", () => {
|
|
|
306
306
|
});
|
|
307
307
|
});
|
|
308
308
|
|
|
309
|
+
// ========================================================================
|
|
310
|
+
// isZero: Float Literals (Issue #1010)
|
|
311
|
+
// ========================================================================
|
|
312
|
+
|
|
313
|
+
describe("isZero - float literals (Issue #1010)", () => {
|
|
314
|
+
it("should return true for float zero (0.0)", () => {
|
|
315
|
+
const literal = extractFloatLiteral("0.0");
|
|
316
|
+
expect(literal).not.toBeNull();
|
|
317
|
+
expect(LiteralUtils.isZero(literal!)).toBe(true);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("should return true for float zero with suffix (0.0f)", () => {
|
|
321
|
+
const literal = extractFloatLiteral("0.0f");
|
|
322
|
+
expect(literal).not.toBeNull();
|
|
323
|
+
expect(LiteralUtils.isZero(literal!)).toBe(true);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("should return true for float zero with uppercase suffix (0.0F)", () => {
|
|
327
|
+
const literal = extractFloatLiteral("0.0F");
|
|
328
|
+
expect(literal).not.toBeNull();
|
|
329
|
+
expect(LiteralUtils.isZero(literal!)).toBe(true);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it("should return true for leading-dot zero (.0)", () => {
|
|
333
|
+
const literal = extractFloatLiteral(".0");
|
|
334
|
+
expect(literal).not.toBeNull();
|
|
335
|
+
expect(LiteralUtils.isZero(literal!)).toBe(true);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it("should return false for non-zero float (1.0)", () => {
|
|
339
|
+
const literal = extractFloatLiteral("1.0");
|
|
340
|
+
expect(literal).not.toBeNull();
|
|
341
|
+
expect(LiteralUtils.isZero(literal!)).toBe(false);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("should return false for small non-zero float (0.001)", () => {
|
|
345
|
+
const literal = extractFloatLiteral("0.001");
|
|
346
|
+
expect(literal).not.toBeNull();
|
|
347
|
+
expect(LiteralUtils.isZero(literal!)).toBe(false);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("should return false for negative float (-0.5)", () => {
|
|
351
|
+
const literal = extractFloatLiteral("-0.5");
|
|
352
|
+
// Note: -0.5 may not parse as a single literal due to negation
|
|
353
|
+
// This is expected - the unary minus is a separate operator
|
|
354
|
+
if (literal) {
|
|
355
|
+
expect(LiteralUtils.isZero(literal!)).toBe(false);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// ========================================================================
|
|
361
|
+
// isFloatZero (Issue #1010)
|
|
362
|
+
// ========================================================================
|
|
363
|
+
|
|
364
|
+
describe("isFloatZero - static method (Issue #1010)", () => {
|
|
365
|
+
it("should return true for 0.0", () => {
|
|
366
|
+
expect(LiteralUtils.isFloatZero("0.0")).toBe(true);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it("should return true for .0", () => {
|
|
370
|
+
expect(LiteralUtils.isFloatZero(".0")).toBe(true);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it("should return true for 0.", () => {
|
|
374
|
+
expect(LiteralUtils.isFloatZero("0.")).toBe(true);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("should return true for 0.0f", () => {
|
|
378
|
+
expect(LiteralUtils.isFloatZero("0.0f")).toBe(true);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it("should return true for 0.0F", () => {
|
|
382
|
+
expect(LiteralUtils.isFloatZero("0.0F")).toBe(true);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("should return true for scientific notation zero (0.0e0)", () => {
|
|
386
|
+
expect(LiteralUtils.isFloatZero("0.0e0")).toBe(true);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("should return true for scientific notation zero (0e0)", () => {
|
|
390
|
+
expect(LiteralUtils.isFloatZero("0e0")).toBe(true);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("should return false for 1.0", () => {
|
|
394
|
+
expect(LiteralUtils.isFloatZero("1.0")).toBe(false);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("should return false for 0.5", () => {
|
|
398
|
+
expect(LiteralUtils.isFloatZero("0.5")).toBe(false);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("should return false for 3.14", () => {
|
|
402
|
+
expect(LiteralUtils.isFloatZero("3.14")).toBe(false);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it("should return false for scientific notation non-zero (1e-10)", () => {
|
|
406
|
+
expect(LiteralUtils.isFloatZero("1e-10")).toBe(false);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
309
410
|
// ========================================================================
|
|
310
411
|
// isFloat
|
|
311
412
|
// ========================================================================
|
|
@@ -50,4 +50,14 @@ describe("IScopeSymbol", () => {
|
|
|
50
50
|
expect(ScopeUtils.isGlobalScope(scope)).toBe(false);
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
|
+
|
|
54
|
+
describe("getDefaultVisibility", () => {
|
|
55
|
+
it("returns 'public' for functions (API surface)", () => {
|
|
56
|
+
expect(ScopeUtils.getDefaultVisibility(true)).toBe("public");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("returns 'private' for non-functions (internal state)", () => {
|
|
60
|
+
expect(ScopeUtils.getDefaultVisibility(false)).toBe("private");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
53
63
|
});
|
|
@@ -10,6 +10,7 @@ interface IParameterSymbol {
|
|
|
10
10
|
isAutoConst?: boolean; // Issue #268: true if parameter should get auto-const (unmodified pointer)
|
|
11
11
|
isCallbackPointer?: boolean; // Issue #914: typedef says this param must be a pointer
|
|
12
12
|
isCallbackConst?: boolean; // Issue #914: typedef says this param must be const
|
|
13
|
+
isOpaqueHandle?: boolean; // Issue #995: type is opaque (incomplete struct), needs pointer not reference
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export default IParameterSymbol;
|