| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- //
- // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #include <Atomic/IO/FileSystem.h>
- #include "../JSBind.h"
- #include "../JSBModule.h"
- #include "../JSBPackage.h"
- #include "../JSBEnum.h"
- #include "../JSBClass.h"
- #include "../JSBFunction.h"
- #include "CSTypeHelper.h"
- #include "CSFunctionWriter.h"
- /*
- *
- C# getters/setters
- local instance storage so we're not constantly creating managed Vector3, etc
- Vector2/Vector3/BoundingBox, etc C# structs so assign by value
- Object lifetime
- C# enum of module types for type info?
- C# version of push class instance?
- new instance from C# needs constructor
- wrapping does not, wrapping doesn't use constructors at all (JS needs this for prototype)
- Store GCHandle to keep an object alive (Component, UI) C# side?
- typedef const void* ClassID;
- which changed based on address, so need register at startup
- so at package startup time, need to setup mapping between
- IntPtr and C# class, we also need to be able to new a class
- instance with existing native or create a native when new'ing from C#
- IntPtr to RefCounted native side is the "ID", like JSHeapPtr
- Lifetime:
- // you cannot derive from native engine classes, other than script components
- a C# instance can be new'd, handed to native, stored in native, the C# side could be GC'd
- future access to this instance would be a new instance
- */
- /*
- // struct marshal Vector2, Vector3, BoundingBox, etc
- // RefCounted*
- // primitive bool, int, uint, float, double
- // String
- RefCounted* csb_Node_Constructor()
- {
- return new Node(NETCore::GetContext());
- }
- void csb_Node_GetPosition(Node* self, Vector3* out)
- {
- *out = self->GetPosition();
- }
- void csb_Node_SetPosition(Node* self, Vector3*__arg0)
- {
- self->SetPosition(*__arg0);
- }
- void csb_Node_SetPosition(Node* self, Vector3*__arg0)
- {
- self->SetPosition(*__arg0);
- }
- bool csb_Audio_Play(Audio* self)
- {
- bool retValue = self->Play();
- return retValue;
- }
- const RefCounted* csb_Node_GetParent(Node* self)
- {
- const RefCounted* retValue = self->GetParent();
- return RefCounted;
- }
- RefCounted* csb_ObjectAnimation_Constructor()
- {
- return new ObjectAnimation(NETCore::GetContext());
- }
- */
- namespace ToolCore
- {
- CSFunctionWriter::CSFunctionWriter(JSBFunction *function) : JSBFunctionWriter(function)
- {
- }
- void CSFunctionWriter::WriteNativeParameterMarshal(String& source)
- {
- }
- void CSFunctionWriter::WriteNativeConstructor(String& source)
- {
- }
- void CSFunctionWriter::GenNativeCallParameters(String& sig)
- {
- JSBClass* klass = function_->GetClass();
- Vector<JSBFunctionType*>& parameters = function_->GetParameters();
- Vector<String> args;
- if (parameters.Size())
- {
- for (unsigned int i = 0; i < parameters.Size(); i++)
- {
- JSBFunctionType* ptype = parameters.At(i);
- // ignore "Context" parameters
- if (ptype->type_->asClassType())
- {
- JSBClassType* classType = ptype->type_->asClassType();
- JSBClass* klass = classType->class_;
- if (klass->GetName() == "Context")
- {
- continue;
- }
- if (klass->IsNumberArray())
- args.Push(ToString("*%s", ptype->name_.CString()));
- else
- args.Push(ToString("%s", ptype->name_.CString()));
- }
- else
- {
- args.Push(ToString("%s", ptype->name_.CString()));
- }
- }
- }
- sig.Join(args, ", ");
- }
- 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("if (returnValue.NotNull()) 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::GenerateNativeSource(String& sourceOut)
- {
- String source = "";
- WriteNativeFunction(source);
- sourceOut += source;
- }
- // MANAGED----------------------------------------------------------------------------------------
- void CSFunctionWriter::WriteDefaultStructParameters(String& source)
- {
- for (unsigned i = 0; i < defaultStructParameters_.Size(); i++)
- {
- const DefaultStructParameter& dparm = defaultStructParameters_[i];
- String line = ToString("if (default(%s).Equals(%s)) %s = %s;\n",
- dparm.type.CString(), dparm.parameterName.CString(), dparm.parameterName.CString(),
- dparm.assignment.CString());
- source += IndentLine(line);
- }
- }
- void CSFunctionWriter::WriteManagedPInvokeFunctionSignature(String& source)
- {
- source += "\n";
- // 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);
- String line = "[DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]\n";
- source += IndentLine(line);
- JSBClass* klass = function_->GetClass();
- JSBPackage* package = klass->GetPackage();
- String returnType = CSTypeHelper::GetPInvokeTypeString(function_->GetReturnType());
- if (returnType == "bool")
- {
- // default boolean marshal is 4 byte windows type BOOL and not 1 byte bool
- // https://blogs.msdn.microsoft.com/jaredpar/2008/10/14/pinvoke-and-bool-or-should-i-say-bool/
- source += IndentLine("[return: MarshalAs(UnmanagedType.I1)]\n");
- }
- if (returnType == "string")
- returnType = "IntPtr";
- if (function_->IsConstructor())
- returnType = "IntPtr";
- Vector<JSBFunctionType*>& parameters = function_->GetParameters();
- Vector<String> args;
- if (!function_->IsConstructor() && !function_->IsStatic())
- {
- args.Push("IntPtr self");
- }
- if (parameters.Size())
- {
- for (unsigned int i = 0; i < parameters.Size(); i++)
- {
- JSBFunctionType* ptype = parameters.At(i);
- String name = ptype->name_;
- if (name == "object")
- name = "_object";
- else if (name == "readonly")
- name = "readOnly";
- else if (name == "params")
- name = "parameters";
- // ignore "Context" parameters
- if (ptype->type_->asClassType())
- {
- JSBClassType* classType = ptype->type_->asClassType();
- JSBClass* klass = classType->class_;
- if (klass->GetName() == "Context")
- {
- continue;
- }
- if (klass->IsNumberArray())
- {
- args.Push("ref " + klass->GetName() + " " + name);
- }
- else
- {
- args.Push("IntPtr " + name);
- }
- }
- else
- {
- args.Push(CSTypeHelper::GetPInvokeTypeString(ptype) + " " + name);
- }
- }
- }
- if (function_->GetReturnClass())
- {
- JSBClass* retClass = function_->GetReturnClass();
- if (retClass->IsNumberArray())
- {
- args.Push("ref " + retClass->GetName() + " retValue");
- }
- }
- String pstring;
- pstring.Join(args, ", ");
- String fname = function_->IsConstructor() ? "Constructor" : function_->GetName();
- line = ToString("private static extern %s csb_%s_%s_%s(%s);\n",
- returnType.CString(), package->GetName().CString(), klass->GetName().CString(),
- fname.CString(), pstring.CString());
- source += IndentLine(line);
- source += "\n";
- }
- void CSFunctionWriter::GenManagedFunctionParameters(String& sig)
- {
- // generate args
- Vector<JSBFunctionType*>& parameters = function_->GetParameters();
- if (parameters.Size())
- {
- for (unsigned int i = 0; i < parameters.Size(); i++)
- {
- JSBFunctionType* ptype = parameters.At(i);
- // ignore "Context" parameters
- if (ptype->type_->asClassType())
- {
- JSBClassType* classType = ptype->type_->asClassType();
- JSBClass* klass = classType->class_;
- if (klass->GetName() == "Context")
- {
- continue;
- }
- }
- sig += CSTypeHelper::GetManagedTypeString(ptype);
- String init = ptype->initializer_;
- if (init.Length())
- {
- init = MapDefaultParameter(ptype);
- if (init.Length())
- sig += " = " + init;
- }
- if (i + 1 != parameters.Size())
- sig += ", ";
- }
- }
- }
- 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);
- 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 nativeThisType = NativeCore.IsNativeType(thisType);\n");
- source += IndentLine("var nativeBaseType = NativeCore.IsNativeType(thisType.BaseType);\n");
- source += IndentLine("if ( (nativeThisType && (thisType == classType)) || (!nativeThisType && (nativeBaseType && (thisType.BaseType == classType))))\n");
- source += IndentLine("{\n");
- Indent();
- String callSig;
- GenPInvokeCallParameters(callSig);
- source += IndentLine("IntPtr nativeInstanceOverride = NativeCore.NativeContructorOverride;\n");
- line = ToString("nativeInstance = NativeCore.RegisterNative (nativeInstanceOverride != IntPtr.Zero ? nativeInstanceOverride : 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");
- Dedent();
- source += IndentLine("}\n");
- }
- void CSFunctionWriter::GenPInvokeCallParameters(String& sig)
- {
- // generate args
- Vector<JSBFunctionType*>& parameters = function_->GetParameters();
- if (parameters.Size())
- {
- for (unsigned int i = 0; i < parameters.Size(); i++)
- {
- JSBFunctionType* ptype = parameters.At(i);
- // ignore "Context" parameters
- if (ptype->type_->asClassType())
- {
- JSBClassType* classType = ptype->type_->asClassType();
- JSBClass* klass = classType->class_;
- if (klass->GetName() == "Context")
- {
- continue;
- }
- }
- String name = ptype->name_;
- if (name == "object")
- name = "_object";
- else if (name == "readonly")
- name = "readOnly";
- else if (name == "params")
- name = "parameters";
- if (ptype->type_->asClassType())
- {
- JSBClass* pclass = ptype->type_->asClassType()->class_;
- if (pclass->IsNumberArray())
- {
- sig += "ref " + name;
- }
- else
- {
- sig += name + " == null ? IntPtr.Zero : " + name + ".nativeInstance";
- }
- }
- else
- {
- sig += name;
- }
- if (i + 1 != parameters.Size())
- sig += ", ";
- }
- }
- // data marshaller
- if (function_->GetReturnType() && !CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
- {
- if (function_->GetReturnClass()->IsNumberArray())
- {
- if (sig.Length())
- sig += ", ";
- JSBClass* klass = function_->GetClass();
- sig += ToString("ref %s%sReturnValue", klass->GetName().CString(), function_->GetName().CString());
- }
- }
- }
- void CSFunctionWriter::WriteManagedFunction(String& source)
- {
- JSBClass* klass = function_->GetClass();
- JSBPackage* package = klass->GetPackage();
- String sig;
- String returnType = CSTypeHelper::GetManagedTypeString(function_->GetReturnType());
- GenManagedFunctionParameters(sig);
- String line = "public ";
- if (function_->IsStatic())
- {
- line += "static ";
- }
- bool marked = false;
- JSBClass* baseClass = klass->GetBaseClass();
- if (baseClass)
- {
- JSBFunction* override = baseClass->MatchFunction(function_, true);
- if (override)
- {
- marked = true;
- if (override->IsVirtual())
- line += "override ";
- else
- line += "new ";
- }
- }
- if (!marked && function_->IsVirtual())
- line += "virtual ";
- line += ToString("%s %s (%s)\n", returnType.CString(), function_->GetName().CString(), sig.CString());
- source += IndentLine(line);
- source += IndentLine("{\n");
- Indent();
- WriteDefaultStructParameters(source);
- line.Clear();
- if (function_->GetReturnType())
- {
- if (function_->GetReturnType()->type_->asStringType() || function_->GetReturnType()->type_->asStringHashType())
- {
- line += "return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(";
- }
- else if (CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
- line += "return ";
- else
- {
- if (function_->GetReturnClass())
- {
- if (!function_->GetReturnClass()->IsNumberArray())
- line += "IntPtr retNativeInstance = ";
- }
- }
- }
- String callSig;
- GenPInvokeCallParameters(callSig);
- String nativeInstance;
- if (!function_->IsStatic())
- nativeInstance = "nativeInstance";
- line += ToString("csb_%s_%s_%s(%s",
- package->GetName().CString(), klass->GetName().CString(), function_->GetName().CString(), nativeInstance.CString());
- if (callSig.Length())
- {
- if (nativeInstance.Length())
- line += ", " + callSig;
- else
- line += callSig;
- }
- if (function_->GetReturnType())
- {
- if (function_->GetReturnType()->type_->asStringType() || function_->GetReturnType()->type_->asStringHashType())
- line += ")";
- }
- line += ");\n";
- source += IndentLine(line);
- if (function_->GetReturnType() && !CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
- {
- if (function_->GetReturnType()->type_->asClassType())
- {
- JSBClass* retClass = function_->GetReturnClass();
- JSBClass* klass = function_->GetClass();
- if (retClass->IsNumberArray())
- {
- line = ToString("return %s%sReturnValue;", klass->GetName().CString(), function_->GetName().CString());
- }
- else
- {
- line = ToString("return retNativeInstance == IntPtr.Zero ? null : NativeCore.WrapNative<%s> (retNativeInstance);", retClass->GetName().CString());
- }
- source += IndentLine(line);
- source+= "\n";
- }
- }
- Dedent();
- source += IndentLine("}\n");
- }
- void CSFunctionWriter::GenerateManagedSource(String& sourceOut)
- {
- String source = "";
- Indent();
- Indent();
- if (function_->GetDocString().Length())
- {
- // monodocer -assembly:NETCore.dll -path:en -pretty
- // mdoc export-html -o htmldocs en
- source += IndentLine("/// <summary>\n");
- if (function_->GetDocString().Contains('\n'))
- source += IndentLine("/* " + function_->GetDocString() + "*/\n");
- else
- source += IndentLine("/// " + function_->GetDocString() + "\n");
- source += IndentLine("/// </summary>\n");
- }
- if (function_->IsConstructor())
- WriteManagedConstructor(source);
- else
- WriteManagedFunction(source);
- WriteManagedPInvokeFunctionSignature(source);
- // data marshaller
- if (function_->GetReturnType() && !CSTypeHelper::IsSimpleReturn(function_->GetReturnType()))
- {
- if (function_->GetReturnClass())
- {
- JSBClass* retClass = function_->GetReturnClass();
- if (retClass->IsNumberArray())
- {
- JSBClass* klass = function_->GetClass();
- String managedType = CSTypeHelper::GetManagedTypeString(function_->GetReturnType());
- String marshal = "private ";
- if (function_->IsStatic())
- marshal += "static ";
- marshal += managedType + " ";
- marshal += ToString("%s%sReturnValue = new %s();\n", klass->GetName().CString(), function_->GetName().CString(), managedType.CString());
- sourceOut += IndentLine(marshal);
- }
- }
- }
- Dedent();
- Dedent();
- sourceOut += source;
- }
- void CSFunctionWriter::GenerateSource(String& sourceOut)
- {
- }
- String CSFunctionWriter::MapDefaultParameter(JSBFunctionType* parameter)
- {
- String init = parameter->initializer_;
- if (!init.Length())
- return init;
- if (parameter->type_->asClassType())
- {
- if (init == "0")
- return "null";
- }
- if (parameter->type_->asEnumType())
- {
- return parameter->type_->asEnumType()->enum_->GetName() + "." + init;
- }
- if (function_->class_->GetPackage()->ContainsConstant(init))
- return "Constants." + init;
- if (init == "true" || init == "false")
- return init;
- if (init == "0.0f")
- return init;
- if (init == "1.0f")
- return init;
- if (init == "0.1f")
- return init;
- if (init == "0")
- return init;
- if (init == "3")
- return init;
- if (init == "-1")
- return init;
- if (init == "\"\\t\"")
- return init;
- if (init == "NULL")
- return "null";
- if (init == "M_MAX_UNSIGNED")
- return "0xffffffff";
- if (init == "String::EMPTY")
- return "\"\"";
- // this kind of sucks, can't define const structs
- // and default parameters need to be const :/
- DefaultStructParameter dparm;
- dparm.parameterName = parameter->name_;
- if (init == "Vector3::ZERO")
- {
- dparm.type = "Vector3";
- dparm.assignment = "Vector3.Zero";
- defaultStructParameters_.Push(dparm);
- return "default(Vector3)";
- }
- if (init == "Vector3::ONE")
- {
- dparm.type = "Vector3";
- dparm.assignment = "Vector3.One";
- defaultStructParameters_.Push(dparm);
- return "default(Vector3)";
- }
- if (init == "Vector3::UP")
- {
- dparm.type = "Vector3";
- dparm.assignment = "Vector3.Up";
- defaultStructParameters_.Push(dparm);
- return "default(Vector3)";
- }
- if (init == "IntVector2::ZERO")
- {
- dparm.type = "IntVector2";
- dparm.assignment = "IntVector2.Zero";
- defaultStructParameters_.Push(dparm);
- return "default(IntVector2)";
- }
- if (init == "Quaternion::IDENTITY")
- {
- dparm.type = "Quaternion";
- dparm.assignment = "Quaternion.Identity";
- defaultStructParameters_.Push(dparm);
- return "default(Quaternion)";
- }
- return String::EMPTY;
- }
- }
|