public VisualScriptCompilerResult Compile(AssetItem assetItem) { var generatedAbsolutePath = assetItem.GetGeneratedAbsolutePath().ToWindowsPath(); var compilerOptions = new VisualScriptCompilerOptions { FilePath = generatedAbsolutePath, Class = Path.GetFileNameWithoutExtension(generatedAbsolutePath), }; // Try to get root namespace from containing project // Since ProjectReference.Location is sometimes absolute sometimes not, we have to handle both case // TODO: ideally we should stop converting those and handle this automatically in a custom Yaml serializer? var sourceProjectAbsolute = assetItem.SourceProject; var sourceProjectRelative = sourceProjectAbsolute?.MakeRelative(assetItem.Package.FullPath.GetFullDirectory()); var projectReference = assetItem.Package.Profiles.SelectMany(x => x.ProjectReferences).FirstOrDefault(x => x.Location == (x.Location.IsAbsolute ? sourceProjectAbsolute : sourceProjectRelative)); if (projectReference != null) { // Find root namespace from project var rootNamespace = projectReference?.RootNamespace ?? projectReference.Location.GetFileName(); if (rootNamespace != null) { compilerOptions.DefaultNamespace = rootNamespace; // Complete namespace with "Include" folder (if not empty) var projectInclude = assetItem.GetProjectInclude(); if (projectInclude != null) { var lastDirectorySeparator = projectInclude.LastIndexOf('\\'); if (lastDirectorySeparator != -1) { var projectIncludeFolder = projectInclude.Substring(0, lastDirectorySeparator); compilerOptions.DefaultNamespace += '.' + projectIncludeFolder.Replace('\\', '.'); } } } } var compilerResult = VisualScriptCompiler.Generate(this, compilerOptions); return(compilerResult); }
public static VisualScriptCompilerResult Generate(VisualScriptAsset visualScriptAsset, VisualScriptCompilerOptions options) { var result = new VisualScriptCompilerResult(); var members = new List <MemberDeclarationSyntax>(); var className = options.Class; // Generate variables foreach (var variable in visualScriptAsset.Properties) { var variableType = variable.Type; if (variableType == null) { result.Error($"Variable {variable.Name} has no type, using \"object\" instead."); variableType = "object"; } var field = FieldDeclaration( VariableDeclaration( ParseTypeName(variableType)) .WithVariables( SingletonSeparatedList( VariableDeclarator( Identifier(variable.Name))))) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))); members.Add(field); } // Process each function foreach (var method in visualScriptAsset.Methods) { var functionStartBlock = method.Blocks.Values.OfType <FunctionStartBlock>().FirstOrDefault(); if (functionStartBlock == null) { continue; } var context = new VisualScriptCompilerContext(visualScriptAsset, method, result); context.ProcessEntryBlock(functionStartBlock); var methodModifiers = new SyntaxTokenList(); methodModifiers = ConvertAccessibility(methodModifiers, method.Accessibility); methodModifiers = ConvertVirtualModifier(methodModifiers, method.VirtualModifier); if (method.IsStatic) { methodModifiers = methodModifiers.Add(Token(SyntaxKind.StaticKeyword)); } var parameters = new List <SyntaxNodeOrToken>(); foreach (var parameter in method.Parameters) { if (parameters.Count > 0) { parameters.Add(Token(SyntaxKind.CommaToken)); } parameters.Add( Parameter(Identifier(parameter.Name)) .WithModifiers(ConvertRefKind(parameter.RefKind)) .WithType(ParseTypeName(parameter.Type))); } // Generate method var methodDeclaration = MethodDeclaration( method.ReturnType == "void" ? PredefinedType(Token(SyntaxKind.VoidKeyword)) : ParseTypeName(method.ReturnType), Identifier(method.Name)) .WithModifiers(methodModifiers) .WithParameterList(ParameterList( SeparatedList <ParameterSyntax>(parameters))) .WithBody( Block(context.Blocks.SelectMany(x => x.Statements))) .WithAdditionalAnnotations(GenerateAnnotation(method)); members.Add(methodDeclaration); } // Generate class var classModifiers = new SyntaxTokenList(); classModifiers = ConvertAccessibility(classModifiers, visualScriptAsset.Accessibility).Add(Token(SyntaxKind.PartialKeyword)); if (visualScriptAsset.IsStatic) { classModifiers = classModifiers.Add(Token(SyntaxKind.StaticKeyword)); } var @class = ClassDeclaration(className) .WithMembers(List(members)) .WithModifiers(classModifiers); if (visualScriptAsset.BaseType != null) { @class = @class.WithBaseList(BaseList(SingletonSeparatedList <BaseTypeSyntax>(SimpleBaseType(IdentifierName(visualScriptAsset.BaseType))))); } // Generate namespace around class (if any) MemberDeclarationSyntax namespaceOrClass = @class; var @namespace = !string.IsNullOrEmpty(visualScriptAsset.Namespace) ? visualScriptAsset.Namespace : options.DefaultNamespace; if (@namespace != null) { namespaceOrClass = NamespaceDeclaration( IdentifierName(@namespace)) .WithMembers( SingletonList <MemberDeclarationSyntax>(@class)); } // Generate compilation unit var compilationUnit = CompilationUnit() .WithUsings( List(visualScriptAsset.UsingDirectives.Select(x => UsingDirective( IdentifierName(x))))) .WithMembers( SingletonList(namespaceOrClass)) .NormalizeWhitespace(); // Generate actual source code result.GeneratedSource = compilationUnit.ToFullString(); result.SyntaxTree = SyntaxTree(compilationUnit, path: options.FilePath ?? string.Empty); return(result); }