import * as fs from 'node:fs'; import { STRUCTURE_FILES, EXTENSION, INDENT } from './common'; import { getStructure, setCppAllowed } from './map'; // Arguments if (process.argv.length < 5) { console.log('USAGE: npm run
'); 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 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; } // Generate Part Of Header function makeHeaderPart(allowCpp: boolean) { // Set Mode setCppAllowed(allowCpp); // Load Symbols const structureObjects = loadSymbols(); // Sort Structures By Dependency while (true) { 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 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 return structures; } // Create Main Header function makeMainHeader(output: string) { let result = ''; result += '#pragma once\n'; result += '\n// Suppress Warnings\n'; result += '#pragma GCC diagnostic push\n'; result += '#pragma GCC diagnostic ignored "-Wunused-variable"\n'; result += '#pragma GCC diagnostic ignored "-Wunused-function"\n'; result += '\n// Shortcuts\n'; result += 'typedef unsigned char uchar;\n'; result += 'typedef unsigned int uint;\n'; result += '\n// Init\n'; result += 'void init_symbols();\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// Switch Mode\n'; result += '#ifndef __cplusplus\n'; result += '\n// C Mode\n'; result += 'typedef uchar bool;\n\n'; result += makeHeaderPart(false); result += '\n// End C Mode\n'; result += '#else\n'; result += '\n// C++ Mode\n'; result += '#include \n'; result += '#include \n'; result += 'extern "C" {\n\n'; result += makeHeaderPart(true); result += '\n// End C++ Mode\n'; result += '}\n'; result += '#endif\n'; result += '\n// Stop Suppressing Warnings\n'; result += '#pragma GCC diagnostic pop\n'; fs.writeFileSync(output, result); } makeMainHeader(headerOutput); // Generate Compiled Code function makeCompiledCode(output: string) { // Set Mode setCppAllowed(true); // 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; fs.writeFileSync(output, result); } makeCompiledCode(sourceOutput);