public static void Visit(ClassDeclarationSyntax @class, Action <SyntaxToken, TypeSyntax, IEnumerable <ParameterSyntax> > methods = null, Action <SyntaxToken, TypeSyntax, ExpressionSyntax> fields = null, Action <IEnumerable <ParameterSyntax> > constructors = null) { var publicMembers = @class .DescendantNodes() .OfType <MemberDeclarationSyntax>() .Where(member => Roslyn.IsVisible(member)); foreach (var member in publicMembers) { if (member is MethodDeclarationSyntax && methods != null) { var method = member as MethodDeclarationSyntax; //since we generate multiple methods if (methods != null && method .AttributeLists .Any(attrList => attrList .Attributes .Any(attr => attr.Name.ToString() == "Concurrent"))) { methods(method.Identifier, method.ReturnType, method.ParameterList.Parameters); } } else if (member is FieldDeclarationSyntax && fields != null) { var declaration = (member as FieldDeclarationSyntax) .Declaration; var variable = declaration .Variables .Single(); fields(variable.Identifier, declaration.Type, variable.Initializer.Value); } else if (member is PropertyDeclarationSyntax && fields != null) { var property = member as PropertyDeclarationSyntax; fields(property.Identifier, property.Type, null); } else if (member is ConstructorDeclarationSyntax) { constructors?.Invoke((member as ConstructorDeclarationSyntax) .ParameterList .Parameters); } else { //td: review other member types } } }
private static void compileProperty(PropertyDeclarationSyntax property, Class ctx, Scope scope) { if (!Roslyn.IsVisible(property)) { return; } var @get = null as AccessorDeclarationSyntax; var @set = null as AccessorDeclarationSyntax; foreach (var accesor in property.AccessorList.Accessors) { switch (accesor.Keyword.Kind()) { case SyntaxKind.GetKeyword: @get = accesor; break; case SyntaxKind.SetKeyword: @set = accesor; break; default: throw new NotImplementedException(); } } bool hasCustomGet = @get != null && @get.Body != null && @get.Body.Statements.Count > 0; if (hasCustomGet && @get.Body.Statements.Count == 1) { hasCustomGet = !(@get.Body.Statements[0] is ReturnStatementSyntax); } bool hasCustomSet = @set != null && @set.Body != null && @set.Body.Statements.Count > 0; if (hasCustomSet && @set.Body.Statements.Count == 1) { hasCustomSet = !(@set.Body.Statements[0] is ExpressionStatementSyntax) || (@set.Body.Statements[0] as ExpressionStatementSyntax) .Expression.Kind() != SyntaxKind.SimpleAssignmentExpression; } if (hasCustomGet || hasCustomSet) { scope.AddError("concurrent00", "invalid concurrent property, custom accessors are not allowed", property); } }
private static IEnumerable <MemberDeclarationSyntax> getConcurrentInterface(ClassDeclarationSyntax @class) { return(@class .ChildNodes() .OfType <MemberDeclarationSyntax>() .Where(member => { if (member is MethodDeclarationSyntax && Roslyn.IsVisible(member)) { return !(member as MethodDeclarationSyntax) .Modifiers .Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword); } return false; })); }
private static bool compileMethod(MethodDeclarationSyntax methodDeclaration, Class ctx, Scope scope, Options options, bool isSingleton) { var method = methodDeclaration; var name = method.Identifier.ToString(); var isMain = name == "main"; var isProtected = method .Modifiers .Where(m => m.Kind() == SyntaxKind.ProtectedKeyword) .Any(); var isVisible = isProtected || Roslyn.IsVisible(method); var isStatic = Roslyn.IsStatic(method); var hasReturnType = method.ReturnType.ToString() != "void"; var returnType = hasReturnType ? method.ReturnType : Roslyn.boolean; var isEmptySignal = method.Body == null || method.Body.IsMissing; if (isEmptySignal) { if (method.ParameterList.Parameters.Count > 0) { scope.AddError("concurrent03", "empty signals cannot contain parameters", method); } if (method.ReturnType.ToString() != "void") { scope.AddError("concurrent04", "empty signals cannot return values", method); } method = method .WithSemicolonToken(CSharp.MissingToken(SyntaxKind.SemicolonToken)) .WithBody(CSharp.Block()); } var cc = parseConcurrentBlock(ctx, method.Body, scope, isStatic); if (cc != null) { method = method.WithBody(cc); } //remove attributes, until needed method = method.WithAttributeLists(CSharp.List <AttributeListSyntax>()); if (isMain) { if (ctx.HasMain) { scope.AddError("concurrent06", "multiple main methods", method); return(false); } ctx.HasMain = true; var statements = method.Body.Statements; var isContinued = (cc == null) && checkContinued(statements); if (isContinued) { method = method .WithBody(CSharp.Block(statements .Take(statements.Count - 1))); } var mainMethod = concurrentMethod(ctx, method); //hook up our start method int currentIndex = 0; ctx.Replace(methodDeclaration, Templates .StartObject .Get <MethodDeclarationSyntax>(Templates .ConcurrentMain .Get <InvocationExpressionSyntax>() .WithArgumentList(CSharp.ArgumentList(CSharp.SeparatedList( mainMethod .ParameterList .Parameters .Where(param => param.Identifier.ToString() != "__cancellation" && param.Identifier.ToString() != "__success" && param.Identifier.ToString() != "__failure") .Select(param => CSharp.Argument(Templates .StartObjectArgument .Get <ExpressionSyntax>( param.Type, currentIndex++))) .Union(new[] { CSharp.Argument(Templates.NullCancelationToken), CSharp.Argument(Roslyn.@null), CSharp.Argument(Roslyn.@null), })))))); return(false); } if (isVisible) { if (isEmptySignal) { Debug.Assert(!isStatic); //td: error ctx.AddMember(Templates .EmptySignalMethod .Get <MethodDeclarationSyntax>( "__concurrent" + name, Roslyn.Quoted(name), isProtected ? Roslyn.@true : Roslyn.@false)); } else { concurrentMethod(ctx, method, asVirtual: options.GenerateRemote); } } else if (cc != null) { concurrentMethod(ctx, method); } else if (isEmptySignal) { ctx.AddMember(Templates .EmptySignalMethod .Get <MethodDeclarationSyntax>( "__concurrent" + name, Roslyn.Quoted(name), isProtected? Roslyn.@true : Roslyn.@false)); } else { return(false); } var signal = ctx.AddSignal(name, returnType, isVisible, isStatic); if (isVisible) { method = createPublicSignals(ctx, method, signal, isSingleton); if (isSingleton) { ctx.Replace(methodDeclaration, method); } } else { ctx.Replace(methodDeclaration, method .WithBody(CSharp.Block() .WithStatements(CSharp.List(new[] { isEmptySignal ? Templates.SignalDispatcher.Get <StatementSyntax>(Roslyn.Quoted(method.Identifier.ToString())) : Templates.PrivateSignal })))); return(false); } return(true); }