PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/Runtime/Samples/sympl/python/runtime.py

http://github.com/IronLanguages/main
Python | 1295 lines | 752 code | 145 blank | 398 comment | 142 complexity | abb03128810d30e1d8c5933d8e4bd9ca MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. import clr
  2. if clr.use35:
  3. clr.AddReference("Microsoft.Scripting")
  4. clr.AddReference("Microsoft.Dynamic")
  5. clr.AddReference("Microsoft.Scripting.Core")
  6. import Microsoft.Scripting.Ast as Exprs
  7. from Microsoft.Scripting.ComInterop import ComBinder
  8. from Microsoft.Scripting.Utils import (Action, Func)
  9. else:
  10. clr.AddReference("System.Core")
  11. clr.AddReference("Microsoft.Dynamic")
  12. import System.Linq.Expressions as Exprs
  13. from Microsoft.Scripting.ComInterop import ComBinder
  14. from System import (Action, Func)
  15. from System.Runtime.CompilerServices import CallSite
  16. from System.Dynamic import (ExpandoObject, InvokeBinder, DynamicMetaObject,
  17. GetMemberBinder, SetMemberBinder, CallInfo,
  18. BindingRestrictions, IDynamicMetaObjectProvider,
  19. InvokeMemberBinder, CreateInstanceBinder,
  20. GetIndexBinder, SetIndexBinder,
  21. BinaryOperationBinder, UnaryOperationBinder)
  22. from System import (MissingMemberException,
  23. InvalidOperationException, Boolean, MissingMemberException,
  24. Type, Array, Delegate, Void)
  25. import System.Reflection as refl
  26. from System.IO import Path, File
  27. ### RuntimeHelpers is a collection of functions that perform operations at
  28. ### runtime of Sympl code, such as performing an import or fetching a global
  29. ### variable's value (depending on global look up semantics).
  30. ###
  31. class RuntimeHelpers (object):
  32. ### SymplImport takes the runtime and module as context for the import.
  33. ### It takes a list of names, what, that either identify a (possibly dotted
  34. ### sequence) of names to fetch from Globals or a file name to load. Names
  35. ### is a list of names to fetch from the final object that what indicates
  36. ### and then set each name in module. Renames is a list of names to add to
  37. ### module instead of names. If names is empty, then the name set in
  38. ### module is the last name in what. If renames is not empty, it must have
  39. ### the same cardinality as names.
  40. ###
  41. @staticmethod
  42. def SymplImport (runtime, module, what, names, renames):
  43. ## Get object or file scope.
  44. helpers = DynamicObjectHelpers
  45. if len(what) == 1:
  46. name = what[0]
  47. if helpers.HasMember(runtime.Globals, name):
  48. value = helpers.GetMember(runtime.Globals, name)
  49. else:
  50. f = DynamicObjectHelpers.GetMember(module, "__file__")
  51. f = Path.Combine(Path.GetDirectoryName(f), name + ".sympl")
  52. if File.Exists(f):
  53. value = runtime.ExecuteFile(f)
  54. else:
  55. raise Exception("Import: can't find name in globals " +
  56. "or as file to load -- " + name + ", " +
  57. f)
  58. else:
  59. ## What has more than one name, must be Globals access.
  60. value = runtime.Globals
  61. for name in what:
  62. value = helpers.GetMember(value, name)
  63. ## Assign variables in module.
  64. if len(names) == 0:
  65. setattr(module, what[-1], value)
  66. else:
  67. for n, m in zip(names, renames or names):
  68. setattr(module, m, getattr(value, n))
  69. return None
  70. @staticmethod
  71. def SymplEq (x, y):
  72. ## Not that Sympl has other immediate values, but could add more branches
  73. ## for doubles or types that might flow in from .NET interop.
  74. if type(x) is int and type(y) is int:
  75. return x == y
  76. else:
  77. return x is y
  78. ### Hack until dynamic expr invoking Cons type is fixed in Ipy.
  79. ###
  80. @staticmethod
  81. def MakeCons (x, y):
  82. return Cons(x, y)
  83. @staticmethod
  84. def GetConsElt (lst, i):
  85. return RuntimeHelpers._nthcdr(lst, i).First
  86. @staticmethod
  87. def SetConsElt (lst, i, value):
  88. lst = RuntimeHelpers._nthcdr(lst, i)
  89. lst.First = value
  90. return value
  91. @staticmethod
  92. def _nthcdr (lst, i):
  93. while i > 0 and lst is not None:
  94. lst = lst.Rest
  95. i = i - 1
  96. if i == 0 and lst is not None:
  97. return lst
  98. else:
  99. raise Exception("List doesn't have " + repr(i) + " elements.")
  100. ### Don't need this in C# because can create an Property MemberExpr. This
  101. ### works in IPy because our TMMO.BindGetMember falls back to Python's
  102. ### MO to fetch the member.
  103. ###
  104. #@staticmethod
  105. #def GetTypeModelReflType (typModel):
  106. # return typModel.ReflType
  107. ########################
  108. ### Helpers for code gen
  109. ########################
  110. ### RunHelpersInvokeBinder is the binder that let's me invoke members of
  111. ### runtimeHelpers as DynamicExprs. In C#, we can create MethodCallExprs
  112. ### with the MethodInfos of my RuntimeHelpers members, so we don't need this.
  113. ###
  114. class RunHelpersInvokeBinder (InvokeBinder):
  115. #@property doesn't work
  116. def get_CacheIdentity (self):
  117. return self
  118. def GetHashCode (self):
  119. ## Random sophmoric hash ...
  120. return 197 ^ super(RunHelpersInvokeBinder, self).GetHashCode()
  121. def Equals (self, obj):
  122. return (isinstance(obj, RunHelpersInvokeBinder) and
  123. super(RunHelpersInvokeBinder, self).Equals(obj))
  124. def FallbackInvoke(objMO, argMOs, errorSuggestionMO):
  125. ## Python handles the actual invoke in its callable MO
  126. ## When translated to C#, won't need DynExpr to call helper ... MCE.
  127. pass
  128. ### MakeSymplImportCall gets called from analysis code that generates
  129. ### Expression Trees for Sympl 'import' expressions. Runtime and module
  130. ### are ParamExprs from the outer lambda wrapping a file's top-level exprs.
  131. ### What, names, and renames are lists (possibly empty) of IdTokens.
  132. ###
  133. def MakeSymplImportCall (runtime, module, what, names, renames):
  134. if not isinstance(names, list):
  135. raise Exception("Internal: name is not list?")
  136. return Exprs.Expression.Dynamic(
  137. RunHelpersInvokeBinder(CallInfo(5)),
  138. object, #ret type
  139. Exprs.Expression.Constant(RuntimeHelpers.SymplImport),
  140. runtime, module,
  141. Exprs.Expression.Constant([x.Name for x in what]),
  142. Exprs.Expression.Constant([x.Name for x in names]),
  143. Exprs.Expression.Constant([x.Name for x in renames]))
  144. def MakeSymplEqCall (left, right):
  145. return Exprs.Expression.Convert(
  146. Exprs.Expression.Dynamic(
  147. RunHelpersInvokeBinder(CallInfo(2)),
  148. object, #ret type
  149. Exprs.Expression.Constant(RuntimeHelpers.SymplEq),
  150. left, right),
  151. bool) #clr.GetClrType(Boolean))
  152. def MakeSymplConsCall (left, right):
  153. return Exprs.Expression.Dynamic(
  154. RunHelpersInvokeBinder(CallInfo(2)),
  155. object, #ret type
  156. Exprs.Expression.Constant(RuntimeHelpers.MakeCons),
  157. left, right)
  158. def MakeSymplListCall (args):
  159. return Exprs.Expression.Dynamic(
  160. RunHelpersInvokeBinder(CallInfo(len(args))),
  161. object, #ret type
  162. Exprs.Expression.Constant(Cons._List),
  163. *args)
  164. ###############################
  165. ### Helpers for runtime binding
  166. ###############################
  167. ### GetTargetArgsRestrictions generates the restrictions needed for the
  168. ### MO resulting from binding an operation. This combines all existing
  169. ### restrictions and adds some for arg conversions. targetInst indicates
  170. ### whether to restrict the target to an instance (for operations on type
  171. ### objects) or to a type (for operations on an instance of that type).
  172. ###
  173. ### NOTE, this function should only be used when the caller is converting
  174. ### arguments to the same types as these restrictions. See ConvertArguments.
  175. ###
  176. def GetTargetArgsRestrictions (targetMO, argMOs, targetInst):
  177. ## Important to add existing restriction first because the
  178. ## DynamicMetaObjects (and possibly values) we're looking at depend
  179. ## on the pre-existing restrictions holding true.
  180. restrictions = targetMO.Restrictions.Merge(
  181. BindingRestrictions.Combine(argMOs))
  182. if targetInst:
  183. restrictions = restrictions.Merge(
  184. BindingRestrictions.GetInstanceRestriction(
  185. targetMO.Expression,
  186. targetMO.Value))
  187. else:
  188. restrictions = restrictions.Merge(
  189. BindingRestrictions.GetTypeRestriction(
  190. targetMO.Expression,
  191. targetMO.LimitType))
  192. for a in argMOs:
  193. if a.HasValue and a.Value is None:
  194. r = BindingRestrictions.GetInstanceRestriction(a.Expression,
  195. None)
  196. else:
  197. r = BindingRestrictions.GetTypeRestriction(a.Expression,
  198. a.LimitType)
  199. restrictions = restrictions.Merge(r)
  200. return restrictions
  201. ### ParamsMatchArgs returns whether the args are assignable to the parameters.
  202. ### We specially check for our TypeModel that wraps .NET's RuntimeType, and
  203. ### elsewhere we detect the same situation to convert the TypeModel for calls.
  204. ###
  205. ### IsAssignableFrom works except for value args that need to pass to reftype
  206. ### params. We could detect that to be smarter and then explicitly StrongBox
  207. ### the args.
  208. ###
  209. ### Could check for a.HasValue and a.Value is None and
  210. ### ((paramtype is class or interface) or (paramtype is generic and
  211. ### nullable<t>)) to support passing nil anywhere.
  212. ###
  213. ### Consider checking p.IsByRef and returning false since that's not CLS.
  214. ###
  215. def ParamsMatchArgs (params, args):
  216. for a,p in zip(args, params):
  217. if (p.ParameterType is clr.GetClrType(Type) and #get past py type wrapping
  218. type(a.Value) is TypeModel): #ok if no value, value = null
  219. continue
  220. if not p.ParameterType.IsAssignableFrom(a.LimitType):
  221. ## or p.IsByRef: punt for non CLS
  222. return False
  223. return True
  224. ### Returns a DynamicMetaObject with an expression that fishes the .NET
  225. ### RuntimeType object from the TypeModel MO.
  226. ###
  227. def GetRuntimeTypeMoFromModel (typeMO):
  228. if type(typeMO) is not TypeModelMetaObject:
  229. raise Exception("Internal: Need TMMO to fish out ReflType.")
  230. return DynamicMetaObject(
  231. ## In C# can use Expression.Call on methodinfo.
  232. Exprs.Expression.Convert(
  233. Exprs.Expression.Dynamic(
  234. ## This call site doesn't share any L2 caching
  235. ## since we don't call GetGetMemberBinder from Sympl.
  236. ## We aren't plumbed to get the runtime instance here.
  237. SymplGetMemberBinder("ReflType"),
  238. object,
  239. typeMO.Expression),
  240. Type),
  241. #Exprs.Expression.Dynamic(
  242. # RunHelpersInvokeBinder(CallInfo(1)),
  243. # object,
  244. # Exprs.Expression.Constant(
  245. # RuntimeHelpers.GetTypeModelReflType),
  246. # typeMO.Expression),
  247. typeMO.Restrictions.Merge(
  248. BindingRestrictions.GetTypeRestriction(
  249. typeMO.Expression, TypeModel))) #,
  250. ## Must supply a value to prevent binder FallbackXXX methods
  251. ## from infinitely looping if they do not check this MO for
  252. ## HasValue == false and call Defer. After Sympl added Defer
  253. ## checks, we could verify, say, FallbackInvokeMember by no
  254. ## longer passing a value here.
  255. #typeMO.ReflType)
  256. ### Returns list of Convert exprs converting args to param types. If an arg
  257. ### is a TypeModel, then we treat it special to perform the binding. We need
  258. ### to map from our runtime model to .NET's RuntimeType object to match.
  259. ###
  260. ### To call this function, args and pinfos must be the same length, and param
  261. ### types must be assignable from args.
  262. ###
  263. ### NOTE, if using this function, then need to use GetTargetArgsRestrictions
  264. ### and make sure you're performing the same conversions as restrictions.
  265. ###
  266. def ConvertArguments (argMOs, pinfos):
  267. res = []
  268. for p,a in zip(pinfos, argMOs):
  269. argExpr = a.Expression
  270. if type(a.Value) is TypeModel and p.ParameterType is clr.GetClrType(Type):
  271. argExpr = GetRuntimeTypeMoFromModel(a).Expression
  272. res.append(Exprs.Expression.Convert(argExpr, p.ParameterType))
  273. return res
  274. ###
  275. ### Note, callers must ensure the DynamicMetaObject that uses this expression
  276. ### has consistent restrictions for the conversion done on args and the target.
  277. ###
  278. def GetIndexExpression (targetMO, indexMOs):
  279. indexExprs = [Exprs.Expression.Convert(x.Expression, x.LimitType)
  280. for x in indexMOs]
  281. if type(targetMO.Value) is Cons: #Don't look at LimitType to compare py type objs.
  282. ## In C# can use Expression.Call on methodinfo.
  283. return Exprs.Expression.Dynamic(
  284. RunHelpersInvokeBinder(CallInfo(2)),
  285. object,
  286. Exprs.Expression.Constant(RuntimeHelpers.GetConsElt),
  287. Exprs.Expression.Convert(targetMO.Expression,
  288. targetMO.LimitType),
  289. indexExprs[0])
  290. elif targetMO.LimitType.IsArray:
  291. return Exprs.Expression.ArrayAccess(
  292. Exprs.Expression.Convert(targetMO.Expression,
  293. targetMO.LimitType),
  294. indexExprs)
  295. else:
  296. ## Check for Item indexer.
  297. props = targetMO.LimitType.GetProperties()
  298. props = [x for x in props if len(x.GetIndexParameters()) == len(indexMOs)]
  299. res = []
  300. for p in props:
  301. if ParamsMatchArgs(p.GetIndexParameters(), indexMOs):
  302. res.append(p)
  303. if len(res) == 0:
  304. return Exprs.Expression.Throw(
  305. Exprs.Expression.New(
  306. MissingMemberException.GetConstructor(
  307. Array[Type]([str])),
  308. Exprs.Expression.Constant(
  309. "Can't find matching indexer property.")))
  310. return Exprs.Expression.MakeIndex(
  311. Exprs.Expression.Convert(targetMO.Expression,
  312. targetMO.LimitType),
  313. res[0], indexExprs)
  314. ## CreateThrow takes arguments like fallback and bind methods, dynamic meta
  315. ## objects. It also takes restrictions to constrain when the throw rule is
  316. ## good. It takes an Exception type and arguments for the throw the resulting
  317. ## DynamicMetaObject represents. It returns a DynamicMetaObject whose expr
  318. ## throws the exception, and ensures the expr's type is object to satisfy
  319. ## the CallSite return type constraint.
  320. ##
  321. def CreateThrow (target, args, moreTests, exception, *exceptionArgs):
  322. argExprs = None
  323. argTypes = Type.EmptyTypes
  324. if exceptionArgs is not None:
  325. argExprs = []
  326. argTypes = []
  327. for o in exceptionArgs:
  328. e = Exprs.Expression.Constant(o)
  329. argExprs.append(e)
  330. argTypes.append(e.Type)
  331. constructor = clr.GetClrType(exception).GetConstructor(Array[Type](argTypes))
  332. if constructor is None:
  333. raise ArgumentException(
  334. "Type doesn't have constructor with a given signature")
  335. return DynamicMetaObject(
  336. Exprs.Expression.Throw(
  337. Exprs.Expression.New(constructor, argExprs),
  338. ## Force expression to be type object so that DLR CallSite code
  339. ## things only type object flows out of the CallSite.
  340. object),
  341. target.Restrictions.Merge(BindingRestrictions.Combine(args))
  342. .Merge(moreTests))
  343. ### EnsureObjectResult wraps expr if necessary so that any binder or
  344. ### DynamicMetaObject result expression returns object. This is required
  345. ### by CallSites.
  346. ###
  347. def EnsureObjectResult (expr):
  348. if not expr.Type.IsValueType:
  349. return expr
  350. if expr.Type is clr.GetClrType(Void):
  351. return Exprs.Expression.Block(expr, Exprs.Expression.Default(object))
  352. else:
  353. return Exprs.Expression.Convert(expr, object)
  354. ##############################
  355. ### Type model IDynObj wrapper
  356. ##############################
  357. ### TypeModel wraps System.Runtimetypes. When Sympl code encounters
  358. ### a type leaf node in Sympl.Globals and tries to invoke a member, wrapping
  359. ### the ReflectionTypes in TypeModels allows member access to get the type's
  360. ### members and not ReflectionType's members.
  361. ###
  362. class TypeModel (object, IDynamicMetaObjectProvider):
  363. def __init__ (self, typ):
  364. ## Note, need to check for initialized members in GetMetaObject so
  365. ## that creating TypeModel's works without using our custom MO.
  366. self.ReflType = typ
  367. ### GetMetaObject needs to wrap the base IDO due to Python's objects all
  368. ### being IDOs. While this GetMetaObject definition is on the stack IPy
  369. ### ensures Ipy uses its own MO for TypeModel instances. However, when
  370. ### this function is NOT pending on the stack, IPy calls this GetMetaObject
  371. ### to get the MO. TypeModelMetaObject needs to delegate to the Python IDO
  372. ### to dot into TypeModel instances for members, or capture all the
  373. ### TypeModel state in our MO. We pass ReflType here so that in
  374. ### TypeModelMetaObject BindXXX methods, we do not have to access TypeModel
  375. ### instance members. If we did access TypeModel instance members from
  376. ### TypeModelMetaObject, then that code would call this GetMetaObject and
  377. ### use the BindGetMember below, which would fail to access ReflType since
  378. ### the BindGetMember blow looks for members on the type represented by
  379. ### ReflType.
  380. ###
  381. ### The C# implementation won't need to do this awkward workaround.
  382. ###
  383. def GetMetaObject (self, objParam):
  384. baseIdoMo = IDynamicMetaObjectProvider.GetMetaObject(self, objParam)
  385. if hasattr(self, "ReflType"):
  386. ## If came through once and initialized this slot, then return
  387. ## my MO for accessing the members of the type represented by
  388. ## ReflType.
  389. return TypeModelMetaObject(objParam, self, self.ReflType,
  390. baseIdoMo)
  391. return baseIdoMo
  392. class TypeModelMetaObject (DynamicMetaObject):
  393. ### Constructor takes ParameterExpr to reference CallSite, a TypeModel
  394. ### that the new TypeModelMetaObject represents, and the base Python IDO MO
  395. ### handle for the TypeModel instance that Python uses. We need to
  396. ### delegate to this MO explicitly to get Python to do binding for us on
  397. ### TypeModel instances when it is NOT Sympl code that is trying to use
  398. ### the TypeModel to dot into members on the type represented by the
  399. ### TypeModel instance.
  400. ###
  401. def __new__ (self, objParam, typModel, refltype, baseIdoMo):
  402. mo = super(TypeModelMetaObject, self).__new__(
  403. TypeModelMetaObject, objParam, BindingRestrictions.Empty,
  404. typModel)
  405. mo.TypModel = typModel
  406. mo.ReflType = refltype
  407. mo.ObjParamExpr = objParam
  408. mo.BaseIDOMO = baseIdoMo
  409. return mo
  410. def BindGetMember (self, binder):
  411. #debugprint("tmmo bindgetmember ...", binder.Name)
  412. flags = (refl.BindingFlags.IgnoreCase | refl.BindingFlags.Static |
  413. refl.BindingFlags.Public)
  414. ## consider BindingFlags.Instance if want to return wrapper for
  415. ## inst members that is callable.
  416. members = self.ReflType.GetMember(binder.Name, flags)
  417. if len(members) == 1:
  418. return DynamicMetaObject(
  419. ## We always access static members for type model
  420. ## objects, so the first argument in MakeMemberAccess
  421. ## should be null (no instance).
  422. EnsureObjectResult(
  423. Exprs.Expression.MakeMemberAccess(
  424. None, members[0])),
  425. ## Don't need restriction test for name since this
  426. ## rule is only used where binder is used, which is
  427. ## only used in sites with this binder.Name.
  428. self.Restrictions.Merge(
  429. BindingRestrictions.GetInstanceRestriction(
  430. self.Expression,
  431. self.Value)))
  432. else:
  433. ## Defer to IPy binding to access TypeModel instance members. IPy
  434. ## will fallback to the binder as appropriate.
  435. ##return binder.FallbackGetMember(self)
  436. return self.BaseIDOMO.BindGetMember(binder)
  437. ### Because we don't ComboBind over several MOs and operations, and no one
  438. ### is falling back to this function with MOs that have no values, we
  439. ### don't need to check HasValue. If we did check, and HasValue == False,
  440. ### then would defer to new InvokeMemberBinder.Defer().
  441. ###
  442. def BindInvokeMember (self, binder, args):
  443. debugprint("tmmo: bindinvokemember ...", binder.Name)
  444. flags = (refl.BindingFlags.IgnoreCase | refl.BindingFlags.Static |
  445. refl.BindingFlags.Public)
  446. members = self.ReflType.GetMember(binder.Name, flags)
  447. if (len(members) == 1 and
  448. (isinstance(members[0], refl.PropertyInfo) or
  449. isinstance(members[0], refl.FieldInfo))):
  450. raise Exception("Haven't implemented invoking delegate values " +
  451. "from properties or fields.")
  452. ## NOT TESTED, should check type for isinstance delegate
  453. #return DynamicMetaObject(
  454. # Exprs.Expression.Dynamic(
  455. # SymplInvokeBinder(CallInfo(len(args))),
  456. # object,
  457. # ([Exprs.MakeMemberAccess(self.Expression, mem)] +
  458. # (x.Expression for x in args))))
  459. ## Don't test for eventinfos since we do nothing with them now.
  460. else:
  461. ## Get MethodInfos with right arg count.
  462. debugprint("tmmo bind invoke mem ... searching ...", len(members))
  463. mi_mems = [x for x in members if isinstance(x, refl.MethodInfo) and
  464. len(x.GetParameters()) == len(args)]
  465. debugprint("methodinfo members with same arg count: ", len(mi_mems))
  466. debugprint(mi_mems)
  467. res = []
  468. for mem in mi_mems:
  469. if ParamsMatchArgs(mem.GetParameters(), args):
  470. res.append(mem)
  471. if len(res) == 0:
  472. ## Sometimes when binding members on TypeModels the member
  473. ## is an intance member since the Type is an instance of Type.
  474. ## We fallback to the binder with the Type instance to see if
  475. ## it binds. The SymplInvokeMemberBinder does handle this.
  476. refltypeMO = GetRuntimeTypeMoFromModel(self)
  477. return binder.FallbackInvokeMember(refltypeMO, args, None)
  478. ## True means generate an instance restriction on the MO.
  479. ## We are only looking at the members defined in this Type instance.
  480. restrictions = GetTargetArgsRestrictions(self, args, True)
  481. ## restrictions and conversion must be done consistently.
  482. callArgs = ConvertArguments(args, res[0].GetParameters())
  483. ## Fix expr to satisfy object type required by CallSite.
  484. return DynamicMetaObject(
  485. EnsureObjectResult(Exprs.Expression.Call(res[0],
  486. callArgs)),
  487. restrictions)
  488. ## Could try just letting Expr.Call factory do the work, but if
  489. ## there is more than one applicable method using just
  490. ## assignablefrom, Expr.Call flames out. It does not pick a "most
  491. ## applicable" method.
  492. ## Defer to IPy binding to invoke TypeModel instance members. IPy
  493. ## will fallback to the binder as appropriate.
  494. ##return binder.FallbackInvokeMember(self)
  495. ##return self.BaseIDOMO.BindInvokeMember(binder, args)
  496. def BindCreateInstance (self, binder, args):
  497. ctors = self.ReflType.GetConstructors()
  498. ## Get constructors with right arg count.
  499. ctors = [x for x in ctors
  500. if len(x.GetParameters()) == len(args)]
  501. res = []
  502. for mem in ctors:
  503. if ParamsMatchArgs(mem.GetParameters(), args):
  504. res.append(mem)
  505. if len(res) == 0:
  506. refltypeMO = GetRuntimeTypeMoFromModel(self)
  507. return binder.FallbackCreateInstance(refltypeMO, args)
  508. ## True means generate an instance restriction on the MO.
  509. ## We only have a rule to create this exact type.
  510. restrictions = GetTargetArgsRestrictions(self, args, True)
  511. ## restrictions and conversion must be done consistently.
  512. callArgs = ConvertArguments(args, res[0].GetParameters())
  513. return DynamicMetaObject(
  514. ## Creating an object, so don't need EnsureObjectResult.
  515. Exprs.Expression.New(res[0], callArgs),
  516. restrictions)
  517. ###
  518. ### Bindings I don't care about, so defer to Pythons IDO
  519. ###
  520. def BindConvert (self, binder):
  521. return self.BaseIDOMO.BindConvert(binder)
  522. def BindSetMember (self, binder, valueMO):
  523. return self.BaseIDOMO.BindSetMember(binder, valueMO)
  524. def BindDeleteMember (self, binder):
  525. return self.BaseIDOMO.BindDeleteMember(binder)
  526. def BindGetIndex (self, binder, indexes):
  527. return self.BaseIDOMO.BindGetIndex (binder, indexes)
  528. def BindSetIndex (self, binder, indexes, value):
  529. return self.BaseIDOMO.BindSetIndex (binder, indexes, value)
  530. def BindDeleteIndex (self, binder, indexes):
  531. return self.BaseIDOMO.BindDeleteIndex (binder, indexes)
  532. def BindInvoke (self, binder, args):
  533. return self.BaseIDOMO.BindInvoke (binder, args)
  534. def BindUnaryOperation (self, binder):
  535. return self.BaseIDOMO.BindUnaryOperation (binder)
  536. def BindBinaryOperation (self, binder, arg):
  537. return self.BaseIDOMO.BindBinaryOperation (binder, arg)
  538. #######################################################
  539. ### Dynamic Helpers for HasMember, GetMember, SetMember
  540. #######################################################
  541. ### DynamicObjectHelpers provides access to IDynObj members given names as
  542. ### data at runtime. When the names are known at compile time (o.foo), then
  543. ### they get baked into specific sites with specific binders that encapsulate
  544. ### the name. We need this in python because hasattr et al are case-sensitive.
  545. ###
  546. ### Currently Sympl only uses this on ExpandoObjects, but it works generally on
  547. ### IDOs.
  548. ###
  549. class DynamicObjectHelpers (object):
  550. Sentinel = object()
  551. GetSites = {}
  552. SetSites = {}
  553. @staticmethod
  554. def HasMember (dynObj, name):
  555. if not isinstance(dynObj, IDynamicMetaObjectProvider):
  556. raise Exception("DynamicObjectHelpers only works on IDOs for now.")
  557. return (DynamicObjectHelpers.GetMember(dynObj, name) !=
  558. DynamicObjectHelpers.Sentinel)
  559. #Alternative impl used when EOs had bug and didn't call fallback ...
  560. #mo = dynObj.GetMetaObject(Exprs.Expression.Parameter(object, "bogus"))
  561. #for member in mo.GetDynamicMemberNames():
  562. # if String.Equals(member, name,
  563. # String.StringComparison.OrdinalIgnoreCase):
  564. # return True
  565. #return False
  566. @staticmethod
  567. def GetMember (dynObj, name):
  568. if not isinstance(dynObj, IDynamicMetaObjectProvider):
  569. raise Exception("DynamicObjectHelpers only works on IDOs for now.")
  570. ## Work around an IronPython 4.0 issue:
  571. ## http://ironpython.codeplex.com/WorkItem/View.aspx?WorkItemId=22735
  572. if clr.use35:
  573. func = Func
  574. else:
  575. func = clr.GetPythonType(Type.GetType("System.Func`3"))
  576. site = DynamicObjectHelpers.GetSites.get(name)
  577. if site is None:
  578. site = CallSite[func[CallSite, object, object]].Create(
  579. DOHelpersGetMemberBinder(name))
  580. DynamicObjectHelpers.GetSites[name] = site
  581. return site.Target(site, dynObj)
  582. @staticmethod
  583. def GetMemberNames (dynObj):
  584. if not isinstance(dynObj, IDynamicMetaObjectProvider):
  585. raise Exception("DynamicObjectHelpers only works on IDOs for now.")
  586. return (dynObj.GetMetaObject(Exprs.Expression.Parameter(object, "bogus"))
  587. .GetDynamicMemberNames())
  588. @staticmethod
  589. def SetMember(dynObj, name, value):
  590. if not isinstance(dynObj, IDynamicMetaObjectProvider):
  591. raise Exception("DynamicObjectHelpers only works on IDOs for now.")
  592. ## Work around an IronPython 4.0 issue:
  593. ## http://ironpython.codeplex.com/WorkItem/View.aspx?WorkItemId=22735
  594. if clr.use35:
  595. action = Action
  596. else:
  597. action = clr.GetPythonType(Type.GetType("System.Action`3"))
  598. site = DynamicObjectHelpers.SetSites.get(name)
  599. if site is None:
  600. ## For general usage ExpandoObject type param could be object.
  601. site = CallSite[action[CallSite, ExpandoObject, object]].Create(
  602. DOHelpersSetMemberBinder(name))
  603. DynamicObjectHelpers.SetSites[name] = site
  604. site.Target(site, dynObj, value)
  605. class DOHelpersGetMemberBinder (GetMemberBinder):
  606. #def __init__ (self, name, ignoreCase):
  607. # ## super(...) always works, even with multiple inheritance but
  608. # ## GetMemberBinder.__init__(self, name, True) would work in this case.
  609. # super(DOHelpersGetMemberBinder, self).__init__(name, ignoreCase)
  610. def __new__ (cls, name):
  611. return GetMemberBinder.__new__(cls, name, True)
  612. def FallbackGetMember(self, targetMO, errorSuggestionMO):
  613. ## Don't add my own type restriction, target adds them.
  614. return DynamicMetaObject(
  615. Exprs.Expression.Constant(DynamicObjectHelpers.Sentinel),
  616. targetMO.Restrictions)
  617. ## Don't need Equals override or GetHashCode because there is no more
  618. ## specific binding metadata in this binder than what the base methods
  619. ## already compare.
  620. # def GetHashCode (self):
  621. # pass
  622. #
  623. # def Equals (self, obj):
  624. # return (isinstance(obj, DOHelpersGetMemberBinder) and
  625. # super(DOHelpersGetMemberBinder, self).Equals(obj))
  626. class DOHelpersSetMemberBinder (SetMemberBinder):
  627. #def __init__ (self, name, ignoreCase):
  628. # super(DOHelpersSetMemberBinder, self).__init__(name, ignoreCase)
  629. def __new__ (cls, name):
  630. return SetMemberBinder.__new__(cls, name, True)
  631. def FallbackSetMember(self, targetMO, valueMO, errorSuggestionMO):
  632. return (errorSuggestionMO or
  633. CreateThrow(
  634. targetMO, None, BindingRestrictions.Empty,
  635. MissingMemberException,
  636. ## General msg: Sympl doesn't override IDOs to set members.
  637. "If IDynObj doesn't support setting members, " +
  638. "DOHelpers can't do it for the IDO."))
  639. ## Don't need Equals override or GetHashCode because there is no more
  640. ## specific binding metadata in this binder than what the base methods
  641. ## already compare.
  642. #def GetHashCode (self):
  643. # pass
  644. #
  645. #def Equals (self, obj):
  646. # return (isinstance(obj, DOHelpersSetMemberBinder) and
  647. # super(DOHelpersSetMemberBinder, self).Equals(obj))
  648. ###########################
  649. ### General Runtime Binders
  650. ###########################
  651. ### SymplGetMemberBinder is used for general dotted expressions for fetching
  652. ### members.
  653. ###
  654. class SymplGetMemberBinder (GetMemberBinder):
  655. #def __init__ (self, name, ignoreCase):
  656. # ## super(...) always works, even with multiple inheritance but
  657. # ## GetMemberBinder.__init__(self, name, True) would work in this case.
  658. # super(DOHelpersGetMemberBinder, self).__init__(name, ignoreCase)
  659. def __new__ (cls, name):
  660. return GetMemberBinder.__new__(cls, name, True) # True = IgnoreCase
  661. def FallbackGetMember(self, targetMO, errorSuggestionMO):
  662. ## Defer if any object has no value so that we evaulate their
  663. ## Expressions and nest a CallSite for the GetMember.
  664. if not targetMO.HasValue:
  665. return self.Defer(targetMO)
  666. ## Try COM binding first.
  667. isCom, com = ComBinder.TryBindGetMember(self, targetMO, True)
  668. if isCom:
  669. return com
  670. debugprint("symplgetmember ...", targetMO.Expression, self.Name)
  671. ## Find our own binding.
  672. flags = (refl.BindingFlags.IgnoreCase | refl.BindingFlags.Static |
  673. refl.BindingFlags.Instance | refl.BindingFlags.Public)
  674. ## bindingflags.flattenhierarchy? public and protected static members
  675. members = targetMO.LimitType.GetMember(self.Name, flags)
  676. if len(members) == 1:
  677. return DynamicMetaObject(
  678. EnsureObjectResult(
  679. Exprs.Expression.MakeMemberAccess(
  680. Exprs.Expression.Convert(targetMO.Expression,
  681. members[0].DeclaringType),
  682. members[0])),
  683. ## Don't need restriction test for name since this
  684. ## rule is only used where binder is used, which is
  685. ## only used in sites with this binder.Name.
  686. BindingRestrictions.GetTypeRestriction(
  687. targetMO.Expression, targetMO.LimitType))
  688. else:
  689. if errorSuggestionMO is not None:
  690. return errorSuggestionMO
  691. return CreateThrow(
  692. targetMO, None,
  693. BindingRestrictions.GetTypeRestriction(
  694. targetMO.Expression, targetMO.LimitType),
  695. MissingMemberException,
  696. "Object " + str(targetMO.Value) +
  697. " does not have member " + self.Name)
  698. ### SymplSetMemberBinder is used for general dotted expressions for setting
  699. ### members.
  700. ###
  701. class SymplSetMemberBinder (SetMemberBinder):
  702. #def __init__ (self, name, ignoreCase):
  703. # ## super(...) always works, even with multiple inheritance but
  704. # ## GetMemberBinder.__init__(self, name, True) would work in this case.
  705. # super(DOHelpersGetMemberBinder, self).__init__(name, ignoreCase)
  706. def __new__ (cls, name):
  707. return SetMemberBinder.__new__(cls, name, True) # True = IgnoreCase
  708. def FallbackSetMember(self, targetMO, valueMO, errorSuggestionMO):
  709. debugprint("symplsetmember fallback ...", targetMO.Expression, self.Name,
  710. " ..name now expr..", valueMO.Expression)
  711. ## Defer if any object has no value so that we evaulate their
  712. ## Expressions and nest a CallSite for the SetMember.
  713. if not targetMO.HasValue:
  714. return self.Defer(targetMO)
  715. ## Try COM object first.
  716. isCom, com = ComBinder.TryBindSetMember(self, targetMO, valueMO)
  717. if isCom:
  718. return com
  719. ## Find our own binding.
  720. flags = (refl.BindingFlags.IgnoreCase | refl.BindingFlags.Static |
  721. refl.BindingFlags.Instance | refl.BindingFlags.Public)
  722. members = targetMO.LimitType.GetMember(self.Name, flags)
  723. if len(members) == 1:
  724. mem = members[0]
  725. val = None
  726. ## Should check for member domain type being Type and value being
  727. ## TypeModel, similar to ConvertArguments, and building an
  728. ## expression like GetRuntimeTypeMoFromModel.
  729. if mem.MemberType == refl.MemberTypes.Property:
  730. val = Exprs.Expression.Convert(valueMO.Expression,
  731. mem.PropertyType)
  732. elif mem.MemberType == refl.MemberTypes.Field:
  733. val = Exprs.Expression.Convert(valueMO.Expression,
  734. mem.FieldType)
  735. else:
  736. return (errorSuggestionMO or
  737. CreateThrow(
  738. targetMO, None,
  739. BindingRestrictions.GetTypeRestriction(
  740. targetMO.Expression, targetMO.LimitType),
  741. InvalidOperationException,
  742. "Sympl only support setting properties and " +
  743. "fields at this time."))
  744. return DynamicMetaObject(
  745. EnsureObjectResult(
  746. Exprs.Expression.Assign(
  747. Exprs.Expression.MakeMemberAccess(
  748. Exprs.Expression.Convert(
  749. targetMO.Expression,
  750. members[0].DeclaringType),
  751. members[0]),
  752. valueMO.Expression)),
  753. ## Don't need restriction test for name since this
  754. ## rule is only used where binder is used, which is
  755. ## only used in sites with this binder.Name.
  756. BindingRestrictions.GetTypeRestriction(
  757. targetMO.Expression, targetMO.LimitType))
  758. else:
  759. if errorSuggestionMO is not None:
  760. return errorSuggestionMO
  761. return CreateThrow(
  762. targetMO, None,
  763. BindingRestrictions.GetTypeRestriction(
  764. targetMO.Expression, targetMO.LimitType),
  765. MissingMemberException,
  766. "IDynObj member name conflict.")
  767. ### SymplInvokeMemberBinder is used for general dotted expressions in function
  768. ### calls for invoking members.
  769. ###
  770. class SymplInvokeMemberBinder (InvokeMemberBinder):
  771. def __new__ (cls, name, callinfo):
  772. return InvokeMemberBinder.__new__(cls, name, True, callinfo)
  773. def FallbackInvokeMember (self, targetMO, argMOs, errorSuggestionMO):
  774. ## Defer if any object has no value so that we evaulate their
  775. ## Expressions and nest a CallSite for the InvokeMember.
  776. if not targetMO.HasValue or not all(map(lambda x: x.HasValue, argMOs)):
  777. return self.Defer((targetMO,) + tuple(argMOs))
  778. ## Try COM object first.
  779. isCom, com = ComBinder.TryBindInvokeMember(self, targetMO, argMOs)
  780. if isCom:
  781. return com
  782. ## Find our own binding.
  783. flags = (refl.BindingFlags.IgnoreCase | refl.BindingFlags.Instance |
  784. refl.BindingFlags.Public)
  785. members = targetMO.LimitType.GetMember(self.Name, flags)
  786. if (len(members) == 1 and
  787. (isinstance(members[0], refl.PropertyInfo) or
  788. isinstance(members[0], refl.FieldInfo))):
  789. raise Exception("Haven't implemented invoking delegate values " +
  790. "from properties or fields.")
  791. ## NOT TESTED, should check type for isinstance delegate
  792. #return DynamicMetaObject(
  793. # Exprs.Expression.Dynamic(
  794. # SymplInvokeBinder(CallInfo(len(args))),
  795. # object,
  796. # ([Exprs.MakeMemberAccess(self.Expression, mem)] +
  797. # (x.Expression for x in args))))
  798. ## Don't test for eventinfos since we do nothing with them now.
  799. else:
  800. ## Get MethodInfos with right arg count.
  801. debugprint("tmmo bind invoke mem ... searching ...", len(members))
  802. mi_mems = [x for x in members if isinstance(x, refl.MethodInfo) and
  803. len(x.GetParameters()) == len(argMOs)]
  804. debugprint("methodinfo members with same arg count: ", len(mi_mems))
  805. debugprint(mi_mems)
  806. res = []
  807. for mem in mi_mems:
  808. if ParamsMatchArgs(mem.GetParameters(), argMOs):
  809. res.append(mem)
  810. ## False below means generate a type restriction on the MO.
  811. ## We are looking at the members targetMO's Type.
  812. restrictions = GetTargetArgsRestrictions(targetMO, argMOs, False)
  813. ## See if we have a result and return an error MO.
  814. if len(res) == 0:
  815. return (errorSuggestionMO or
  816. CreateThrow(
  817. targetMO, argMOs, restrictions,
  818. MissingMemberException,
  819. "Cannot bind member invoke -- " + repr(argMOs)))
  820. ## restrictions and conversion must be done consistently.
  821. callArgs = ConvertArguments(argMOs, res[0].GetParameters())
  822. return DynamicMetaObject(
  823. EnsureObjectResult(
  824. Exprs.Expression.Call(
  825. Exprs.Expression.Convert(targetMO.Expression,
  826. targetMO.LimitType),
  827. res[0], callArgs)),
  828. restrictions)
  829. def FallbackInvoke (self, targetMO, argMOs, errorSuggestionMO):
  830. ## Just "defer" since we have code in SymplInvokeBinder that knows
  831. ## what to do, and typically this fallback is from a language like Python
  832. ## that passes a DynamicMetaObject with HasValue == false.
  833. return DynamicMetaObject(
  834. Exprs.Expression.Dynamic(
  835. ## This call site doesn't share any L2 caching
  836. ## since we don't call GetInvokeBinder from Sympl.
  837. ## We aren't plumbed to get the runtime instance here.
  838. SymplInvokeBinder(CallInfo(len(argMOs))),
  839. object, #ret type
  840. [targetMO.Expression] +
  841. [x.Expression for x in argMOs]),
  842. ## No new restrictions since SymplInvokeBinder will handle it.
  843. targetMO.Restrictions.Merge(
  844. BindingRestrictions.Combine(argMOs)))
  845. ## This class is needed to canonicalize InvokeMemberBinders in Sympl. See
  846. ## the comment above the GetXXXBinder methods at the end of the Sympl class.
  847. ##
  848. class InvokeMemberBinderKey (object):
  849. def __init__ (self, name, info):
  850. self._name = name
  851. self._info = info
  852. def _getName (self): return self._name
  853. Name = property(_getName)
  854. def _getInfo (self): return self._info
  855. Info = property(_getInfo)
  856. def __eq__ (self, obj): #def Equals (self, obj):
  857. return ((obj is not None) and (obj.Name == self._name) and
  858. obj.Info.Equals(self._info))
  859. def __hash__ (self): #def GetHashCode (self):
  860. return 0x28000000 ^ self._name.GetHashCode() ^ self._info.GetHashCode()
  861. ### Used for calling runtime helpers, delegate values, and callable IDO (which
  862. ### really get handled by their MOs.
  863. ###
  864. class SymplInvokeBinder (InvokeBinder):
  865. def FallbackInvoke (self, targetMO, argMOs, errorSuggestionMO):
  866. debugprint("symplinvokebinder fallback...", targetMO.Expression, "...",
  867. [x.Expression for x in argMOs])
  868. ## Defer if any object has no value so that we evaulate their
  869. ## Expressions and nest a CallSite for the InvokeMember.
  870. if not targetMO.HasValue or not all(map(lambda x: x.HasValue, argMOs)):
  871. return self.Defer((targetMO,) + tuple(argMOs))
  872. ## Try COM object first.
  873. isCom, com = ComBinder.TryBindInvoke(self, targetMO, argMOs)
  874. if isCom:
  875. return com
  876. ## Find our own binding.
  877. if targetMO.LimitType.IsSubclassOf(Delegate):
  878. params = targetMO.LimitType.GetMethod("Invoke").GetParameters()
  879. if len(params) == len(argMOs):
  880. debugprint("returning rule")
  881. debugprint(" ... ", targetMO.LimitType, "...", targetMO.Expression.Type,
  882. "...", targetMO.Value)
  883. ## Don't need to check if argument types match parameters.
  884. ## If they don't, users get an argument conversion error.
  885. expression = Exprs.Expression.Invoke(
  886. Exprs.Expression.Convert(targetMO.Expression,
  887. targetMO.LimitType),
  888. ConvertArguments(argMOs, params))
  889. return DynamicMetaObject(
  890. EnsureObjectResult(expression),
  891. BindingRestrictions.GetTypeRestriction(
  892. targetMO.Expression, targetMO.LimitType))
  893. return (errorSuggestionMO or
  894. CreateThrow(
  895. targetMO, argMOs,
  896. BindingRestrictions.GetTypeRestriction(
  897. targetMO.Expression, targetMO.LimitType),
  898. InvalidOperationException,
  899. "Wrong number of arguments for function -- " +
  900. str(targetMO.LimitType) + " got " + argMOs))
  901. ### Used to instantiate types or IDOs that can be instantiated (though their MOs
  902. ### really do the work.
  903. ###
  904. class SymplCreateInstanceBinder (CreateInstanceBinder):
  905. def __new__ (cls, callinfo):
  906. return CreateInstanceBinder.__new__(cls, callinfo)
  907. def FallbackCreateInstance (self, targetMO, argMOs, errorSuggestionMO):
  908. ## Defer if any object has no value so that we evaulate their
  909. ## Expressions and nest a CallSite for the CreateInstance.
  910. if not targetMO.HasValue or not all(map(lambda x: x.HasValue, argMOs)):
  911. return self.Defer((targetMO,) + tuple(argMOs))
  912. ## Make sure target actually contains a Type.
  913. if not (Type.IsAssignableFrom(Type, targetMO.LimitType)):
  914. return (errorSuggestionMO or
  915. CreateThrow(
  916. targetMO, argMOs, BindingRestrictions.Empty,
  917. InvalidOperationException,
  918. ("Type object must be used when creating instance -- " +
  919. repr(targetMO))))
  920. ## Get constructors with right arg count.
  921. ctors = [x for x in targetMO.Value.GetConstructors()
  922. if len(x.GetParameters()) == len(argMOs)]
  923. ## Get ctors with param types that work for args. This works
  924. ## for except for value args that need to pass to reftype params.
  925. ## We could detect that to be smarter and then explicitly StrongBox
  926. ## the args.
  927. res = []
  928. for mem in ctors:
  929. if ParamsMatchArgs(mem.GetParameters(), argMOs):
  930. res.append(mem)
  931. ## True means generate an instance restriction on the MO.
  932. ## We are only looking at the members defined in this Type instance.
  933. restrictions = GetTargetArgsRestrictions(targetMO, argMOs, True)
  934. if len(res) == 0:
  935. return (errorSuggestionMO or
  936. CreateThrow(
  937. targetMO, argMOs, restrictions,
  938. MissingMemberException,
  939. "Can't bind create instance -- " + repr(targetMO)))
  940. ## restrictions and conversion must be done consistently.
  941. callArgs = ConvertArguments(argMOs, res[0].GetParameters())
  942. return DynamicMetaObject(
  943. ## Creating an object, so don't need EnsureObjectResult.
  944. Exprs.Expression.New(res[0], callArgs),
  945. restrictions)
  946. class SymplGetIndexBinder (GetIndexBinder):
  947. #def __new__ (cls, callinfo):
  948. # return GetIndexBinder.__new__(cls, callinfo)
  949. def FallbackGetIndex (self, targetMO, argMOs, errorSuggestionMO):
  950. ## Defer if any object has no value so that we evaulate their
  951. ## Expressions and nest a CallSite for the InvokeMember.
  952. if not targetMO.HasValue or not all(map(lambda x: x.HasValue, argMOs)):
  953. return self.Defer((targetMO,) + tuple(argMOs))
  954. ## Try COM object first.
  955. isCom, com = ComBinder.TryBindGetIndex(self, targetMO, argMOs)
  956. if isCom:
  957. return com
  958. ## Give a good error for Cons.
  959. if type(targetMO.Value) is Cons:
  960. if len(argMOs) != 1:
  961. return (errorSuggestionMO or
  962. CreateThrow(
  963. targetMO, argMOs, BindingRestrictions.Empty,
  964. InvalidOperationException,
  965. "Indexing Sympl list requires exactly one argument."))
  966. ## Find our own binding.
  967. ##
  968. ## Conversions created in GetIndexExpression must be consistent with
  969. ## restrictions made in GetTargetArgsRestrictions.
  970. return DynamicMetaObject(
  971. EnsureObjectResult(GetIndexExpression(targetMO, argMOs)),
  972. ## False means make type restriction on targetMO.LimitType
  973. GetTargetArgsRestrictions(targetMO, argMOs, False))
  974. class SymplSetIndexBinder (SetIndexBinder):
  975. #def __new__ (cls, callinfo):
  976. # return SetIndexBinder.__new__(cls, callinfo)
  977. def FallbackSetIndex (self, targetMO, argMOs, valueMO, errorSuggestionMO):
  978. ## Defer if any object has no value so that we evaulate their
  979. ## Expressions and nest a CallSite for the SetIndex.
  980. if (not targetMO.HasValue or not a

Large files files are truncated, but you can click here to view the full file