c-next 0.2.14 → 0.2.16

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 (23) hide show
  1. package/dist/index.js +98 -17
  2. package/dist/index.js.map +2 -2
  3. package/package.json +1 -1
  4. package/src/transpiler/logic/symbols/SymbolTable.ts +37 -10
  5. package/src/transpiler/logic/symbols/SymbolUtils.ts +21 -8
  6. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +33 -0
  7. package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +2 -1
  8. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +28 -0
  9. package/src/transpiler/logic/symbols/c/collectors/VariableCollector.ts +12 -1
  10. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +2 -1
  11. package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +5 -2
  12. package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +5 -2
  13. package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +7 -2
  14. package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +4 -2
  15. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +2 -1
  16. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +6 -1
  17. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +5 -1
  18. package/src/transpiler/state/CodeGenState.ts +45 -3
  19. package/src/transpiler/state/__tests__/CodeGenState.test.ts +145 -3
  20. package/src/transpiler/types/symbols/c/ICFieldInfo.ts +6 -2
  21. package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +5 -2
  22. package/src/utils/ScopeUtils.ts +19 -0
  23. package/src/utils/__tests__/ScopeUtils.test.ts +10 -0
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { hideBin } from "yargs/helpers";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "c-next",
14
- version: "0.2.14",
14
+ version: "0.2.16",
15
15
  description: "A safer C for embedded systems development. Transpiles to clean, readable C.",
16
16
  packageManager: "npm@11.9.0",
17
17
  type: "module",
