// 写入绑定代码 protected void WriteCSMethodBinding(MethodBaseBindingInfo <T> bindingInfo, T method, string argc, bool isVararg) { // 是否接管 cs 绑定代码生成 var transform = cg.bindingManager.GetTypeTransform(method.DeclaringType); if (transform != null && transform.OnBinding(BindingPoints.METHOD_BINDING_FULL, method, cg)) { return; } var isExtension = BindingManager.IsExtensionMethod(method); // var isRaw = method.IsDefined(typeof(JSCFunctionAttribute)); var parameters = method.GetParameters(); var in_params = new List <ParameterInfo>(); var out_params = new List <ParameterInfo>(); SplitParamters(parameters, isExtension ? 1 : 0, in_params, out_params); var caller = this.cg.AppendGetThisCS(method); var returnType = GetReturnType(method); // if (isRaw) // { // do // { // if (!isExtension) // { // if (returnType == typeof(int) && in_params.Count == 1) // { // var p = in_params[0]; // if (p.ParameterType == typeof(IntPtr) && !p.IsOut) // { // cg.cs.AppendLine($"return {caller}.{method.Name}(ctx);"); // return; // } // } // cg.bindingManager.Error($"invalid JSCFunction definition: {method}"); // break; // } // cg.bindingManager.Error($"Extension as JSCFunction is not supported: {method}"); // } while (false); // } if (returnType == null || returnType == typeof(void)) { // 方法本身没有返回值 this.BeginInvokeBinding(); cg.cs.AppendLine($"{this.GetInvokeBinding(caller, method, isVararg, isExtension, argc, parameters)};"); this.EndInvokeBinding(); var backVars = out_params.Count > 0 ? _WriteBackParametersByRef(isExtension, out_params, null) : null; if (!method.IsStatic && method.DeclaringType.IsValueType) // struct 非静态方法 检查 Mutable 属性 { if (!string.IsNullOrEmpty(caller)) { cg.cs.AppendLine($"js_rebind_this(ctx, this_obj, {caller});"); } } if (string.IsNullOrEmpty(backVars)) { this.InvokeVoidReturn(); } else { cg.cs.AppendLine("return {0};", backVars); } } else { var retVar = "ret"; // cs return value var name var retJsVar = "ret_js"; this.BeginInvokeBinding(); cg.cs.AppendLine($"var {retVar} = {this.GetInvokeBinding(caller, method, isVararg, isExtension, argc, parameters)};"); this.EndInvokeBinding(); var retPusher = cg.AppendMethodReturnValuePusher(method, returnType, retVar); cg.cs.AppendLine("var {0} = {1};", retJsVar, retPusher); cg.cs.AppendLine("if (JSApi.JS_IsException({0}))", retJsVar); using (cg.cs.Block()) { cg.cs.AppendLine("return {0};", retJsVar); } var backVars = out_params.Count > 0 ? _WriteBackParametersByRef(isExtension, out_params, retJsVar) : retJsVar; cg.cs.AppendLine("return {0};", backVars); } }
protected List <ParameterInfo> WriteTSDeclaration(T method, MethodBaseBindingInfo <T> bindingInfo) { var isExtension = BindingManager.IsExtensionMethod(method); var refParameters = new List <ParameterInfo>(); string tsMethodDeclaration; this.cg.AppendJSDoc(method); if (this.cg.bindingManager.GetTSMethodDeclaration(method, out tsMethodDeclaration)) { this.cg.tsDeclare.AppendLine(tsMethodDeclaration); return(refParameters); } var isRaw = method.IsDefined(typeof(JSCFunctionAttribute)); //TODO: 需要处理参数类型归并问题, 因为如果类型没有导入 ts 中, 可能会在声明中出现相同参数列表的定义 // 在 MethodVariant 中创建每个方法对应的TS类型名参数列表, 完全相同的不再输出 var prefix = ""; // if (method.Name.StartsWith("op_")) if (bindingInfo is OperatorBindingInfo) { prefix += "// js_op_overloading: "; } if (method.IsStatic && !isExtension) { prefix += "static "; } string tsMethodRename; if (this.cg.bindingManager.GetTSMethodRename(method, out tsMethodRename)) { this.cg.tsDeclare.Append($"{prefix}{tsMethodRename}("); } else { this.cg.tsDeclare.Append($"{prefix}{bindingInfo.regName}("); } if (isRaw) { this.cg.tsDeclare.AppendL("...uncertain: any[]): any /* uncertain */"); this.cg.tsDeclare.AppendLine(); } else { var parameters = method.GetParameters(); if (isExtension) { ArrayUtility.RemoveAt(ref parameters, 0); } // 剔除 out 参数 for (int i = 0, len = parameters.Length; i < len;) { var parameter = parameters[i]; if (parameter.IsOut) { ArrayUtility.RemoveAt(ref parameters, i); len--; refParameters.Add(parameter); } else { if (parameter.ParameterType.IsByRef) { refParameters.Add(parameter); } i++; } } for (int i = 0, len = parameters.Length; i < len; i++) { var parameter = parameters[i]; var parameter_prefix = ""; var parameterType = parameter.ParameterType; if (parameter.IsDefined(typeof(ParamArrayAttribute), false) && i == parameters.Length - 1) { var elementType = parameterType.GetElementType(); var elementTS = this.cg.bindingManager.GetTSTypeFullName(elementType); var parameterVarName = BindingManager.GetTSVariable(parameter); this.cg.tsDeclare.AppendL($"{parameter_prefix}...{parameterVarName}: {elementTS}[]"); } else { var parameterTS = this.cg.bindingManager.GetTSTypeFullName(parameter); var parameterVarName = BindingManager.GetTSVariable(parameter); this.cg.tsDeclare.AppendL($"{parameter_prefix}{parameterVarName}: {parameterTS}"); } if (i != parameters.Length - 1) { this.cg.tsDeclare.AppendL(", "); } } this.cg.tsDeclare.AppendL($")"); WriteTSReturn(method, refParameters); } return(refParameters); }
// 写入返回类型声明 protected virtual void WriteTSReturn(T method, List <ParameterInfo> returnParameters) { var returnType = GetReturnType(method); var count = returnParameters.Count; if (returnType != null && returnType != typeof(void)) { if (count != 0) { this.cg.tsDeclare.AppendL(": { "); var returnTypeTS = this.cg.bindingManager.GetTSReturnTypeFullName(returnType); var returnVarName = BindingManager.GetTSVariable("return"); this.cg.tsDeclare.AppendL($"\"{returnVarName}\": {returnTypeTS}"); for (var i = 0; i < count; i++) { var rp = returnParameters[i]; var name = BindingManager.GetTSVariable(rp.Name); var ts = this.cg.bindingManager.GetTSTypeFullName(rp.ParameterType); if (i != count - 1) { this.cg.tsDeclare.AppendL($", \"{name}\": {ts}"); } else { this.cg.tsDeclare.AppendL($", \"{name}\": {ts}"); } } this.cg.tsDeclare.AppendL(" }"); this.cg.tsDeclare.AppendLine(); } else { var returnTypeTS = this.cg.bindingManager.GetTSReturnTypeFullName(returnType); this.cg.tsDeclare.AppendL($": {returnTypeTS}"); this.cg.tsDeclare.AppendLine(); } } else { if (count != 0) { this.cg.tsDeclare.AppendL(": { "); for (var i = 0; i < count; i++) { var rp = returnParameters[i]; var name = rp.Name; var ts = this.cg.bindingManager.GetTSTypeFullName(rp.ParameterType); if (i != count - 1) { this.cg.tsDeclare.AppendL($"\"{name}\": {ts}, "); } else { this.cg.tsDeclare.AppendL($"\"{name}\": {ts}"); } } this.cg.tsDeclare.AppendL(" }"); this.cg.tsDeclare.AppendLine(); } else { this.cg.tsDeclare.AppendLine(); } } }
// 收集所有 字段,属性,方法 public void Collect() { var bindingFlags = Binding.DynamicType.PublicFlags; var fields = type.GetFields(bindingFlags); foreach (var field in fields) { if (field.IsSpecialName || field.Name.StartsWith("_JSFIX_")) { bindingManager.Info("skip special field: {0}", field.Name); continue; } if (field.FieldType.IsPointer) { bindingManager.Info("skip pointer field: {0}", field.Name); continue; } if (field.IsDefined(typeof(JSOmitAttribute), false)) { bindingManager.Info("skip omitted field: {0}", field.Name); continue; } if (field.IsDefined(typeof(ObsoleteAttribute), false)) { bindingManager.Info("skip obsolete field: {0}", field.Name); continue; } if (transform != null && transform.IsMemberBlocked(field.Name)) { bindingManager.Info("skip blocked field: {0}", field.Name); continue; } AddField(field); } var events = type.GetEvents(bindingFlags); foreach (var evt in events) { if (evt.IsSpecialName) { bindingManager.Info("skip special event: {0}", evt.Name); continue; } if (evt.EventHandlerType.IsPointer) { bindingManager.Info("skip pointer event: {0}", evt.Name); continue; } if (evt.IsDefined(typeof(ObsoleteAttribute), false)) { bindingManager.Info("skip obsolete event: {0}", evt.Name); continue; } if (evt.IsDefined(typeof(JSOmitAttribute), false)) { bindingManager.Info("skip omitted event: {0}", evt.Name); continue; } if (transform != null && transform.IsMemberBlocked(evt.Name)) { bindingManager.Info("skip blocked event: {0}", evt.Name); continue; } AddEvent(evt); } var properties = type.GetProperties(bindingFlags); foreach (var property in properties) { if (property.IsSpecialName) { bindingManager.Info("skip special property: {0}", property.Name); continue; } if (property.PropertyType.IsPointer) { bindingManager.Info("skip pointer property: {0}", property.Name); continue; } if (property.IsDefined(typeof(JSOmitAttribute), false)) { bindingManager.Info("skip omitted property: {0}", property.Name); continue; } if (property.IsDefined(typeof(ObsoleteAttribute), false)) { bindingManager.Info("skip obsolete property: {0}", property.Name); continue; } if (transform != null && transform.IsMemberBlocked(property.Name)) { bindingManager.Info("skip blocked property: {0}", property.Name); continue; } //NOTE: 索引访问 if (property.Name == "Item") { if (property.CanRead && property.GetMethod != null) { if (BindingManager.IsUnsupported(property.GetMethod)) { bindingManager.Info("skip unsupported get-method: {0}", property.GetMethod); continue; } AddMethod(property.GetMethod, true, "$GetValue"); } if (property.CanWrite && property.SetMethod != null) { if (BindingManager.IsUnsupported(property.SetMethod)) { bindingManager.Info("skip unsupported set-method: {0}", property.SetMethod); continue; } AddMethod(property.SetMethod, true, "$SetValue"); } // bindingManager.Info("skip indexer property: {0}", property.Name); continue; } AddProperty(property); } if (!type.IsAbstract) { var constructors = type.GetConstructors(); foreach (var constructor in constructors) { if (constructor.IsDefined(typeof(JSOmitAttribute), false)) { bindingManager.Info("skip omitted constructor: {0}", constructor); continue; } if (constructor.IsDefined(typeof(ObsoleteAttribute), false)) { bindingManager.Info("skip obsolete constructor: {0}", constructor); continue; } if (BindingManager.ContainsPointer(constructor)) { bindingManager.Info("skip pointer-param constructor: {0}", constructor); continue; } if (BindingManager.ContainsByRefParameters(constructor)) { bindingManager.Info("skip byref-param constructor: {0}", constructor); continue; } AddConstructor(constructor); } } CollectMethods(type.GetMethods(bindingFlags)); CollectMethods(bindingManager.GetTypeTransform(type).extensionMethods); }
public void AddMethod(MethodInfo methodInfo, bool isIndexer, string renameRegName) { if (this.transform != null) { if (this.transform.IsBlocked(methodInfo)) { bindingManager.Info("skip blocked method: {0}", methodInfo.Name); return; } } var isExtension = BindingManager.IsExtensionMethod(methodInfo); var isStatic = methodInfo.IsStatic && !isExtension; var methodName = TypeBindingInfo.GetNamingAttribute(methodInfo); if (IsSupportedOperators(methodInfo)) { var parameters = methodInfo.GetParameters(); var declaringType = methodInfo.DeclaringType; OperatorBindingInfo operatorBindingInfo = null; switch (methodName) { case "op_LessThan": if (parameters.Length == 2) { if (parameters[0].ParameterType == declaringType && parameters[1].ParameterType == declaringType) { operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, methodName, "<", "<", 2); } } break; case "op_Addition": if (parameters.Length == 2) { if (parameters[0].ParameterType == declaringType && parameters[1].ParameterType == declaringType) { operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, methodName, "+", "+", 2); } } break; case "op_Subtraction": if (parameters.Length == 2) { if (parameters[0].ParameterType == declaringType && parameters[1].ParameterType == declaringType) { operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, methodName, "-", "-", 2); } } break; case "op_Equality": if (parameters.Length == 2) { if (parameters[0].ParameterType == declaringType && parameters[1].ParameterType == declaringType) { operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, methodName, "==", "==", 2); } } break; case "op_Multiply": if (parameters.Length == 2) { var op0 = bindingManager.GetExportedType(parameters[0].ParameterType); var op1 = bindingManager.GetExportedType(parameters[1].ParameterType); if (op0 != null && op1 != null) { var bindingName = methodName + "_" + op0.name + "_" + op1.name; operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, bindingName, "*", "*", 2); } } break; case "op_Division": if (parameters.Length == 2) { var op0 = bindingManager.GetExportedType(parameters[0].ParameterType); var op1 = bindingManager.GetExportedType(parameters[1].ParameterType); if (op0 != null && op1 != null) { var bindingName = methodName + "_" + op0.name + "_" + op1.name; operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, bindingName, "/", "/", 2); } } break; case "op_UnaryNegation": { operatorBindingInfo = new OperatorBindingInfo(methodInfo, isExtension, isStatic, methodName, "neg", "-", 1); } break; } if (operatorBindingInfo != null) { operators.Add(operatorBindingInfo); CollectDelegate(methodInfo); bindingManager.Info("[AddOperator] {0}.{1}", type, methodInfo); return; } // fallback to normal method binding } var group = isStatic ? staticMethods : methods; MethodBindingInfo methodBindingInfo; if (!group.TryGetValue(methodName, out methodBindingInfo)) { methodBindingInfo = new MethodBindingInfo(isIndexer, isStatic, methodName, renameRegName ?? methodName); group.Add(methodName, methodBindingInfo); } if (!methodBindingInfo.Add(methodInfo, isExtension)) { bindingManager.Info("fail to add method: {0}", methodInfo.Name); return; } CollectDelegate(methodInfo); bindingManager.Info("[AddMethod] {0}.{1}", type, methodInfo); }
public override void Dispose() { using (new RegFuncCodeGen(cg)) { using (new RegFuncNamespaceCodeGen(cg, typeBindingInfo)) { var constructor = typeBindingInfo.constructors.available ? typeBindingInfo.constructors.name : "JSApi.class_private_ctor"; if (!typeBindingInfo.constructors.available && !typeBindingInfo.type.IsAbstract) { if (typeBindingInfo.type.IsSubclassOf(typeof(Component))) { // 因为 ts 泛型约束需要 new() 形式, 所以在定义中产生一个 public 定义 // 例如: GetComponent<T extends Component>(type: { new(): T }): T cg.tsDeclare.AppendLine("/*protected*/ constructor()"); } else { cg.tsDeclare.AppendLine("protected constructor()"); } } cg.cs.AppendLine("var cls = ns.CreateClass(\"{0}\", typeof({1}), {2});", typeBindingInfo.jsName, this.cg.bindingManager.GetCSTypeFullName(typeBindingInfo.type), constructor); // 运算符 foreach (var operatorBindingInfo in typeBindingInfo.operators) { var regName = operatorBindingInfo.regName; var funcName = operatorBindingInfo.name; var parameters = operatorBindingInfo.methodInfo.GetParameters(); var declaringType = operatorBindingInfo.methodInfo.DeclaringType; string redirect; if (this.typeBindingInfo.transform != null && this.typeBindingInfo.transform.TryRedirectMethod(regName, out redirect)) { funcName = redirect; } do { if (parameters.Length == 2) { if (parameters[0].ParameterType != declaringType) { var leftType = typeBindingInfo.bindingManager.GetCSTypeFullName(parameters[0].ParameterType); cg.cs.AppendLine("cls.AddLeftOperator(\"{0}\", {1}, {2}, typeof({3}));", regName, funcName, operatorBindingInfo.length, leftType); break; } else if (parameters[1].ParameterType != declaringType) { var rightType = typeBindingInfo.bindingManager.GetCSTypeFullName(parameters[1].ParameterType); cg.cs.AppendLine("cls.AddRightOperator(\"{0}\", {1}, {2}, typeof({3}));", regName, funcName, operatorBindingInfo.length, rightType); break; } } cg.cs.AppendLine("cls.AddSelfOperator(\"{0}\", {1}, {2});", regName, funcName, operatorBindingInfo.length); } while (false); } // 非静态方法 foreach (var kv in typeBindingInfo.methods) { var regName = kv.Value.regName; var funcName = kv.Value.name; string redirect; if (this.typeBindingInfo.transform != null && this.typeBindingInfo.transform.TryRedirectMethod(regName, out redirect)) { funcName = redirect; } if (typeBindingInfo.bindingManager.prefs.optToString && regName == "ToString") { cg.cs.AppendLine("cls.AddMethod(false, \"{0}\", {1});", "toString", funcName); } else { cg.cs.AppendLine("cls.AddMethod(false, \"{0}\", {1});", regName, funcName); } } // 静态方法 foreach (var kv in typeBindingInfo.staticMethods) { var regName = kv.Value.regName; var funcName = kv.Value.name; string redirect; if (this.typeBindingInfo.transform != null && this.typeBindingInfo.transform.TryRedirectMethod(regName, out redirect)) { funcName = redirect; } cg.cs.AppendLine("cls.AddMethod(true, \"{0}\", {1});", regName, funcName); } // 属性 foreach (var kv in typeBindingInfo.properties) { var bindingInfo = kv.Value; if (bindingInfo.staticPair.IsValid()) { var tsPropertyVar = BindingManager.GetTSVariable(bindingInfo.regName); cg.cs.AppendLine("cls.AddProperty(true, \"{0}\", {1}, {2});", tsPropertyVar, bindingInfo.staticPair.getterName != null ? bindingInfo.staticPair.getterName : "null", bindingInfo.staticPair.setterName != null ? bindingInfo.staticPair.setterName : "null"); var tsPropertyPrefix = "static "; if (bindingInfo.staticPair.setterName == null) { tsPropertyPrefix += "readonly "; } var tsPropertyType = this.cg.bindingManager.GetTSTypeFullName(bindingInfo.propertyInfo.PropertyType); cg.AppendJSDoc(bindingInfo.propertyInfo); cg.tsDeclare.AppendLine($"{tsPropertyPrefix}{tsPropertyVar}: {tsPropertyType}"); } if (bindingInfo.instancePair.IsValid()) { var tsPropertyVar = BindingManager.GetTSVariable(bindingInfo.regName); cg.cs.AppendLine("cls.AddProperty(false, \"{0}\", {1}, {2});", tsPropertyVar, bindingInfo.instancePair.getterName != null ? bindingInfo.instancePair.getterName : "null", bindingInfo.instancePair.setterName != null ? bindingInfo.instancePair.setterName : "null"); var tsPropertyPrefix = ""; if (bindingInfo.instancePair.setterName == null) { tsPropertyPrefix += "readonly "; } var tsPropertyType = this.cg.bindingManager.GetTSTypeFullName(bindingInfo.propertyInfo.PropertyType); cg.AppendJSDoc(bindingInfo.propertyInfo); cg.tsDeclare.AppendLine($"{tsPropertyPrefix}{tsPropertyVar}: {tsPropertyType}"); } } foreach (var kv in typeBindingInfo.fields) { var bindingInfo = kv.Value; var bStatic = bindingInfo.isStatic; var tsFieldVar = BindingManager.GetTSVariable(bindingInfo.regName); if (bindingInfo.constantValue != null) { var cv = bindingInfo.constantValue; cg.cs.AppendLine($"cls.AddConstValue(\"{tsFieldVar}\", {cv});"); } else { cg.cs.AppendLine("cls.AddField({0}, \"{1}\", {2}, {3});", bStatic ? "true" : "false", tsFieldVar, bindingInfo.getterName != null ? bindingInfo.getterName : "null", bindingInfo.setterName != null ? bindingInfo.setterName : "null"); } var tsFieldPrefix = bStatic ? "static " : ""; if (bindingInfo.setterName == null) { tsFieldPrefix += "readonly "; } var tsFieldType = this.cg.bindingManager.GetTSTypeFullName(bindingInfo.fieldInfo.FieldType); cg.AppendJSDoc(bindingInfo.fieldInfo); cg.tsDeclare.AppendLine($"{tsFieldPrefix}{tsFieldVar}: {tsFieldType}"); } foreach (var kv in typeBindingInfo.events) { var eventBindingInfo = kv.Value; var bStatic = eventBindingInfo.isStatic; //NOTE: 静态事件在绑定过程直接定义, 非静态事件推迟到构造时直接赋值创建 var tsFieldVar = BindingManager.GetTSVariable(eventBindingInfo.regName); var tsFieldType = this.cg.bindingManager.GetTSTypeFullName(eventBindingInfo.eventInfo.EventHandlerType); var tsFieldPrefix = ""; if (bStatic) { tsFieldPrefix += "static "; cg.cs.AppendLine($"cls.AddEvent(true, \"{tsFieldVar}\", {eventBindingInfo.adderName}, {eventBindingInfo.removerName});"); } else { cg.cs.AppendLine($"cls.AddProperty(false, \"{tsFieldVar}\", {eventBindingInfo.proxyName}, null);"); } cg.tsDeclare.AppendLine($"{tsFieldPrefix}{tsFieldVar}: {CodeGenerator.NamespaceOfScriptTypes}.event<{tsFieldType}>"); } cg.cs.AppendLine("cls.Close();"); } } base.Dispose(); this.cg.tsDeclare.DecTabLevel(); this.cg.tsDeclare.AppendLine("}"); }