PageRenderTime 46ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/Rx/NET/tools/HomoIcon/Program.cs

http://rx.codeplex.com
C# | 929 lines | 768 code | 148 blank | 13 comment | 208 complexity | e6df851ef640e5b212c3cfcd786b9bb2 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, MIT, WTFPL, GPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using System.Threading.Tasks;
  8. using System.Xml.Linq;
  9. namespace HomoIconize
  10. {
  11. static class Program
  12. {
  13. static void Main(string[] args)
  14. {
  15. Console.WriteLine("Auto-homoiconizer for Qbservable[Ex]");
  16. Console.WriteLine("------------------------------------");
  17. Console.WriteLine();
  18. var uri = new Uri(Assembly.GetEntryAssembly().CodeBase);
  19. var root = Path.Combine(Path.GetDirectoryName(uri.LocalPath), @"..\..\..\..\Source");
  20. if (!Directory.Exists(root))
  21. {
  22. Console.WriteLine("Error: Could not find directory \"" + root + "\"");
  23. return;
  24. }
  25. Process(root, "System.Reactive.Linq", "System.Reactive.Providers", @"Reactive\Linq\Qbservable.Generated.cs", "System.Reactive.Linq.Observable", "Qbservable", true);
  26. Console.WriteLine();
  27. Process(root, "System.Reactive.Experimental", "System.Reactive.Experimental", @"Reactive\Linq\QbservableEx.Generated.cs", "System.Reactive.Linq.ObservableEx", "QbservableEx");
  28. Console.WriteLine();
  29. }
  30. static void Process(string root, string sourceAssembly, string targetAssembly, string targetFile, string sourceTypeName, string targetTypeName, bool includeAsync = false)
  31. {
  32. var rxRoot = Path.Combine(root, sourceAssembly);
  33. if (!Directory.Exists(rxRoot))
  34. {
  35. Console.WriteLine("Error: Could not find directory \"" + rxRoot + "\"");
  36. return;
  37. }
  38. var qbRoot = Path.Combine(root, targetAssembly);
  39. if (!Directory.Exists(qbRoot))
  40. {
  41. Console.WriteLine("Error: Could not find directory \"" + qbRoot + "\"");
  42. return;
  43. }
  44. var dll = Path.Combine(rxRoot, @"bin\debug40\" + sourceAssembly + ".dll");
  45. if (!File.Exists(dll))
  46. {
  47. Console.WriteLine("Error: Could not find file \"" + dll + "\"");
  48. return;
  49. }
  50. var xml = Path.Combine(rxRoot, @"bin\debug40\" + sourceAssembly + ".xml");
  51. if (!File.Exists(xml))
  52. {
  53. Console.WriteLine("Error: Could not find file \"" + xml + "\"");
  54. return;
  55. }
  56. var qbsgen = Path.Combine(qbRoot, targetFile);
  57. if (!File.Exists(qbsgen))
  58. {
  59. Console.WriteLine("Error: Could not find file \"" + qbsgen + "\"");
  60. return;
  61. }
  62. Generate(dll, xml, qbsgen, sourceTypeName, targetTypeName, includeAsync);
  63. }
  64. // Prototype interface to break dependencies. Only used for ToString2 ultimately.
  65. interface IQbservable<T>
  66. {
  67. }
  68. static void Generate(string input, string xml, string output, string sourceTypeName, string targetTypeName, bool includeAsync)
  69. {
  70. var docs = XDocument.Load(xml).Root.Element("members").Elements("member").ToDictionary(m => m.Attribute("name").Value, m => m);
  71. Console.WriteLine("Loading {0}...", input);
  72. var asm = Assembly.LoadFrom(input);
  73. var t = asm.GetType(sourceTypeName);
  74. _qbs = typeof(IQbservable<>); //asm.GetType("System.Reactive.Linq.IQbservable`1");
  75. Console.WriteLine("Checking {0}...", output);
  76. var attr = File.GetAttributes(output);
  77. if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
  78. {
  79. Console.Write("Attempting to check out generated files... ");
  80. try
  81. {
  82. System.Diagnostics.Process.Start("tf.exe", "edit \"" + output + "\"").WaitForExit();
  83. }
  84. catch { /* no comment */ }
  85. attr = File.GetAttributes(output);
  86. if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
  87. {
  88. Console.WriteLine("Failed.");
  89. Console.ForegroundColor = ConsoleColor.Yellow;
  90. Console.WriteLine("Making file writable. DON'T FORGET TO INCLUDE IN CHECK-IN!");
  91. Console.ResetColor();
  92. File.SetAttributes(output, attr & ~FileAttributes.ReadOnly);
  93. }
  94. else
  95. {
  96. Console.WriteLine("Succeeded.");
  97. }
  98. }
  99. Console.WriteLine("Deleting {0}...", output);
  100. File.Delete(output);
  101. Console.WriteLine("Creating {0}...", output);
  102. using (var fs = File.OpenWrite(output))
  103. {
  104. using (Out = new StreamWriter(fs))
  105. {
  106. Generate(t, docs, targetTypeName, includeAsync);
  107. }
  108. }
  109. }
  110. static Type _qbs;
  111. static void Generate(Type t, IDictionary<string, XElement> docs, string typeName, bool includeAsync)
  112. {
  113. WriteLine(
  114. @"/*
  115. * WARNING: Auto-generated file (" + DateTime.Now + @")
  116. * Run Rx's auto-homoiconizer tool to generate this file (in the HomoIcon directory).
  117. */
  118. ");
  119. WriteLine(
  120. @"#pragma warning disable 1591
  121. ");
  122. WriteLine(
  123. @"#if !NO_EXPRESSIONS
  124. ");
  125. WriteLine(
  126. @"using System;
  127. using System.Reactive.Concurrency;
  128. using System.Collections.Generic;
  129. using System.Reactive.Joins;
  130. using System.Linq;
  131. using System.Linq.Expressions;
  132. using System.Reflection;
  133. using System.Threading;
  134. using System.Reactive;
  135. using System.Reactive.Subjects;
  136. #if !NO_TPL
  137. using System.Threading.Tasks;
  138. #endif
  139. #if !NO_REMOTING
  140. using System.Runtime.Remoting.Lifetime;
  141. #endif
  142. ");
  143. WriteLine(
  144. @"namespace System.Reactive.Linq
  145. {");
  146. Indent();
  147. WriteLine(
  148. @"public static partial class " + typeName + @"
  149. {");
  150. Indent();
  151. var except = new[] { "ToAsync", "FromAsyncPattern", "And", "Then", "GetEnumerator", "get_Provider", "Wait", "ForEach", "ForEachAsync", "GetAwaiter", "First", "FirstOrDefault", "Last", "LastOrDefault", "Single", "SingleOrDefault", "Subscribe", "AsQbservable", "AsObservable", "ToEvent", "ToEventPattern" };
  152. foreach (var m in t.GetMethods(BindingFlags.Public | BindingFlags.Static).OrderBy(m => m.Name).ThenBy(m => !m.IsGenericMethod ? "" : string.Join(",", m.GetGenericArguments().Select(p => p.Name))).ThenBy(m => string.Join(",", m.GetParameters().Select(p => p.Name + ":" + p.ParameterType.FullName))).Where(m => !except.Contains(m.Name)))
  153. {
  154. var docName = ToDocName(m);
  155. var xmlDoc = default(XElement);
  156. if (!docs.TryGetValue(docName, out xmlDoc))
  157. {
  158. Console.ForegroundColor = ConsoleColor.Yellow;
  159. Console.WriteLine("Missing XML documentation for {0}", docName);
  160. Console.ResetColor();
  161. }
  162. var p = m.GetParameters();
  163. if (m.Name == "When" && p.Length == 1 && p.Single().ParameterType.ToString().Contains("Plan"))
  164. continue;
  165. var funky = from pi in p
  166. let pt = pi.ParameterType
  167. where pt.IsGenericType
  168. let ptgtd = pt.GetGenericTypeDefinition()
  169. where ptgtd.Name.StartsWith("Func")
  170. where ptgtd.GetGenericArguments().Count() > 5
  171. select pi;
  172. var isLargeArity = funky.Any();
  173. var hasTask = p.Any(pa => ContainsTask(pa.ParameterType));
  174. var ret = m.ReturnType;
  175. if (ret.IsGenericType)
  176. {
  177. var d = ret.GetGenericTypeDefinition();
  178. if (d.Name.StartsWith("IConnectableObservable") || d.Name.StartsWith("ListObservable"))
  179. continue;
  180. if (d != typeof(IObservable<>) && d != typeof(IEnumerable<>))
  181. throw new InvalidOperationException("Invalid return type for " + m.Name);
  182. }
  183. else
  184. throw new InvalidOperationException("Invalid return type for " + m.Name);
  185. ret = ret.Iconize();
  186. var hasProvider = true;
  187. if (p.Length > 0)
  188. {
  189. var f = p.First();
  190. if (f.ParameterType.IsGenericType)
  191. {
  192. var d = f.ParameterType.GetGenericTypeDefinition();
  193. if (d == typeof(IObservable<>)) // Check - e.g. Amb || d == typeof(IEnumerable<>))
  194. hasProvider = false;
  195. }
  196. }
  197. var nulls = new List<string>();
  198. var pars = new List<string>();
  199. var ptps = new List<string>();
  200. var args = new List<string>();
  201. var firstArg = hasProvider ? "IQbservableProvider" : p.First().ParameterType.Iconize().ToString2();
  202. var firstName = hasProvider ? "provider" : p.First().Name;
  203. pars.Add("this " + firstArg + " " + firstName);
  204. ptps.Add(firstArg);
  205. if (!hasProvider)
  206. args.Add(firstName + ".Expression");
  207. else
  208. args.Add("Expression.Constant(provider, typeof(IQbservableProvider))");
  209. nulls.Add(firstName);
  210. var rem = hasProvider ? p : p.Skip(1);
  211. var isCreateAsync = false;
  212. foreach (var q in rem)
  213. {
  214. var pt = q.ParameterType;
  215. if (pt.Name.StartsWith("Func") || pt.Name.StartsWith("Action"))
  216. {
  217. if (pt.Name.StartsWith("Func") && pt.GetGenericArguments().Last().Name.StartsWith("Task"))
  218. {
  219. isCreateAsync = true;
  220. }
  221. pt = typeof(Expression<>).MakeGenericType(pt);
  222. args.Add(q.Name);
  223. }
  224. else
  225. {
  226. var isObs = new Func<Type, bool>(tt => tt.IsGenericType && tt.GetGenericTypeDefinition() == typeof(IObservable<>));
  227. var isEnm = new Func<Type, bool>(tt => tt.IsGenericType && tt.GetGenericTypeDefinition() == typeof(IEnumerable<>));
  228. if (isObs(pt) || pt.IsArray && isObs(pt.GetElementType()) || isEnm(pt) || pt.IsArray && isEnm(pt.GetElementType()))
  229. args.Add("GetSourceExpression(" + q.Name + ")");
  230. else
  231. args.Add("Expression.Constant(" + q.Name + ", typeof(" + pt.ToString2() + "))");
  232. }
  233. var pts = pt.ToString2();
  234. var par = pts + " " + q.Name;
  235. if (q.IsDefined(typeof(ParamArrayAttribute), false))
  236. par = "params " + par;
  237. pars.Add(par);
  238. ptps.Add(pts);
  239. if (!q.ParameterType.IsValueType && !q.ParameterType.IsGenericParameter)
  240. nulls.Add(q.Name);
  241. }
  242. var factory = hasProvider ? "provider" : p.First().Name + ".Provider";
  243. var requiresQueryProvider = ret.GetGenericTypeDefinition() == typeof(IQueryable<>);
  244. if (requiresQueryProvider)
  245. factory = "((IQueryProvider)" + factory + ")";
  246. var genArgs = m.GetGenericArguments().Select(a => a.ToString2()).ToList();
  247. var g = genArgs.Count > 0 ? "<" + string.Join(", ", genArgs) + ">" : "";
  248. var name = m.Name;
  249. if (name == "ToEnumerable")
  250. name = "ToQueryable";
  251. var isExp = m.GetCustomAttributes(true).Where(a => a.GetType().Name.Equals("ExperimentalAttribute")).Any();
  252. if (isExp)
  253. WriteLine("#if !STABLE", true);
  254. var obsolete = m.GetCustomAttributes(typeof(ObsoleteAttribute), false).Cast<ObsoleteAttribute>().SingleOrDefault();
  255. var poundIf = false;
  256. if (name == "ObserveOn" || name == "SubscribeOn")
  257. {
  258. if (p.Last().ParameterType.Name == "DispatcherScheduler")
  259. {
  260. WriteLine("#if !MONO", true);
  261. poundIf = true;
  262. }
  263. if (p.Last().ParameterType.Name == "ControlScheduler")
  264. {
  265. WriteLine("#if DESKTOPCLR", true);
  266. poundIf = true;
  267. }
  268. }
  269. if (name == "ObserveOnDispatcher" || name == "SubscribeOnDispatcher")
  270. {
  271. WriteLine("#if !MONO", true);
  272. poundIf = true;
  273. }
  274. if (isCreateAsync || hasTask)
  275. {
  276. WriteLine("#if !NO_TPL", true);
  277. poundIf = true;
  278. }
  279. //if (name == "Remotable")
  280. //{
  281. // WriteLine("#if DESKTOPCLR", true);
  282. // poundIf = true;
  283. // if (nulls.Contains("lease"))
  284. // nulls.Remove("lease");
  285. //}
  286. if (isLargeArity)
  287. {
  288. WriteLine("#if !NO_LARGEARITY", true);
  289. }
  290. var isFep = m.Name == "FromEventPattern";
  291. var isGenFep = isFep && m.GetGenericArguments().Any(a => a.Name == "TEventArgs");
  292. var isNonGenFep = isFep && !isGenFep;
  293. for (var r = 0; r < (isNonGenFep ? 2 : 1); r++)
  294. {
  295. var retStr = ret.ToString2();
  296. if (isNonGenFep)
  297. {
  298. if (r == 0)
  299. {
  300. WriteLine("#if !NO_EVENTARGS_CONSTRAINT", true);
  301. }
  302. else if (r == 1)
  303. {
  304. WriteLine("#else", true);
  305. retStr = retStr.Replace("EventPattern<EventArgs>", "EventPattern<object>");
  306. }
  307. }
  308. if (xmlDoc != null)
  309. {
  310. foreach (var docLine in xmlDoc.Element("summary").ToString().Split('\n'))
  311. WriteLine("/// " + docLine.TrimStart().TrimEnd('\r'));
  312. if (hasProvider)
  313. WriteLine("/// <param name=\"provider\">Query provider used to construct the IQbservable&lt;T&gt; data source.</param>");
  314. foreach (var docLine in xmlDoc.Elements().Where(e => e.Name != "summary").SelectMany(e => e.ToString().Split('\n')))
  315. WriteLine("/// " + docLine.TrimStart().TrimEnd('\r'));
  316. if (requiresQueryProvider)
  317. WriteLine("/// <remarks>This operator requires the source's <see cref=\"IQbservableProvider\"/> object (see <see cref=\"IQbservable.Provider\"/>) to implement <see cref=\"IQueryProvider\"/>.</remarks>");
  318. }
  319. if (isExp)
  320. WriteLine("[Experimental]");
  321. if (obsolete != null)
  322. WriteLine("[Obsolete(\"" + obsolete.Message + "\")]");
  323. WriteLine("public static " + retStr + " " + name + g + "(" + string.Join(", ", pars) + ")");
  324. if (isGenFep)
  325. {
  326. WriteLine("#if !NO_EVENTARGS_CONSTRAINT", true);
  327. Indent();
  328. WriteLine("where TEventArgs : EventArgs");
  329. Outdent();
  330. WriteLine("#endif", true);
  331. }
  332. else
  333. {
  334. var genCons = (from a in m.GetGenericArguments()
  335. from c in a.GetGenericParameterConstraints()
  336. select new { a, c })
  337. .ToList();
  338. if (genCons.Count > 0)
  339. {
  340. Indent();
  341. foreach (var gc in genCons)
  342. WriteLine("where " + gc.a.Name + " : " + gc.c.Name);
  343. Outdent();
  344. }
  345. }
  346. WriteLine("{");
  347. Indent();
  348. foreach (var n in nulls)
  349. {
  350. WriteLine("if (" + n + " == null)");
  351. Indent();
  352. WriteLine("throw new ArgumentNullException(\"" + n + "\");");
  353. Outdent();
  354. }
  355. WriteLine("");
  356. var gArg = ret.GetGenericArguments().Single().ToString2();
  357. if (isNonGenFep && r == 1)
  358. {
  359. gArg = gArg.Replace("EventPattern<EventArgs>", "EventPattern<object>");
  360. }
  361. WriteLine("return " + factory + ".CreateQuery<" + gArg + ">(");
  362. Indent();
  363. WriteLine("Expression.Call(");
  364. Indent();
  365. WriteLine("null,");
  366. var cma = args.Count > 0 ? "," : "";
  367. WriteLine("#if CRIPPLED_REFLECTION", true);
  368. WriteLine("InfoOf(() => " + typeName + "." + name + g + "(" + string.Join(", ", ptps.Select(pt => "default(" + pt + ")")) + "))" + cma);
  369. WriteLine("#else", true);
  370. if (!m.IsGenericMethod)
  371. WriteLine("(MethodInfo)MethodInfo.GetCurrentMethod()" + cma);
  372. else
  373. WriteLine("((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(" + string.Join(", ", m.GetGenericArguments().Select(ga => "typeof(" + ga.Name + ")").ToArray()) + ")" + cma);
  374. WriteLine("#endif", true);
  375. for (int j = 0; j < args.Count; j++)
  376. WriteLine(args[j] + (j < args.Count - 1 ? "," : ""));
  377. Outdent();
  378. WriteLine(")");
  379. Outdent();
  380. WriteLine(");");
  381. Outdent();
  382. WriteLine("}");
  383. if (isNonGenFep && r == 1)
  384. WriteLine("#endif", true);
  385. }
  386. if (poundIf)
  387. WriteLine("#endif", true);
  388. if (isExp)
  389. WriteLine("#endif", true);
  390. if (isLargeArity)
  391. WriteLine("#endif", true);
  392. WriteLine("");
  393. }
  394. if (includeAsync)
  395. {
  396. GenerateAsync(docs, typeName);
  397. }
  398. Outdent();
  399. WriteLine(
  400. @"}");
  401. Outdent();
  402. WriteLine(
  403. @"}
  404. ");
  405. WriteLine(
  406. @"#endif
  407. ");
  408. WriteLine(
  409. @"#pragma warning restore 1591
  410. ");
  411. }
  412. static bool ContainsTask(Type t)
  413. {
  414. if (t == typeof(Task))
  415. return true;
  416. if (t.IsGenericType)
  417. {
  418. if (t.GetGenericTypeDefinition() == typeof(Task<>))
  419. return true;
  420. return t.GetGenericArguments().Any(ContainsTask);
  421. }
  422. if (t.IsArray)
  423. return ContainsTask(t.GetElementType());
  424. return false;
  425. }
  426. static void GenerateAsync(IDictionary<string, XElement> docs, string typeName)
  427. {
  428. foreach (var ret in new[] { "Unit", "TResult" })
  429. {
  430. for (int i = 0; i <= 16; i++)
  431. {
  432. if (i == 5)
  433. WriteLine("#if !NO_LARGEARITY", true);
  434. foreach (var withScheduler in new[] { false, true })
  435. {
  436. var genArgs = default(string[]);
  437. var lamPars = default(string[]);
  438. if (i == 0)
  439. {
  440. genArgs = new string[0];
  441. lamPars = new string[0];
  442. }
  443. //else if (i == 1)
  444. //{
  445. // genArgs = new[] { "TSource" };
  446. // lamPars = new[] { "t" };
  447. //}
  448. else
  449. {
  450. genArgs = Enumerable.Range(1, i).Select(j => "TArg" + j).ToArray();
  451. lamPars = Enumerable.Range(1, i).Select(j => "t" + j).ToArray();
  452. }
  453. var fParam = ret == "Unit" ? "action" : "function";
  454. var gConst = ret == "Unit" ? "Action" : "Func";
  455. var retType = "Func<" + string.Join(", ", genArgs.Concat(new[] { "IQbservable<" + ret + ">" }).ToArray()) + ">";
  456. if (ret != "Unit")
  457. genArgs = genArgs.Concat(new[] { "TResult" }).ToArray();
  458. var docName = "M:System.Reactive.Linq.Observable.ToAsync";
  459. if (genArgs.Length > 0)
  460. docName += "``" + genArgs.Length;
  461. var docArg = ret == "Unit" ? "System.Action" : "System.Func";
  462. if (genArgs.Length > 0)
  463. docArg += "{" + string.Join(",", Enumerable.Range(0, genArgs.Length).Select(j => "``" + j)) + "}";
  464. docName += "(" + docArg + (withScheduler ? ",System.Reactive.Concurrency.IScheduler" : "") + ")";
  465. var xmlDoc = default(XElement);
  466. if (!docs.TryGetValue(docName, out xmlDoc))
  467. {
  468. Console.ForegroundColor = ConsoleColor.Yellow;
  469. Console.WriteLine("Missing XML documentation for {0}", docName);
  470. Console.ResetColor();
  471. }
  472. var actType = "Expression<" + gConst + (genArgs.Length > 0 ? "<" + string.Join(", ", genArgs) + ">" : "") + ">";
  473. var genArgss = genArgs.Length > 0 ? "<" + string.Join(", ", genArgs) + ">" : "";
  474. if (xmlDoc != null)
  475. {
  476. foreach (var docLine in xmlDoc.Element("summary").ToString().Split('\n'))
  477. WriteLine("/// " + docLine.TrimStart().TrimEnd('\r'));
  478. WriteLine("/// <param name=\"provider\">Query provider used to construct the IQbservable&lt;T&gt; data source.</param>");
  479. foreach (var docLine in xmlDoc.Elements().Where(e => e.Name != "summary").SelectMany(e => e.ToString().Split('\n')))
  480. WriteLine("/// " + docLine.TrimStart().TrimEnd('\r'));
  481. }
  482. WriteLine("public static " + retType + " ToAsync" + genArgss + "(this IQbservableProvider provider, " + actType + " " + fParam + (withScheduler ? ", IScheduler scheduler" : "") + ")");
  483. WriteLine("{");
  484. Indent();
  485. WriteLine("if (provider == null)");
  486. Indent();
  487. WriteLine("throw new ArgumentNullException(\"provider\");");
  488. Outdent();
  489. WriteLine("if (" + fParam + " == null)");
  490. Indent();
  491. WriteLine("throw new ArgumentNullException(\"" + fParam + "\");");
  492. Outdent();
  493. if (withScheduler)
  494. {
  495. WriteLine("if (scheduler == null)");
  496. Indent();
  497. WriteLine("throw new ArgumentNullException(\"scheduler\");");
  498. Outdent();
  499. }
  500. WriteLine("");
  501. WriteLine("#if CRIPPLED_REFLECTION", true);
  502. var aprs = new List<string> { "IQbservableProvider", actType };
  503. if (withScheduler)
  504. aprs.Add("IScheduler");
  505. WriteLine("var m = InfoOf(() => " + typeName + ".ToAsync" + genArgss + "(" + string.Join(", ", aprs.Select(pt => "default(" + pt + ")")) + "));");
  506. WriteLine("#else", true);
  507. if (genArgs.Length == 0)
  508. WriteLine("var m = (MethodInfo)MethodInfo.GetCurrentMethod();");
  509. else
  510. WriteLine("var m = ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(" + string.Join(", ", genArgs.Select(a => "typeof(" + a + ")").ToArray()) + ");");
  511. WriteLine("#endif", true);
  512. WriteLine("return (" + string.Join(", ", lamPars) + ") => provider.CreateQuery<" + ret + ">(");
  513. Indent();
  514. WriteLine("Expression.Invoke(");
  515. Indent();
  516. WriteLine("Expression.Call(");
  517. Indent();
  518. WriteLine("null,");
  519. WriteLine("m,");
  520. WriteLine("Expression.Constant(provider, typeof(IQbservableProvider)),");
  521. WriteLine(fParam + (withScheduler ? "," : ""));
  522. if (withScheduler)
  523. WriteLine("Expression.Constant(scheduler, typeof(IScheduler))");
  524. Outdent();
  525. WriteLine(")" + (lamPars.Length > 0 ? "," : ""));
  526. var k = 0;
  527. foreach (var e in genArgs.Zip(lamPars, (g, l) => new { g, l }))
  528. {
  529. WriteLine("Expression.Constant(" + e.l + ", typeof(" + e.g + "))" + (k < i - 1 ? "," : ""));
  530. k++;
  531. }
  532. Outdent();
  533. WriteLine(")");
  534. Outdent();
  535. WriteLine(");");
  536. Outdent();
  537. WriteLine("}");
  538. WriteLine("");
  539. }
  540. if (i == 16)
  541. WriteLine("#endif", true);
  542. }
  543. }
  544. WriteLine("");
  545. foreach (var ret in new[] { "Unit", "TResult" })
  546. {
  547. for (int i = 0; i < 15; i++)
  548. {
  549. if (i == 3)
  550. WriteLine("#if !NO_LARGEARITY", true);
  551. var genArgs = default(string[]);
  552. var lamPars = default(string[]);
  553. if (i == 0)
  554. {
  555. genArgs = new string[0];
  556. lamPars = new string[0];
  557. }
  558. else
  559. {
  560. genArgs = Enumerable.Range(1, i).Select(j => "TArg" + j).ToArray();
  561. lamPars = Enumerable.Range(1, i).Select(j => "t" + j).ToArray();
  562. }
  563. var fParam = ret == "Unit" ? "action" : "function";
  564. var retType = "Func<" + string.Join(", ", genArgs.Concat(new[] { "IQbservable<" + ret + ">" }).ToArray()) + ">";
  565. var begType = "Expression<Func<" + string.Join(", ", genArgs.Concat(new[] { "AsyncCallback", "object", "IAsyncResult" }).ToArray()) + ">>";
  566. var endType = ret == "Unit" ? "Expression<Action<IAsyncResult>>" : "Expression<Func<IAsyncResult, TResult>>";
  567. if (ret != "Unit")
  568. genArgs = genArgs.Concat(new[] { "TResult" }).ToArray();
  569. var docName = "M:System.Reactive.Linq.Observable.FromAsyncPattern";
  570. if (genArgs.Length > 0)
  571. docName += "``" + genArgs.Length;
  572. if (ret == "Unit")
  573. {
  574. var docArgB = "System.Func{" + string.Join(",", Enumerable.Range(0, genArgs.Length).Select(j => "``" + j)) + (genArgs.Length > 0 ? "," : "") + "System.AsyncCallback,System.Object,System.IAsyncResult}";
  575. var docArgE = "System.Action{System.IAsyncResult}";
  576. docName += "(" + docArgB + "," + docArgE + ")";
  577. }
  578. else
  579. {
  580. var docArgB = "System.Func{" + string.Join(",", Enumerable.Range(0, genArgs.Length - 1).Select(j => "``" + j)) + (genArgs.Length > 1 ? "," : "") + "System.AsyncCallback,System.Object,System.IAsyncResult}";
  581. var docArgE = "System.Func{System.IAsyncResult,``" + (genArgs.Length - 1) + "}";
  582. docName += "(" + docArgB + "," + docArgE + ")";
  583. }
  584. var xmlDoc = default(XElement);
  585. if (!docs.TryGetValue(docName, out xmlDoc))
  586. {
  587. Console.ForegroundColor = ConsoleColor.Yellow;
  588. Console.WriteLine("Missing XML documentation for {0}", docName);
  589. Console.ResetColor();
  590. }
  591. var genArgss = genArgs.Length > 0 ? "<" + string.Join(", ", genArgs) + ">" : "";
  592. if (xmlDoc != null)
  593. {
  594. foreach (var docLine in xmlDoc.Element("summary").ToString().Split('\n'))
  595. WriteLine("/// " + docLine.TrimStart().TrimEnd('\r'));
  596. WriteLine("/// <param name=\"provider\">Query provider used to construct the IQbservable&lt;T&gt; data source.</param>");
  597. foreach (var docLine in xmlDoc.Elements().Where(e => e.Name != "summary").SelectMany(e => e.ToString().Split('\n')))
  598. WriteLine("/// " + docLine.TrimStart().TrimEnd('\r'));
  599. }
  600. WriteLine("#if PREFERASYNC", true);
  601. WriteLine("[Obsolete(Constants_Linq.USE_TASK_FROMASYNCPATTERN)]");
  602. WriteLine("#endif", true);
  603. WriteLine("public static " + retType + " FromAsyncPattern" + genArgss + "(this IQbservableProvider provider, " + begType + " begin, " + endType + "end)");
  604. WriteLine("{");
  605. Indent();
  606. WriteLine("if (provider == null)");
  607. Indent();
  608. WriteLine("throw new ArgumentNullException(\"provider\");");
  609. Outdent();
  610. WriteLine("if (begin == null)");
  611. Indent();
  612. WriteLine("throw new ArgumentNullException(\"begin\");");
  613. Outdent();
  614. WriteLine("if (end == null)");
  615. Indent();
  616. WriteLine("throw new ArgumentNullException(\"end\");");
  617. Outdent();
  618. WriteLine("");
  619. WriteLine("#if CRIPPLED_REFLECTION", true);
  620. var aprs = new List<string> { "IQbservableProvider", begType, endType };
  621. WriteLine("var m = InfoOf(() => " + typeName + ".FromAsyncPattern" + genArgss + "(" + string.Join(", ", aprs.Select(pt => "default(" + pt + ")")) + "));");
  622. WriteLine("#else", true);
  623. if (genArgs.Length == 0)
  624. WriteLine("var m = (MethodInfo)MethodInfo.GetCurrentMethod();");
  625. else
  626. WriteLine("var m = ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(" + string.Join(", ", genArgs.Select(a => "typeof(" + a + ")").ToArray()) + ");");
  627. WriteLine("#endif", true);
  628. WriteLine("return (" + string.Join(", ", lamPars) + ") => provider.CreateQuery<" + ret + ">(");
  629. Indent();
  630. WriteLine("Expression.Invoke(");
  631. Indent();
  632. WriteLine("Expression.Call(");
  633. Indent();
  634. WriteLine("null,");
  635. WriteLine("m,");
  636. WriteLine("Expression.Constant(provider, typeof(IQbservableProvider)),");
  637. WriteLine("begin,");
  638. WriteLine("end");
  639. Outdent();
  640. WriteLine(")" + (lamPars.Length > 0 ? "," : ""));
  641. var k = 0;
  642. foreach (var e in genArgs.Zip(lamPars, (g, l) => new { g, l }))
  643. {
  644. WriteLine("Expression.Constant(" + e.l + ", typeof(" + e.g + "))" + (k < i - 1 ? "," : ""));
  645. k++;
  646. }
  647. Outdent();
  648. WriteLine(")");
  649. Outdent();
  650. WriteLine(");");
  651. Outdent();
  652. WriteLine("}");
  653. WriteLine("");
  654. if (i == 14)
  655. WriteLine("#endif", true);
  656. }
  657. }
  658. }
  659. static TextWriter Out { get; set; }
  660. static int _indent;
  661. static void WriteLine(string s, bool noIndent = false)
  662. {
  663. foreach (var t in s.Split('\n'))
  664. Out.WriteLine((noIndent ? "" : new string(' ', _indent * 4)) + t.TrimEnd('\r'));
  665. }
  666. static void Indent()
  667. {
  668. _indent++;
  669. }
  670. static void Outdent()
  671. {
  672. _indent--;
  673. }
  674. static Type Iconize(this Type type)
  675. {
  676. if (type.IsGenericType && !type.IsGenericTypeDefinition)
  677. {
  678. var g = type.GetGenericTypeDefinition();
  679. if (g == typeof(IObservable<>))
  680. {
  681. return _qbs.MakeGenericType(type.GetGenericArguments());
  682. }
  683. else if (g == typeof(IEnumerable<>))
  684. {
  685. return typeof(IQueryable<>).MakeGenericType(type.GetGenericArguments());
  686. }
  687. }
  688. return type;
  689. }
  690. static string ToString2(this Type type)
  691. {
  692. if (type == typeof(int))
  693. return "int";
  694. else if (type == typeof(uint))
  695. return "uint";
  696. else if (type == typeof(long))
  697. return "long";
  698. else if (type == typeof(ulong))
  699. return "ulong";
  700. else if (type == typeof(float))
  701. return "float";
  702. else if (type == typeof(double))
  703. return "double";
  704. else if (type == typeof(byte))
  705. return "byte";
  706. else if (type == typeof(sbyte))
  707. return "sbyte";
  708. else if (type == typeof(bool))
  709. return "bool";
  710. else if (type == typeof(short))
  711. return "short";
  712. else if (type == typeof(ushort))
  713. return "ushort";
  714. else if (type == typeof(string))
  715. return "string";
  716. else if (type == typeof(object))
  717. return "object";
  718. else if (type == typeof(void))
  719. return "void";
  720. else if (type == typeof(decimal))
  721. return "decimal";
  722. if (type.IsArray)
  723. return type.GetElementType().ToString2() + "[" + new string(',', type.GetArrayRank() - 1) + "]";
  724. if (type.IsGenericType)
  725. {
  726. if (!type.IsGenericTypeDefinition)
  727. {
  728. var g = type.GetGenericTypeDefinition();
  729. if (g == typeof(Nullable<>))
  730. return type.GetGenericArguments()[0].ToString2() + "?";
  731. else
  732. return g.ToString2() + "<" + string.Join(", ", type.GetGenericArguments().Select(t => t.ToString2()).ToArray()) + ">";
  733. }
  734. else
  735. {
  736. var s = type.Name;
  737. return s.Substring(0, s.LastIndexOf('`'));
  738. }
  739. }
  740. return type.Name;
  741. }
  742. static string ToDocName(MethodInfo method)
  743. {
  744. var name = "M:" + ToDocName(method.DeclaringType) + "." + method.Name;
  745. var genArgs = new Type[0];
  746. if (method.IsGenericMethod)
  747. {
  748. genArgs = method.GetGenericArguments();
  749. name += "``" + genArgs.Length;
  750. }
  751. var pars = method.GetParameters();
  752. if (pars.Length > 0)
  753. {
  754. name += "(" + string.Join(",", method.GetParameters().Select(p => ToDocName(p.ParameterType, genArgs))) + ")";
  755. }
  756. return name;
  757. }
  758. static string ToDocName(Type t, params Type[] genArgs)
  759. {
  760. var i = Array.IndexOf(genArgs, t);
  761. if (i >= 0)
  762. return "``" + i;
  763. if (t.IsArray)
  764. {
  765. return ToDocName(t.GetElementType(), genArgs) + "[]";
  766. }
  767. if (t.IsGenericType)
  768. {
  769. var def = t.GetGenericTypeDefinition();
  770. var name = def.FullName.Substring(0, def.FullName.LastIndexOf("`"));
  771. var args = t.GetGenericArguments();
  772. name += "{" + string.Join(",", args.Select(a => ToDocName(a, genArgs))) + "}";
  773. return name;
  774. }
  775. else
  776. {
  777. return t.FullName;
  778. }
  779. }
  780. }
  781. }