static MemberDeclarationSyntax MakeConstructor(ClassDeclarationSyntax @class, TypeSyntax returnType, MethodDeclarationSyntax method) { var assignments = method.ParameterList .Parameters .Select(p => ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(CodeGenUtil.MakeFirstCharUpper(p.Identifier.Text)), IdentifierName(p.Identifier.Text)))); return(ConstructorDeclaration(Identifier(method.Identifier.Text)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) .WithParameterList(method.ParameterList) .WithBody(Block(List(assignments)))); }
static MemberDeclarationSyntax MakeField(TypeSyntax returnType, ParameterSyntax p) { var fieldName = CodeGenUtil.MakeFirstCharUpper(p.Identifier.Text); var field = FieldDeclaration( VariableDeclaration(p.Type) .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier(fieldName))))) .WithModifiers( TokenList( new[] { Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.ReadOnlyKeyword) })) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));; return(field); }
static MethodDeclarationSyntax MakeMapFunction( SyntaxToken applyToIdentifier, SyntaxList <TypeParameterConstraintClauseSyntax> applyToConstraints, MethodDeclarationSyntax[] applyToMembers, TypeParameterListSyntax applyToTypeParams, MethodDeclarationSyntax pure) { var genA = applyToTypeParams.Parameters.First().ToString(); var genB = CodeGenUtil.NextGenName(genA); var genC = CodeGenUtil.NextGenName(genB); var typeA = MakeTypeName(applyToIdentifier.Text, genA); var typeB = MakeTypeName(applyToIdentifier.Text, genB); var typeC = MakeTypeName(applyToIdentifier.Text, genC); var mapFuncType = ParseTypeName($"System.Func<{genA}, {genB}>"); var pureTypeA = MakeTypeName(pure.Identifier.Text, genA); var pureTypeB = MakeTypeName(pure.Identifier.Text, genB); var mapFunc = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("v"), IdentifierName("Next"))) .WithArgumentList(ArgumentList(SingletonSeparatedList <ArgumentSyntax>(Argument(IdentifierName("n"))))), IdentifierName("Map"))) .WithArgumentList( ArgumentList( SingletonSeparatedList <ArgumentSyntax>( Argument( IdentifierName("f"))))); var pureFunc = new SyntaxNodeOrToken[] { SwitchExpressionArm( DeclarationPattern( pureTypeA, SingleVariableDesignation(Identifier("v"))), ObjectCreationExpression(pureTypeB) .WithArgumentList( ArgumentList( SingletonSeparatedList <ArgumentSyntax>( Argument( InvocationExpression(IdentifierName("f")) .WithArgumentList( ArgumentList( SingletonSeparatedList <ArgumentSyntax>( Argument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("v"), IdentifierName(CodeGenUtil.MakeFirstCharUpper(pure.ParameterList.Parameters.First().Identifier.Text)))))))))))), Token(SyntaxKind.CommaToken) }; var termimalFuncs = applyToMembers .Where(m => m != pure && m.AttributeLists != null && m.AttributeLists.SelectMany(a => a.Attributes).Any(a => a.Name.ToString() == "Pure")) .SelectMany(m => new SyntaxNodeOrToken[] { SwitchExpressionArm( DeclarationPattern( ParseTypeName($"{m.Identifier.Text}<{genA}>"), SingleVariableDesignation(Identifier("v"))), ObjectCreationExpression(MakeTypeName(m.Identifier.Text, genB)) .WithArgumentList( ArgumentList( SeparatedList <ArgumentSyntax>( m.ParameterList .Parameters .Select(p => Argument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("v"), IdentifierName(CodeGenUtil.MakeFirstCharUpper(p.Identifier))))))))), Token(SyntaxKind.CommaToken) }); var freeFuncs = applyToMembers .Where(m => m.AttributeLists == null || !m.AttributeLists.SelectMany(a => a.Attributes).Any(a => a.Name.ToString() == "Pure")) .SelectMany(m => new SyntaxNodeOrToken[] { SwitchExpressionArm( DeclarationPattern( ParseTypeName($"{m.Identifier.Text}<{genA}>"), SingleVariableDesignation(Identifier("v"))), ObjectCreationExpression(MakeTypeName(m.Identifier.Text, genB)) .WithArgumentList( ArgumentList( SeparatedList <ArgumentSyntax>( Enumerable.Concat( m.ParameterList .Parameters .Take(m.ParameterList.Parameters.Count - 1) .SelectMany(p => new SyntaxNodeOrToken[] { Argument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("v"), IdentifierName(CodeGenUtil.MakeFirstCharUpper(p.Identifier.Text)))), Token(SyntaxKind.CommaToken) }), new SyntaxNodeOrToken [1] { Argument(SimpleLambdaExpression(Parameter(Identifier("n")), mapFunc)) }))))), Token(SyntaxKind.CommaToken) }); var tokens = new List <SyntaxNodeOrToken>(); tokens.AddRange(pureFunc); tokens.AddRange(termimalFuncs); tokens.AddRange(freeFuncs); tokens.Add( SwitchExpressionArm( DiscardPattern(), ThrowExpression( ObjectCreationExpression( QualifiedName( IdentifierName("System"), IdentifierName("NotSupportedException"))) .WithArgumentList(ArgumentList())))); return(MethodDeclaration(typeB, Identifier("Map")) .WithModifiers( TokenList(new[] { Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword) })) .WithTypeParameterList( TypeParameterList( SeparatedList <TypeParameterSyntax>( new SyntaxNodeOrToken[] { TypeParameter( Identifier(genA)), Token(SyntaxKind.CommaToken), TypeParameter( Identifier(genB)) }))) .WithParameterList( ParameterList( SeparatedList <ParameterSyntax>( new SyntaxNodeOrToken[] { Parameter( Identifier("ma")) .WithModifiers( TokenList( Token(SyntaxKind.ThisKeyword))) .WithType(typeA), Token(SyntaxKind.CommaToken), Parameter( Identifier("f")) .WithType(mapFuncType) }))) .WithExpressionBody( ArrowExpressionClause( SwitchExpression( IdentifierName("ma")) .WithArms(SeparatedList <SwitchExpressionArmSyntax>(tokens)))) .WithSemicolonToken( Token(SyntaxKind.SemicolonToken)) .NormalizeWhitespace()); }