/// <summary> /// 指定した引数に最も適合するメソッドのオーバーロードを検索します /// </summary> /// <param name="arguments">引数</param> /// <returns>最も適合するメソッドのオーバーロード</returns> /// <exception cref="ArgumentException"> /// 指定した引数に適合するメソッドのオーバーロードが見つからなかった場合に発生します。 /// </exception> protected System.Reflection.MethodInfo SelectOverload(JavaScript.Array arguments) { float comp0, compat = float.NegativeInfinity; System.Reflection.MethodInfo m0, m = null; int iM = this.methods.Length; int w = 0; //重なり for (int i = 0; i < iM; i++) { m0 = this.methods[i]; comp0 = FunctionBase.ConvertParamsCompat(m0, arguments); if (comp0 < compat) { continue; } if (comp0 == compat) { w++; continue; } w = 1; compat = comp0; m = m0; } if (compat == float.NegativeInfinity) { throw new System.ArgumentException(OVERLOAD_NONE, "arguments"); } if (w > 1) { throw new System.ArgumentException(OVERLOAD_AMBIGUOUS, "arguments"); } return(m); }
/// <summary> /// Javascript 側で指定した引数と、指定した MethodInfo の引数の適合性を判定します /// </summary> /// <returns> /// 計算した適合性を返します。 /// 引数を変換する事が出来ない場合には float.NegativeInfinity を返します /// </returns> /// <remarks> /// TODO: params 修飾子が付いている時、一つも要素を指定しない場合の動作を実装 /// 1. arrParam.Length>arguments.length の判定だけでは不十分 /// 2. 点数を低くする(params の付いた引数だけ除いた別のオーバーロードの可能性) /// </remarks> public static float ConvertParamsCompat(System.Reflection.MethodInfo m, JavaScript.Array arguments) { System.Reflection.ParameterInfo[] arrParam = m.GetParameters(); if (arrParam.Length == 0) { return(0); } if (arrParam.Length > arguments.length) { return(float.NegativeInfinity); } int iM = arrParam.Length; float r = 0; for (int i = 0; i < iM; i++) { //CHECK>OK: params の入った関数を識別出来るか実際に確認する事 if (i + 1 == iM && arrParam[iM - 1].GetCustomAttributes(typeof(System.ParamArrayAttribute), false).Length > 0) { System.Type t = arrParam[iM - 1].ParameterType.GetElementType(); iM = arguments.length; for (; i < iM; i++) { r += arguments[i].ConvertCompat(t); } break; } r += arguments[i].ConvertCompat(arrParam[i].ParameterType); } return(r + (arguments.length - iM) * COMPAT_OVERPARAM); }
/// <summary> /// Javascript 側で指定した Javascript.Array 型の引数配列を /// object[] 型に変換します。 /// </summary> /// <param name="m">最終的に呼び出したいメソッド</param> /// <param name="arguments">呼び出しに用いる Javascript.Array の引数配列</param> /// <returns>実際に呼び出しに用いる事の出来る引数配列 object[]</returns> /// <remarks> /// 実装: ConvertParamsCompat の処理と似た処理を行うので、 /// ConvertParamsCompat の際に System.Type[] を作って置くのも手。 /// </remarks> public static object[] ConvertParams(System.Reflection.MethodInfo m, JavaScript.Array arguments) { System.Reflection.ParameterInfo[] arrParam = m.GetParameters(); int iM = arrParam.Length; object[] r = new object[iM]; for (int i = 0; i < iM; i++) { if (i + 1 == iM && arrParam[iM - 1].GetCustomAttributes(typeof(System.ParamArrayAttribute), false).Length > 0) { //変換 System.Collections.ArrayList list = new System.Collections.ArrayList(); System.Type t = arrParam[iM - 1].ParameterType.GetElementType(); for (; i < arguments.length; i++) { list.Add(arguments[i].Convert(t)); } r[iM - 1] = list.ToArray(t); } else { r[i] = arguments[i].Convert(arrParam[i].ParameterType); } } return(r); }
/// <summary> /// 配列の初期化子 /// </summary> /// <param name="array">配列の要素を指定します。</param> /// <returns>指定した引数を要素として持つ配列 Javascript.Array を返します。</returns> public static JavaScript.Array Construct(params JavaScript.Object[] array) { JavaScript.Array ret = new JavaScript.Array(); foreach (JavaScript.Object o in array) { ret[ret.len++] = Global.ConvertFromManaged(o); } return(ret); }
/// <summary> /// Object 木を辿って目的のメンバ関数を実行します /// </summary> /// <param name="index"> /// 次に検索するべき names の位置。 /// このメソッドを持つインスタンスが /// names[index] と言う名のメンバを持つ事が期待されています。 /// </param> /// <param name="names">オブジェクトの系譜。<see cref="afh.Javascript.Object.TraceMember"/></param> /// <returns>見つかったメンバを実行した結果を返します</returns> /// <exception cref="Null.UndefinedException"> /// 指定したメンバが未定義だった場合に発生します。 /// </exception> public JavaScript.Object InvokeMember(int index, string[] names, JavaScript.Array arguments) { //--直接の親と key の取得 int dest = names.Length - 2; JavaScript.Object parent = index <= dest?this.TraceMember(index, dest, names) : this; string key = names[dest + 1]; //--Invoke try{ return(((FunctionBase)parent[key]).Invoke(parent, arguments)); }catch (System.NullReferenceException e) { //※: 一回目の NullReferenceException は時間がかかる throw new Null.UndefinedException(e); }catch (System.InvalidCastException e) { throw new System.Exception("指定したオブジェクトは関数ではありません", e); }catch (System.Exception e) { throw e; } }
//=========================================================== // Invoke //=========================================================== /// <summary> /// 指定したオブジェクトの当該メソッドを実行します /// </summary> /// <param name="obj">オブジェクトを指定します</param> /// <param name="arguments">メソッドに渡す引数を指定します</param> /// <returns>メソッドの結果を返します</returns> /// <remarks> /// 案1: Type と Methods を保持し Invoke の命令が来たら /// <list> /// <item><description>Type と obj を照合</description></item> /// <item><description>引数リストの比較</description></item> /// <item><description>実行</description></item> /// </list> /// </remarks> public override JavaScript.Object Invoke(JavaScript.Object obj, JavaScript.Array arguments) { // ManagedObject 以外の時 (Javascript.Object を直接指定した場合の時) にも対応する事にする。 // 古いコード // if(!(obj is Javascript.ManagedObject))throw new System.ArgumentException(INVOKE_NOTMANAGED,"obj"); // object o=((Javascript.ManagedObject)obj).Value; object o = (obj is JavaScript.ManagedObject)?((JavaScript.ManagedObject)obj).Value:obj; //CHECK>×: IsSubclassOf で継承した interface も確認する事が出来るかどうか if (!Global.IsCastable(o.GetType(), this.type)) { throw new System.ArgumentException(INVOKE_NOTSUPPORTED, "obj"); } System.Reflection.MethodInfo m; try{ m = this.SelectOverload(arguments); }catch (System.Exception e) { throw e; } object ret = m.Invoke(o, FunctionBase.ConvertParams(m, arguments)); return(Global.ConvertFromManaged(ret)); }
/// <summary> /// この関数を実行します。 /// </summary> /// <param name="obj">この関数を保持する Object です。関数内からは this で参照されます</param> /// <param name="arguments">この関数に渡される引数の配列を設定します</param> /// <returns>この関数を実行した結果を返します</returns> public abstract JavaScript.Object Invoke(JavaScript.Object obj, JavaScript.Array arguments);