c-next 0.1.68 → 0.1.70

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 (62) hide show
  1. package/package.json +1 -1
  2. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -204
  3. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +693 -0
  4. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +86 -5
  5. package/src/transpiler/{output/codegen → logic/analysis}/helpers/AssignmentTargetExtractor.ts +1 -1
  6. package/src/transpiler/{output/codegen → logic/analysis}/helpers/ChildStatementCollector.ts +1 -1
  7. package/src/transpiler/{output/codegen → logic/analysis}/helpers/StatementExpressionCollector.ts +1 -1
  8. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/AssignmentTargetExtractor.test.ts +2 -2
  9. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/ChildStatementCollector.test.ts +2 -2
  10. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/StatementExpressionCollector.test.ts +2 -2
  11. package/src/transpiler/output/codegen/CodeGenerator.ts +160 -742
  12. package/src/transpiler/output/codegen/TypeRegistrationUtils.ts +4 -6
  13. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  14. package/src/transpiler/output/codegen/TypeValidator.ts +7 -7
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +2 -2
  16. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +29 -1
  17. package/src/transpiler/output/codegen/__tests__/TypeRegistrationUtils.test.ts +36 -51
  18. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +20 -17
  19. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +4 -6
  20. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +4 -2
  21. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  22. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  23. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +9 -9
  24. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +12 -12
  25. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +11 -11
  26. package/src/transpiler/output/codegen/assignment/AssignmentContextBuilder.ts +49 -0
  27. package/src/transpiler/output/codegen/assignment/IAssignmentContext.ts +15 -0
  28. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +30 -17
  29. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +25 -18
  30. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +19 -8
  31. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +3 -3
  32. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +4 -4
  33. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +5 -5
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +9 -1
  35. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +41 -26
  36. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +29 -37
  37. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +27 -19
  38. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +10 -1
  39. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +51 -33
  40. package/src/transpiler/output/codegen/assignment/handlers/__tests__/StringHandlers.test.ts +9 -1
  41. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +5 -4
  42. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
  43. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
  44. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +21 -4
  45. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
  46. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +2 -1
  47. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +2 -2
  48. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +3 -3
  49. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  50. package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +6 -1
  51. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
  52. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  53. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +7 -7
  54. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +7 -7
  55. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
  56. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
  57. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +2 -2
  58. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
  59. package/src/transpiler/state/CodeGenState.ts +157 -5
  60. package/src/transpiler/state/__tests__/CodeGenState.test.ts +274 -6
  61. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/TransitiveModificationPropagator.ts +0 -0
  62. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/TransitiveModificationPropagator.test.ts +0 -0
@@ -6,6 +6,27 @@ import { describe, it, expect, beforeEach } from "vitest";
6
6
  import CodeGenState from "../CodeGenState";
7
7
  import TTypeInfo from "../../output/codegen/types/TTypeInfo";
8
8
  import ICodeGenSymbols from "../../types/ICodeGenSymbols";
9
+ import ESymbolKind from "../../../utils/types/ESymbolKind";
10
+ import ESourceLanguage from "../../../utils/types/ESourceLanguage";
11
+ import ISymbol from "../../../utils/types/ISymbol";
12
+
13
+ /**
14
+ * Create a minimal ISymbol for testing with required fields.
15
+ */
16
+ function createTestSymbol(
17
+ overrides: Partial<ISymbol> & {
18
+ name: string;
19
+ kind: ESymbolKind;
20
+ sourceLanguage: ESourceLanguage;
21
+ },
22
+ ): ISymbol {
23
+ return {
24
+ sourceFile: "test.cnx",
25
+ sourceLine: 1,
26
+ isExported: false,
27
+ ...overrides,
28
+ };
29
+ }
9
30
 
