PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/Backend/Runtime/Ops.cs

https://bitbucket.org/AdamMil/boaold
C# | 1392 lines | 1227 code | 129 blank | 36 comment | 233 complexity | 64c55c876078e2092712d40776b95970 MD5 | raw file
Possible License(s): GPL-2.0

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

  1. /*
  2. Boa is the reference implementation for a language similar to Python,
  3. also called Boa. This implementation is both interpreted and compiled,
  4. targeting the Microsoft .NET Framework.
  5. http://www.adammil.net/
  6. Copyright (C) 2004-2005 Adam Milazzo
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. using System;
  20. using System.Collections;
  21. using System.Globalization;
  22. // TODO: make sure all static methods everywhere are thread-safe
  23. // TODO: investigate python's changes to the division operator
  24. // TODO: should we allow integer operations on chars?
  25. // TODO: implement all of http://docs.python.org/ref/specialnames.html
  26. // TODO: double check all mathematical operations
  27. // TODO: support floats in all integer operations as long as they are whole numbers
  28. // TODO: implement a warning system
  29. namespace Boa.Runtime
  30. {
  31. [Flags] public enum Conversion
  32. { Unsafe=1, Safe=3, Reference=5, Identity=7, None=8, Overflow=10,
  33. Failure=8, Success=1
  34. }
  35. // TODO: make use of #regions in here to group things together
  36. public sealed class Ops
  37. { Ops() { }
  38. public static readonly object Missing = "<Missing>";
  39. public static readonly object NotImplemented = "<NotImplemented>";
  40. public static readonly DefaultBoaComparer DefaultComparer = new DefaultBoaComparer();
  41. public class DefaultBoaComparer : IComparer
  42. { public int Compare(object x, object y) { return Ops.Compare(x, y); }
  43. }
  44. public static AssertionErrorException AssertionError(Boa.AST.Node node, string format, params object[] args)
  45. { return new AssertionErrorException(Source(node)+string.Format(format, args));
  46. }
  47. public static AttributeErrorException AttributeError(string format, params object[] args)
  48. { return new AttributeErrorException(string.Format(format, args));
  49. }
  50. public static object Add(object a, object b)
  51. { switch(Convert.GetTypeCode(a))
  52. { case TypeCode.Boolean: return IntOps.Add((bool)a ? 1 : 0, b);
  53. case TypeCode.Byte: return IntOps.Add((int)(byte)a, b);
  54. case TypeCode.Char:
  55. if(b is string) return (char)a+(string)b;
  56. break;
  57. case TypeCode.Decimal:
  58. if(b is Decimal) return (Decimal)a + (Decimal)b;
  59. try { return (Decimal)a + Convert.ToDecimal(b); }
  60. catch { break; }
  61. case TypeCode.Double: return FloatOps.Add((double)a, b);
  62. case TypeCode.Int16: return IntOps.Add((int)(short)a, b);
  63. case TypeCode.Int32: return IntOps.Add((int)a, b);
  64. case TypeCode.Int64: return LongOps.Add((long)a, b);
  65. case TypeCode.Object:
  66. { if(a is Integer) return IntegerOps.Add((Integer)a, b);
  67. if(a is Complex) return ComplexOps.Add((Complex)a, b);
  68. if(a is ICollection || a is ISequence) return ArrayOps.Concat(a, b);
  69. object ret;
  70. return TryInvoke(a, "__add__", out ret, b) ? ret : Invoke(b, "__radd__", a);
  71. }
  72. case TypeCode.SByte: return IntOps.Add((int)(sbyte)a, b);
  73. case TypeCode.Single: return FloatOps.Add((float)a, b);
  74. case TypeCode.String:
  75. if(b is string) return (string)a + (string)b;
  76. if(b is char) return (string)a + (char)b;
  77. break;
  78. case TypeCode.UInt16: return IntOps.Add((int)(short)a, b);
  79. case TypeCode.UInt32:
  80. { uint v = (uint)a;
  81. return v<=int.MaxValue ? IntOps.Add((int)v, b) : LongOps.Add((long)v, b);
  82. }
  83. case TypeCode.UInt64:
  84. { ulong v = (ulong)a;
  85. return v<=long.MaxValue ? LongOps.Add((long)v, b) : IntegerOps.Add(new Integer(v), b);
  86. }
  87. }
  88. throw TypeError("unsupported operand types for +: '{0}' and '{1}'", TypeName(a), TypeName(b));
  89. }
  90. public static object BitwiseAnd(object a, object b)
  91. { switch(Convert.GetTypeCode(a))
  92. { case TypeCode.Boolean:
  93. if(b is bool) return FromBool((bool)a && (bool)b);
  94. return IntOps.BitwiseAnd((bool)a ? 1 : 0, b);
  95. case TypeCode.Byte: return IntOps.BitwiseAnd((int)(byte)a, b);
  96. case TypeCode.Int16: return IntOps.BitwiseAnd((int)(short)a, b);
  97. case TypeCode.Int32: return IntOps.BitwiseAnd((int)a, b);
  98. case TypeCode.Int64: return LongOps.BitwiseAnd((long)a, b);
  99. case TypeCode.Object:
  100. { if(a is Integer) return IntegerOps.BitwiseAnd((Integer)a, b);
  101. object ret;
  102. return TryInvoke(a, "__and__", out ret, b) ? ret : Invoke(b, "__rand__", a);
  103. }
  104. case TypeCode.SByte: return IntOps.BitwiseAnd((int)(sbyte)a, b);
  105. case TypeCode.UInt16: return IntOps.BitwiseAnd((int)(short)a, b);
  106. case TypeCode.UInt32:
  107. { uint v = (uint)a;
  108. return v<=int.MaxValue ? IntOps.BitwiseAnd((int)v, b) : LongOps.BitwiseAnd((long)v, b);
  109. }
  110. case TypeCode.UInt64:
  111. { ulong v = (ulong)a;
  112. return v<=long.MaxValue ? LongOps.BitwiseAnd((long)v, b) : IntegerOps.BitwiseAnd(new Integer(v), b);
  113. }
  114. }
  115. throw TypeError("unsupported operand types for &: '{0}' and '{1}'", TypeName(a), TypeName(b));
  116. }
  117. public static object BitwiseOr(object a, object b)
  118. { switch(Convert.GetTypeCode(a))
  119. { case TypeCode.Boolean:
  120. if(b is bool) return FromBool((bool)a || (bool)b);
  121. return IntOps.BitwiseOr((bool)a ? 1 : 0, b);
  122. case TypeCode.Byte: return IntOps.BitwiseOr((int)(byte)a, b);
  123. case TypeCode.Int16: return IntOps.BitwiseOr((int)(short)a, b);
  124. case TypeCode.Int32: return IntOps.BitwiseOr((int)a, b);
  125. case TypeCode.Int64: return LongOps.BitwiseOr((long)a, b);
  126. case TypeCode.Object:
  127. { if(a is Integer) return IntegerOps.BitwiseOr((Integer)a, b);
  128. object ret;
  129. return TryInvoke(a, "__or___", out ret, b) ? ret : Invoke(b, "__ror___", a);
  130. }
  131. case TypeCode.SByte: return IntOps.BitwiseOr((int)(sbyte)a, b);
  132. case TypeCode.UInt16: return IntOps.BitwiseOr((int)(short)a, b);
  133. case TypeCode.UInt32:
  134. { uint v = (uint)a;
  135. return v<=int.MaxValue ? IntOps.BitwiseOr((int)v, b) : LongOps.BitwiseOr((long)v, b);
  136. }
  137. case TypeCode.UInt64:
  138. { ulong v = (ulong)a;
  139. return v<=long.MaxValue ? LongOps.BitwiseOr((long)v, b) : IntegerOps.BitwiseOr(new Integer(v), b);
  140. }
  141. }
  142. throw TypeError("unsupported operand types for |: '{0}' and '{1}'", TypeName(a), TypeName(b));
  143. }
  144. public static object BitwiseXor(object a, object b)
  145. { switch(Convert.GetTypeCode(a))
  146. { case TypeCode.Boolean:
  147. if(b is bool) return FromBool((bool)a != (bool)b);
  148. return IntOps.BitwiseXor((bool)a ? 1 : 0, b);
  149. case TypeCode.Byte: return IntOps.BitwiseXor((int)(byte)a, b);
  150. case TypeCode.Int16: return IntOps.BitwiseXor((int)(short)a, b);
  151. case TypeCode.Int32: return IntOps.BitwiseXor((int)a, b);
  152. case TypeCode.Int64: return LongOps.BitwiseXor((long)a, b);
  153. case TypeCode.Object:
  154. { if(a is Integer) return IntegerOps.BitwiseXor((Integer)a, b);
  155. object ret;
  156. return TryInvoke(a, "__xor__", out ret, b) ? ret : Invoke(b, "__rxor__", a);
  157. }
  158. case TypeCode.SByte: return IntOps.BitwiseXor((int)(sbyte)a, b);
  159. case TypeCode.UInt16: return IntOps.BitwiseXor((int)(short)a, b);
  160. case TypeCode.UInt32:
  161. { uint v = (uint)a;
  162. return v<=int.MaxValue ? IntOps.BitwiseXor((int)v, b) : LongOps.BitwiseXor((long)v, b);
  163. }
  164. case TypeCode.UInt64:
  165. { ulong v = (ulong)a;
  166. return v<=long.MaxValue ? LongOps.BitwiseXor((long)v, b) : IntegerOps.BitwiseXor(new Integer(v), b);
  167. }
  168. }
  169. throw TypeError("unsupported operand types for ^: '{0}' and '{1}'", TypeName(a), TypeName(b));
  170. }
  171. public static object BitwiseNegate(object a)
  172. { switch(Convert.GetTypeCode(a))
  173. { case TypeCode.Boolean: return (bool)a ? -2 : -1;
  174. case TypeCode.Byte: return ~(int)(byte)a;
  175. case TypeCode.Int16: return ~(int)(short)a;
  176. case TypeCode.Int32: return ~(int)a;
  177. case TypeCode.Int64: return ~(long)a;
  178. case TypeCode.Object: return a is Integer ? ~(Integer)a : Invoke(a, "__invert__");
  179. case TypeCode.SByte: return ~(int)(sbyte)a;
  180. case TypeCode.UInt16: return ~(int)(short)a;
  181. case TypeCode.UInt32:
  182. { uint v = (uint)a;
  183. return v<=int.MaxValue ? (object)~(int)v : (object)~(long)v;
  184. }
  185. case TypeCode.UInt64:
  186. { ulong v = (ulong)a;
  187. return v<=long.MaxValue ? (object)(~(long)v) : (object)(~new Integer(v));
  188. }
  189. }
  190. throw TypeError("unsupported operand type for ~: '{0}'", TypeName(a));
  191. }
  192. public static object Call(object func, params object[] args)
  193. { ICallable ic = func as ICallable;
  194. return ic==null ? Invoke(func, "__call__", args) : ic.Call(args);
  195. }
  196. public unsafe static object Call(object func, CallArg[] args)
  197. { int ai=0, pi=0, num=0;
  198. bool hasdict=false;
  199. for(; ai<args.Length; ai++)
  200. if(args[ai].Type==null) num++;
  201. else if(args[ai].Type==CallArg.ListType)
  202. { ICollection col = args[ai].Value as ICollection;
  203. if(col!=null) num += col.Count;
  204. else
  205. { ISequence seq = args[ai].Value as ISequence;
  206. num += seq==null ? Ops.ToInt(Ops.Invoke(args[ai].Value, "__len__")) : seq.__len__();
  207. }
  208. }
  209. else if(args[ai].Type is int) num += (int)args[ai].Type;
  210. else break;
  211. object[] positional = num==0 ? null : new object[num];
  212. for(int i=0; i<ai; i++)
  213. if(args[i].Type==null) positional[pi++] = args[i].Value;
  214. else if(args[i].Type==CallArg.ListType)
  215. { ICollection col = args[i].Value as ICollection;
  216. if(col!=null) { col.CopyTo(positional, pi); pi += col.Count; }
  217. else
  218. { IEnumerator e = Ops.GetEnumerator(args[i].Value);
  219. while(e.MoveNext()) positional[pi++] = e.Current;
  220. }
  221. }
  222. else if(args[i].Type is int)
  223. { object[] items = (object[])args[i].Value;
  224. items.CopyTo(positional, pi); pi += items.Length;
  225. }
  226. if(ai==args.Length) return Call(func, positional);
  227. num = 0;
  228. for(int i=ai; i<args.Length; i++)
  229. if(args[i].Type==CallArg.DictType)
  230. { IDictionary dict = args[i].Value as IDictionary;
  231. if(dict!=null) num += dict.Count;
  232. else
  233. { IMapping map = args[i].Value as IMapping;
  234. num += map==null ? Ops.ToInt(Ops.Invoke(args[i].Value, "__len__")) : map.__len__();
  235. }
  236. hasdict = true;
  237. }
  238. else num += ((object[])args[i].Type).Length;
  239. if(!hasdict) return Call(func, positional, (string[])args[ai].Value, (object[])args[ai].Type);
  240. string[] names = new string[num];
  241. object[] values = new object[num];
  242. pi = 0;
  243. for(; ai<args.Length; ai++)
  244. if(args[ai].Type!=CallArg.DictType)
  245. { string[] na = (string[])args[ai].Value;
  246. na.CopyTo(names, pi);
  247. ((object[])args[ai].Type).CopyTo(values, pi);
  248. pi += na.Length;
  249. }
  250. else
  251. { IDictionary dict = args[ai].Value as IDictionary;
  252. if(dict!=null)
  253. foreach(DictionaryEntry e in dict)
  254. { names[pi] = Ops.Str(e.Key);
  255. values[pi] = e.Value;
  256. pi++;
  257. }
  258. else
  259. { IMapping map = args[ai].Value as IMapping;
  260. if(map!=null)
  261. { IEnumerator e = map.iteritems();
  262. while(e.MoveNext())
  263. { Tuple tup = (Tuple)e.Current;
  264. names[pi] = Ops.Str(tup.items[0]);
  265. values[pi] = tup.items[1];
  266. pi++;
  267. }
  268. }
  269. else
  270. { object eo = Ops.Invoke(args[ai].Value, "itemiter");
  271. if(eo is IEnumerator)
  272. { IEnumerator e = (IEnumerator)eo;
  273. while(e.MoveNext())
  274. { Tuple tup = e.Current as Tuple;
  275. if(tup==null || tup.items.Length!=2)
  276. throw TypeError("dict expansion: itemiter()'s iterator should return (key,value)");
  277. names[pi] = Ops.Str(tup.items[0]);
  278. values[pi] = tup.items[1];
  279. pi++;
  280. }
  281. }
  282. else
  283. { object next = Ops.GetAttr(eo, "next");
  284. try
  285. { while(true)
  286. { Tuple tup = Ops.Call(next) as Tuple;
  287. if(tup==null || tup.items.Length!=2)
  288. throw TypeError("dict expansion: itemiter()'s iterator should return (key,value)");
  289. names[pi] = Ops.Str(tup.items[0]);
  290. values[pi] = tup.items[1];
  291. pi++;
  292. }
  293. }
  294. catch(StopIterationException) { }
  295. }
  296. }
  297. }
  298. }
  299. return Call(func, positional, names, values);
  300. }
  301. public static object Call(object func, object[] positional, string[] names, object[] values)
  302. { IFancyCallable ic = func as IFancyCallable;
  303. if(ic==null) throw Ops.NotImplementedError("This object does not support named arguments.");
  304. return ic.Call(positional, names, values);
  305. }
  306. public static object Call0(object func) { return Call(func, Misc.EmptyArray); }
  307. public static object Call1(object func, object a0) { return Call(func, a0); }
  308. public static object CallWithArgsSequence(object func, object seq)
  309. { object[] arr = seq as object[];
  310. if(arr!=null) return Call(func, arr);
  311. Tuple tup = seq as Tuple;
  312. if(tup!=null) return Call(func, tup.items);
  313. ICollection col = seq as ICollection;
  314. if(col!=null)
  315. { arr = new object[col.Count];
  316. col.CopyTo(arr, 0);
  317. return Call(func, arr);
  318. }
  319. List list = new List(Ops.GetEnumerator(seq));
  320. arr = new object[list.Count];
  321. list.CopyTo(arr, 0);
  322. return Call(func, arr);
  323. }
  324. public static int Compare(object a, object b)
  325. { if(a==b) return 0;
  326. switch(Convert.GetTypeCode(a))
  327. { case TypeCode.Boolean:
  328. if(b is bool) return (bool)a ? (bool)b ? 0 : 1 : (bool)b ? -1 : 0;
  329. return IntOps.Compare((bool)a ? 1 : 0, b);
  330. case TypeCode.Byte: return IntOps.Compare((int)(byte)a, b);
  331. case TypeCode.Char:
  332. { string sb = b as string;
  333. if(sb!=null)
  334. { if(sb.Length==0) return 1;
  335. int diff = (int)(char)a - (int)sb[0];
  336. return diff!=0 ? diff : sb.Length==1 ? 0 : -1;
  337. }
  338. else if(b is char) return (int)(char)a - (int)(char)b;
  339. else return "string".CompareTo(TypeName(b));
  340. }
  341. case TypeCode.Decimal:
  342. if(b is Decimal) return ((Decimal)a).CompareTo(b);
  343. try { return ((Decimal)a).CompareTo(Convert.ToDecimal(b)); }
  344. catch { break; }
  345. case TypeCode.Double: return FloatOps.Compare((double)a, b);
  346. case TypeCode.Empty: return b==null ? 0 : -1;
  347. case TypeCode.Int16: return IntOps.Compare((int)(short)a, b);
  348. case TypeCode.Int32: return IntOps.Compare((int)a, b);
  349. case TypeCode.Int64: return LongOps.Compare((long)a, b);
  350. case TypeCode.Object:
  351. if(a is Integer) return IntegerOps.Compare((Integer)a, b);
  352. if(a is Complex) return ComplexOps.Compare((Complex)a, b);
  353. if(a is ICollection || a is ISequence) return ArrayOps.Compare(a, b);
  354. object ret;
  355. return Ops.ToInt(TryInvoke(a, "__cmp__", out ret, b) ? ret : Invoke(b, "__cmp__", a));
  356. case TypeCode.SByte: return IntOps.Compare((int)(sbyte)a, b);
  357. case TypeCode.Single: return FloatOps.Compare((float)a, b);
  358. case TypeCode.String:
  359. { string sb = b as string;
  360. if(sb!=null) return ((string)a).CompareTo(sb);
  361. else if(b is char)
  362. { string sa = (string)a;
  363. if(sa.Length==0) return -1;
  364. int diff = (int)sa[0] - (int)(char)b;
  365. return diff!=0 ? diff : sa.Length==1 ? 0 : 1;
  366. }
  367. else return "string".CompareTo(TypeName(b));
  368. }
  369. case TypeCode.UInt16: return IntOps.Compare((int)(short)a, b);
  370. case TypeCode.UInt32:
  371. { uint v = (uint)a;
  372. return v<=int.MaxValue ? IntOps.Compare((int)v, b) : LongOps.Compare((long)v, b);
  373. }
  374. case TypeCode.UInt64:
  375. { ulong v = (ulong)a;
  376. return v<=long.MaxValue ? LongOps.Compare((long)v, b) : IntegerOps.Compare(new Integer(v), b);
  377. }
  378. }
  379. throw TypeError("can't compare '{0}' to '{1}'", TypeName(a), TypeName(b));
  380. }
  381. public static object ConvertTo(object o, Type type)
  382. { switch(ConvertTo(o==null ? null : o.GetType(), type))
  383. { case Conversion.Identity: case Conversion.Reference: return o;
  384. case Conversion.None: throw TypeError("object cannot be converted to '{0}'", type);
  385. default:
  386. if(type==typeof(bool)) return FromBool(IsTrue(o));
  387. if(type.IsSubclassOf(typeof(Delegate))) return MakeDelegate(o, type);
  388. try { return Convert.ChangeType(o, type); }
  389. catch(OverflowException) { throw ValueError("large value caused overflow"); }
  390. }
  391. }
  392. public static Conversion ConvertTo(Type from, Type to)
  393. { if(from==null)
  394. return !to.IsValueType ? Conversion.Reference : to==typeof(bool) ? Conversion.Safe : Conversion.None;
  395. else if(to==from) return Conversion.Identity;
  396. else if(to.IsAssignableFrom(from)) return Conversion.Reference;
  397. // TODO: check whether it's faster to use IndexOf() or our own loop
  398. // TODO: check whether it's possible to speed up this big block of checks up somehow
  399. // TODO: add support for Integer, Complex, and Decimal
  400. if(from.IsPrimitive && to.IsPrimitive)
  401. { if(from==typeof(int)) return IsIn(typeConv[4], to) ? Conversion.Safe : Conversion.Unsafe;
  402. if(to ==typeof(bool)) return IsIn(typeConv[9], from) ? Conversion.None : Conversion.Safe;
  403. if(from==typeof(double)) return Conversion.None;
  404. if(from==typeof(long)) return IsIn(typeConv[6], to) ? Conversion.Safe : Conversion.Unsafe;
  405. if(from==typeof(char)) return IsIn(typeConv[8], to) ? Conversion.Safe : Conversion.Unsafe;
  406. if(from==typeof(byte)) return IsIn(typeConv[1], to) ? Conversion.Safe : Conversion.Unsafe;
  407. if(from==typeof(uint)) return IsIn(typeConv[5], to) ? Conversion.Safe : Conversion.Unsafe;
  408. if(from==typeof(float)) return to==typeof(double) ? Conversion.Safe : Conversion.None;
  409. if(from==typeof(short)) return IsIn(typeConv[2], to) ? Conversion.Safe : Conversion.Unsafe;
  410. if(from==typeof(ushort)) return IsIn(typeConv[3], to) ? Conversion.Safe : Conversion.Unsafe;
  411. if(from==typeof(sbyte)) return IsIn(typeConv[0], to) ? Conversion.Safe : Conversion.Unsafe;
  412. if(from==typeof(ulong)) return IsIn(typeConv[7], to) ? Conversion.Safe : Conversion.Unsafe;
  413. }
  414. if(from.IsArray && to.IsArray && to.GetElementType().IsAssignableFrom(from.GetElementType()))
  415. return Conversion.Reference;
  416. if(to.IsSubclassOf(typeof(Delegate))) // we use None if both are delegates because we already checked above that it's not the right type of delegate
  417. return from.IsSubclassOf(typeof(Delegate)) ? Conversion.None : Conversion.Unsafe;
  418. return Conversion.None;
  419. }
  420. public static void DelAttr(object o, string name)
  421. { IHasAttributes iha = o as IHasAttributes;
  422. if(iha!=null) iha.__delattr__(name);
  423. else GetDynamicType(o).DelAttr(o, name);
  424. }
  425. public static bool DelDescriptor(object desc, object instance)
  426. { if(Convert.GetTypeCode(desc)!=TypeCode.Object) return false;
  427. IDataDescriptor dd = desc as IDataDescriptor;
  428. if(dd != null) { dd.__delete__(instance); return true; }
  429. object dummy;
  430. return TryInvoke(desc, "__delete__", out dummy, instance);
  431. }
  432. public static void DelIndex(object obj, object index)
  433. { IMutableSequence seq = obj as IMutableSequence;
  434. if(seq!=null)
  435. { Slice slice = index as Slice;
  436. if(slice!=null) seq.__delitem__(slice);
  437. else seq.__delitem__(Ops.ToInt(index));
  438. }
  439. else Ops.Invoke(obj, "__delitem__", index);
  440. }
  441. public static object Divide(object a, object b)
  442. { switch(Convert.GetTypeCode(a))
  443. { case TypeCode.Boolean: return (bool)a ? IntOps.Divide(1, b) : 0;
  444. case TypeCode.Byte: return IntOps.Divide((byte)a, b);
  445. case TypeCode.Decimal:
  446. if(b is Decimal) return (Decimal)a / (Decimal)b;
  447. try { return (Decimal)a / Convert.ToDecimal(b); }
  448. catch { goto default; }
  449. case TypeCode.Double: return FloatOps.Divide((double)a, b);
  450. case TypeCode.Int16: return IntOps.Divide((short)a, b);
  451. case TypeCode.Int32: return IntOps.Divide((int)a, b);
  452. case TypeCode.Int64: return LongOps.Divide((long)a, b);
  453. case TypeCode.Object:
  454. if(a is Integer) return IntegerOps.Divide((Integer)a, b);
  455. if(a is Complex) return ComplexOps.Divide((Complex)a, b);
  456. object ret;
  457. return TryInvoke(a, "__truediv__", out ret, b) ? ret :
  458. TryInvoke(b, "__rtruediv__", out ret, a) ? ret :
  459. TryInvoke(a, "__div__", out ret, b) ? ret : Invoke(b, "__rdiv__", a);
  460. case TypeCode.SByte: return IntOps.Divide((sbyte)a, b);
  461. case TypeCode.Single: return FloatOps.Divide((float)a, b);
  462. case TypeCode.UInt16: return IntOps.Divide((short)a, b);
  463. case TypeCode.UInt32: return LongOps.Divide((uint)a, b);
  464. case TypeCode.UInt64: return IntegerOps.Divide(new Integer((ulong)a), b);
  465. default: throw TypeError("unsupported operand types for /: '{0}' and '{1}'", TypeName(a), TypeName(b));
  466. }
  467. }
  468. public static DivideByZeroException DivideByZeroError(string message) { return new DivideByZeroException(message); }
  469. public static DivideByZeroException DivideByZeroError(string format, params object[] args)
  470. { return new DivideByZeroException(string.Format(format, args));
  471. }
  472. public static Tuple DivMod(object a, object b) // TODO: this could be optimized with type-specific code
  473. { object mod = Modulus(a, b);
  474. return new Tuple(Divide(Subtract(a, mod), b), mod);
  475. }
  476. public static System.IO.EndOfStreamException EOFError(string format, params object[] args)
  477. { return new System.IO.EndOfStreamException(string.Format(format, args));
  478. }
  479. public static object Equal(object a, object b)
  480. { if(a==b) return TRUE;
  481. return FromBool(a is Complex ? ((Complex)a).Equals(b) : Compare(a, b)==0);
  482. }
  483. public static object FindMetaclass(Tuple bases, IDictionary dict)
  484. { object mc = dict["__metaclass__"];
  485. if(mc!=null) return mc;
  486. // TODO: use a better rule for choosing the metaclass?
  487. return bases.Count>0 ? GetDynamicType(bases.items[0]) : ReflectedType.FromType(typeof(UserType));
  488. }
  489. public static int FixIndex(int index, int length)
  490. { if(index<0)
  491. { index += length;
  492. if(index<0) throw IndexError("index out of range: {0}", index-length);
  493. }
  494. else if(index>=length) throw IndexError("index out of range: {0}", index);
  495. return index;
  496. }
  497. public static int FixSliceIndex(int index, int length)
  498. { if(index<0)
  499. { index += length;
  500. if(index<0) index=0;
  501. }
  502. else if(index>length) index=length;
  503. return index;
  504. }
  505. public static object FloorDivide(object a, object b)
  506. { switch(Convert.GetTypeCode(a))
  507. { case TypeCode.Boolean: return (bool)a ? IntOps.FloorDivide(1, b) : 0;
  508. case TypeCode.Byte: return IntOps.FloorDivide((byte)a, b);
  509. case TypeCode.Double: return FloatOps.FloorDivide((double)a, b);
  510. case TypeCode.Int16: return IntOps.FloorDivide((short)a, b);
  511. case TypeCode.Int32: return IntOps.FloorDivide((int)a, b);
  512. case TypeCode.Int64: return LongOps.FloorDivide((long)a, b);
  513. case TypeCode.Object:
  514. if(a is Integer) return IntegerOps.FloorDivide((Integer)a, b);
  515. object ret;
  516. return TryInvoke(a, "__floordiv__", out ret, b) ? ret : Invoke(b, "__rfloordiv__", a);
  517. case TypeCode.SByte: return IntOps.FloorDivide((sbyte)a, b);
  518. case TypeCode.Single: return FloatOps.FloorDivide((float)a, b);
  519. case TypeCode.UInt16: return IntOps.FloorDivide((short)a, b);
  520. case TypeCode.UInt32:
  521. { uint v = (uint)a;
  522. return v<=int.MaxValue ? IntOps.FloorDivide((int)v, b) : LongOps.FloorDivide((long)v, b);
  523. }
  524. case TypeCode.UInt64:
  525. { ulong v = (ulong)a;
  526. return v<=long.MaxValue ? LongOps.FloorDivide((long)v, b) : IntegerOps.FloorDivide(new Integer(v), b);
  527. }
  528. }
  529. throw TypeError("unsupported operand types for /: '{0}' and '{1}'", TypeName(a), TypeName(b));
  530. }
  531. // TODO: check whether we can eliminate this (ie, "true is true" still works)
  532. public static object FromBool(bool value) { return value ? TRUE : FALSE; }
  533. public static CompiledFunction GenerateFunction(string name, Boa.AST.Parameter[] parms, Delegate target)
  534. { string[] names = new string[parms.Length];
  535. for(int i=0; i<parms.Length; i++) names[i] = parms[i].Name.String;
  536. if(target is CallTargetN)
  537. return new CompiledFunctionN(name, names, null, false, false, names.Length, (CallTargetN)target);
  538. else throw new ArgumentException("Unhandled target type: " + target.GetType().FullName);
  539. }
  540. public static object GetAttr(object o, string name)
  541. { IHasAttributes iha = o as IHasAttributes;
  542. if(iha!=null)
  543. { object ret = iha.__getattr__(name);
  544. if(ret==Ops.Missing) throw AttributeError("object has no attribute '{0}'", name);
  545. return ret;
  546. }
  547. return GetDynamicType(o).GetAttr(o, name);
  548. }
  549. public static bool GetAttr(object o, string name, out object value)
  550. { try
  551. { IHasAttributes iha = o as IHasAttributes;
  552. if(iha!=null)
  553. { value = iha.__getattr__(name);
  554. return value!=Missing;
  555. }
  556. return GetDynamicType(o).GetAttr(o, name, out value);
  557. }
  558. catch(AttributeErrorException) { value=null; return false; }
  559. }
  560. public static List GetAttrNames(object o)
  561. { IHasAttributes iha = o as IHasAttributes;
  562. return iha==null ? GetDynamicType(o).GetAttrNames(o) : iha.__attrs__();
  563. }
  564. public static object GetDescriptor(object desc, object instance)
  565. { if(Convert.GetTypeCode(desc)!=TypeCode.Object) return desc; // TODO: i'm not sure how much this optimization helps (if at all)
  566. IDescriptor d = desc as IDescriptor;
  567. if(d!=null) return d.__get__(instance);
  568. object ret;
  569. if(TryInvoke(desc, "__get__", out ret, instance)) return ret;
  570. return desc;
  571. }
  572. public static DynamicType GetDynamicType(object o)
  573. { if(o==null) return NullType.Value;
  574. IDynamicObject dt = o as IDynamicObject;
  575. if(dt!=null) return dt.GetDynamicType();
  576. if(o is string) return StringType;
  577. return ReflectedType.FromType(o.GetType());
  578. }
  579. public static IEnumerator GetEnumerator(object o)
  580. { IEnumerator e;
  581. if(GetEnumerator(o, out e)) return e;
  582. throw TypeError("object is not enumerable");
  583. }
  584. public static bool GetEnumerator(object o, out IEnumerator e)
  585. { if(o is string) e=new BoaCharEnumerator((string)o);
  586. else if(o is IEnumerable) e=((IEnumerable)o).GetEnumerator();
  587. else if(o is ISequence) e=new ISeqEnumerator((ISequence)o);
  588. else if(o is IEnumerator) e=(IEnumerator)o;
  589. else
  590. { object iter;
  591. if(TryInvoke(o, "__iter__", out iter)) e = new IterEnumerator(iter);
  592. else
  593. { object len, getitem;
  594. if(GetAttr(o, "__len__", out len) && GetAttr(o, "__getitem__", out getitem)) e = new SeqEnumerator(o);
  595. else e=null;
  596. }
  597. }
  598. return e!=null;
  599. }
  600. public static Module GetExecutingModule()
  601. { System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
  602. for(int i=1; i<trace.FrameCount; i++)
  603. { Type type = trace.GetFrame(i).GetMethod().DeclaringType;
  604. System.Reflection.FieldInfo fi = type.GetField(Module.FieldName);
  605. if(fi!=null && type.IsSubclassOf(typeof(Boa.AST.Snippet))) return (Module)fi.GetValue(null);
  606. }
  607. if(Frames.Count>0) return ((Frame)Frames.Peek()).Module;
  608. throw new InvalidOperationException("No executing module");
  609. }
  610. public static object GetIndex(object obj, object index)
  611. { ISequence seq = obj as ISequence;
  612. if(seq!=null)
  613. { Slice slice = index as Slice;
  614. return slice==null ? seq.__getitem__(ToInt(index)) : seq.__getitem__(slice);
  615. }
  616. else
  617. { string s = obj as string;
  618. if(s!=null)
  619. { Slice slice = index as Slice;
  620. return slice==null ? new string(s[FixIndex(ToInt(index), s.Length)], 1) : StringOps.Slice(s, slice);
  621. }
  622. }
  623. return Ops.Invoke(obj, "__getitem__", index);
  624. }
  625. public static object GetRawAttr(object obj, string name)
  626. { DynamicType dt = obj as DynamicType;
  627. if(dt==null)
  628. { IHasAttributes ha = obj as IHasAttributes;
  629. if(ha!=null) return ha.__getattr__(name);
  630. dt = GetDynamicType(obj);
  631. }
  632. return dt.GetRawAttr(name);
  633. }
  634. public static ImportErrorException ImportError(string format, params object[] args)
  635. { return new ImportErrorException(string.Format(format, args));
  636. }
  637. public static void ImportFrom(Module module, string moduleName, string[] names, string[] asNames)
  638. { if(names.Length==0) return;
  639. if(names[0]=="*") ImportStar(module, moduleName);
  640. else
  641. { IHasAttributes mod = (IHasAttributes)Importer.Import(moduleName);
  642. if(mod is ReflectedType)
  643. { ReflectedType rmod = (ReflectedType)mod;
  644. for(int i=0; i<names.Length; i++)
  645. module.__setattr__(asNames[i]==null ? names[i] : asNames[i], rmod.GetRawAttr(names[i]));
  646. }
  647. else
  648. for(int i=0; i<names.Length; i++)
  649. module.__setattr__(asNames[i]==null ? names[i] : asNames[i], mod.__getattr__(names[i]));
  650. }
  651. }
  652. public static void ImportStar(Module module, string moduleName)
  653. { IHasAttributes mod = (IHasAttributes)Importer.Import(moduleName);
  654. ISequence exports = mod.__getattr__("__all__") as ISequence;
  655. if(mod is ReflectedType)
  656. { ReflectedType rmod = (ReflectedType)mod;
  657. if(exports==null)
  658. { foreach(string name in mod.__attrs__()) if(name[0]!='_') module.__setattr__(name, rmod.GetRawAttr(name));
  659. }
  660. else
  661. for(int i=0,len=exports.__len__(); i<len; i++)
  662. { string name = (string)exports.__getitem__(i);
  663. module.__setattr__(name, rmod.GetRawAttr(name));
  664. }
  665. }
  666. else
  667. { if(exports==null)
  668. { foreach(string name in mod.__attrs__()) if(name[0]!='_') module.__setattr__(name, mod.__getattr__(name));
  669. }
  670. else
  671. for(int i=0,len=exports.__len__(); i<len; i++)
  672. { string name = (string)exports.__getitem__(i);
  673. module.__setattr__(name, mod.__getattr__(name));
  674. }
  675. }
  676. }
  677. public static IndexErrorException IndexError(string format, params object[] args)
  678. { return new IndexErrorException(string.Format(format, args));
  679. }
  680. public static object Invoke(object target, string name, params object[] args)
  681. { object ret=Call(GetAttr(target, name), args);
  682. if(ret==NotImplemented)
  683. throw Ops.TypeError("method '{0}' is not implemented on type '{1}'", name, TypeName(target));
  684. return ret;
  685. }
  686. public static System.IO.IOException IOError(string format, params object[] args)
  687. { return new System.IO.IOException(string.Format(format, args));
  688. }
  689. public static object IsIn(object a, object b, bool not)
  690. { IContainer ct = b as IContainer;
  691. if(ct==null)
  692. { object isin = Invoke(b, "__contains__", a);
  693. return not ? FromBool(!Ops.IsTrue(isin)) : isin;
  694. }
  695. else return FromBool(not ? !ct.__contains__(a) : ct.__contains__(a));
  696. }
  697. public static bool IsTrue(object a)
  698. { switch(Convert.GetTypeCode(a))
  699. { case TypeCode.Boolean: return (bool)a;
  700. case TypeCode.Byte: return (byte)a!=0;
  701. case TypeCode.Char: return (char)a!=0;
  702. case TypeCode.Decimal: return (Decimal)a!=0;
  703. case TypeCode.Double: return (double)a!=0;
  704. case TypeCode.Empty: return false;
  705. case TypeCode.Int16: return (short)a!=0;
  706. case TypeCode.Int32: return (int)a!=0;
  707. case TypeCode.Int64: return (long)a!=0;
  708. case TypeCode.Object:
  709. if(a is Integer) return (Integer)a!=0;
  710. if(a is Complex) return ComplexOps.NonZero((Complex)a);
  711. if(a is ICollection) return ((ICollection)a).Count>0;
  712. if(a is ISequence) return ((ISequence)a).__len__()>0;
  713. object ret;
  714. if(TryInvoke(a, "__nonzero__", out ret)) return IsTrue(ret);
  715. if(TryInvoke(a, "__len__", out ret)) return Ops.ToInt(ret)>0;
  716. return true;
  717. case TypeCode.SByte: return (sbyte)a!=0;
  718. case TypeCode.Single: return (float)a!=0;
  719. case TypeCode.String: return ((string)a).Length>0;
  720. case TypeCode.UInt16: return (short)a!=0;
  721. case TypeCode.UInt32: return (uint)a!=0;
  722. case TypeCode.UInt64: return (ulong)a!=0;
  723. }
  724. return true;
  725. }
  726. public static KeyErrorException KeyError(string format, params object[] args)
  727. { return new KeyErrorException(string.Format(format, args));
  728. }
  729. public static object LeftShift(object a, object b)
  730. { switch(Convert.GetTypeCode(a))
  731. { case TypeCode.Boolean: return IntOps.LeftShift((bool)a ? 1 : 0, b);
  732. case TypeCode.Byte: return IntOps.LeftShift((int)(byte)a, b);
  733. case TypeCode.Int16: return IntOps.LeftShift((int)(short)a, b);
  734. case TypeCode.Int32: return IntOps.LeftShift((int)a, b);
  735. case TypeCode.Int64: return LongOps.LeftShift((long)a, b);
  736. case TypeCode.Object:
  737. if(a is Integer) return IntegerOps.LeftShift((Integer)a, b);
  738. object ret;
  739. return TryInvoke(a, "__lshift__", out ret, b) ? ret : Invoke(b, "__rlshift__", a);
  740. case TypeCode.SByte: return IntOps.LeftShift((int)(sbyte)a, b);
  741. case TypeCode.UInt16: return IntOps.LeftShift((int)(short)a, b);
  742. case TypeCode.UInt32: return LongOps.LeftShift((long)(uint)a, b);
  743. case TypeCode.UInt64:
  744. { ulong v = (ulong)a;
  745. return v<=long.MaxValue ? LongOps.LeftShift((long)v, b) : IntegerOps.LeftShift(new Integer(v), b);
  746. }
  747. }
  748. throw TypeError("unsupported operand types for <<: '{0}' and '{1}'",
  749. TypeName(a), TypeName(b));
  750. }
  751. public static object Less(object a, object b) { return FromBool(Compare(a,b)<0); }
  752. public static object LessEqual(object a, object b) { return FromBool(Compare(a,b)<=0); }
  753. public static object LogicalAnd(object a, object b) { return IsTrue(a) ? b : a; }
  754. public static object LogicalOr (object a, object b) { return IsTrue(a) ? a : b; }
  755. public static LookupErrorException LookupError(string format, params object[] args)
  756. { return new LookupErrorException(string.Format(format, args));
  757. }
  758. public static object MakeClass(string module, string name, Tuple bases, IDictionary dict)
  759. { if(bases.Count==0) bases = new Tuple(new object[] { ReflectedType.FromType(typeof(object)) });
  760. object metaclass = FindMetaclass(bases, dict);
  761. if(metaclass==ReflectedType.FromType(typeof(ReflectedType)) ||
  762. metaclass==ReflectedType.FromType(typeof(UserType)))
  763. return new UserType(module, name, bases, dict);
  764. return Call(metaclass, name, bases, dict);
  765. }
  766. public static Delegate MakeDelegate(object callable, Type delegateType)
  767. { return Delegate.CreateDelegate(delegateType, DelegateProxy.Make(callable, delegateType), "Handle");
  768. }
  769. public static TypeErrorException MethodCalledWithoutInstance(string name)
  770. { return new TypeErrorException(name+" is a method and requires an instance object");
  771. }
  772. public static object Modulus(object a, object b)
  773. { switch(Convert.GetTypeCode(a))
  774. { case TypeCode.Boolean: return IntOps.Modulus((bool)a ? 1 : 0, b);
  775. case TypeCode.Byte: return IntOps.Modulus((int)(byte)a, b);
  776. case TypeCode.Decimal: return FloatOps.Modulus(((IConvertible)a).ToDouble(NumberFormatInfo.InvariantInfo), b);
  777. case TypeCode.Double: return FloatOps.Modulus((double)a, b);
  778. case TypeCode.Int16: return IntOps.Modulus((int)(short)a, b);
  779. case TypeCode.Int32: return IntOps.Modulus((int)a, b);
  780. case TypeCode.Int64: return LongOps.Modulus((long)a, b);
  781. case TypeCode.Object:
  782. if(a is Integer) return IntegerOps.Modulus((Integer)a, b);
  783. object ret;
  784. return TryInvoke(a, "__mod__", out ret, b) ? ret : Invoke(b, "__rmod__", a);
  785. case TypeCode.SByte: return IntOps.Modulus((int)(sbyte)a, b);
  786. case TypeCode.Single: return FloatOps.Modulus((float)a, b);
  787. case TypeCode.String: return StringOps.PrintF((string)a, b);
  788. case TypeCode.UInt16: return IntOps.Modulus((int)(short)a, b);
  789. case TypeCode.UInt32:
  790. { uint v = (uint)a;
  791. return v<=int.MaxValue ? IntOps.Modulus((int)v, b) : LongOps.Modulus((long)v, b);
  792. }
  793. case TypeCode.UInt64:
  794. { ulong v = (ulong)a;
  795. return v<=long.MaxValue ? LongOps.Modulus((long)v, b) : IntegerOps.Modulus(new Integer(v), b);
  796. }
  797. }
  798. throw TypeError("unsupported operand types for %: '{0}' and '{1}'", TypeName(a), TypeName(b));
  799. }
  800. public static object Multiply(object a, object b)
  801. { switch(Convert.GetTypeCode(a))
  802. { case TypeCode.Boolean: return IntOps.Multiply((bool)a ? 1 : 0, b);
  803. case TypeCode.Byte: return IntOps.Multiply((int)(byte)a, b);
  804. case TypeCode.Char: return new string((char)a, ToInt(b));
  805. case TypeCode.Decimal:
  806. if(b is Decimal) return (Decimal)a * (Decimal)b;
  807. try { return (Decimal)a * Convert.ToDecimal(b); }
  808. catch { break; }
  809. case TypeCode.Double: return FloatOps.Multiply((double)a, b);
  810. case TypeCode.Int16: return IntOps.Multiply((int)(short)a, b);
  811. case TypeCode.Int32: return IntOps.Multiply((int)a, b);
  812. case TypeCode.Int64: return LongOps.Multiply((long)a, b);
  813. case TypeCode.Object:
  814. if(a is Integer) return IntegerOps.Multiply((Integer)a, b);
  815. if(a is Complex) return ComplexOps.Multiply((Complex)a, b);
  816. if(a is ICollection || a is ISequence) return ArrayOps.Multiply(a, b);
  817. object ret;
  818. return TryInvoke(a, "__mul__", out ret, b) ? ret : Invoke(b, "__rmul__", a);
  819. case TypeCode.SByte: return IntOps.Multiply((int)(sbyte)a, b);
  820. case TypeCode.Single: return FloatOps.Multiply((float)a, b);
  821. case TypeCode.String: return StringOps.Multiply((string)a, b);
  822. case TypeCode.UInt16: return IntOps.Multiply((int)(short)a, b);
  823. case TypeCode.UInt32:
  824. { uint v = (uint)a;
  825. return v<=int.MaxValue ? IntOps.Multiply((int)v, b) : LongOps.Multiply((long)v, b);
  826. }
  827. case TypeCode.UInt64:
  828. { ulong v = (ulong)a;
  829. return v<=long.MaxValue ? LongOps.Multiply((long)v, b) : IntegerOps.Multiply(new Integer(v), b);
  830. }
  831. }
  832. throw TypeError("unsupported operand types for *: '{0}' and '{1}'", TypeName(a), TypeName(b));
  833. }
  834. public static object More(object a, object b) { return FromBool(Compare(a,b)>0); }
  835. public static object MoreEqual(object a, object b) { return FromBool(Compare(a,b)>=0); }
  836. public static NameErrorException NameError(string format, params object[] args)
  837. { return new NameErrorException(string.Format(format, args));
  838. }
  839. public static object Negate(object a)
  840. { switch(Convert.GetTypeCode(a))
  841. { case TypeCode.Boolean: return (bool)a ? -1 : 0;
  842. case TypeCode.Byte: return -(int)(byte)a;
  843. case TypeCode.Decimal: return -(Decimal)a;
  844. case TypeCode.Double: return -(double)a;
  845. case TypeCode.Int16: return -(int)(short)a;
  846. case TypeCode.Int32: return -(int)a;
  847. case TypeCode.Int64: return -(long)a;
  848. case TypeCode.Object:
  849. return a is Integer ? -(Integer)a : a is Complex ? -(Complex)a : Invoke(a, "__neg__");
  850. case TypeCode.SByte: return -(int)(sbyte)a;
  851. case TypeCode.Single: return -(float)a;
  852. case TypeCode.UInt16: return -(int)(short)a;
  853. case TypeCode.UInt32:
  854. { uint v = (uint)a;
  855. return v<=int.MaxValue ? (object)-(int)v : (object)-(long)v;
  856. }
  857. case TypeCode.UInt64:
  858. { ulong v = (ulong)a;
  859. return v<=long.MaxValue ? (object)-(long)v : (object)-new Integer(v);
  860. }
  861. }
  862. throw TypeError("unsupported operand type for unary -: '{0}'", TypeName(a));
  863. }
  864. public static object NotEqual(object a, object b)
  865. { if(a==b) return FALSE;
  866. return FromBool(a is Complex ? !((Complex)a).Equals(b) : Compare(a, b)!=0);
  867. }
  868. public static NotImplementedException NotImplementedError(string format, params object[] args)
  869. { return new NotImplementedException(string.Format(format, args));
  870. }
  871. public static OSErrorException OSError(string format, params object[] args)
  872. { return new OSErrorException(string.Format(format, args));
  873. }
  874. public static OverflowException OverflowError(string format, params object[] args)
  875. { return new OverflowException(string.Format(format, args));
  876. }
  877. public static object Power(object a, object b)
  878. { switch(Convert.GetTypeCode(a))
  879. { case TypeCode.Boolean: return IntOps.Power((bool)a ? 1 : 0, b);
  880. case TypeCode.Byte: return IntOps.Power((int)(byte)a, b);
  881. case TypeCode.Double: return FloatOps.Power((double)a, b);
  882. case TypeCode.Int16: return IntOps.Power((int)(short)a, b);
  883. case TypeCode.Int32: return IntOps.Power((int)a, b);
  884. case TypeCode.Int64: return LongOps.Power((long)a, b);
  885. case TypeCode.Object:
  886. if(a is Integer) return IntegerOps.Power((Integer)a, b);
  887. if(a is Complex) return ComplexOps.Power((Complex)a, b);
  888. object ret;
  889. return TryInvoke(a, "__pow__", out ret, b) ? ret : Invoke(b, "__rpow__", a);
  890. case TypeCode.SByte: return IntOps.Power((int)(sbyte)a, b);
  891. case TypeCode.Single: return FloatOps.Power((float)a, b);
  892. case TypeCode.UInt16: return IntOps.Power((int)(short)a, b);
  893. case TypeCode.UInt32:
  894. { uint v = (uint)a;
  895. return v<=int.MaxValue ? IntOps.Power((int)v, b) : LongOps.Power((long)v, b);
  896. }
  897. case TypeCode.UInt64:
  898. { ulong v = (ulong)a;
  899. return v<=long.MaxValue ? LongOps.Power((long)v, b) : IntegerOps.Power(new Integer(v), b);
  900. }
  901. }
  902. throw TypeError("unsupported operand types for **: '{0}' and '{1}'", TypeName(a), TypeName(b));
  903. }
  904. // TODO: optimize this
  905. public static object PowerMod(object a, object b, object c)
  906. { if(Convert.GetTypeCode(a)==TypeCode.Object)
  907. { if(a is Integer) return IntegerOps.PowerMod((Integer)a, b, c);
  908. if(a is Complex) return ComplexOps.PowerMod((Complex)a, b, c);
  909. return Invoke(a, "__pow__", b, c);
  910. }
  911. return Modulus(Power(a, b), c);
  912. }
  913. public static IEnumerator PrepareTupleAssignment(object value, int items)
  914. { if(value is ICollection)
  915. { ICollection col = (ICollection)value;
  916. if(col.Count==items)
  917. { IDictionary d = col as IDictionary;
  918. return d==null ? col.GetEnumerator() : d.Keys.GetEnumerator();
  919. }
  920. }
  921. else if(value is string)
  922. { string s = (string)value;
  923. if(s.Length==items) return new BoaCharEnumerator(s);
  924. }
  925. else if(value is ISequence)
  926. { ISequence seq = (ISequence)value;
  927. if(seq.__len__()==items) return new ISeqEnumerator(seq);
  928. }
  929. else if(ToInt(Invoke(value, "__len__", Misc.EmptyArray)) == items) return new SeqEnumerator(value);
  930. throw Ops.ValueError("wrong number of values to unpack");
  931. }
  932. public static void Print(object file, object o)
  933. { string str = Str(o);
  934. if(file==null) { Console.Write(str); return; }
  935. IFile f = file as IFile;
  936. if(f!=null) { f.write(str); return; }
  937. System.IO.Stream stream = file as System.IO.Stream;
  938. if(stream!=null)
  939. { byte[] data = System.Text.Encoding.Default.GetBytes(str);
  940. stream.Write(data, 0, data.Length);
  941. return;
  942. }
  943. Invoke(file, "write", str);
  944. }
  945. public static void PrintNewline(object file)
  946. { if(file==null) { Console.WriteLine(); return; }
  947. IFile f = file as IFile;
  948. if(f!=null) { f.writebyte('\n'); return; }
  949. System.IO.Stream stream = file as System.IO.Stream;
  950. if(stream!=null) { stream.WriteByte((byte)'\n'); return; }
  951. Invoke(file, "write", "\n");
  952. }
  953. // TODO: handle char somehow
  954. public static string Repr(object o)
  955. { switch(Convert.GetTypeCode(o))
  956. { case TypeCode.Boolean: return (bool)o ? "true" : "false";
  957. case TypeCode.Byte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.SByte: case TypeCode.UInt16:
  958. return o.ToString();
  959. case TypeCode.Double: return ((double)o).ToString("R");
  960. case TypeCode.Empty: return "null";
  961. case TypeCode.Int64: case TypeCode.UInt64: return o.ToString()+'L';
  962. case TypeCode.Object:
  963. if(o is IRepresentable) return ((IRepresentable)o).__repr__();
  964. if(o is Array) return ArrayOps.Repr((Array)o);
  965. break;
  966. case TypeCode.Single: return ((float)o).ToString("R");
  967. case TypeCode.String: return StringOps.Escape((string)o);
  968. case TypeCode.UInt32:
  969. { string ret = o.ToString();
  970. if((uint)o>int.MaxValue) ret += 'L';
  971. return ret;
  972. }
  973. }
  974. return GetDynamicType(o).Repr(o);
  975. }
  976. public static object RightShift(object a, object b)
  977. { switch(Convert.GetTypeCode(a))
  978. { case TypeCode.Boolean: return IntOps.RightShift((bool)a ? 1 : 0, b);
  979. case TypeCode.Byte: return IntOps.RightShift((int)(byte)a, b);
  980. case TypeCode.Int16: return IntOps.RightShift((int)(short)a, b);
  981. case TypeCode.Int32: return IntOps.RightShift((int)a, b);
  982. case TypeCode.Int64: return LongOps.RightShift((long)a, b);
  983. case TypeCode.Object:
  984. if(a is Integer) return IntegerOps.RightShift((Integer)a, b);
  985. object ret;
  986. return TryInvoke(a, "__rshift__", out ret, b) ? ret : Invoke(b, "__rrshift__", a);
  987. case TypeCode.SByte: return IntOps.RightShift((int)(sbyte)a, b);
  988. case TypeCode.UInt16: return IntOps.RightShift((int)(short)a, b);
  989. case TypeCode.UInt32: return LongOps.RightShift((long)(uint)a, b);
  990. case TypeCode.UInt64:
  991. { ulong v = (ulong)a;
  992. return v<=long.MaxValue ? LongOps.RightShift((long)v, b) : IntegerOps.RightShift(new Integer(v), b);
  993. }
  994. }
  995. throw TypeError("unsupported operand types for >>: '{0}' and '{1}'", TypeName(a), TypeName(b));
  996. }
  997. public static RuntimeException RuntimeError(string format, params object[] args)
  998. { return new RuntimeException(string.Format(format, args));
  999. }
  1000. public static List SequenceSlice(ISequence seq, Slice slice)
  1001. { Tuple tup = slice.indices(seq.__len__());
  1002. return SequenceSlice(seq, (int)tup.items[0], (int)tup.items[1], (int)tup.items[2]);
  1003. }
  1004. public static List SequenceSlice(ISequence seq, int start, int stop, int step)
  1005. { if(step<0 && start<=stop || step>0 && start>=stop) return new List();
  1006. int sign = Math.Sign(step);
  1007. List ret = new List((stop-start+step-sign)/step);
  1008. if(step<0) for(; start>stop; start+=step) ret.append(seq.__getitem__(start));
  1009. else for(; start<stop; start+=step) ret.append(seq.__getitem__(start));
  1010. return ret;
  1011. }
  1012. public static void SetAttr(object value, object o, string name)
  1013. { IHasAttributes iha = o as IHasAttributes;
  1014. if(iha!=null) iha.__setattr__(name, value);
  1015. else GetDynamicType(o).SetAttr(o, name, value);
  1016. }
  1017. public static bool SetDescriptor(object desc, object instance, object value)
  1018. { if(Convert.GetTypeCode(desc)!=TypeCode.Object) return false; // TODO: i'm not sure how much this optimization helps (if at all)
  1019. IDataDescriptor dd = desc as IDataDescriptor;
  1020. if(dd!=null) { dd.__set__(instance, value); return true; }
  1021. object dummy;
  1022. return TryInvoke(desc, "__set__", out dummy, instance, value);
  1023. }
  1024. public static void SetIndex(object value, object obj, object index)
  1025. { IMutableSequence seq = obj as IMutableSequence;
  1026. if(seq!=null)
  1027. { Slice slice = index as Slice;
  1028. if(slice!=null) seq.__setitem__(slice, value);
  1029. else seq.__setitem__(Ops.ToInt(index), value);
  1030. }
  1031. else Ops.Invoke(obj, "__setitem__", index, value);
  1032. }
  1033. public static string Str(object o)
  1034. { switch(Convert.GetTypeCode(o))
  1035. { case TypeCode.Boolean: return (bool)o ? "true" : "false";
  1036. case TypeCode.Empty: return "null";
  1037. case TypeCode.Object:
  1038. { object ret;
  1039. if(TryInvoke(o, "__str__", out ret)) return Ops.ToString(ret);
  1040. break;
  1041. }
  1042. case TypeCode.String: return (string)o;
  1043. }
  1044. return o.ToString();
  1045. }
  1046. public static object Subtract(object a, object b)
  1047. { switch(Convert.GetTypeCode(a))
  1048. { case TypeCode.Boolean: return IntOps.Subtract((bool)a ? 1 : 0, b);
  1049. case TypeCode.Byte: return IntOps.Subtract((int)(byte)a, b);
  1050. case TypeCode.Decimal:
  1051. if(b is Decimal) return (Decimal)a - (Decimal)b;
  1052. try { return (Decimal)a - Convert.ToDecimal(b); }
  1053. catch { break; }
  1054. case TypeCode.Double: return FloatOps.Subtract((double)a, b);
  1055. case TypeCode.Int16: return IntOps.Subtract((int)(short)a, b);
  1056. case TypeCode.Int32: return IntOps.Subtract((int)a, b);
  1057. case TypeCode.Int64: return LongOps.Subtract((long)a, b);
  1058. case TypeCode.Object:
  1059. if(a is Integer) return IntegerOps.Subtract((Integer)a, b);
  1060. if(a is Complex) return ComplexOps.Subtract((Complex)a, b);
  1061. object ret;
  1062. return TryInvoke(a, "__sub__", out ret, b) ? ret : Invoke(b, "__rsub__", a);
  1063. case TypeCode.SByte: return IntOps.Subtract((int)(sbyte)a, b);
  1064. case TypeCode.Single: return FloatOps.Subtract((float)a, b);
  1065. case TypeCode.UInt16: return IntOps.Subtract((int)(short)a, b);
  1066. case TypeCode.UInt32:
  1067. { uint v = (uint)a;
  1068. return v<=int.MaxValue ? IntOps.Subtract((int)v, b) : LongOps.Subtract((long)v, b);
  1069. }
  1070. case TypeCode.UInt64:
  1071. { ulong v = (ulong)a;
  1072. return v<=long.MaxValue ? LongOps.Subtract((long)v, b) : IntegerOps.Subtract(new Integer(v), b);
  1073. }
  1074. }
  1075. throw TypeError("unsupported operand types for -: '{0}' and '{1}'", TypeName(a), TypeName(b));
  1076. }
  1077. public static SyntaxErrorException SyntaxError(string format, params object[] args)
  1078. { return new SyntaxErrorException(string.Format(format, args));
  1079. }
  1080. public static SyntaxErrorException SyntaxError(Boa.AST.Node node, string format, params object[] args)

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