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 * as fs from 'node:fs';
import { isCppAllowed } from './map';
export const INDENT = ' '; export const INDENT = ' ';
export const POINTER_SIZE = 4; export const POINTER_SIZE = 4;
@ -67,7 +66,7 @@ export function toHex(x: number) {
return '0x' + x.toString(16); return '0x' + x.toString(16);
} }
export function getAssertFunction() { export function getAssertFunction() {
return isCppAllowed() ? 'static_assert' : '_Static_assert'; return 'static_assert';
} }
export function assertSize(name: string, size: number, isDefined: boolean) { export function assertSize(name: string, size: number, isDefined: boolean) {
let out = ''; let out = '';
@ -75,7 +74,7 @@ export function assertSize(name: string, size: number, isDefined: boolean) {
const macro = toUpperSnakeCase(name) + '_SIZE'; const macro = toUpperSnakeCase(name) + '_SIZE';
out += `#define ${macro} ${toHex(size)}\n`; out += `#define ${macro} ${toHex(size)}\n`;
// Check Size // 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 // Hide Structure Size If The Real Size Is Unknown
if (!isDefined) { if (!isDefined) {
out += `#undef ${macro}\n`; 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 * as fs from 'node:fs';
import { STRUCTURE_FILES, EXTENSION, INDENT } from './common'; import { STRUCTURE_FILES, EXTENSION, INDENT } from './common';
import { getStructure, setCppAllowed } from './map'; import { getStructure } from './map';
import { Struct } from './struct'; import { Struct } from './struct';
import { fixupCpp } from './cpp';
// Arguments // Arguments
if (process.argv.length < 5) { if (process.argv.length < 5) {
@ -103,10 +104,7 @@ function dependencySort(structureObjects: Struct[]) {
} }
// Generate Part Of Header // Generate Part Of Header
function makeHeaderPart(allowCpp: boolean) { function makeHeaderPart() {
// Set Mode
setCppAllowed(allowCpp);
// Load Symbols // Load Symbols
const structureObjects = loadSymbols(); const structureObjects = loadSymbols();
@ -148,10 +146,6 @@ function makeMainHeader(output: string) {
result += '#ifndef __arm__\n'; result += '#ifndef __arm__\n';
result += '#error "Symbols Are ARM-Only"\n'; result += '#error "Symbols Are ARM-Only"\n';
result += '#endif\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 += '\n// Shortcuts\n';
result += 'typedef unsigned char uchar;\n'; result += 'typedef unsigned char uchar;\n';
result += 'typedef unsigned short ushort;\n'; result += 'typedef unsigned short ushort;\n';
@ -164,34 +158,31 @@ function makeMainHeader(output: string) {
for (const file of extraHeaders) { for (const file of extraHeaders) {
result += fs.readFileSync(file, {encoding: 'utf8'}); result += fs.readFileSync(file, {encoding: 'utf8'});
} }
result += '\n// Switch Mode\n'; let core = '';
result += '#ifndef __cplusplus\n'; core += '// C/C++ Support\n';
result += '\n// C Mode\n'; core += '#ifndef __cplusplus\n';
result += '#include <stddef.h>\n'; core += '#include <stddef.h>\n';
result += 'typedef uchar bool;\n\n'; core += '#include <assert.h>\n';
result += makeHeaderPart(false); core += 'typedef uchar bool;\n';
result += '\n// End C Mode\n'; core += '#else\n';
result += '#else\n'; core += '#include <cstddef>\n';
result += '\n// C++ Mode\n'; core += 'extern "C" {\n';
result += '#include <string>\n'; core += '#pragma GCC diagnostic push\n';
result += '#include <vector>\n'; core += '#pragma GCC diagnostic ignored "-Winvalid-offsetof"\n';
result += '#include <cstddef>\n'; core += '#endif\n\n';
result += '#include <map>\n'; core += makeHeaderPart();
result += 'extern "C" {\n\n'; core += '\n// Cleanup C++ Support\n';
result += makeHeaderPart(true); core += '#ifdef __cplusplus\n';
result += '\n// End C++ Mode\n'; core += '#pragma GCC diagnostic pop\n';
result += '}\n'; core += '}\n';
result += '#endif\n'; core += '#endif\n';
result += '\n// Stop Suppressing Warnings\n'; result += '\n' + fixupCpp(core);
result += '#pragma GCC diagnostic pop\n';
fs.writeFileSync(output, result); fs.writeFileSync(output, result);
} }
makeMainHeader(headerOutput); makeMainHeader(headerOutput);
// Generate Compiled Code // Generate Compiled Code
function makeCompiledCode(output: string) { function makeCompiledCode(output: string) {
// Set Mode
setCppAllowed(true);
// Load Symbols // Load Symbols
const structureObjects = loadSymbols(); const structureObjects = loadSymbols();

View File

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

View File

@ -1,16 +1,6 @@
import { Struct } from './struct'; import { Struct } from './struct';
import { ErrorOnLine, load } from './loader'; 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 // Store Loaded Structures
const structures: {[id: string]: Struct} = {}; 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<')) { } else if (this.#type.startsWith('std::vector<')) {
// C++ Vector // C++ Vector
return 12; return 12;
} else if (this.#type.startsWith('std::map<')) {
// C++ Map
return 24;
} else { } else {
// Structure // Structure
const structure = getStructure(this.#type); const structure = getStructure(this.#type);
@ -96,6 +99,9 @@ export class SimpleProperty implements Property {
} else if (this.#type.startsWith('std::vector<')) { } else if (this.#type.startsWith('std::vector<')) {
// C++ Vector // C++ Vector
return 4; return 4;
} else if (this.#type.startsWith('std::map<')) {
// C++ Map
return 4;
} else { } else {
// Structure // Structure
const structure = getStructure(this.#type); const structure = getStructure(this.#type);

View File

@ -174,7 +174,7 @@ export class VTable implements Property {
declarations += `${INDENT}if (obj == NULL) {\n`; declarations += `${INDENT}if (obj == NULL) {\n`;
declarations += `${INDENT}${INDENT}return NULL;\n`; declarations += `${INDENT}${INDENT}return NULL;\n`;
declarations += `${INDENT}}\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 += `${INDENT}return obj;\n`;
declarations += '}\n'; declarations += '}\n';
} }