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

/Languages/IronPython/IronPythonTest/LightExceptionTests.cs

http://github.com/IronLanguages/main
C# | 318 lines | 262 code | 41 blank | 15 comment | 22 complexity | acc2ef5dcaf924780ca9e2bd919571de MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. using Microsoft.Scripting.Ast;
  18. #else
  19. using Microsoft.Scripting.Ast;
  20. #endif
  21. using System;
  22. using System.Collections.Generic;
  23. using System.Dynamic;
  24. using System.Runtime.CompilerServices;
  25. using Microsoft.Scripting.Generation;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime;
  28. using System.Reflection;
  29. using Microsoft.Scripting.Runtime;
  30. using Microsoft.Scripting.Actions;
  31. namespace IronPythonTest {
  32. class LightExceptionTests {
  33. private Func<LightExceptionTests, IEnumerable<Expression>>[] StatementBuilders = new[] {
  34. new Func<LightExceptionTests, IEnumerable<Expression>>(TryCatchBuilder),
  35. new Func<LightExceptionTests, IEnumerable<Expression>>(TryFinallyBuilder),
  36. new Func<LightExceptionTests, IEnumerable<Expression>>(ThrowBuilder),
  37. new Func<LightExceptionTests, IEnumerable<Expression>>(CallBuilder),
  38. new Func<LightExceptionTests, IEnumerable<Expression>>(ReturnBuilder),
  39. };
  40. private static ParameterExpression _input = Expression.Parameter(typeof(List<string>), "log");
  41. private static MethodInfo _addLog = typeof(List<string>).GetMethod("Add");
  42. private static LabelTarget _ret = Expression.Label(typeof(object), "return");
  43. private static Expression[] _catchExtras = new[] { (Expression)Expression.Default(typeof(void)), Expression.Rethrow() };
  44. public static void RunTests() {
  45. var param = Expression.Parameter(typeof(Exception), "foo");
  46. var lambdax = Expression.Lambda<Func<object>>(
  47. Expression.Block(
  48. LightExceptions.RewriteExternal(
  49. Expression.TryCatch(
  50. Expression.Default(typeof(object)),
  51. Expression.Catch(param, Expression.Default(typeof(object)))
  52. )
  53. ),
  54. LightExceptions.RewriteExternal(
  55. Expression.TryCatch(
  56. Expression.Default(typeof(object)),
  57. Expression.Catch(param, Expression.Default(typeof(object)))
  58. )
  59. )
  60. )
  61. );
  62. lambdax.Compile()();
  63. CompilerHelpers.LightCompile(lambdax)();
  64. var builder = new LightExceptionTests();
  65. List<string> record = new List<string>();
  66. List<string> rewriteRecord = new List<string>();
  67. int testCount = 0;
  68. try {
  69. foreach (var lambda in builder.MakeLambda()) {
  70. // run each test in normal and lightweight exception modes, make sure they have the same result
  71. try {
  72. object res = lambda.Compile()(record);
  73. if (res != null) {
  74. record.Add(res.ToString());
  75. }
  76. } catch (Exception e) {
  77. record.Add(String.Format("EXCEPTION {0}", e.GetType()));
  78. }
  79. try {
  80. object res = ((Expression<Func<List<string>, object>>)LightExceptions.Rewrite(lambda)).Compile()(rewriteRecord);
  81. Exception e = LightExceptions.GetLightException(res);
  82. if (e != null) {
  83. rewriteRecord.Add(String.Format("EXCEPTION {0}", e.GetType()));
  84. } else if (res != null) {
  85. rewriteRecord.Add(res.ToString());
  86. }
  87. } catch (Exception e) {
  88. rewriteRecord.Add(String.Format("EXCEPTION {0}", e.GetType()));
  89. }
  90. if (record.Count != rewriteRecord.Count) {
  91. PrintLambda(lambda, record, rewriteRecord);
  92. throw new Exception("Records differ in length");
  93. }
  94. for (int i = 0; i < record.Count; i++) {
  95. if (record[i] != rewriteRecord[i]) {
  96. PrintLambda(lambda, record, rewriteRecord);
  97. throw new Exception("Records differ");
  98. }
  99. }
  100. record.Clear();
  101. rewriteRecord.Clear();
  102. testCount++;
  103. }
  104. } finally {
  105. Console.Write("Ran {0} tests", testCount);
  106. }
  107. }
  108. private static void PrintLambda(Expression<Func<List<string>, object>> lambda, List<string> record, List<string> rewriteRecord) {
  109. for (int i = 0; i < Math.Min(record.Count, rewriteRecord.Count); i++) {
  110. Console.WriteLine(record[i]);
  111. Console.WriteLine(rewriteRecord[i]);
  112. Console.WriteLine();
  113. }
  114. #if CLR2
  115. Console.WriteLine("Before: " + Environment.NewLine + lambda.DebugView);
  116. Console.WriteLine("After: " + Environment.NewLine + LightExceptions.Rewrite(lambda).DebugView);
  117. #endif
  118. }
  119. private int _depth = 0;
  120. private IEnumerable<Expression<Func<List<string>, object>>> MakeLambda() {
  121. foreach (var expr in GetStatements()) {
  122. var res = expr;
  123. if (res.Type != typeof(object)) {
  124. res = Expression.Block(expr, Expression.Default(typeof(object)));
  125. }
  126. yield return Expression.Lambda<Func<List<string>, object>>(
  127. Expression.Label(_ret, res),
  128. _input
  129. );
  130. }
  131. }
  132. public IEnumerable<Expression> GetStatements() {
  133. if (_depth < 2) {
  134. foreach (var func in StatementBuilders) {
  135. foreach (var expr in func(this)) { yield return expr; }
  136. }
  137. }
  138. }
  139. private static Expression AddLogging(Expression expr, string log) {
  140. return Expression.Block(
  141. Expression.Call(
  142. _input,
  143. _addLog,
  144. Expression.Constant(log)
  145. ),
  146. expr
  147. );
  148. }
  149. private static IEnumerable<Expression> ReturnBuilder(LightExceptionTests self) {
  150. yield return Expression.Return(_ret, Expression.Default(typeof(object)));
  151. }
  152. private static IEnumerable<Expression> TryCatchBuilder(LightExceptionTests self) {
  153. using (new DepthHolder(self)) {
  154. foreach (var body in self.GetStatements()) {
  155. foreach (var handler in self.GetStatements()) {
  156. for (int i = 0; i < _catchExtras.Length; i++) {
  157. var extra = _catchExtras[i];
  158. yield return AddLogging(
  159. Expression.TryCatch(
  160. Expression.Block(typeof(void), body),
  161. Expression.Catch(
  162. typeof(Exception),
  163. AddLogging(Expression.Block(typeof(void), handler, extra), "catch " + i)
  164. )
  165. ),
  166. "try"
  167. );
  168. yield return AddLogging(
  169. Expression.TryCatch(
  170. Expression.Block(typeof(void), body),
  171. Expression.Catch(
  172. typeof(InvalidOperationException),
  173. AddLogging(Expression.Block(typeof(void), handler, extra), "invalidEx catch 1 " + i)
  174. )
  175. ),
  176. "try"
  177. );
  178. yield return AddLogging(
  179. Expression.TryCatch(
  180. Expression.Block(typeof(void), body),
  181. Expression.Catch(
  182. typeof(InvalidOperationException),
  183. AddLogging(Expression.Block(typeof(void), handler, extra), "invalidEx catch 2 " + i)
  184. ),
  185. Expression.Catch(
  186. typeof(InvalidOperationException),
  187. AddLogging(Expression.Block(typeof(void), handler, extra), "catch " + i)
  188. )
  189. ),
  190. "try"
  191. );
  192. }
  193. }
  194. }
  195. }
  196. }
  197. private static IEnumerable<Expression> TryFinallyBuilder(LightExceptionTests self) {
  198. using (new DepthHolder(self)) {
  199. foreach (var body in self.GetStatements()) {
  200. foreach (var handler in self.GetStatements()) {
  201. yield return Expression.TryFinally(AddLogging(body, "try finally"), AddLogging(handler, "finally"));
  202. }
  203. }
  204. }
  205. }
  206. private static IEnumerable<Expression> ThrowBuilder(LightExceptionTests self) {
  207. yield return AddLogging(Expression.Throw(Expression.New(typeof(Exception))), "throw ex");
  208. yield return AddLogging(Expression.Throw(Expression.New(typeof(InvalidOperationException))), "throw invalidEx");
  209. }
  210. private static IEnumerable<Expression> CallBuilder(LightExceptionTests self) {
  211. yield return AddLogging(LightExceptions.CheckAndThrow(Expression.Call(typeof(LightExceptionTests).GetMethod("SomeCall"))), "call");
  212. yield return AddLogging(Expression.Call(typeof(LightExceptionTests).GetMethod("ThrowingCall")), "call throw");
  213. yield return AddLogging(Expression.Call(typeof(LightExceptionTests).GetMethod("ThrowingCallInvalidOp")), "call throw invalidop");
  214. yield return AddLogging(LightExceptions.CheckAndThrow(Expression.Call(typeof(LightExceptionTests).GetMethod("LightThrowingCall"))), "call throw");
  215. yield return AddLogging(LightExceptions.CheckAndThrow(Expression.Call(typeof(LightExceptionTests).GetMethod("LightThrowingCallInvalidOp"))), "call throw invalidop");
  216. yield return AddLogging(DynamicExpression.Dynamic(new LightExBinder("test", false), typeof(object), Expression.Constant(42)), "dynamic throw");
  217. yield return AddLogging(
  218. DynamicExpression.Dynamic(new LightExBinder("test", false), typeof(object),
  219. DynamicExpression.Dynamic(new LightExBinder("foo", false), typeof(object), Expression.Constant(42))), "dynamic nothrow");
  220. }
  221. public static object SomeCall() {
  222. return null;
  223. }
  224. public static object ThrowingCall() {
  225. throw new Exception();
  226. }
  227. public static object ThrowingCallInvalidOp() {
  228. throw new InvalidOperationException();
  229. }
  230. public static object LightThrowingCall() {
  231. return LightExceptions.Throw(new Exception());
  232. }
  233. public static object LightThrowingCallInvalidOp() {
  234. return LightExceptions.Throw(new InvalidOperationException());
  235. }
  236. struct DepthHolder : IDisposable {
  237. private LightExceptionTests Builder;
  238. public DepthHolder(LightExceptionTests builder) {
  239. Builder = builder;
  240. builder._depth++;
  241. }
  242. public void Dispose() {
  243. Builder._depth--;
  244. }
  245. }
  246. class LightExBinder : GetMemberBinder, ILightExceptionBinder {
  247. private bool _supportsLightEx;
  248. public LightExBinder(string name, bool supportsLightEx)
  249. : base(name, false) {
  250. _supportsLightEx = supportsLightEx;
  251. }
  252. public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) {
  253. var ex = Expression.New(typeof(MissingMemberException));
  254. Expression body;
  255. if (Name == "foo") {
  256. body = target.Expression;
  257. } else if (_supportsLightEx) {
  258. body = LightExceptions.Throw(ex, typeof(object));
  259. } else {
  260. body = Expression.Throw(ex, typeof(object));
  261. }
  262. return new DynamicMetaObject(
  263. body,
  264. BindingRestrictions.GetTypeRestriction(target.Expression, target.Value.GetType())
  265. );
  266. }
  267. #region ILightExceptionBinder Members
  268. public bool SupportsLightThrow {
  269. get { return _supportsLightEx; }
  270. }
  271. public CallSiteBinder GetLightExceptionBinder() {
  272. return new LightExBinder(Name, true);
  273. }
  274. #endregion
  275. }
  276. }
  277. }