Better Static Properties
This commit is contained in:
parent
603010e3cc
commit
fbb9b6d6da
@ -66,14 +66,7 @@ export function toHex(x: number) {
|
|||||||
return '0x' + x.toString(16);
|
return '0x' + x.toString(16);
|
||||||
}
|
}
|
||||||
export function assertSize(name: string, size: number) {
|
export function assertSize(name: string, size: number) {
|
||||||
let out = '';
|
return `static_assert(sizeof(${name}) == ${toHex(size)}, "Invalid Size");\n`;
|
||||||
// Define Size Macro
|
|
||||||
const macro = toUpperSnakeCase(name) + '_SIZE';
|
|
||||||
out += `#define ${macro} ${toHex(size)}\n`;
|
|
||||||
// Check Size
|
|
||||||
out += `static_assert(sizeof(${name}) == ${macro}, "Invalid Size");\n`;
|
|
||||||
// Return
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
export function safeParseInt(str: string) {
|
export function safeParseInt(str: string) {
|
||||||
const x = parseInt(str);
|
const x = parseInt(str);
|
||||||
|
20
src/index.ts
20
src/index.ts
@ -1,5 +1,5 @@
|
|||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { STRUCTURE_FILES, EXTENSION, INDENT } from './common';
|
import { STRUCTURE_FILES, EXTENSION } from './common';
|
||||||
import { getStructure } from './map';
|
import { getStructure } from './map';
|
||||||
import { Struct } from './struct';
|
import { Struct } from './struct';
|
||||||
|
|
||||||
@ -130,11 +130,7 @@ function makeHeaderPart() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
let result = '';
|
return structures;
|
||||||
result += '// Init\n';
|
|
||||||
result += 'void init_symbols();\n\n';
|
|
||||||
result += structures;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Main Header
|
// Create Main Header
|
||||||
@ -180,7 +176,6 @@ function makeCompiledCode(output: string) {
|
|||||||
|
|
||||||
// Generate
|
// Generate
|
||||||
let declarations = '';
|
let declarations = '';
|
||||||
let init = '';
|
|
||||||
let isFirst = true;
|
let isFirst = true;
|
||||||
for (const structure of structureObjects) {
|
for (const structure of structureObjects) {
|
||||||
const name = structure.getName();
|
const name = structure.getName();
|
||||||
@ -188,14 +183,11 @@ function makeCompiledCode(output: string) {
|
|||||||
isFirst = false;
|
isFirst = false;
|
||||||
} else {
|
} else {
|
||||||
declarations += '\n';
|
declarations += '\n';
|
||||||
init += '\n';
|
|
||||||
}
|
}
|
||||||
declarations += `// ${name}\n`;
|
declarations += `// ${name}\n`;
|
||||||
init += `${INDENT}// ${name}\n`;
|
|
||||||
try {
|
try {
|
||||||
const code = structure.generateCode();
|
const code = structure.generateCode();
|
||||||
declarations += code.functions;
|
declarations += code;
|
||||||
init += code.init;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Error Generating Code: ${name}: ${e instanceof Error ? e.stack : e}`);
|
console.log(`Error Generating Code: ${name}: ${e instanceof Error ? e.stack : e}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@ -205,11 +197,7 @@ function makeCompiledCode(output: string) {
|
|||||||
// Write
|
// Write
|
||||||
let result = '';
|
let result = '';
|
||||||
result += `#include "${fs.realpathSync(headerOutput)}"\n`;
|
result += `#include "${fs.realpathSync(headerOutput)}"\n`;
|
||||||
result += '\n#include <cstring>\n';
|
result += '\n#include <cstring>\n\n';
|
||||||
result += '\n// Init\n';
|
|
||||||
result += 'void init_symbols() {\n';
|
|
||||||
result += init;
|
|
||||||
result += '}\n\n';
|
|
||||||
result += declarations;
|
result += declarations;
|
||||||
fs.writeFileSync(output, result);
|
fs.writeFileSync(output, result);
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ export class Method {
|
|||||||
|
|
||||||
// Generate Variable Definition
|
// Generate Variable Definition
|
||||||
generateDefinition(nameSuffix?: string) {
|
generateDefinition(nameSuffix?: string) {
|
||||||
return `${this.getType()} ${this.getName()}${nameSuffix !== undefined ? nameSuffix : ''};\n`;
|
return `${this.getType()} ${this.getName()}${nameSuffix !== undefined ? nameSuffix : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate "New Method" Test
|
// Generate "New Method" Test
|
||||||
|
@ -34,8 +34,14 @@ export class Property {
|
|||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
#fullName(separator: string) {
|
||||||
|
return this.#self + separator + this.name();
|
||||||
|
}
|
||||||
fullName() {
|
fullName() {
|
||||||
return `${this.#self}_${this.name()}`;
|
return this.#fullName('_');
|
||||||
|
}
|
||||||
|
prettyName() {
|
||||||
|
return this.#fullName('::');
|
||||||
}
|
}
|
||||||
rawType() {
|
rawType() {
|
||||||
return this.#type;
|
return this.#type;
|
||||||
@ -48,13 +54,8 @@ export class StaticProperty extends Property {
|
|||||||
super(address, type, name, self);
|
super(address, type, name, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate Variable Definition
|
// Reference
|
||||||
globalPointerDefinition() {
|
referenceDefinition(addSelf: boolean) {
|
||||||
return `${this.type()} *${this.fullName()}_pointer;\n`;
|
return `${this.type()} &${addSelf ? this.prettyName() : this.name()}`;
|
||||||
}
|
|
||||||
|
|
||||||
// Generate Macro
|
|
||||||
macro() {
|
|
||||||
return `#define ${this.fullName()} (*${this.fullName()}_pointer)\n`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -193,16 +193,14 @@ export class Struct {
|
|||||||
// Static Properties
|
// Static Properties
|
||||||
for (const property of this.#staticProperties) {
|
for (const property of this.#staticProperties) {
|
||||||
out += property.typedef();
|
out += property.typedef();
|
||||||
out += `extern ${property.globalPointerDefinition()}`;
|
|
||||||
out += property.macro();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
for (const method of this.#methods) {
|
for (const method of this.#methods) {
|
||||||
if (!method.isInherited) {
|
if (!method.isInherited) {
|
||||||
out += method.generateTypedef();
|
out += method.generateTypedef();
|
||||||
out += `extern ${method.generateDefinition()}`;
|
out += `extern ${method.generateDefinition()};\n`;
|
||||||
out += `extern ${method.generateDefinition(ORIGINAL_SUFFIX)}`;
|
out += `extern ${method.generateDefinition(ORIGINAL_SUFFIX)};\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +218,10 @@ export class Struct {
|
|||||||
out += `struct ${this.#name} {\n`;
|
out += `struct ${this.#name} {\n`;
|
||||||
out += this.#generateProperties();
|
out += this.#generateProperties();
|
||||||
out += this.#generateMethods();
|
out += this.#generateMethods();
|
||||||
|
for (const property of this.#staticProperties) {
|
||||||
|
// Static Property References
|
||||||
|
out += `${INDENT}static ${property.referenceDefinition(false)};\n`;
|
||||||
|
}
|
||||||
if (this.#size === null) {
|
if (this.#size === null) {
|
||||||
// Prevent Manually Copying/Allocating Structure With Undefined
|
// Prevent Manually Copying/Allocating Structure With Undefined
|
||||||
out += `${INDENT}${this.#name}() = delete;\n`;
|
out += `${INDENT}${this.#name}() = delete;\n`;
|
||||||
@ -247,34 +249,29 @@ export class Struct {
|
|||||||
|
|
||||||
// Generate Compiled Code
|
// Generate Compiled Code
|
||||||
generateCode() {
|
generateCode() {
|
||||||
let declarations = '';
|
let out = '';
|
||||||
let init = '';
|
|
||||||
|
|
||||||
// Static Properties
|
// Static Properties
|
||||||
for (const property of this.#staticProperties) {
|
for (const property of this.#staticProperties) {
|
||||||
init += `${INDENT}${property.fullName()}_pointer = (${property.type()} *) ${toHex(property.offset)};\n`;
|
out += `${property.referenceDefinition(true)} = *(${property.type()} *) ${toHex(property.offset)};\n`;
|
||||||
declarations += property.globalPointerDefinition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
for (const method of this.#methods) {
|
for (const method of this.#methods) {
|
||||||
if (!method.isInherited) {
|
if (!method.isInherited) {
|
||||||
init += `${INDENT}${method.getName()} = (${method.getType()}) ${toHex(method.address)};\n`;
|
out += `${method.generateDefinition()} = (${method.getType()}) ${toHex(method.address)};\n`;
|
||||||
declarations += method.generateDefinition();
|
out += `${method.generateDefinition(ORIGINAL_SUFFIX)} = ${method.getName()};\n`;
|
||||||
init += `${INDENT}${method.getName()}${ORIGINAL_SUFFIX} = ${method.getName()};\n`;
|
|
||||||
declarations += method.generateDefinition(ORIGINAL_SUFFIX);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VTable
|
// VTable
|
||||||
if (this.#vtable !== null) {
|
if (this.#vtable !== null) {
|
||||||
const vtable = this.#vtable.generateCode();
|
const vtable = this.#vtable.generateCode();
|
||||||
declarations += vtable.declarations;
|
out += vtable;
|
||||||
init += vtable.init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
return {functions: declarations, init};
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Direct Parent (Used For "New Method" Testing)
|
// Set Direct Parent (Used For "New Method" Testing)
|
||||||
|
@ -133,7 +133,7 @@ export class VTable {
|
|||||||
const pointerType = `${type} *`;
|
const pointerType = `${type} *`;
|
||||||
out += `extern ${pointerType}${name}_vtable_addr;\n`;
|
out += `extern ${pointerType}${name}_vtable_addr;\n`;
|
||||||
out += info.generateNewMethodTest(directParent, '*', '_vtable_addr');
|
out += info.generateNewMethodTest(directParent, '*', '_vtable_addr');
|
||||||
out += `extern ${info.generateDefinition(ORIGINAL_SUFFIX)}`;
|
out += `extern ${info.generateDefinition(ORIGINAL_SUFFIX)};\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,8 +149,7 @@ export class VTable {
|
|||||||
|
|
||||||
// Generate Compiled Code
|
// Generate Compiled Code
|
||||||
generateCode() {
|
generateCode() {
|
||||||
let declarations = '';
|
let out = '';
|
||||||
let init = '';
|
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
this.#check();
|
this.#check();
|
||||||
@ -158,8 +157,7 @@ export class VTable {
|
|||||||
// Pointers
|
// Pointers
|
||||||
if (this.#address !== null) {
|
if (this.#address !== null) {
|
||||||
// Base
|
// Base
|
||||||
init += `${INDENT}${this.#getName()}_base = (${this.#getName()} *) ${toHex(this.#address)};\n`;
|
out += `${this.#getName()} *${this.#getName()}_base = (${this.#getName()} *) ${toHex(this.#address)};\n`;
|
||||||
declarations += `${this.#getName()} *${this.#getName()}_base;\n`;
|
|
||||||
// Methods
|
// Methods
|
||||||
const methods = this.getMethods();
|
const methods = this.getMethods();
|
||||||
for (let i = 0; i < methods.length; i++) {
|
for (let i = 0; i < methods.length; i++) {
|
||||||
@ -169,31 +167,29 @@ export class VTable {
|
|||||||
const name = info.getName();
|
const name = info.getName();
|
||||||
const type = info.getType();
|
const type = info.getType();
|
||||||
const pointerType = `${type} *`;
|
const pointerType = `${type} *`;
|
||||||
init += `${INDENT}${name}_vtable_addr = (${pointerType}) ${toHex(vtableAddress)};\n`;
|
out += `${pointerType}${name}_vtable_addr = (${pointerType}) ${toHex(vtableAddress)};\n`;
|
||||||
declarations += `${pointerType}${name}_vtable_addr;\n`;
|
out += `${info.generateDefinition(ORIGINAL_SUFFIX)} = *${name}_vtable_addr;\n`;
|
||||||
init += `${INDENT}${name}${ORIGINAL_SUFFIX} = *${name}_vtable_addr;\n`;
|
|
||||||
declarations += info.generateDefinition(ORIGINAL_SUFFIX);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplication Method
|
// Duplication Method
|
||||||
if (this.#size !== null) {
|
if (this.#size !== null) {
|
||||||
declarations += `${this.#getName()} *dup_${this.#getName()}(${this.#getName()} *vtable) {\n`;
|
out += `${this.#getName()} *dup_${this.#getName()}(${this.#getName()} *vtable) {\n`;
|
||||||
declarations += `${INDENT}uchar *real_vtable = (uchar *) vtable;\n`;
|
out += `${INDENT}uchar *real_vtable = (uchar *) vtable;\n`;
|
||||||
declarations += `${INDENT}real_vtable -= ${RTTI_SIZE};\n`;
|
out += `${INDENT}real_vtable -= ${RTTI_SIZE};\n`;
|
||||||
declarations += `${INDENT}size_t real_vtable_size = sizeof(${this.#getName()}) + ${RTTI_SIZE};\n`;
|
out += `${INDENT}size_t real_vtable_size = sizeof(${this.#getName()}) + ${RTTI_SIZE};\n`;
|
||||||
declarations += `${INDENT}uchar *new_vtable = (uchar *) ::operator new(real_vtable_size);\n`;
|
out += `${INDENT}uchar *new_vtable = (uchar *) ::operator new(real_vtable_size);\n`;
|
||||||
declarations += `${INDENT}if (new_vtable == NULL) {\n`;
|
out += `${INDENT}if (new_vtable == NULL) {\n`;
|
||||||
declarations += `${INDENT}${INDENT}return NULL;\n`;
|
out += `${INDENT}${INDENT}return NULL;\n`;
|
||||||
declarations += `${INDENT}}\n`;
|
out += `${INDENT}}\n`;
|
||||||
declarations += `${INDENT}memcpy((void *) new_vtable, (void *) real_vtable, real_vtable_size);\n`;
|
out += `${INDENT}memcpy((void *) new_vtable, (void *) real_vtable, real_vtable_size);\n`;
|
||||||
declarations += `${INDENT}new_vtable += ${RTTI_SIZE};\n`;
|
out += `${INDENT}new_vtable += ${RTTI_SIZE};\n`;
|
||||||
declarations += `${INDENT}return (${this.#getName()} *) new_vtable;\n`;
|
out += `${INDENT}return (${this.#getName()} *) new_vtable;\n`;
|
||||||
declarations += '}\n';
|
out += '}\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
return {declarations, init};
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user