This commit is contained in:
TheBrokenRail 2024-01-04 17:00:19 -05:00
parent e99239fecf
commit ddbbbcb8e3
5 changed files with 120 additions and 91 deletions

View File

@ -3,9 +3,12 @@ import * as fs from 'node:fs';
export const INDENT = ' ';
export const POINTER_SIZE = 4;
export const EXTENSION = '.def';
export const STRUCTURE_FILES: {[id: string]: string} = {};
export function readDefinition(name: string) {
const file = `${__dirname}/../symbols/${name}${EXTENSION}`;
return fs.readFileSync(file, {encoding: 'utf8'});
if (!STRUCTURE_FILES[name]) {
throw new Error(`Missing Definition File: ${name}${EXTENSION}`);
}
return fs.readFileSync(STRUCTURE_FILES[name]!, {encoding: 'utf8'});
}
export function parseTypeAndName(parts: string[]) {
let type = parts[0]!;

View File

@ -1,29 +1,50 @@
import * as fs from 'node:fs';
import { EXTENSION, INDENT } from './common';
import { STRUCTURE_FILES, EXTENSION, INDENT } from './common';
import { getStructure, setCppAllowed } from './map';
// Output Directory
let outputDirectory = process.argv[2];
if (!outputDirectory) {
outputDirectory = `${__dirname}/../out`;
// Arguments
if (process.argv.length < 5) {
console.log('USAGE: npm run <Source Output File> <Header Output File> <Input Files...>');
process.exit(1);
}
process.argv.shift();
process.argv.shift();
function invalidFileType(file: string) {
throw new Error(`Invalid File Type: ${file}`);
}
const sourceOutput = process.argv.shift()!;
if (!sourceOutput.endsWith('.cpp')) {
invalidFileType(sourceOutput);
}
const headerOutput = process.argv.shift()!;
if (!headerOutput.endsWith('.h')) {
invalidFileType(headerOutput);
}
const extraHeaders: string[] = [];
while (process.argv.length > 0) {
const file = process.argv.shift()!;
if (file.endsWith(EXTENSION)) {
// Get Class Name
const parts = file.split('/');
let name = parts[parts.length - 1]!;
name = name.substring(0, name.length - EXTENSION.length);
// Store
STRUCTURE_FILES[name] = file;
} else if (file.endsWith('.h')) {
// Extra Headers
extraHeaders.push(file);
} else {
// Invalid File Type
invalidFileType(file);
}
}
fs.rmSync(outputDirectory, {force: true, recursive: true});
fs.mkdirSync(outputDirectory, {recursive: true});
// Main
// Load And Sort Structures
function loadSymbols() {
// Load
const files = fs.readdirSync(`${__dirname}/../symbols`);
const structureObjects = [];
for (const file of files) {
if (file.endsWith(EXTENSION)) {
// Get Name
const parts = file.split('/');
let name = parts[parts.length - 1]!;
name = name.substring(0, name.length - EXTENSION.length);
// Structures
structureObjects.push(getStructure(name));
}
for (const name in STRUCTURE_FILES) {
structureObjects.push(getStructure(name));
}
// Sort
structureObjects.sort((a, b) => {
@ -38,20 +59,15 @@ function loadSymbols() {
// Return
return structureObjects;
}
function makeHeader(output: string, allowCpp: boolean) {
// Generate Part Of Header
function makeHeaderPart(allowCpp: boolean) {
// Set Mode
setCppAllowed(allowCpp);
// Load Symbols
const structureObjects = loadSymbols();
// Forward Declarations
let forwardDeclarations = '// Forward Declarations\n';
for (const structure of structureObjects) {
const name = structure.getName();
forwardDeclarations += `typedef struct ${name} ${name};\n`;
}
// Sort Structures By Dependency
while (true) {
let valid = true;
@ -84,9 +100,15 @@ function makeHeader(output: string, allowCpp: boolean) {
// Generate Code
let structures = '';
let isFirst = true;
for (const structure of structureObjects) {
const name = structure.getName();
structures += `\n// ${name}\n`;
if (isFirst) {
isFirst = false;
} else {
structures += '\n';
}
structures += `// ${name}\n`;
try {
structures += structure.generate();
} catch (e) {
@ -95,22 +117,50 @@ function makeHeader(output: string, allowCpp: boolean) {
}
}
// Write
let result = '';
result += '#pragma once\n';
result += '\n';
result += forwardDeclarations;
result += '\n// Init\n';
result += 'void init_symbols();';
result += '\n// Extra Definitions\n';
result += fs.readFileSync(`${__dirname}/../symbols/extra.h`, {encoding: 'utf8'}).trim() + '\n';
result += structures;
fs.writeFileSync(output, result);
// Return
return structures;
}
// Run
makeHeader(`${outputDirectory}/minecraft_c.h`, false);
makeHeader(`${outputDirectory}/minecraft_cpp.h`, true);
// Create Main Header
function makeMainHeader(output: string) {
let result = '';
result += '#pragma once\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 int uint;\n';
result += '\n// Init\n';
result += 'void init_symbols();\n';
result += '\n// Forward Declarations\n';
for (const name in STRUCTURE_FILES) {
result += `typedef struct ${name} ${name};\n`;
}result += '\n// Extra Headers\n';
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 += '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 += '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';
fs.writeFileSync(output, result);
}
makeMainHeader(headerOutput);
// Generate Compiled Code
function makeCompiledCode(output: string) {
@ -122,10 +172,17 @@ function makeCompiledCode(output: string) {
// Generate
let declarations = '';
let init = '';
let isFirst = true;
for (const structure of structureObjects) {
const name = structure.getName();
declarations += `\n// ${name}\n`;
init += `\n${INDENT}// ${name}\n`;
if (isFirst) {
isFirst = false;
} else {
declarations += '\n';
init += '\n';
}
declarations += `// ${name}\n`;
init += `${INDENT}// ${name}\n`;
try {
const code = structure.generateCode();
declarations += code.functions;
@ -138,39 +195,13 @@ function makeCompiledCode(output: string) {
// Write
let result = '';
result += '#include "minecraft.h"\n';
result += `#include "${fs.realpathSync(headerOutput)}"\n`;
result += '\n#include <cstring>\n';
result += '\n// Init\n';
result += 'void init_symbols() {';
result += 'void init_symbols() {\n';
result += init;
result += '}\n';
result += '}\n\n';
result += declarations;
fs.writeFileSync(output, result);
}
makeCompiledCode(`${outputDirectory}/minecraft.cpp`);
// Create Main Header
function makeMainHeader(output: string) {
let result = '';
result += '#pragma once\n';
result += '#pragma GCC diagnostic push\n';
result += '#pragma GCC diagnostic ignored "-Wunused-variable"\n';
result += '#pragma GCC diagnostic ignored "-Wunused-function"\n';
result += 'typedef unsigned char uchar;\n';
result += 'typedef unsigned int uint;\n';
result += '#include <string.h>\n';
result += '#include <stdlib.h>\n';
result += '#include <stddef.h>\n';
result += '#ifndef __cplusplus\n';
result += 'typedef unsigned char bool;\n';
result += '#include "minecraft_c.h"\n';
result += '#else\n';
result += '#include <string>\n';
result += '#include <vector>\n';
result += 'extern "C" {\n';
result += '#include "minecraft_cpp.h"\n';
result += '}\n';
result += '#endif\n';
result += '#pragma GCC diagnostic pop\n';
fs.writeFileSync(output, result);
}
makeMainHeader(`${outputDirectory}/minecraft.h`);
makeCompiledCode(sourceOutput);

View File

@ -4,6 +4,7 @@ import { Method } from './method';
import { SimpleProperty, StaticProperty } from './property';
import { Struct } from './struct';
// Error Handling
function safeParseInt(str: string) {
const x = parseInt(str);
if (isNaN(x)) {
@ -14,7 +15,6 @@ function safeParseInt(str: string) {
function syntaxError(message?: string) {
throw new Error('Syntax Error' + (message ? `: ${message}` : ''));
}
export class ErrorOnLine {
readonly error: unknown;
readonly file: string;
@ -199,14 +199,6 @@ export function load(target: Struct, name: string, isExtended: boolean) {
}
break;
}
case 'requires': {
// Add Dependency
if (args.length === 0) {
syntaxError('Missing Dependency Name');
}
target.addDependency(args);
break;
}
default: {
throw new Error(`Invalid Command: ${command}`);
}

View File

@ -16,7 +16,7 @@ const structures: {[id: string]: Struct} = {};
// Get Or Load Structure
export function getStructure(name: string) {
if (Object.prototype.hasOwnProperty.call(structures, name)) {
if (name in structures) {
// Already Loaded
return structures[name]!;
} else {
@ -45,8 +45,6 @@ export function getStructure(name: string) {
// Clear Loaded Structures
function clearStructures() {
for (const name in structures) {
if (Object.prototype.hasOwnProperty.call(structures, name)) {
delete structures[name];
}
delete structures[name];
}
}

View File

@ -1,4 +1,4 @@
import { INDENT, MIN_SIZE, toUpperSnakeCase, formatType } from './common';
import { INDENT, MIN_SIZE, toUpperSnakeCase, formatType, STRUCTURE_FILES } from './common';
import { isCppAllowed } from './map';
import { Method } from './method';
import { Property, StaticProperty } from './property';
@ -25,7 +25,7 @@ export class Struct {
}
// Dependencies
addDependency(dependency: string) {
#addDependency(dependency: string) {
this.#dependencies.push(dependency);
}
getDependencies() {
@ -94,6 +94,11 @@ export class Struct {
// Add Property
addProperty(property: Property) {
this.#properties.push(property);
// Add Dependency If Needed
const type = property.propertyType();
if (type in STRUCTURE_FILES) {
this.#addDependency(type);
}
}
// Add Static Property
addStaticProperty(property: StaticProperty) {