2024-01-04 20:27:02 +00:00
|
|
|
import * as fs from 'node:fs';
|
2024-01-04 22:00:19 +00:00
|
|
|
import { STRUCTURE_FILES, EXTENSION, INDENT } from './common';
|
2024-02-15 08:16:34 +00:00
|
|
|
import { getStructure } from './map';
|
2024-01-05 20:47:53 +00:00
|
|
|
import { Struct } from './struct';
|
2024-01-04 20:27:02 +00:00
|
|
|
|
2024-01-04 22:00:19 +00:00
|
|
|
// Arguments
|
|
|
|
if (process.argv.length < 5) {
|
2024-01-05 20:47:53 +00:00
|
|
|
console.log('USAGE: npm start -- <Source Output File> <Header Output File> <Input Files...>');
|
2024-01-04 22:00:19 +00:00
|
|
|
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
|
2024-01-16 00:01:59 +00:00
|
|
|
if (name in STRUCTURE_FILES) {
|
|
|
|
throw new Error(`Multiple Definition Files Provided: ${name}${EXTENSION}`);
|
|
|
|
}
|
2024-01-04 22:00:19 +00:00
|
|
|
STRUCTURE_FILES[name] = file;
|
|
|
|
} else if (file.endsWith('.h')) {
|
|
|
|
// Extra Headers
|
|
|
|
extraHeaders.push(file);
|
|
|
|
} else {
|
|
|
|
// Invalid File Type
|
|
|
|
invalidFileType(file);
|
|
|
|
}
|
2024-01-04 20:27:02 +00:00
|
|
|
}
|
|
|
|
|
2024-01-04 22:00:19 +00:00
|
|
|
// Load And Sort Structures
|
2024-01-04 20:27:02 +00:00
|
|
|
function loadSymbols() {
|
|
|
|
// Load
|
|
|
|
const structureObjects = [];
|
2024-01-04 22:00:19 +00:00
|
|
|
for (const name in STRUCTURE_FILES) {
|
|
|
|
structureObjects.push(getStructure(name));
|
2024-01-04 20:27:02 +00:00
|
|
|
}
|
|
|
|
// 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;
|
|
|
|
}
|
2024-01-04 22:00:19 +00:00
|
|
|
|
2024-01-05 20:47:53 +00:00
|
|
|
// Sort Structures By Dependency
|
|
|
|
function dependencySort(structureObjects: Struct[]) {
|
|
|
|
let loops = 0;
|
|
|
|
const MAX_LOOPS = 100;
|
2024-01-04 20:27:02 +00:00
|
|
|
while (true) {
|
2024-01-05 20:47:53 +00:00
|
|
|
if (loops > MAX_LOOPS) {
|
|
|
|
throw new Error('Unable To Sort Dependencies');
|
|
|
|
}
|
|
|
|
loops++;
|
2024-01-04 20:27:02 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2024-01-05 20:47:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate Part Of Header
|
2024-02-15 08:16:34 +00:00
|
|
|
function makeHeaderPart() {
|
2024-01-05 20:47:53 +00:00
|
|
|
// Load Symbols
|
|
|
|
const structureObjects = loadSymbols();
|
|
|
|
|
|
|
|
// Sort Structures By Dependency
|
|
|
|
dependencySort(structureObjects);
|
2024-01-04 20:27:02 +00:00
|
|
|
|
|
|
|
// Generate Code
|
|
|
|
let structures = '';
|
2024-01-04 22:00:19 +00:00
|
|
|
let isFirst = true;
|
2024-01-04 20:27:02 +00:00
|
|
|
for (const structure of structureObjects) {
|
|
|
|
const name = structure.getName();
|
2024-01-04 22:00:19 +00:00
|
|
|
if (isFirst) {
|
|
|
|
isFirst = false;
|
|
|
|
} else {
|
|
|
|
structures += '\n';
|
|
|
|
}
|
|
|
|
structures += `// ${name}\n`;
|
2024-01-04 20:27:02 +00:00
|
|
|
try {
|
|
|
|
structures += structure.generate();
|
|
|
|
} catch (e) {
|
|
|
|
console.log(`Error Generating Header: ${name}: ${e instanceof Error ? e.stack : e}`);
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-04 22:00:19 +00:00
|
|
|
// Return
|
2024-01-06 10:59:19 +00:00
|
|
|
let result = '';
|
|
|
|
result += '// Init\n';
|
|
|
|
result += 'void init_symbols();\n\n';
|
|
|
|
result += structures;
|
|
|
|
return result;
|
2024-01-04 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create Main Header
|
|
|
|
function makeMainHeader(output: string) {
|
2024-01-04 20:27:02 +00:00
|
|
|
let result = '';
|
|
|
|
result += '#pragma once\n';
|
2024-01-05 20:47:53 +00:00
|
|
|
result += '\n// Check Architecture\n';
|
|
|
|
result += '#ifndef __arm__\n';
|
|
|
|
result += '#error "Symbols Are ARM-Only"\n';
|
|
|
|
result += '#endif\n';
|
2024-01-04 22:00:19 +00:00
|
|
|
result += '\n// Shortcuts\n';
|
|
|
|
result += 'typedef unsigned char uchar;\n';
|
2024-01-21 23:19:13 +00:00
|
|
|
result += 'typedef unsigned short ushort;\n';
|
2024-01-04 22:00:19 +00:00
|
|
|
result += 'typedef unsigned int uint;\n';
|
|
|
|
result += '\n// Forward Declarations\n';
|
|
|
|
for (const name in STRUCTURE_FILES) {
|
|
|
|
result += `typedef struct ${name} ${name};\n`;
|
2024-01-05 20:47:53 +00:00
|
|
|
}
|
|
|
|
result += '\n// Extra Headers\n';
|
2024-01-04 22:00:19 +00:00
|
|
|
for (const file of extraHeaders) {
|
|
|
|
result += fs.readFileSync(file, {encoding: 'utf8'});
|
|
|
|
}
|
2024-04-03 07:18:51 +00:00
|
|
|
result += '\n// Headers\n';
|
|
|
|
result += '#include <cstddef>\n';
|
|
|
|
result += '#include <string>\n';
|
|
|
|
result += '#include <vector>\n';
|
|
|
|
result += '#include <map>\n';
|
|
|
|
result += '\n// Warnings\n';
|
|
|
|
result += '#pragma GCC diagnostic push\n';
|
2024-05-04 02:20:03 +00:00
|
|
|
result += '#pragma GCC diagnostic ignored "-Winvalid-offsetof"\n';
|
|
|
|
result += '#pragma GCC diagnostic ignored "-Wshadow"\n\n';
|
2024-04-03 07:18:51 +00:00
|
|
|
result += makeHeaderPart();
|
|
|
|
result += '\n// Cleanup Warnings\n';
|
|
|
|
result += '#pragma GCC diagnostic pop\n';
|
2024-01-04 20:27:02 +00:00
|
|
|
fs.writeFileSync(output, result);
|
|
|
|
}
|
2024-01-04 22:00:19 +00:00
|
|
|
makeMainHeader(headerOutput);
|
2024-01-04 20:27:02 +00:00
|
|
|
|
|
|
|
// Generate Compiled Code
|
|
|
|
function makeCompiledCode(output: string) {
|
|
|
|
// Load Symbols
|
|
|
|
const structureObjects = loadSymbols();
|
|
|
|
|
|
|
|
// Generate
|
|
|
|
let declarations = '';
|
|
|
|
let init = '';
|
2024-01-04 22:00:19 +00:00
|
|
|
let isFirst = true;
|
2024-01-04 20:27:02 +00:00
|
|
|
for (const structure of structureObjects) {
|
|
|
|
const name = structure.getName();
|
2024-01-04 22:00:19 +00:00
|
|
|
if (isFirst) {
|
|
|
|
isFirst = false;
|
|
|
|
} else {
|
|
|
|
declarations += '\n';
|
|
|
|
init += '\n';
|
|
|
|
}
|
|
|
|
declarations += `// ${name}\n`;
|
|
|
|
init += `${INDENT}// ${name}\n`;
|
2024-01-04 20:27:02 +00:00
|
|
|
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 = '';
|
2024-01-04 22:00:19 +00:00
|
|
|
result += `#include "${fs.realpathSync(headerOutput)}"\n`;
|
|
|
|
result += '\n#include <cstring>\n';
|
2024-01-04 20:27:02 +00:00
|
|
|
result += '\n// Init\n';
|
2024-01-04 22:00:19 +00:00
|
|
|
result += 'void init_symbols() {\n';
|
2024-01-04 20:27:02 +00:00
|
|
|
result += init;
|
2024-01-04 22:00:19 +00:00
|
|
|
result += '}\n\n';
|
2024-01-04 20:27:02 +00:00
|
|
|
result += declarations;
|
|
|
|
fs.writeFileSync(output, result);
|
|
|
|
}
|
2024-02-06 23:20:38 +00:00
|
|
|
makeCompiledCode(sourceOutput);
|