symbol-processor/src/index.ts

234 lines
7.0 KiB
TypeScript
Raw Normal View History

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-01-04 20:27:02 +00:00
import { getStructure, setCppAllowed } 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
function makeHeaderPart(allowCpp: boolean) {
// Set Mode
setCppAllowed(allowCpp);
// 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// 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';
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'});
}
result += '\n// Switch Mode\n';
result += '#ifndef __cplusplus\n';
result += '\n// C Mode\n';
2024-01-05 20:47:53 +00:00
result += '#include <stddef.h>\n';
2024-01-04 22:00:19 +00:00
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 <string>\n';
result += '#include <vector>\n';
2024-01-05 20:47:53 +00:00
result += '#include <cstddef>\n';
2024-02-06 23:20:38 +00:00
result += '#include <map>\n';
2024-01-04 22:00:19 +00:00
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';
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) {
// Set Mode
setCppAllowed(true);
// 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);