10
31
  /**
11
32
  * Create a minimal mock ICodeGenSymbols with default empty collections.
@@ -110,7 +131,7 @@ describe("CodeGenState", () => {
110
131
 
111
132
  it("getScopeMembers returns members for known scope", () => {
112
133
  const members = new Set(["member1", "member2"]);
113
- CodeGenState.scopeMembers.set("TestScope", members);
134
+ CodeGenState.setScopeMembers("TestScope", members);
114
135
 
115
136
  expect(CodeGenState.getScopeMembers("TestScope")).toBe(members);
116
137
  });
@@ -122,14 +143,14 @@ describe("CodeGenState", () => {
122
143
 
123
144
  it("isCurrentScopeMember returns false for non-member", () => {
124
145
  CodeGenState.currentScope = "TestScope";
125
- CodeGenState.scopeMembers.set("TestScope", new Set(["member1"]));
146
+ CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
126
147
 
127
148
  expect(CodeGenState.isCurrentScopeMember("nonMember")).toBe(false);
128
149
  });
129
150
 
130
151
  it("isCurrentScopeMember returns true for member", () => {
131
152
  CodeGenState.currentScope = "TestScope";
132
- CodeGenState.scopeMembers.set("TestScope", new Set(["member1"]));
153
+ CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
133
154
 
134
155
  expect(CodeGenState.isCurrentScopeMember("member1")).toBe(true);
135
156
  });
@@ -143,14 +164,14 @@ describe("CodeGenState", () => {
143
164
 
144
165
  it("returns identifier unchanged when not a scope member", () => {
145
166
  CodeGenState.currentScope = "TestScope";
146
- CodeGenState.scopeMembers.set("TestScope", new Set(["member1"]));
167
+ CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
147
168
 
148
169
  expect(CodeGenState.resolveIdentifier("varName")).toBe("varName");
149
170
  });
150
171
 
151
172
  it("returns scoped name for scope member", () => {
152
173
  CodeGenState.currentScope = "TestScope";
153
- CodeGenState.scopeMembers.set("TestScope", new Set(["member1"]));
174
+ CodeGenState.setScopeMembers("TestScope", new Set(["member1"]));
154
175
 
155
176
  expect(CodeGenState.resolveIdentifier("member1")).toBe(
156
177
  "TestScope_member1",
@@ -281,7 +302,7 @@ describe("CodeGenState", () => {
281
302
 
282
303
  CodeGenState.registerType("myVar", typeInfo);
283
304
 
284
- expect(CodeGenState.typeRegistry.get("myVar")).toBe(typeInfo);
305
+ expect(CodeGenState.getVariableTypeInfo("myVar")).toBe(typeInfo);
285
306
  });
286
307
 
287
308
  it("registerConstValue adds to constValues", () => {
@@ -348,6 +369,253 @@ describe("CodeGenState", () => {
348
369
  });
349
370
  });
350
371
 
372
+ describe("Variable Type Info API (Issue #786)", () => {
373
+ it("getVariableTypeInfo returns local type info from registry", () => {
374
+ const typeInfo: TTypeInfo = {
375
+ baseType: "u32",
376
+ bitWidth: 32,
377
+ isArray: false,
378
+ isConst: false,
379
+ };
380
+
381
+ CodeGenState.setVariableTypeInfo("localVar", typeInfo);
382
+
383
+ expect(CodeGenState.getVariableTypeInfo("localVar")).toBe(typeInfo);
384
+ });
385
+
386
+ it("getVariableTypeInfo returns undefined for unknown variable", () => {
387
+ expect(CodeGenState.getVariableTypeInfo("unknownVar")).toBeUndefined();
388
+ });
389
+
390
+ it("getVariableTypeInfo falls back to SymbolTable for C-Next variables", () => {
391
+ // Add a C-Next variable to SymbolTable (simulating cross-file include)
392
+ CodeGenState.symbolTable.addSymbol(
393
+ createTestSymbol({
394
+ name: "crossFileVar",
395
+ kind: ESymbolKind.Variable,
396
+ type: "u16",
397
+ sourceLanguage: ESourceLanguage.CNext,
398
+ isArray: true,
399
+ arrayDimensions: ["10"],
400
+ }),
401
+ );
402
+
403
+ const result = CodeGenState.getVariableTypeInfo("crossFileVar");
404
+
405
+ expect(result).toBeDefined();
406
+ expect(result?.baseType).toBe("u16");
407
+ expect(result?.bitWidth).toBe(16);
408
+ expect(result?.isArray).toBe(true);
409
+ expect(result?.arrayDimensions).toEqual([10]);
410
+ });
411
+
412
+ it("getVariableTypeInfo does not use C header symbols", () => {
413
+ // Add a C header variable (should NOT be used)
414
+ CodeGenState.symbolTable.addSymbol(
415
+ createTestSymbol({
416
+ name: "cHeaderVar",
417
+ kind: ESymbolKind.Variable,
418
+ type: "uint32_t",
419
+ sourceLanguage: ESourceLanguage.C,
420
+ }),
421
+ );
422
+
423
+ expect(CodeGenState.getVariableTypeInfo("cHeaderVar")).toBeUndefined();
424
+ });
425
+
426
+ it("getVariableTypeInfo prefers local registry over SymbolTable", () => {
427
+ // Add both local and SymbolTable version
428
+ const localInfo: TTypeInfo = {
429
+ baseType: "i32",
430
+ bitWidth: 32,
431
+ isArray: false,
432
+ isConst: true,
433
+ };
434
+ CodeGenState.setVariableTypeInfo("mixedVar", localInfo);
435
+
436
+ CodeGenState.symbolTable.addSymbol(
437
+ createTestSymbol({
438
+ name: "mixedVar",
439
+ kind: ESymbolKind.Variable,
440
+ type: "u8",
441
+ sourceLanguage: ESourceLanguage.CNext,
442
+ }),
443
+ );
444
+
445
+ // Should return local info, not SymbolTable info
446
+ const result = CodeGenState.getVariableTypeInfo("mixedVar");
447
+ expect(result?.baseType).toBe("i32");
448
+ expect(result?.isConst).toBe(true);
449
+ });
450
+
451
+ it("hasVariableTypeInfo returns true for local registry", () => {
452
+ CodeGenState.setVariableTypeInfo("localVar", {
453
+ baseType: "u8",
454
+ bitWidth: 8,
455
+ isArray: false,
456
+ isConst: false,
457
+ });
458
+
459
+ expect(CodeGenState.hasVariableTypeInfo("localVar")).toBe(true);
460
+ });
461
+
462
+ it("hasVariableTypeInfo returns true for C-Next SymbolTable variable", () => {
463
+ CodeGenState.symbolTable.addSymbol(
464
+ createTestSymbol({
465
+ name: "crossFileVar",
466
+ kind: ESymbolKind.Variable,
467
+ type: "u32",
468
+ sourceLanguage: ESourceLanguage.CNext,
469
+ }),
470
+ );
471
+
472
+ expect(CodeGenState.hasVariableTypeInfo("crossFileVar")).toBe(true);
473
+ });
474
+
475
+ it("hasVariableTypeInfo returns false for unknown variable", () => {
476
+ expect(CodeGenState.hasVariableTypeInfo("unknownVar")).toBe(false);
477
+ });
478
+
479
+ it("hasVariableTypeInfo returns false for C header variable", () => {
480
+ CodeGenState.symbolTable.addSymbol(
481
+ createTestSymbol({
482
+ name: "cVar",
483
+ kind: ESymbolKind.Variable,
484
+ type: "int",
485
+ sourceLanguage: ESourceLanguage.C,
486
+ }),
487
+ );
488
+
489
+ expect(CodeGenState.hasVariableTypeInfo("cVar")).toBe(false);
490
+ });
491
+
492
+ it("setVariableTypeInfo and deleteVariableTypeInfo work correctly", () => {
493
+ const typeInfo: TTypeInfo = {
494
+ baseType: "f32",
495
+ bitWidth: 32,
496
+ isArray: false,
497
+ isConst: false,
498
+ };
499
+
500
+ CodeGenState.setVariableTypeInfo("tempVar", typeInfo);
501
+ expect(CodeGenState.getVariableTypeInfo("tempVar")).toBe(typeInfo);
502
+
503
+ CodeGenState.deleteVariableTypeInfo("tempVar");
504
+ expect(CodeGenState.getVariableTypeInfo("tempVar")).toBeUndefined();
505
+ });
506
+
507
+ it("getTypeRegistryView returns readonly view", () => {
508
+ CodeGenState.setVariableTypeInfo("var1", {
509
+ baseType: "u8",
510
+ bitWidth: 8,
511
+ isArray: false,
512
+ isConst: false,
513
+ });
514
+ CodeGenState.setVariableTypeInfo("var2", {
515
+ baseType: "u16",
516
+ bitWidth: 16,
517
+ isArray: false,
518
+ isConst: false,
519
+ });
520
+
521
+ const view = CodeGenState.getTypeRegistryView();
522
+
523
+ expect(view.size).toBe(2);
524
+ expect(view.has("var1")).toBe(true);
525
+ expect(view.has("var2")).toBe(true);
526
+ });
527
+
528
+ it("getTypeInfo is deprecated alias for getVariableTypeInfo", () => {
529
+ const typeInfo: TTypeInfo = {
530
+ baseType: "u64",
531
+ bitWidth: 64,
532
+ isArray: false,
533
+ isConst: false,
534
+ };
535
+
536
+ CodeGenState.setVariableTypeInfo("aliasVar", typeInfo);
537
+
538
+ // getTypeInfo should return same result
539
+ expect(CodeGenState.getTypeInfo("aliasVar")).toBe(typeInfo);
540
+ });
541
+
542
+ it("convertSymbolToTypeInfo handles string<N> types", () => {
543
+ CodeGenState.symbolTable.addSymbol(
544
+ createTestSymbol({
545
+ name: "myString",
546
+ kind: ESymbolKind.Variable,
547
+ type: "string<32>",
548
+ sourceLanguage: ESourceLanguage.CNext,
549
+ }),
550
+ );
551
+
552
+ const result = CodeGenState.getVariableTypeInfo("myString");
553
+
554
+ expect(result?.baseType).toBe("char");
555
+ expect(result?.bitWidth).toBe(8);
556
+ expect(result?.isString).toBe(true);
557
+ expect(result?.stringCapacity).toBe(32);
558
+ });
559
+
560
+ it("convertSymbolToTypeInfo handles enum types", () => {
561
+ // Register an enum
562
+ CodeGenState.symbols = createMockSymbols({
563
+ knownEnums: new Set(["EColor"]),
564
+ });
565
+
566
+ CodeGenState.symbolTable.addSymbol(
567
+ createTestSymbol({
568
+ name: "color",
569
+ kind: ESymbolKind.Variable,
570
+ type: "EColor",
571
+ sourceLanguage: ESourceLanguage.CNext,
572
+ }),
573
+ );
574
+
575
+ const result = CodeGenState.getVariableTypeInfo("color");
576
+
577
+ expect(result?.baseType).toBe("EColor");
578
+ expect(result?.isEnum).toBe(true);
579
+ expect(result?.enumTypeName).toBe("EColor");
580
+ });
581
+
582
+ it("convertSymbolToTypeInfo handles const and atomic", () => {
583
+ CodeGenState.symbolTable.addSymbol(
584
+ createTestSymbol({
585
+ name: "constAtomicVar",
586
+ kind: ESymbolKind.Variable,
587
+ type: "u32",
588
+ sourceLanguage: ESourceLanguage.CNext,
589
+ isConst: true,
590
+ isAtomic: true,
591
+ }),
592
+ );
593
+
594
+ const result = CodeGenState.getVariableTypeInfo("constAtomicVar");
595
+
596
+ expect(result?.isConst).toBe(true);
597
+ expect(result?.isAtomic).toBe(true);
598
+ });
599
+
600
+ it("convertSymbolToTypeInfo filters invalid array dimensions", () => {
601
+ CodeGenState.symbolTable.addSymbol(
602
+ createTestSymbol({
603
+ name: "arrayVar",
604
+ kind: ESymbolKind.Variable,
605
+ type: "u8",
606
+ sourceLanguage: ESourceLanguage.CNext,
607
+ isArray: true,
608
+ arrayDimensions: ["10", "invalid", "20"],
609
+ }),
610
+ );
611
+
612
+ const result = CodeGenState.getVariableTypeInfo("arrayVar");
613
+
614
+ // Should only include valid numeric dimensions
615
+ expect(result?.arrayDimensions).toEqual([10, 20]);
616
+ });
617
+ });
618
+
351
619
  describe("Overflow Operation Helpers", () => {
352
620
  it("markClampOpUsed adds to usedClampOps", () => {
353
621
  CodeGenState.markClampOpUsed("add", "u8");