@@ -111792,19 +111792,17 @@ var SymbolTable = class {
111792
111792
  /**
111793
111793
  * Register struct fields in structFields map for cross-file type resolution.
111794
111794
  * Called automatically when adding struct symbols.
111795
+ * Issue #981: Now preserves string dimensions (macro names) for proper array detection.
111795
111796
  */
111796
111797
  registerStructFields(struct) {
111797
111798
  const cName = SymbolNameUtils_default.getTranspiledCName(struct);
111798
111799
  for (const [fieldName, fieldInfo] of struct.fields) {
111799
111800
  const typeString = TypeResolver_default.getTypeName(fieldInfo.type);
111800
- const numericDims = fieldInfo.dimensions?.filter(
111801
- (d) => typeof d === "number"
111802
- );
111803
111801
  this.addStructField(
111804
111802
  cName,
111805
111803
  fieldName,
111806
111804
  typeString,
111807
- numericDims && numericDims.length > 0 ? numericDims : void 0
111805
+ fieldInfo.dimensions && fieldInfo.dimensions.length > 0 ? fieldInfo.dimensions : void 0
111808
111806
  );
111809
111807
  }
111810
111808
  }
@@ -111917,6 +111915,7 @@ var SymbolTable = class {
111917
111915
  // ========================================================================
111918
111916
  /**
111919
111917
  * Add a C symbol to the table
111918
+ * Issue #981: Also register struct fields for type resolution
111920
111919
  */
111921
111920
  addCSymbol(symbol) {
111922
111921
  const existing = this.cSymbols.get(symbol.name);
@@ -111931,6 +111930,23 @@ var SymbolTable = class {
111931
111930
  } else {
111932
111931
  this.cSymbolsByFile.set(symbol.sourceFile, [symbol]);
111933
111932
  }
111933
+ if (symbol.kind === "struct" && symbol.fields) {
111934
+ this.registerCStructFields(symbol.name, symbol.fields);
111935
+ }
111936
+ }
111937
+ /**
111938
+ * Register C struct fields in structFields map for cross-file type resolution.
111939
+ * Issue #981: Required for macro-sized array field detection on local struct variables.
111940
+ */
111941
+ registerCStructFields(structName, fields) {
111942
+ for (const [fieldName, fieldInfo] of fields) {
111943
+ this.addStructField(
111944
+ structName,
111945
+ fieldName,
111946
+ fieldInfo.type,
111947
+ fieldInfo.arrayDimensions
111948
+ );
111949
+ }
111934
111950
  }
111935
111951
  /**
111936
111952
  * Add multiple C symbols at once
@@ -112265,11 +112281,12 @@ Rename the C-Next symbol to resolve.`
112265
112281
  // Struct Field Information
112266
112282
  // ========================================================================
112267
112283
  /**
112268
- * Add struct field information
112284
+ * Add struct field information.
112285
+ * Issue #981: Accept (number | string)[] for arrayDimensions to support macro-sized arrays.
112269
112286
  * @param structName Name of the struct
112270
112287
  * @param fieldName Name of the field
112271
112288
  * @param fieldType Type of the field (e.g., "uint32_t")
112272
- * @param arrayDimensions Optional array dimensions if field is an array
112289
+ * @param arrayDimensions Optional array dimensions - numbers for resolved, strings for macros
112273
112290
  */
112274
112291
  addStructField(structName, fieldName, fieldType, arrayDimensions) {
112275
112292
  let fields = this.structFields.get(structName);
@@ -112279,7 +112296,7 @@ Rename the C-Next symbol to resolve.`
112279
112296
  }
112280
112297
  fields.set(fieldName, {
112281
112298
  type: fieldType,
112282
- arrayDimensions
112299
+ arrayDimensions: arrayDimensions ? [...arrayDimensions] : void 0
112283
112300
  });
112284
112301
  }
112285
112302
  /**
@@ -112676,7 +112693,7 @@ var DEFAULT_TARGET = {
112676
112693
  hasLdrexStrex: false,
112677
112694
  hasBasepri: false
112678
112695
  };
112679
- var CodeGenState = class {
112696
+ var CodeGenState = class _CodeGenState {
112680
112697
  // ===========================================================================
112681
112698
  // GENERATOR REFERENCE (for handler access)
112682
112699
  // ===========================================================================
@@ -113043,6 +113060,19 @@ var CodeGenState = class {
113043
113060
  if (symbol?.kind === "variable" && symbol.type) {
113044
113061
  return this.convertTSymbolToTypeInfo(symbol);
113045
113062
  }
113063
+ const cSymbol = this.symbolTable.getCSymbol(name);
113064
+ if (cSymbol?.kind === "variable" && cSymbol.type) {
113065
+ const baseType = _CodeGenState.stripTrailingPointers(cSymbol.type);
113066
+ if (this.symbolTable.isTypedefStructType(baseType) || this.symbolTable.getStructFields(baseType)) {
113067
+ return {
113068
+ baseType,
113069
+ bitWidth: 0,
113070
+ isArray: cSymbol.isArray || false,
113071
+ isConst: cSymbol.isConst || false,
113072
+ isPointer: cSymbol.type.endsWith("*")
113073
+ };
113074
+ }
113075
+ }
113046
113076
  return void 0;
113047
113077
  }
113048
113078
  /**
@@ -113061,7 +113091,15 @@ var CodeGenState = class {
113061
113091
  return true;
113062
113092
  }
113063
113093
  const symbol = this.symbolTable.getTSymbol(name);
113064
- return symbol?.kind === "variable" && symbol.type !== void 0;
113094
+ if (symbol?.kind === "variable" && symbol.type !== void 0) {
113095
+ return true;
113096
+ }
113097
+ const cSymbol = this.symbolTable.getCSymbol(name);
113098
+ if (cSymbol?.kind === "variable" && cSymbol.type) {
113099
+ const baseType = _CodeGenState.stripTrailingPointers(cSymbol.type);
113100
+ return this.symbolTable.isTypedefStructType(baseType) || !!this.symbolTable.getStructFields(baseType);
113101
+ }
113102
+ return false;
113065
113103
  }
113066
113104
  /**
113067
113105
  * Set variable type info in the local registry.
@@ -113087,6 +113125,17 @@ var CodeGenState = class {
113087
113125
  * Convert a TSymbol IVariableSymbol to TTypeInfo for unified type lookups.
113088
113126
  * ADR-055 Phase 7: Works with typed TSymbol instead of ISymbol.
113089
113127
  */
113128
+ /**
113129
+ * Strip trailing pointer stars from a C type string (e.g., "font_t*" → "font_t").
113130
+ * Uses string operations instead of regex to avoid SonarCloud ReDoS flag (S5852).
113131
+ */
113132
+ static stripTrailingPointers(type) {
113133
+ let end = type.length;
113134
+ while (end > 0 && type[end - 1] === "*") {
113135
+ end--;
113136
+ }
113137
+ return type.slice(0, end).trim();
113138
+ }
113090
113139
  static convertTSymbolToTypeInfo(symbol) {
113091
113140
  const typeName = TypeResolver_default.getTypeName(symbol.type);
113092
113141
  const stringPattern = /^string<(\d+)>$/;
@@ -113643,6 +113692,22 @@ var ScopeUtils = class _ScopeUtils {
113643
113692
  return scope.name === "" && scope.parent === scope;
113644
113693
  }
113645
113694
  // ============================================================================
113695
+ // Visibility Utilities
113696
+ // ============================================================================
113697
+ /**
113698
+ * ADR-016: Get the default visibility for a scope member based on its type.
113699
+ *
113700
+ * Member-type-aware defaults reduce boilerplate:
113701
+ * - Functions: public by default (API surface)
113702
+ * - Variables/types: private by default (internal state)
113703
+ *
113704
+ * @param isFunction - Whether the member is a function declaration
113705
+ * @returns The default visibility for this member type
113706
+ */
113707
+ static getDefaultVisibility(isFunction) {
113708
+ return isFunction ? "public" : "private";
113709
+ }
113710
+ // ============================================================================
113646
113711
  // Path Utilities
113647
113712
  // ============================================================================
113648
113713
  /**
@@ -120029,7 +120094,9 @@ function generateEnumMembersFromAST(members, fullName, orchestrator) {
120029
120094
  return lines;
120030
120095
  }
120031
120096
  function processScopeMember(member, scopeName, input, state, orchestrator) {
120032
- const visibility = member.visibilityModifier()?.getText() || "private";
120097
+ const explicitVisibility = member.visibilityModifier()?.getText();
120098
+ const isFunction = member.functionDeclaration() !== null;
120099
+ const visibility = explicitVisibility ?? ScopeUtils_default.getDefaultVisibility(isFunction);
120033
120100
  const isPrivate = visibility === "private";
120034
120101
  if (member.variableDeclaration()) {
120035
120102
  const varDecl = member.variableDeclaration();
@@ -134528,7 +134595,9 @@ var ScopeCollector = class {
134528
134595
  const memberSymbols = [];
134529
134596
  for (const member of ctx.scopeMember()) {
134530
134597
  const visibilityMod = member.visibilityModifier();
134531
- const visibility = visibilityMod?.getText() ?? "private";
134598
+ const explicitVisibility = visibilityMod?.getText();
134599
+ const isFunction = member.functionDeclaration() !== null;
134600
+ const visibility = explicitVisibility ?? ScopeUtils_default.getDefaultVisibility(isFunction);
134532
134601
  const isPublic = visibility === "public";
134533
134602
  if (member.variableDeclaration()) {
134534
134603
  const varDecl = member.variableDeclaration();
@@ -135218,12 +135287,15 @@ var TSymbolInfoAdapter_default = TSymbolInfoAdapter;
135218
135287
  var RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set([]);
135219
135288
  function parseArrayDimensions2(text) {
135220
135289
  const dimensions = [];
135221
- const arrayMatches = text.match(/\[(\d+)\]/g);
135290
+ const arrayMatches = text.match(/\[([^\]]+)\]/g);
135222
135291
  if (arrayMatches) {
135223
135292
  for (const match of arrayMatches) {
135224
- const size = Number.parseInt(match.slice(1, -1), 10);
135225
- if (!Number.isNaN(size)) {
135226
- dimensions.push(size);
135293
+ const content = match.slice(1, -1).trim();
135294
+ const numericValue = Number.parseInt(content, 10);
135295
+ if (!Number.isNaN(numericValue) && String(numericValue) === content) {
135296
+ dimensions.push(numericValue);
135297
+ } else {
135298
+ dimensions.push(content);
135227
135299
  }
135228
135300
  }
135229
135301
  }
@@ -135421,6 +135493,7 @@ var DeclaratorUtils = class _DeclaratorUtils {
135421
135493
  }
135422
135494
  /**
135423
135495
  * Extract array dimensions from a declarator.
135496
+ * Issue #981: Returns (number | string)[] to support macro-sized arrays.
135424
135497
  */
135425
135498
  static extractArrayDimensions(declarator) {
135426
135499
  const directDecl = declarator.directDeclarator?.();
@@ -135949,6 +136022,8 @@ var VariableCollector2 = class {
135949
136022
  */
135950
136023
  static collect(name, baseType, declarator, sourceFile, line, isExtern) {
135951
136024
  const arrayDimensions = declarator ? DeclaratorUtils_default.extractArrayDimensions(declarator) : [];
136025
+ const hasPointer = declarator?.pointer?.() !== null && declarator?.pointer?.() !== void 0;
136026
+ const resolvedType = hasPointer ? `${baseType}*` : baseType;
135952
136027
  return {
135953
136028
  kind: "variable",
135954
136029
  name,
@@ -135956,7 +136031,7 @@ var VariableCollector2 = class {
135956
136031
  sourceLine: line,
135957
136032
  sourceLanguage: ESourceLanguage_default.C,
135958
136033
  isExported: !isExtern,
135959
- type: baseType,
136034
+ type: resolvedType,
135960
136035
  isArray: arrayDimensions.length > 0,
135961
136036
  arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : void 0,
135962
136037
  isExtern
@@ -135966,6 +136041,10 @@ var VariableCollector2 = class {
135966
136041
  * Collect a variable from declaration specifiers (when identifier appears as typedefName).
135967
136042
  * This handles the C grammar ambiguity where variable names can be parsed as typedef names.
135968
136043
  *
136044
+ * Note: No pointer detection here — this path handles declarations without an
136045
+ * initDeclaratorList. Pointer declarations (e.g., `font_t *ptr`) always produce
136046
+ * an initDeclaratorList (the `*` creates a declarator), so they go through collect().
136047
+ *
135969
136048
  * @param name Variable name
135970
136049
  * @param baseType Variable type
135971
136050
  * @param sourceFile Source file path
@@ -136569,6 +136648,7 @@ var DeclaratorUtils2 = class _DeclaratorUtils {
136569
136648
  }
136570
136649
  /**
136571
136650
  * Extract array dimensions from a declarator.
136651
+ * Issue #981: Returns (number | string)[] to support macro-sized arrays.
136572
136652
  */
136573
136653
  static extractArrayDimensions(declarator) {
136574
136654
  const ptrDecl = declarator.pointerDeclarator?.();
@@ -136586,6 +136666,7 @@ var DeclaratorUtils2 = class _DeclaratorUtils {
136586
136666
  }
136587
136667
  /**
136588
136668
  * Extract array dimensions from a noPointerDeclarator.
136669
+ * Issue #981: Returns (number | string)[] to support macro-sized arrays.
136589
136670
  */
136590
136671
  static extractArrayDimensionsFromNoPtr(noPtr) {
136591
136672
  return SymbolUtils_default.parseArrayDimensions(noPtr.getText());