// 输出所有变体绑定 // hasOverrides: 是否需要处理重载 protected void WriteCSAllVariants(MethodBaseBindingInfo <T> methodBindingInfo) // SortedDictionary<int, MethodBaseVariant<T>> variants) { var variants = methodBindingInfo.variants; var prefs = cg.bindingManager.prefs; if (prefs.alwaysCheckArgc || /*hasOverrides*/ methodBindingInfo.count > 1) { // 需要处理重载 GenMethodVariants(methodBindingInfo, variants); } else { // 没有重载的情况 (variants.Count == 1) foreach (var variantKV in variants) { var args = variantKV.Key; var variant = variantKV.Value; var argc = cg.AppendGetArgCount(variant.isVararg); if (variant.isVararg) { var method = variant.varargMethods[0]; WriteCSMethodBinding(methodBindingInfo, method.method, argc, true, method.isExtension); } else { var method = variant.plainMethods[0]; WriteCSMethodBinding(methodBindingInfo, method.method, argc, false, method.isExtension); } } } }
protected void WriteTSAllVariants(TypeBindingInfo typeBindingInfo, MethodBaseBindingInfo <T> bindingInfo) { var variants = bindingInfo.variants; //NOTE: 如果产生了无法在 typescript 中声明的方法, 则作标记, 并输出一条万能声明 // [key: string]: any foreach (var variantKV in variants) { foreach (var method in variantKV.Value.plainMethods) { WriteTSDeclaration(typeBindingInfo, method.method, bindingInfo, method.isExtension); } foreach (var method in variantKV.Value.varargMethods) { WriteTSDeclaration(typeBindingInfo, method.method, bindingInfo, method.isExtension); } } }
// 写入绑定代码 protected void WriteCSMethodBinding(MethodBaseBindingInfo <T> bindingInfo, T method, string argc, bool isVararg, bool isExtension) { if (this.cg.bindingManager.prefs.verboseLog) { cg.bindingManager.Info($"WriteCSMethodBinding: {method.Name} {isExtension}"); } // 是否接管 cs 绑定代码生成 var transform = cg.bindingManager.GetTypeTransform(method.DeclaringType); if (transform != null && transform.OnBinding(BindingPoints.METHOD_BINDING_FULL, method, cg)) { return; } // var isRaw = method.IsDefined(typeof(JSCFunctionAttribute)); var parameters = method.GetParameters(); var caller = this.cg.AppendGetThisCS(method, isExtension); var returnType = GetReturnType(method); if (returnType == null || returnType == typeof(void)) { // 方法本身没有返回值 this.BeginInvokeBinding(); cg.cs.AppendLine($"{this.GetInvokeBinding(caller, method, isVararg, isExtension, argc, parameters)};"); this.EndInvokeBinding(); _WriteBackParameters(isExtension, parameters); WriteRebindThis(method, caller); InvokeVoidReturn(); } else { var retVar = "ret"; // cs return value var name this.BeginInvokeBinding(); cg.cs.AppendLine($"var {retVar} = {this.GetInvokeBinding(caller, method, isVararg, isExtension, argc, parameters)};"); this.EndInvokeBinding(); var retPusher = cg.AppendMethodReturnValuePusher(method, returnType, retVar); _WriteBackParameters(isExtension, parameters); cg.cs.AppendLine("return {0};", retPusher); } }
protected List <ParameterInfo> WriteTSDeclaration(TypeBindingInfo typeBindingInfo, T method, MethodBaseBindingInfo <T> bindingInfo, bool isExtension) { var refParameters = new List <ParameterInfo>(); string tsMethodDeclaration; this.cg.AppendJSDoc(method); if (typeBindingInfo.transform.GetTSMethodDeclaration(method, out tsMethodDeclaration) || this.cg.bindingManager.GetTSMethodDeclaration(method, out tsMethodDeclaration)) { this.cg.tsDeclare.AppendLine(tsMethodDeclaration); return(refParameters); } string tsMethodRename; if (!this.cg.bindingManager.GetTSMethodRename(method, out tsMethodRename)) { tsMethodRename = bindingInfo.jsName; } 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: "; } else { // var baseType = typeBindingInfo.type.BaseType; // if (baseType != null) // { // //TODO: 需要检查 TypeBindingInfo 对此的命名修改 // if (baseType.GetMethods().Where(baseMethodInfo => baseMethodInfo.Name == tsMethodRename).Count() != 0) // { // prefix += "// @ts-ignore" + this.cg.tsDeclare.newline + this.cg.tsDeclare.tabString; // } // } } if (method.IsStatic && !isExtension) { prefix += "static "; } this.cg.tsDeclare.Append($"{prefix}{tsMethodRename}("); 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); } for (int i = 0, len = parameters.Length; i < len;) { var parameter = parameters[i]; var parameterType = parameter.ParameterType; if (parameterType == typeof(Native.JSContext) || parameterType == typeof(Native.JSRuntime)) { // 剔除 JSContext, JSRuntime ArrayUtility.RemoveAt(ref parameters, i); len--; } else if (parameterType == typeof(ScriptContext) || parameterType == typeof(ScriptRuntime)) { // 剔除 ScriptContext, ScriptRuntime ArrayUtility.RemoveAt(ref parameters, i); len--; } // else if (parameter.IsOut) // { // ArrayUtility.RemoveAt(ref parameters, i); // len--; // refParameters.Add(parameter); // } else { // if (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 void GenMethodVariants(MethodBaseBindingInfo <T> methodBindingInfo, SortedDictionary <int, MethodBaseVariant <T> > variants) { var argc = cg.AppendGetArgCount(true); using (cg.cs.DoWhileBlockScope(methodBindingInfo.count > 1)) { foreach (var variantKV in variants) { var expectedArgCount = variantKV.Key; var variant = variantKV.Value; var gecheck = expectedArgCount > 0 && variant.isVararg; // 最后一组分支且存在变参时才需要判断 >= if (gecheck) { cg.cs.AppendLine("if (argc >= {0})", expectedArgCount); cg.cs.AppendLine("{"); cg.cs.AddTabLevel(); } // 处理定参 if (variant.plainMethods.Count > 0) { cg.cs.AppendLine("if (argc == {0})", expectedArgCount); using (cg.cs.CodeBlockScope()) { var prefs = cg.bindingManager.prefs; if (prefs.alwaysCheckArgType || variant.plainMethods.Count > 1) { foreach (var method in variant.plainMethods) { var fixedMatchers = GetFixedMatchTypes(method.method, false, method.isExtension); if (fixedMatchers.Length != 0) { cg.cs.AppendLine($"if ({fixedMatchers})"); using (cg.cs.CodeBlockScope()) { this.WriteCSMethodBinding(methodBindingInfo, method.method, argc, false, method.isExtension); } } else { this.WriteCSMethodBinding(methodBindingInfo, method.method, argc, false, method.isExtension); } } if (methodBindingInfo.count > 1 && expectedArgCount != 0) { cg.cs.AppendLine("break;"); } } else { // 只有一个定参方法时, 不再判定类型匹配 var method = variant.plainMethods[0]; this.WriteCSMethodBinding(methodBindingInfo, method.method, argc, false, method.isExtension); } } } // 处理变参 if (variant.varargMethods.Count > 0) { foreach (var method in variant.varargMethods) { var fixedMatchers = GetFixedMatchTypes(method.method, true, method.isExtension); var variantMatchers = GetParamArrayMatchType(method.method); if (fixedMatchers.Length > 0) { cg.cs.AppendLine($"if ({fixedMatchers} && js_match_param_types(ctx, {expectedArgCount}, argv, {variantMatchers}))"); } else { cg.cs.AppendLine($"if (js_match_param_types(ctx, {expectedArgCount}, argv, {variantMatchers}))"); } using (cg.cs.CodeBlockScope()) { this.WriteCSMethodBinding(methodBindingInfo, method.method, argc, true, method.isExtension); } } } if (gecheck) { cg.cs.DecTabLevel(); cg.cs.AppendLine("}"); } } } var error = this.cg.bindingManager.GetThrowError("no matched method variant"); cg.cs.AppendLine($"return {error};"); }
public TSMethodCodeGen(CodeGenerator cg, TypeBindingInfo typeBindingInfo, MethodBaseBindingInfo <T> bindingInfo) : base(cg) { this.bindingInfo = bindingInfo; WriteTSAllVariants(typeBindingInfo, this.bindingInfo); }