public override ExpressionSyntax GenerateExpression(VisualScriptCompilerContext context) { var expression = ParseExpression(Expression); // Forward diagnostics to log foreach (var diagnostic in expression.GetDiagnostics()) { LogMessageType logType; switch (diagnostic.Severity) { case DiagnosticSeverity.Info: logType = LogMessageType.Info; break; case DiagnosticSeverity.Warning: logType = LogMessageType.Warning; break; case DiagnosticSeverity.Error: logType = LogMessageType.Error; break; default: throw new ArgumentOutOfRangeException(); } context.Log.Log(new LogMessage(nameof(CustomExpression), logType, diagnostic.GetMessage())); } return(expression); }
public ExpressionSyntax GenerateExpression(VisualScriptCompilerContext context, Slot slot) { // TODO: Out/ref // Other cases should have been handled by context.RegisterLocalVariable during code generation // It's also possible that this block is actually not executed and used as input, so we issue a warning anyway context.Log.Error($"No value found for slot {slot}. Note that out/ref slots are not implemented yet.", CallerInfo.Get()); return(null); }
public override ExpressionSyntax GenerateExpression(VisualScriptCompilerContext context) { if (Name == null) { return(IdentifierName("variable_not_set")); } return(IdentifierName(Name)); }
public override void GenerateCode(VisualScriptCompilerContext context) { var arguments = new List <SyntaxNodeOrToken>(); var memberCallProcessed = false; var invocationTarget = MethodName; for (int index = 0; index < Slots.Count; index++) { var slot = Slots[index]; if (slot.Direction == SlotDirection.Input && slot.Kind == SlotKind.Value) { var argument = context.GenerateExpression(slot); if (IsMemberCall && !memberCallProcessed) { // this parameter (non-static or extension method) memberCallProcessed = true; invocationTarget = argument.ToFullString() + "." + invocationTarget; continue; } if (arguments.Count > 0) { arguments.Add(Token(SyntaxKind.CommaToken)); } arguments.Add(Argument(argument)); } } var expression = InvocationExpression(ParseExpression(invocationTarget), ArgumentList(SeparatedList <ArgumentSyntax>(arguments))); var statement = (StatementSyntax)ExpressionStatement(expression); // Only store return variable if somebody is using it if (ReturnSlot != null && context.FindOutputLinks(ReturnSlot).Any()) { var localVariableName = context.GenerateLocalVariableName(); // Store return value in a local variable statement = LocalDeclarationStatement( VariableDeclaration( IdentifierName("var")) .WithVariables( SingletonSeparatedList <VariableDeclaratorSyntax>( VariableDeclarator( Identifier(localVariableName)) .WithInitializer( EqualsValueClause(expression))))); context.RegisterLocalVariable(ReturnSlot, localVariableName); } context.AddStatement(statement); }
//[DataMemberIgnore] //public Slot OutputSlot => FindSlot(SlotDirection.Output, SlotKind.Value, null); public override void GenerateCode(VisualScriptCompilerContext context) { if (Name == null) { return; } // Evaluate value var newValue = context.GenerateExpression(InputSlot); // Generate assignment statement context.AddStatement(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(Name), newValue))); }
public override void GenerateCode(VisualScriptCompilerContext context) { // Create local variable that will store the item var itemVariableName = context.GenerateLocalVariableName("item"); context.RegisterLocalVariable(ItemSlot, itemVariableName); // Switch to "continue" instead of "return" in case there is no next node var wasInsideLoop = context.IsInsideLoop; context.IsInsideLoop = true; var innerBlockStatements = context.ProcessInnerLoop(LoopSlot); context.IsInsideLoop = wasInsideLoop; context.AddStatement(ForEachStatement(IdentifierName("var"), itemVariableName, context.GenerateExpression(CollectionSlot), Block(innerBlockStatements))); }
public override void GenerateCode(VisualScriptCompilerContext context) { // Generate false then true block (false block will be reached if the previous condition failed), then true block (reached by goto) var falseBlock = context.GetOrCreateBasicBlockFromSlot(FalseSlot); var trueBlock = context.GetOrCreateBasicBlockFromSlot(TrueSlot); // Generate condition var condition = context.GenerateExpression(ConditionSlot); // if (condition) goto trueBlock; if (trueBlock != null) { context.AddStatement(IfStatement(condition, context.CreateGotoStatement(trueBlock))); } // Execution continue in false block context.CurrentBasicBlock.NextBlock = falseBlock; }
public override void GenerateCode(VisualScriptCompilerContext context) { // Nothing to do (since we have autoflow on Start slot) }
public abstract ExpressionSyntax GenerateExpression(VisualScriptCompilerContext context);
ExpressionSyntax IExpressionBlock.GenerateExpression(VisualScriptCompilerContext context, Slot slot) { return(GenerateExpression(context)); }
public abstract void GenerateCode(VisualScriptCompilerContext context);
public override void GenerateCode(VisualScriptCompilerContext context) { var blockStatement = ParseStatement($"{{ {Code} }}"); // Forward diagnostics to log foreach (var diagnostic in blockStatement.GetDiagnostics()) { LogMessageType logType; switch (diagnostic.Severity) { case DiagnosticSeverity.Info: logType = LogMessageType.Info; break; case DiagnosticSeverity.Warning: logType = LogMessageType.Warning; break; case DiagnosticSeverity.Error: logType = LogMessageType.Error; break; default: throw new ArgumentOutOfRangeException(); } context.Log.Log(new LogMessage(nameof(CustomCodeBlock), logType, diagnostic.GetMessage())); } var block = blockStatement as BlockSyntax; if (block != null) { RoslynHelper.CreateCompilationUnitFromBlock(ref block); foreach (var slot in Slots.Where(x => x.Kind == SlotKind.Value)) { var symbolsToReplace = block.DescendantNodes() .OfType <IdentifierNameSyntax>() .Where(x => x.Identifier.Text == slot.Name) .Where(x => { // We can never be on the right side of a member access var memberAccess = (x.Parent as MemberAccessExpressionSyntax); return(memberAccess == null || memberAccess.Expression == x); }) .ToArray(); if (slot.Direction == SlotDirection.Input) { // Input // Find expression var expression = context.GenerateExpression(slot); block = block.ReplaceNodes(symbolsToReplace, (x1, x2) => expression); } else { // Output // Replace every reference of slot.Name into generated slotName var slotName = context.GenerateLocalVariableName(slot.Name); block = block.ReplaceNodes(symbolsToReplace, (x1, x2) => x1.WithIdentifier(Identifier(slotName))); // Register a local var with generated name context.RegisterLocalVariable(slot, slotName); } } foreach (var statement in block.Statements) { context.AddStatement(statement); } } }
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); }