This Is So Cursed, I Hate It
This commit is contained in:
parent
8bca4b7ec6
commit
1b29e09e67
@ -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
110
src/cpp.ts
Normal 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;
|
||||||
|
}
|
53
src/index.ts
53
src/index.ts
@ -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();
|
||||||
|
|
||||||
|
@ -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(' ');
|
||||||
|
17
src/map.ts
17
src/map.ts
@ -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} = {};
|
||||||
|
|
||||||
@ -40,11 +30,4 @@ export function getStructure(name: string) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Clear Loaded Structures
|
|
||||||
function clearStructures() {
|
|
||||||
for (const name in structures) {
|
|
||||||
delete structures[name];
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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);
|
||||||
|
@ -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';
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user