176 lines
5.5 KiB
TypeScript
176 lines
5.5 KiB
TypeScript
|
import * as fs from 'node:fs';
|
||
|
import { EXTENSION, INDENT } from './common';
|
||
|
import { getStructure, setCppAllowed } from './map';
|
||
|
|
||
|
// Output Directory
|
||
|
let outputDirectory = process.argv[2];
|
||
|
if (!outputDirectory) {
|
||
|
outputDirectory = `${__dirname}/../out`;
|
||
|
}
|
||
|
fs.rmSync(outputDirectory, {force: true, recursive: true});
|
||
|
fs.mkdirSync(outputDirectory, {recursive: true});
|
||
|
|
||
|
// Main
|
||
|
function loadSymbols() {
|
||
|
// Load
|
||
|
const files = fs.readdirSync(`${__dirname}/../symbols`);
|
||
|
const structureObjects = [];
|
||
|
for (const file of files) {
|
||
|
if (file.endsWith(EXTENSION)) {
|
||
|
// Get Name
|
||
|
const parts = file.split('/');
|
||
|
let name = parts[parts.length - 1]!;
|
||
|
name = name.substring(0, name.length - EXTENSION.length);
|
||
|
// Structures
|
||
|
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;
|
||
|
}
|
||
|
function makeHeader(output: string, allowCpp: boolean) {
|
||
|
// Set Mode
|
||
|
setCppAllowed(allowCpp);
|
||
|
|
||
|
// Load Symbols
|
||
|
const structureObjects = loadSymbols();
|
||
|
|
||
|
// Forward Declarations
|
||
|
let forwardDeclarations = '// Forward Declarations\n';
|
||
|
for (const structure of structureObjects) {
|
||
|
const name = structure.getName();
|
||
|
forwardDeclarations += `typedef struct ${name} ${name};\n`;
|
||
|
}
|
||
|
|
||
|
// 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 = '';
|
||
|
for (const structure of structureObjects) {
|
||
|
const name = structure.getName();
|
||
|
structures += `\n// ${name}\n`;
|
||
|
try {
|
||
|
structures += structure.generate();
|
||
|
} catch (e) {
|
||
|
console.log(`Error Generating Header: ${name}: ${e instanceof Error ? e.stack : e}`);
|
||
|
process.exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write
|
||
|
let result = '';
|
||
|
result += '#pragma once\n';
|
||
|
result += '\n';
|
||
|
result += forwardDeclarations;
|
||
|
result += '\n// Init\n';
|
||
|
result += 'void init_symbols();';
|
||
|
result += '\n// Extra Definitions\n';
|
||
|
result += fs.readFileSync(`${__dirname}/../symbols/extra.h`, {encoding: 'utf8'}).trim() + '\n';
|
||
|
result += structures;
|
||
|
fs.writeFileSync(output, result);
|
||
|
}
|
||
|
|
||
|
// Run
|
||
|
makeHeader(`${outputDirectory}/minecraft_c.h`, false);
|
||
|
makeHeader(`${outputDirectory}/minecraft_cpp.h`, true);
|
||
|
|
||
|
// Generate Compiled Code
|
||
|
function makeCompiledCode(output: string) {
|
||
|
// Set Mode
|
||
|
setCppAllowed(true);
|
||
|
// Load Symbols
|
||
|
const structureObjects = loadSymbols();
|
||
|
|
||
|
// Generate
|
||
|
let declarations = '';
|
||
|
let init = '';
|
||
|
for (const structure of structureObjects) {
|
||
|
const name = structure.getName();
|
||
|
declarations += `\n// ${name}\n`;
|
||
|
init += `\n${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 "minecraft.h"\n';
|
||
|
result += '\n// Init\n';
|
||
|
result += 'void init_symbols() {';
|
||
|
result += init;
|
||
|
result += '}\n';
|
||
|
result += declarations;
|
||
|
fs.writeFileSync(output, result);
|
||
|
}
|
||
|
makeCompiledCode(`${outputDirectory}/minecraft.cpp`);
|
||
|
|
||
|
// Create Main Header
|
||
|
function makeMainHeader(output: string) {
|
||
|
let result = '';
|
||
|
result += '#pragma once\n';
|
||
|
result += '#pragma GCC diagnostic push\n';
|
||
|
result += '#pragma GCC diagnostic ignored "-Wunused-variable"\n';
|
||
|
result += '#pragma GCC diagnostic ignored "-Wunused-function"\n';
|
||
|
result += 'typedef unsigned char uchar;\n';
|
||
|
result += 'typedef unsigned int uint;\n';
|
||
|
result += '#include <string.h>\n';
|
||
|
result += '#include <stdlib.h>\n';
|
||
|
result += '#include <stddef.h>\n';
|
||
|
result += '#ifndef __cplusplus\n';
|
||
|
result += 'typedef unsigned char bool;\n';
|
||
|
result += '#include "minecraft_c.h"\n';
|
||
|
result += '#else\n';
|
||
|
result += '#include <string>\n';
|
||
|
result += '#include <vector>\n';
|
||
|
result += 'extern "C" {\n';
|
||
|
result += '#include "minecraft_cpp.h"\n';
|
||
|
result += '}\n';
|
||
|
result += '#endif\n';
|
||
|
result += '#pragma GCC diagnostic pop\n';
|
||
|
fs.writeFileSync(output, result);
|
||
|
}
|
||
|
makeMainHeader(`${outputDirectory}/minecraft.h`);
|