private static CommonSyntaxNode TransformRootVisualBasic(Roslyn.Compilers.VisualBasic.SyntaxNode originalRoot) { var comments = originalRoot.DescendantTrivia().Where(t => t.Kind == Roslyn.Compilers.VisualBasic.SyntaxKind.CommentTrivia); var newRoot = originalRoot.ReplaceTrivia(comments, (t1, t2) => Roslyn.Compilers.VisualBasic.SyntaxTriviaList.Empty); return newRoot; }
public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { var awaitExpr = null as ExpressionSyntax; var extraStatement = null as StatementSyntax; if (node.Declaration.Variables.Count == 1) { var variable = node .Declaration .Variables[0]; var value = variable ?.Initializer ?.Value; if (node.Declaration.Type.ToString() == "await") { //case: await signal; awaitExpr = CSharp.IdentifierName(variable.Identifier); } else if (value != null && value is AwaitExpressionSyntax) { //case: var a = await b(); extraStatement = CSharp .LocalDeclarationStatement(CSharp.VariableDeclaration( node.Declaration.Type, CSharp.SeparatedList(new[] { CSharp.VariableDeclarator(variable.Identifier) }))); awaitExpr = CSharp.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, CSharp.IdentifierName(variable.Identifier), (value as AwaitExpressionSyntax) .Expression); } } if (awaitExpr != null) { var result = VisitExpressionStatement(Templates .AwaitExpr .Get <ExpressionStatementSyntax>(awaitExpr)) as StatementSyntax; if (extraStatement != null) { var block = Roslyn.TrackNode(CSharp.Block( extraStatement, result)); var document = _scope.GetDocument(); document.change(node.Parent, Roslyn.ExplodeBlock(block)); return(block); } return(result); } return(base.VisitLocalDeclarationStatement(node)); }
private static MethodDeclarationSyntax createRemoteMethod(MethodDeclarationSyntax method) { var original = method; var args = CSharp .AnonymousObjectCreationExpression(CSharp.SeparatedList(method .ParameterList .Parameters .Select(parameter => { var identifierName = CSharp.IdentifierName(parameter.Identifier); return(CSharp.AnonymousObjectMemberDeclarator( CSharp.NameEquals(identifierName), identifierName)); }))); var value = original .ReturnType.ToString() == "void" ? Roslyn.@null : Templates .RemoteResult .Get <ExpressionSyntax>(original.ReturnType); return(method .WithModifiers(CSharp.TokenList()) .AddModifiers( CSharp.Token(SyntaxKind.ProtectedKeyword), CSharp.Token(SyntaxKind.OverrideKeyword)) .WithBody(Templates .RemoteInternalMethod .Get <BlockSyntax>( Roslyn.Quoted(original.Identifier.ToString()), args, value))); }
public Signal AddSignal() { var signal = AddSignal(Roslyn.uniqueId(), false); signal.Internal = true; return(signal); }
private StatementSyntax LinkAssignment(AssignmentExpressionSyntax assignment, InvocationExpressionSyntax success, InvocationExpressionSyntax failure, Dictionary <string, TypeSyntax> assignments) { var leftString = assignment.Left.ToString(); var leftType = Roslyn.SymbolTypeSyntax(_model, assignment.Left); Debug.Assert(assignment.Left is IdentifierNameSyntax); Debug.Assert(!assignments.ContainsKey(leftString)); Debug.Assert(leftType != null); //td: error assignments[leftString] = leftType; var emptyAssignments = new Dictionary <string, TypeSyntax>(); var right = LinkOperand(assignment.Right, success, failure, emptyAssignments); Debug.Assert(right != null); Debug.Assert(!emptyAssignments.Any()); //there are 2 scenarios, first, the right operand was a concurrent expression //in which case it would have a success function var successFunc = right .DescendantNodes() .OfType <ParenthesizedLambdaExpressionSyntax>() .Where(fn => fn .ParameterList .Parameters .Any(p => p.Identifier.ToString() == "__res")) .SingleOrDefault(); if (successFunc != null) { return(right.ReplaceNode(successFunc, successFunc .WithBody(CSharp.Block(new[] { Templates .ExpressionAssigment .Get <StatementSyntax>(assignment.Left, leftType) } .Union(successFunc.Body is BlockSyntax ? (successFunc.Body as BlockSyntax) .Statements .AsEnumerable() : new[] { successFunc.Body as StatementSyntax }) .ToArray())))); } //else, we need to substitute the actual Right expr by //an assignment. var rightString = assignment.Right.ToString(); return(right.ReplaceNodes(right. DescendantNodes() .OfType <ExpressionSyntax>() .Where(node => node.ToString().Equals(rightString)), (on, nn) => CSharp.AssignmentExpression( assignment.Kind(), Templates .ExpressionProperty .Get <ExpressionSyntax>(assignment.Left), nn))); }
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 Func <SyntaxNode, Scope, SyntaxNode> AddFunctionClass(ClassDeclarationSyntax @class) { return((node, scope) => { var document = scope.GetDocument(); @class = (ClassDeclarationSyntax)document.change(@class, CompileFunctionClass); return Roslyn.AddMember(@class)(node, scope); }); }
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { if (_class.IsSignal(node)) { _isStatic = Roslyn.IsStatic(node); return(base.VisitMethodDeclaration(node)); } return(node); }
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 MethodDeclarationSyntax concurrentMethod(Class ctx, MethodDeclarationSyntax method, bool forever = false) { var name = method.Identifier.ToString(); var body = method.Body; var returnStatements = body .DescendantNodes() .OfType <ReturnStatementSyntax>(); var lastReturn = body.Statements.LastOrDefault() as ReturnStatementSyntax; if (returnStatements.Any()) { body = body .ReplaceNodes(returnStatements, (on, nn) => Templates .ExpressionReturn .Get <StatementSyntax>(nn.Expression == null || nn.Expression.IsMissing ? Roslyn.@null : nn.Expression, Roslyn.Quoted(method.Identifier.ToString()))); } if (forever) { body = CSharp.Block( CSharp.ForStatement(body)); } else if (lastReturn == null) { body = body.AddStatements(Templates .ExpressionReturn .Get <StatementSyntax>( Roslyn.@null, Roslyn.Quoted(method.Identifier.ToString()))); } var result = Templates .ConcurrentMethod .Get <MethodDeclarationSyntax>("__concurrent" + name); result = result .WithParameterList(method .ParameterList .AddParameters(result .ParameterList .Parameters .ToArray())) .WithBody(body); ctx.AddMember(result); return(result); }
private StatementSyntax LinkSignal(IdentifierNameSyntax name, InvocationExpressionSyntax success, InvocationExpressionSyntax failure) { var signalName = name.ToString(); var signal = _class.GetSignal(signalName); Debug.Assert(signal != null); return(Templates .SignalListener .Get <StatementSyntax>( Roslyn.Quoted(signalName), WrapInLambda(success))); }
private void AddNodeToTree(Roslyn.Compilers.VisualBasic.SyntaxNode codeNode, ItemsControl parent) { var newNode = new TreeViewItem(); newNode.Header = codeNode.GetType().Name; newNode.ToolTip = codeNode.ToFullString(); parent.Items.Add(newNode); foreach (var childCodeName in codeNode.ChildNodes()) { AddNodeToTree(childCodeName, newNode); } }
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 SyntaxNode Transform(SyntaxNode oldNode, SyntaxNode newNode, Scope scope, LexicalExtension <SyntaxToken> extension) { Debug.Assert(newNode is AnonymousObjectCreationExpressionSyntax); var result = createJson.Get(newNode); var isAssignment = false; result = Roslyn.ReplaceAssignment(oldNode, result, out isAssignment); if (!isAssignment) { scope.AddError("json01", "json expects to be assigned", oldNode); return(newNode); } return(result); }
private static MethodDeclarationSyntax MemberFunctionModifiers(MethodDeclarationSyntax method) { var modifiers = method.Modifiers; if (!modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword))) { method = method.AddModifiers(CSharp.Token(SyntaxKind.StaticKeyword)); } if (!Roslyn.HasVisibilityModifier(method.Modifiers)) { method = method.AddModifiers(CSharp.Token(SyntaxKind.PublicKeyword)); } return(method); }
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 IEnumerable <StatementSyntax> FunctionInjectionStatements(BlockSyntax block, SyntaxNode toReplace, IEnumerable <StatementSyntax> toReplaceWith) { foreach (var statement in block.Statements) { if (Roslyn.SameNode(statement, toReplace)) { foreach (var newStatement in toReplaceWith) { yield return(newStatement); } } else { yield return(statement); } } }
public static dynamic Compile(CotMethod cotMethod, CancellationToken token = default) { var rndClass = CodeSnippet.RandomString(); var pageOfCode = CodeSnippet.GeneratePage(rndClass, new[] { cotMethod.ToString() }, out var refs); var errors = Roslyn.Compile(pageOfCode, refs, out var asm, token); if (errors.Length == 0) { var t = asm.GetType(rndClass); try { var mn = cotMethod.Info.Name.ValueText; var d = RuntimeDelegateFactory.StaticMethod(t, mn); return(d); } catch (ArgumentException) { throw; } } throw new CompilationException(errors); }
public static DelegateWrapper <T> Compile <T>(CotMethod cotMethod, CancellationToken token = default) where T : Delegate { var rndClass = CodeSnippet.RandomString(); var pageOfCode = CodeSnippet.GeneratePage(rndClass, new[] { cotMethod.ToString() }, out var refs); var errors = Roslyn.Compile(pageOfCode, refs, out var asm, token); if (errors.Length == 0) { var t = asm.GetType(rndClass); try { var mn = cotMethod.Info.Name.ValueText; var d = Delegate.CreateDelegate(typeof(T), t, mn, false, true) as T; return(new DelegateWrapper <T>(d, mn)); } catch (ArgumentException) { throw; } } throw new CompilationException(errors); }
public DefaultCaseCodeAction(IDocument document, Roslyn.Compilers.CSharp.SwitchStatementSyntax switchNode) { this.document = document; this.switchNode = switchNode; }
private void AddAlignmentBlockOperationRelativeToFirstTokenOnBaseTokenLine(List<IndentBlockOperation> list, Roslyn.Utilities.ValueTuple<SyntaxToken, SyntaxToken> bracePair) { var option = IndentBlockOption.RelativeToFirstTokenOnBaseTokenLine; SetAlignmentBlockOperation(list, bracePair.Item1, bracePair.Item1.GetNextToken(includeZeroWidth: true), bracePair.Item2, option); }
private static SyntaxNode LinkServerInstance(ServerInstance app, Func <ServerModel, Scope, SyntaxNode> transform, Scope scope) { //a list of statements and types to be added var statements = new List <StatementSyntax>(); foreach (var node in app.Nodes) { var appStatement = default(StatementSyntax); scope.AddType(LinkNode(node, out appStatement)); if (appStatement != null) { statements.Add(appStatement); } } //create the http start // var except = Templates .StringArray .Get <ArrayCreationExpressionSyntax>() .WithInitializer(StringArrayInitializer(app .Nodes .SelectMany(node => node.HostedClasses))); //find functional filters var filters = new List <ExpressionSyntax>(); if (app.SQL != null) { var connectionString = default(ExpressionSyntax); if (app.SQL.ConnectionString != null) { Debug.Assert(app.SQL.ConnectionId == null); connectionString = Roslyn.Quoted(app.SQL.ConnectionString); } else { Debug.Assert(app.SQL.ConnectionId != null); connectionString = Templates .SqlConnectionStringFromConfig .Get <ExpressionSyntax>( Roslyn.Quoted(app.SQL.ConnectionId)); } var connectionClass = app.SQL.ConnectionInstantiator ?? "SqlConnection"; filters.Add(Templates .SqlFilter .Get <ExpressionSyntax>( connectionString, CSharp.IdentifierName(connectionClass))); } filters.Add(Templates.UserFilter); //start the server statements.Add(Templates .StartHttpServer .Get <StatementSyntax>( Roslyn.Quoted(app.Host.Address), Roslyn.Quoted(app.Identity), Roslyn.Quoted(app.StaticFiles, escaped: true), Roslyn.Constant(app.Threads), except, Roslyn.Constant(app.Nodes.Count), app.Id, Templates .EmptyArray .WithInitializer(CSharp.InitializerExpression( SyntaxKind.ArrayInitializerExpression, CSharp.SeparatedList( filters))))); //generate configuration class var result = Templates .ServerInstance .Get <ClassDeclarationSyntax>(app.Id, Roslyn.Quoted(app.Id)); var runMethods = result .DescendantNodes() .OfType <MethodDeclarationSyntax>() .Where(method => method.Identifier.ToString() == "Run"); return(result.ReplaceNodes(runMethods, (on, nn) => nn.AddBodyStatements(statements.ToArray()))); }
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 Func <SyntaxNode, Scope, SyntaxNode> CompileApp(Options options) { var compileObject = CompileObject(options); return((node, scope) => { var result = (node as ClassDeclarationSyntax) .WithModifiers(CSharp.TokenList( CSharp.Token(SyntaxKind.PublicKeyword))); var main = result .DescendantNodes() .OfType <MethodDeclarationSyntax>() .Where(method => method.Identifier.ToString() == "main") .SingleOrDefault(); if (main != null) { result = result.ReplaceNode(main, CompileAppMain(main, options)); } else { Debug.Assert(false, "concurrent app must have main"); //td: error } if (options.GenerateAppProgram) { scope.AddType(Templates.AppProgram.Get <ClassDeclarationSyntax>()); } //convert to concurrent object result = (ClassDeclarationSyntax)compileObject(result, scope); //add a way for this app to run, stop and await completion var runner = null as Func <BlockSyntax, MemberDeclarationSyntax>; if (options.GenerateAppConstructor) { runner = body => CSharp.ConstructorDeclaration("__app") .WithModifiers(CSharp.TokenList( CSharp.Token(SyntaxKind.StaticKeyword))) .WithBody(body); } else { runner = body => Templates.AppRun.WithBody(options.GenerateAppProgram ? CSharp.Block(new StatementSyntax[] { Templates.AppAssignArguments } .Union(body.Statements)) : body); } return result.AddMembers( runner(Templates.AppThreaded .Get <BlockSyntax>( Roslyn.Constant(options.ThreadCount), Roslyn.Constant(options.BlockUntilNextEvent), options.AsFastAsPossible ? Templates.HighPriority : Templates.NormalPriority)), Templates.AppArguments, Templates.AppStop, Templates.AppAwait); }); }
/// <summary> /// Inspects the given code document to see if there's any need for immutable / mutable generation /// </summary> /// <param name="codeDocument"></param> /// <param name="text"></param> private void InspectAndUpdate(IDocument codeDocument, Roslyn.Compilers.Common.CommonCompilation commonCompilation) { // mild premature optimization var text = codeDocument.GetText().GetText(); if (text.Contains("immutable_generated") && text.Contains("immutable_declarations")) { var updateRegions = new List<UpdateRegion>(); // Compile var syntax = codeDocument.GetSyntaxTree(); var root = syntax.GetRoot(); // Filter down to classes foreach (var classDeclaration in root.DescendantNodes().OfType<ClassDeclarationSyntax>()) { var immutableGeneratedTrivia = this.GetRegion(classDeclaration, "immutable_generated"); if (null != immutableGeneratedTrivia) { var className = classDeclaration.Identifier.ValueText; var classFullName = className; var parent = classDeclaration.Parent; while (null != parent) { if (parent is NamespaceDeclarationSyntax) classFullName = ((NamespaceDeclarationSyntax)parent).Name.ToString().Trim() + "." + classFullName; parent = parent.Parent; } var compiledClass = commonCompilation.GetTypeByMetadataName(classFullName); var updateRegion = new UpdateRegion() { begin = immutableGeneratedTrivia.beginRegionTrivia.FullSpan.End, end = immutableGeneratedTrivia.endRegionTrivia.FullSpan.Start }; try { if (null != compiledClass) { Console.WriteLine("\t\t\t{0} is an immutable", classDeclaration.Identifier.GetText()); var immutableDeclarationsTrivia = this.GetRegion(classDeclaration, "immutable_declarations"); if (null != immutableDeclarationsTrivia) { var fields = new List<IFieldSymbol>(); // Iterate through all the tokens in the immutable_declarations to figure out the fields var token = immutableDeclarationsTrivia.beginRegionTrivia.Token; while (token != immutableDeclarationsTrivia.endRegionTrivia.Token) { if (token.Kind == SyntaxKind.IdentifierToken) { // Get the compiled version of the identifies var identifier = token.ValueText; var field = compiledClass.GetMembers(identifier) .FirstOrDefault() as IFieldSymbol; // Verify it if (null != field) { if (field.IsStatic) throw new Exception(string.Format( "Can not wrap static fields: {0}", identifier)); if (!field.IsReadOnly) throw new Exception(string.Format( "Exposed fields must be readonly: {0}", identifier)); if (field.HasConstantValue) throw new Exception(string.Format( "Exposed fields not be constant: {0}", identifier)); // TODO: Need to verify that the field is private fields.Add(field); } } token = token.GetNextToken(); } var builder = new StringBuilder(); builder.AppendLine(); builder.Append(immutableGeneratedTrivia.whiteSpace); builder.AppendLine("// Generated code, do not edit unless you know what you're doing!"); var propertyNames = new Dictionary<IFieldSymbol, string>(); // Generate properties and set mutators foreach (var field in fields) { var type = field.Type.ToDisplayString(); // Determine property name string propertyName; if (field.Name.StartsWith("_")) propertyName = field.Name.Substring(1); else { var firstChar = field.Name[0].ToString(); var firstCharU = firstChar.ToUpperInvariant(); var firstCharL = firstChar.ToLowerInvariant(); if (firstCharL == firstCharU) { propertyName = field.Name.ToUpperInvariant(); if (propertyName == field.Name) propertyName = field.Name.ToLowerInvariant(); if (propertyName == field.Name) propertyName = field.Name + "_Property"; } else { propertyName = field.Name.Substring(1); if (firstCharL == firstChar) propertyName = firstCharU + propertyName; else propertyName = firstCharL + propertyName; } } propertyNames[field] = propertyName; // Property builder.AppendFormat( "{0}public {1} {2} {{ get {{ return this.{3}; }}}}", immutableGeneratedTrivia.whiteSpace, type, propertyName, field.Name); builder.AppendLine(); // Set Mutator builder.AppendFormat( "{0}public {1} Set{2}({3} {4}) {{ return new {1}(", immutableGeneratedTrivia.whiteSpace, className, propertyName, type, field.Name); var passes = new List<string>(); foreach (var subField in fields) { if (subField == field) passes.Add(field.Name); else passes.Add("this." + subField.Name); } builder.Append(string.Join(", ", passes.ToArray())); builder.AppendLine("); }"); builder.AppendLine(); } builder.AppendLine(); // Generate constructor builder.Append(immutableDeclarationsTrivia.whiteSpace); builder.AppendFormat("public {0}(", className); var argumentDeclarations = new List<string>(); foreach (var field in fields) { argumentDeclarations.Add(string.Format( "{0} {1} = default({0})", field.Type.ToDisplayString(), field.Name)); } builder.Append(string.Join(", ", argumentDeclarations.ToArray())); builder.Append(") { "); foreach (var field in fields) { var typeDisplayString = field.Type.ToDisplayString(); if (this.IsIEnumerable(typeDisplayString)) { builder.AppendFormat("if (default({1}) != {0}) this.{0} = {0}.ToArray().AsEnumerable(); ", field.Name, typeDisplayString); } else { builder.AppendFormat("this.{0} = {0}; ", field.Name); } } builder.AppendLine("}"); builder.AppendLine(); // Mutable class builder.Append(immutableGeneratedTrivia.whiteSpace); builder.Append("public class Mutable {"); foreach (var field in fields) { var typeDisplayString = field.Type.ToDisplayString(); if (this.IsIEnumerable(typeDisplayString)) { typeDisplayString = typeDisplayString.Replace("IEnumerable", "IList"); } builder.AppendFormat( " public {0} {1} {{ get; set; }}", typeDisplayString, propertyNames[field]); } // Generate immutable from mutable builder.AppendFormat( " public {0} ToImmutable() {{ return new {0}(", className); var assignments = new List<string>(fields.Count); foreach (var field in fields) assignments.Add(string.Format( "this.{0}", propertyNames[field])); builder.Append(string.Join(", ", assignments.ToArray())); builder.AppendLine(");} }"); // GenerateMutable method builder.AppendFormat( "{0}public Mutable ToMutable() {{ return new Mutable() {{ ", immutableGeneratedTrivia.whiteSpace); assignments = new List<string>(fields.Count); foreach (var field in fields) { var copyMethod = String.Empty; var typeDisplayString = field.Type.ToDisplayString(); if (this.IsIEnumerable(typeDisplayString)) { copyMethod = ".ToList()"; } assignments.Add(string.Format( "{0} = this.{1}{2}", propertyNames[field], field.Name, copyMethod)); } builder.Append(string.Join(", ", assignments.ToArray())); builder.AppendLine("}; }"); builder.AppendLine(); // == builder.AppendFormat( "{0}public static bool operator ==({1} lhs, {1} rhs) {{ return", immutableGeneratedTrivia.whiteSpace, className); var conditionBuilder = new List<string>(fields.Count); foreach (var field in fields) { var typeDisplayString = field.Type.ToDisplayString(); if (this.IsIEnumerable(typeDisplayString)) { conditionBuilder.Add(string.Format( " lhs.{0}.SequenceEqual(rhs.{0})", field.Name)); } else { conditionBuilder.Add(string.Format( " lhs.{0} == rhs.{0} ", field.Name)); } } builder.Append(string.Join("&&", conditionBuilder.ToArray())); builder.Append("; }"); builder.AppendLine(); // != builder.AppendFormat( "{0}public static bool operator !=({1} lhs, {1} rhs) {{ return", immutableGeneratedTrivia.whiteSpace, className); conditionBuilder = new List<string>(fields.Count); foreach (var field in fields) { var typeDisplayString = field.Type.ToDisplayString(); if (this.IsIEnumerable(typeDisplayString)) { conditionBuilder.Add(string.Format( " (!lhs.{0}.SequenceEqual(rhs.{0}))", field.Name)); } else { conditionBuilder.Add(string.Format( " lhs.{0} != rhs.{0} ", field.Name)); } } builder.Append(string.Join("||", conditionBuilder.ToArray())); builder.Append("; }"); builder.AppendLine(); updateRegion.newText = builder.ToString(); } else { updateRegion.newText = immutableGeneratedTrivia.whiteSpace + "// Missing #region immutable_declarations\n\r"; } } else { updateRegion.newText = immutableGeneratedTrivia.whiteSpace + "// " + classFullName + " does not compile\n\r"; } } catch (Exception e) { updateRegion.newText = string.Format("/*{0}*/\r\n", e); } updateRegions.Add(updateRegion); } } if (updateRegions.Count > 0) this.Update(codeDocument, text, updateRegions); } }
public override SyntaxNode VisitTryStatement(TryStatementSyntax node) { _trysInStack++; try { var newNode = (TryStatementSyntax)base.VisitTryStatement(node); if (_tryConcurrent) { var variableName = "__try" + _trysInStack; _tryVariables.Add(variableName); //we can only split on expressions directly on the try level //i.e. no try { if () { EXPRESSION }} if (_trysInStack > 1 && !(newNode.Parent.Parent is TryStatementSyntax)) { Debug.Assert(false); //td: error return(newNode); } var statements = new List <StatementSyntax>(newNode.Block.Statements); var newStatements = new List <StatementSyntax>(); var currentIndex = 0; while (currentIndex < statements.Count) { var oldIndex = currentIndex; for (int i = oldIndex; i < statements.Count; i++, currentIndex++) { var statement = statements[i]; if (statement is YieldStatementSyntax) { newStatements.Add(newNode .WithBlock(CSharp.Block( statements .Skip(oldIndex) .Take(currentIndex - oldIndex - 1)))); //variable and return yield //td: assert newStatements.Add(statements[currentIndex - 1]); newStatements.Add(statements[currentIndex++]); break; } //must make variables available to later code, unless it precedes a yield var yieldNext = statements.Count > i + 1 && statements[i + 1] is YieldStatementSyntax; if (statement is LocalDeclarationStatementSyntax && !yieldNext) { var decl = statement as LocalDeclarationStatementSyntax; var varType = decl.Declaration.Type; if (varType == null || varType.Kind() == SyntaxKind.TypeVarKeyword) { varType = Roslyn.SymbolTypeSyntax(_model, decl .Declaration .Variables[0] .Initializer .Value); } Debug.Assert(varType != null, "Untyped local variable on try fix"); var assignmentStatements = new List <StatementSyntax>(); newStatements.Add(decl .WithDeclaration(decl.Declaration .WithType(varType) .WithVariables(CSharp.SeparatedList( decl .Declaration .Variables .Select(v => { assignmentStatements.Add(CSharp.ExpressionStatement( CSharp.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, CSharp.IdentifierName(v.Identifier), v.Initializer.Value))); return(v.WithInitializer(v .Initializer .WithValue(Templates .DefaultValue .Get <ExpressionSyntax>(varType)))); }))))); //once moved the variables "up" scope //we must keep the assignments Debug.Assert(assignmentStatements.Any()); statements.RemoveAt(i); statements.InsertRange(i, assignmentStatements); } } } Debug.Assert(newStatements.Any()); return(LinkTryStatements(newStatements, variableName)); } return(newNode); } finally { _trysInStack--; } }