private static ArgumentListSyntax Arguments(ParserRuleContext node) { var expr = null as ExpressionSyntax; var args = null as ArgumentListSyntax; if (node.ChildCount == 1) { expr = visitNode(node.GetRuleContext <ParserRuleContext>(0)); } else { Debug.Assert(node.ChildCount == 2); expr = visitNode(node.GetRuleContext <ParserRuleContext>(1)); args = Arguments(node.GetRuleContext <ParserRuleContext>(0)); } var arg = CSharp.Argument(expr); if (args != null) { return(args.AddArguments(arg)); } return(CSharp .ArgumentList(CSharp .SeparatedList(new[] { arg }))); }
private static string argumentsFromParameters(IEnumerable <ParameterSyntax> parameters) { return(CSharp .ArgumentList(CSharp.SeparatedList( parameters .Select(parameter => CSharp.Argument(CSharp. IdentifierName(parameter.Identifier))))) .ToString()); }
private Func <BlockSyntax, SyntaxToken, ParameterListSyntax, Scope, SyntaxNode> CodeExtensions_Transform( bool expectsIdentifier = false, bool expectsParameters = false) { return((block, identifier, parameters, scope) => { if (expectsIdentifier) { Assert.IsFalse(identifier.IsKind(SyntaxKind.None)); } if (expectsParameters) { Assert.IsNotNull(parameters); } if (identifier.IsKind(SyntaxKind.None)) { identifier = CSharp.ParseToken("SomeIdentifier"); } var result = CodeExtensions_Template .Get <StatementSyntax>(identifier); if (parameters != null) { result = result .ReplaceNodes(result .DescendantNodes() .OfType <ArgumentListSyntax>(), (on, nn) => nn .AddArguments(parameters .Parameters .Select(parameter => CSharp.Argument(CSharp.IdentifierName( parameter.Identifier.IsMissing ? parameter.Type.GetFirstToken() : parameter.Identifier))) .ToArray())); } var lambda = result .DescendantNodes() .OfType <ParenthesizedLambdaExpressionSyntax>() .Single(); return result.ReplaceNode(lambda, lambda .WithBody(block)); }); }
private StatementSyntax LinkExternalInvocation(InvocationExpressionSyntax invocation, InvocationExpressionSyntax success, InvocationExpressionSyntax failure) { var queueStatement = null as StatementSyntax; if (_class.isQueueInvocation(invocation, true, success, out queueStatement)) { return(queueStatement); } Debug.Assert(invocation.Expression is MemberAccessExpressionSyntax); Debug.Assert(!invocation.Expression .DescendantNodes() .OfType <InvocationExpressionSyntax>() .Any()); //td: errors var symbol = _model.GetSymbolInfo(invocation.Expression).Symbol; if (symbol != null) { if (isConcurrent(symbol)) { return(CSharp.ExpressionStatement( invocation .WithArgumentList(invocation .ArgumentList .AddArguments( CSharp.Argument(Templates.CancelationArgument), CSharp.Argument(Templates .SuccessFunction .Get <ExpressionSyntax>(success)), CSharp.Argument(Templates .FailureFunction .Get <ExpressionSyntax>(failure)))))); } if (isTask(symbol)) { return(Templates.TaskInvocation .Get <StatementSyntax>(invocation, success, failure)); } } return(Templates .NonConcurrentInvocation .Get <StatementSyntax>(invocation, success, failure)); }
private static SyntaxNode CompileFunction(SyntaxNode node, Scope scope) { var method = (MethodDeclarationSyntax)node; var concurrentClass = method.Identifier.ToString() + "__concurrent"; //create a concurrent class with the method var @class = CSharp.ClassDeclaration(concurrentClass) .AddMembers(method); //add it to the parent var document = scope.GetDocument(); document.change(node.Parent, AddFunctionClass(@class)); //create a substitute call var invocation = Templates.FunctionInvocation .Get <ExpressionStatementSyntax>( concurrentClass, method.Identifier); if (method.ParameterList.Parameters.Count > 0) { var invoke = (InvocationExpressionSyntax)invocation.Expression; var arguments = method.ParameterList .Parameters .Select(parameter => CSharp.Argument(CSharp.IdentifierName( parameter.Identifier))) .Union(invoke.ArgumentList.Arguments); invocation = invocation .WithExpression(invoke .WithArgumentList(CSharp.ArgumentList(CSharp.SeparatedList( arguments)))); } return(method .AddAttributeLists(CSharp.AttributeList(CSharp.SeparatedList <AttributeSyntax>(new[] { CSharp.Attribute(CSharp.ParseName("Concurrent")) }))) .AddParameterListParameters(Templates .FunctionParameters .Parameters .ToArray()) .WithBody(CSharp.Block(invocation))); }
private StatementSyntax LinkThisInvocation(InvocationExpressionSyntax invocation, InvocationExpressionSyntax success, InvocationExpressionSyntax failure) { Debug.Assert(invocation.Expression is IdentifierNameSyntax); //internal calls StatementSyntax result; if (syntaxOperation(invocation, success, failure, out result)) { return(result); } else { var identifier = (invocation.Expression as IdentifierNameSyntax) .ToString(); var signal = _class.GetSignal(identifier); var functional = default(StatementSyntax); if (signal != null) { var expr = invocation .WithExpression(CSharp.IdentifierName("__concurrent" + identifier)) .WithArgumentList(invocation .ArgumentList .AddArguments( CSharp.Argument( Templates.CancelationArgument), CSharp.Argument(WrapInLambda(success) .AddParameterListParameters(CSharp.Parameter(CSharp.ParseToken( "__res")))), CSharp.Argument(WrapInLambda(failure) .AddParameterListParameters(CSharp.Parameter(CSharp.ParseToken( "__ex")))))); return(CSharp.ExpressionStatement(Templates .Advance .Get <ExpressionSyntax>(expr))); } else if (isFunctionalCall(invocation, out functional)) { return(functional); } return(CSharp.ExpressionStatement(invocation)); } }
private ExpressionSyntax CreateCallback(bool success, bool leftOfParent, SyntaxToken token) { var arg1 = leftOfParent ? success ? Roslyn.@true : Roslyn.@false : Roslyn.@null; var arg2 = leftOfParent ? Roslyn.@null : success ? Roslyn.@true : Roslyn.@false; var ex = success ? Roslyn.@null : Templates.FailureParameter; return(CSharp .InvocationExpression(CSharp.IdentifierName(token)) .WithArgumentList(CSharp.ArgumentList(CSharp.SeparatedList(new[] { CSharp.Argument(arg1), CSharp.Argument(arg2), CSharp.Argument(ex) })))); }
private static Func <SyntaxNode, SyntaxNode, SemanticModel, Scope, SyntaxNode> LinkNamespaceFunction(bool calculateType) { return((original, node, model, scope) => { if (calculateType) { node = CalculateReturnType(original, node, model, scope); } var calls = node .DescendantNodes() .OfType <ExpressionStatementSyntax>() .Where(statement => statement.Expression is InvocationExpressionSyntax && (statement.Expression as InvocationExpressionSyntax) .Expression is IdentifierNameSyntax) .Select(statement => (InvocationExpressionSyntax)statement.Expression); return node.ReplaceNodes(calls, (on, nn) => { var lastArgument = nn .ArgumentList .Arguments .LastOrDefault(); if (lastArgument != null && lastArgument.ToString() == "__newScope") { return nn; } return nn.AddArgumentListArguments( CSharp.Argument(Templates.ScopeIdentifier)); }); }); }
private static MethodDeclarationSyntax singletonPublicSignal(MethodDeclarationSyntax method, out MethodDeclarationSyntax result) { result = method.WithIdentifier(CSharp.ParseToken("__" + method.Identifier.ToString())); var sCall = method.ReturnType.ToString() == "void" ? Templates.SingletonCall .Get <StatementSyntax>(result.Identifier.ToString()) : Templates.SingletonReturnCall .Get <StatementSyntax>(result.Identifier.ToString()); return(method .AddModifiers([email protected]()) .WithBody(CSharp.Block(sCall .ReplaceNodes(sCall .DescendantNodes() .OfType <ArgumentListSyntax>(), (on, nn) => nn.WithArguments(CSharp.SeparatedList(method .ParameterList .Parameters .Select(parameter => CSharp.Argument(CSharp.IdentifierName(parameter.Identifier))))))))); }
private static MethodDeclarationSyntax createPublicSignals(Class ctx, MethodDeclarationSyntax method, Signal signal, bool isSingleton) { var returnType = method.ReturnType.ToString() != "void" ? method.ReturnType : Roslyn.@object; var realType = default(TypeSyntax); if ((returnType is GenericNameSyntax) || (returnType is ArrayTypeSyntax)) { realType = returnType; returnType = CSharp.ParseTypeName("__temp__"); //hack } var internalMethod = method.Identifier.ToString(); if (!internalMethod.StartsWith("__concurrent")) { internalMethod = "__concurrent" + internalMethod; } var internalCall = Templates.InternalCall .Get <ExpressionSyntax>(internalMethod); internalCall = internalCall .ReplaceNodes(internalCall .DescendantNodes() .OfType <InvocationExpressionSyntax>() .Where(i => i.ArgumentList.Arguments.Count == 3), (on, nn) => nn .WithArgumentList(CSharp.ArgumentList(CSharp.SeparatedList( method.ParameterList.Parameters .Select(param => CSharp.Argument(CSharp.IdentifierName( param.Identifier))) .Union(on.ArgumentList.Arguments))))); var ps1 = publicSignal( method.ParameterList, Templates.TaskPublicMethod .Get <MethodDeclarationSyntax>( method.Identifier.ToString(), returnType, internalCall, Templates.Cheese(signal.Static))); if (realType != null) { ps1 = ps1.ReplaceNodes(ps1 .DescendantNodes() .OfType <TypeSyntax>() .Where(type => type.ToString() == "__temp__"), (on, nn) => realType); } var ps2 = publicSignal( method.ParameterList, Templates.TaskCallbackMethod .Get <MethodDeclarationSyntax>( method.Identifier.ToString(), internalCall, Templates.Cheese(signal.Static))); if (isSingleton) { ctx.AddMember(singletonPublicSignal(ps1, out ps1)); ctx.AddMember(singletonPublicSignal(ps2, out ps2)); ctx.AddMember(singletonPublicSignal(method, out method)); } ctx.AddMember(ps1); ctx.AddMember(ps2); return(method); }
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); }
private static IEnumerable <MemberDeclarationSyntax> createRemoteConstructors(ClassDeclarationSyntax @class, string typeName) { var constructor = @class .ChildNodes() .OfType <ConstructorDeclarationSyntax>() .OrderBy(ctor => ctor.ParameterList.Parameters.Count) .FirstOrDefault(); var result = CSharp.ConstructorDeclaration(typeName) .AddParameterListParameters(CSharp .Parameter(CSharp.Identifier("id")).WithType(CSharp.ParseTypeName("Guid"))) .WithBody(CSharp.Block(Templates.RemoteIdAssign)) .WithModifiers(Roslyn.@public); if (constructor != null) { result = result.WithInitializer(CSharp.ConstructorInitializer( SyntaxKind.BaseConstructorInitializer, CSharp.ArgumentList(CSharp.SeparatedList( constructor .ParameterList .Parameters .Select(parameter => CSharp.Argument( CSharp.DefaultExpression(parameter.Type))))))); } return(new MemberDeclarationSyntax[] { result }); }
private static SyntaxNode Compile(SyntaxNode node, Scope scope, bool isSingleton, Options options) { Debug.Assert(node is ClassDeclarationSyntax); var @class = (node as ClassDeclarationSyntax) .AddBaseListTypes( CSharp.SimpleBaseType(CSharp.ParseTypeName( "ConcurrentObject"))); if (options.GenerateInterface) { @class = @class.AddBaseListTypes( CSharp.SimpleBaseType(CSharp.ParseTypeName( "I" + (node as ClassDeclarationSyntax).Identifier.ToString()))); } var className = @class.Identifier.ToString(); var ctx = new Class(className, scope, isSingleton); scope.set <Class>(ctx); foreach (var member in @class.Members) { if (member is PropertyDeclarationSyntax) { compileProperty(member as PropertyDeclarationSyntax, ctx, scope); } else if (member is MethodDeclarationSyntax) { var method = member as MethodDeclarationSyntax; if (compileMethod(method, ctx, scope, options, isSingleton)) { var isVoid = method.ReturnType.ToString() == "void"; var taskArgs = isVoid ? new[] { CSharp.Argument(Templates.NullCancelationToken), CSharp.Argument(Roslyn.@null), CSharp.Argument(Roslyn.@null) } : new[] { CSharp.Argument(Templates.NullCancelationToken) }; var taskCall = CSharp .InvocationExpression( CSharp.IdentifierName(method.Identifier), CSharp.ArgumentList(CSharp.SeparatedList( method .ParameterList .Parameters .Select(parameter => CSharp .Argument(CSharp.IdentifierName(parameter.Identifier))) .Union( taskArgs)))); var newMethod = method .AddAttributeLists(CSharp.AttributeList(CSharp.SeparatedList(new[] { CSharp .Attribute(CSharp .ParseName("Concurrent")) }))) .WithBody(CSharp.Block() .WithStatements(CSharp.List(new[] { isVoid ? Templates .SynchVoidMethod .Get <StatementSyntax>(taskCall) : Templates .SynchReturnMethod .Get <StatementSyntax>(taskCall) }))); if (isSingleton && ctx.willReplace(method)) { //singleton methods must change into __methodName var fs = (newMethod .Body .Statements .First() as ExpressionStatementSyntax) .Expression as InvocationExpressionSyntax; var newId = "__" + method.Identifier.ToString(); newMethod = newMethod .ReplaceNode(fs, fs.WithExpression(CSharp.IdentifierName(newId))) .WithIdentifier(CSharp.ParseToken(newId)); } ctx.Replace(method, newMethod); } } } //all concurrent compilation has been done, produce @class = ctx.Update(@class); if (isSingleton) { @class = @class.AddMembers( Templates.SingletonField .Get <MemberDeclarationSyntax>(@class.Identifier), Templates.SingletonInit .Get <MemberDeclarationSyntax>(@class.Identifier)); } //generate the interface if (options.GenerateInterface) { scope.AddType(CreateInterface(@class)); } if (options.GenerateRemote) { //add a remote type, to be used with an identity server var remoteMethod = null as MethodDeclarationSyntax; createRemoteType(@class, scope, out remoteMethod); @class = @class.AddMembers(remoteMethod); } if (options.GenerateID) { @class = @class.AddMembers(Templates .ObjectId .Get <MemberDeclarationSyntax>()); } //schedule linking var document = scope.GetDocument(); return(document.change(@class, Link(ctx), null)); }
private static IEnumerable <StatementSyntax> ProcessScopeStatements(SyntaxList <StatementSyntax> statements) { yield return(Templates.NewScope); foreach (var statement in statements) { if (statement is LocalDeclarationStatementSyntax) { //changes to the scope, again expressed as variables var localDeclaration = statement as LocalDeclarationStatementSyntax; var type = localDeclaration.Declaration.Type; Debug.Assert(localDeclaration.Declaration.Variables.Count == 1); //td: for now var variable = localDeclaration.Declaration.Variables.Single(); if (variable.Initializer != null) { yield return(statement); yield return(Templates.AddToNewScope .Get <StatementSyntax>( Roslyn.Quoted(variable.Identifier.ToString()), CSharp.IdentifierName(variable.Identifier))); } else { //td: error, should set values } } else if (statement is ExpressionStatementSyntax) { //invocations to happen on a different context var invocation = (statement as ExpressionStatementSyntax) .Expression as InvocationExpressionSyntax; if (invocation != null) { if (invocation.Expression is MemberAccessExpressionSyntax) { //td: error, only namspace function calls? } else { yield return(statement.ReplaceNode(invocation, invocation .AddArgumentListArguments(CSharp.Argument(Templates .NewScopeValue)))); } } else { //td: error, bad invocation } } else { //td: error, only variables and invocations } } }
private static SyntaxNode ArgumentList(RParser.SublistContext args, Func <ParserRuleContext, Scope, SyntaxNode> transform, Scope scope) { var nodes = new List <ArgumentSyntax>(); foreach (var arg in args.sub()) { var argName = null as string; var value = null as ExpressionSyntax; if (arg is RParser.SubExpressionContext) { value = (ExpressionSyntax)transform((arg as RParser.SubExpressionContext).expr(), scope); } else if (arg is RParser.SubAssignmentContext) { var paramName = (arg as RParser.SubAssignmentContext); argName = paramName.ID().ToString(); value = (ExpressionSyntax)transform(paramName.expr(), scope); } else if (arg is RParser.SubStringAssignmentContext) { var paramName = (arg as RParser.SubStringAssignmentContext); argName = paramName.STRING().ToString(); value = (ExpressionSyntax)transform(paramName.expr(), scope); } else if (arg is RParser.SubIncompleteNullContext || arg is RParser.SubNullAssignmentContext) { throw new NotImplementedException(); } else if (arg is RParser.SubEllipsisContext) { throw new NotImplementedException(); } else if (arg is RParser.SubIncompleteAssignmentContext || arg is RParser.SubIncompleteStringContext || arg is RParser.SubIncompleteStringContext) { throw new NotImplementedException(); } else if (arg is RParser.SubEmptyContext) { continue; } else { Debug.Assert(false); } Debug.Assert(value != null); var result = CSharp.Argument(value); if (argName != null) { result = result .WithNameColon(CSharp .NameColon(argName)); } nodes.Add(result); } return(CSharp .ArgumentList() .WithArguments(CSharp .SeparatedList(nodes))); }
private static void createPublicSignals(Class ctx, MethodDeclarationSyntax method, Signal signal) { var returnType = method.ReturnType.ToString() != "void" ? method.ReturnType : Roslyn.@object; var internalMethod = method.Identifier.ToString(); if (!internalMethod.StartsWith("__concurrent")) { internalMethod = "__concurrent" + internalMethod; } var internalCall = Templates .InternalCall .Get <ExpressionSyntax>(internalMethod); internalCall = internalCall .ReplaceNodes(internalCall .DescendantNodes() .OfType <InvocationExpressionSyntax>() .Where(i => i.ArgumentList.Arguments.Count == 2), (on, nn) => nn .WithArgumentList(CSharp.ArgumentList(CSharp.SeparatedList( method.ParameterList.Parameters .Select(param => CSharp.Argument(CSharp.IdentifierName( param.Identifier))) .Union(on.ArgumentList.Arguments))))); ctx.AddMember(AddParameters( method.ParameterList, Templates.TaskPublicMethod .Get <MethodDeclarationSyntax>( method.Identifier.ToString(), returnType, internalCall))); ctx.AddMember(AddParameters( method.ParameterList, Templates.TaskCallbackMethod .Get <MethodDeclarationSyntax>( method.Identifier.ToString(), internalCall))); }