CodeMemberMethod CreateMatchMethod(int n) { var retType = new CodeTypeReference("TResult"); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Match", ReturnType = retType, }; for (int i = 0; i < n; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n, i)); } m.TypeParameters.Add("TResult"); var selfType = new CodeTypeReference("this Tuple", Types.GetTypeParameterReferences(n, false).ToArray()); m.Parameters.Add(new CodeParameterDeclarationExpression(selfType, "self")); var matchersType = new CodeTypeReference( new CodeTypeReference(Types.FuncType(n), Types.GetTypeParameterReferences(n, false) .Concat(new[] { new CodeTypeReference("Cadenza.Maybe", new[] { new CodeTypeReference("TResult") }) }) .ToArray()), 1); var matchersParam = new CodeParameterDeclarationExpression(matchersType, "matchers"); matchersParam.CustomAttributes.Add(new CodeAttributeDeclaration("System.ParamArrayAttribute")); m.Parameters.Add(matchersParam); m.Statements.AddCheck("Self", "self"); m.Statements.ThrowWhenArgumentIsNull("matchers"); var loop = new StringBuilder(); loop.Append(" foreach (var m in matchers) {\n"); loop.Append(" var r = m (self.Item1"); for (int i = 1; i < n; ++i) { loop.Append(", self.").Append(Tuple.Item(n, i)); } loop.Append(");\n"); loop.Append(" if (r.HasValue)\n"); loop.Append(" return r.Value;\n"); loop.Append(" }"); m.Statements.Add(new CodeSnippetStatement(loop.ToString())); m.Statements.Add( new CodeThrowExceptionStatement( new CodeObjectCreateExpression( new CodeTypeReference("System.InvalidOperationException"), new CodePrimitiveExpression("no match")))); var fref = "<see cref=\"T:System.Func{" + Types.GetTypeParameterList(n) + ",Cadenza.Maybe{TResult}}\" />"; var tref = "<see cref=\"T:Cadenza.Tuple{" + Types.GetTypeParameterList(n) + "}\" />"; m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters), XmlDocs.Param("self", "A " + tref + " to match against."), XmlDocs.Param("matchers", "A " + fref, "array containing the conversion routines to use to convert ", "the current " + tref + " instance into a ", "<typeparamref name=\"TResult\" /> value."), XmlDocs.Summary( "Converts the current " + tref + " instance into a <typeparamref name=\"TResult\"/>."), XmlDocs.Returns( "The <typeparamref name=\"TResult\"/> returned by one of the <paramref name=\"matchers\"/>."), XmlDocs.Remarks( "<para>", " <block subset=\"none\" type=\"behaviors\">", " <para>", " The current " + tref + " instance is converted into a ", " <typeparamref name=\"TResult\" /> instance by trying each", " " + fref, " within <paramref name=\"matchers\" />.", " </para>", " <para>", " This method returns ", " <see cref=\"P:Cadenza.Maybe{TResult}.Value\" /> ", " for the first delegate to return a", " <see cref=\"T:Cadenza.Maybe{TResult}\" /> instance", " where <see cref=\"P:Cadenza.Maybe{TResult}.HasValue\" />", " is <see langword=\"true\" />.", " </para>", " <para>", " If no " + fref, " returns a ", " <see cref=\"T:Cadenza.Maybe{TResult}\" /> instance", " where <see cref=\"P:Cadenza.Maybe{TResult}.HasValue\" />", " is <see langword=\"true\" />, then an", " <see cref=\"T:System.InvalidOperationException\" /> is thrown.", " </para>", " </block>", " <code lang=\"C#\">", "var a = Tuple.Create (1, 2);", "string b = a.Match (", " (t, v) => Match.When ( t + v == 3, \"foo!\"),", " (t, v) => \"*default*\".Just ());", "Console.WriteLine (b); // prints \"foo!\"</code>", "</para>"), XmlDocs.ArgumentNullException(new[] { "self", "matchers" }), XmlDocs.Exception(typeof(InvalidOperationException), "None of the ", "<see cref=\"T:System.Func{TSource,Cadenza.Maybe{TResult}}\" />", "delegates within <paramref name=\"matchers\" /> returned a ", "<see cref=\"T:Cadenza.Maybe{TResult}\" /> instance where", "<see cref=\"P:Cadenza.Maybe{TResult}.HasValue\" /> was", "<see langword=\"true\" />.")); return(m); }
CodeMemberMethod AddTimingsDocs(CodeMemberMethod m, int n, CodeTypeDeclaration t, CodeMemberMethod full) { m.Comments.AddDocs( GetTypeParameters(n, m.Parameters [0].Type), XmlDocs.Summary("Get timing information for delegate invocations."), XmlDocs.Param("self", "The " + XmlDocs.See(m.Parameters [0].Type) + " to generate timings for."), GetTimingsParameters(n), XmlDocs.Param("runs", "An <see cref=\"T:System.Int32\" /> containing the number of <see cref=\"T:System.TimeSpan\" /> values to return."), full == null ? XmlDocs.Param("loopsPerRun", "An <see cref=\"T:System.Int32\" /> containing the number of " + "times to invoke <paramref name=\"self\" /> for each " + "<see cref=\"T:System.TimeSpan\" /> value returned.") : new[] { "" }, XmlDocs.Returns( "An " + XmlDocs.See(m.ReturnType), "which will return the timing information for <paramref name=\"self\" />.")); if (full != null) { var alt = new StringBuilder().Append("self.Timing ("); Values(alt, n, 0, n); if (n > 0) { alt.Append(", "); } alt.Append("runs, 1)"); m.Comments.AddDocs( XmlDocs.Remarks( "<para>", " This is equivalent to calling", " " + XmlDocs.See(DefaultNamespace, t, full), " with a <paramref name=\"loopsPerRun\" /> value of <c>1</c>,", " e.g. as if by calling <c>" + alt.ToString() + "</c>.", "</para>"), "<seealso cref=\"" + XmlDocs.Cref(DefaultNamespace, t, full) + "\" />"); } else { m.Comments.AddDocs(XmlDocs.Remarks( "<para>", " Generates <paramref name=\"runs\" /> <see cref=\"T:System.TimeSpan\" />", " instances, in which each <c>TimeSpan</c> instance is the amount of time", " required to execute <paramref name=\"self\" /> for", " <paramref name=\"loopsPerRun\" /> times.", "</para>")); } m.Comments.AddDocs( XmlDocs.Exception(typeof(ArgumentException), "<para>", " <paramref name=\"runs\" /> is negative.", "</para>", full != null ? new object[0] : new object[] { "<para>-or-</para>", "<para>", " <paramref name=\"loopsPerRun\" /> is negative.", "</para>" }), XmlDocs.ArgumentNullException("self")); return(m); }