/Machete.Runtime/RuntimeTypes/LanguageTypes/LType.cs

https://github.com/Surg420/Machete · C# · 418 lines · 363 code · 55 blank · 0 comment · 57 complexity · 4bc0c983d85549bea449566c7cf0aab6 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Machete.Runtime.RuntimeTypes.SpecificationTypes;
  6. using Machete.Runtime.NativeObjects;
  7. using Machete.Core;
  8. using System.Dynamic;
  9. using System.Linq.Expressions;
  10. using System.Diagnostics;
  11. namespace Machete.Runtime.RuntimeTypes.LanguageTypes
  12. {
  13. public abstract class LType : IDynamic
  14. {
  15. public IEnvironment Environment { get; private set; }
  16. public abstract LanguageTypeCode TypeCode { get; }
  17. public abstract bool IsPrimitive { get; }
  18. public virtual IDynamic Value
  19. {
  20. get { return this; }
  21. set { }
  22. }
  23. protected LType(IEnvironment environment)
  24. {
  25. Environment = environment;
  26. }
  27. public virtual IDynamic Op_LogicalNot()
  28. {
  29. return Environment.CreateBoolean(!this.ConvertToBoolean().BaseValue);
  30. }
  31. public virtual IDynamic Op_LogicalOr(IDynamic other)
  32. {
  33. return this.ConvertToBoolean().BaseValue ? this : other;
  34. }
  35. public virtual IDynamic Op_LogicalAnd(IDynamic other)
  36. {
  37. return !this.ConvertToBoolean().BaseValue ? this : other;
  38. }
  39. public virtual IDynamic Op_BitwiseNot()
  40. {
  41. return Environment.CreateNumber((double)(~(int)(double)this.ConvertToInt32().BaseValue));
  42. }
  43. public virtual IDynamic Op_BitwiseOr(IDynamic other)
  44. {
  45. var lnum = (int)this.ConvertToInt32().BaseValue;
  46. var rnum = (int)(double)other.ConvertToInt32().BaseValue;
  47. return Environment.CreateNumber((double)(lnum | rnum));
  48. }
  49. public virtual IDynamic Op_BitwiseXor(IDynamic other)
  50. {
  51. var lnum = (int)(double)this.ConvertToInt32().BaseValue;
  52. var rnum = (int)(double)other.ConvertToInt32().BaseValue;
  53. return Environment.CreateNumber((double)(lnum ^ rnum));
  54. }
  55. public virtual IDynamic Op_BitwiseAnd(IDynamic other)
  56. {
  57. var lnum = (int)(double)this.ConvertToInt32().BaseValue;
  58. var rnum = (int)(double)other.ConvertToInt32().BaseValue;
  59. return Environment.CreateNumber((double)(lnum & rnum));
  60. }
  61. public abstract IDynamic Op_Equals(IDynamic other);
  62. public virtual IDynamic Op_DoesNotEquals(IDynamic other)
  63. {
  64. return this.Op_Equals(other).Op_LogicalNot();
  65. }
  66. public abstract IDynamic Op_StrictEquals(IDynamic other);
  67. public virtual IDynamic Op_StrictDoesNotEquals(IDynamic other)
  68. {
  69. return this.Op_StrictEquals(other).Op_LogicalNot();
  70. }
  71. public virtual IDynamic Op_Lessthan(IDynamic other)
  72. {
  73. var r = RelationalComparison(true, this, other);
  74. return r.TypeCode == LanguageTypeCode.Undefined ? Environment.False : r;
  75. }
  76. public virtual IDynamic Op_Greaterthan(IDynamic other)
  77. {
  78. var r = RelationalComparison(false, other, this);
  79. return r.TypeCode == LanguageTypeCode.Undefined ? Environment.False : r;
  80. }
  81. public virtual IDynamic Op_LessthanOrEqual(IDynamic other)
  82. {
  83. var r = RelationalComparison(false, other, this);
  84. if (r.TypeCode == LanguageTypeCode.Undefined || ((LBoolean)r).BaseValue)
  85. {
  86. return Environment.False;
  87. }
  88. return Environment.True;
  89. }
  90. public virtual IDynamic Op_GreaterthanOrEqual(IDynamic other)
  91. {
  92. var r = RelationalComparison(true, this, other);
  93. if (r.TypeCode == LanguageTypeCode.Undefined || ((LBoolean)r).BaseValue)
  94. {
  95. return Environment.False;
  96. }
  97. return Environment.True;
  98. }
  99. public virtual IDynamic Op_Instanceof(IDynamic other)
  100. {
  101. var func = other.Value as IHasInstance;
  102. if (func == null)
  103. {
  104. throw Environment.CreateTypeError("");
  105. }
  106. return Environment.CreateBoolean(func.HasInstance(this));
  107. }
  108. public virtual IDynamic Op_In(IDynamic other)
  109. {
  110. if (other.TypeCode != LanguageTypeCode.Object)
  111. {
  112. throw Environment.CreateTypeError("");
  113. }
  114. var obj = other.ConvertToObject();
  115. var prop = this.ConvertToString().BaseValue;
  116. return Environment.CreateBoolean(obj.HasProperty(prop));
  117. }
  118. public virtual IDynamic Op_LeftShift(IDynamic other)
  119. {
  120. var lnum = (int)(double)this.ConvertToInt32().BaseValue;
  121. var rnum = (uint)(double)other.ConvertToUInt32().BaseValue;
  122. var shiftCount = (int)(rnum & (uint)0x1F);
  123. return Environment.CreateNumber((double)(lnum << shiftCount));
  124. }
  125. public virtual IDynamic Op_SignedRightShift(IDynamic other)
  126. {
  127. var lnum = (int)(double)this.ConvertToInt32().BaseValue;
  128. var rnum = (uint)(double)other.ConvertToUInt32().BaseValue;
  129. var shiftCount = (int)(rnum & (uint)0x1F);
  130. return Environment.CreateNumber((double)(lnum >> shiftCount));
  131. }
  132. public virtual IDynamic Op_UnsignedRightShift(IDynamic other)
  133. {
  134. var lnum = (uint)(double)this.ConvertToUInt32().BaseValue;
  135. var rnum = (uint)(double)other.ConvertToUInt32().BaseValue;
  136. var shiftCount = (int)(rnum & (uint)0x1F);
  137. return Environment.CreateNumber((double)unchecked(lnum >> shiftCount));
  138. }
  139. public virtual IDynamic Op_Addition(IDynamic other)
  140. {
  141. var lprim = this.ConvertToPrimitive(null);
  142. var rprim = other.ConvertToPrimitive(null);
  143. if (lprim.TypeCode == LanguageTypeCode.String || rprim.TypeCode == LanguageTypeCode.String)
  144. {
  145. var lstr = (string)lprim.ConvertToString().BaseValue;
  146. var rstr = (string)rprim.ConvertToString().BaseValue;
  147. return Environment.CreateString(lstr + rstr);
  148. }
  149. else
  150. {
  151. var lnum = (double)lprim.ConvertToNumber().BaseValue;
  152. var rnum = (double)rprim.ConvertToNumber().BaseValue;
  153. return Environment.CreateNumber(lnum + rnum);
  154. }
  155. }
  156. public virtual IDynamic Op_Subtraction(IDynamic other)
  157. {
  158. var lnum = (double)this.ConvertToNumber().BaseValue;
  159. var rnum = (double)other.ConvertToNumber().BaseValue;
  160. return Environment.CreateNumber(lnum - rnum);
  161. }
  162. public virtual IDynamic Op_Multiplication(IDynamic other)
  163. {
  164. var lnum = (double)this.ConvertToNumber().BaseValue;
  165. var rnum = (double)other.ConvertToNumber().BaseValue;
  166. return Environment.CreateNumber(lnum * rnum);
  167. }
  168. public virtual IDynamic Op_Division(IDynamic other)
  169. {
  170. var lnum = (double)this.ConvertToNumber().BaseValue;
  171. var rnum = (double)other.ConvertToNumber().BaseValue;
  172. return Environment.CreateNumber(lnum / rnum);
  173. }
  174. public virtual IDynamic Op_Modulus(IDynamic other)
  175. {
  176. var lnum = (double)this.ConvertToNumber().BaseValue;
  177. var rnum = (double)other.ConvertToNumber().BaseValue;
  178. return Environment.CreateNumber(lnum % rnum);
  179. }
  180. public virtual IDynamic Op_Delete()
  181. {
  182. return Environment.True;
  183. }
  184. public virtual IDynamic Op_Void()
  185. {
  186. return Environment.Undefined;
  187. }
  188. public abstract IDynamic Op_Typeof();
  189. public virtual IDynamic Op_PrefixIncrement()
  190. {
  191. throw new NotImplementedException();
  192. }
  193. public virtual IDynamic Op_PrefixDecrement()
  194. {
  195. throw new NotImplementedException();
  196. }
  197. public virtual IDynamic Op_Plus()
  198. {
  199. return this.ConvertToNumber();
  200. }
  201. public virtual IDynamic Op_Minus()
  202. {
  203. var r = (double)this.ConvertToNumber().BaseValue;
  204. if (double.IsNaN(r))
  205. {
  206. return Environment.CreateNumber(double.NaN);
  207. }
  208. return Environment.CreateNumber(-r);
  209. }
  210. public virtual IDynamic Op_PostfixIncrement()
  211. {
  212. throw new NotImplementedException();
  213. }
  214. public virtual IDynamic Op_PostfixDecrement()
  215. {
  216. throw new NotImplementedException();
  217. }
  218. public virtual IDynamic Op_Call(IArgs args)
  219. {
  220. throw Environment.CreateTypeError("This value is not callable.");
  221. }
  222. public virtual IObject Op_Construct(IArgs args)
  223. {
  224. var c = this as IConstructable;
  225. if (c != null)
  226. {
  227. return c.Construct(Environment, args);
  228. }
  229. throw Environment.CreateTypeError("This value is not constructable.");
  230. }
  231. public virtual void Op_Throw()
  232. {
  233. Environment.ThrowRuntimeException(this);
  234. }
  235. public abstract IDynamic ConvertToPrimitive(string preferredType);
  236. public abstract IBoolean ConvertToBoolean();
  237. public abstract INumber ConvertToNumber();
  238. public abstract IString ConvertToString();
  239. public abstract IObject ConvertToObject();
  240. public virtual INumber ConvertToInteger()
  241. {
  242. var number = this.ConvertToNumber();
  243. if (double.IsNaN((double)number.BaseValue))
  244. {
  245. return Environment.CreateNumber(0);
  246. }
  247. else if (number.BaseValue == 0.0 || double.IsInfinity((double)number.BaseValue))
  248. {
  249. return number;
  250. }
  251. else
  252. {
  253. var sign = Math.Sign((double)number.BaseValue);
  254. var abs = Math.Abs((double)number.BaseValue);
  255. var floor = Math.Floor(abs);
  256. return Environment.CreateNumber(sign * floor);
  257. }
  258. }
  259. public virtual INumber ConvertToInt32()
  260. {
  261. var number = (double)this.ConvertToNumber().BaseValue;
  262. if (number == 0.0 || double.IsNaN(number) || double.IsInfinity(number))
  263. {
  264. return Environment.CreateNumber(0);
  265. }
  266. var posInt = Math.Sign(number) * Math.Floor(Math.Abs(number));
  267. var int32Bit = posInt % uint.MaxValue;
  268. if (int32Bit > int.MaxValue)
  269. {
  270. return Environment.CreateNumber(int32Bit - uint.MaxValue);
  271. }
  272. return Environment.CreateNumber(int32Bit);
  273. }
  274. public virtual INumber ConvertToUInt32()
  275. {
  276. var number = (double)this.ConvertToNumber().BaseValue;
  277. if (number == 0.0 || double.IsNaN(number) || double.IsInfinity(number))
  278. {
  279. return Environment.CreateNumber(0);
  280. }
  281. var posInt = Math.Sign(number) * Math.Floor(Math.Abs(number));
  282. var int32Bit = posInt % uint.MaxValue;
  283. return Environment.CreateNumber(int32Bit);
  284. }
  285. public virtual INumber ConvertToUInt16()
  286. {
  287. var number = (double)this.ConvertToNumber().BaseValue;
  288. if (number == 0.0 || double.IsNaN(number) || double.IsInfinity(number))
  289. {
  290. return Environment.CreateNumber(0);
  291. }
  292. var posInt = Math.Sign(number) * Math.Floor(Math.Abs(number));
  293. var int16Bit = posInt % ushort.MaxValue;
  294. return Environment.CreateNumber(int16Bit);
  295. }
  296. public override string ToString()
  297. {
  298. return ConvertToString().BaseValue;
  299. }
  300. private IDynamic RelationalComparison(bool leftFirst, IDynamic left, IDynamic right)
  301. {
  302. IDynamic px, py;
  303. if (leftFirst)
  304. {
  305. px = left.ConvertToPrimitive("Number");
  306. py = right.ConvertToPrimitive("Number");
  307. }
  308. else
  309. {
  310. py = right.ConvertToPrimitive("Number");
  311. px = left.ConvertToPrimitive("Number");
  312. }
  313. if (px.TypeCode == LanguageTypeCode.String && py.TypeCode == LanguageTypeCode.String)
  314. {
  315. string sx = (string)px.ConvertToString().BaseValue, sy = (string)py.ConvertToString().BaseValue;
  316. if (sx.StartsWith(sy))
  317. {
  318. return Environment.False;
  319. }
  320. else if (sy.StartsWith(sx))
  321. {
  322. return Environment.True;
  323. }
  324. else
  325. {
  326. return Environment.CreateBoolean(sx.CompareTo(sy) < 0);
  327. }
  328. }
  329. else
  330. {
  331. double nx = (double)px.ConvertToNumber().BaseValue, ny = (double)py.ConvertToNumber().BaseValue;
  332. if (double.IsNaN(nx) || double.IsNaN(ny))
  333. {
  334. return Environment.Undefined;
  335. }
  336. else if (nx != ny)
  337. {
  338. if (double.IsPositiveInfinity(nx))
  339. {
  340. return Environment.False;
  341. }
  342. else if (double.IsPositiveInfinity(ny))
  343. {
  344. return Environment.True;
  345. }
  346. else if (double.IsNegativeInfinity(ny))
  347. {
  348. return Environment.False;
  349. }
  350. else if (double.IsNegativeInfinity(nx))
  351. {
  352. return Environment.True;
  353. }
  354. else
  355. {
  356. return Environment.CreateBoolean(nx < ny);
  357. }
  358. }
  359. return Environment.False;
  360. }
  361. }
  362. }
  363. }