void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut) { Indent(); String source; String line = ToString("public static partial class %sModule\n", module_->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += IndentLine("public static void Initialize()\n"); source += IndentLine("{\n"); Indent(); Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values(); for (unsigned i = 0; i < classes.Size(); i++) { JSBClass* klass = classes.At(i); JSBPackage* package = module_->GetPackage(); if (klass->IsNumberArray() || klass->IsAbstract()) continue; line = ToString("NativeCore.RegisterNativeType(typeof(%s));\n", klass->GetName().CString()); source += IndentLine(line); line = ToString("NativeCore.nativeClassIDToManagedConstructor [ %s.csb_%s_%s_GetClassIDStatic ()] = (IntPtr x) => {\n", klass->GetName().CString(), package->GetName().CString(), klass->GetName().CString()); source += IndentLine(line); Indent(); source += IndentLine(ToString("return new %s (x);\n", klass->GetName().CString())); Dedent(); source += IndentLine("};\n"); } Dedent(); source += IndentLine("}\n"); Dedent(); source += IndentLine("}\n"); sourceOut += source; Dedent(); }
void CSFunctionWriter::WriteManagedConstructor(String& source) { JSBClass* klass = function_->GetClass(); JSBPackage* package = klass->GetPackage(); if (klass->GetName() == "RefCounted") return; // wrapping constructor String line; line = ToString("public %s (IntPtr native) : base (native)\n", klass->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); source += IndentLine("}\n\n"); String sig; GenManagedFunctionParameters(sig); line = ToString("public %s (%s)\n", klass->GetName().CString(), sig.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); WriteDefaultStructParameters(source); line = ToString("if (typeof(%s) == this.GetType()", klass->GetName().CString()); line += ToString(" || (this.GetType().BaseType == typeof(%s) && !NativeCore.GetNativeType(this.GetType())))\n", klass->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); String callSig; GenPInvokeCallParameters(callSig); line = ToString("nativeInstance = NativeCore.RegisterNative (csb_%s_%s_Constructor(%s), this);\n", package->GetName().CString(), klass->GetName().CString(), callSig.CString()); source += IndentLine(line); Dedent(); source += IndentLine("}\n"); Dedent(); source += IndentLine("}\n"); }
void CSClassWriter::WriteManagedProperties(String& sourceOut) { String source; if (klass_->HasProperties()) { Vector<String> pnames; klass_->GetPropertyNames(pnames); for (unsigned j = 0; j < pnames.Size(); j++) { JSBProperty* prop = klass_->GetProperty(pnames[j]); JSBFunctionType* fType = NULL; JSBFunctionType* getType = NULL; JSBFunctionType* setType = NULL; if (CSTypeHelper::OmitFunction(prop->getter_) || CSTypeHelper::OmitFunction(prop->setter_)) continue; if (prop->getter_ && !prop->getter_->Skip()) { fType = getType = prop->getter_->GetReturnType(); } if (prop->setter_ && !prop->setter_->Skip()) { setType = prop->setter_->GetParameters()[0]; if (!fType) fType = setType; else if (fType->type_->ToString() != setType->type_->ToString()) continue; } if (!fType) continue; String line = klass_->IsInterface() ? "" : "public "; JSBClass* baseClass = klass_->GetBaseClass(); if (baseClass) { if (baseClass->MatchProperty(prop, true)) { // always new so we don't have to deal with virtual/override on properties line += "new "; } } String type = CSTypeHelper::GetManagedTypeString(fType, false); line += ToString("%s %s\n", type.CString(), prop->name_.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); if (prop->getter_) { if (klass_->IsInterface()) { source += IndentLine("get;\n"); } else { source += IndentLine("get\n"); source += IndentLine("{\n"); Indent(); source += IndentLine(ToString("return %s();\n", prop->getter_->GetName().CString())); Dedent(); source += IndentLine("}\n"); } } if (prop->setter_) { if (klass_->IsInterface()) { source += IndentLine("set;\n"); } else { source += IndentLine("set\n"); source += IndentLine("{\n"); Indent(); source += IndentLine(ToString("%s(value);\n", prop->setter_->GetName().CString())); Dedent(); source += IndentLine("}\n"); } } Dedent(); source += IndentLine("}\n\n"); } } sourceOut += source; }
void CSClassWriter::GenerateManagedSource(String& sourceOut) { String source = ""; if (klass_->IsNumberArray()) return; Indent(); source += "\n"; String line; if (klass_->GetDocString().Length()) { // monodocer -assembly:NETCore.dll -path:en -pretty // mdoc export-html -o htmldocs en source += IndentLine("/// <summary>\n"); if (klass_->GetDocString().Contains('\n')) source += IndentLine("/* " + klass_->GetDocString() + "*/\n"); else source += IndentLine("/// " + klass_->GetDocString() + "\n"); source += IndentLine("/// </summary>\n"); } if (klass_->GetBaseClass()) { String baseString = klass_->GetBaseClass()->GetName(); const PODVector<JSBClass*>& interfaces = klass_->GetInterfaces(); if (interfaces.Size()) { StringVector baseStrings; baseStrings.Push(baseString); for (unsigned i = 0; i < interfaces.Size(); i++) { baseStrings.Push(interfaces.At(i)->GetName()); } baseString = String::Joined(baseStrings, ","); } line = ToString("public partial class %s%s : %s\n", klass_->GetName().CString(), klass_->IsGeneric() ? "<T>" : "", baseString.CString()); } else { String classString = "class"; if (klass_->IsInterface()) classString = "interface"; line = ToString("public partial %s %s%s\n", classString.CString(), klass_->GetName().CString(), klass_->IsGeneric() ? "<T>" : ""); } source += IndentLine(line); source += IndentLine("{\n"); Indent(); WriteManagedProperties(source); JSBPackage* package = klass_->GetPackage(); // CoreCLR has pinvoke security demand code commented out, so we do not (currently) need this optimization: // https://github.com/dotnet/coreclr/issues/1605 // line = "[SuppressUnmanagedCodeSecurity]\n"; // source += IndentLine(line); if (!klass_->IsInterface()) { line = "[DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]\n"; source += IndentLine(line); line = ToString("public static extern IntPtr csb_%s_%s_GetClassIDStatic();\n", package->GetName().CString(), klass_->GetName().CString()); source += IndentLine(line); source += "\n"; } Dedent(); // managed functions CSFunctionWriter::SetWroteConstructor(false); for (unsigned i = 0; i < klass_->functions_.Size(); i++) { JSBFunction* function = klass_->functions_.At(i); if (function->Skip()) continue; if (klass_->IsInterface() && function->IsConstructor()) continue; if (function->IsDestructor()) continue; if (CSTypeHelper::OmitFunction(function)) continue; CSFunctionWriter fwriter(function); fwriter.GenerateManagedSource(source); } // There are some constructors being skipped (like HTTPRequest as it uses a vector of strings in args) // Make sure we have at least a IntPtr version if (!klass_->IsInterface() && !CSFunctionWriter::GetWroteConstructor() && klass_->GetName() != "RefCounted") { ATOMIC_LOGINFOF("WARNING: %s class didn't write a constructor, filling in generated native constructor", klass_->GetName().CString()); line = ToString("public %s (IntPtr native) : base (native)\n", klass_->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); source += IndentLine("}\n\n"); } CSFunctionWriter::SetWroteConstructor(false); source += IndentLine("}\n"); Dedent(); sourceOut += source; }
void CSModuleWriter::GenerateManagedEnumsAndConstants(String& source) { Vector<SharedPtr<JSBEnum>> enums = module_->enums_.Values(); Indent(); for (unsigned i = 0; i < enums.Size(); i++) { JSBEnum* jenum = enums[i]; source += "\n"; String line = "public enum " + jenum->GetName() + "\n"; source += IndentLine(line); source += IndentLine("{\n"); HashMap<String, String>& values = jenum->GetValues(); HashMap<String, String>::ConstIterator itr = values.Begin(); Indent(); while (itr != values.End()) { String name = (*itr).first_; String value = (*itr).second_; if (value.Length()) { line = name + " = " + value; } else { line = name; } itr++; if (itr != values.End()) line += ","; line += "\n"; source += IndentLine(line); } Dedent(); source += IndentLine("}\n"); } // constants HashMap<String, JSBModule::Constant>& constants = module_->GetConstants(); if (constants.Size()) { source += "\n"; String line = "public static partial class Constants\n"; source += IndentLine(line); source += IndentLine("{\n"); const Vector<String>& constantsName = constants.Keys(); Indent(); for (unsigned i = 0; i < constantsName.Size(); i++) { const String& cname = constantsName.At(i); JSBModule::Constant& constant = constants[cname]; String managedType = GetManagedPrimitiveType(constant.type); String value = constant.value; if (!value.Length()) continue; //static const unsigned M_MIN_UNSIGNED = 0x00000000; // /static const unsigned M_MAX_UNSIGNED = 0xffffffff; if (cname == "M_MIN_INT") value = "int.MinValue"; if (cname == "M_INFINITY") value = "float.MaxValue"; if (value == "M_MAX_UNSIGNED") value = "0xffffffff"; // Input stuff if (module_->GetName() == "Input") { if (cname.StartsWith("KEY_")) { if (value.Length() == 1 && (IsAlpha(value[0]) || IsDigit(value[0]))) value = "'" + value + "'"; } // https://raw.githubusercontent.com/flibitijibibo/SDL2-CS/master/src/SDL2.cs if (value.StartsWith("SDL_BUTTON_") || value.StartsWith("SDL_HAT_")) { value = "(int) SDL." + value; } else if (value.StartsWith("SDLK_")) { value = "(int) SDL.SDL_Keycode." + value; } else if (value.StartsWith("SDL_SCANCODE_")) { value = "(int) SDL.SDL_Scancode." + value; } else if (value.StartsWith("SDL_CONTROLLER_BUTTON_")) { value = "(int) SDL.SDL_GameControllerButton." + value; } else if (value.StartsWith("SDL_CONTROLLER_AXIS_")) { value = "(int) SDL.SDL_GameControllerAxis." + value; } } String line = "public const " + managedType + " " + cname + " = " + value; if (managedType == "float" && !line.EndsWith("f") && IsDigit(line[line.Length()-1])) line += "f"; line += ";\n"; source += IndentLine(line); } Dedent(); source += "\n"; line = "}\n"; source += IndentLine(line); } source += "\n"; Dedent(); }
void CSFunctionWriter::WriteNativeFunction(String& source) { JSBClass* klass = function_->GetClass(); JSBPackage* package = klass->GetPackage(); String fname = function_->IsConstructor() ? "Constructor" : function_->GetName(); String returnType; String functionSig = CSTypeHelper::GetNativeFunctionSignature(function_, returnType); String line; line = ToString("ATOMIC_EXPORT_API %s %s\n", returnType.CString(), functionSig.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += "\n"; bool returnValue = false; bool sharedPtrReturn = false; String returnStatement; if (returnType == "const char*") { returnValue = true; source += IndentLine("static String returnValue;\n"); returnStatement = "returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnClass()->IsNumberArray()) { returnStatement = "*returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnType()->isSharedPtr_) { returnStatement = ToString("SharedPtr<%s> returnValue = ", function_->GetReturnClass()->GetNativeName().CString()); sharedPtrReturn = true; } else { if (returnType != "void") { returnStatement = "return "; } } String callSig; GenNativeCallParameters(callSig); if (!function_->isConstructor_) { if (function_->IsStatic()) { line = ToString("%s%s::%s(%s);\n", returnStatement.CString(), klass->GetNativeName().CString(), function_->GetName().CString(), callSig.CString()); } else { line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString()); } } else { if (klass->IsAbstract()) { line = "return 0; // Abstract Class\n"; } else if (klass->IsObject()) { if (callSig.Length()) line = ToString("return new %s(NETCore::GetContext(), %s);\n", klass->GetNativeName().CString(), callSig.CString()); else line = ToString("return new %s(NETCore::GetContext());\n", klass->GetNativeName().CString()); } else { line = ToString("return new %s(%s);\n", klass->GetNativeName().CString(), callSig.CString()); } } source += IndentLine(line); if (sharedPtrReturn) { source += IndentLine("returnValue->AddRef();\n"); source += IndentLine("return returnValue;\n"); } else if (returnType == "const char*") { source += IndentLine("return returnValue.CString();\n"); } Dedent(); source += IndentLine("}\n"); source += "\n"; }
void CSFunctionWriter::WriteManagedConstructor(String& source) { JSBClass* klass = function_->GetClass(); JSBPackage* package = klass->GetPackage(); if (klass->GetName() == "RefCounted") return; // wrapping constructor String line; if (!wroteConstructor_) { line = ToString("public %s (IntPtr native) : base (native)\n", klass->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); source += IndentLine("}\n\n"); } // don't add wrapping constructor for overloads wroteConstructor_ = true; String sig; GenManagedFunctionParameters(sig); line = ToString("public %s (%s)\n", klass->GetName().CString(), sig.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); WriteDefaultStructParameters(source); source += IndentLine("if (nativeInstance == IntPtr.Zero)\n"); source += IndentLine("{\n"); Indent(); source += IndentLine(ToString("var classType = typeof(%s);\n", klass->GetName().CString())); source += IndentLine("var thisType = this.GetType();\n"); source += IndentLine("var thisTypeIsNative = NativeCore.IsNativeType(thisType);\n"); source += IndentLine("var nativeAncsestorType = NativeCore.GetNativeAncestorType(thisType);\n"); source += IndentLine("if ( (thisTypeIsNative && (thisType == classType)) || (!thisTypeIsNative && (nativeAncsestorType == classType)))\n"); source += IndentLine("{\n"); Indent(); String callSig; GenPInvokeCallParameters(callSig); line = ToString("nativeInstance = NativeCore.RegisterNative (csb_%s_%s_Constructor_%u(%s), this);\n", package->GetName().CString(), klass->GetName().CString(), function_->GetID(), callSig.CString()); source += IndentLine(line); Dedent(); source += IndentLine("}\n"); Dedent(); source += IndentLine("}\n"); Dedent(); source += IndentLine("}\n"); }
void CSFunctionWriter::WriteNativeFunction(String& source) { JSBClass* klass = function_->GetClass(); JSBPackage* package = klass->GetPackage(); String fname = function_->IsConstructor() ? "Constructor" : function_->GetName(); String returnType; String functionSig = CSTypeHelper::GetNativeFunctionSignature(function_, returnType); String line; line = ToString("ATOMIC_EXPORT_API %s %s\n", returnType.CString(), functionSig.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += "\n"; // vector marshal bool hasVectorMarshal = false; const Vector<JSBFunctionType*>& fparams = function_->GetParameters(); for (unsigned i = 0; i < fparams.Size(); i++) { JSBFunctionType* ftype = fparams[i]; // Interface JSBClass* interface = 0; if (ftype->type_->asClassType() && ftype->type_->asClassType()->class_->IsInterface()) { // We need to downcast to the interface // TODO: this assumes Object* is in hierarchy, how do we validate this? interface = ftype->type_->asClassType()->class_; line = ToString("%s = dynamic_cast<%s*>((Object*)%s);\n", ftype->name_.CString(), interface->GetNativeName().CString(), ftype->name_.CString()); source += IndentLine(line); } // Vector JSBVectorType* vtype = ftype->type_->asVectorType(); if (!vtype) continue; JSBClassType* classType = vtype->vectorType_->asClassType(); if (!classType) continue; String className = classType->class_->GetName(); String vectorMarshal; hasVectorMarshal = true; if (vtype->isPODVector_) { const String& pname = ftype->name_; source += IndentLine(ToString("PODVector<%s*> %s__vector;\n", className.CString(), pname.CString())); source += IndentLine(ToString("if (%s) %s->AdaptToVector<%s*>(%s__vector);\n", pname.CString(), pname.CString(), className.CString(), pname.CString())); } else { // vectorMarshal = ToString("PODVector<%s*> %s__vector", className.CString(), ftype->name_.CString()); } if (vectorMarshal.Length()) { source += IndentLine(vectorMarshal); vectorMarshal = String::EMPTY; } } bool returnValue = false; bool sharedPtrReturn = false; String returnStatement; if (returnType == "const char*") { returnValue = true; source += IndentLine("static String returnValue;\n"); returnStatement = "returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnClass()->IsNumberArray()) { returnStatement = "*returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnType()->isSharedPtr_) { returnStatement = ToString("SharedPtr<%s> returnValue = ", function_->GetReturnClass()->GetNativeName().CString()); sharedPtrReturn = true; } else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType()) { // we have an out parameter JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType(); if (!vtype->vectorTypeIsSharedPtr_ && !vtype->vectorTypeIsWeakPtr_) { returnStatement = ToString("%sVector<%s*> returnValue__vector = ", vtype->isPODVector_ ? "POD" : "", vtype->vectorType_->asClassType()->class_->GetName().CString()); } else { returnStatement = ToString("%sVector<%s<%s>> returnValue__vector = ", vtype->isPODVector_ ? "POD" : "", vtype->vectorTypeIsSharedPtr_ ? "SharedPtr" : "WeakPtr", vtype->vectorType_->asClassType()->class_->GetName().CString()); } } else { if (returnType != "void" && !hasVectorMarshal) { returnStatement = "return "; } else if (returnType != "void") { returnStatement = ToString("%s returnValue = ", returnType.CString()); } } String callSig; GenNativeCallParameters(callSig); if (!function_->isConstructor_) { if (function_->IsStatic()) { line = ToString("%s%s::%s(%s);\n", returnStatement.CString(), klass->GetNativeName().CString(), function_->GetName().CString(), callSig.CString()); } else { line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString()); } } else { if (klass->IsAbstract()) { line = "return 0; // Abstract Class\n"; } else if (klass->IsObject()) { if (callSig.Length()) line = ToString("return new %s(NETCore::GetContext(), %s);\n", klass->GetNativeName().CString(), callSig.CString()); else line = ToString("return new %s(NETCore::GetContext());\n", klass->GetNativeName().CString()); } else { line = ToString("return new %s(%s);\n", klass->GetNativeName().CString(), callSig.CString()); } } source += IndentLine(line); // Vector marshaling for (unsigned i = 0; i < fparams.Size(); i++) { JSBFunctionType* ftype = fparams[i]; JSBVectorType* vtype = ftype->type_->asVectorType(); if (!vtype) continue; JSBClassType* classType = vtype->vectorType_->asClassType(); if (!classType) continue; String className = classType->class_->GetName(); String vectorMarshal; if (vtype->isPODVector_) { const String& pname = ftype->name_; source += IndentLine(ToString("if (%s) %s->AdaptFromVector<%s*>(%s__vector);\n", pname.CString(), pname.CString(), className.CString(), pname.CString())); } else { // vectorMarshal = ToString("PODVector<%s*> %s__vector", className.CString(), ftype->name_.CString()); } if (vectorMarshal.Length()) { source += IndentLine(vectorMarshal); vectorMarshal = String::EMPTY; } } if (sharedPtrReturn) { source += IndentLine("if (returnValue.NotNull()) returnValue->AddRef();\n"); source += IndentLine("return returnValue;\n"); } else if (returnType == "const char*") { source += IndentLine("return returnValue.CString();\n"); } else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType()) { // we have an out parameter JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType(); source += IndentLine("if (returnValue) returnValue->AdaptFromVector(returnValue__vector);\n"); } else if (returnType != "void" && hasVectorMarshal) { source += IndentLine("return returnValue;\n"); } Dedent(); source += IndentLine("}\n"); source += "\n"; }