Эх сурвалжийг харах

[c] Codegen can export JSON (--export-json) and returns super and sub type info for each C type

Mario Zechner 1 сар өмнө
parent
commit
8b135f18bb

+ 114 - 2
spine-c/codegen/src/index.ts

@@ -7,6 +7,7 @@ import { isTypeExcluded, loadExclusions } from './exclusions';
 import { generateArrays, generateTypes } from './ir-generator';
 import { extractTypes } from './type-extractor';
 import type { ClassOrStruct } from './types';
+import { toSnakeCase } from './types';
 
 const __dirname = path.dirname(fileURLToPath(import.meta.url));
 
@@ -69,12 +70,123 @@ export async function generate() {
     // Generate C intermediate representation for classes, enums and arrays
     const { cTypes, cEnums } = await generateTypes(types, exclusions, allExtractedTypes);
     const cArrayTypes = await generateArrays(types, arrayType, exclusions);
-    return { cTypes, cEnums, cArrayTypes };
+
+    // Build inheritance relationships including template classes
+    const supertypes = buildSupertypesMap(allExtractedTypes.filter(t => t.kind !== 'enum') as ClassOrStruct[], types.filter(t => t.kind !== 'enum') as ClassOrStruct[]);
+
+    console.log('Built supertypes map with', Object.keys(supertypes).length, 'entries');
+    for (const [child, supertypeList] of Object.entries(supertypes)) {
+        if (child.includes('constraint')) {
+            console.log(`  ${child} -> [${supertypeList.join(', ')}]`);
+        }
+    }
+
+    // Build subtypes map (opposite of supertypes)  
+    const subtypes = buildSubtypesMap(supertypes);
+    
+    return { cTypes, cEnums, cArrayTypes, supertypes, subtypes };
+}
+
+/** Build supertypes map for inheritance relationships, including template classes */
+function buildSupertypesMap(allTypes: (ClassOrStruct)[], nonTemplateTypes: (ClassOrStruct)[]): Record<string, string[]> {
+    const supertypes: Record<string, string[]> = {};
+    const typeMap = new Map<string, ClassOrStruct>();
+
+    // Build type lookup map from all types (including templates)
+    for (const type of allTypes) {
+        typeMap.set(type.name, type);
+    }
+
+    // Build non-template type lookup for C names
+    const nonTemplateMap = new Map<string, ClassOrStruct>();
+    for (const type of nonTemplateTypes) {
+        nonTemplateMap.set(type.name, type);
+    }
+
+    // For each non-template type, find all non-template ancestors
+    for (const type of nonTemplateTypes) {
+        const classType = type;
+        const cName = `spine_${toSnakeCase(classType.name)}`;
+        const supertypeList = findNonTemplateSupertypes(classType, typeMap, nonTemplateMap);
+
+        if (supertypeList.length > 0) {
+            supertypes[cName] = supertypeList;
+        }
+    }
+
+    return supertypes;
+}
+
+/** Find all non-template supertypes for a given type */
+function findNonTemplateSupertypes(type: ClassOrStruct, typeMap: Map<string, ClassOrStruct>, nonTemplateMap: Map<string, ClassOrStruct>): string[] {
+    const visited = new Set<string>();
+    const supertypes: string[] = [];
+
+    function traverse(currentType: ClassOrStruct) {
+        if (visited.has(currentType.name)) return;
+        visited.add(currentType.name);
+
+        if (!currentType.superTypes) return;
+
+        for (const superTypeName of currentType.superTypes) {
+            // Extract base type name from templated types like "ConstraintGeneric<...>"
+            const baseTypeName = superTypeName.split('<')[0];
+            const superType = typeMap.get(baseTypeName);
+            if (!superType) continue;
+
+            // If this supertype is not a template and has bindings, add it to supertypes
+            if (!superType.isTemplate && nonTemplateMap.has(superType.name)) {
+                const cName = `spine_${toSnakeCase(superType.name)}`;
+                if (!supertypes.includes(cName)) {
+                    supertypes.push(cName);
+                }
+            }
+
+            // Continue traversing up the chain (through templates too)
+            traverse(superType);
+        }
+    }
+
+    traverse(type);
+    return supertypes;
+}
+
+/** Build subtypes map from supertypes data */
+function buildSubtypesMap(supertypes: Record<string, string[]>): Record<string, string[]> {
+    const subtypes: Record<string, string[]> = {};
+    
+    // For each type and its supertypes, add this type to each supertype's subtypes list
+    for (const [childType, supertypeList] of Object.entries(supertypes)) {
+        for (const supertype of supertypeList) {
+            if (!subtypes[supertype]) {
+                subtypes[supertype] = [];
+            }
+            if (!subtypes[supertype].includes(childType)) {
+                subtypes[supertype].push(childType);
+            }
+        }
+    }
+    
+    return subtypes;
 }
 
 async function main() {
+    // Check if we should just export JSON for debugging
+    if (process.argv.includes('--export-json')) {
+        // Suppress console output during generation
+        const originalLog = console.log;
+        console.log = () => {};
+
+        const { cTypes, cEnums, cArrayTypes, supertypes, subtypes } = await generate();
+
+        // Restore console.log and output JSON
+        console.log = originalLog;
+        console.log(JSON.stringify({ cTypes, cEnums, cArrayTypes, supertypes, subtypes }, null, 2));
+        return;
+    }
+
     // Generate C types and enums
-    const { cTypes, cEnums, cArrayTypes } = await generate();
+    const { cTypes, cEnums, cArrayTypes, supertypes, subtypes } = await generate();
 
     // Write all files to disk
     const cWriter = new CWriter(path.join(__dirname, '../../src/generated'));