import * as fs from 'node:fs'; import { STRUCTURE_FILES, EXTENSION, INDENT } from './common'; import { getStructure } from './map'; import { Struct } from './struct'; // Arguments if (process.argv.length < 5) { console.log('USAGE: npm start --
'); process.exit(1); } process.argv.shift(); process.argv.shift(); function invalidFileType(file: string) { throw new Error(`Invalid File Type: ${file}`); } const sourceOutput = process.argv.shift()!; if (!sourceOutput.endsWith('.cpp')) { invalidFileType(sourceOutput); } const headerOutput = process.argv.shift()!; if (!headerOutput.endsWith('.h')) { invalidFileType(headerOutput); } const extraHeaders: string[] = []; while (process.argv.length > 0) { const file = process.argv.shift()!; if (file.endsWith(EXTENSION)) { // Get Class Name const parts = file.split('/'); let name = parts[parts.length - 1]!; name = name.substring(0, name.length - EXTENSION.length); // Store if (name in STRUCTURE_FILES) { throw new Error(`Multiple Definition Files Provided: ${name}${EXTENSION}`); } STRUCTURE_FILES[name] = file; } else if (file.endsWith('.h')) { // Extra Headers extraHeaders.push(file); } else { // Invalid File Type invalidFileType(file); } } // Load And Sort Structures function loadSymbols() { // Load const structureObjects = []; for (const name in STRUCTURE_FILES) { structureObjects.push(getStructure(name)); } // Sort structureObjects.sort((a, b) => { if (a.getName() > b.getName()) { return 1; } else if (a.getName() < b.getName()) { return -1; } else { return 0; } }); // Return return structureObjects; } // Sort Structures By Dependency function dependencySort(structureObjects: Struct[]) { let loops = 0; const MAX_LOOPS = 100; while (true) { if (loops > MAX_LOOPS) { throw new Error('Unable To Sort Dependencies'); } loops++; let valid = true; // Loop Through Structures for (const structure of structureObjects) { // Loop Through Dependencies const currentIndex = structureObjects.indexOf(structure); for (const dependency of structure.getDependencies()) { // Compare Current And Dependency Index const obj = getStructure(dependency); const dependencyIndex = structureObjects.indexOf(obj); if (dependencyIndex > currentIndex) { // Dependency Must Be Moved structureObjects.splice(dependencyIndex, 1); structureObjects.splice(currentIndex, 0, obj); valid = false; break; } } // Check If Any Changes Were Made if (!valid) { break; } } // Check If Any Changes Were Made if (valid) { break; } } } // Generate Part Of Header function makeHeaderPart() { // Load Symbols const structureObjects = loadSymbols(); // Sort Structures By Dependency dependencySort(structureObjects); // Generate Code let structures = ''; let isFirst = true; for (const structure of structureObjects) { const name = structure.getName(); if (isFirst) { isFirst = false; } else { structures += '\n'; } structures += `// ${name}\n`; try { structures += structure.generate(); } catch (e) { console.log(`Error Generating Header: ${name}: ${e instanceof Error ? e.stack : e}`); process.exit(1); } } // Return let result = ''; result += '// Init\n'; result += 'void init_symbols();\n\n'; result += structures; return result; } // Create Main Header function makeMainHeader(output: string) { let result = ''; result += '#pragma once\n'; result += '\n// Check Architecture\n'; result += '#ifndef __arm__\n'; result += '#error "Symbols Are ARM-Only"\n'; result += '#endif\n'; result += '\n// Shortcuts\n'; result += 'typedef unsigned char uchar;\n'; result += 'typedef unsigned short ushort;\n'; result += 'typedef unsigned int uint;\n'; result += '\n// Forward Declarations\n'; for (const name in STRUCTURE_FILES) { result += `typedef struct ${name} ${name};\n`; } result += '\n// Extra Headers\n'; for (const file of extraHeaders) { result += fs.readFileSync(file, {encoding: 'utf8'}); } result += '\n// Headers\n'; result += '#include \n'; result += '#include \n'; result += '#include \n'; result += '#include \n'; result += '\n// Warnings\n'; result += '#pragma GCC diagnostic push\n'; result += '#pragma GCC diagnostic ignored "-Winvalid-offsetof"\n\n'; result += makeHeaderPart(); result += '\n// Cleanup Warnings\n'; result += '#pragma GCC diagnostic pop\n'; result += '\n// Array Of All Method Symbols\n'; result += 'extern void *_all_method_symbols[];\n'; fs.writeFileSync(output, result); } makeMainHeader(headerOutput); // Generate Compiled Code function makeCompiledCode(output: string) { // Load Symbols const structureObjects = loadSymbols(); // Generate let declarations = ''; let init = ''; let isFirst = true; for (const structure of structureObjects) { const name = structure.getName(); if (isFirst) { isFirst = false; } else { declarations += '\n'; init += '\n'; } declarations += `// ${name}\n`; init += `${INDENT}// ${name}\n`; try { const code = structure.generateCode(); declarations += code.functions; init += code.init; } catch (e) { console.log(`Error Generating Code: ${name}: ${e instanceof Error ? e.stack : e}`); process.exit(1); } } // Write let result = ''; result += `#include "${fs.realpathSync(headerOutput)}"\n`; result += '\n#include \n'; result += '\n// Init\n'; result += 'void init_symbols() {\n'; result += init; result += '}\n\n'; result += declarations; result += '\n// Setup Methods Array\n'; result += 'void *_all_method_symbols[] = {\n'; for (const structure of structureObjects) { const methods = structure.getMethodSymbols(); for (const method of methods) { result += `${INDENT}&${method},\n`; } } result += `${INDENT}nullptr\n`; result += '};\n'; fs.writeFileSync(output, result); } makeCompiledCode(sourceOutput);