c-next 0.2.6 → 0.2.7
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 +387 -433
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +50 -29
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -1
- package/src/transpiler/data/PathResolver.ts +10 -6
- package/src/transpiler/data/__tests__/PathResolver.test.ts +32 -0
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +1 -12
- package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +239 -0
- package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +414 -0
- package/src/transpiler/logic/analysis/__tests__/StructFieldAnalyzer.test.ts +15 -75
- package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +3 -15
- package/src/transpiler/logic/analysis/runAnalyzers.ts +11 -2
- package/src/transpiler/logic/analysis/types/ISignedShiftError.ts +15 -0
- package/src/transpiler/logic/symbols/SymbolUtils.ts +4 -1
- package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +10 -11
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +4 -4
- package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +4 -4
- package/src/transpiler/output/codegen/CodeGenerator.ts +12 -4
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +3 -3
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +26 -26
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +12 -11
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +21 -21
- package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +7 -326
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +14 -275
- package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +13 -1
- package/src/transpiler/output/codegen/generators/expressions/__tests__/AccessExprGenerator.test.ts +0 -573
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +8 -439
- package/src/transpiler/output/codegen/generators/expressions/__tests__/UnaryExprGenerator.test.ts +196 -0
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +7 -2
- package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +34 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +48 -0
- package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +88 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +15 -2
- package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +87 -0
- package/src/utils/ExpressionUtils.ts +51 -0
- package/src/utils/types/IParameterSymbol.ts +2 -0
|
@@ -583,117 +583,12 @@ describe("PostfixExpressionGenerator", () => {
|
|
|
583
583
|
});
|
|
584
584
|
});
|
|
585
585
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
590
|
-
]);
|
|
591
|
-
const input = createMockInput();
|
|
592
|
-
const state = createMockState({ mainArgsName: "args" });
|
|
593
|
-
const orchestrator = createMockOrchestrator({
|
|
594
|
-
generatePrimaryExpr: () => "argv",
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
598
|
-
expect(result.code).toBe("argc");
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
it("returns comment for unknown type", () => {
|
|
602
|
-
const ctx = createMockPostfixExpressionContext("unknown", [
|
|
603
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
604
|
-
]);
|
|
605
|
-
const input = createMockInput();
|
|
606
|
-
const state = createMockState();
|
|
607
|
-
const orchestrator = createMockOrchestrator({
|
|
608
|
-
generatePrimaryExpr: () => "unknown",
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
612
|
-
expect(result.code).toContain("unknown type");
|
|
613
|
-
expect(result.code).toContain("0");
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
it("returns array dimension for array type", () => {
|
|
617
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
618
|
-
[
|
|
619
|
-
"arr",
|
|
620
|
-
{
|
|
621
|
-
baseType: "u32",
|
|
622
|
-
bitWidth: 32,
|
|
623
|
-
isArray: true,
|
|
624
|
-
arrayDimensions: [10],
|
|
625
|
-
isConst: false,
|
|
626
|
-
},
|
|
627
|
-
],
|
|
628
|
-
]);
|
|
629
|
-
const ctx = createMockPostfixExpressionContext("arr", [
|
|
630
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
631
|
-
]);
|
|
632
|
-
const input = createMockInput({ typeRegistry });
|
|
633
|
-
const state = createMockState();
|
|
634
|
-
const orchestrator = createMockOrchestrator({
|
|
635
|
-
generatePrimaryExpr: () => "arr",
|
|
636
|
-
});
|
|
637
|
-
|
|
638
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
639
|
-
expect(result.code).toBe("10");
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
it("returns strlen for string type", () => {
|
|
643
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
644
|
-
[
|
|
645
|
-
"str",
|
|
646
|
-
{
|
|
647
|
-
baseType: "char",
|
|
648
|
-
bitWidth: 8,
|
|
649
|
-
isArray: false,
|
|
650
|
-
isConst: false,
|
|
651
|
-
isString: true,
|
|
652
|
-
},
|
|
653
|
-
],
|
|
654
|
-
]);
|
|
655
|
-
const ctx = createMockPostfixExpressionContext("str", [
|
|
656
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
657
|
-
]);
|
|
658
|
-
const input = createMockInput({ typeRegistry });
|
|
659
|
-
const state = createMockState();
|
|
660
|
-
const orchestrator = createMockOrchestrator({
|
|
661
|
-
generatePrimaryExpr: () => "str",
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
665
|
-
expect(result.code).toBe("strlen(str)");
|
|
666
|
-
});
|
|
667
|
-
|
|
668
|
-
it("uses cached length when available", () => {
|
|
669
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
670
|
-
[
|
|
671
|
-
"str",
|
|
672
|
-
{
|
|
673
|
-
baseType: "char",
|
|
674
|
-
bitWidth: 8,
|
|
675
|
-
isArray: false,
|
|
676
|
-
isConst: false,
|
|
677
|
-
isString: true,
|
|
678
|
-
},
|
|
679
|
-
],
|
|
680
|
-
]);
|
|
681
|
-
const ctx = createMockPostfixExpressionContext("str", [
|
|
682
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
683
|
-
]);
|
|
684
|
-
const input = createMockInput({ typeRegistry });
|
|
685
|
-
const state = createMockState({
|
|
686
|
-
lengthCache: new Map([["str", "__len_str"]]),
|
|
687
|
-
});
|
|
688
|
-
const orchestrator = createMockOrchestrator({
|
|
689
|
-
generatePrimaryExpr: () => "str",
|
|
690
|
-
});
|
|
691
|
-
|
|
692
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
693
|
-
expect(result.code).toBe("__len_str");
|
|
694
|
-
});
|
|
586
|
+
// Note: .length property tests removed (ADR-058)
|
|
587
|
+
// .length is deprecated - use explicit properties instead:
|
|
588
|
+
// .bit_length, .byte_length, .element_count, .char_count
|
|
695
589
|
|
|
696
|
-
|
|
590
|
+
describe(".length property deprecation", () => {
|
|
591
|
+
it("throws deprecation error for .length property access", () => {
|
|
697
592
|
const typeRegistry = new Map<string, TTypeInfo>([
|
|
698
593
|
[
|
|
699
594
|
"val",
|
|
@@ -714,335 +609,9 @@ describe("PostfixExpressionGenerator", () => {
|
|
|
714
609
|
generatePrimaryExpr: () => "val",
|
|
715
610
|
});
|
|
716
611
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
it("returns 32 for enum type", () => {
|
|
722
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
723
|
-
[
|
|
724
|
-
"color",
|
|
725
|
-
{
|
|
726
|
-
baseType: "Color",
|
|
727
|
-
bitWidth: 32,
|
|
728
|
-
isArray: false,
|
|
729
|
-
isConst: false,
|
|
730
|
-
isEnum: true,
|
|
731
|
-
},
|
|
732
|
-
],
|
|
733
|
-
]);
|
|
734
|
-
const ctx = createMockPostfixExpressionContext("color", [
|
|
735
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
736
|
-
]);
|
|
737
|
-
const input = createMockInput({ typeRegistry });
|
|
738
|
-
const state = createMockState();
|
|
739
|
-
const orchestrator = createMockOrchestrator({
|
|
740
|
-
generatePrimaryExpr: () => "color",
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
744
|
-
expect(result.code).toBe("32");
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
it("returns dimension for 2D array type at depth 0", () => {
|
|
748
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
749
|
-
[
|
|
750
|
-
"matrix",
|
|
751
|
-
{
|
|
752
|
-
baseType: "u32",
|
|
753
|
-
bitWidth: 32,
|
|
754
|
-
isArray: true,
|
|
755
|
-
arrayDimensions: [3, 4],
|
|
756
|
-
isConst: false,
|
|
757
|
-
},
|
|
758
|
-
],
|
|
759
|
-
]);
|
|
760
|
-
const ctx = createMockPostfixExpressionContext("matrix", [
|
|
761
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
762
|
-
]);
|
|
763
|
-
const input = createMockInput({ typeRegistry });
|
|
764
|
-
const state = createMockState();
|
|
765
|
-
const orchestrator = createMockOrchestrator({
|
|
766
|
-
generatePrimaryExpr: () => "matrix",
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
770
|
-
expect(result.code).toBe("3");
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
it("returns dimension for 2D array type at depth 1", () => {
|
|
774
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
775
|
-
[
|
|
776
|
-
"matrix",
|
|
777
|
-
{
|
|
778
|
-
baseType: "u32",
|
|
779
|
-
bitWidth: 32,
|
|
780
|
-
isArray: true,
|
|
781
|
-
arrayDimensions: [3, 4],
|
|
782
|
-
isConst: false,
|
|
783
|
-
},
|
|
784
|
-
],
|
|
785
|
-
]);
|
|
786
|
-
const ctx = createMockPostfixExpressionContext("matrix", [
|
|
787
|
-
createMockPostfixOp({ expressions: [createMockExpression("0")] }),
|
|
788
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
789
|
-
]);
|
|
790
|
-
const input = createMockInput({ typeRegistry });
|
|
791
|
-
const state = createMockState();
|
|
792
|
-
const orchestrator = createMockOrchestrator({
|
|
793
|
-
generatePrimaryExpr: () => "matrix",
|
|
794
|
-
generateExpression: () => "0",
|
|
795
|
-
});
|
|
796
|
-
|
|
797
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
798
|
-
expect(result.code).toBe("4");
|
|
799
|
-
});
|
|
800
|
-
|
|
801
|
-
it("returns bit width when subscriptDepth exceeds dimensions", () => {
|
|
802
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
803
|
-
[
|
|
804
|
-
"arr",
|
|
805
|
-
{
|
|
806
|
-
baseType: "u32",
|
|
807
|
-
bitWidth: 32,
|
|
808
|
-
isArray: true,
|
|
809
|
-
arrayDimensions: [10],
|
|
810
|
-
isConst: false,
|
|
811
|
-
},
|
|
812
|
-
],
|
|
813
|
-
]);
|
|
814
|
-
const ctx = createMockPostfixExpressionContext("arr", [
|
|
815
|
-
createMockPostfixOp({ expressions: [createMockExpression("0")] }),
|
|
816
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
817
|
-
]);
|
|
818
|
-
const input = createMockInput({ typeRegistry });
|
|
819
|
-
const state = createMockState();
|
|
820
|
-
const orchestrator = createMockOrchestrator({
|
|
821
|
-
generatePrimaryExpr: () => "arr",
|
|
822
|
-
generateExpression: () => "0",
|
|
823
|
-
});
|
|
824
|
-
|
|
825
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
826
|
-
expect(result.code).toBe("32");
|
|
827
|
-
});
|
|
828
|
-
|
|
829
|
-
it("returns strlen for string array element", () => {
|
|
830
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
831
|
-
[
|
|
832
|
-
"names",
|
|
833
|
-
{
|
|
834
|
-
baseType: "char",
|
|
835
|
-
bitWidth: 8,
|
|
836
|
-
isArray: true,
|
|
837
|
-
arrayDimensions: [5, 32],
|
|
838
|
-
isConst: false,
|
|
839
|
-
isString: true,
|
|
840
|
-
},
|
|
841
|
-
],
|
|
842
|
-
]);
|
|
843
|
-
const ctx = createMockPostfixExpressionContext("names", [
|
|
844
|
-
createMockPostfixOp({ expressions: [createMockExpression("0")] }),
|
|
845
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
846
|
-
]);
|
|
847
|
-
const input = createMockInput({ typeRegistry });
|
|
848
|
-
const state = createMockState();
|
|
849
|
-
const orchestrator = createMockOrchestrator({
|
|
850
|
-
generatePrimaryExpr: () => "names",
|
|
851
|
-
generateExpression: () => "0",
|
|
852
|
-
});
|
|
853
|
-
|
|
854
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
855
|
-
expect(result.code).toBe("strlen(names[0])");
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
it("returns dimension for string array at depth 0", () => {
|
|
859
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
860
|
-
[
|
|
861
|
-
"names",
|
|
862
|
-
{
|
|
863
|
-
baseType: "char",
|
|
864
|
-
bitWidth: 8,
|
|
865
|
-
isArray: true,
|
|
866
|
-
arrayDimensions: [5, 32],
|
|
867
|
-
isConst: false,
|
|
868
|
-
isString: true,
|
|
869
|
-
},
|
|
870
|
-
],
|
|
871
|
-
]);
|
|
872
|
-
const ctx = createMockPostfixExpressionContext("names", [
|
|
873
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
874
|
-
]);
|
|
875
|
-
const input = createMockInput({ typeRegistry });
|
|
876
|
-
const state = createMockState();
|
|
877
|
-
const orchestrator = createMockOrchestrator({
|
|
878
|
-
generatePrimaryExpr: () => "names",
|
|
879
|
-
});
|
|
880
|
-
|
|
881
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
882
|
-
expect(result.code).toBe("5");
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
it("returns struct field array dimension for struct member access", () => {
|
|
886
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
887
|
-
[
|
|
888
|
-
"config",
|
|
889
|
-
{
|
|
890
|
-
baseType: "Config",
|
|
891
|
-
bitWidth: 0,
|
|
892
|
-
isArray: false,
|
|
893
|
-
isConst: false,
|
|
894
|
-
},
|
|
895
|
-
],
|
|
896
|
-
]);
|
|
897
|
-
const symbols = createMockSymbols({
|
|
898
|
-
knownStructs: new Set(["Config"]),
|
|
899
|
-
});
|
|
900
|
-
const ctx = createMockPostfixExpressionContext("config", [
|
|
901
|
-
createMockPostfixOp({ identifier: "values" }),
|
|
902
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
903
|
-
]);
|
|
904
|
-
const input = createMockInput({ symbols, typeRegistry });
|
|
905
|
-
const state = createMockState();
|
|
906
|
-
const orchestrator = createMockOrchestrator({
|
|
907
|
-
generatePrimaryExpr: () => "config",
|
|
908
|
-
isKnownStruct: (name) => name === "Config",
|
|
909
|
-
getMemberTypeInfo: () => ({
|
|
910
|
-
baseType: "u32",
|
|
911
|
-
isArray: true,
|
|
912
|
-
bitWidth: 32,
|
|
913
|
-
isConst: false,
|
|
914
|
-
}),
|
|
915
|
-
getStructFieldInfo: () => ({
|
|
916
|
-
type: "u32",
|
|
917
|
-
dimensions: [10],
|
|
918
|
-
}),
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
922
|
-
expect(result.code).toBe("10");
|
|
923
|
-
});
|
|
924
|
-
|
|
925
|
-
it("returns bit width for scalar struct field", () => {
|
|
926
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
927
|
-
[
|
|
928
|
-
"point",
|
|
929
|
-
{
|
|
930
|
-
baseType: "Point",
|
|
931
|
-
bitWidth: 0,
|
|
932
|
-
isArray: false,
|
|
933
|
-
isConst: false,
|
|
934
|
-
},
|
|
935
|
-
],
|
|
936
|
-
]);
|
|
937
|
-
const symbols = createMockSymbols({
|
|
938
|
-
knownStructs: new Set(["Point"]),
|
|
939
|
-
});
|
|
940
|
-
const ctx = createMockPostfixExpressionContext("point", [
|
|
941
|
-
createMockPostfixOp({ identifier: "x" }),
|
|
942
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
943
|
-
]);
|
|
944
|
-
const input = createMockInput({ symbols, typeRegistry });
|
|
945
|
-
const state = createMockState();
|
|
946
|
-
const orchestrator = createMockOrchestrator({
|
|
947
|
-
generatePrimaryExpr: () => "point",
|
|
948
|
-
isKnownStruct: (name) => name === "Point",
|
|
949
|
-
getMemberTypeInfo: () => ({
|
|
950
|
-
baseType: "i32",
|
|
951
|
-
isArray: false,
|
|
952
|
-
bitWidth: 32,
|
|
953
|
-
isConst: false,
|
|
954
|
-
}),
|
|
955
|
-
getStructFieldInfo: () => ({
|
|
956
|
-
type: "i32",
|
|
957
|
-
}),
|
|
958
|
-
});
|
|
959
|
-
|
|
960
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
961
|
-
expect(result.code).toBe("32");
|
|
962
|
-
});
|
|
963
|
-
|
|
964
|
-
it("returns strlen for string struct field", () => {
|
|
965
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
966
|
-
[
|
|
967
|
-
"person",
|
|
968
|
-
{
|
|
969
|
-
baseType: "Person",
|
|
970
|
-
bitWidth: 0,
|
|
971
|
-
isArray: false,
|
|
972
|
-
isConst: false,
|
|
973
|
-
},
|
|
974
|
-
],
|
|
975
|
-
]);
|
|
976
|
-
const symbols = createMockSymbols({
|
|
977
|
-
knownStructs: new Set(["Person"]),
|
|
978
|
-
});
|
|
979
|
-
const ctx = createMockPostfixExpressionContext("person", [
|
|
980
|
-
createMockPostfixOp({ identifier: "name" }),
|
|
981
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
982
|
-
]);
|
|
983
|
-
const input = createMockInput({ symbols, typeRegistry });
|
|
984
|
-
const state = createMockState();
|
|
985
|
-
const orchestrator = createMockOrchestrator({
|
|
986
|
-
generatePrimaryExpr: () => "person",
|
|
987
|
-
isKnownStruct: (name) => name === "Person",
|
|
988
|
-
getMemberTypeInfo: () => ({
|
|
989
|
-
baseType: "string<32>",
|
|
990
|
-
isArray: false,
|
|
991
|
-
bitWidth: 32,
|
|
992
|
-
isConst: false,
|
|
993
|
-
}),
|
|
994
|
-
getStructFieldInfo: () => ({
|
|
995
|
-
type: "string<32>",
|
|
996
|
-
dimensions: [32],
|
|
997
|
-
}),
|
|
998
|
-
});
|
|
999
|
-
|
|
1000
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
1001
|
-
expect(result.code).toBe("strlen(person.name)");
|
|
1002
|
-
expect(result.effects).toContainEqual({
|
|
1003
|
-
type: "include",
|
|
1004
|
-
header: "string",
|
|
1005
|
-
});
|
|
1006
|
-
});
|
|
1007
|
-
|
|
1008
|
-
it("returns first dimension for multi-dimensional string struct field at depth 0", () => {
|
|
1009
|
-
const typeRegistry = new Map<string, TTypeInfo>([
|
|
1010
|
-
[
|
|
1011
|
-
"data",
|
|
1012
|
-
{
|
|
1013
|
-
baseType: "Data",
|
|
1014
|
-
bitWidth: 0,
|
|
1015
|
-
isArray: false,
|
|
1016
|
-
isConst: false,
|
|
1017
|
-
},
|
|
1018
|
-
],
|
|
1019
|
-
]);
|
|
1020
|
-
const symbols = createMockSymbols({
|
|
1021
|
-
knownStructs: new Set(["Data"]),
|
|
1022
|
-
});
|
|
1023
|
-
const ctx = createMockPostfixExpressionContext("data", [
|
|
1024
|
-
createMockPostfixOp({ identifier: "names" }),
|
|
1025
|
-
createMockPostfixOp({ identifier: "length" }),
|
|
1026
|
-
]);
|
|
1027
|
-
const input = createMockInput({ symbols, typeRegistry });
|
|
1028
|
-
const state = createMockState();
|
|
1029
|
-
const orchestrator = createMockOrchestrator({
|
|
1030
|
-
generatePrimaryExpr: () => "data",
|
|
1031
|
-
isKnownStruct: (name) => name === "Data",
|
|
1032
|
-
getMemberTypeInfo: () => ({
|
|
1033
|
-
baseType: "string<32>",
|
|
1034
|
-
isArray: true,
|
|
1035
|
-
bitWidth: 32,
|
|
1036
|
-
isConst: false,
|
|
1037
|
-
}),
|
|
1038
|
-
getStructFieldInfo: () => ({
|
|
1039
|
-
type: "string<32>",
|
|
1040
|
-
dimensions: [5, 32],
|
|
1041
|
-
}),
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
|
-
const result = generatePostfixExpression(ctx, input, state, orchestrator);
|
|
1045
|
-
expect(result.code).toBe("5");
|
|
612
|
+
expect(() =>
|
|
613
|
+
generatePostfixExpression(ctx, input, state, orchestrator),
|
|
614
|
+
).toThrow("'.length' on 'val' is deprecated");
|
|
1046
615
|
});
|
|
1047
616
|
});
|
|
1048
617
|
|
package/src/transpiler/output/codegen/generators/expressions/__tests__/UnaryExprGenerator.test.ts
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for UnaryExprGenerator
|
|
3
|
+
*
|
|
4
|
+
* Tests bitwise NOT (~) MISRA-compliant cast generation:
|
|
5
|
+
* - Unsigned types get cast back to original type (MISRA 10.1/10.3)
|
|
6
|
+
* - Signed types and unresolvable types are unchanged
|
|
7
|
+
* - C++ mode uses static_cast
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
11
|
+
import generateUnaryExpr from "../UnaryExprGenerator";
|
|
12
|
+
import type { UnaryExpressionContext } from "../../../../../logic/parser/grammar/CNextParser";
|
|
13
|
+
import type IGeneratorInput from "../../IGeneratorInput";
|
|
14
|
+
import type IGeneratorState from "../../IGeneratorState";
|
|
15
|
+
import type IOrchestrator from "../../IOrchestrator";
|
|
16
|
+
import CodeGenState from "../../../../../state/CodeGenState";
|
|
17
|
+
|
|
18
|
+
vi.mock("../../../TypeResolver", () => {
|
|
19
|
+
return {
|
|
20
|
+
default: {
|
|
21
|
+
getUnaryExpressionType: vi.fn(),
|
|
22
|
+
isUnsignedType: vi.fn(),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
import TypeResolver from "../../../TypeResolver";
|
|
28
|
+
|
|
29
|
+
// ========================================================================
|
|
30
|
+
// Test Helpers
|
|
31
|
+
// ========================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a mock UnaryExpressionContext for a prefix unary expression.
|
|
35
|
+
* The node has no postfixExpression (prefix case) and a child unaryExpression.
|
|
36
|
+
*/
|
|
37
|
+
function createMockUnaryNode(fullText: string): UnaryExpressionContext {
|
|
38
|
+
const innerUnary = {} as UnaryExpressionContext;
|
|
39
|
+
return {
|
|
40
|
+
postfixExpression: () => null,
|
|
41
|
+
unaryExpression: () => innerUnary,
|
|
42
|
+
getText: () => fullText,
|
|
43
|
+
} as unknown as UnaryExpressionContext;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const mockInput = {} as IGeneratorInput;
|
|
47
|
+
const mockState = {} as IGeneratorState;
|
|
48
|
+
|
|
49
|
+
function createMockOrchestrator(innerResult: string): IOrchestrator {
|
|
50
|
+
return {
|
|
51
|
+
generateUnaryExpr: () => innerResult,
|
|
52
|
+
generatePostfixExpr: () => "",
|
|
53
|
+
} as unknown as IOrchestrator;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ========================================================================
|
|
57
|
+
// Tests
|
|
58
|
+
// ========================================================================
|
|
59
|
+
|
|
60
|
+
describe("UnaryExprGenerator", () => {
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
vi.mocked(TypeResolver.getUnaryExpressionType).mockReset();
|
|
63
|
+
vi.mocked(TypeResolver.isUnsignedType).mockReset();
|
|
64
|
+
CodeGenState.cppMode = false;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("bitwise NOT on unsigned types", () => {
|
|
68
|
+
it("should cast ~u8 to (uint8_t)~c in C mode", () => {
|
|
69
|
+
vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("u8");
|
|
70
|
+
vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(true);
|
|
71
|
+
|
|
72
|
+
const node = createMockUnaryNode("~c");
|
|
73
|
+
const orchestrator = createMockOrchestrator("c");
|
|
74
|
+
const result = generateUnaryExpr(
|
|
75
|
+
node,
|
|
76
|
+
mockInput,
|
|
77
|
+
mockState,
|
|
78
|
+
orchestrator,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(result.code).toBe("(uint8_t)~c");
|
|
82
|
+
expect(result.effects).toEqual([]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should cast ~u16 to (uint16_t)~c in C mode", () => {
|
|
86
|
+
vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("u16");
|
|
87
|
+
vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(true);
|
|
88
|
+
|
|
89
|
+
const node = createMockUnaryNode("~c");
|
|
90
|
+
const orchestrator = createMockOrchestrator("c");
|
|
91
|
+
const result = generateUnaryExpr(
|
|
92
|
+
node,
|
|
93
|
+
mockInput,
|
|
94
|
+
mockState,
|
|
95
|
+
orchestrator,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(result.code).toBe("(uint16_t)~c");
|
|
99
|
+
expect(result.effects).toEqual([]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should use static_cast in C++ mode", () => {
|
|
103
|
+
CodeGenState.cppMode = true;
|
|
104
|
+
vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("u8");
|
|
105
|
+
vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(true);
|
|
106
|
+
|
|
107
|
+
const node = createMockUnaryNode("~c");
|
|
108
|
+
const orchestrator = createMockOrchestrator("c");
|
|
109
|
+
const result = generateUnaryExpr(
|
|
110
|
+
node,
|
|
111
|
+
mockInput,
|
|
112
|
+
mockState,
|
|
113
|
+
orchestrator,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(result.code).toBe("static_cast<uint8_t>(~c)");
|
|
117
|
+
expect(result.effects).toEqual([]);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("bitwise NOT on signed/unresolvable types", () => {
|
|
122
|
+
it("should not cast ~i8 (signed type)", () => {
|
|
123
|
+
vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue("i8");
|
|
124
|
+
vi.mocked(TypeResolver.isUnsignedType).mockReturnValue(false);
|
|
125
|
+
|
|
126
|
+
const node = createMockUnaryNode("~c");
|
|
127
|
+
const orchestrator = createMockOrchestrator("c");
|
|
128
|
+
const result = generateUnaryExpr(
|
|
129
|
+
node,
|
|
130
|
+
mockInput,
|
|
131
|
+
mockState,
|
|
132
|
+
orchestrator,
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(result.code).toBe("~c");
|
|
136
|
+
expect(result.effects).toEqual([]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should not cast when type is unresolvable", () => {
|
|
140
|
+
vi.mocked(TypeResolver.getUnaryExpressionType).mockReturnValue(null);
|
|
141
|
+
|
|
142
|
+
const node = createMockUnaryNode("~expr");
|
|
143
|
+
const orchestrator = createMockOrchestrator("expr");
|
|
144
|
+
const result = generateUnaryExpr(
|
|
145
|
+
node,
|
|
146
|
+
mockInput,
|
|
147
|
+
mockState,
|
|
148
|
+
orchestrator,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
expect(result.code).toBe("~expr");
|
|
152
|
+
expect(result.effects).toEqual([]);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe("other unary operators", () => {
|
|
157
|
+
it("should generate logical NOT unchanged", () => {
|
|
158
|
+
const node = createMockUnaryNode("!flag");
|
|
159
|
+
const orchestrator = createMockOrchestrator("flag");
|
|
160
|
+
const result = generateUnaryExpr(
|
|
161
|
+
node,
|
|
162
|
+
mockInput,
|
|
163
|
+
mockState,
|
|
164
|
+
orchestrator,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
expect(result.code).toBe("!flag");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should generate negation unchanged", () => {
|
|
171
|
+
const node = createMockUnaryNode("-x");
|
|
172
|
+
const orchestrator = createMockOrchestrator("x");
|
|
173
|
+
const result = generateUnaryExpr(
|
|
174
|
+
node,
|
|
175
|
+
mockInput,
|
|
176
|
+
mockState,
|
|
177
|
+
orchestrator,
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
expect(result.code).toBe("-x");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should generate address-of unchanged", () => {
|
|
184
|
+
const node = createMockUnaryNode("&x");
|
|
185
|
+
const orchestrator = createMockOrchestrator("x");
|
|
186
|
+
const result = generateUnaryExpr(
|
|
187
|
+
node,
|
|
188
|
+
mockInput,
|
|
189
|
+
mockState,
|
|
190
|
+
orchestrator,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
expect(result.code).toBe("&x");
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
@@ -212,6 +212,9 @@ class ParameterInputAdapter {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
// Issue #914: Callback typedef overrides — param carries resolved pointer/const info
|
|
216
|
+
const isCallbackPointer = param.isCallbackPointer ?? false;
|
|
217
|
+
|
|
215
218
|
return {
|
|
216
219
|
name: param.name,
|
|
217
220
|
baseType: param.type,
|
|
@@ -221,8 +224,10 @@ class ParameterInputAdapter {
|
|
|
221
224
|
isArray: false,
|
|
222
225
|
isCallback: false,
|
|
223
226
|
isString: false,
|
|
224
|
-
isPassByValue: deps.isPassByValue,
|
|
225
|
-
isPassByReference: !deps.isPassByValue,
|
|
227
|
+
isPassByValue: isCallbackPointer ? false : deps.isPassByValue,
|
|
228
|
+
isPassByReference: isCallbackPointer ? true : !deps.isPassByValue,
|
|
229
|
+
forcePointerSyntax: isCallbackPointer || undefined,
|
|
230
|
+
forceConst: param.isCallbackConst || undefined,
|
|
226
231
|
};
|
|
227
232
|
}
|
|
228
233
|
|