private static SyntaxNode Typedef(SyntaxNode node, Scope scope) { var field = node .AncestorsAndSelf() .OfType <FieldDeclarationSyntax>() .FirstOrDefault(); if (field == null) { scope.AddError("xs01", "malformed typedef", node); //td: error, malformed typedef return(node); } if (field.Declaration.Variables.Count != 1) { scope.AddError("xs01", "malformed typedef", node); return(node); } var variable = field .Declaration .Variables[0]; Debug.Assert(variable.Initializer == null || variable.Initializer.IsMissing); var type = RoslynCompiler.UnMark(field.Declaration.Type); var identifier = variable.Identifier; var parentScope = scope.CreateScope <SyntaxToken, SyntaxNode, SemanticModel>(field.Parent); Debug.Assert(parentScope != null); parentScope.set("__tdef" + identifier.ToString(), type); //schedule deletion var document = scope.GetDocument <SyntaxToken, SyntaxNode, SemanticModel>(); document.change(field.Parent, RoslynCompiler.RemoveMember(field)); //return intact return(node); }
//server compilation private static SyntaxNode CompileServer(SyntaxNode node, Scope scope, SyntacticalExtension <SyntaxNode> data) { Debug.Assert(node is MethodDeclarationSyntax); var methodSyntax = node as MethodDeclarationSyntax; var mainServer = new ServerModel(); if (!parseMainServer(methodSyntax, mainServer)) { return(node); //errors } //main server class var configurationClass = Templates .ConfigClass .Get <ClassDeclarationSyntax>(data.Identifier); configurationClass = configurationClass .ReplaceNodes(configurationClass .DescendantNodes() .OfType <MethodDeclarationSyntax>(), (on, nn) => { var methodName = nn.Identifier.ToString(); switch (methodName) { case "Deploy": return(nn.AddBodyStatements( mainServer .Nodes .SelectMany(serverNode => serverNode.DeployStatements) .Union( mainServer.DeployStatements) .ToArray())); case "Start": return(nn.AddBodyStatements(mainServer.StartStatements.ToArray())); case "StartNodes": return(nn.AddBodyStatements( mainServer .Nodes .Select(serverNode => Templates .NodeInvocation .Get <StatementSyntax>(serverNode.ServerId)) .ToArray())); case "RemoteTypes": var initializer = Templates .RemoteTypes .DescendantNodes() .OfType <InitializerExpressionSyntax>() .Single(); return(nn.AddBodyStatements(Templates .RemoteTypes .ReplaceNode( initializer, initializer.AddExpressions(mainServer .Nodes .SelectMany(serverNode => serverNode.HostedClasses) .Select(type => CSharp.TypeOfExpression(type)) .ToArray())))); case "NodeCount": return(nn.AddBodyStatements(CSharp .ReturnStatement(CSharp.ParseExpression( mainServer.Nodes.Count.ToString())))); } throw new NotImplementedException(); }); //add a method per node which will be invoked when starting configurationClass = configurationClass .AddMembers(mainServer .Nodes .Select(serverNode => { var hostedTypes = Templates .TypeArray .WithInitializer(CSharp.InitializerExpression( SyntaxKind.ArrayInitializerExpression, CSharp.SeparatedList <ExpressionSyntax>( serverNode .HostedClasses .Select(type => CSharp.TypeOfExpression(type))))); return(Templates .NodeMethod .Get <MethodDeclarationSyntax>( serverNode.ServerId, hostedTypes) .AddBodyStatements(serverNode .StartStatements .ToArray())); }) .ToArray()); //apply changes var document = scope.GetDocument(); document.change(node.Parent, RoslynCompiler.AddType(configurationClass)); document.change(node.Parent, RoslynCompiler.RemoveMember(node)); return(node); //untouched, it will be removed }