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.
Files changed (37) hide show
  1. package/dist/index.js +387 -433
  2. package/dist/index.js.map +4 -4
  3. package/package.json +1 -1
  4. package/src/transpiler/Transpiler.ts +50 -29
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -1
  6. package/src/transpiler/data/PathResolver.ts +10 -6
  7. package/src/transpiler/data/__tests__/PathResolver.test.ts +32 -0
  8. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +1 -12
  9. package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +239 -0
  10. package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +414 -0
  11. package/src/transpiler/logic/analysis/__tests__/StructFieldAnalyzer.test.ts +15 -75
  12. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +3 -15
  13. package/src/transpiler/logic/analysis/runAnalyzers.ts +11 -2
  14. package/src/transpiler/logic/analysis/types/ISignedShiftError.ts +15 -0
  15. package/src/transpiler/logic/symbols/SymbolUtils.ts +4 -1
  16. package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +10 -11
  17. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +4 -4
  18. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +4 -4
  19. package/src/transpiler/output/codegen/CodeGenerator.ts +12 -4
  20. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +3 -3
  21. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +26 -26
  22. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +12 -11
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +21 -21
  24. package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +7 -326
  25. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +14 -275
  26. package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +13 -1
  27. package/src/transpiler/output/codegen/generators/expressions/__tests__/AccessExprGenerator.test.ts +0 -573
  28. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +8 -439
  29. package/src/transpiler/output/codegen/generators/expressions/__tests__/UnaryExprGenerator.test.ts +196 -0
  30. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +7 -2
  31. package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +34 -0
  32. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +48 -0
  33. package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +88 -0
  34. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +15 -2
  35. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +87 -0
  36. package/src/utils/ExpressionUtils.ts +51 -0
  37. package/src/utils/types/IParameterSymbol.ts +2 -0
