public Microsoft.CodeAnalysis.SyntaxTree Translate(VSGraphModel graphModel, CompilationOptions options)
 {
     Profiler.BeginSample("Translation");
     Microsoft.CodeAnalysis.SyntaxTree syntaxTree = ToSyntaxTree(graphModel, options);
     Profiler.EndSample();
     if (syntaxTree is CSharpSyntaxTree cSharpSyntaxTree && syntaxTree.TryGetRoot(out var treeRoot))
     {
         var treeOptions = cSharpSyntaxTree.Options.WithLanguageVersion(LanguageVersion);
         return(syntaxTree.WithRootAndOptions(treeRoot, treeOptions));
     }
     return(syntaxTree);
 }
        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 = UsingDirectives.OrderBy(n => n).Select(ns => UsingDirective(ParseName(ns)));
            var namespaceAliases     = UsingAliases.OrderBy(n => n.Key).Select(pair =>
                                                                               UsingDirective(ParseName(pair.Key))
                                                                               .WithAlias(NameEquals(
                                                                                              IdentifierName(pair.Value))));
            var usings          = referencedNamespaces.Concat(namespaceAliases).ToArray();
            var compilationUnit = CompilationUnit()
                                  .WithUsings(
                List(usings))
                                  .WithMembers(
                SingletonList <MemberDeclarationSyntax>(classDeclaration)).NormalizeWhitespace();

            return(compilationUnit.SyntaxTree);
        }
        public virtual Microsoft.CodeAnalysis.SyntaxTree OnTranslate(VSGraphModel graphModel, AssemblyType assemblyType, CompilationOptions compilationOptions, ref CompilationResult compilationResult)
        {
            const string windowsLineEndings = "\r\n";
            const string unixLineEndings    = "\n";

            Microsoft.CodeAnalysis.SyntaxTree syntaxTree = Translate(graphModel, compilationOptions); // we will measure plugins time later

            string          preferredLineEndings;
            LineEndingsMode lineEndingsForNewScripts = EditorSettings.lineEndingsForNewScripts;

            switch (lineEndingsForNewScripts)
            {
            case LineEndingsMode.OSNative:
                preferredLineEndings = Application.platform == RuntimePlatform.WindowsEditor ? windowsLineEndings : unixLineEndings;
                break;

            case LineEndingsMode.Unix:
                preferredLineEndings = unixLineEndings;
                break;

            case LineEndingsMode.Windows:
                preferredLineEndings = windowsLineEndings;
                break;

            default:
                preferredLineEndings = unixLineEndings;
                break;
            }

            var adHocWorkspace = new AdhocWorkspace();

            var options = adHocWorkspace.Options
                          .WithChangedOption(CSharpFormattingOptions.NewLineForMembersInObjectInit, true)
                          .WithChangedOption(CSharpFormattingOptions.WrappingPreserveSingleLine, false)
                          .WithChangedOption(CSharpFormattingOptions.WrappingKeepStatementsOnSingleLine, false)
                          .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInObjectCollectionArrayInitializers, true)
                          .WithChangedOption(FormattingOptions.NewLine, LanguageNames.CSharp, preferredLineEndings);

            compilationResult.sourceCode[(int)SourceCodePhases.Initial] = syntaxTree.GetText().ToString();

            var formattedTree = Formatter.Format(syntaxTree.GetCompilationUnitRoot(), adHocWorkspace, options);

            formattedTree = new VisualScriptingCSharpFormatter().Visit(formattedTree);
            string codeText = formattedTree.GetText().ToString();

            compilationResult.sourceCode[(int)SourceCodePhases.Final] = codeText;

            return(syntaxTree);
        }
        public CompilationResult TranslateAndCompile(VSGraphModel graphModel, AssemblyType assemblyType, CompilationOptions compilationOptions)
        {
            string graphModelSourceFilePath = graphModel.SourceFilePath;

            CompilationResult compilationResult = new CompilationResult();

            compilationResult.sourceCode = new string[Enum.GetNames(typeof(SourceCodePhases)).Length];

            long translationTime = 0;
            long analysisTime    = 0;
            long compilationTime = 0;

            Stopwatch sw = Stopwatch.StartNew();

            Profiler.BeginSample("Validation");
            OnValidate(graphModel, assemblyType, compilationOptions, ref compilationResult);
            long validationTime = sw.ElapsedMilliseconds;

            Profiler.EndSample();

            compilationResult.errors.AddRange(m_Errors);
            m_Errors.Clear();

            if (compilationResult.status == CompilationStatus.Succeeded)
            {
                sw.Restart();
                Profiler.BeginSample("Translation");

                var syntaxTree = OnTranslate(graphModel, assemblyType, compilationOptions, ref compilationResult);

                compilationResult.errors.AddRange(m_Errors);
                m_Errors.Clear();

                translationTime = sw.ElapsedMilliseconds;
                Profiler.EndSample();

                sw.Restart();
                Profiler.BeginSample("Compilation");

                if (compilationResult.status == CompilationStatus.Succeeded)
                {
                    int syntaxTreeHashCode = compilationResult.sourceCode[(int)SourceCodePhases.Final].GetHashCode();
                    if (s_LastSyntaxTreeHashCode == 0 && File.Exists(graphModelSourceFilePath))
                    {
                        var diskSourceCode = File.ReadAllText(graphModelSourceFilePath);
                        s_LastSyntaxTreeHashCode = diskSourceCode.GetHashCode();
                        if (s_LastSyntaxTreeHashCode == syntaxTreeHashCode)
                        {
                            s_LastCompilationResult = new CompilationResult
                            {
                                errors     = new List <CompilerError>(),
                                sourceCode = new string[]
                                {
                                    diskSourceCode,
                                    diskSourceCode,
                                }
                            };
                        }
                        if (LogCompileTimeStats)
                        {
                            Debug.Log($"Found Graph version on disk with hash {s_LastSyntaxTreeHashCode}");
                        }
                    }

                    if (s_LastSyntaxTreeHashCode == syntaxTreeHashCode)
                    {
                        compilationResult = s_LastCompilationResult;
                        if (LogCompileTimeStats)
                        {
                            Debug.Log("Reused cached compilation result");
                        }
                    }
                    else
                    {
                        try
                        {
                            if (LogCompileTimeStats)
                            {
                                Debug.Log($"Compute new compilation result (last hash {s_LastSyntaxTreeHashCode}, current: {syntaxTreeHashCode}");
                            }
                            compilationResult = CheckSemanticModel(syntaxTree, compilationResult);
                        }
                        catch (LoopDetectedException e)
                        {
                            compilationResult.AddError(e.Message);
                        }
                        finally
                        {
                            s_LastSyntaxTreeHashCode = syntaxTreeHashCode;
                            s_LastCompilationResult  = compilationResult;
                        }
                    }

                    Profiler.BeginSample("WriteSource");
                    if (assemblyType == AssemblyType.Source)
                    {
                        string directoryName = Path.GetDirectoryName(graphModelSourceFilePath);
                        Assert.IsNotNull(directoryName, nameof(directoryName) + " != null");
                        Directory.CreateDirectory(directoryName);

                        string sourceCode = compilationResult.sourceCode[(int)SourceCodePhases.Final];

                        if (compilationResult.status == CompilationStatus.Succeeded)
                        {
                            File.WriteAllText(graphModelSourceFilePath, sourceCode);
                        }
                    }
                    Profiler.EndSample();
                }
                compilationTime = sw.ElapsedMilliseconds;
                Profiler.EndSample();
            }

            // needs to be done on the main thread
            foreach (CompilerError error in compilationResult.errors)
            {
                if (error.sourceNodeGuid == default && error.sourceNode != null && !error.sourceNode.Destroyed)
                {
                    error.sourceNodeGuid = error.sourceNode.Guid;
                }
                else
                {
                    graphModel.NodesByGuid.TryGetValue(error.sourceNodeGuid, out error.sourceNode);
                }
            }

            if (LogCompileTimeStats)
            {
                Debug.Log($"Validation: {validationTime}ms Translation: {translationTime}ms Code Analysis: {analysisTime}ms Compilation: {compilationTime}ms");
            }

            return(compilationResult);
        }
 public virtual void OnValidate(VSGraphModel graphModel, AssemblyType assemblyType, CompilationOptions compilationOptions, ref CompilationResult results)
 {
 }