222 lines
6.6 KiB
TypeScript
222 lines
6.6 KiB
TypeScript
import { Member } from "./members/Member";
|
|
import { Header } from "./Header";
|
|
import { Implementation } from "./Implementation";
|
|
import { Files } from "../library/Files";
|
|
import { MatchResult } from "../library/MatchResult";
|
|
import { Texts } from "../library/Texts";
|
|
import { MemberType } from "./MemberType";
|
|
import { Field } from "./members/Field";
|
|
import { RJLog } from "../library/RJLog";
|
|
import { CppDefinition } from "./CppDefinition";
|
|
import { Objects } from "../library/Objects";
|
|
import { Variations } from "./Variations";
|
|
import { VariationDefinitions, VariationTemplates } from "./VariationTemplates";
|
|
import { Method } from "./members/Method";
|
|
import { MemberFactory } from "./factories/MemberFactory";
|
|
|
|
export class CppCreator
|
|
{
|
|
static definitionsPath = __dirname + "/../../../rokojori-action-library-definitions";
|
|
static outputPath = __dirname + "/../../../rokojori-action-library";
|
|
static rawPath = CppCreator.definitionsPath + "/_raw";
|
|
static registerTypesPath = CppCreator.rawPath + "/register_types.cpp";
|
|
static registerTypesPathOutput = CppCreator.outputPath + "/register_types.cpp";
|
|
|
|
static createIncludes( className:string )
|
|
{
|
|
// RJLog.log( "Create include", className );
|
|
|
|
let godotClasses:any =
|
|
{
|
|
"Node" : "scene/main/node.h",
|
|
"Node2D" : "scene/2d/node_2d.h",
|
|
"Node3D" : "scene/3d/node_3d.h",
|
|
"Resource" : "core/io/resource.h"
|
|
}
|
|
|
|
if ( godotClasses[ className ] )
|
|
{
|
|
return `#include "${godotClasses[ className ]}"`;
|
|
}
|
|
|
|
|
|
return `#include "./${className}.h"`;
|
|
}
|
|
|
|
static getHeaderDefine( className:string )
|
|
{
|
|
className = className.replace( /^RJ/, "" );
|
|
|
|
let output = [ className[ 0 ] ];
|
|
|
|
for ( let i = 1; i < className.length; i++ )
|
|
{
|
|
let character = className[ i ];
|
|
let upperCaseCharacter = character.toUpperCase();
|
|
|
|
if ( character === upperCaseCharacter )
|
|
{
|
|
output.push( "_" );
|
|
|
|
}
|
|
|
|
output.push( upperCaseCharacter );
|
|
|
|
}
|
|
|
|
className = output.join( "" );
|
|
|
|
return "ROKOJORI__" + className + "_H";
|
|
}
|
|
|
|
static async createCppFiles( definitionPath:string )
|
|
{
|
|
let jsonPath = definitionPath;
|
|
// path.join( definitionsPath, definitionPath );
|
|
|
|
let isDir = await Files.isDirectory( jsonPath );
|
|
|
|
if ( isDir )
|
|
{
|
|
let files = await Files.getFiles( jsonPath );
|
|
|
|
for ( let file of files )
|
|
{
|
|
if ( file.startsWith( "_" ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
await CppCreator.createCppFiles( Texts.joinPaths( jsonPath, file ) );
|
|
}
|
|
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return this.createCppFile( jsonPath );
|
|
|
|
}
|
|
|
|
static async createCppFile( jsonPath:string )
|
|
{
|
|
let data = await Files.loadJSON<CppDefinition>( jsonPath );
|
|
|
|
if ( data.variations )
|
|
{
|
|
let variationsData = data.variations;
|
|
|
|
if ( typeof variationsData == "string" )
|
|
{
|
|
variationsData = (VariationTemplates as any as {[index:string]:VariationDefinitions})[ variationsData ];
|
|
}
|
|
|
|
let variations = new Variations( variationsData );
|
|
|
|
console.log( variations.items, variations.counter, variations.hasItems );
|
|
|
|
while ( variations.hasItems )
|
|
{
|
|
let newData = CppDefinition.createVariation( data, variations.currentMap );
|
|
|
|
await this.createCppFileWith( newData );
|
|
|
|
variations.nextItem();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await CppCreator.createCppFileWith( data );
|
|
}
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
}
|
|
|
|
static async createCppFileWith( data:CppDefinition )
|
|
{
|
|
let classNameResult = /(\w+)(?:\:(\w+))?/.exec( data.class );
|
|
|
|
let className = classNameResult[ 1 ];
|
|
let extendingClass = classNameResult[ 2 ];
|
|
|
|
let headerDefine = CppCreator.getHeaderDefine( className );
|
|
|
|
let fromProtectedMembers = MemberFactory.grabMembers( data.protected, "protected" );
|
|
let fromPublicMembers = MemberFactory.grabMembers( data.public, "public" );
|
|
|
|
let protectedMembers:Member[] = [];
|
|
let publicMembers:Member[] = [];
|
|
|
|
let insertMember = ( m:Member ) =>
|
|
{
|
|
let container = m.accessModifier === "public" ? publicMembers : protectedMembers;
|
|
container.push( m );
|
|
};
|
|
|
|
fromProtectedMembers.forEach( m => insertMember( m ) );
|
|
fromPublicMembers.forEach( m => insertMember( m ) );
|
|
|
|
|
|
let allMembers:Member[] = [].concat( protectedMembers ).concat( publicMembers );
|
|
|
|
|
|
let protectedHeader = protectedMembers.map( m => m.getHeaderDefinition() ).join( "\n " );
|
|
let publicHeader = publicMembers.map( m => m.getHeaderDefinition() ).join( "\n " );
|
|
|
|
let fields:Field[] = allMembers.filter( m => m.memberType === MemberType.Field ) as Field[];
|
|
let methods:Method[] = allMembers.filter( m => m.memberType === MemberType.Method ) as Method[];
|
|
|
|
let fieldDeclarations = fields.map( f => f.getFieldDeclaration() ).join( "\n " );
|
|
|
|
protectedHeader += "\n\n " + fieldDeclarations;
|
|
|
|
let methodBindings = allMembers.map( m => m.getBindings( className ) ).join( "\n " );
|
|
|
|
let initializers = fields.filter( m => m.hasInitializer ).map( m => m.getInitializer() ).join( "\n ");
|
|
|
|
let includes = `#include "./RJGodotHeaders.h"`;
|
|
|
|
if ( data.includes )
|
|
{
|
|
let mappedIncludes = data.includes.map( ( inc:string ) => `#include "${inc}"` );
|
|
includes += "\n" + mappedIncludes.join( "\n" );
|
|
}
|
|
|
|
let extendingClassInclude = CppCreator.createIncludes( extendingClass );
|
|
|
|
includes += "\n" + extendingClassInclude;
|
|
|
|
let forwards = "";
|
|
|
|
if ( data.forwards )
|
|
{
|
|
let forwardDeclarations = data.forwards as string[];
|
|
forwards = forwardDeclarations.join( "\n" );
|
|
}
|
|
|
|
let header = Header.create( className, extendingClass, headerDefine,
|
|
protectedHeader, publicHeader, includes,
|
|
forwards );
|
|
|
|
let constructorExpressions = initializers;
|
|
let destructorExpressions = "";
|
|
let implementations = "";
|
|
|
|
let fieldImplementations = fields.map( f => f.getFieldImplementation( className ) );
|
|
implementations += fieldImplementations.join( "\n" ) + "\n";
|
|
|
|
let methodsWithImplementation = methods.filter( m => m.hasMethodImplementation );
|
|
let methodImplementations = methodsWithImplementation.map( m => m.getMethodImplementation( className ) );
|
|
|
|
implementations += methodImplementations.join( "\n" );
|
|
|
|
let implementation = Implementation.craete( className, methodBindings, constructorExpressions, destructorExpressions, implementations );
|
|
|
|
let rawFilePath = Texts.joinPaths( CppCreator.outputPath, className );
|
|
|
|
await Files.saveUTF8( rawFilePath + ".h", header );
|
|
await Files.saveUTF8( rawFilePath + ".cpp", implementation );
|
|
}
|
|
|
|
} |