private static MethodDeclarationSyntax GenerateGetMethodNameMethod(Type grainType) { var method = TypeUtils.Method((GrainReference _) => _.GetMethodName(default(int), default(int))); var methodDeclaration = method.GetDeclarationSyntax() .AddModifiers(SF.Token(SyntaxKind.OverrideKeyword)); var parameters = method.GetParameters(); var interfaceIdArgument = parameters[0].Name.ToIdentifierName(); var methodIdArgument = parameters[1].Name.ToIdentifierName(); var interfaceCases = CodeGeneratorCommon.GenerateGrainInterfaceAndMethodSwitch( grainType, methodIdArgument, methodType => new StatementSyntax[] { SF.ReturnStatement(methodType.Name.GetLiteralExpression()) }); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), interfaceIdArgument); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); var interfaceIdSwitch = SF.SwitchStatement(interfaceIdArgument).AddSections(interfaceCases.ToArray()).AddSections(defaultCase); return(methodDeclaration.AddBodyStatements(interfaceIdSwitch)); }
/// <summary> /// The generate method. /// </summary> /// <param name="actor"> /// The actor. /// </param> /// <returns> /// The <see cref="MethodDeclarationSyntax"/>. /// </returns> private static MethodDeclarationSyntax GenerateInvokeMethod(ActorDescription actor) { // Get the method with the correct type. var method = TypeUtil.GenericTypeMethod( (IEventInvoker <IGrain> x) => x.Invoke(default(IGrain), default(Event)), new[] { actor.Type }); var methodDeclaration = method.GetMethodDeclarationSyntax(); var parameters = method.GetParameters(); var @event = SF.IdentifierName(parameters.First(_ => typeof(Event) == _.ParameterType).Name); var instance = SF.IdentifierName(parameters.First(_ => actor.Type == _.ParameterType).Name); var switchCases = GenerateSwitchCases(actor, m => GenerateDispatchBlockForMethod(m, instance, @event)).ToArray(); var returnNull = SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)); var defaultSection = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(returnNull); var kindSwitch = SF.SwitchStatement(@event.Member((Event _) => _.Type)) .AddSections(switchCases) .AddSections(defaultSection); return (methodDeclaration .AddBodyStatements(kindSwitch)); }
public override SyntaxList <StatementSyntax> VisitSelectBlock(VBSyntax.SelectBlockSyntax node) { var expr = (ExpressionSyntax)node.SelectStatement.Expression.Accept(_nodesVisitor); var exprWithoutTrivia = expr.WithoutTrivia().WithoutAnnotations(); var sections = new List <SwitchSectionSyntax>(); foreach (var block in node.CaseBlocks) { var labels = new List <SwitchLabelSyntax>(); foreach (var c in block.CaseStatement.Cases) { if (c is VBSyntax.SimpleCaseClauseSyntax s) { var expressionSyntax = (ExpressionSyntax)s.Value.Accept(_nodesVisitor); SwitchLabelSyntax caseSwitchLabelSyntax = SyntaxFactory.CaseSwitchLabel(expressionSyntax); if (!_semanticModel.GetConstantValue(s.Value).HasValue) { caseSwitchLabelSyntax = WrapInCasePatternSwitchLabelSyntax(expressionSyntax); } labels.Add(caseSwitchLabelSyntax); } else if (c is VBSyntax.ElseCaseClauseSyntax) { labels.Add(SyntaxFactory.DefaultSwitchLabel()); } else if (c is VBSyntax.RelationalCaseClauseSyntax relational) { var operatorKind = VBasic.VisualBasicExtensions.Kind(relational); var cSharpSyntaxNode = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(TokenContext.Local), exprWithoutTrivia, (ExpressionSyntax)relational.Value.Accept(_nodesVisitor)); labels.Add(WrapInCasePatternSwitchLabelSyntax(cSharpSyntaxNode)); } else if (c is VBSyntax.RangeCaseClauseSyntax range) { var lowerBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, (ExpressionSyntax)range.LowerBound.Accept(_nodesVisitor), exprWithoutTrivia); var upperBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, exprWithoutTrivia, (ExpressionSyntax)range.UpperBound.Accept(_nodesVisitor)); var withinBounds = SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, lowerBoundCheck, upperBoundCheck); labels.Add(WrapInCasePatternSwitchLabelSyntax(withinBounds)); } else { throw new NotSupportedException(c.Kind().ToString()); } } var csBlockStatements = block.Statements.SelectMany(s => s.Accept(CommentConvertingVisitor)).ToList(); if (csBlockStatements.LastOrDefault() ?.IsKind(SyntaxKind.ReturnStatement) != true) { csBlockStatements.Add(SyntaxFactory.BreakStatement()); } var list = SingleStatement(SyntaxFactory.Block(csBlockStatements)); sections.Add(SyntaxFactory.SwitchSection(SyntaxFactory.List(labels), list)); } var switchStatementSyntax = SyntaxFactory.SwitchStatement(expr, SyntaxFactory.List(sections)); return(SingleStatement(switchStatementSyntax)); }
/// <summary> /// Returns syntax for dispatching <paramref name="event"/> to <paramref name="actor"/>. /// </summary> /// <param name="event"> /// The event. /// </param> /// <param name="actor"> /// The actor description. /// </param> /// <returns> /// Syntax for dispatching <paramref name="event"/> to <paramref name="actor"/>. /// </returns> private static StatementSyntax GenerateActorBlock( ExpressionSyntax @event, ActorDescription actor) { var @var = SF.IdentifierName("var"); var grainType = actor.Type.GetTypeSyntax(); var getGrain = SF.InvocationExpression(SF.IdentifierName("GrainFactory").Member("GetGrain", grainType)) .AddArgumentListArguments(SF.Argument(@event.Member("To").Member("Id"))); var grain = SF.VariableDeclarator("grain").WithInitializer(SF.EqualsValueClause(getGrain)); var grainDeclaration = SF.LocalDeclarationStatement(SF.VariableDeclaration(@var).AddVariables(grain)); var returnNull = SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)); var defaultSection = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(returnNull); var methodSwitch = SF.SwitchStatement(@event.Member("Type")) .AddSections( actor.Methods.Values.Where(_ => _.Visible) .Select(method => GetMethodSwitchCase(@event, method)) .ToArray()) .AddSections(defaultSection); var methodDispatcher = SF.Block().AddStatements(grainDeclaration, methodSwitch); return(methodDispatcher); }
/// <summary> /// Returns method syntax for dispatching events to the provided <paramref name="actors"/>. /// </summary> /// <param name="actors"> /// The actor descriptions. /// </param> /// <returns> /// Method syntax for dispatching events to the provided <paramref name="actors"/>. /// </returns> private static MethodDeclarationSyntax GenerateMethod(IEnumerable <ActorDescription> actors) { // Types var eventType = typeof(Event).GetTypeSyntax(); var returnType = typeof(Task <object>).GetTypeSyntax(); // Local variables var @event = SF.IdentifierName("@event"); // Parameters var eventParam = SF.Parameter(@event.Identifier).WithType(eventType); // Body statements var returnNull = SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)); var defaultSection = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(returnNull); var kindSwitch = SF.SwitchStatement(@event.Member("To").Member("Kind")) .AddSections( actors.Where(actor => actor.Methods.Any()) .Select(actor => GetActorSwitch(actor, @event)) .ToArray()) .AddSections(defaultSection); // Build and return the method. return (SF.MethodDeclaration(returnType, "Dispatch") .AddModifiers(SF.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters(eventParam) .AddBodyStatements(kindSwitch)); }
private bool ConvertToSwitch(ExpressionSyntax expr, SyntaxList <VBSyntax.CaseBlockSyntax> caseBlocks, out SwitchStatementSyntax switchStatement) { switchStatement = null; var sections = new List <SwitchSectionSyntax>(); foreach (var block in caseBlocks) { var labels = new List <SwitchLabelSyntax>(); foreach (var c in block.CaseStatement.Cases) { if (c is VBSyntax.SimpleCaseClauseSyntax) { var s = (VBSyntax.SimpleCaseClauseSyntax)c; labels.Add(SyntaxFactory.CaseSwitchLabel((ExpressionSyntax)s.Value.Accept(nodesVisitor))); } else if (c is VBSyntax.ElseCaseClauseSyntax) { labels.Add(SyntaxFactory.DefaultSwitchLabel()); } else { return(false); } } var list = SingleStatement(SyntaxFactory.Block(block.Statements.SelectMany(s => s.Accept(this)).Concat(SyntaxFactory.BreakStatement()))); sections.Add(SyntaxFactory.SwitchSection(SyntaxFactory.List(labels), list)); } switchStatement = SyntaxFactory.SwitchStatement(expr, SyntaxFactory.List(sections)); return(true); }
/// <summary> /// Generates syntax for an invoke method. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="invokeMethod"> /// The invoke method to generate. /// </param> /// <returns> /// Syntax for an invoke method. /// </returns> private static MethodDeclarationSyntax GenerateInvokeMethod(Type grainType, MethodInfo invokeMethod) { var methodDeclaration = invokeMethod.GetDeclarationSyntax(); var parameters = invokeMethod.GetParameters(); var grainArgument = parameters[0].Name.ToIdentifierName(); var interfaceIdArgument = parameters[1].Name.ToIdentifierName(); var methodIdArgument = parameters[2].Name.ToIdentifierName(); var argumentsArgument = parameters[3].Name.ToIdentifierName(); var interfaceCases = CodeGeneratorCommon.GenerateGrainInterfaceAndMethodSwitch( grainType, methodIdArgument, methodType => GenerateInvokeForMethod(grainType, grainArgument, methodType, argumentsArgument)); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), interfaceIdArgument); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); var interfaceIdSwitch = SF.SwitchStatement(interfaceIdArgument).AddSections(interfaceCases.ToArray()).AddSections(defaultCase); // If the provided grain is null, throw an argument exception. var argumentNullException = SF.ObjectCreationExpression(typeof(ArgumentNullException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(parameters[0].Name.GetLiteralExpression())); var grainArgumentCheck = SF.IfStatement( SF.BinaryExpression( SyntaxKind.EqualsExpression, grainArgument, SF.LiteralExpression(SyntaxKind.NullLiteralExpression)), SF.ThrowStatement(argumentNullException)); // Wrap everything in a try-catch block. var faulted = (Expression <Func <Task <object> > >)(() => TaskUtility.Faulted(null)); const string Exception = "exception"; var exception = SF.Identifier(Exception); var body = SF.TryStatement() .AddBlockStatements(grainArgumentCheck, interfaceIdSwitch) .AddCatches( SF.CatchClause() .WithDeclaration( SF.CatchDeclaration(typeof(Exception).GetTypeSyntax()).WithIdentifier(exception)) .AddBlockStatements( SF.ReturnStatement( faulted.Invoke().AddArgumentListArguments(SF.Argument(SF.IdentifierName(Exception)))))); return(methodDeclaration.AddBodyStatements(body)); }
/// <summary> /// Returns syntax for the <see cref="IEventInvoker{T}.GetArgumentTypes"/> method. /// </summary> /// <param name="actor"> /// The actor description. /// </param> /// <returns> /// Syntax for the <see cref="IEventInvoker{T}.GetArgumentTypes"/> method. /// </returns> private static MemberDeclarationSyntax GenerateGetTypeArgumentsMethod(ActorDescription actor) { var method = TypeUtil.GenericTypeMethod( (IEventInvoker <IGrain> m) => m.GetArgumentTypes(default(string)), new[] { actor.Type }); var methodDeclaration = method.GetMethodDeclarationSyntax(); var parameters = method.GetParameters(); var eventTypeArg = SF.IdentifierName(parameters.First(_ => typeof(string) == _.ParameterType).Name); var switchCases = GenerateSwitchCases(actor, GenerateGetTypeArgumentsSwitchBlock).ToArray(); var returnNull = SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)); var defaultSection = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(returnNull); var kindSwitch = SF.SwitchStatement(eventTypeArg) .AddSections(switchCases) .AddSections(defaultSection); return(methodDeclaration.AddBodyStatements(kindSwitch)); }
/// <summary> /// Generates switch cases for the provided grain type. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="methodIdArgument"> /// The method id argument, which is used to select the correct switch label. /// </param> /// <param name="generateMethodHandler"> /// The function used to generate switch block statements for each method. /// </param> /// <returns> /// The switch cases for the provided grain type. /// </returns> public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch( Type grainType, IdentifierNameSyntax methodIdArgument, Func <MethodInfo, StatementSyntax[]> generateMethodHandler) { var interfaces = GrainInterfaceData.GetRemoteInterfaces(grainType); interfaces[GrainInterfaceData.GetGrainInterfaceId(grainType)] = grainType; // Switch on interface id. var interfaceCases = new List <SwitchSectionSyntax>(); foreach (var @interface in interfaces) { var interfaceType = @interface.Value; var interfaceId = @interface.Key; var methods = GrainInterfaceData.GetMethods(interfaceType); var methodCases = new List <SwitchSectionSyntax>(); // Switch on method id. foreach (var method in methods) { // Generate switch case. var methodId = GrainInterfaceData.ComputeMethodId(method); var methodType = method; // Generate the switch label for this interface id. var methodIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Generate the switch body. var methodInvokeStatement = generateMethodHandler(methodType); methodCases.Add( SF.SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement)); } // Generate the switch label for this interface id. var interfaceIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId))); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), SF.BinaryExpression( SyntaxKind.AddExpression, SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)), SF.BinaryExpression( SyntaxKind.AddExpression, ",methodId=".GetLiteralExpression(), methodIdArgument))); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); // Generate switch statements for the methods in this interface. var methodSwitchStatements = SF.SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()).AddSections(defaultCase); // Generate the switch section for this interface. interfaceCases.Add( SF.SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements)); } return(interfaceCases.ToArray()); }
/// <summary> /// Generates syntax for an invoke method. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="invokeMethod"> /// The invoke method to generate. /// </param> /// <returns> /// Syntax for an invoke method. /// </returns> private static MethodDeclarationSyntax GenerateInvokeMethod(Type grainType, MethodInfo invokeMethod) { var parameters = invokeMethod.GetParameters(); var grainArgument = parameters[0].Name.ToIdentifierName(); var requestArgument = parameters[1].Name.ToIdentifierName(); // Store the relevant values from the request in local variables. var interfaceIdDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(int).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("interfaceId") .WithInitializer(SF.EqualsValueClause(requestArgument.Member((InvokeMethodRequest _) => _.InterfaceId))))); var interfaceIdVariable = SF.IdentifierName("interfaceId"); var methodIdDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(int).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("methodId") .WithInitializer(SF.EqualsValueClause(requestArgument.Member((InvokeMethodRequest _) => _.MethodId))))); var methodIdVariable = SF.IdentifierName("methodId"); var argumentsDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(object[]).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("arguments") .WithInitializer(SF.EqualsValueClause(requestArgument.Member((InvokeMethodRequest _) => _.Arguments))))); var argumentsVariable = SF.IdentifierName("arguments"); var methodDeclaration = invokeMethod.GetDeclarationSyntax() .AddBodyStatements(interfaceIdDeclaration, methodIdDeclaration, argumentsDeclaration); var interfaceCases = CodeGeneratorCommon.GenerateGrainInterfaceAndMethodSwitch( grainType, methodIdVariable, methodType => GenerateInvokeForMethod(grainType, grainArgument, methodType, argumentsVariable)); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), interfaceIdVariable); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); var interfaceIdSwitch = SF.SwitchStatement(interfaceIdVariable).AddSections(interfaceCases.ToArray()).AddSections(defaultCase); // If the provided grain is null, throw an argument exception. var argumentNullException = SF.ObjectCreationExpression(typeof(ArgumentNullException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(parameters[0].Name.GetLiteralExpression())); var grainArgumentCheck = SF.IfStatement( SF.BinaryExpression( SyntaxKind.EqualsExpression, grainArgument, SF.LiteralExpression(SyntaxKind.NullLiteralExpression)), SF.ThrowStatement(argumentNullException)); return(methodDeclaration.AddBodyStatements(grainArgumentCheck, interfaceIdSwitch)); }