PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/Backend/Runtime/UserType.cs

https://bitbucket.org/AdamMil/boaold
C# | 262 lines | 201 code | 52 blank | 9 comment | 48 complexity | 24b37f5bc631e30cf218a01b022e6e9c MD5 | raw file
Possible License(s): GPL-2.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Specialized;
  4. using Boa.AST;
  5. namespace Boa.Runtime
  6. {
  7. // FIXME: make these wrappers expose the attributes of the underlying functions
  8. // TODO: create a base class for these wrappers
  9. // FIXME: this doesn't work properly for derived classes (or does it?)
  10. #region FunctionWrapper
  11. public abstract class FunctionWrapper : IHasAttributes
  12. { public FunctionWrapper(IFancyCallable func) { this.func = func; }
  13. protected internal IFancyCallable func;
  14. public List __attrs__() { return Ops.GetAttrNames(func); }
  15. public object __getattr__(string key) { return key=="__call__" ? this : Ops.GetAttr(func, key); }
  16. public void __setattr__(string key, object value) { Ops.SetAttr(value, func, key); }
  17. public void __delattr__(string key) { Ops.DelAttr(func, key); }
  18. }
  19. #endregion
  20. #region ClassWrapper
  21. public sealed class ClassWrapper : FunctionWrapper, IDescriptor, IFancyCallable
  22. { public ClassWrapper(IFancyCallable func, BoaType type) : base(func) { this.type=type; }
  23. public object __get__(object instance)
  24. { return instance==null ? this : new ClassWrapper(func, ((IInstance)instance).__class__);
  25. }
  26. public object Call(object[] positional, string[] names, object[] values)
  27. { object[] npos = new object[positional.Length+1];
  28. npos[0] = type;
  29. if(positional.Length>0) Array.Copy(positional, 0, npos, 1, positional.Length);
  30. return func.Call(npos, names, values);
  31. }
  32. object Boa.Runtime.ICallable.Call(params object[] args)
  33. { object[] nargs = new object[args.Length+1];
  34. nargs[0] = type;
  35. if(args.Length>0) Array.Copy(args, 0, nargs, 1, args.Length);
  36. return func.Call(nargs);
  37. }
  38. // FIXME: fix this
  39. public override string ToString()
  40. { return string.Format("<classmethod '{0}' on '{1}'>", /*func.Name*/"", type.__name__);
  41. }
  42. BoaType type;
  43. }
  44. #endregion
  45. #region MethodWrapper
  46. public sealed class MethodWrapper : FunctionWrapper, IDescriptor, IFancyCallable
  47. { public MethodWrapper(IFancyCallable func) : base(func) { }
  48. public MethodWrapper(IFancyCallable func, object instance) : base(func) { this.instance=instance; }
  49. public object __get__(object instance) { return instance==null ? this : new MethodWrapper(func, instance); }
  50. public object Call(object[] positional, string[] names, object[] values)
  51. { object[] npos = new object[positional.Length+1];
  52. npos[0] = instance;
  53. if(positional.Length>0) Array.Copy(positional, 0, npos, 1, positional.Length);
  54. return func.Call(npos, names, values);
  55. }
  56. object Boa.Runtime.ICallable.Call(params object[] args)
  57. { object[] nargs = new object[args.Length+1];
  58. nargs[0] = instance;
  59. if(args.Length>0) Array.Copy(args, 0, nargs, 1, args.Length);
  60. return func.Call(nargs);
  61. }
  62. // FIXME: fix this
  63. public override string ToString()
  64. { return "<method>";
  65. //return string.Format("<method '{0}'>", func.Name);
  66. }
  67. object instance;
  68. }
  69. #endregion
  70. #region UserType
  71. public class UserType : BoaType
  72. { public UserType(string module, string name, Tuple bases, IDictionary dict)
  73. : base(TypeMaker.MakeType(module, name, bases.items, dict))
  74. { Initialize();
  75. __name__ = name;
  76. __module__ = module;
  77. this.bases = bases;
  78. foreach(DictionaryEntry e in dict)
  79. { Function func = e.Value as Function;
  80. this.dict[e.Key] = func!=null && func.Type==FunctionType.Class ? new ClassWrapper(func, this) : e.Value;
  81. }
  82. List[] mros = new List[bases.Count+1];
  83. mros[0] = new List(bases.items);
  84. for(int i=0; i<bases.Count; i++) mros[i+1] = new List(((BoaType)bases.items[i]).mro);
  85. List mrolist = new List();
  86. mrolist.Add(this);
  87. bool done=false;
  88. do mrolist.Add(MergeMRO(mros, ref done)); while(!done);
  89. mro = new Tuple(mrolist);
  90. }
  91. public Tuple __bases__ { get { return bases; } }
  92. public override object Call(params object[] args)
  93. { object dummy;
  94. // TODO: implement __new__
  95. //if(!Ops.TryInvoke(this, "__new__", out obj, nargs)) obj = cons.Call(args);
  96. // TODO: choose a more appropriate constructor if we've derived from .NET classes that have constructors w/ params
  97. IInstance obj = (IInstance)type.GetConstructor(Type.EmptyTypes).Invoke(null);
  98. obj.__class__ = this;
  99. if(obj!=null) Ops.TryInvoke(obj, "__init__", out dummy, args);
  100. return obj;
  101. }
  102. public override void DelAttr(Tuple mro, int index, object self, string name)
  103. { IInstance ui = (IInstance)self;
  104. if(ui!=null)
  105. { int count = ui.__dict__.Count; // i assume it's more efficient to check .Count twice than to call Contains()
  106. ui.__dict__.Remove(name); // (to see if the item was actually removed)
  107. if(ui.__dict__.Count!=count) return;
  108. }
  109. object slot = LookupSlot(mro, index, name);
  110. if(slot!=Ops.Missing) Ops.DelDescriptor(slot, self);
  111. else throw Ops.AttributeError("no such slot '{0}'", name);
  112. }
  113. public override void DelAttr(object self, string name) { DelAttr(mro, 0, self, name); }
  114. public override object GetAttr(Tuple mro, int index, object self, string name)
  115. { object value;
  116. if(!GetAttr(mro, index, self, name, out value)) throw Ops.AttributeError("no such slot '{0}'", name);
  117. return value;
  118. }
  119. public bool GetAttr(Tuple mro, int index, object self, string name, out object value)
  120. { object slot = LookupSlot(mro, index, name);
  121. if(slot!=Ops.Missing)
  122. { Function func = slot as Function;
  123. if(func!=null && (func.Type==FunctionType.Unmarked || func.Type==FunctionType.Method))
  124. value = new MethodWrapper(func, self);
  125. else value = Ops.GetDescriptor(slot, self);
  126. return true;
  127. }
  128. value = null;
  129. return false;
  130. }
  131. public override bool GetAttr(object self, string name, out object value)
  132. { IInstance ui = (IInstance)self;
  133. if(self!=null)
  134. { if(name=="__dict__")
  135. { value = ui.__dict__;
  136. return true;
  137. }
  138. if(name=="__class__")
  139. { value = ui.__class__;
  140. return true;
  141. }
  142. object obj = ui.__dict__[name];
  143. if(obj!=null || ui.__dict__.Contains(name))
  144. { value = Ops.GetDescriptor(obj, self);
  145. return true;
  146. }
  147. }
  148. return GetAttr(mro, 0, self, name, out value);
  149. }
  150. public override List GetAttrNames(object self)
  151. { Dict keys = new Dict();
  152. if(self!=null)
  153. { IInstance ui = (IInstance)self;
  154. foreach(object key in ui.__dict__.Keys) keys[key] = null;
  155. }
  156. return __attrs__(keys);
  157. }
  158. public override DynamicType GetDynamicType() { return ReflectedType.FromType(typeof(UserType)); } // TODO: cache somewhere?
  159. public override bool IsSubclassOf(object other)
  160. { ReflectedType ort = other as ReflectedType;
  161. for(int i=0; i<mro.items.Length; i++) if(mro.items[i]==other) return true;
  162. if(ort!=null)
  163. for(int i=0; i<mro.items.Length; i++)
  164. { ReflectedType rt = mro.items[i] as ReflectedType;
  165. if(rt!=null && (rt==ort || rt.IsSubclassOf(ort))) return true;
  166. }
  167. return false;
  168. }
  169. public override void SetAttr(Tuple mro, int index, object self, string name, object value)
  170. { object slot = LookupSlot(mro, index, name);
  171. if(slot!=Ops.Missing && (self==null || slot is ReflectedMember) && Ops.SetDescriptor(slot, null, value)) return;
  172. else if(self!=null) ((IInstance)self).__dict__[name] = value;
  173. else throw Ops.AttributeError("no such slot '{0}'", name);
  174. }
  175. public override void SetAttr(object self, string name, object value) { SetAttr(mro, 0, self, name, value); }
  176. public override string ToString() { return string.Format("<class '{0}.{1}'>", __module__, __name__); }
  177. public override List __attrs__() { return __attrs__(new Dict()); }
  178. public object __module__;
  179. List __attrs__(Dict keys)
  180. { foreach(BoaType type in mro)
  181. { UserType ut = type as UserType;
  182. if(ut!=null) foreach(object key in ut.dict.Keys) keys[key] = null;
  183. else foreach(object key in type.GetAttrNames(this)) keys[key] = null;
  184. }
  185. List ret = keys.keys();
  186. ret.sort();
  187. return ret;
  188. }
  189. static object MergeMRO(List[] lists, ref bool done)
  190. { for(int li=0; li<lists.Length; li++)
  191. { if(lists[li].Count==0) continue;
  192. object bo = lists[li][0];
  193. for(int oi=li+1; oi<lists.Length; oi++)
  194. { if(lists[oi].Count>1 && lists[oi].__getitem__(-1)==bo) goto badhead;
  195. }
  196. done = true;
  197. for(int oi=0; oi<lists.Length; oi++)
  198. { List l = lists[oi];
  199. for(int i=0; i<l.Count; i++) if(l[i]==bo) { l.RemoveAt(i); break; }
  200. if(l.Count>0) done = false;
  201. }
  202. return bo;
  203. badhead:;
  204. }
  205. throw Ops.TypeError("MRO conflict");
  206. }
  207. Tuple bases;
  208. }
  209. #endregion
  210. } // namespace Boa.Runtime