c-next 0.2.10 → 0.2.11
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 +148 -25
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +5 -0
- package/src/transpiler/logic/symbols/SymbolTable.ts +66 -0
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +55 -0
- package/src/transpiler/logic/symbols/c/__tests__/PointerTypedef.test.ts +47 -0
- package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +62 -19
- package/src/transpiler/logic/symbols/c/index.ts +25 -3
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +17 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +9 -0
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +6 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +9 -3
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +2 -0
- package/src/transpiler/state/CodeGenState.ts +9 -0
- package/src/transpiler/types/ICachedFileEntry.ts +2 -0
- package/src/utils/cache/CacheManager.ts +9 -1
- package/src/utils/cache/__tests__/CacheManager.test.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { hideBin } from "yargs/helpers";
|
|
|
10
10
|
// package.json
|
|
11
11
|
var package_default = {
|
|
12
12
|
name: "c-next",
|
|
13
|
-
version: "0.2.
|
|
13
|
+
version: "0.2.11",
|
|
14
14
|
description: "A safer C for embedded systems development. Transpiles to clean, readable C.",
|
|
15
15
|
packageManager: "npm@11.9.0",
|
|
16
16
|
type: "module",
|
|
@@ -109971,6 +109971,14 @@ var SymbolTable = class {
|
|
|
109971
109971
|
* These are "opaque" types that can only be used as pointers.
|
|
109972
109972
|
*/
|
|
109973
109973
|
opaqueTypes = /* @__PURE__ */ new Set();
|
|
109974
|
+
/**
|
|
109975
|
+
* Issue #958: Track typedef struct type names with their source files.
|
|
109976
|
+
* Maps typeName -> sourceFile. Used for scope variables which should be pointers
|
|
109977
|
+
* when the struct definition comes from a different file than the typedef.
|
|
109978
|
+
* If definition is in the same file as typedef, the entry is removed (value type).
|
|
109979
|
+
* If definition is in a different file, the entry remains (pointer type).
|
|
109980
|
+
*/
|
|
109981
|
+
typedefStructTypes = /* @__PURE__ */ new Map();
|
|
109974
109982
|
/**
|
|
109975
109983
|
* Issue #948: Track struct tag -> typedef name relationships.
|
|
109976
109984
|
* When a typedef declares an alias for a struct tag (e.g., typedef struct _foo foo_t),
|
|
@@ -110666,6 +110674,56 @@ Rename the C-Next symbol to resolve.`
|
|
|
110666
110674
|
return this.structTagAliases.get(structTag);
|
|
110667
110675
|
}
|
|
110668
110676
|
// ========================================================================
|
|
110677
|
+
// Issue #958: Typedef Struct Type Tracking
|
|
110678
|
+
// ========================================================================
|
|
110679
|
+
/**
|
|
110680
|
+
* Issue #958: Mark a typedef as aliasing a struct type.
|
|
110681
|
+
* Records the source file to enable same-file vs cross-file distinction.
|
|
110682
|
+
* @param typedefName The typedef name (e.g., "widget_t")
|
|
110683
|
+
* @param sourceFile The file where the typedef was declared
|
|
110684
|
+
*/
|
|
110685
|
+
markTypedefStructType(typedefName, sourceFile) {
|
|
110686
|
+
this.typedefStructTypes.set(typedefName, sourceFile);
|
|
110687
|
+
}
|
|
110688
|
+
/**
|
|
110689
|
+
* Issue #958: Unmark a typedef struct type when full definition is found.
|
|
110690
|
+
* Only unmarks if the definition is in the SAME file as the typedef declaration.
|
|
110691
|
+
* Cross-file definitions keep the typedef marked (pointer semantics).
|
|
110692
|
+
* @param typeName The typedef name to unmark
|
|
110693
|
+
* @param sourceFile The file where the definition was found
|
|
110694
|
+
*/
|
|
110695
|
+
unmarkTypedefStructType(typeName, sourceFile) {
|
|
110696
|
+
const typedefFile = this.typedefStructTypes.get(typeName);
|
|
110697
|
+
if (typedefFile === sourceFile) {
|
|
110698
|
+
this.typedefStructTypes.delete(typeName);
|
|
110699
|
+
}
|
|
110700
|
+
}
|
|
110701
|
+
/**
|
|
110702
|
+
* Issue #958: Check if a typedef aliases a struct type.
|
|
110703
|
+
* Used for scope variables which should be pointers for external struct types.
|
|
110704
|
+
* @param typeName The type name to check
|
|
110705
|
+
* @returns true if this is a typedef'd struct type from C headers
|
|
110706
|
+
*/
|
|
110707
|
+
isTypedefStructType(typeName) {
|
|
110708
|
+
return this.typedefStructTypes.has(typeName);
|
|
110709
|
+
}
|
|
110710
|
+
/**
|
|
110711
|
+
* Issue #958: Get all typedef struct types for cache serialization.
|
|
110712
|
+
* @returns Map entries as [typeName, sourceFile] pairs
|
|
110713
|
+
*/
|
|
110714
|
+
getAllTypedefStructTypes() {
|
|
110715
|
+
return Array.from(this.typedefStructTypes.entries());
|
|
110716
|
+
}
|
|
110717
|
+
/**
|
|
110718
|
+
* Issue #958: Restore typedef struct types from cache.
|
|
110719
|
+
* @param entries Array of [typeName, sourceFile] pairs
|
|
110720
|
+
*/
|
|
110721
|
+
restoreTypedefStructTypes(entries) {
|
|
110722
|
+
for (const [name, sourceFile] of entries) {
|
|
110723
|
+
this.typedefStructTypes.set(name, sourceFile);
|
|
110724
|
+
}
|
|
110725
|
+
}
|
|
110726
|
+
// ========================================================================
|
|
110669
110727
|
// Enum Bit Width Tracking
|
|
110670
110728
|
// ========================================================================
|
|
110671
110729
|
/**
|
|
@@ -110785,6 +110843,7 @@ Rename the C-Next symbol to resolve.`
|
|
|
110785
110843
|
this.opaqueTypes.clear();
|
|
110786
110844
|
this.structTagAliases.clear();
|
|
110787
110845
|
this.enumBitWidth.clear();
|
|
110846
|
+
this.typedefStructTypes.clear();
|
|
110788
110847
|
}
|
|
110789
110848
|
};
|
|
110790
110849
|
var SymbolTable_default = SymbolTable;
|
|
@@ -111136,6 +111195,14 @@ var CodeGenState = class {
|
|
|
111136
111195
|
static isOpaqueType(typeName) {
|
|
111137
111196
|
return this.symbols?.opaqueTypes.has(typeName) ?? false;
|
|
111138
111197
|
}
|
|
111198
|
+
/**
|
|
111199
|
+
* Issue #958: Check if a type name is an external typedef struct type.
|
|
111200
|
+
* External typedef struct types should use pointer semantics for scope variables.
|
|
111201
|
+
* Unlike isOpaqueType, this returns true for both forward-declared and complete structs.
|
|
111202
|
+
*/
|
|
111203
|
+
static isTypedefStructType(typeName) {
|
|
111204
|
+
return this.symbolTable?.isTypedefStructType(typeName) ?? false;
|
|
111205
|
+
}
|
|
111139
111206
|
/**
|
|
111140
111207
|
* Get type info for a variable.
|
|
111141
111208
|
* Checks local typeRegistry first, then falls back to SymbolTable
|
|
@@ -118067,7 +118134,8 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
|
|
|
118067
118134
|
let type = orchestrator.generateType(varDecl.type());
|
|
118068
118135
|
const fullName = QualifiedNameGenerator_default.forMember(scopeName, varName);
|
|
118069
118136
|
const isOpaque = orchestrator.isOpaqueType(type);
|
|
118070
|
-
|
|
118137
|
+
const isExternalStruct = orchestrator.isTypedefStructType(type);
|
|
118138
|
+
if (isOpaque || isExternalStruct) {
|
|
118071
118139
|
type = `${type}*`;
|
|
118072
118140
|
orchestrator.markOpaqueScopeVariable(fullName);
|
|
118073
118141
|
}
|
|
@@ -118082,7 +118150,7 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
|
|
|
118082
118150
|
decl += orchestrator.generateArrayDimensions(arrayDims);
|
|
118083
118151
|
}
|
|
118084
118152
|
decl += ArrayDimensionUtils_default.generateStringCapacityDim(varDecl.type());
|
|
118085
|
-
if (isOpaque) {
|
|
118153
|
+
if (isOpaque || isExternalStruct) {
|
|
118086
118154
|
decl += " = NULL";
|
|
118087
118155
|
} else {
|
|
118088
118156
|
decl += generateInitializer(varDecl, isArray, orchestrator);
|
|
@@ -128797,6 +128865,14 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
128797
128865
|
isOpaqueType(typeName) {
|
|
128798
128866
|
return CodeGenState.isOpaqueType(typeName);
|
|
128799
128867
|
}
|
|
128868
|
+
/**
|
|
128869
|
+
* Issue #958: Check if a type is an external typedef struct type.
|
|
128870
|
+
* Used for scope variables which should always be pointers for external struct types.
|
|
128871
|
+
* Part of IOrchestrator interface.
|
|
128872
|
+
*/
|
|
128873
|
+
isTypedefStructType(typeName) {
|
|
128874
|
+
return CodeGenState.isTypedefStructType(typeName);
|
|
128875
|
+
}
|
|
128800
128876
|
/**
|
|
128801
128877
|
* Issue #948: Mark a scope variable as having an opaque type.
|
|
128802
128878
|
* These variables are generated as pointers with NULL initialization.
|
|
@@ -133680,6 +133756,18 @@ var DeclaratorUtils = class _DeclaratorUtils {
|
|
|
133680
133756
|
if (!firstDeclarator) return void 0;
|
|
133681
133757
|
return _DeclaratorUtils.extractDeclaratorName(firstDeclarator) ?? void 0;
|
|
133682
133758
|
}
|
|
133759
|
+
/**
|
|
133760
|
+
* Check if the first declarator in an init-declarator-list has a pointer.
|
|
133761
|
+
* For "typedef struct X *handle_t;", the declarator is "*handle_t" which has a pointer.
|
|
133762
|
+
* Used for Issue #957 to distinguish pointer typedefs from opaque struct typedefs.
|
|
133763
|
+
*/
|
|
133764
|
+
static firstDeclaratorHasPointer(initDeclList) {
|
|
133765
|
+
const initDeclarators = initDeclList.initDeclarator?.();
|
|
133766
|
+
if (!initDeclarators || initDeclarators.length === 0) return false;
|
|
133767
|
+
const firstDeclarator = initDeclarators[0].declarator?.();
|
|
133768
|
+
if (!firstDeclarator) return false;
|
|
133769
|
+
return Boolean(firstDeclarator.pointer?.());
|
|
133770
|
+
}
|
|
133683
133771
|
};
|
|
133684
133772
|
var DeclaratorUtils_default = DeclaratorUtils;
|
|
133685
133773
|
|
|
@@ -133692,11 +133780,10 @@ var StructCollector2 = class _StructCollector {
|
|
|
133692
133780
|
* @param sourceFile Source file path
|
|
133693
133781
|
* @param line Source line number
|
|
133694
133782
|
* @param symbolTable Optional symbol table for field tracking
|
|
133695
|
-
* @param
|
|
133696
|
-
* @param isTypedef Whether this is part of a typedef declaration
|
|
133697
|
-
* @param warnings Array to collect warnings
|
|
133783
|
+
* @param options Optional collection options (typedef info, warnings)
|
|
133698
133784
|
*/
|
|
133699
|
-
static collect(structSpec, sourceFile, line, symbolTable,
|
|
133785
|
+
static collect(structSpec, sourceFile, line, symbolTable, options = {}) {
|
|
133786
|
+
const { typedefName, isTypedef, warnings, isPointerTypedef } = options;
|
|
133700
133787
|
const identifier = structSpec.Identifier();
|
|
133701
133788
|
const name = identifier?.getText() || typedefName;
|
|
133702
133789
|
if (!name) return null;
|
|
@@ -133710,15 +133797,14 @@ var StructCollector2 = class _StructCollector {
|
|
|
133710
133797
|
);
|
|
133711
133798
|
const needsStructKeyword = Boolean(identifier && !isTypedef);
|
|
133712
133799
|
if (symbolTable) {
|
|
133713
|
-
_StructCollector.updateSymbolTable(
|
|
133714
|
-
symbolTable,
|
|
133715
|
-
name,
|
|
133800
|
+
_StructCollector.updateSymbolTable(symbolTable, name, sourceFile, {
|
|
133716
133801
|
needsStructKeyword,
|
|
133717
133802
|
hasBody,
|
|
133718
133803
|
isTypedef,
|
|
133719
133804
|
typedefName,
|
|
133720
|
-
identifier?.getText()
|
|
133721
|
-
|
|
133805
|
+
structTag: identifier?.getText(),
|
|
133806
|
+
isPointerTypedef
|
|
133807
|
+
});
|
|
133722
133808
|
}
|
|
133723
133809
|
return {
|
|
133724
133810
|
kind: "struct",
|
|
@@ -133736,38 +133822,54 @@ var StructCollector2 = class _StructCollector {
|
|
|
133736
133822
|
* Update symbol table with struct metadata.
|
|
133737
133823
|
* Extracted to reduce cognitive complexity of collect().
|
|
133738
133824
|
*/
|
|
133739
|
-
static updateSymbolTable(symbolTable, name,
|
|
133825
|
+
static updateSymbolTable(symbolTable, name, sourceFile, options) {
|
|
133826
|
+
const {
|
|
133827
|
+
needsStructKeyword,
|
|
133828
|
+
hasBody,
|
|
133829
|
+
isTypedef,
|
|
133830
|
+
typedefName,
|
|
133831
|
+
structTag,
|
|
133832
|
+
isPointerTypedef
|
|
133833
|
+
} = options;
|
|
133740
133834
|
if (needsStructKeyword) {
|
|
133741
133835
|
symbolTable.markNeedsStructKeyword(name);
|
|
133742
133836
|
}
|
|
133743
|
-
if (isTypedef && !hasBody && typedefName) {
|
|
133837
|
+
if (isTypedef && !hasBody && typedefName && !isPointerTypedef) {
|
|
133744
133838
|
symbolTable.markOpaqueType(typedefName);
|
|
133745
133839
|
if (structTag) {
|
|
133746
133840
|
symbolTable.registerStructTagAlias(structTag, typedefName);
|
|
133747
133841
|
}
|
|
133748
133842
|
}
|
|
133843
|
+
if (isTypedef && typedefName && !isPointerTypedef) {
|
|
133844
|
+
symbolTable.markTypedefStructType(typedefName, sourceFile);
|
|
133845
|
+
}
|
|
133749
133846
|
if (hasBody) {
|
|
133750
133847
|
_StructCollector.unmarkOpaqueTypesOnDefinition(
|
|
133751
133848
|
symbolTable,
|
|
133849
|
+
sourceFile,
|
|
133752
133850
|
structTag,
|
|
133753
133851
|
typedefName
|
|
133754
133852
|
);
|
|
133755
133853
|
}
|
|
133756
133854
|
}
|
|
133757
133855
|
/**
|
|
133758
|
-
* Unmark opaque types when a full struct definition is encountered.
|
|
133856
|
+
* Unmark opaque and typedef struct types when a full struct definition is encountered.
|
|
133759
133857
|
* Handles: typedef struct _foo foo; struct _foo { ... };
|
|
133858
|
+
* Issue #958: Only unmarks typedefStructTypes when definition is in SAME file.
|
|
133760
133859
|
*/
|
|
133761
|
-
static unmarkOpaqueTypesOnDefinition(symbolTable, structTag, typedefName) {
|
|
133860
|
+
static unmarkOpaqueTypesOnDefinition(symbolTable, sourceFile, structTag, typedefName) {
|
|
133762
133861
|
if (structTag) {
|
|
133763
|
-
symbolTable.unmarkOpaqueType(structTag);
|
|
133764
133862
|
const typedefAlias = symbolTable.getStructTagAlias(structTag);
|
|
133863
|
+
symbolTable.unmarkOpaqueType(structTag);
|
|
133864
|
+
symbolTable.unmarkTypedefStructType(structTag, sourceFile);
|
|
133765
133865
|
if (typedefAlias) {
|
|
133766
133866
|
symbolTable.unmarkOpaqueType(typedefAlias);
|
|
133867
|
+
symbolTable.unmarkTypedefStructType(typedefAlias, sourceFile);
|
|
133767
133868
|
}
|
|
133768
133869
|
}
|
|
133769
133870
|
if (typedefName) {
|
|
133770
133871
|
symbolTable.unmarkOpaqueType(typedefName);
|
|
133872
|
+
symbolTable.unmarkTypedefStructType(typedefName, sourceFile);
|
|
133771
133873
|
}
|
|
133772
133874
|
}
|
|
133773
133875
|
/**
|
|
@@ -134154,14 +134256,18 @@ var CResolver = class _CResolver {
|
|
|
134154
134256
|
*/
|
|
134155
134257
|
static collectStructSymbol(structSpec, decl, declSpecs, ctx, symbolTable, warnings) {
|
|
134156
134258
|
const typedefName = ctx.isTypedef ? _CResolver.extractTypedefName(decl, declSpecs) : void 0;
|
|
134259
|
+
const isPointerTypedef = ctx.isTypedef ? _CResolver.isPointerTypedef(decl) : false;
|
|
134157
134260
|
const structSymbol = StructCollector_default2.collect(
|
|
134158
134261
|
structSpec,
|
|
134159
134262
|
ctx.sourceFile,
|
|
134160
134263
|
ctx.line,
|
|
134161
134264
|
symbolTable,
|
|
134162
|
-
|
|
134163
|
-
|
|
134164
|
-
|
|
134265
|
+
{
|
|
134266
|
+
typedefName,
|
|
134267
|
+
isTypedef: ctx.isTypedef,
|
|
134268
|
+
warnings,
|
|
134269
|
+
isPointerTypedef
|
|
134270
|
+
}
|
|
134165
134271
|
);
|
|
134166
134272
|
if (structSymbol) {
|
|
134167
134273
|
ctx.symbols.push(structSymbol);
|
|
@@ -134179,6 +134285,16 @@ var CResolver = class _CResolver {
|
|
|
134179
134285
|
}
|
|
134180
134286
|
return DeclaratorUtils_default.extractTypedefNameFromSpecs(declSpecs);
|
|
134181
134287
|
}
|
|
134288
|
+
/**
|
|
134289
|
+
* Check if a typedef declaration has a pointer declarator.
|
|
134290
|
+
* For "typedef struct X *Y", the declarator is "*Y" which has a pointer.
|
|
134291
|
+
* Used for Issue #957 to distinguish pointer typedefs from opaque struct typedefs.
|
|
134292
|
+
*/
|
|
134293
|
+
static isPointerTypedef(decl) {
|
|
134294
|
+
const initDeclList = decl.initDeclaratorList();
|
|
134295
|
+
if (!initDeclList) return false;
|
|
134296
|
+
return DeclaratorUtils_default.firstDeclaratorHasPointer(initDeclList);
|
|
134297
|
+
}
|
|
134182
134298
|
/**
|
|
134183
134299
|
* Collect enum symbols from an enum specifier.
|
|
134184
134300
|
* Extracted to reduce cognitive complexity of collectDeclaration().
|
|
@@ -138880,7 +138996,7 @@ var CacheKeyGenerator_default = CacheKeyGenerator;
|
|
|
138880
138996
|
|
|
138881
138997
|
// src/utils/cache/CacheManager.ts
|
|
138882
138998
|
var defaultFs7 = NodeFileSystem_default.instance;
|
|
138883
|
-
var CACHE_VERSION =
|
|
138999
|
+
var CACHE_VERSION = 6;
|
|
138884
139000
|
var TRANSPILER_VERSION = package_default.version;
|
|
138885
139001
|
var CacheManager = class {
|
|
138886
139002
|
projectRoot;
|
|
@@ -138981,14 +139097,15 @@ var CacheManager = class {
|
|
|
138981
139097
|
structFields,
|
|
138982
139098
|
needsStructKeyword: cachedEntry.needsStructKeyword ?? [],
|
|
138983
139099
|
enumBitWidth,
|
|
138984
|
-
opaqueTypes: cachedEntry.opaqueTypes ?? []
|
|
139100
|
+
opaqueTypes: cachedEntry.opaqueTypes ?? [],
|
|
139101
|
+
typedefStructTypes: cachedEntry.typedefStructTypes ?? []
|
|
138985
139102
|
};
|
|
138986
139103
|
}
|
|
138987
139104
|
/**
|
|
138988
139105
|
* Store symbols and struct fields for a file
|
|
138989
139106
|
* ADR-055 Phase 7: Takes ISerializedSymbol[] directly
|
|
138990
139107
|
*/
|
|
138991
|
-
setSymbols(filePath, symbols, structFields, needsStructKeyword, enumBitWidth, opaqueTypes) {
|
|
139108
|
+
setSymbols(filePath, symbols, structFields, needsStructKeyword, enumBitWidth, opaqueTypes, typedefStructTypes) {
|
|
138992
139109
|
if (!this.cache) return;
|
|
138993
139110
|
let cacheKey;
|
|
138994
139111
|
try {
|
|
@@ -139017,7 +139134,8 @@ var CacheManager = class {
|
|
|
139017
139134
|
structFields: serializedFields,
|
|
139018
139135
|
needsStructKeyword,
|
|
139019
139136
|
enumBitWidth: serializedEnumBitWidth,
|
|
139020
|
-
opaqueTypes
|
|
139137
|
+
opaqueTypes,
|
|
139138
|
+
typedefStructTypes
|
|
139021
139139
|
};
|
|
139022
139140
|
this.cache.setKey(filePath, entry);
|
|
139023
139141
|
this.dirty = true;
|
|
@@ -139046,13 +139164,15 @@ var CacheManager = class {
|
|
|
139046
139164
|
symbolTable
|
|
139047
139165
|
);
|
|
139048
139166
|
const opaqueTypes = symbolTable.getAllOpaqueTypes();
|
|
139167
|
+
const typedefStructTypes = symbolTable.getAllTypedefStructTypes();
|
|
139049
139168
|
this.setSymbols(
|
|
139050
139169
|
filePath,
|
|
139051
139170
|
symbols,
|
|
139052
139171
|
structFields,
|
|
139053
139172
|
needsStructKeyword,
|
|
139054
139173
|
enumBitWidth,
|
|
139055
|
-
opaqueTypes
|
|
139174
|
+
opaqueTypes,
|
|
139175
|
+
typedefStructTypes
|
|
139056
139176
|
);
|
|
139057
139177
|
}
|
|
139058
139178
|
/**
|
|
@@ -140109,6 +140229,9 @@ var Transpiler = class {
|
|
|
140109
140229
|
);
|
|
140110
140230
|
CodeGenState.symbolTable.restoreEnumBitWidths(cached.enumBitWidth);
|
|
140111
140231
|
CodeGenState.symbolTable.restoreOpaqueTypes(cached.opaqueTypes);
|
|
140232
|
+
CodeGenState.symbolTable.restoreTypedefStructTypes(
|
|
140233
|
+
cached.typedefStructTypes
|
|
140234
|
+
);
|
|
140112
140235
|
this.detectCppFromFileType(file);
|
|
140113
140236
|
return true;
|
|
140114
140237
|
}
|