@@ -112,14 +112,13 @@ describe("SymbolUtils", () => {
112
112
 
113
113
  // ========================================================================
114
114
  // Reserved Field Names
115
+ // ADR-058: .length removed, so "length" is no longer reserved
115
116
  // ========================================================================
116
117
 
117
118
  describe("isReservedFieldName", () => {
118
- it("should return true for reserved names", () => {
119
- expect(SymbolUtils.isReservedFieldName("length")).toBe(true);
120
- });
121
-
122
- it("should return false for non-reserved names", () => {
119
+ it("should return false for all names (no reserved names after ADR-058)", () => {
120
+ // "length" is no longer reserved since .length was deprecated
121
+ expect(SymbolUtils.isReservedFieldName("length")).toBe(false);
123
122
  expect(SymbolUtils.isReservedFieldName("x")).toBe(false);
124
123
  expect(SymbolUtils.isReservedFieldName("data")).toBe(false);
125
124
  expect(SymbolUtils.isReservedFieldName("size")).toBe(false);
@@ -128,10 +127,10 @@ describe("SymbolUtils", () => {
128
127
  });
129
128
 
130
129
  describe("getReservedFieldNames", () => {
131
- it("should return array of reserved names", () => {
130
+ it("should return empty array (no reserved names after ADR-058)", () => {
132
131
  const reserved = SymbolUtils.getReservedFieldNames();
133
132
  expect(Array.isArray(reserved)).toBe(true);
134
- expect(reserved).toContain("length");
133
+ expect(reserved).toHaveLength(0);
135
134
  });
136
135
  });
137
136
 
@@ -140,11 +139,11 @@ describe("SymbolUtils", () => {
140
139
  const msg = SymbolUtils.getReservedFieldWarning(
141
140
  "C",
142
141
  "MyStruct",
143
- "length",
142
+ "someField",
144
143
  );
145
144
  expect(msg).toContain("C header struct");
146
145
  expect(msg).toContain("MyStruct");
147
- expect(msg).toContain("length");
146
+ expect(msg).toContain("someField");
148
147
  expect(msg).toContain("conflicts with C-Next");
149
148
  });
150
149
 
@@ -152,11 +151,11 @@ describe("SymbolUtils", () => {
152
151
  const msg = SymbolUtils.getReservedFieldWarning(
153
152
  "C++",
154
153
  "MyClass",
155
- "length",
154
+ "someField",
156
155
  );
157
156
  expect(msg).toContain("C++ header struct");
158
157
  expect(msg).toContain("MyClass");
159
- expect(msg).toContain("length");
158
+ expect(msg).toContain("someField");
160
159
  });
161
160
  });
162
161
  });
@@ -350,14 +350,14 @@ describe("CResolver - Struct Fields", () => {
350
350
  expect(fieldsMap?.get("inner")?.type).toBe("Inner");
351
351
  });
352
352
 
353
- it("warns about reserved field names", () => {
353
+ // ADR-058: "length" is no longer reserved since .length was deprecated
354
+ it("does not warn about 'length' field names after ADR-058", () => {
354
355
  const tree = TestHelpers.parseC(`struct Test { int length; };`);
355
356
  const symbolTable = new SymbolTable();
356
357
  const result = CResolver.resolve(tree!, "test.h", symbolTable);
357
358
 
358
- expect(result.warnings.length).toBeGreaterThan(0);
359
- expect(result.warnings[0]).toContain("length");
360
- expect(result.warnings[0]).toContain("conflicts with C-Next");
359
+ // No warnings since "length" is no longer reserved
360
+ expect(result.warnings.length).toBe(0);
361
361
  });
362
362
  });
363
363
 
@@ -255,16 +255,16 @@ describe("CppResolver", () => {
255
255
  });
256
256
  });
257
257
 
258
+ // ADR-058: "length" is no longer reserved since .length was deprecated
258
259
  describe("warnings", () => {
259
- it("warns about reserved field names", () => {
260
+ it("does not warn about 'length' field names after ADR-058", () => {
260
261
  const source = `class MyStruct { int length; };`;
261
262
  const tree = TestHelpers.parseCpp(source);
262
263
  expect(tree).not.toBeNull();
263
264
  const result = CppResolver.resolve(tree!, "test.hpp", symbolTable);
264
265
 
265
- expect(result.warnings).toHaveLength(1);
266
- expect(result.warnings[0]).toContain("length");
267
- expect(result.warnings[0]).toContain("MyStruct");
266
+ // No warnings since "length" is no longer reserved
267
+ expect(result.warnings).toHaveLength(0);
268
268
  });
269
269
  });
270
270
  });
@@ -749,17 +749,23 @@ export default class CodeGenerator implements IOrchestrator {
749
749
  */
750
750
  private _isArrayAccessStringExpression(text: string): boolean {
751
751
  // Pattern: identifier[expression] or identifier[expression][expression]...
752
- // BUT NOT if accessing .length/.capacity/.size (those return numbers, not strings)
752
+ // BUT NOT if accessing properties that return numbers, not strings
753
753
  const arrayAccessMatch = /^([a-zA-Z_]\w*)\[/.exec(text);
754
754
  if (!arrayAccessMatch) {
755
755
  return false;
756
756
  }
757
757
 
758
- // ADR-045: String properties return numeric values, not strings
758
+ // ADR-045/ADR-058: String/array properties return numeric values, not strings
759
+ // ADR-058: .length deprecated, replaced by .bit_length, .byte_length,
760
+ // .element_count, .char_count
759
761
  if (
760
762
  text.endsWith(".length") ||
761
763
  text.endsWith(".capacity") ||
762
- text.endsWith(".size")
764
+ text.endsWith(".size") ||
765
+ text.endsWith(".bit_length") ||
766
+ text.endsWith(".byte_length") ||
767
+ text.endsWith(".element_count") ||
768
+ text.endsWith(".char_count")
763
769
  ) {
764
770
  return false;
765
771
  }
@@ -2202,7 +2208,9 @@ export default class CodeGenerator implements IOrchestrator {
2202
2208
  const pathToUse =
2203
2209
  options?.sourceRelativePath ||
2204
2210
  CodeGenState.sourcePath.replace(/^.*[\\/]/, "");
2205
- const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ".h");
2211
+ // Issue #933: Use .hpp extension in C++ mode to match header file
2212
+ const ext = CodeGenState.cppMode ? ".hpp" : ".h";
2213
+ const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ext);
2206
2214
  output.push(`#include "${headerName}"`, "");
2207
2215
  CodeGenState.selfIncludeAdded = true;
2208
2216
  }
@@ -61,15 +61,15 @@ describe("CodeGenerator Coverage Tests", () => {
61
61
  // NEW CODE IN PR: _isArrayAccessStringExpression (lines 811-852)
62
62
  // ==========================================================================
63
63
  describe("_isArrayAccessStringExpression() - PR new code", () => {
64
- it("should return false for string property access (.length)", () => {
64
+ it("should return false for string property access (.char_count)", () => {
65
65
  const source = `
66
66
  string<32> name <- "test";
67
67
  void main() {
68
- u32 len <- name.length;
68
+ u32 len <- name.char_count;
69
69
  }
70
70
  `;
71
71
  const { code } = setupGenerator(source);
72
- // .length returns a number, not a string
72
+ // .char_count returns a number, not a string
73
73
  expect(code).toContain("strlen(name)");
74
74
  });
75
75
 
@@ -4719,11 +4719,11 @@ describe("CodeGenerator", () => {
4719
4719
  });
4720
4720
  });
4721
4721
 
4722
- describe("Array length", () => {
4723
- it("should generate array length using sizeof", () => {
4722
+ describe("Array element_count", () => {
4723
+ it("should generate array element_count using sizeof", () => {
4724
4724
  const source = `
4725
4725
  u32[10] data;
4726
- u32 len <- data.length;
4726
+ u32 len <- data.element_count;
4727
4727
  `;
4728
4728
  const { tree, tokenStream } = CNextSourceParser.parse(source);
4729
4729
  const generator = new CodeGenerator();
@@ -4735,7 +4735,7 @@ describe("CodeGenerator", () => {
4735
4735
  sourcePath: "test.cnx",
4736
4736
  });
4737
4737
 
4738
- // .length compiles to sizeof(arr)/sizeof(arr[0]) or constant
4738
+ // .element_count compiles to sizeof(arr)/sizeof(arr[0]) or constant
4739
4739
  expect(code).toContain("len =");
4740
4740
  });
4741
4741
  });
@@ -9750,7 +9750,7 @@ describe("CodeGenerator", () => {
9750
9750
  it("should resolve string parameter", () => {
9751
9751
  const source = `
9752
9752
  void test(string<32> name) {
9753
- u32 len <- name.length;
9753
+ u32 len <- name.char_count;
9754
9754
  }
9755
9755
  `;
9756
9756
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -10273,12 +10273,12 @@ describe("CodeGenerator", () => {
10273
10273
  });
10274
10274
  });
10275
10275
 
10276
- describe("string capacity helpers", () => {
10277
- it("should get string capacity for global string variable", () => {
10276
+ describe("string char_count helpers", () => {
10277
+ it("should get string char_count for global string variable", () => {
10278
10278
  const source = `
10279
10279
  string<64> message <- "Hello World";
10280
10280
  void test() {
10281
- u32 cap <- message.length;
10281
+ u32 cap <- message.char_count;
10282
10282
  }
10283
10283
  `;
10284
10284
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -10294,12 +10294,12 @@ describe("CodeGenerator", () => {
10294
10294
  expect(code).toContain("message[65]");
10295
10295
  });
10296
10296
 
10297
- it("should get string capacity for scoped string variable", () => {
10297
+ it("should get string char_count for scoped string variable", () => {
10298
10298
  const source = `
10299
10299
  scope Logger {
10300
10300
  string<128> buffer;
10301
10301
  public u32 getCapacity() {
10302
- return this.buffer.length;
10302
+ return this.buffer.char_count;
10303
10303
  }
10304
10304
  }
10305
10305
  `;
@@ -13098,13 +13098,13 @@ describe("CodeGenerator", () => {
13098
13098
  });
13099
13099
 
13100
13100
  describe("strlen optimization (_setupLengthCache)", () => {
13101
- it("should optimize multiple .length accesses on same string", () => {
13101
+ it("should optimize multiple .char_count accesses on same string", () => {
13102
13102
  const source = `
13103
13103
  void test() {
13104
13104
  string<32> name <- "hello";
13105
- u32 a <- name.length;
13106
- u32 b <- name.length;
13107
- u32 c <- name.length;
13105
+ u32 a <- name.char_count;
13106
+ u32 b <- name.char_count;
13107
+ u32 c <- name.char_count;
13108
13108
  }
13109
13109
  `;
13110
13110
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -13117,15 +13117,15 @@ describe("CodeGenerator", () => {
13117
13117
  sourcePath: "test.cnx",
13118
13118
  });
13119
13119
 
13120
- // Multiple .length accesses should be present
13120
+ // Multiple .char_count accesses should be present
13121
13121
  expect(code).toContain("strlen");
13122
13122
  });
13123
13123
 
13124
- it("should generate proper strlen call for single length access", () => {
13124
+ it("should generate proper strlen call for single char_count access", () => {
13125
13125
  const source = `
13126
13126
  void test() {
13127
13127
  string<32> msg <- "test";
13128
- u32 len <- msg.length;
13128
+ u32 len <- msg.char_count;
13129
13129
  }
13130
13130
  `;
13131
13131
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -13241,7 +13241,7 @@ describe("CodeGenerator", () => {
13241
13241
  it("should handle string parameter with capacity", () => {
13242
13242
  const source = `
13243
13243
  void greet(string<64> name) {
13244
- u32 len <- name.length;
13244
+ u32 len <- name.char_count;
13245
13245
  }
13246
13246
  `;
13247
13247
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -13726,8 +13726,8 @@ describe("CodeGenerator", () => {
13726
13726
  const source = `
13727
13727
  void test() {
13728
13728
  string<64> msg <- "hello world";
13729
- u32 len1 <- msg.length;
13730
- u32 len2 <- msg.length;
13729
+ u32 len1 <- msg.char_count;
13730
+ u32 len2 <- msg.char_count;
13731
13731
  }
13732
13732
  `;
13733
13733
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -13743,12 +13743,12 @@ describe("CodeGenerator", () => {
13743
13743
  expect(code).toContain("strlen");
13744
13744
  });
13745
13745
 
13746
- it("should generate cache for multiple .length accesses", () => {
13746
+ it("should generate cache for multiple .char_count accesses", () => {
13747
13747
  const source = `
13748
13748
  void test() {
13749
13749
  string<32> s <- "hello";
13750
- if (s.length > 0) {
13751
- u32 x <- s.length;
13750
+ if (s.char_count > 0) {
13751
+ u32 x <- s.char_count;
13752
13752
  }
13753
13753
  }
13754
13754
  `;
@@ -13762,15 +13762,15 @@ describe("CodeGenerator", () => {
13762
13762
  sourcePath: "test.cnx",
13763
13763
  });
13764
13764
 
13765
- // Should generate cache variable for repeated .length access
13765
+ // Should generate cache variable for repeated .char_count access
13766
13766
  expect(code).toContain("strlen");
13767
13767
  });
13768
13768
 
13769
- it("should not cache for single .length access", () => {
13769
+ it("should not cache for single .char_count access", () => {
13770
13770
  const source = `
13771
13771
  void test() {
13772
13772
  string<32> s <- "hello";
13773
- u32 len <- s.length;
13773
+ u32 len <- s.char_count;
13774
13774
  }
13775
13775
  `;
13776
13776
  const { tree, tokenStream } = CNextSourceParser.parse(source);
@@ -1,23 +1,24 @@
1
1
  /**
2
- * StringLengthCounter - Counts .length accesses on string variables
2
+ * StringLengthCounter - Counts .char_count accesses on string variables
3
3
  *
4
4
  * Issue #644: Extracted from CodeGenerator to reduce code duplication.
5
- * Used for strlen caching optimization - when a string's .length is accessed
5
+ * Used for strlen caching optimization - when a string's .char_count is accessed
6
6
  * multiple times, we cache the strlen result in a temp variable.
7
7
  *
8
8
  * Migrated to use CodeGenState instead of constructor DI.
9
+ * Updated for ADR-058: .length replaced with .char_count
9
10
  */
10
11
 
11
12
  import * as Parser from "../../../logic/parser/grammar/CNextParser";
12
13
  import CodeGenState from "../../../state/CodeGenState";
13
14
 
14
15
  /**
15
- * Counts .length accesses on string variables in an expression tree.
16
+ * Counts .char_count accesses on string variables in an expression tree.
16
17
  * This enables strlen caching optimization.
17
18
  */
18
19
  class StringLengthCounter {
19
20
  /**
20
- * Count .length accesses in an expression.
21
+ * Count .char_count accesses in an expression.
21
22
  */
22
23
  static countExpression(ctx: Parser.ExpressionContext): Map<string, number> {
23
24
  const counts = new Map<string, number>();
@@ -26,7 +27,7 @@ class StringLengthCounter {
26
27
  }
27
28
 
28
29
  /**
29
- * Count .length accesses in a block.
30
+ * Count .char_count accesses in a block.
30
31
  */
31
32
  static countBlock(ctx: Parser.BlockContext): Map<string, number> {
32
33
  const counts = new Map<string, number>();
@@ -37,7 +38,7 @@ class StringLengthCounter {
37
38
  }
38
39
 
39
40
  /**
40
- * Count .length accesses in a block, adding to existing counts.
41
+ * Count .char_count accesses in a block, adding to existing counts.
41
42
  */
42
43
  static countBlockInto(
43
44
  ctx: Parser.BlockContext,
@@ -49,7 +50,7 @@ class StringLengthCounter {
49
50
  }
50
51
 
51
52
  /**
52
- * Walk an expression tree, counting .length accesses.
53
+ * Walk an expression tree, counting .char_count accesses.
53
54
  * Uses generic traversal - only postfix expressions need special handling.
54
55
  */
55
56
  private static walkExpression(
@@ -177,7 +178,7 @@ class StringLengthCounter {
177
178
  }
178
179
 
179
180
  /**
180
- * Walk a postfix expression - this is where we detect .length accesses.
181
+ * Walk a postfix expression - this is where we detect .char_count accesses.
181
182
  */
182
183
  private static walkPostfixExpr(
183
184
  ctx: Parser.PostfixExpressionContext,
@@ -187,11 +188,11 @@ class StringLengthCounter {
187
188
  const primaryId = primary.IDENTIFIER()?.getText();
188
189
  const ops = ctx.postfixOp();
189
190
 
190
- // Check for pattern: identifier.length where identifier is a string
191
+ // Check for pattern: identifier.char_count where identifier is a string
191
192
  if (primaryId && ops.length > 0) {
192
193
  for (const op of ops) {
193
194
  const memberName = op.IDENTIFIER()?.getText();
194
- if (memberName === "length") {
195
+ if (memberName === "char_count") {
195
196
  // Check if this is a string type
196
197
  const typeInfo = CodeGenState.getVariableTypeInfo(primaryId);
197
198
  if (typeInfo?.isString) {
@@ -213,7 +214,7 @@ class StringLengthCounter {
213
214
  }
214
215
 
215
216
  /**
216
- * Walk a statement, counting .length accesses.
217
+ * Walk a statement, counting .char_count accesses.
217
218
  */
218
219
  private static walkStatement(
219
220
  ctx: Parser.StatementContext,
@@ -37,7 +37,7 @@ describe("StringLengthCounter", () => {
37
37
  });
38
38
 
39
39
  describe("countExpression", () => {
40
- it("counts single .length access on string variable", () => {
40
+ it("counts single .char_count access on string variable", () => {
41
41
  CodeGenState.setVariableTypeInfo("myStr", {
42
42
  baseType: "char",
43
43
  bitWidth: 8,
@@ -47,13 +47,13 @@ describe("StringLengthCounter", () => {
47
47
  stringCapacity: 64,
48
48
  });
49
49
 
50
- const expr = parseExpression("myStr.length");
50
+ const expr = parseExpression("myStr.char_count");
51
51
  const counts = StringLengthCounter.countExpression(expr);
52
52
 
53
53
  expect(counts.get("myStr")).toBe(1);
54
54
  });
55
55
 
56
- it("counts multiple .length accesses on same variable", () => {
56
+ it("counts multiple .char_count accesses on same variable", () => {
57
57
  CodeGenState.setVariableTypeInfo("str", {
58
58
  baseType: "char",
59
59
  bitWidth: 8,
@@ -63,14 +63,14 @@ describe("StringLengthCounter", () => {
63
63
  stringCapacity: 32,
64
64
  });
65
65
 
66
- // Expression: str.length + str.length
67
- const expr = parseExpression("str.length + str.length");
66
+ // Expression: str.char_count + str.char_count
67
+ const expr = parseExpression("str.char_count + str.char_count");
68
68
  const counts = StringLengthCounter.countExpression(expr);
69
69
 
70
70
  expect(counts.get("str")).toBe(2);
71
71
  });
72
72
 
73
- it("counts .length accesses on different string variables", () => {
73
+ it("counts .char_count accesses on different string variables", () => {
74
74
  CodeGenState.setVariableTypeInfo("a", {
75
75
  baseType: "char",
76
76
  bitWidth: 8,
@@ -88,14 +88,14 @@ describe("StringLengthCounter", () => {
88
88
  stringCapacity: 16,
89
89
  });
90
90
 
91
- const expr = parseExpression("a.length + b.length");
91
+ const expr = parseExpression("a.char_count + b.char_count");
92
92
  const counts = StringLengthCounter.countExpression(expr);
93
93
 
94
94
  expect(counts.get("a")).toBe(1);
95
95
  expect(counts.get("b")).toBe(1);
96
96
  });
97
97
 
98
- it("ignores .length on non-string variables", () => {
98
+ it("ignores .char_count on non-string variables", () => {
99
99
  CodeGenState.setVariableTypeInfo("arr", {
100
100
  baseType: "u8",
101
101
  bitWidth: 8,
@@ -104,7 +104,7 @@ describe("StringLengthCounter", () => {
104
104
  arrayDimensions: [10],
105
105
  });
106
106
 
107
- const expr = parseExpression("arr.length");
107
+ const expr = parseExpression("arr.char_count");
108
108
  const counts = StringLengthCounter.countExpression(expr);
109
109
 
110
110
  expect(counts.get("arr")).toBeUndefined();
@@ -126,7 +126,7 @@ describe("StringLengthCounter", () => {
126
126
 
127
127
  it("handles unknown variables gracefully", () => {
128
128
  // No type registered for "unknown"
129
- const expr = parseExpression("unknown.length");
129
+ const expr = parseExpression("unknown.char_count");
130
130
  const counts = StringLengthCounter.countExpression(expr);
131
131
 
132
132
  expect(counts.size).toBe(0);
@@ -134,7 +134,7 @@ describe("StringLengthCounter", () => {
134
134
  });
135
135
 
136
136
  describe("countBlock", () => {
137
- it("counts .length accesses across multiple statements", () => {
137
+ it("counts .char_count accesses across multiple statements", () => {
138
138
  CodeGenState.setVariableTypeInfo("msg", {
139
139
  baseType: "char",
140
140
  bitWidth: 8,
@@ -145,15 +145,15 @@ describe("StringLengthCounter", () => {
145
145
  });
146
146
 
147
147
  const block = parseBlock(`
148
- u32 len <- msg.length;
149
- u32 doubled <- msg.length * 2;
148
+ u32 len <- msg.char_count;
149
+ u32 doubled <- msg.char_count * 2;
150
150
  `);
151
151
  const counts = StringLengthCounter.countBlock(block);
152
152
 
153
153
  expect(counts.get("msg")).toBe(2);
154
154
  });
155
155
 
156
- it("counts .length in assignment statements", () => {
156
+ it("counts .char_count in assignment statements", () => {
157
157
  CodeGenState.setVariableTypeInfo("text", {
158
158
  baseType: "char",
159
159
  bitWidth: 8,
@@ -165,7 +165,7 @@ describe("StringLengthCounter", () => {
165
165
 
166
166
  const block = parseBlock(`
167
167
  u32 x;
168
- x <- text.length;
168
+ x <- text.char_count;
169
169
  `);
170
170
  const counts = StringLengthCounter.countBlock(block);
171
171
 
@@ -197,8 +197,8 @@ describe("StringLengthCounter", () => {
197
197
  counts.set("s1", 1);
198
198
 
199
199
  const block = parseBlock(`
200
- u32 a <- s1.length;
201
- u32 b <- s2.length;
200
+ u32 a <- s1.char_count;
201
+ u32 b <- s2.char_count;
202
202
  `);
203
203
  StringLengthCounter.countBlockInto(block, counts);
204
204
 
@@ -208,7 +208,7 @@ describe("StringLengthCounter", () => {
208
208
  });
209
209
 
210
210
  describe("nested expressions", () => {
211
- it("counts .length in ternary expressions", () => {
211
+ it("counts .char_count in ternary expressions", () => {
212
212
  CodeGenState.setVariableTypeInfo("str", {
213
213
  baseType: "char",
214
214
  bitWidth: 8,
@@ -218,13 +218,13 @@ describe("StringLengthCounter", () => {
218
218
  stringCapacity: 64,
219
219
  });
220
220
 
221
- const expr = parseExpression("(str.length > 0) ? str.length : 0");
221
+ const expr = parseExpression("(str.char_count > 0) ? str.char_count : 0");
222
222
  const counts = StringLengthCounter.countExpression(expr);
223
223
 
224
224
  expect(counts.get("str")).toBe(2);
225
225
  });
226
226
 
227
- it("counts .length in comparison expressions", () => {
227
+ it("counts .char_count in comparison expressions", () => {
228
228
  CodeGenState.setVariableTypeInfo("name", {
229
229
  baseType: "char",
230
230
  bitWidth: 8,
@@ -234,7 +234,7 @@ describe("StringLengthCounter", () => {
234
234
  stringCapacity: 50,
235
235
  });
236
236
 
237
- const expr = parseExpression("name.length = 10");
237
+ const expr = parseExpression("name.char_count = 10");
238
238
  const counts = StringLengthCounter.countExpression(expr);
239
239
 
240
240
  expect(counts.get("name")).toBe(1);