private static SyntaxNode ProcessContract(SyntaxNode node, Scope scope, SyntacticalExtension<SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { var block = extension.Body as BlockSyntax; Debug.Assert(block != null); List<StatementSyntax> checks = new List<StatementSyntax>(); foreach (var st in block.Statements) { var stExpression = st as ExpressionStatementSyntax; if (stExpression == null) { scope.AddError("contract01", "contracts only support boolean expressions", st); continue; } var contractCheck = ContractCheck .ReplaceNodes(ContractCheck .DescendantNodes() .OfType<ExpressionSyntax>() .Where(expr => expr.ToString() == "__condition"), (oldNode, newNode) => stExpression.Expression); checks.Add(contractCheck); } return CSharp.Block(checks); } scope.AddError("contract02", "contract cannot return a value", node); return node; }
public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { if (node.Declaration.Variables.Count == 1) { var variable = node .Declaration .Variables[0]; if (variable.Initializer != null) { var call = variable.Initializer.Value as InvocationExpressionSyntax; if (call != null) { SyntacticalExtension <SyntaxNode> extension = codeExtension(call); if (extension != null) { if (extension.Kind != ExtensionKind.Code) { //td: error, incorrect extension (i.e. a code extension being used inside a type) return(node); } _lookahead = CheckCodeExtension(node, extension); return(null); } } } } return(base.VisitLocalDeclarationStatement(node)); }
private static SyntaxNode ProcessContract(SyntaxNode node, Scope scope, SyntacticalExtension <SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { var block = extension.Body as BlockSyntax; Debug.Assert(block != null); List <StatementSyntax> checks = new List <StatementSyntax>(); foreach (var st in block.Statements) { var stExpression = st as ExpressionStatementSyntax; if (stExpression == null) { scope.AddError("contract01", "contracts only support boolean expressions", st); continue; } var contractCheck = ContractCheck .ReplaceNodes(ContractCheck .DescendantNodes() .OfType <ExpressionSyntax>() .Where(expr => expr.ToString() == "__condition"), (oldNode, newNode) => stExpression.Expression); checks.Add(contractCheck); } return(CSharp.Block(checks)); } scope.AddError("contract02", "contract cannot return a value", node); return(node); }
private SyntaxNode typeExtension(SyntaxNode node, SyntacticalExtension <SyntaxNode> extension) { return(CSharp.ClassDeclaration(extension.Identifier) .WithMembers(CSharp.List <MemberDeclarationSyntax>(new[] { CSharp.MethodDeclaration(CSharp.ParseTypeName("int"), "myMethod") .WithBody((BlockSyntax)extension.Body) }))); }
private static SyntaxNode ProcessSynch(SyntaxNode node, Scope scope, SyntacticalExtension <SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { //td: verify it's inside an asynch return(SynchTemplate .ReplaceNodes(SynchTemplate .DescendantNodes() .OfType <BlockSyntax>(), (oldNode, newNode) => extension.Body)); } scope.AddError("synch01", "synch does not return a value", node); return(node); }
private static SyntaxNode ProcessSynch(SyntaxNode node, Scope scope, SyntacticalExtension<SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { //td: verify it's inside an asynch return SynchTemplate .ReplaceNodes(SynchTemplate .DescendantNodes() .OfType<BlockSyntax>(), (oldNode, newNode) => extension.Body); } scope.AddError("synch01", "synch does not return a value", node); return node; }
private SyntaxNode memberExtension(SyntaxNode node, SyntacticalExtension <SyntaxNode> extension) { var memberDecl = node as MethodDeclarationSyntax; Assert.IsNotNull(memberDecl); return(memberDecl .WithReturnType(CSharp.ParseTypeName("int")) .WithIdentifier(CSharp.ParseToken("anotherName")) .WithParameterList(CSharp.ParameterList()) .WithBody(memberDecl.Body .AddStatements(new[] { CSharp.ParseStatement("var myFoo = 5;"), CSharp.ParseStatement("bar(myFoo);") }))); }
private SyntaxNode codeExtension(SyntaxNode node, SyntacticalExtension <SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { var codeBlock = extension.Body as BlockSyntax; Assert.IsNotNull(extension.Body); return(codeBlock.AddStatements( new[] { CSharp.ParseStatement("var myFoo = 5;"), CSharp.ParseStatement("bar(myFoo);") })); } Assert.AreEqual(extension.Kind, ExtensionKind.Expression); return(CSharp.ParseExpression("bar(7)")); }
private static SyntaxNode ProcessAsynch(SyntaxNode node, Scope scope, SyntacticalExtension<SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { var result = AsynchTemplate .ReplaceNodes(AsynchTemplate .DescendantNodes() .OfType<BlockSyntax>(), (oldNode, newNode) => extension.Body); var document = scope.GetDocument<SyntaxToken, SyntaxNode, SemanticModel>(); document.change(node.Parent, RoslynCompiler.AddStatement(ContextVariable, before: node)); return result; } scope.AddError("asynch01", "asynch does not return a value", node); return node; }
private static SyntaxNode ProcessAsynch(SyntaxNode node, Scope scope, SyntacticalExtension <SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { var result = AsynchTemplate .ReplaceNodes(AsynchTemplate .DescendantNodes() .OfType <BlockSyntax>(), (oldNode, newNode) => extension.Body); var document = scope.GetDocument <SyntaxToken, SyntaxNode, SemanticModel>(); document.change(node.Parent, RoslynCompiler.AddStatement(ContextVariable, before: node)); return(result); } scope.AddError("asynch01", "asynch does not return a value", node); return(node); }
public override SyntaxNode VisitIncompleteMember(IncompleteMemberSyntax node) { SyntacticalExtension <SyntaxNode> extension = typeExtension(node); if (extension != null) { if (extension.Kind == ExtensionKind.Type) { _lookahead = MatchTypeExtension(node, extension); return(null); //remove the incomplete member } else { //td: error, incorrect extension (i.e. a code extension being used inside a type) return(null); } } return(node); //error, stop processing }
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax method) { SyntacticalExtension <SyntaxNode> extension = methodExtension(method); if (extension != null) { switch (extension.Kind) { case ExtensionKind.Member: case ExtensionKind.Type: { return(extension.Handler(method, new Scope(_scope), extension)); } default: { //td: error, incorrect extension (i.e. a code extension being used inside a type) return(null); } } } return(base.VisitMethodDeclaration(method)); }
//rewriters private Func <SyntaxNode, Scope, LookAheadResult> CheckCodeExtension(SyntaxNode original, SyntacticalExtension <SyntaxNode> extension) { return((node, scope) => { var code = node as BlockSyntax; if (code == null) { return new LookAheadResult { Matched = false } } ; _lookahead = null; extension.Body = base.Visit(code); SyntaxNode resulSyntaxNode = null; if (original is LocalDeclarationStatementSyntax) { extension.Kind = ExtensionKind.Expression; resulSyntaxNode = extension.Handler(node, scope, extension); if (!(resulSyntaxNode is ExpressionSyntax)) { //td: error, expecting expression return new LookAheadResult { Matched = false }; } var localDecl = original as LocalDeclarationStatementSyntax; resulSyntaxNode = localDecl .WithDeclaration(localDecl.Declaration .WithVariables(CSharp.SeparatedList(new[] { localDecl.Declaration.Variables[0] .WithInitializer(localDecl.Declaration.Variables[0].Initializer .WithValue((ExpressionSyntax)resulSyntaxNode)) }))) .WithSemicolonToken(CSharp.ParseToken(";")); } else if (original is ExpressionStatementSyntax) { var exprStatement = original as ExpressionStatementSyntax; var assignment = exprStatement.Expression as AssignmentExpressionSyntax; if (assignment != null) { extension.Kind = ExtensionKind.Expression; resulSyntaxNode = extension.Handler(node, scope, extension); if (!(resulSyntaxNode is ExpressionSyntax)) { //td: error, expecting expression return new LookAheadResult { Matched = false }; } resulSyntaxNode = exprStatement .WithExpression(assignment .WithRight((ExpressionSyntax)resulSyntaxNode)) .WithSemicolonToken(CSharp.ParseToken(";")); } else { resulSyntaxNode = extension.Handler(node, scope, extension); if (resulSyntaxNode != null) { resulSyntaxNode = RoslynCompiler.UpdateExcessId(resulSyntaxNode, node); } } } else { throw new NotImplementedException(); } return new LookAheadResult { Matched = true, Result = resulSyntaxNode, }; }); }
private SyntaxNode memberExtension(SyntaxNode node, SyntacticalExtension<SyntaxNode> extension) { var memberDecl = node as MethodDeclarationSyntax; Assert.IsNotNull(memberDecl); return memberDecl .WithReturnType(CSharp.ParseTypeName("int")) .WithIdentifier(CSharp.ParseToken("anotherName")) .WithParameterList(CSharp.ParameterList()) .WithBody(memberDecl.Body .AddStatements(new[] { CSharp.ParseStatement("var myFoo = 5;"), CSharp.ParseStatement("bar(myFoo);")})); }
private Func <SyntaxNode, Scope, LookAheadResult> MatchTypeExtension(IncompleteMemberSyntax incomplete, SyntacticalExtension <SyntaxNode> extension) { return((node, scope) => { var resulSyntaxNode = node; if (node is ClassDeclarationSyntax) { ClassDeclarationSyntax clazz = (ClassDeclarationSyntax)node; clazz = clazz .WithAttributeLists(incomplete.AttributeLists) .WithModifiers(incomplete.Modifiers); resulSyntaxNode = extension.Handler(node, scope, extension); } //td: error?, expecting class return new LookAheadResult { Matched = resulSyntaxNode != null, Result = resulSyntaxNode }; }); }
private Func<SyntaxNode, Scope, LookAheadResult> MatchTypeExtension(IncompleteMemberSyntax incomplete, SyntacticalExtension<SyntaxNode> extension) { return (node, scope) => { var resulSyntaxNode = node; if (node is ClassDeclarationSyntax) { ClassDeclarationSyntax clazz = (ClassDeclarationSyntax)node; clazz = clazz .WithAttributeLists(incomplete.AttributeLists) .WithModifiers(incomplete.Modifiers); resulSyntaxNode = extension.Handler(node, scope, extension); } //td: error?, expecting class return new LookAheadResult { Matched = resulSyntaxNode != null, Result = resulSyntaxNode }; }; }
//rewriters private Func<SyntaxNode, Scope, LookAheadResult> CheckCodeExtension(SyntaxNode original, SyntacticalExtension<SyntaxNode> extension) { return (node, scope) => { var code = node as BlockSyntax; if (code == null) return new LookAheadResult { Matched = false }; _lookahead = null; extension.Body = base.Visit(code); SyntaxNode resulSyntaxNode = null; if (original is LocalDeclarationStatementSyntax) { extension.Kind = ExtensionKind.Expression; resulSyntaxNode = extension.Handler(node, scope, extension); if (!(resulSyntaxNode is ExpressionSyntax)) { //td: error, expecting expression return new LookAheadResult { Matched = false }; } var localDecl = original as LocalDeclarationStatementSyntax; resulSyntaxNode = localDecl .WithDeclaration(localDecl.Declaration .WithVariables(CSharp.SeparatedList(new[] { localDecl.Declaration.Variables[0] .WithInitializer(localDecl.Declaration.Variables[0].Initializer .WithValue((ExpressionSyntax)resulSyntaxNode))}))) .WithSemicolonToken(CSharp.ParseToken(";")); } else if (original is ExpressionStatementSyntax) { var exprStatement = original as ExpressionStatementSyntax; var assignment = exprStatement.Expression as AssignmentExpressionSyntax; if (assignment != null) { extension.Kind = ExtensionKind.Expression; resulSyntaxNode = extension.Handler(node, scope, extension); if (!(resulSyntaxNode is ExpressionSyntax)) { //td: error, expecting expression return new LookAheadResult { Matched = false }; } resulSyntaxNode = exprStatement .WithExpression(assignment .WithRight((ExpressionSyntax)resulSyntaxNode)) .WithSemicolonToken(CSharp.ParseToken(";")); } else { resulSyntaxNode = extension.Handler(node, scope, extension); if (resulSyntaxNode != null) resulSyntaxNode = RoslynCompiler.UpdateExcessId(resulSyntaxNode, node); } } else throw new NotImplementedException(); return new LookAheadResult { Matched = true, Result = resulSyntaxNode, }; }; }
private SyntaxNode typeExtension(SyntaxNode node, SyntacticalExtension<SyntaxNode> extension) { return CSharp.ClassDeclaration(extension.Identifier) .WithMembers(CSharp.List<MemberDeclarationSyntax>(new[] { CSharp.MethodDeclaration(CSharp.ParseTypeName("int"), "myMethod") .WithBody((BlockSyntax)extension.Body) })); }
//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 }
private SyntaxNode codeExtension(SyntaxNode node, SyntacticalExtension<SyntaxNode> extension) { if (extension.Kind == ExtensionKind.Code) { var codeBlock = extension.Body as BlockSyntax; Assert.IsNotNull(extension.Body); return codeBlock.AddStatements( new[] { CSharp.ParseStatement("var myFoo = 5;"), CSharp.ParseStatement("bar(myFoo);") }); } Assert.AreEqual(extension.Kind, ExtensionKind.Expression); return CSharp.ParseExpression("bar(7)"); }