PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython/Runtime/Types/BuiltinFunction.cs

http://github.com/IronLanguages/main
C# | 961 lines | 671 code | 164 blank | 126 comment | 141 complexity | 42a801fc4ee8cbc14a0a7658c6f445d3 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections;
  22. using System.Collections.Generic;
  23. using System.Diagnostics;
  24. using System.Reflection;
  25. using System.Runtime.CompilerServices;
  26. using System.Dynamic;
  27. using System.Text;
  28. using System.Threading;
  29. using Microsoft.Scripting;
  30. using Microsoft.Scripting.Actions;
  31. using Microsoft.Scripting.Actions.Calls;
  32. using Microsoft.Scripting.Runtime;
  33. using Microsoft.Scripting.Utils;
  34. using IronPython.Runtime.Binding;
  35. using IronPython.Runtime.Operations;
  36. namespace IronPython.Runtime.Types {
  37. using Ast = Expression;
  38. using AstUtils = Microsoft.Scripting.Ast.Utils;
  39. /// <summary>
  40. /// BuiltinFunction represents any standard CLR function exposed to Python.
  41. /// This is used for both methods on standard Python types such as list or tuple
  42. /// and for methods from arbitrary .NET assemblies.
  43. ///
  44. /// All calls are made through the optimizedTarget which is created lazily.
  45. ///
  46. /// TODO: Back BuiltinFunction's by MethodGroup's.
  47. /// </summary>
  48. [PythonType("builtin_function_or_method"), DontMapGetMemberNamesToDir]
  49. public partial class BuiltinFunction : PythonTypeSlot, ICodeFormattable, IDynamicMetaObjectProvider, IDelegateConvertible, IFastInvokable {
  50. internal readonly BuiltinFunctionData/*!*/ _data; // information describing the BuiltinFunction
  51. internal readonly object _instance; // the bound instance or null if unbound
  52. private static readonly object _noInstance = new object();
  53. #region Static factories
  54. /// <summary>
  55. /// Creates a new builtin function for a static .NET function. This is used for module methods
  56. /// and well-known __new__ methods.
  57. /// </summary>
  58. internal static BuiltinFunction/*!*/ MakeFunction(string name, MethodBase[] infos, Type declaringType) {
  59. #if DEBUG
  60. foreach (MethodBase mi in infos) {
  61. Debug.Assert(!mi.ContainsGenericParameters);
  62. }
  63. #endif
  64. return new BuiltinFunction(name, infos, declaringType, FunctionType.AlwaysVisible | FunctionType.Function);
  65. }
  66. /// <summary>
  67. /// Creates a built-in function for a .NET method declared on a type.
  68. /// </summary>
  69. internal static BuiltinFunction/*!*/ MakeMethod(string name, MethodBase[] infos, Type declaringType, FunctionType ft) {
  70. foreach (MethodBase mi in infos) {
  71. if (mi.ContainsGenericParameters) {
  72. return new GenericBuiltinFunction(name, infos, declaringType, ft);
  73. }
  74. }
  75. return new BuiltinFunction(name, infos, declaringType, ft);
  76. }
  77. internal virtual BuiltinFunction/*!*/ BindToInstance(object instance) {
  78. return new BuiltinFunction(instance, _data);
  79. }
  80. #endregion
  81. #region Constructors
  82. internal BuiltinFunction(string/*!*/ name, MethodBase/*!*/[]/*!*/ originalTargets, Type/*!*/ declaringType, FunctionType functionType) {
  83. Assert.NotNull(name);
  84. Assert.NotNull(declaringType);
  85. Assert.NotNullItems(originalTargets);
  86. _data = new BuiltinFunctionData(name, originalTargets, declaringType, functionType);
  87. _instance = _noInstance;
  88. }
  89. /// <summary>
  90. /// Creates a bound built-in function. The instance may be null for built-in functions
  91. /// accessed for None.
  92. /// </summary>
  93. internal BuiltinFunction(object instance, BuiltinFunctionData/*!*/ data) {
  94. Assert.NotNull(data);
  95. _instance = instance;
  96. _data = data;
  97. }
  98. #endregion
  99. #region Internal API Surface
  100. internal void AddMethod(MethodInfo mi) {
  101. _data.AddMethod(mi);
  102. }
  103. internal bool TestData(object data) {
  104. return _data == data;
  105. }
  106. internal bool IsUnbound {
  107. get {
  108. return _instance == _noInstance;
  109. }
  110. }
  111. internal string Name {
  112. get {
  113. return _data.Name;
  114. }
  115. set {
  116. _data.Name = value;
  117. }
  118. }
  119. internal object Call(CodeContext context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object[], object>>> storage, object instance, object[] args) {
  120. storage = GetInitializedStorage(context, storage);
  121. object callable;
  122. if (!GetDescriptor().TryGetValue(context, instance, DynamicHelpers.GetPythonTypeFromType(DeclaringType), out callable)) {
  123. callable = this;
  124. }
  125. return storage.Data.Target(storage.Data, context, callable, args);
  126. }
  127. internal object Call0(CodeContext context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object>>> storage, object instance) {
  128. storage = GetInitializedStorage(context, storage);
  129. object callable;
  130. if (!GetDescriptor().TryGetValue(context, instance, DynamicHelpers.GetPythonTypeFromType(DeclaringType), out callable)) {
  131. callable = this;
  132. }
  133. return storage.Data.Target(storage.Data, context, callable);
  134. }
  135. private static SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object[], object>>> GetInitializedStorage(CodeContext context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object[], object>>> storage) {
  136. if (storage == null) {
  137. storage = PythonContext.GetContext(context).GetGenericCallSiteStorage();
  138. }
  139. if (storage.Data == null) {
  140. storage.Data = PythonContext.GetContext(context).MakeSplatSite();
  141. }
  142. return storage;
  143. }
  144. private static SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object>>> GetInitializedStorage(CodeContext context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object>>> storage) {
  145. if (storage.Data == null) {
  146. storage.Data = CallSite<Func<CallSite, CodeContext, object, object>>.Create(
  147. PythonContext.GetContext(context).InvokeNone
  148. );
  149. }
  150. return storage;
  151. }
  152. internal object Call(CodeContext context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object[], IDictionary<object, object>, object>>> storage, object instance, object[] args, IDictionary<object, object> keywordArgs) {
  153. if (storage == null) {
  154. storage = PythonContext.GetContext(context).GetGenericKeywordCallSiteStorage();
  155. }
  156. if (storage.Data == null) {
  157. storage.Data = PythonContext.GetContext(context).MakeKeywordSplatSite();
  158. }
  159. if (instance != null) {
  160. return storage.Data.Target(storage.Data, context, this, ArrayUtils.Insert(instance, args), keywordArgs);
  161. }
  162. return storage.Data.Target(storage.Data, context, this, args, keywordArgs);
  163. }
  164. /// <summary>
  165. /// Returns a BuiltinFunction bound to the provided type arguments. Returns null if the binding
  166. /// cannot be performed.
  167. /// </summary>
  168. internal BuiltinFunction MakeGenericMethod(Type[] types) {
  169. TypeList tl = new TypeList(types);
  170. // check for cached method first...
  171. BuiltinFunction bf;
  172. if (_data.BoundGenerics != null) {
  173. lock (_data.BoundGenerics) {
  174. if (_data.BoundGenerics.TryGetValue(tl, out bf)) {
  175. return bf;
  176. }
  177. }
  178. }
  179. // Search for generic targets with the correct arity (number of type parameters).
  180. // Compatible targets must be MethodInfos by definition (constructors never take
  181. // type arguments).
  182. List<MethodBase> targets = new List<MethodBase>(Targets.Count);
  183. foreach (MethodBase mb in Targets) {
  184. MethodInfo mi = mb as MethodInfo;
  185. if (mi == null)
  186. continue;
  187. if (mi.ContainsGenericParameters && mi.GetGenericArguments().Length == types.Length)
  188. targets.Add(mi.MakeGenericMethod(types));
  189. }
  190. if (targets.Count == 0) {
  191. return null;
  192. }
  193. // Build a new ReflectedMethod that will contain targets with bound type arguments & cache it.
  194. bf = new BuiltinFunction(Name, targets.ToArray(), DeclaringType, FunctionType);
  195. EnsureBoundGenericDict();
  196. lock (_data.BoundGenerics) {
  197. _data.BoundGenerics[tl] = bf;
  198. }
  199. return bf;
  200. }
  201. /// <summary>
  202. /// Returns a descriptor for the built-in function if one is
  203. /// neededed
  204. /// </summary>
  205. internal PythonTypeSlot/*!*/ GetDescriptor() {
  206. if ((FunctionType & FunctionType.Method) != 0) {
  207. return new BuiltinMethodDescriptor(this);
  208. }
  209. return this;
  210. }
  211. public Type DeclaringType {
  212. [PythonHidden]
  213. get {
  214. return _data.DeclaringType;
  215. }
  216. }
  217. /// <summary>
  218. /// Gets the target methods that we'll be calling.
  219. /// </summary>
  220. public IList<MethodBase> Targets {
  221. [PythonHidden]
  222. get {
  223. return _data.Targets;
  224. }
  225. }
  226. /// <summary>
  227. /// True if the method should be visible to non-CLS opt-in callers
  228. /// </summary>
  229. internal override bool IsAlwaysVisible {
  230. get {
  231. return (_data.Type & FunctionType.AlwaysVisible) != 0;
  232. }
  233. }
  234. internal bool IsReversedOperator {
  235. get {
  236. return (FunctionType & FunctionType.ReversedOperator) != 0;
  237. }
  238. }
  239. internal bool IsBinaryOperator {
  240. get {
  241. return (FunctionType & FunctionType.BinaryOperator) != 0;
  242. }
  243. }
  244. internal FunctionType FunctionType {
  245. get {
  246. return _data.Type;
  247. }
  248. set {
  249. _data.Type = value;
  250. }
  251. }
  252. /// <summary>
  253. /// Makes a test for the built-in function against the private _data
  254. /// which is unique per built-in function.
  255. /// </summary>
  256. internal Expression/*!*/ MakeBoundFunctionTest(Expression/*!*/ functionTarget) {
  257. Debug.Assert(functionTarget.Type == typeof(BuiltinFunction));
  258. return Ast.Call(
  259. typeof(PythonOps).GetMethod("TestBoundBuiltinFunction"),
  260. functionTarget,
  261. AstUtils.Constant(_data, typeof(object))
  262. );
  263. }
  264. #endregion
  265. #region PythonTypeSlot Overrides
  266. internal override bool TryGetValue(CodeContext context, object instance, PythonType owner, out object value) {
  267. value = this;
  268. return true;
  269. }
  270. internal override bool GetAlwaysSucceeds {
  271. get {
  272. return true;
  273. }
  274. }
  275. internal override void MakeGetExpression(PythonBinder/*!*/ binder, Expression/*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject/*!*/ owner, ConditionalBuilder/*!*/ builder) {
  276. builder.FinishCondition(Ast.Constant(this));
  277. }
  278. #endregion
  279. #region ICodeFormattable members
  280. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  281. if (IsUnbound || IsBuiltinModuleMethod) {
  282. return string.Format("<built-in function {0}>", Name);
  283. }
  284. return string.Format("<built-in method {0} of {1} object at {2}>",
  285. __name__,
  286. PythonOps.GetPythonTypeName(__self__),
  287. PythonOps.HexId(__self__));
  288. }
  289. #endregion
  290. #region IDynamicMetaObjectProvider Members
  291. DynamicMetaObject/*!*/ IDynamicMetaObjectProvider.GetMetaObject(Expression/*!*/ parameter) {
  292. return new Binding.MetaBuiltinFunction(parameter, BindingRestrictions.Empty, this);
  293. }
  294. internal class BindingResult {
  295. public readonly BindingTarget Target;
  296. public readonly DynamicMetaObject MetaObject;
  297. public BindingResult(BindingTarget target, DynamicMetaObject meta) {
  298. Target = target;
  299. MetaObject = meta;
  300. }
  301. }
  302. /// <summary>
  303. /// Helper for generating the call to a builtin function. This is used for calls from built-in method
  304. /// descriptors and built-in functions w/ and w/o a bound instance.
  305. ///
  306. /// This provides all sorts of common checks on top of the call while the caller provides a delegate
  307. /// to do the actual call. The common checks include:
  308. /// check for generic-only methods
  309. /// reversed operator support
  310. /// transforming arguments so the default binder can understand them (currently user defined mapping types to PythonDictionary)
  311. /// returning NotImplemented from binary operators
  312. /// Warning when calling certain built-in functions
  313. ///
  314. /// </summary>
  315. /// <param name="call">The call binder we're doing the call for</param>
  316. /// <param name="codeContext">An expression which points to the code context</param>
  317. /// <param name="function">the meta object for the built in function</param>
  318. /// <param name="hasSelf">true if we're calling with an instance</param>
  319. /// <param name="args">The arguments being passed to the function</param>
  320. /// <param name="functionRestriction">A restriction for the built-in function, method desc, etc...</param>
  321. /// <param name="bind">A delegate to perform the actual call to the method.</param>
  322. internal DynamicMetaObject/*!*/ MakeBuiltinFunctionCall(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/ function, DynamicMetaObject/*!*/[] args, bool hasSelf, BindingRestrictions/*!*/ functionRestriction, Func<DynamicMetaObject/*!*/[]/*!*/, BindingResult/*!*/> bind) {
  323. DynamicMetaObject res = null;
  324. // if we have a user defined operator for **args then transform it into a PythonDictionary
  325. DynamicMetaObject translated = TranslateArguments(call, codeContext, new DynamicMetaObject(function.Expression, functionRestriction, function.Value), args, hasSelf, Name);
  326. if (translated != null) {
  327. return translated;
  328. }
  329. // swap the arguments if we have a reversed operator
  330. if (IsReversedOperator) {
  331. ArrayUtils.SwapLastTwo(args);
  332. }
  333. // do the appropriate calling logic
  334. BindingResult result = bind(args);
  335. // validate the result
  336. BindingTarget target = result.Target;
  337. res = result.MetaObject;
  338. if (target.Overload != null && target.Overload.IsProtected) {
  339. // report an error when calling a protected member
  340. res = new DynamicMetaObject(
  341. BindingHelpers.TypeErrorForProtectedMember(
  342. target.Overload.DeclaringType,
  343. target.Overload.Name
  344. ),
  345. res.Restrictions
  346. );
  347. } else if (IsBinaryOperator && args.Length == 2 && IsThrowException(res.Expression)) {
  348. // Binary Operators return NotImplemented on failure.
  349. res = new DynamicMetaObject(
  350. Ast.Property(null, typeof(PythonOps), "NotImplemented"),
  351. res.Restrictions
  352. );
  353. } else if (target.Overload != null) {
  354. // Add profiling information for this builtin function, if applicable
  355. IPythonSite pythonSite = (call as IPythonSite);
  356. if (pythonSite != null) {
  357. var pc = pythonSite.Context;
  358. var po = pc.Options as PythonOptions;
  359. if (po != null && po.EnableProfiler) {
  360. Profiler profiler = Profiler.GetProfiler(pc);
  361. res = new DynamicMetaObject(
  362. profiler.AddProfiling(res.Expression, target.Overload.ReflectionInfo),
  363. res.Restrictions
  364. );
  365. }
  366. }
  367. }
  368. // add any warnings that are applicable for calling this function
  369. WarningInfo info;
  370. if (target.Overload != null && BindingWarnings.ShouldWarn(PythonContext.GetPythonContext(call), target.Overload, out info)) {
  371. res = info.AddWarning(codeContext, res);
  372. }
  373. // finally add the restrictions for the built-in function and return the result.
  374. res = new DynamicMetaObject(
  375. res.Expression,
  376. functionRestriction.Merge(res.Restrictions)
  377. );
  378. // The function can return something typed to boolean or int.
  379. // If that happens, we need to apply Python's boxing rules.
  380. if (res.Expression.Type.IsValueType()) {
  381. res = BindingHelpers.AddPythonBoxing(res);
  382. } else if (res.Expression.Type == typeof(void)) {
  383. res = new DynamicMetaObject(
  384. Expression.Block(
  385. res.Expression,
  386. Expression.Constant(null)
  387. ),
  388. res.Restrictions
  389. );
  390. }
  391. return res;
  392. }
  393. internal static DynamicMetaObject TranslateArguments(DynamicMetaObjectBinder call, Expression codeContext, DynamicMetaObject function, DynamicMetaObject/*!*/[] args, bool hasSelf, string name) {
  394. if (hasSelf) {
  395. args = ArrayUtils.RemoveFirst(args);
  396. }
  397. CallSignature sig = BindingHelpers.GetCallSignature(call);
  398. if (sig.HasDictionaryArgument()) {
  399. int index = sig.IndexOf(ArgumentType.Dictionary);
  400. DynamicMetaObject dict = args[index];
  401. if (!(dict.Value is IDictionary) && dict.Value != null) {
  402. // The DefaultBinder only handles types that implement IDictionary. Here we have an
  403. // arbitrary user-defined mapping type. We'll convert it into a PythonDictionary
  404. // and then have an embedded dynamic site pass that dictionary through to the default
  405. // binder.
  406. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args);
  407. dynamicArgs[index + 1] = new DynamicMetaObject(
  408. Expression.Call(
  409. typeof(PythonOps).GetMethod("UserMappingToPythonDictionary"),
  410. codeContext,
  411. args[index].Expression,
  412. AstUtils.Constant(name)
  413. ),
  414. BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()),
  415. PythonOps.UserMappingToPythonDictionary(PythonContext.GetPythonContext(call).SharedContext, dict.Value, name)
  416. );
  417. if (call is IPythonSite) {
  418. dynamicArgs = ArrayUtils.Insert(
  419. new DynamicMetaObject(codeContext, BindingRestrictions.Empty),
  420. dynamicArgs
  421. );
  422. }
  423. return new DynamicMetaObject(
  424. DynamicExpression.Dynamic(
  425. call,
  426. typeof(object),
  427. DynamicUtils.GetExpressions(dynamicArgs)
  428. ),
  429. BindingRestrictions.Combine(dynamicArgs).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()))
  430. );
  431. }
  432. }
  433. if (sig.HasListArgument()) {
  434. int index = sig.IndexOf(ArgumentType.List);
  435. DynamicMetaObject str = args[index];
  436. // TODO: ANything w/ __iter__ that's not an IList<object>
  437. if (!(str.Value is IList<object>) && str.Value is IEnumerable) {
  438. // The DefaultBinder only handles types that implement IList<object>. Here we have a
  439. // string. We'll convert it into a tuple
  440. // and then have an embedded dynamic site pass that tuple through to the default
  441. // binder.
  442. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args);
  443. dynamicArgs[index + 1] = new DynamicMetaObject(
  444. Expression.Call(
  445. typeof(PythonOps).GetMethod("MakeTupleFromSequence"),
  446. Expression.Convert(args[index].Expression, typeof(object))
  447. ),
  448. BindingRestrictions.Empty
  449. );
  450. if (call is IPythonSite) {
  451. dynamicArgs = ArrayUtils.Insert(
  452. new DynamicMetaObject(codeContext, BindingRestrictions.Empty),
  453. dynamicArgs
  454. );
  455. }
  456. return new DynamicMetaObject(
  457. DynamicExpression.Dynamic(
  458. call,
  459. typeof(object),
  460. DynamicUtils.GetExpressions(dynamicArgs)
  461. ),
  462. function.Restrictions.Merge(
  463. BindingRestrictions.Combine(args).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(str.Expression, str.GetLimitType()))
  464. )
  465. );
  466. }
  467. }
  468. return null;
  469. }
  470. private static bool IsThrowException(Expression expr) {
  471. if (expr.NodeType == ExpressionType.Throw) {
  472. return true;
  473. } else if (expr.NodeType == ExpressionType.Convert) {
  474. return IsThrowException(((UnaryExpression)expr).Operand);
  475. } else if (expr.NodeType == ExpressionType.Block) {
  476. foreach (Expression e in ((BlockExpression)expr).Expressions) {
  477. if (IsThrowException(e)) {
  478. return true;
  479. }
  480. }
  481. }
  482. return false;
  483. }
  484. #endregion
  485. #region Public Python APIs
  486. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "cls")]
  487. public static object/*!*/ __new__(object cls, object newFunction, object inst) {
  488. return new Method(newFunction, inst, null);
  489. }
  490. public int __cmp__(CodeContext/*!*/ context, [NotNull]BuiltinFunction/*!*/ other) {
  491. if (other == this) {
  492. return 0;
  493. }
  494. if (!IsUnbound && !other.IsUnbound) {
  495. int result = PythonOps.Compare(__self__, other.__self__);
  496. if (result != 0) {
  497. return result;
  498. }
  499. if (_data == other._data) {
  500. return 0;
  501. }
  502. }
  503. int res = String.CompareOrdinal(__name__, other.__name__);
  504. if (res != 0) {
  505. return res;
  506. }
  507. res = String.CompareOrdinal(Get__module__(context), other.Get__module__(context));
  508. if (res != 0) {
  509. return res;
  510. }
  511. long lres = IdDispenser.GetId(this) - IdDispenser.GetId(other);
  512. return lres > 0 ? 1 : -1;
  513. }
  514. // these are present in CPython but always return NotImplemented.
  515. [return: MaybeNotImplemented]
  516. [Python3Warning("builtin_function_or_method order comparisons not supported in 3.x")]
  517. public static NotImplementedType operator >(BuiltinFunction self, BuiltinFunction other) {
  518. return PythonOps.NotImplemented;
  519. }
  520. [return: MaybeNotImplemented]
  521. [Python3Warning("builtin_function_or_method order comparisons not supported in 3.x")]
  522. public static NotImplementedType operator <(BuiltinFunction self, BuiltinFunction other) {
  523. return PythonOps.NotImplemented;
  524. }
  525. [return: MaybeNotImplemented]
  526. [Python3Warning("builtin_function_or_method order comparisons not supported in 3.x")]
  527. public static NotImplementedType operator >=(BuiltinFunction self, BuiltinFunction other) {
  528. return PythonOps.NotImplemented;
  529. }
  530. [return: MaybeNotImplemented]
  531. [Python3Warning("builtin_function_or_method order comparisons not supported in 3.x")]
  532. public static NotImplementedType operator <=(BuiltinFunction self, BuiltinFunction other) {
  533. return PythonOps.NotImplemented;
  534. }
  535. public int __hash__(CodeContext/*!*/ context) {
  536. return PythonOps.Hash(context, _instance) ^ PythonOps.Hash(context, _data);
  537. }
  538. [SpecialName, PropertyMethod]
  539. public string Get__module__(CodeContext/*!*/ context) {
  540. if (Targets.Count > 0) {
  541. PythonType declaringType = DynamicHelpers.GetPythonTypeFromType(DeclaringType);
  542. string res = PythonTypeOps.GetModuleName(context, declaringType.UnderlyingSystemType);
  543. if (res != "__builtin__" || DeclaringType == typeof(IronPython.Modules.Builtin)) {
  544. return res;
  545. }
  546. }
  547. return null;
  548. }
  549. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), SpecialName, PropertyMethod]
  550. public void Set__module__(string value) {
  551. // Do nothing but don't return an error
  552. }
  553. /// <summary>
  554. /// Provides (for reflected methods) a mapping from a signature to the exact target
  555. /// which takes this signature.
  556. /// signature with syntax like the following:
  557. /// someClass.SomeMethod.Overloads[str, int]("Foo", 123)
  558. /// </summary>
  559. public virtual BuiltinFunctionOverloadMapper Overloads {
  560. [PythonHidden]
  561. get {
  562. // The mapping is actually provided by a class rather than a dictionary
  563. // since it's hard to generate all the keys of the signature mapping when
  564. // two type systems are involved.
  565. return new BuiltinFunctionOverloadMapper(this, IsUnbound ? null : _instance);
  566. }
  567. }
  568. /// <summary>
  569. /// Gets the overload dictionary for the logical function. These overloads
  570. /// are never bound to an instance.
  571. /// </summary>
  572. internal Dictionary<BuiltinFunction.TypeList, BuiltinFunction> OverloadDictionary {
  573. get {
  574. if (_data.OverloadDictionary == null) {
  575. Interlocked.CompareExchange(
  576. ref _data.OverloadDictionary,
  577. new Dictionary<BuiltinFunction.TypeList, BuiltinFunction>(),
  578. null);
  579. }
  580. return _data.OverloadDictionary;
  581. }
  582. }
  583. public string __name__ {
  584. get {
  585. return Name;
  586. }
  587. }
  588. public virtual string __doc__ {
  589. get {
  590. StringBuilder sb = new StringBuilder();
  591. IList<MethodBase> targets = Targets;
  592. for (int i = 0; i < targets.Count; i++) {
  593. if (targets[i] != null) {
  594. if (IsBuiltinModuleMethod) {
  595. sb.Append(DocBuilder.DocOneInfo(targets[i], Name, false));
  596. } else {
  597. sb.Append(DocBuilder.DocOneInfo(targets[i], Name));
  598. }
  599. }
  600. }
  601. return sb.ToString();
  602. }
  603. }
  604. public object __self__ {
  605. get {
  606. if (IsUnbound || IsBuiltinModuleMethod) {
  607. return null;
  608. }
  609. return _instance;
  610. }
  611. }
  612. /// <summary>
  613. /// Returns the instance used for binding. This differs on module functions implemented
  614. /// using instance methods so the built-in functions there don't expose the instance.
  615. /// </summary>
  616. internal object BindingSelf {
  617. get {
  618. if (IsUnbound) {
  619. return null;
  620. }
  621. return _instance;
  622. }
  623. }
  624. private bool IsBuiltinModuleMethod {
  625. get {
  626. return (FunctionType & FunctionType.ModuleMethod) != 0;
  627. }
  628. }
  629. public object __call__(CodeContext/*!*/ context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object[], IDictionary<object, object>, object>>> storage, [ParamDictionary]IDictionary<object, object> dictArgs, params object[] args) {
  630. return Call(context, storage, null, args, dictArgs);
  631. }
  632. internal virtual bool IsOnlyGeneric {
  633. get {
  634. return false;
  635. }
  636. }
  637. #endregion
  638. #region Private members
  639. private BinderType BinderType {
  640. get {
  641. return IsBinaryOperator ? BinderType.BinaryOperator : BinderType.Normal;
  642. }
  643. }
  644. private void EnsureBoundGenericDict() {
  645. if (_data.BoundGenerics == null) {
  646. Interlocked.CompareExchange<Dictionary<TypeList, BuiltinFunction>>(
  647. ref _data.BoundGenerics,
  648. new Dictionary<TypeList, BuiltinFunction>(1),
  649. null);
  650. }
  651. }
  652. internal class TypeList {
  653. private Type[] _types;
  654. public TypeList(Type[] types) {
  655. Debug.Assert(types != null);
  656. _types = types;
  657. }
  658. public override bool Equals(object obj) {
  659. TypeList tl = obj as TypeList;
  660. if (tl == null || _types.Length != tl._types.Length) return false;
  661. for (int i = 0; i < _types.Length; i++) {
  662. if (_types[i] != tl._types[i]) return false;
  663. }
  664. return true;
  665. }
  666. public override int GetHashCode() {
  667. int hc = 6551;
  668. foreach (Type t in _types) {
  669. hc = (hc << 5) ^ t.GetHashCode();
  670. }
  671. return hc;
  672. }
  673. }
  674. #endregion
  675. #region IDelegateConvertible Members
  676. Delegate IDelegateConvertible.ConvertToDelegate(Type type) {
  677. // see if we have any functions which are compatible with the delegate type...
  678. ParameterInfo[] delegateParams = type.GetMethod("Invoke").GetParameters();
  679. // if we have overloads then we need to do the overload resolution at runtime
  680. if (Targets.Count == 1) {
  681. MethodInfo mi = Targets[0] as MethodInfo;
  682. if (mi != null) {
  683. ParameterInfo[] methodParams = mi.GetParameters();
  684. if (methodParams.Length == delegateParams.Length) {
  685. bool match = true;
  686. for (int i = 0; i < methodParams.Length; i++) {
  687. if (delegateParams[i].ParameterType != methodParams[i].ParameterType) {
  688. match = false;
  689. break;
  690. }
  691. }
  692. if (match) {
  693. if (IsUnbound) {
  694. return mi.CreateDelegate(type);
  695. } else {
  696. return mi.CreateDelegate(type, _instance);
  697. }
  698. }
  699. }
  700. }
  701. }
  702. return null;
  703. }
  704. #endregion
  705. #region BuiltinFunctionData
  706. internal sealed class BuiltinFunctionData {
  707. public string/*!*/ Name;
  708. public MethodBase/*!*/[]/*!*/ Targets;
  709. public readonly Type/*!*/ DeclaringType;
  710. public FunctionType Type;
  711. public Dictionary<TypeList, BuiltinFunction> BoundGenerics;
  712. public Dictionary<BuiltinFunction.TypeList, BuiltinFunction> OverloadDictionary;
  713. public BuiltinFunctionData(string name, MethodBase[] targets, Type declType, FunctionType functionType) {
  714. Name = name;
  715. Targets = targets;
  716. DeclaringType = declType;
  717. Type = functionType;
  718. }
  719. internal void AddMethod(MethodBase/*!*/ info) {
  720. Assert.NotNull(info);
  721. MethodBase[] ni = new MethodBase[Targets.Length + 1];
  722. Targets.CopyTo(ni, 0);
  723. ni[Targets.Length] = info;
  724. Targets = ni;
  725. }
  726. }
  727. #endregion
  728. #region IFastInvokable Members
  729. FastBindResult<T> IFastInvokable.MakeInvokeBinding<T>(CallSite<T> site, PythonInvokeBinder binder, CodeContext state, object[] args) {
  730. return new FastBindResult<T>(
  731. binder.LightBind<T>(ArrayUtils.Insert(state, this, args), 100),
  732. true
  733. );
  734. }
  735. #endregion
  736. }
  737. /// <summary>
  738. /// A custom built-in function which supports indexing
  739. /// </summary>
  740. public class GenericBuiltinFunction : BuiltinFunction {
  741. internal GenericBuiltinFunction(string/*!*/ name, MethodBase/*!*/[]/*!*/ originalTargets, Type/*!*/ declaringType, FunctionType functionType)
  742. : base(name, originalTargets, declaringType, functionType) {
  743. }
  744. public BuiltinFunction/*!*/ this[PythonTuple tuple] {
  745. get {
  746. return this[tuple._data];
  747. }
  748. }
  749. internal GenericBuiltinFunction(object instance, BuiltinFunctionData/*!*/ data) : base(instance, data) {
  750. }
  751. internal override BuiltinFunction BindToInstance(object instance) {
  752. return new GenericBuiltinFunction(instance, _data);
  753. }
  754. /// <summary>
  755. /// Use indexing on generic methods to provide a new reflected method with targets bound with
  756. /// the supplied type arguments.
  757. /// </summary>
  758. public BuiltinFunction/*!*/ this[params object[] key] {
  759. get {
  760. // Retrieve the list of type arguments from the index.
  761. Type[] types = new Type[key.Length];
  762. for (int i = 0; i < types.Length; i++) {
  763. types[i] = Converter.ConvertToType(key[i]);
  764. }
  765. BuiltinFunction res = MakeGenericMethod(types);
  766. if (res == null) {
  767. bool hasGenerics = false;
  768. foreach (MethodBase mb in Targets) {
  769. MethodInfo mi = mb as MethodInfo;
  770. if (mi != null && mi.ContainsGenericParameters) {
  771. hasGenerics = true;
  772. }
  773. }
  774. if (hasGenerics) {
  775. throw PythonOps.TypeError(string.Format("bad type args to this generic method {0}", Name));
  776. } else {
  777. throw PythonOps.TypeError(string.Format("{0} is not a generic method and is unsubscriptable", Name));
  778. }
  779. }
  780. if (IsUnbound) {
  781. return res;
  782. }
  783. return new BuiltinFunction(_instance, res._data);
  784. }
  785. }
  786. internal override bool IsOnlyGeneric {
  787. get {
  788. foreach (MethodBase mb in Targets) {
  789. if (!mb.IsGenericMethod || !mb.ContainsGenericParameters) {
  790. return false;
  791. }
  792. }
  793. return true;
  794. }
  795. }
  796. }
  797. }