void AddCreatorDocs(CodeTypeDeclaration type, CodeMemberMethod method, int w, int n) { var tp = Types.GetTypeParameter(n, w); var idx = XmlDocs.GetIndex(tp); var fold = type.GetMethods("Fold").First(); method.Comments.AddDocs( XmlDocs.Param("value", " A <typeparamref name=\"" + tp + "\" /> containing the value", " to provide to the " + idx, " " + XmlDocs.See(DefaultNamespace, type, fold), " delegate." ), XmlDocs.Summary( " Creates a " + XmlDocs.See(DefaultNamespace, type) + " instance which", " holds a <typeparamref name=\"" + tp + "\" /> value." ), XmlDocs.Returns( " A " + XmlDocs.See(DefaultNamespace, type) + " instance which holds a ", " holds a <typeparamref name=\"" + tp + "\" /> value." ), XmlDocs.Remarks( " <para>", " When", " " + XmlDocs.See(DefaultNamespace, type, fold), " is invoked,", " the returned " + XmlDocs.See(DefaultNamespace, type) + " instance", " will invoke the " + idx + " delegate", " for conversions.", " </para>" ), XmlDocs.ArgumentNullException("value") ); }
void AddFoldDocs(CodeTypeDeclaration type, CodeMemberMethod method, int n) { method.Comments.AddDocs( XmlDocs.TypeParam("TResult", " The type to convert the " + XmlDocs.See(DefaultNamespace, type) + " to." ), GetFoldParametersDocs(type, n), XmlDocs.Summary( " Converts a " + XmlDocs.See(DefaultNamespace, type) + " into a <typeparamref name=\"TResult\" /> value." ), XmlDocs.Returns( " A <typeparamref name=\"TResult\" /> as generated by one", " of the conversion delegate parameters." ), XmlDocs.Remarks( " <para>", " Converts a " + XmlDocs.See(DefaultNamespace, type) + " into a <typeparamref name=\"TResult\" />", " by invoking one of the provided delegate parameters.", " </para>", " <para>", " The parameter which is invoked is predicated upon the internal position of", " the value held. For example, if the internal value is in the first position ", " (i.e. " + XmlDocs.See(DefaultNamespace, type, type.GetMethods(A(0)).First()), " was used to create the " + XmlDocs.See(DefaultNamespace, type) + " instance), then", " <paramref name=\"a\" /> (the first delegate parameter) will be invoked to", " convert the <typeparamref name=\"T1\" /> into a ", " <typeparamref name=\"TResult\" />.", " </para>" ), XmlDocs.ArgumentNullException(Enumerable.Range(0, n).Select(v => a(v))) ); }
void AddEqualsDocs(CodeTypeDeclaration type, CodeMemberMethod method, int n) { var et = XmlDocs.See(DefaultNamespace, type); method.Comments.AddDocs( XmlDocs.Param("obj", "A " + et + "to compare this instance against." ), XmlDocs.Summary( " Determines whether the current instance and the specified " + et + " have the same value." ), XmlDocs.Returns( " <para>", " <see langword=\"true\"/> if each member of <paramref name=\"obj\"/>", " and the current instance have the same value (according to", " <see cref=\"M:System.Object.Equals(System.Object)\"/>); otherwise", " <see langword=\"false\"/> is returned.", " </para>" ), XmlDocs.Remarks( " <para>", " This method checks for value equality", " (<see cref=\"M:System.Object.Equals(System.Object)\"/>), as defined by each", " value type.", " </para>" ) ); }
CodeMemberMethod CreateAggregateMethod(int n) { var retType = new CodeTypeReference("TResult"); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Aggregate", 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 funcType = Types.Func(n); m.Parameters.Add(new CodeParameterDeclarationExpression(funcType, "func")); m.Statements.AddCheck("Self", "self"); m.Statements.AddCheck("Func", "func"); m.Statements.Add( new CodeMethodReturnStatement( new CodeDelegateInvokeExpression( new CodeVariableReferenceExpression("func"), Enumerable.Range(0, n).Select(p => new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("self"), Tuple.Item(n, p))).ToArray()))); var tref = "<see cref=\"T:Cadenza.Tuple{" + Types.GetTypeParameterList(n) + "}\" />"; var props = string.Join(", ", Enumerable.Range(0, n).Select(p => "<see cref=\"P:Cadenza.Tuple`" + n + "." + Tuple.Item(n, p) + "\"/>").ToArray()); m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters), XmlDocs.Param("self", "A " + tref + " to aggregate the values of."), XmlDocs.Param("func", "A " + XmlDocs.See(funcType) + " which will be invoked, providing the values", props, "to <paramref name=\"func\"/> and ", "returning the value returned by <paramref name=\"func\"/>."), XmlDocs.Summary( "Converts the " + tref + " into a <typeparamref name=\"TResult\"/>."), XmlDocs.Returns( "The <typeparamref name=\"TResult\"/> returned by <paramref name=\"func\"/>."), XmlDocs.Remarks( "<para>", " <block subset=\"none\" type=\"behaviors\">", " Passes the values " + props + " to ", " <paramref name=\"func\"/>, returning the value produced by ", " <paramref name=\"func\"/>.", " </block>", "</para>"), XmlDocs.ArgumentNullException(new[] { "self", "func" })); return(m); }
CodeMemberMethod CreateTupleGetHashCodeMethod(int n) { var m = new CodeMemberMethod() { Attributes = MemberAttributes.Override | MemberAttributes.Public, Name = "GetHashCode", ReturnType = new CodeTypeReference(typeof(int)), }; m.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "hc", new CodePrimitiveExpression(0))); for (int i = 0; i < n; ++i) { m.Statements.Add(new CodeSnippetStatement( string.Format(" hc ^= {0}.GetHashCode();", Tuple.Item(n, i)))); } m.Statements.Add( new CodeMethodReturnStatement(new CodeVariableReferenceExpression("hc"))); m.Comments.AddDocs( XmlDocs.Summary("Generates a hash code for the current instance."), XmlDocs.Returns("A <see cref=\"T:System.Int32\"/> containing the hash code for this instance."), XmlDocs.Remarks( "<para>", " <block subset=\"none\" type=\"note\">", " This method overrides <see cref=\"M:System.Object.GetHashCode\"/>.", " </block>", "</para>")); return(m); }
protected static CodeMemberMethod CreateComposeMethod(Func <int, int, int, CodeTypeReference> getSelfType, Func <int, int, int, CodeTypeReference> getRetType, int n, bool tret) { var selfType = getSelfType(n + 1, n, 1); var retType = getRetType(n + 1, 0, n); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Compose", ReturnType = retType, }; for (int i = 0; i < n + 1; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n + 1, i)); } if (tret) { m.TypeParameters.Add("TResult"); } m.Parameters.Add(new CodeParameterDeclarationExpression(selfType, "self")); var composerType = new CodeTypeReference( Types.FuncType(n), Types.GetTypeParameterReferences(n + 1, 0, n + 1, false).ToArray()); m.Parameters.Add(new CodeParameterDeclarationExpression(composerType, "composer")); m.Statements.AddCheck("Self", "self"); m.Statements.AddCheck("Composer", "composer"); var expr = new StringBuilder().Append("("); Values(expr, n, 0, n); expr.Append(") => self (composer ("); Values(expr, n, 0, n); expr.Append("))"); m.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(expr.ToString()))); m.Comments.AddDocs( GetComposeTypeParameters(n, selfType, composerType, tret), XmlDocs.Summary("Creates a " + XmlDocs.See(retType) + " delegate."), XmlDocs.Param("self", "The " + XmlDocs.See(selfType) + " to compose."), XmlDocs.Param("composer", "The " + XmlDocs.See(composerType) + " to compose with <paramref name=\"self\" />."), XmlDocs.Returns( "Returns a " + XmlDocs.See(retType) + " which, when invoked, will", "invoke <paramref name=\"composer\"/> and pass the return value of", "<paramref name=\"composer\" /> to <paramref name=\"self\" />."), XmlDocs.Remarks( "<para>", " Composition is useful for chaining delegates together, so that the", " return value of <paramref name=\"composer\" /> is automatically used as", " the input parameter for <paramref name=\"self\" />.", "</para>", "<code lang=\"C#\">", "Func<int,string> tostring = Lambda.F ((int n) => n.ToString ());", "Func<int, int> doubler = Lambda.F ((int n) => n * 2);", "Func<int, string>", " double_then_tostring = tostring.Compose (doubler);", "Console.WriteLine (double_then_tostring (5));", " // Prints \"10\";</code>"), XmlDocs.ArgumentNullException(new[] { "self", "composer" })); return(m); }
protected static CodeMemberMethod CreateCurryTupleMethod(Func <int, int, CodeTypeReference> getSelfType, Func <int, int, CodeTypeReference> getRetType, int n, int a, bool tret) { var selfType = getSelfType(n, 0); var retType = getRetType(n, a); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Curry", ReturnType = retType, }; for (int i = 0; i < n; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n, i)); } if (tret) { m.TypeParameters.Add("TResult"); } m.Parameters.Add(new CodeParameterDeclarationExpression(selfType, "self")); var valuesType = new CodeTypeReference("Tuple", Types.GetTypeParameterReferences(n, 0, a, false).ToArray()); m.Parameters.Add(new CodeParameterDeclarationExpression(valuesType, "values")); m.Statements.AddCheck("Self", "self"); var expr = new StringBuilder().Append("("); Values(expr, n, a, n); expr.Append(") => self (values.Item1"); for (int i = 1; i < a; ++i) { expr.Append(", ").Append("values.Item" + (i + 1)); } if (a < n) { expr.Append(", "); Values(expr, n, a, n); } expr.Append(")"); m.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(expr.ToString()))); m.Comments.AddDocs( GetTypeParameters(n, selfType), XmlDocs.Summary("Creates a " + XmlDocs.See(retType) + " delegate."), XmlDocs.Param("self", "The " + XmlDocs.See(selfType) + " to curry."), XmlDocs.Param("values", "A value of type " + XmlDocs.See(valuesType) + " which contains the values to fix."), XmlDocs.Returns( "Returns a " + XmlDocs.See(retType) + " which, when invoked, will", "invoke <paramref name=\"self\"/> along with the provided fixed parameters."), XmlDocs.ArgumentNullException("self")); return(m); }
static CodeMemberMethod XF(int args) { var t = new CodeTypeReference("System.Linq.Expressions.Expression", Types.Func(args)); var m = CreateMethod("XF", t, "expr", args, true); m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters, t), XmlDocs.Param("expr", "The " + XmlDocs.See(t) + " to return."), XmlDocs.Summary("Creates a " + XmlDocs.See(t) + " expression tree."), XmlDocs.Returns("Returns <paramref name=\"expr\" />.") ); return(m); }
static CodeMemberMethod F(int args) { var t = Types.Func(args); var m = CreateMethod("F", t, "lambda", args, true); m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters, t), XmlDocs.Param("lambda", "The " + XmlDocs.See(t) + " to return."), XmlDocs.Summary("Creates a " + XmlDocs.See(t) + " delegate."), XmlDocs.Returns("Returns <paramref name=\"lambda\" />.") ); return(m); }
void AddGetHashCodeDocs(CodeTypeDeclaration type, CodeMemberMethod method, int n) { method.Comments.AddDocs( XmlDocs.Summary(" Generates a hash code for the current instance."), XmlDocs.Returns(" A <see cref=\"T:System.Int32\"/> containing the hash code for this instance."), XmlDocs.Remarks( " <para>", " <block subset=\"none\" type=\"note\">", " This method overrides <see cref=\"M:System.Object.GetHashCode\"/>.", " </block>", " </para>" ) ); }
CodeMemberMethod CreateTupleToStringMethod(int n, CodeTypeDeclaration tuple) { var m = new CodeMemberMethod() { Attributes = MemberAttributes.Override | MemberAttributes.Public, Name = "ToString", ReturnType = new CodeTypeReference(typeof(string)), }; Func <int, CodeMethodInvokeExpression> c = w => new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeThisReferenceExpression(), Tuple.Item(n, w)), "ToString"); var args = new List <CodeExpression> (); args.Add(new CodePrimitiveExpression("(")); args.Add(c(0)); for (int i = 1; i < n; ++i) { args.Add(new CodePrimitiveExpression(", ")); args.Add(c(i)); } args.Add(new CodePrimitiveExpression(")")); m.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeTypeReferenceExpression(typeof(string)), "Concat"), args.ToArray()))); m.Comments.AddDocs( XmlDocs.Summary("Returns a <see cref=\"T:System.String\"/> representation of the value of the current instance."), XmlDocs.Returns("A <see cref=\"T:System.String\"/> representation of the value of the current instance."), XmlDocs.Remarks( "<para>", " <block subset=\"none\" type=\"behaviors\">", " Returns <c>(</c>, followed by a comma-separated list of the result of", " calling <see cref=\"M:System.Object.ToString\"/> on", Enumerable.Range(0, n).Select(p => XmlDocs.See(DefaultNamespace, tuple, tuple.Members.OfType <CodeMemberProperty>().First(v => v.Name == Tuple.Item(n, p))) + ", "), " followed by <c>)</c>.", " </block>", "</para>")); return(m); }
IEnumerable <string> GetCreators(CodeTypeDeclaration type, int n) { var targs = Types.GetTypeParameterList(n); var targsc = string.Join(",", Enumerable.Range(0, n).Select(p => "`" + p).ToArray()); for (int i = 0; i < n; ++i) { yield return(" <item><term><see cref=\"" + XmlDocs.Cref(DefaultNamespace, type, type.GetMethods(A(i)).First()) + "\" /></term></item>"); yield return(" <item><term><see cref=\"M:Cadenza.Either{" + targs + "}.op_Implicit(`" + i + ")~Cadenza.Either{" + targsc + "}\" /></term></item>"); } }
static IEnumerable GetComposeTypeParameters(int n, CodeTypeReference selfType, CodeTypeReference composerType, bool tret) { for (int i = 0; i < n - 1; ++i) { yield return(XmlDocs.TypeParam(Types.GetTypeParameter(n + 1, i), "A " + XmlDocs.See(composerType) + " parameter type.")); } yield return(XmlDocs.TypeParam(Types.GetTypeParameter(n + 1, n), "The " + XmlDocs.See(composerType) + " return type, and " + XmlDocs.See(selfType) + " argument type.")); if (tret) { yield return(XmlDocs.TypeParam("TResult", "The " + XmlDocs.See(selfType) + " return type.")); } }
CodeMemberMethod CreateToEnumerableMethod(int n) { var retType = new CodeTypeReference("System.Collections.Generic.IEnumerable", new CodeTypeReference(typeof(object))); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "ToEnumerable", ReturnType = retType, }; for (int i = 0; i < n; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n, i)); } var selfType = new CodeTypeReference("this Tuple", Types.GetTypeParameterReferences(n, false).ToArray()); m.Parameters.Add(new CodeParameterDeclarationExpression(selfType, "self")); m.Statements.AddCheck("Self", "self"); m.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(new CodeTypeReferenceExpression("TupleCoda"), "CreateToEnumerableIterator"), new CodeVariableReferenceExpression("self")))); var tref = "<see cref=\"T:Cadenza.Tuple{" + Types.GetTypeParameterList(n) + "}\" />"; var props = string.Join(", ", Enumerable.Range(0, n).Select(p => "<see cref=\"P:Cadenza.Tuple`" + n + "." + Tuple.Item(n, p) + "\"/>").ToArray()); m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters), XmlDocs.Param("self", "A " + tref + " to convert into an <see cref=\"T:System.Collections.Generic.IEnumerable{System.Object}\"/>."), XmlDocs.Summary( "Converts the " + tref + " into a <see cref=\"T:System.Collections.Generic.IEnumerable{System.Object}\"/>."), XmlDocs.Returns( "A <see cref=\"T:System.Collections.Generic.IEnumerable{System.Object}\"/>."), XmlDocs.Remarks( "<para>", " <block subset=\"none\" type=\"behaviors\">", " Passes the values " + props + " to ", " <paramref name=\"func\"/>, returning the value produced by ", " <paramref name=\"func\"/>.", " </block>", "</para>"), XmlDocs.ArgumentNullException("self")); return(m); }
protected static CodeMemberMethod CreateCurryMethod(Func <int, int, CodeTypeReference> getSelfType, Func <int, int, CodeTypeReference> getRetType, int n, int a, bool tret) { var selfType = getSelfType(n, 0); var retType = getRetType(n, a); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Curry", ReturnType = retType, }; for (int i = 0; i < n; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n, i)); } if (tret) { m.TypeParameters.Add("TResult"); } m.Parameters.Add(new CodeParameterDeclarationExpression(selfType, "self")); for (int i = 0; i < a; ++i) { m.Parameters.Add(new CodeParameterDeclarationExpression(Types.GetTypeParameter(n, i), Value(n, i))); } m.Statements.AddCheck("Self", "self"); var expr = new StringBuilder().Append("("); Values(expr, n, a, n); expr.Append(") => self ("); Values(expr, n, 0, n); expr.Append(")"); m.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(expr.ToString()))); m.Comments.AddDocs( GetTypeParameters(n, selfType), XmlDocs.Summary("Creates a " + XmlDocs.See(retType) + " delegate."), XmlDocs.Param("self", "The " + XmlDocs.See(selfType) + " to curry."), Enumerable.Range(0, a).Select(p => XmlDocs.Param(Value(n, p), "A value of type <typeparamref name=\"" + Types.GetTypeParameter(n, p) + "\"/> to fix.")), XmlDocs.Returns( "Returns a " + XmlDocs.See(retType) + " which, when invoked, will", "invoke <paramref name=\"self\"/> along with the provided fixed parameters."), XmlDocs.ArgumentNullException("self")); return(m); }
IEnumerable <string> GetFoldParametersDocs(CodeTypeDeclaration type, int n) { for (int i = 0; i < n; ++i) { var tp = Types.GetTypeParameter(n, i); yield return("<param name=\"" + a(i) + "\">"); yield return(" A <see cref=\"T:System.Func{" + tp + ",TResult}\" /> "); yield return(" used if the " + XmlDocs.See(DefaultNamespace, type) + " stores a "); yield return(" <typeparamref name=\"" + tp + "\" /> value into a "); yield return(" <typeparamref name=\"TResult\" /> value."); yield return("</param>"); } }
CodeTypeDeclaration CreateTupleCodaType(int n) { var t = new CodeTypeDeclaration("TupleCoda") { IsClass = true, IsPartial = true, }; for (int i = 1; i <= n; ++i) { t.Members.Add(CreateAggregateMethod(i)); t.Members.Add(CreateMatchMethod(i)); t.Members.Add(CreateToEnumerableMethod(i)); t.Members.Add(CreateCreateToEnumerableIteratorMethod(i)); } t.Comments.AddDocs( XmlDocs.Summary("Extension methods on <c>Tuple</c> types."), XmlDocs.Remarks()); return(t); }
static CodeMemberMethod RecFunc(int args) { var t = Types.Func(args); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Static | MemberAttributes.Public, Name = "RecFunc", ReturnType = t, }; m.TypeParameters.AddRange(Types.GetTypeParameters(args, true).ToArray()); var a = "lambda"; m.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("Func", t, t), a)); m.Statements.ThrowWhenArgumentIsNull(a); var expr = AppendArgs(new StringBuilder(), args); expr.Append(" => lambda (RecFunc (lambda))"); AppendArgs(expr, args); m.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(expr.ToString()))); m.Comments.AddRange("From: http://blogs.msdn.com/madst/archive/2007/05/11/recursive-lambda-expressions.aspx"); m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters, t), XmlDocs.Param("lambda", "The " + XmlDocs.See(t) + " to use."), XmlDocs.Summary("Creates a " + XmlDocs.See(t) + " delegate, which may be recursive."), XmlDocs.Returns("Returns a " + XmlDocs.See(t) + " which (eventually) invokes <paramref name=\"lambda\"/>."), XmlDocs.ArgumentNullException("lambda"), XmlDocs.Remarks( "<para>", " The following example makes use of a recursive lambda:", "</para>", "<code lang=\"C#\">", " Func<int, int> factorial = Lambda.RecFunc<int, int> (".Replace("<", "<"), " fac => x => x == 0 ? 1 : x * fac (x-1));", " Console.WriteLine (factorial (5)); // prints \"120\"", "</code>" ) ); return(m); }
CodeMemberMethod CreateCreateMethod(int n) { var retType = new CodeTypeReference("Cadenza.Tuple", Types.GetTypeParameterReferences(n, false).ToArray()); var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Create", ReturnType = retType, }; for (int i = 0; i < n; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n, i)); } for (int i = 0; i < n; ++i) { m.Parameters.Add( new CodeParameterDeclarationExpression( new CodeTypeReference(Types.GetTypeParameter(n, i)), Tuple.item(n, i))); } m.Statements.Add( new CodeMethodReturnStatement( new CodeObjectCreateExpression( new CodeTypeReference("Cadenza.Tuple", Types.GetTypeParameterReferences(n, false).ToArray()), Enumerable.Range(0, n).Select(p => new CodeVariableReferenceExpression(Tuple.item(n, p))).ToArray()))); var tcref = "Cadenza.Tuple{" + Types.GetTypeParameterList(n) + "}"; m.Comments.AddDocs( Enumerable.Range(0, n).Select(p => XmlDocs.TypeParam(Types.GetTypeParameter(n, p), string.Format("The {0} <see cref=\"T:{1}\" /> value type.", XmlDocs.GetIndex(p), tcref))), XmlDocs.Summary("Creates a <see cref=\"" + tcref + "\" />."), Enumerable.Range(0, n).Select(p => XmlDocs.Param(Tuple.item(n, p), string.Format("The {0} <see cref=\"T:{1}\" /> value.", XmlDocs.GetIndex(p), tcref))), XmlDocs.Returns( "A <see cref=\"T:" + tcref + "\" /> initialized with the parameter values."), "<seealso cref=\"C:" + tcref + "(" + string.Join(",", Enumerable.Range(0, n) .Select(p => "`" + p.ToString()).ToArray()) + ")\" />"); return(m); }
protected virtual void AppendTypeName(CodeTypeReference type) { Cref.Append(XmlDocs.GetType(type)); }
CodeTypeDeclaration CreateTupleCreatorType(int n) { var tuple = new CodeTypeDeclaration("Tuple") { TypeAttributes = TypeAttributes.Public, IsPartial = true, }; AddConditionalCompilationDirective(tuple, "!NET_4_0"); var maxValues = new CodeMemberProperty() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "MaxValues", Type = new CodeTypeReference(typeof(int)), HasGet = true, HasSet = false, }; maxValues.GetStatements.Add( new CodeMethodReturnStatement(new CodePrimitiveExpression(n))); maxValues.Comments.AddDocs( XmlDocs.Summary("The maximum number of Tuple types provided."), "<value>", " The maximum number of Tuple types provided.", "</value>", XmlDocs.Remarks( " <para>", " Only tuples up to a certain \"arity\" are supported; for example,", " a <c>Tuple<T1, T2, ..., T100></c> isn't supported (and won't", " likely ever be).", " </para>", " <para>", " <see cref=\"P:Cadenza.Tuple.MaxValues\" /> is the maximum number of", " values that the Tuple types support. If you need to support", " more values, then you need to either live with potential boxing", " and use a e.g. <see cref=\"T:System.Collections.Generic.List{System.Object}\" />", " or nest Tuple instantiations, e.g. ", " <c>Tuple<int, Tuple<int, Tuple<int, Tuple<int, int>>>></c>.", " The problem with such nesting is that it becomes \"unnatural\" to access ", " later elements -- <c>t._2._2._2._2</c> to access the fifth value for", " the previous example.", " </para>")); tuple.Members.Add(maxValues); for (int i = 0; i < n; ++i) { tuple.Members.Add(CreateCreateMethod(i + 1)); } tuple.Comments.AddDocs( XmlDocs.Summary("Utility methods to create Tuple instances."), XmlDocs.Remarks( "<para>", " Provides a set of <see cref=\"M:Cadenza.Tuple.Create\"/> methods so that", " C# type inferencing can easily be used with tuples. For example,", " instead of:", "</para>", "<code lang=\"C#\">", "Tuple<int, long> a = new Tuple<int, long> (1, 2L);</code>", "<para>You can instead write:</para>", "<code lang=\"C#\">", "Tuple<int, long> b = Tuple.Create (1, 2L);", "// or", "var c = Tuple.Create (1, 2L);</code>")); return(tuple); }
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); }
protected static IEnumerable <IEnumerable <string> > GetTypeParameters(int n, CodeTypeReference selfType) { return(Enumerable.Range(0, n).Select(p => XmlDocs.TypeParam(Types.GetTypeParameter(n, p), "A " + XmlDocs.See(selfType) + " parameter type."))); }
protected static CodeMemberMethod CreateTraditionalCurryMethod(Func <int, int, CodeTypeReference> getSelfType, Func <int, int, CodeTypeReference> getRetType, int n, bool tret) { var selfType = getSelfType(n, 0); var retType = getRetType(n, n - 1); for (int i = n - 2; i >= 0; --i) { retType = new CodeTypeReference("System.Func", new CodeTypeReference(Types.GetTypeParameter(n, i)), retType); } var m = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "Curry", ReturnType = retType, }; for (int i = 0; i < n; ++i) { m.TypeParameters.Add(Types.GetTypeParameter(n, i)); } if (tret) { m.TypeParameters.Add("TResult"); } m.Parameters.Add(new CodeParameterDeclarationExpression(selfType, "self")); m.Statements.AddCheck("Self", "self"); var expr = new StringBuilder(); for (int i = 0; i < n; ++i) { expr.Append(Value(n, i)).Append(" => "); } expr.Append("self ("); Values(expr, n, 0, n); expr.Append(")"); m.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(expr.ToString()))); var retDocs = new StringBuilder(); if (retType.TypeArguments.Count > 1) { var rt = retType.TypeArguments [1]; while (rt != null && rt.TypeArguments.Count > 1) { retDocs.Append("return a ").Append(XmlDocs.See(rt)).Append(" which, when invoked, will "); rt = rt.TypeArguments [1]; } if (rt.TypeArguments.Count > 0) { retDocs.Append("return a ").Append(XmlDocs.See(rt)).Append(" which, when invoked, will "); } } m.Comments.Add(new CodeCommentStatement("Currying method idea courtesy of:")); m.Comments.Add(new CodeCommentStatement("http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx")); m.Comments.AddDocs( XmlDocs.TypeParams(m.TypeParameters), XmlDocs.Param("self", "The " + XmlDocs.See(selfType) + " to curry."), XmlDocs.Summary("Creates a " + XmlDocs.See(retType) + " for currying."), XmlDocs.Returns( "A " + XmlDocs.See(retType) + " which, when invoked, will ", retDocs.ToString(), "invoke <paramref name=\"self\"/>."), XmlDocs.Remarks( "<para>", " This is the more \"traditional\" view of currying, turning a method", " which takes <c>(X * Y)->Z</c> (i.e. separate arguments) into a", " <c>X -> (Y -> Z)</c> (that is a \"chain\" of nested Funcs such that", " you provide only one argument to each Func until you provide enough", " arguments to invoke the original method).", "</para>", "<code lang=\"C#\">", "Func<int,int,int,int> function = (int a, int b, int c) => a + b + c;", "Func<int,Func<int,Func<int, int>>> curry = function.Curry ();", "Assert.AreEqual(6, curry (3)(2)(1));</code>"), XmlDocs.ArgumentNullException("self")); 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); }
CodeMemberMethod CreateTupleEqualsMethod(int n, CodeTypeDeclaration tuple) { var m = new CodeMemberMethod() { Attributes = MemberAttributes.Override | MemberAttributes.Public, Name = "Equals", ReturnType = new CodeTypeReference(typeof(bool)), }; var t = "Tuple<" + Types.GetTypeParameterList(n) + ">"; m.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "obj")); m.Statements.Add(new CodeSnippetStatement(string.Format(" {0} o = obj as {0};", t))); m.Statements.Add(new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeVariableReferenceExpression("o"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(null)), new CodeMethodReturnStatement(new CodePrimitiveExpression(false)))); Func <int, CodeMethodInvokeExpression> c = w => new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeTypeReferenceExpression( new CodeTypeReference("System.Collections.Generic.EqualityComparer", new CodeTypeReference(new CodeTypeParameter(Types.GetTypeParameter(n, w))))), "Default"), "Equals", new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), Tuple.item(n, w)), new CodeFieldReferenceExpression( new CodeVariableReferenceExpression("o"), Tuple.item(n, w))); CodeExpression pred = c(0); for (int i = 1; i < n; ++i) { pred = new CodeBinaryOperatorExpression( pred, CodeBinaryOperatorType.BooleanAnd, c(i)); } m.Statements.Add( new CodeMethodReturnStatement(pred)); m.Comments.AddDocs( XmlDocs.Param("obj", "A <see cref=\"T:System.Object\"/> to compare this instance against."), XmlDocs.Summary("Determines whether the current instance and the specified object have the same value."), XmlDocs.Returns( "<para>", " <see langword=\"true\"/> if <paramref name=\"obj\"/> is a", " " + XmlDocs.See(DefaultNamespace, tuple) + " and each member of <paramref name=\"obj\"/>", " and the current instance have the same value (according to", " <see cref=\"M:System.Collections.Generic.EqualityComparer{T}.Equals(`0,`0)\" />); otherwise", " <see langword=\"false\"/> is returned.", "</para>"), XmlDocs.Remarks( "<para>", " This method checks for value equality", " (<see cref=\"M:System.Collections.Generic.EqualityComparer{T}.Equals(`0,`0)\" />), as defined by each", " value type.", "</para>", "<para>", " <block subset=\"none\" type=\"note\">", " This method overrides <see cref=\"M:System.Object.Equals(System.Object)\"/>.", " </block>", "</para>")); return(m); }
CodeTypeDeclaration CreateTupleType(int n) { var tuple = new CodeTypeDeclaration("Tuple") { TypeAttributes = TypeAttributes.Public, IsPartial = true, }; AddConditionalCompilationDirective(tuple, "!NET_4_0"); for (int i = 0; i < n; ++i) { tuple.TypeParameters.Add(Types.GetTypeParameter(n, i)); tuple.Members.Add(new CodeMemberField(Types.GetTypeParameter(n, i), Tuple.item(n, i))); var p = new CodeMemberProperty() { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = Tuple.Item(n, i), HasGet = true, HasSet = false, Type = new CodeTypeReference(Types.GetTypeParameter(n, i)), }; p.GetStatements.Add( new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), Tuple.item(n, i)))); p.Comments.AddDocs( XmlDocs.Summary(string.Format("The {0} tuple value.", XmlDocs.GetIndex(i))), XmlDocs.Value("A <typeparamref name=\"" + Types.GetTypeParameter(n, i) + "\" /> which is the " + XmlDocs.GetIndex(i) + " tuple value."), XmlDocs.Remarks(string.Format("The {0} tuple value.", XmlDocs.GetIndex(i)))); tuple.Members.Add(p); } var c = new CodeConstructor() { Attributes = MemberAttributes.Public, }; for (int i = 0; i < n; ++i) { c.Parameters.Add(new CodeParameterDeclarationExpression(Types.GetTypeParameter(n, i), Tuple.item(n, i))); c.Statements.Add(new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), Tuple.item(n, i)), new CodeVariableReferenceExpression(Tuple.item(n, i)))); } tuple.Members.Add(c); c.Comments.AddDocs( XmlDocs.Summary("Constructs and initializes a new " + XmlDocs.See(DefaultNamespace, tuple) + " instance."), Enumerable.Range(0, n).Select(p => XmlDocs.Param(Tuple.item(n, p), "A <typeparamref name=\"" + Types.GetTypeParameter(n, p) + "\"/> which is used to initialize the " + XmlDocs.See(DefaultNamespace, tuple, tuple.Members.OfType <CodeMemberProperty>().First(v => v.Name == Tuple.Item(n, p))) + " property.")), XmlDocs.Remarks( "<para>", " Constructs and initializes a new " + XmlDocs.See(DefaultNamespace, tuple) + " instance.", "</para>")); tuple.Members.Add(CreateTupleEqualsMethod(n, tuple)); tuple.Members.Add(CreateTupleGetHashCodeMethod(n)); tuple.Members.Add(CreateTupleToStringMethod(n, tuple)); tuple.Comments.AddDocs( XmlDocs.TypeParams(tuple.TypeParameters), XmlDocs.Summary("A strongly-typed sequence of " + n + " variously typed values."), XmlDocs.Remarks( "<para>", " A <c>Tuple</c> is an immutable, strongly typed sequence of variously", " typed values with each value lacking an otherwise meaningful name aside", " from its position.", "</para>")); return(tuple); }
CodeTypeDeclaration CreateEither(int n) { var either = new CodeTypeDeclaration("Either") { TypeAttributes = TypeAttributes.Public | TypeAttributes.Abstract, }; either.BaseTypes.Add(new CodeTypeReference("IEquatable", GetEitherType(n))); either.TypeParameters.AddRange(Types.GetTypeParameters(n, false)); either.Members.Add(new CodeConstructor() { Attributes = MemberAttributes.Private, }); for (int i = 0; i < n; ++i) { either.Members.Add(CreateImplicitCreator(either, i, n)); either.Members.Add(CreateCreator(either, i, n)); } either.Members.Add(CreateFold(either, n)); either.Members.Add(CreateCheckFolders(n)); either.Members.Add(CreateEqualsObject()); either.Members.Add(CreateEquals(n)); either.Members.Add(CreateGetHashCode()); for (int i = 0; i < n; ++i) { either.Members.Add(CreateHandler(i, n)); } either.Comments.AddDocs( XmlDocs.TypeParams(either.TypeParameters), XmlDocs.Summary("A union of " + n + " values."), "<remarks>", " <para>", " An <c>Either</c> is an immutable, strongly typed union of variously ", " typed values with each value lacking an otherwise meaningful name aside ", " from its position, which is not exposed. It stores only one (non-null) ", " value from a set of types (as determined by the type parameter list).", " </para>", " <para>", " The value held by a " + XmlDocs.See(DefaultNamespace, either) + " instance", " can be converted into a value by using the ", " <see cref=\"" + XmlDocs.Cref(DefaultNamespace, either, either.GetMethods("Fold").First()) + "\" /> method.", " <c>Fold</c> takes a list of delegates to perform the conversion; the", " delegate used to perform the conversion is based upon the internal ", " position of the value stored.", " </para>", " <para>", " <c>Either</c> instances are created through one of the following", " creation methods:", " </para>", " <list type=\"bullet\">", GetCreators(either, n), " </list>", " <code lang=\"C#\">", " var a = Either<double, string>.A (Math.PI); // value stored in 1st position", " ", " int r = a.Fold (", " v => (int) v, // 1st position converter", " v => v.Length); // 2nd position converter", " ", " Console.WriteLine (r); // prints 3", " ", " // alternatively...", " Either<double, string> b = \"value\"; // value stored in 2nd position", " Console.WriteLine (b.Fold (v => v.ToString(), v => v));", " // prints \"value\"</code>", "</remarks>" ); for (int i = 0; i < n; ++i) { AddCreatorDocs(either, either.GetMethods(A(i)).First(), i, n); } AddFoldDocs(either, either.GetMethods("Fold").First(), n); AddEqualsObjectDocs(either, either.GetMethods("Equals").First(m => m.Parameters [0].Type.BaseType == "System.Object"), n); AddEqualsDocs(either, either.GetMethods("Equals").First(m => m.Parameters [0].Type.BaseType != "System.Object"), n); AddGetHashCodeDocs(either, either.GetMethods("GetHashCode").First(), n); return(either); }
static IEnumerable GetTimingsParameters(int n) { return(Enumerable.Range(0, n).Select(p => XmlDocs.Param(Value(n, p), "The " + XmlDocs.GetIndex(Value(n, p)) + " <paramref name=\"self\"/> parameter value."))); }
protected override IEnumerable <CodeTypeDeclaration> GetRocksNamespaceTypes() { var dr = new CodeTypeDeclaration("FuncCoda") { IsPartial = true, TypeAttributes = TypeAttributes.Public, }; for (int i = 0; i <= TypeParameterCount; ++i) { dr.Members.AddRange(CreateCurryFuncs(i)); dr.Members.AddRange(CreateCurryTupleFuncs(i)); dr.Members.AddRange(CreateTraditionalCurryFuncs(i)); dr.Members.Add(CreateComposeMethod(Types.ThisFunc, Types.Func, i, true)); } dr.Comments.AddDocs( XmlDocs.Summary( "Provides extension methods on <see cref=\"T:System.Func{TResult}\"/>", "and related delegates."), XmlDocs.Remarks( "<para>", " " + XmlDocs.See(DefaultNamespace, dr) + " provides methods methods for:", "</para>", "<list type=\"bullet\">", " <item><term>", " Delegate currying and partial application (<see cref=\"M:Cadenza.DelegateCoda.Curry\" />)", " </term></item>", " <item><term>", " Delegate composition (<see cref=\"M:Cadenza.DelegateCoda.Compose\" />)", " </term></item>", " <item><term>", " Timing generation (<see cref=\"M:Cadenza.DelegateCoda.Timings\" />)", " </term></item>", "</list>", "<para>", " Currying via partial application is a way to easily transform ", " functions which accept N arguments into functions which accept ", " N-1 arguments, by \"fixing\" arguments with a value.", "</para>", "<code lang=\"C#\">", "// partial application:", "Func<int,int,int,int> function = (int a, int b, int c) => a + b + c;", "Func<int,int,int> f_3 = function.Curry (3);", "Func<int> f_321 = function.Curry (3, 2, 1);", "Console.WriteLine (f_3 (2, 1)); // prints (3 + 2 + 1) == \"6\"", "Console.WriteLine (f_321 ()); // prints (3 + 2 + 1) == \"6\"</code>", "<para>", " \"Traditional\" currying converts a delegate that accepts N arguments", " into a delegate which accepts only one argument, but when invoked may ", " return a further delegate (etc.) until the final value is returned.", "</para>", "<code lang=\"C#\">", "// traditional currying:", "Func<int, Func<int, Func<int, int>>> curry = function.Curry ();", "Func<int, Func<int, int>> fc_1 = curry (1);", "Func<int, int> fc_12 = fc_1 (2);", "Console.WriteLine (fc_12 (3)); // prints (3 + 2 + 1) == \"6\"", "Console.WriteLine (curry (3)(2)(1)); // prints (3 + 2 + 1) == \"6\"</code>", "<para>", " Composition is a way to easy chain (or pipe) together multiple delegates", " so that the return value of a \"composer\" delegate is used as the input ", " parameter for the chained delegate:", "</para>", "<code lang=\"C#\">", "Func<int,string> tostring = Lambda.F ((int n) => n.ToString ());", "Func<int, int> doubler = Lambda.F ((int n) => n * 2);", "Func<int, string>", " double_then_tostring = tostring.Compose (doubler);", "Console.WriteLine (double_then_tostring (5));", " // Prints \"10\";</code>", "<para>", " All possible argument and return delegate permutations are provided", " for the <see cref=\"T:System.Func{T,TResult}\"/> and related types.", "</para>") ); yield return(dr); }