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) { }