class CppParameter { name = ""; type = ""; } class CppClassMember { name = ""; isMethod = false; isVirtual = false; isStatic = false; isSignal = false; type = "void"; initialValue = null; parameters = []; constructor( nameDefinition, body ) { if ( nameDefinition.indexOf( "()" ) != -1) { this.isMethod = true; let typeRegex = /\(\)\s*(?:\:\s*(.+)\s*)?$/; let result = typeRegex.exec( nameDefinition ); if ( result[ 1 ] ) { this.type = result[ 1 ]; } nameDefinition = nameDefinition.replace( typeRegex, "" ); } let names = nameDefinition.split( /\s+/ ); this.name = names[ names.length -1 ]; for ( let i = 0; i < names.length - 1; i++ ) { if ( "virtual" === names[ i ] ) { this.isVirtual = true; } if ( "static" === names[ i ] ) { this.isStatic = true; } if ( "signal" === names[ i ] ) { this.isSignal = true; } } if ( this.isMethod ) { this.parseMethodBody( body ); } else { this.parseVariableBody( body ); } } get isMemberWithInitialValue() { return ! this.isMethod && this.initialValue !== null; } getMemberInitializer() { return `${this.name} = ${this.initialValue};`; } parseVariableBody( body ) { if ( typeof body === "boolean" ) { this.type = "bool"; this.initialValue = body + ""; return; } if ( typeof body === "number" ) { this.type = "float"; this.initialValue = body + ""; return; } let regex = /((?:\w|\<|\>)+)(?:\s*\=\s*(.+))?/; let result = regex.exec( body ); this.type = result[ 1 ]; this.initialValue = result[ 2 ] || null; } parseMethodBody( body ) { if ( ! body ) { return; } if ( typeof body === "string" ) { this.type = body; return; } for ( let it in body ) { if ( ! body.hasOwnProperty( it ) ) { continue; } let cppParameter = new CppParameter(); cppParameter.name = it; cppParameter.type = body[ it ]; this.parameters.push( cppParameter ); } } getMethodBinding( className ) { if ( ! this.isMethod ) { let type = stringToVariantType( this.type ); let bindings = []; bindings.push( `/* ${this.name}: ${this.type} */` ); bindings.push( `ClassDB::bind_method(D_METHOD("get_${this.name}"), &${className}::get_${this.name});` ); bindings.push( `ClassDB::bind_method(D_METHOD("set_${this.name}"), &${className}::set_${this.name});` ); bindings.push( `ADD_PROPERTY(PropertyInfo(Variant::${type}, "${this.name}"), "set_${this.name}", "get_${this.name}");` ); bindings.push( ` ` ); //ClassDB::bind_method(D_METHOD("set_color", "color"), &GLTFLight::set_color); //ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); // Color return bindings.join( "\n " ); } if ( this.isSignal ) { //ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported"))); let parameterInfos = ""; for ( let i = 0; i < this.parameters.length; i++ ) { let type = stringToVariantType( this.parameters[ i ].type ); let name = this.parameters[ i ].name; let pi = `, PropertyInfo(Variant::${type}, "${name}")`; parameterInfos += pi; } return `ADD_SIGNAL (MethodInfo( "${this.name}" ${parameterInfos}) );`; } else if ( this.isVirtual ) { let parameterInfos = ""; for ( let i = 0; i < this.parameters.length; i++ ) { let name = `, "${this.parameters[ i ].name}"`; parameterInfos += name; } return `GDVIRTUAL_BIND( ${this.name}${parameterInfos} );`; } else { return `ClassDB::bind_method( D_METHOD( "${this.name}" ) , &${className}::${this.name} );` } } getHeaderDefinition() { if ( this.isSignal ) { return `/* signal ${this.name} */`; } else if ( this.isMethod ) { return this.getMethodHeaderDefinition(); } else { return this.getVariableHeaderDefinition(); } } getParametersDefinition() { return this.parameters.map( p => p.type + " " + p.name ).join( ", " ); } getMethodHeaderDefinition() { if ( this.isVirtual ) { let numParameters = this.parameters.length; let methodReturnType = this.type === "void" ? "" : "R"; let returnTypeDefinition = this.type === "void" ? "" : ( this.type + ", " ) ; let parametersDefinition = ""; if ( numParameters > 0 ) { parametersDefinition = ", " + this.parameters.map( p => p.type ).join( ", " ); } return `GDVIRTUAL${numParameters}${methodReturnType}( ${returnTypeDefinition}${this.name}${parametersDefinition} );` } return `${this.type} ${this.name}(${this.parametersDefinition});` } getVariableHeaderDefinition() { return `${this.type} get_${this.name}(); void set_${this.name}( ${this.type} p_${this.name} );` //return `${this.type} ${this.name};` } getPropertyHeaderDefinition() { return `${this.type} ${this.name};` } getPropertyImplementation( className ) { let bindings = []; bindings.push( `/* ${this.name}: ${this.type} */` ); bindings.push( `${this.type} ${className}::get_${this.name}() { return ${this.name}; }` ); bindings.push( `void ${className}::set_${this.name}( ${this.type} p_${this.name} ) { ${this.name} = p_${this.name}; }` ); bindings.push( ` ` ); return bindings.join( "\n" ); } } module.exports = { CppParameter, CppClassMember } function stringToVariantType( stringType ) { if ( /^TypedArray\<.+\>$/.test( stringType ) ) { return "ARRAY"; } switch( stringType ) { case "bool": return "BOOL"; case "int": return "INT"; case "float": return "FLOAT"; case "String": return "STRING"; // Math types. case "Vector2": return "VECTOR2"; case "Vector2i": return "VECTOR2I"; case "Rect2": return "RECT2"; case "Rect2i": return "RECT2I"; case "Transform2D": return "TRANSFORM2D"; case "Vector3": return "VECTOR3"; case "Vector3i": return "VECTOR3I"; case "Vector4": return "VECTOR4"; case "Vector4i": return "VECTOR4I"; case "Plane": return "PLANE"; case "AABB": return "AABB"; case "Quaternion": return "QUATERNION"; case "Basis": return "BASIS"; case "Transform3D": return "TRANSFORM3D"; case "Projection": return "PROJECTION"; // Miscellaneous types. case "Color": return "COLOR"; case "RID": return "RID"; case "Object": return "OBJECT"; case "Callable": return "CALLABLE"; case "Signal": return "SIGNAL"; case "StringName": return "STRING_NAME"; case "NodePath": return "NODE_PATH"; case "Dictionary": return "DICTIONARY"; case "Array": return "ARRAY"; // Arrays. case "PackedByteArray": return "PACKED_BYTE_ARRAY"; case "PackedInt32Array": return "PACKED_INT32_ARRAY"; case "PackedInt64Array": return "PACKED_INT64_ARRAY"; case "PackedFloat32Array": return "PACKED_FLOAT32_ARRAY"; case "PackedFloat64Array": return "PACKED_FLOAT64_ARRAY"; case "PackedStringArray": return "PACKED_STRING_ARRAY"; case "PackedVector2Array": return "PACKED_VECTOR2_ARRAY"; case "PackedVector3Array": return "PACKED_VECTOR3_ARRAY"; case "PackedColorArray": return "PACKED_COLOR_ARRAY"; } console.error( "Type could not be mapped: ", stringType ); return "OBJECT"; }