diff --git a/data/out.h b/data/out.h index 97f861d..61e61ed 100644 --- a/data/out.h +++ b/data/out.h @@ -157,6 +157,38 @@ T *dup_vtable(T *vtable) { } #undef RTTI_SIZE +// Internal Macros +#define __PREVENT_DESTRUCTION(self) \ + ~self() = delete +#define __PREVENT_CONSTRUCTION(self) \ + self() = delete; \ + __PREVENT_DESTRUCTION(self) +#define __PREVENT_COPY(self) \ + self(const self &) = delete; \ + self &operator=(const self &) = delete + +// Easily Extend Structures +template +struct __HasAllocate : std::false_type {}; +template +struct __HasAllocate>> : std::true_type {}; +template +class __ExtendedStruct final { + static_assert(__HasAllocate::value, "Super Type Does Not Have A Defined Size"); + __PREVENT_DESTRUCTION(__ExtendedStruct); + __PREVENT_COPY(__ExtendedStruct); + alignas(Super) uchar _super[sizeof(Super)]; +public: + __ExtendedStruct() {} + Super *super() { + return (Super *) &_super[0]; + } + Self data; +}; +#define EXTEND_STRUCT(name, base, ...) \ + typedef __VA_ARGS__ __##name##_data; \ + typedef __ExtendedStruct name + // Forward Declarations {{ forwardDeclarations }} diff --git a/src/common.ts b/src/common.ts index 7f2eab7..8d56053 100644 --- a/src/common.ts +++ b/src/common.ts @@ -100,9 +100,8 @@ export function formatFile(file: string, options: {[key: string]: string}) { export const INTERNAL = '__'; export function preventConstruction(self: string) { let out = ''; - out += `${INDENT}${self}() = delete;\n`; - out += `${INDENT}${self}(const ${self} &) = delete;\n`; - out += `${INDENT}${self} &operator=(const ${self} &) = delete;\n`; + out += `${INDENT}${INTERNAL}PREVENT_CONSTRUCTION(${self});\n`; + out += `${INDENT}${INTERNAL}PREVENT_COPY(${self});\n`; return out; } export const LEAN_HEADER_GUARD = '#ifndef LEAN_SYMBOLS_HEADER\n'; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index f71b10f..8782604 100644 --- a/src/index.ts +++ b/src/index.ts @@ -52,9 +52,9 @@ function loadSymbols() { } // Sort structureObjects.sort((a, b) => { - if (a.getName() > b.getName()) { + if (a.name > b.name) { return 1; - } else if (a.getName() < b.getName()) { + } else if (a.name < b.name) { return -1; } else { return 0; @@ -113,7 +113,7 @@ function makeHeaderPart() { // Generate Code let structures = ''; for (const structure of structureObjects) { - const name = structure.getName(); + const name = structure.name; structures += `// ${name}\n`; try { structures += structure.generate(); @@ -167,7 +167,7 @@ function makeCompiledCode(outputDir: string) { } // Structure - const name = structure.getName(); + const name = structure.name; declarations += `// ${name}\n`; try { declarations += structure.generateCode().trim(); diff --git a/src/loader.ts b/src/loader.ts index 8ef89be..e76a605 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -116,29 +116,29 @@ export function load(target: Struct, name: string, isExtended: boolean) { case 'vtable-size': { // Set VTable Size if (!isExtended) { - target.setVTableSize(safeParseInt(args)); + target.getVTable().setSize(safeParseInt(args)); } break; } case 'vtable': { // Set VTable Address - target.ensureVTable(); + const vtable = target.getVTable(); if (!isExtended && args.length > 0) { - target.setVTableAddress(safeParseInt(args)); + vtable.setAddress(safeParseInt(args)); } break; } case 'property': { // Add Property const info = parseProperty(args); - target.addProperty(new Property(info.offset, info.type, info.name, target.getName())); + target.addProperty(new Property(info.offset, info.type, info.name, target.name)); break; } case 'static-property': { // Add Static Property if (!isExtended) { const info = parseProperty(args); - target.addStaticProperty(new StaticProperty(info.offset, info.type, info.name, target.getName())); + target.addStaticProperty(new StaticProperty(info.offset, info.type, info.name, target.name)); } break; } @@ -150,14 +150,14 @@ export function load(target: Struct, name: string, isExtended: boolean) { } case 'virtual-method': { // Add Virtual Method - const method = parseMethod(args, target.getName(), true, isExtended); + const method = parseMethod(args, target.name, true, isExtended); target.addMethod(method, true); break; } case 'static-method': { // Add Static Method if (!isExtended) { - const method = parseMethod(args, target.getName(), false, false); + const method = parseMethod(args, target.name, false, false); target.addMethod(method, false); } break; @@ -165,7 +165,7 @@ export function load(target: Struct, name: string, isExtended: boolean) { case 'constructor': { // Constructor if (!isExtended) { - let data = `${target.getName()} *constructor`; + let data = `${target.name} *constructor`; if (args.startsWith('(')) { // No Custom Name data += ' '; @@ -174,14 +174,22 @@ export function load(target: Struct, name: string, isExtended: boolean) { data += '_'; } data += args; - const method = parseMethod(data, target.getName(), true, false); + const method = parseMethod(data, target.name, true, false); target.addMethod(method, false); } break; } case 'vtable-destructor-offset': { // Set VTable Destructor Offset - target.setVTableDestructorOffset(safeParseInt(args)); + target.getVTable().setDestructorOffset(safeParseInt(args)); + break; + } + case 'mark-as-simple': { + // Mark As Simple + if (isExtended) { + throw new Error('Cannot Extend Simple Structure'); + } + target.markAsSimple(); break; } default: { diff --git a/src/struct.ts b/src/struct.ts index 484fcf9..461f4d6 100644 --- a/src/struct.ts +++ b/src/struct.ts @@ -4,7 +4,7 @@ import { Property, StaticProperty } from './property'; import { VTable } from './vtable'; export class Struct { - readonly #name: string; + readonly name: string; #vtable: VTable | null; readonly #methods: Method[]; readonly #properties: Property[]; @@ -12,10 +12,11 @@ export class Struct { readonly #dependencies: string[]; readonly #staticProperties: StaticProperty[]; #directParent: string | null; + #isSimple: boolean; // Constructor constructor(name: string) { - this.#name = name; + this.name = name; this.#methods = []; this.#properties = []; this.#vtable = null; @@ -23,6 +24,7 @@ export class Struct { this.#dependencies = []; this.#staticProperties = []; this.#directParent = null; + this.#isSimple = false; } // Dependencies @@ -34,39 +36,29 @@ export class Struct { } // Ensure VTable Exists - ensureVTable() { + getVTable() { if (this.#vtable === null) { - this.#vtable = new VTable(this.#name); + this.#vtable = new VTable(this.name); this.addProperty(this.#vtable.property); } - } - - // Set VTable Destructor Offset - setVTableDestructorOffset(offset: number) { - this.ensureVTable(); - this.#vtable!.setDestructorOffset(offset); + return this.#vtable; } // Setters setSize(size: number) { this.#size = size; } - // Getters - getName() { - return this.#name; - } // Add Method addMethod(method: Method, isVirtual: boolean) { - if (method.returnType !== this.#name && method.returnType in STRUCTURE_FILES) { + if (method.returnType !== this.name && method.returnType in STRUCTURE_FILES) { this.#addDependency(method.returnType); } if (isVirtual) { - if (method.self !== this.#name) { + if (method.self !== this.name) { throw new Error(); } - this.ensureVTable(); - this.#vtable!.add(method); + this.getVTable().add(method); } else { if (method.isInherited) { this.#addDependency(method.self); @@ -88,14 +80,21 @@ export class Struct { this.#staticProperties.push(property); } - // Configure VTable - setVTableSize(size: number) { - this.ensureVTable(); - this.#vtable!.setSize(size); + // "Simple" Structures + markAsSimple() { + this.#isSimple = true; } - setVTableAddress(address: number) { - this.ensureVTable(); - this.#vtable!.setAddress(address); + #checkSimple() { + const checks = [ + ['Cannot Inherit', this.#directParent !== null], + ['Must Have A Defined Size', this.#size === null], + ['Cannot Have A VTable', this.#vtable !== null] + ]; + for (const check of checks) { + if (check[1]) { + throw new Error('Simple Structures ' + check[0]); + } + } } // Generate Properties @@ -127,7 +126,9 @@ export class Struct { if (lastProperty) { paddingSize += ` - sizeof(${lastProperty.type()})`; } - out += `${INDENT}uchar ${INTERNAL}padding${i}[${paddingSize}];\n`; + if (!this.#isSimple) { + out += `${INDENT}uchar ${INTERNAL}padding${i}[${paddingSize}];\n`; + } // The Actual Property if (property !== sizeProperty) { @@ -175,6 +176,13 @@ export class Struct { } } } + // Allocation Method + if (this.#size !== null) { + // THIS DOES NOT CONSTRUCT THE OBJECT + out += `${INDENT}static ${this.name} *allocate() {\n`; + out += `${INDENT}${INDENT}return (${this.name} *) ::operator new(sizeof(${this.name}));\n`; + out += `${INDENT}}\n`; + } // Return out += '#endif\n'; return out; @@ -184,6 +192,11 @@ export class Struct { generate() { let out = ''; + // Check "Simple" Status + if (this.#isSimple) { + this.#checkSimple(); + } + // VTable if (this.#vtable !== null) { out += this.#vtable.generate(); @@ -214,16 +227,16 @@ export class Struct { out += '#endif\n'; // Structure - out += `struct ${this.#name} {\n`; + out += `struct ${this.name} final {\n`; out += this.#generateProperties(); out += this.#generateMethods(); for (const property of this.#staticProperties) { // Static Property References out += `${INDENT}static ${property.referenceDefinition(false)};\n`; } - if (this.#size === null) { - // Prevent Manually Copying/Allocating Structure With Undefined - out += preventConstruction(this.#name); + if (!this.#isSimple) { + // Disable Construction Of Complex Structures + out += preventConstruction(this.name); } out += `};\n`; @@ -232,12 +245,12 @@ export class Struct { const property = this.#properties[i]!; const name = property.name(); const offset = property.offset; - out += `static_assert(offsetof(${this.#name}, ${name}) == ${toHex(offset)}, "Invalid Offset");\n`; + out += `static_assert(offsetof(${this.name}, ${name}) == ${toHex(offset)}, "Invalid Offset");\n`; } // Sanity Check Size if (this.#size !== null) { - out += assertSize(this.#name, this.#size); + out += assertSize(this.name, this.#size); } // Return diff --git a/src/vtable.ts b/src/vtable.ts index 2c3ecfc..0742a3e 100644 --- a/src/vtable.ts +++ b/src/vtable.ts @@ -133,7 +133,7 @@ export class VTable { // Structure out += `typedef struct ${this.#getName()} ${this.#getName()};\n`; - out += `struct ${this.#getName()} {\n`; + out += `struct ${this.#getName()} final {\n`; for (let i = 0; i < methods.length; i++) { const info = methods[i]; if (info) { diff --git a/syntax-highlighting/ksyntaxhighlighting/symbol-processor.xml b/syntax-highlighting/ksyntaxhighlighting/symbol-processor.xml index f1ce253..2323239 100644 --- a/syntax-highlighting/ksyntaxhighlighting/symbol-processor.xml +++ b/syntax-highlighting/ksyntaxhighlighting/symbol-processor.xml @@ -13,6 +13,7 @@ static-method constructor vtable-destructor-offset + mark-as-simple const diff --git a/syntax-highlighting/nano/symbol-processor.nanorc b/syntax-highlighting/nano/symbol-processor.nanorc index a190883..cca5e49 100644 --- a/syntax-highlighting/nano/symbol-processor.nanorc +++ b/syntax-highlighting/nano/symbol-processor.nanorc @@ -2,7 +2,7 @@ syntax def "\.def$" comment "//" # Commands -color magenta "\<(extends|size|vtable(-size|-destructor-offset)?|property|static-property|((static|virtual)-)?method|constructor)\>" +color magenta "\<(extends|size|vtable(-size|-destructor-offset)?|property|static-property|((static|virtual)-)?method|constructor|mark-as-simple)\>" # Types color green "\<((u?(char|short|int))|float|bool|void|std::(string|vector|map))\>" diff --git a/syntax-highlighting/textmate/SymbolProcessor.tmbundle/Syntaxes/SymbolProcessor.tmLanguage b/syntax-highlighting/textmate/SymbolProcessor.tmbundle/Syntaxes/SymbolProcessor.tmLanguage index 1103f73..0310d3a 100644 --- a/syntax-highlighting/textmate/SymbolProcessor.tmbundle/Syntaxes/SymbolProcessor.tmLanguage +++ b/syntax-highlighting/textmate/SymbolProcessor.tmbundle/Syntaxes/SymbolProcessor.tmLanguage @@ -34,13 +34,13 @@ name keyword.control.symbol-processor match - \b(extends|size|vtable-size|vtable-destructor-offset|vtable|property|static-property|method|virtual-method|static-method|constructor)\b + \b(extends|size|vtable-size|vtable-destructor-offset|vtable|property|static-property|method|virtual-method|static-method|constructor|mark-as-simple)\b name storage.type.symbol-processor match - \b(const|char|uchar|short|ushort|int|uint|float|bool|void|std::string|std::vector|std::map)\b + \b(const|char|uchar|short|ushort|int|uint|float|bool|void|std::string|std::vector|std::map|unsigned|long)\b name