Update
This commit is contained in:
parent
e99239fecf
commit
ddbbbcb8e3
@ -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]!;
|
||||
|
179
src/index.ts
179
src/index.ts
@ -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);
|
@ -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}`);
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user