This Is So Cursed, I Hate It

This commit is contained in:
TheBrokenRail 2024-02-15 03:16:34 -05:00
parent 8bca4b7ec6
commit 1b29e09e67
7 changed files with 141 additions and 57 deletions

View File

@ -1,5 +1,4 @@
import * as fs from 'node:fs';
import { isCppAllowed } from './map';
export const INDENT = ' ';
export const POINTER_SIZE = 4;
@ -67,7 +66,7 @@ export function toHex(x: number) {
return '0x' + x.toString(16);
}
export function getAssertFunction() {
return isCppAllowed() ? 'static_assert' : '_Static_assert';
return 'static_assert';
}
export function assertSize(name: string, size: number, isDefined: boolean) {
let out = '';
@ -75,7 +74,7 @@ export function assertSize(name: string, size: number, isDefined: boolean) {
const macro = toUpperSnakeCase(name) + '_SIZE';
out += `#define ${macro} ${toHex(size)}\n`;
// Check Size
out += `${getAssertFunction()}(sizeof (${name}) == ${macro}, "Invalid Size");\n`;
out += `${getAssertFunction()}(sizeof(${name}) == ${macro}, "Invalid Size");\n`;
// Hide Structure Size If The Real Size Is Unknown
if (!isDefined) {
out += `#undef ${macro}\n`;

110
src/cpp.ts Normal file
View File

@ -0,0 +1,110 @@
import { INDENT } from './common';
import { SimpleProperty } from './property';
// List Of Supported C++ Types
const CPP_TYPES = [
'std::string',
'std::vector<',
'std::map<'
];
const CPP_HEADERS = [
'string',
'vector',
'map'
];
// Get Fake Type Name
function isGeneric(type: string) {
return type.endsWith('<');
}
function removeGeneric(type: string) {
if (isGeneric(type)) {
// Remove Generic Parameters
type = type.substring(0, type.length - 1);
}
return type;
}
function getFakeName(type: string) {
return removeGeneric(type).replaceAll('std::', '__std_');
}
// Generate C Type Definition
function generateStruct(type: string) {
// Get Information
const property = new SimpleProperty(0, type, 'fake');
const size = property.propertySize();
const alignment = property.propertyAlignment();
// Generate
let struct = '';
struct += `typedef struct __attribute__((aligned(${alignment}))) __attribute__((packed)) {\n`;
struct += `${INDENT}uchar data[${size}];\n`;
struct += `} ${getFakeName(type)};\n`;
return struct;
}
// Turn A C++ Header Into A C/C++ Headeer
export function fixupCpp(data: string) {
// Replace Types
for (const type of CPP_TYPES) {
// Check If Type Is Generic
if (isGeneric(type)) {
// Generic
while (data.includes(type)) {
// Find Type
let index = data.indexOf(type);
// Replace Type
data = data.substring(0, index) + getFakeName(type) + '(' + data.substring(index + type.length);
// Replace > With (
index = data.indexOf('>', index);
if (index !== -1) {
data = data.substring(0, index) + ')' + data.substring(index + 1);
}
}
} else {
// Normal
data = data.replaceAll(type, getFakeName(type));
}
}
// Setup Macros
let header = '';
header += '// C++ Types\n';
// C++ Support
header += '#ifdef __cplusplus\n';
for (const headerFile of CPP_HEADERS) {
header += `#include <${headerFile}>\n`;
}
for (const type of CPP_TYPES) {
const fakeName = getFakeName(type);
if (isGeneric(type)) {
header += `#define ${fakeName}(...) ${type}__VA_ARGS__>\n`;
} else {
header += `#define ${fakeName} ${type}\n`;
}
}
// C Support
header += '#else\n';
for (let type of CPP_TYPES) {
const fakeName = getFakeName(type);
header += generateStruct(type);
// Strip Generic Information
if (isGeneric(type)) {
type = removeGeneric(type);
header += `#define ${fakeName}(...) ${fakeName}\n`;
}
}
header += '#endif\n';
// Cleanup Macros
let footer = '';
footer += '// Cleanup C++ Types\n';
for (const type of CPP_TYPES) {
const fakeName = getFakeName(type);
footer += `#undef ${fakeName}\n`;
}
// Return
return header + '\n' + data + '\n' + footer;
}

View File

@ -1,7 +1,8 @@
import * as fs from 'node:fs';
import { STRUCTURE_FILES, EXTENSION, INDENT } from './common';
import { getStructure, setCppAllowed } from './map';
import { getStructure } from './map';
import { Struct } from './struct';
import { fixupCpp } from './cpp';
// Arguments
if (process.argv.length < 5) {
@ -103,10 +104,7 @@ function dependencySort(structureObjects: Struct[]) {
}
// Generate Part Of Header
function makeHeaderPart(allowCpp: boolean) {
// Set Mode
setCppAllowed(allowCpp);
function makeHeaderPart() {
// Load Symbols
const structureObjects = loadSymbols();
@ -148,10 +146,6 @@ function makeMainHeader(output: string) {
result += '#ifndef __arm__\n';
result += '#error "Symbols Are ARM-Only"\n';
result += '#endif\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 short ushort;\n';
@ -164,34 +158,31 @@ function makeMainHeader(output: string) {
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 += '#include <stddef.h>\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 <string>\n';
result += '#include <vector>\n';
result += '#include <cstddef>\n';
result += '#include <map>\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';
let core = '';
core += '// C/C++ Support\n';
core += '#ifndef __cplusplus\n';
core += '#include <stddef.h>\n';
core += '#include <assert.h>\n';
core += 'typedef uchar bool;\n';
core += '#else\n';
core += '#include <cstddef>\n';
core += 'extern "C" {\n';
core += '#pragma GCC diagnostic push\n';
core += '#pragma GCC diagnostic ignored "-Winvalid-offsetof"\n';
core += '#endif\n\n';
core += makeHeaderPart();
core += '\n// Cleanup C++ Support\n';
core += '#ifdef __cplusplus\n';
core += '#pragma GCC diagnostic pop\n';
core += '}\n';
core += '#endif\n';
result += '\n' + fixupCpp(core);
fs.writeFileSync(output, result);
}
makeMainHeader(headerOutput);
// Generate Compiled Code
function makeCompiledCode(output: string) {
// Set Mode
setCppAllowed(true);
// Load Symbols
const structureObjects = loadSymbols();

View File

@ -1,5 +1,4 @@
import { COMMENT, EXTENSION, getSelfArg, parseTypeAndName, readDefinition, safeParseInt, syntaxError } from './common';
import { isCppAllowed } from './map';
import { Method } from './method';
import { SimpleProperty, StaticProperty } from './property';
import { Struct } from './struct';
@ -93,10 +92,6 @@ export function load(target: Struct, name: string, isExtended: boolean) {
if (piece.length === 0) {
continue;
}
// Skip C++ Types If Applicable
if (!isCppAllowed() && piece.includes('std::')) {
continue;
}
// Handle Commands
let firstSpace = piece.indexOf(' ');

View File

@ -1,16 +1,6 @@
import { Struct } from './struct';
import { ErrorOnLine, load } from './loader';
// Track Mode
let allowCpp = false;
export function isCppAllowed() {
return allowCpp;
}
export function setCppAllowed(newMode: boolean) {
clearStructures();
allowCpp = newMode;
}
// Store Loaded Structures
const structures: {[id: string]: Struct} = {};
@ -41,10 +31,3 @@ export function getStructure(name: string) {
}
}
}
// Clear Loaded Structures
function clearStructures() {
for (const name in structures) {
delete structures[name];
}
}

View File

@ -60,6 +60,9 @@ export class SimpleProperty implements Property {
} else if (this.#type.startsWith('std::vector<')) {
// C++ Vector
return 12;
} else if (this.#type.startsWith('std::map<')) {
// C++ Map
return 24;
} else {
// Structure
const structure = getStructure(this.#type);
@ -96,6 +99,9 @@ export class SimpleProperty implements Property {
} else if (this.#type.startsWith('std::vector<')) {
// C++ Vector
return 4;
} else if (this.#type.startsWith('std::map<')) {
// C++ Map
return 4;
} else {
// Structure
const structure = getStructure(this.#type);

View File

@ -174,7 +174,7 @@ export class VTable implements Property {
declarations += `${INDENT}if (obj == NULL) {\n`;
declarations += `${INDENT}${INDENT}return NULL;\n`;
declarations += `${INDENT}}\n`;
declarations += `${INDENT}memcpy((void *) obj, (void *) vtable, sizeof (${this.#getName()}));\n`;
declarations += `${INDENT}memcpy((void *) obj, (void *) vtable, sizeof(${this.#getName()}));\n`;
declarations += `${INDENT}return obj;\n`;
declarations += '}\n';
}