зеркало из https://github.com/mono/rocks.git
320 строки
11 KiB
Perl
Executable File
320 строки
11 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
use strict;
|
|
use Generator;
|
|
use Getopt::Long;
|
|
|
|
my $n = 1;
|
|
my $namespace = "Mono.Rocks";
|
|
my $output = "Lambdas.cs";
|
|
my $help = undef;
|
|
|
|
GetOptions (
|
|
"n|count=i", \$n,
|
|
"o|output=s", \$output,
|
|
"namespace=s", \$namespace,
|
|
"h|?|help", \$help
|
|
);
|
|
|
|
if ($help) {
|
|
print <<EOF;
|
|
$0 [-n N] [-o FILE] [-h]
|
|
Create a C# file containing C# lambda helper methods.
|
|
|
|
Options:
|
|
-n, --count=N The number of types to generate. Default is 1.
|
|
-o, --output=FILE The file to create. Default is `Tuples.cs'.
|
|
--namespace=NS Place the types within the namespace NS.
|
|
Default is `Mono.Rocks'.
|
|
-h, -?, --help Show this message and exit.
|
|
EOF
|
|
exit 0;
|
|
}
|
|
|
|
if ($n < 1) {
|
|
print STDERR "error: n must be >= 1, was $n\n";
|
|
exit 1;
|
|
}
|
|
|
|
my $handle = *STDOUT;
|
|
|
|
my $g = Generator->new ($handle);
|
|
|
|
my $header = <<EOF;
|
|
//
|
|
// $output: C# Lambda Expression Helpers.
|
|
//
|
|
// GENERATED CODE: DO NOT EDIT.
|
|
//
|
|
// To regenerate this code, execute: $0 -n $n -o $output
|
|
//
|
|
// Copyright (c) 2008 Novell, Inc. (http://www.novell.com)
|
|
EOF
|
|
$g->Write ($header);
|
|
$g->WriteLicense ();
|
|
$g->Write ("using System;\n");
|
|
$g->Write ("using System.Linq.Expressions;\n\n");
|
|
|
|
$g->Namespace ($namespace, sub {
|
|
create_actions ($g, $n);
|
|
|
|
$g->Write ("\n");
|
|
$g->XmlSummary (
|
|
qq(Provides static utility methods to generate anonymous delegates
|
|
or expression trees of pre-determined types.));
|
|
$g->XmlRemarks (
|
|
qq(<para>
|
|
C# lambda methods and anonymous delegates are a curious
|
|
1.5-class citizen: They are implicitly convertable to any
|
|
delegate type, but have no type by themselves. Thus,
|
|
the following code fails to compile:
|
|
</para>
|
|
<code lang="C#">
|
|
((int x) => Console.WriteLine (x))(5);</code>
|
|
<para>It would instead need:</para>
|
|
<code lang="C#">
|
|
// either:
|
|
Action<int> a = x => Console.WriteLine (x);
|
|
a (5);
|
|
//
|
|
// or
|
|
//
|
|
((Action<int>) (x => Console.WriteLine (x)))(5);</code>
|
|
<para>
|
|
So you'd either need to assign the lambda to an actual
|
|
delegate type, or insert a cast.
|
|
</para>
|
|
<para>
|
|
<see cref="M:Mono.Rocks.Lambda.A" /> allows you to
|
|
provide a lambda body for the <see cref="T:System.Action"/>
|
|
builtin delegate type, and <see cref="M:Mono.Rocks.Lambda.F" />
|
|
allows you to provide a lambda body for the
|
|
<see cref="T:System.Func{TResult}"/> delegate type,
|
|
thus removing the need for a cast or an extra variable:
|
|
</para>
|
|
<code lang="C#">
|
|
Lambda.F ((int x) => Console.WriteLine (x)) (5);</code>
|
|
<para>
|
|
<see cref="T:Mono.Rocks.Lambda"/> provides the following sets of
|
|
functionality:
|
|
</para>
|
|
<list type="bullet">
|
|
<item><term>Delegate creation methods, which return
|
|
<see cref="T:System.Action"/>-like delegates:
|
|
<see cref="M:Mono.Rocks.Lambda.A(System.Action)"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.A``1(System.Action{``0})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.A``2(System.Action{``0,``1})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.A``3(System.Action{``0,``1,``2})"/>, and
|
|
<see cref="M:Mono.Rocks.Lambda.A``4(System.Action{``0,``1,``2,``3})"/>.
|
|
</term></item>
|
|
<item><term>Delegate creation methods which return
|
|
return <see cref="T:System.Func{TResult}"/>-like delegates
|
|
<see cref="M:Mono.Rocks.Lambda.F``1(System.Func{``0})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.F``2(System.Func{``0,``1})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.F``3(System.Func{``0,``1,``2})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.F``4(System.Func{``0,``1,``2,``3})"/>, and
|
|
<see cref="M:Mono.Rocks.Lambda.F``5(System.Func{``0,``1,``2,``3,``4})"/>.
|
|
</term></item>
|
|
<item><term><see cref="T:System.Linq.Expressions.Expression"/>-creating methods:
|
|
<see cref="M:Mono.Rocks.Lambda.XA(System.Linq.Expressions.Expression{System.Action})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XA``1(System.Linq.Expressions.Expression{System.Action{``0}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XA``2(System.Linq.Expressions.Expression{System.Action{``0,``1}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XA``3(System.Linq.Expressions.Expression{System.Action{``0,``1,``2}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XA``4(System.Linq.Expressions.Expression{System.Action{``0,``1,``2,``3}})"/>, and
|
|
<see cref="M:Mono.Rocks.Lambda.XF``1(System.Linq.Expressions.Expression{System.Func{``0}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XF``2(System.Linq.Expressions.Expression{System.Func{``0,``1}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XF``3(System.Linq.Expressions.Expression{System.Func{``0,``1,``2}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XF``4(System.Linq.Expressions.Expression{System.Func{``0,``1,``2,``3}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.XF``5(System.Linq.Expressions.Expression{System.Func{``0,``1,``2,``3,``4}})"/>.
|
|
</term></item>
|
|
<item><term>Y-Combinators, which permit writing recursive lambdas:
|
|
<see cref="M:Mono.Rocks.Lambda.RecFunc``2(System.Func{System.Func{``0,``1},System.Func{``0,``1}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.RecFunc``3(System.Func{System.Func{``0,``1,``2},System.Func{``0,``1,``2}})"/>,
|
|
<see cref="M:Mono.Rocks.Lambda.RecFunc``4(System.Func{System.Func{``0,``1,``2,``3},System.Func{``0,``1,``2,``3}})"/>, and
|
|
<see cref="M:Mono.Rocks.Lambda.RecFunc``5(System.Func{System.Func{``0,``1,``2,``3,``4},System.Func{``0,``1,``2,``3,``4}})"/>.
|
|
</term></item>
|
|
</list>
|
|
));
|
|
$g->Type ("public static partial class Lambda", sub {
|
|
|
|
$g->Write ("\n");
|
|
create_func_doc ($g, 0, Generator::GetDocAction (0));
|
|
$g->Method (
|
|
"public static Action ", "A", "Action lambda", "return lambda;\n"
|
|
);
|
|
|
|
$g->Write ("\n");
|
|
create_func_doc ($g, 0, Generator::GetDocFunc (0));
|
|
$g->Method (
|
|
"public static Func<TResult> ", "F<TResult>", "Func<TResult> lambda", "return lambda;\n"
|
|
);
|
|
|
|
$g->Write ("\n");
|
|
create_expr_doc ($g, 0, Generator::GetDocAction (0));
|
|
$g->Method (
|
|
"public static Expression<Action> ", "XA", "Expression<Action> expr", "return expr;\n"
|
|
);
|
|
|
|
$g->Write ("\n");
|
|
create_expr_doc ($g, 0, Generator::GetDocFunc (0));
|
|
$g->Method (
|
|
"public static Expression<Func<TResult>> ", "XF<TResult>", "Expression<Func<TResult>> expr", "return expr;\n"
|
|
);
|
|
for (my $i = 1; $i <= $n; ++$i) {
|
|
$g->Write ("\n");
|
|
create_func_doc ($g, $i, Generator::GetDocAction ($i));
|
|
$g->Method (
|
|
sub {
|
|
$g->Write ("public static ")->Action ($i)
|
|
->Write ("<")->TypeParameterList ($i)->Write (">");
|
|
},
|
|
sub { $g->Write ("\n\tA<")->TypeParameterList ($i)->Write (">"); },
|
|
sub { $g->Action ($i)->Write ("<")->TypeParameterList ($i)->Write ("> lambda"); },
|
|
"return lambda;\n"
|
|
);
|
|
|
|
$g->Write ("\n");
|
|
create_func_doc ($g, $i, Generator::GetDocFunc ($i));
|
|
$g->Method (
|
|
sub {
|
|
$g->Write ("public static ")->Func ($i)
|
|
->Write ("<")->TypeParameterList ($i)->Write (", TResult>");
|
|
},
|
|
sub { $g->Write ("\n\tF<")->TypeParameterList ($i)->Write (", TResult>"); },
|
|
sub { $g->Func ($i)->Write ("<")->TypeParameterList ($i)->Write (", TResult> lambda"); },
|
|
"return lambda;\n"
|
|
);
|
|
|
|
$g->Write ("\n");
|
|
create_expr_doc ($g, $i, Generator::GetDocAction ($i));
|
|
$g->Method (
|
|
sub {
|
|
$g->Write ("public static Expression<")->Action ($i)
|
|
->Write ("<")->TypeParameterList ($i)->Write (">>");
|
|
},
|
|
sub { $g->Write ("\n\tXA<")->TypeParameterList ($i)->Write (">"); },
|
|
sub { $g->Write ("Expression<")->Action ($i)->Write ("<")->TypeParameterList ($i)->Write (">> expr"); },
|
|
"return expr;\n"
|
|
);
|
|
|
|
$g->Write ("\n");
|
|
create_expr_doc ($g, $i, Generator::GetDocFunc ($i));
|
|
$g->Method (
|
|
sub {
|
|
$g->Write ("public static Expression<")->Func ($i)
|
|
->Write ("<")->TypeParameterList ($i)->Write (", TResult>>");
|
|
},
|
|
sub { $g->Write ("\n\tXF<")->TypeParameterList ($i)->Write (", TResult>"); },
|
|
sub { $g->Write ("Expression<")->Func ($i)->Write ("<")->TypeParameterList ($i)->Write (", TResult>> expr"); },
|
|
"return expr;\n"
|
|
);
|
|
}
|
|
$g->Write ("\n//\n");
|
|
$g->Write ("// Y-Combinators\n");
|
|
$g->Write ("// http://blogs.msdn.com/madst/archive/2007/05/11/recursive-lambda-expressions.aspx\n");
|
|
$g->Write ("//\n");
|
|
for (my $i = 1; $i <= $n; ++$i) {
|
|
$g->Write ("\n");
|
|
create_recfunc_doc ($g, $i, Generator::GetDocFunc ($i));
|
|
$g->Method (
|
|
sub {
|
|
$g->Write ("public static ")->Func ($i)
|
|
->Write ("<")->TypeParameterList ($i)->Write (", TResult>");
|
|
},
|
|
sub { $g->Write ("\n\tRecFunc<")->TypeParameterList ($i)->Write (", TResult>"); },
|
|
sub { $g->Func ($i)->Write ("<")
|
|
->Func ($i)->Write ("<")->TypeParameterList ($i)->Write (", TResult>, ")
|
|
->Func ($i)->Write ("<")->TypeParameterList ($i)->Write (", TResult>> lambda");
|
|
},
|
|
sub {
|
|
$g->Write ("if (lambda == null)\n")
|
|
->Write ("\tthrow new ArgumentNullException (\"lambda\");\n\n");
|
|
$g->Write ("return (")->ValueList ($i)->Write (") => ")
|
|
->Write ("lambda (RecFunc (lambda))(")->ValueList ($i)->Write (");\n");
|
|
}
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
sub create_actions {
|
|
my ($g, $n) = @_;
|
|
if ($n > $g->MaxSystemFuncs) {
|
|
for (my $i = $g->MaxSystemFuncs+1; $i <= $n; ++$i) {
|
|
$g->Write ("\npublic delegate void RocksAction<");
|
|
$g->TypeParameterList ($i);
|
|
$g->Write ("> (");
|
|
$g->MethodParameterList ($i);
|
|
$g->Write (");");
|
|
}
|
|
$g->Write ("\n");
|
|
}
|
|
}
|
|
|
|
sub create_func_doc {
|
|
my ($g, $n, $t) = @_;
|
|
|
|
for (my $i = 1; $i <= $n; ++$i) {
|
|
$g->XmlTypeparam (Generator::GetTypeParameter ($n, $i),
|
|
"A <see cref=\"T:$t\"/> parameter type.");
|
|
}
|
|
if ($t =~ m/Func/) {
|
|
$g->XmlTypeparam ("TResult", "The <see cref=\"T:$t\"/> return type.");
|
|
}
|
|
$g->XmlParam ("lambda",
|
|
"The <see cref=\"T:$t\"/> to return.");
|
|
$g->XmlSummary ("Creates a <see cref=\"T:$t\"/> delegate.");
|
|
$g->XmlReturns ("Returns <paramref name=\"lambda\"/>.");
|
|
# $g->XmlRemarks ("remarks", "");
|
|
}
|
|
|
|
sub create_expr_doc {
|
|
my ($g, $n, $t) = @_;
|
|
|
|
my $e = "System.Linq.Expressions.Expression";
|
|
$t = "$e\{$t\}";
|
|
|
|
for (my $i = 1; $i <= $n; ++$i) {
|
|
$g->XmlTypeparam (Generator::GetTypeParameter ($n, $i),
|
|
"A <see cref=\"T:$t\"/> parameter type.");
|
|
}
|
|
if ($t =~ m/Func/) {
|
|
$g->XmlTypeparam ("TResult", "The <see cref=\"T:$t\"/> return type.");
|
|
}
|
|
$g->XmlParam ("expr",
|
|
"The <see cref=\"T:$t\"/> to return.");
|
|
$g->XmlSummary ("Creates a <see cref=\"T:$t\"/> expression tree.");
|
|
$g->XmlReturns ("Returns <paramref name=\"expr\"/>.");
|
|
# $g->XmlRemarks ("remarks", "");
|
|
}
|
|
|
|
sub create_recfunc_doc {
|
|
my ($g, $n, $t) = @_;
|
|
|
|
for (my $i = 1; $i <= $n; ++$i) {
|
|
$g->XmlTypeparam (Generator::GetTypeParameter ($n, $i),
|
|
"A <see cref=\"T:$t\"/> parameter type.");
|
|
}
|
|
if ($t =~ m/Func/) {
|
|
$g->XmlTypeparam ("TResult", "The <see cref=\"T:$t\"/> return type.");
|
|
}
|
|
$g->XmlParam ("lambda",
|
|
"The <see cref=\"T:System.Func{$t,$t}\"/> to use.");
|
|
$g->XmlSummary ("Creates a <see cref=\"T:$t\"/> delegate, which may be recursive.");
|
|
$g->XmlReturns (
|
|
qq(Returns a <see cref=\"T:$t\"/> which (eventually) invokes
|
|
<paramref name="lambda"/>.));
|
|
$g->XmlException ("System.ArgumentNullException",
|
|
"if <paramref name=\"lambda\"/> is <see langword=\"null\"/>.");
|
|
$g->XmlRemarks(
|
|
qq(<para>
|
|
The following example makes use of a recursive lambda:
|
|
</para>
|
|
<code lang="C#">
|
|
Func<int, int> factorial = Lambda.RecFunc<int, int> (
|
|
fac => x => x == 0 ? 1 : x * fac (x-1));
|
|
Console.WriteLine (factorial (5)); // prints "120"</code>
|
|
));
|
|
# $g->XmlRemarks ("remarks", "");
|
|
}
|
|
|