public static IEnumerable <SyntaxNode> BuildMethod(this RoslynTranslator roslynTranslator, IFunctionModel stack, IPortModel portModel) { roslynTranslator.ClearBuiltStacks(); var generatedName = roslynTranslator.MakeUniqueName(stack.CodeTitle); var methodSyntaxNode = RoslynBuilder.DeclareMethod( generatedName, AccessibilityFlags.Public, stack.ReturnType.Resolve(roslynTranslator.Stencil)); var localDeclarationNodes = BuildLocalDeclarations(roslynTranslator, stack); var argumentNodes = BuildArguments(roslynTranslator.Stencil, stack); methodSyntaxNode = methodSyntaxNode.WithParameterList(SyntaxFactory.ParameterList( SyntaxFactory.SeparatedList(argumentNodes.ToArray()))); methodSyntaxNode = methodSyntaxNode.WithBody(SyntaxFactory.Block(localDeclarationNodes.ToArray())); if (stack.EnableProfiling) { throw new NotImplementedException("BuildMethod Profiling not implemented"); // methodSyntaxNode = methodSyntaxNode.WithAdditionalAnnotations(InstrumentForProfiling.profilingAnnotation); } BlockSyntax stackBlock = SyntaxFactory.Block(); roslynTranslator.BuildStack(stack, ref stackBlock); foreach (var statement in stackBlock.Statements) { methodSyntaxNode = methodSyntaxNode.AddBodyStatements(statement); } yield return(methodSyntaxNode); }
IEnumerable <MemberDeclarationSyntax> BuildComponentMembers(RoslynTranslator translator) { var states = new List <SwitchSectionSyntax>(); var variables = new Dictionary <string, FieldDeclarationSyntax>(); var stateIndex = 0; // Add members (MoveNext + variables) from coroutine nodes in stack var stack = Parent.IterationContext.Query; BuildStack(translator, stack, ref variables, ref states, ref stateIndex); // Fields var members = new List <MemberDeclarationSyntax> { RoslynBuilder.DeclareField( typeof(int), RoslynEcsBuilder.CoroutineStateVariableName, AccessibilityFlags.Private) }; members.AddRange(variables.Values); // Parameters + Arguments foreach (var component in m_AccessedComponents) { var componentName = GetComponentVariableName(IterationContext.Query, component); var componentType = component.Resolve(IterationContext.Stencil); m_Parameters.Add( Argument(IdentifierName(componentName)) .WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Parameter(Identifier(componentName)) .WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))) .WithType(TypeSystem.BuildTypeSyntax(componentType))); } foreach (var localVariable in IterationContext.Query.FunctionVariableModels) { m_Parameters.Add( Argument(IdentifierName(localVariable.Name)), Parameter(Identifier(localVariable.Name)) .WithType(TypeSystem.BuildTypeSyntax(localVariable.DataType.Resolve(IterationContext.Stencil)))); } // Create MoveNext method members.Add( RoslynBuilder.DeclareMethod(k_MoveNext, AccessibilityFlags.Public, typeof(bool)) .WithParameterList( ParameterList(SeparatedList(m_Parameters.Values))) .WithBody( Block( SwitchStatement(IdentifierName(RoslynEcsBuilder.CoroutineStateVariableName)) .WithOpenParenToken(Token(SyntaxKind.OpenParenToken)) .WithCloseParenToken(Token(SyntaxKind.CloseParenToken)) .WithSections(List(states)), ReturnStatement( LiteralExpression(SyntaxKind.FalseLiteralExpression))))); return(members); }
protected MethodDeclarationSyntax BuildUpdateCoroutineMethod() { var states = new List <SwitchSectionSyntax>(); var index = 0; foreach (var state in m_States) { if (!state.SkipStateBuilding) { state.Statements.Add(BuildGoToState(state.NextStateIndex)); state.Statements.Add(ReturnStatement(LiteralExpression(SyntaxKind.TrueLiteralExpression))); } states.Add(SwitchSection() .WithLabels( SingletonList <SwitchLabelSyntax>( CaseSwitchLabel( LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(index))))) .WithStatements( SingletonList <StatementSyntax>( Block(state.Statements)))); index++; } var coroutineIdentifier = BuildCoroutineParameter(); return(RoslynBuilder.DeclareMethod( UpdateMethodName, AccessibilityFlags.Private | AccessibilityFlags.Static, typeof(bool)) .WithParameterList( ParameterList(SeparatedList(m_Parameters.Values))) .WithBody( Block( SwitchStatement( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, coroutineIdentifier, IdentifierName(k_CoroutineStateVariableName))) .WithOpenParenToken(Token(SyntaxKind.OpenParenToken)) .WithCloseParenToken(Token(SyntaxKind.CloseParenToken)) .WithSections(List(states)), ReturnStatement( LiteralExpression(SyntaxKind.FalseLiteralExpression))))); }
protected virtual Microsoft.CodeAnalysis.SyntaxTree ToSyntaxTree(VSGraphModel graphModel, CompilationOptions options) { //TODO fix graph name, do not use the asset name var className = graphModel.TypeName; var baseClass = graphModel.Stencil.GetBaseClass().Name; var classDeclaration = ClassDeclaration(className) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))); if (!String.IsNullOrEmpty(baseClass)) { classDeclaration = classDeclaration.WithBaseList( BaseList( SingletonSeparatedList <BaseTypeSyntax>( SimpleBaseType( IdentifierName(baseClass))))); } if (graphModel.Stencil.addCreateAssetMenuAttribute) { classDeclaration = classDeclaration.WithAttributeLists( SingletonList( AttributeList( SingletonSeparatedList( Attribute( IdentifierName("CreateAssetMenu")) .WithArgumentList( AttributeArgumentList( SeparatedList <AttributeArgumentSyntax>( new SyntaxNodeOrToken[] { AttributeArgument( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal(graphModel.Stencil.fileName))) .WithNameEquals( NameEquals( IdentifierName("fileName"))), Token(SyntaxKind.CommaToken), AttributeArgument( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal(graphModel.Stencil.menuName))) .WithNameEquals( NameEquals( IdentifierName("menuName"))) }))))))); } var allMembers = new List <MemberDeclarationSyntax>(); m_AllFields = new List <MemberDeclarationSyntax>(); var allRemainingMembers = new List <MemberDeclarationSyntax>(); foreach (var fieldDecl in graphModel.GraphVariableModels) { var fieldSyntaxNode = fieldDecl.DeclareField(this); m_AllFields.Add(fieldSyntaxNode); } var entryPoints = graphModel.GetEntryPoints(); Dictionary <string, MethodDeclarationSyntax> declaredMethods = new Dictionary <string, MethodDeclarationSyntax>(); foreach (var stack in entryPoints) { var entrySyntaxNode = BuildNode(stack); foreach (var memberDeclaration in entrySyntaxNode.Cast <MemberDeclarationSyntax>()) { if (memberDeclaration is MethodDeclarationSyntax methodDeclarationSyntax) { string key = methodDeclarationSyntax.Identifier.ToString(); declaredMethods.Add(key, methodDeclarationSyntax); } else { allRemainingMembers.Add(memberDeclaration); } } } allMembers.AddRange(m_AllFields); m_AllFields = null; allMembers.AddRange(allRemainingMembers); if (m_EventRegistrations.Any()) { if (!declaredMethods.TryGetValue("Update", out var method)) { method = RoslynBuilder.DeclareMethod("Update", AccessibilityFlags.Public, typeof(void)) .WithParameterList( ParameterList( SeparatedList( Enumerable.Empty <ParameterSyntax>()))) .WithBody(Block()); } BlockSyntax blockSyntax = Block(m_EventRegistrations.Concat(method.Body.Statements)); method = method.WithBody(blockSyntax); declaredMethods["Update"] = method; } allMembers.AddRange(declaredMethods.Values); classDeclaration = classDeclaration.AddMembers(allMembers.ToArray()); var referencedNamespaces = new[] { "System", "System.Collections", "System.Collections.Generic", "System.Dynamic", "System.Linq", "Microsoft.CSharp", "UnityEngine", "UnityEngine.SceneManagement", "UnityEngine.VisualScripting" }.Select(namespaceName => UsingDirective(ParseName(namespaceName))); var namespaceAliases = new Dictionary <string, string> { { "UnityEngine.Object", "Object" }, { "UnityEngine.Random", "Random" }, { "UnityEngine.Debug", "Debug" }, { "UnityEngine.SceneManagement.SceneManager", "SceneManager" }, }.Select(pair => UsingDirective(ParseName(pair.Key)) .WithAlias(NameEquals( IdentifierName(pair.Value)))); UsingDirectiveSyntax[] usings = referencedNamespaces.Concat(namespaceAliases).ToArray(); var compilationUnit = CompilationUnit() .WithUsings( List(usings)) .WithMembers( SingletonList <MemberDeclarationSyntax>(classDeclaration)).NormalizeWhitespace(); return(compilationUnit.SyntaxTree); }
public ClassDeclarationSyntax Build(RoslynTranslator translator, VSGraphModel graphModel) { var baseClass = m_NeedToCompleteDependenciesFirst ? nameof(ComponentSystem) : nameof(JobComponentSystem); m_ClassDeclaration = m_ClassDeclaration.WithBaseList( BaseList( SingletonSeparatedList <BaseTypeSyntax>( SimpleBaseType( IdentifierName(baseClass))))); foreach (var queryTracking in m_QueryHasStateTracking) { var trackingMembers = new List <MemberDeclarationSyntax>(); if (queryTracking.Value.Tracking) { trackingMembers.Add( FieldDeclaration( VariableDeclaration( PredefinedType( Token(SyntaxKind.BoolKeyword))) .WithVariables( SingletonSeparatedList( VariableDeclarator( Identifier("Processed"))))) .WithModifiers( TokenList( Token(SyntaxKind.InternalKeyword)))); } DeclareComponent <ISystemStateComponentData>(queryTracking.Value.ComponentName, trackingMembers); } foreach (var eventSystem in m_EventSystems) { // ClearEvents<TestEvent2>.Initialize(World); InitializationStatements.Add(ExpressionStatement(InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, GenericName( Identifier("EventSystem")) .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList <TypeSyntax>( IdentifierName(eventSystem.FullName)))), IdentifierName("Initialize"))) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument( IdentifierName("World"))))))); } if ((TranslationOptions & RoslynEcsTranslator.TranslationOptions.Tracing) != 0) { DeclareAndInitField(typeof(TracingRecorderSystem), nameof(TracingRecorderSystem), initValue: InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("World"), GenericName( Identifier(nameof(World.GetExistingSystem))) .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList <TypeSyntax>( IdentifierName(nameof(TracingRecorderSystem)))))))); } HashSet <string> declaredQueries = new HashSet <string>(); foreach (var group in m_WrittenComponentsPerGroup) { declaredQueries.Add(group.Key.Query.ComponentQueryDeclarationModel.GetId()); DeclareEntityQueries(group.Value); } // declare unused queries in case there's a Count Entities In Query node somewhere foreach (var graphVariable in graphModel.GraphVariableModels.OfType <ComponentQueryDeclarationModel>().Where(q => !declaredQueries.Contains(q.GetId()))) { var args = graphVariable.Components.Select(c => SyntaxFactory.Argument( InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("ComponentType"), GenericName( Identifier("ReadOnly")) .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList <TypeSyntax>( IdentifierName(c.Component.TypeHandle.Resolve(graphModel.Stencil) .FullName)))))) )); var initValue = MakeInitQueryExpression(args); DeclareAndInitField(typeof(EntityQuery), graphVariable.VariableName, initValue: initValue); } var singletonMembers = new List <FieldDeclarationSyntax>(); var initArguments = new List <AssignmentExpressionSyntax>(); foreach (var graphVariable in graphModel.GraphVariableModels .Where(g => g.VariableType == VariableType.GraphVariable)) { singletonMembers.Add(graphVariable.DeclareField(translator, false) .WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.VariableAnnotationKind))); initArguments.Add(RoslynBuilder.Assignment( IdentifierName(graphVariable.VariableName), translator.Constant(graphVariable.InitializationModel.ObjectValue, m_Stencil))); } if (singletonMembers.Any()) { DeclareComponent <IComponentData>(SingletonComponentTypeName, singletonMembers); InitializationStatements.Add(ExpressionStatement( RoslynBuilder.MethodInvocation( nameof(EntityManager.CreateEntity), IdentifierName(nameof(EntityManager)), new[] { Argument(TypeOfExpression(IdentifierName(SingletonComponentTypeName))) }, Enumerable.Empty <TypeSyntax>()))); InitializationStatements.Add( ExpressionStatement( RoslynBuilder.MethodInvocation( SafeGuardNamingSystem.SetSingletonName, null, new[] { Argument(RoslynBuilder.DeclareNewObject( IdentifierName(SingletonComponentTypeName), Enumerable.Empty <ArgumentSyntax>(), initArguments)) }, Enumerable.Empty <TypeSyntax>()))); } // TODO : Remove this once there is real Systems' dependency tool var attributes = new List <AttributeListSyntax>(); foreach (var assetModel in m_Stencil.UpdateAfter.Where(a => a.GraphModel.Stencil is EcsStencil)) { RegisterAttributes <UpdateAfterAttribute>(attributes, assetModel.Name); } foreach (var assetModel in m_Stencil.UpdateBefore.Where(a => a.GraphModel.Stencil is EcsStencil)) { RegisterAttributes <UpdateBeforeAttribute>(attributes, assetModel.Name); } m_ClassDeclaration = m_ClassDeclaration .AddAttributeLists(attributes.ToArray()) .AddMembers(m_ClassMembers.OrderBy(x => x is FieldDeclarationSyntax ? 0 : 1).ToArray()); if (m_InitializationStatements != null) { var onCreateManagerOverride = RoslynBuilder.DeclareMethod( SafeGuardNamingSystem.OnCreateManagerName, AccessibilityFlags.Protected | AccessibilityFlags.Override, typeof(void)); m_ClassDeclaration = m_ClassDeclaration .AddMembers( onCreateManagerOverride.WithBody( Block(m_InitializationStatements))); } if (m_SingletonUpdateSyntax != null) { AddStatement(m_SingletonUpdateSyntax); } var onUpdateBlock = Block(m_UpdateStatements); return(m_ClassDeclaration.AddMembers( RoslynEcsTranslator.MakeOnUpdateOverride( onUpdateBlock, m_NeedToCompleteDependenciesFirst, m_CreatedManagers))); }