Esempio n. 1
0
        static void UpgradeEnumerableInputDependency(WorkflowBuilder builder, WorkflowInputDependency inputDependency)
        {
            var dependency = builder.Workflow.Build(inputDependency.Dependency);
            var sourceType = dependency.Type.GetGenericArguments()[0];

            if (ExpressionHelper.IsEnumerableType(sourceType) && sourceType != typeof(string))
            {
                var workflow  = inputDependency.Target;
                var inputNode = workflow.FirstOrDefault(node =>
                {
                    return(ExpressionBuilder.Unwrap(node.Value) is WorkflowInputBuilder inputBuilder && inputBuilder.Index == 0);
                });

                if (inputNode != null)
                {
                    var mergeBuilder = new CombinatorBuilder
                    {
                        Combinator = new Reactive.Merge()
                    };

                    var mergeNode = workflow.Add(mergeBuilder);
                    foreach (var successor in inputNode.Successors)
                    {
                        mergeNode.Successors.Add(successor);
                    }

                    inputNode.Successors.Clear();
                    workflow.AddEdge(inputNode, mergeNode, new ExpressionBuilderArgument());
                }
            }
        }
        public void Build_SourceSubscribeDisposeError_ThrowsRuntimeException()
        {
            var source  = new SubscribeDisposeErrorSource();
            var builder = new CombinatorBuilder {
                Combinator = source
            };

            RunInspector(builder);
        }
        public void Build_SourceGenerateError_ThrowsException()
        {
            var source  = new ErrorSource();
            var builder = new CombinatorBuilder {
                Combinator = source
            };

            RunInspector(builder);
        }
        public void Build_CombinatorTransformError_ThrowsRuntimeException()
        {
            var source     = new UnitBuilder();
            var combinator = new TransformErrorCombinator();
            var builder    = new CombinatorBuilder {
                Combinator = combinator
            };

            RunInspector(source, builder);
        }
        IObservable <TSource> TestCombinatorBuilder <TSource>(object combinator, params Expression[] arguments)
        {
            var builder = new CombinatorBuilder {
                Combinator = combinator
            };
            var buildResult   = builder.Build(arguments);
            var lambda        = Expression.Lambda <Func <IObservable <TSource> > >(buildResult);
            var resultFactory = lambda.Compile();
            var result        = resultFactory();

            return(result);
        }
            public void ShouldSelectEveryClassesAndEveryExpressionInsideClasses()
            {
                // Arrange
                var sourceText = @"
                    public class Foo {
                        public void FooMethod() {
                            var i = 10 + 5;
                        }
                    }
                ";
                var tree = ParseDeclaration(sourceText);
                var combinator = new CombinatorBuilder()
                                    .Select(new ClassDeclarationSelector())
                                    .And(new ExpressionSelector())
                                    .Build();

                // Act
                var elements = combinator.Calculate(Array(tree));

                // Assert
                var result = elements.Select(element => element.ToString());
                Assert.That(result, Contains.Item("10 + 5"));
            }
        public override bool EditComponent(ITypeDescriptorContext context, object component, IServiceProvider provider, IWin32Window owner)
        {
            var scriptComponent = (CSharpScript)component;

            if (scriptComponent == null || provider == null)
            {
                return(false);
            }

            var workflowBuilder   = (WorkflowBuilder)provider.GetService(typeof(WorkflowBuilder));
            var commandExecutor   = (CommandExecutor)provider.GetService(typeof(CommandExecutor));
            var editorService     = (IWorkflowEditorService)provider.GetService(typeof(IWorkflowEditorService));
            var selectionModel    = (WorkflowSelectionModel)provider.GetService(typeof(WorkflowSelectionModel));
            var scriptEnvironment = (IScriptEnvironment)provider.GetService(typeof(IScriptEnvironment));

            if (workflowBuilder == null || commandExecutor == null || selectionModel == null || scriptEnvironment == null)
            {
                return(false);
            }

            var selectedView = selectionModel.SelectedView;

            if (selectedView == null)
            {
                return(false);
            }

            var selectedNode = selectionModel.SelectedNodes.SingleOrDefault();

            if (selectedNode == null)
            {
                return(false);
            }

            string typeName;
            string scriptFile;
            var    inputType  = default(Type);
            var    scriptName = scriptComponent.Category + DefaultScriptName;

            using (var codeProvider = new CSharpCodeProvider())
            {
                var builderNode = (Node <ExpressionBuilder, ExpressionBuilderArgument>)selectedNode.Tag;
                var predecessor = selectedView.Workflow.Predecessors(builderNode).FirstOrDefault();
                if (predecessor != null)
                {
                    var expression = workflowBuilder.Workflow.Build(predecessor.Value);
                    if (expression.Type == typeof(void))
                    {
                        throw new InvalidOperationException(
                                  "Script generation failed because the input type could not be determined. " +
                                  "Please ensure that the preceding node has a valid output and that all " +
                                  "other generated scripts have been successfully compiled.");
                    }

                    inputType = expression.Type;
                }

                var typeReference = CreateTypeReference(inputType ?? typeof(IObservable <int>));
                typeName = codeProvider.GetTypeOutput(typeReference);

                var extensionsDirectory = editorService.EnsureExtensionsDirectory();
                if (!extensionsDirectory.Exists)
                {
                    return(false);
                }

                using (var dialog = new SaveFileDialog {
                    InitialDirectory = extensionsDirectory.FullName, FileName = scriptName, Filter = ScriptFilter
                })
                {
                    if (dialog.ShowDialog() != DialogResult.OK)
                    {
                        return(false);
                    }
                    scriptFile = dialog.FileName;
                    scriptName = Path.GetFileNameWithoutExtension(scriptFile);
                    if (!codeProvider.IsValidIdentifier(scriptName))
                    {
                        throw new InvalidOperationException(
                                  "The specified name '" + scriptName + "' is not a valid type identifier. " +
                                  "Valid identifiers must start with a letter and must not contain white spaces.");
                    }
                }
            }

            if (scriptEnvironment.AssemblyName != null)
            {
                var existingType = Type.GetType(scriptName + ", " + scriptEnvironment.AssemblyName.FullName);
                if (existingType != null)
                {
                    throw new InvalidOperationException("An extension type with the name " + scriptName + " already exists.");
                }
            }

            var namespaces         = new HashSet <string>();
            var assemblyReferences = new HashSet <string>();

            assemblyReferences.Add("Bonsai.Core");
            namespaces.Add("Bonsai");
            namespaces.Add("System");
            namespaces.Add("System.ComponentModel");
            namespaces.Add("System.Collections.Generic");
            namespaces.Add("System.Linq");
            namespaces.Add("System.Reactive.Linq");
            if (inputType != null)
            {
                CollectNamespaces(inputType, namespaces);
                CollectAssemblyReferences(inputType, assemblyReferences);
                assemblyReferences.ExceptWith(IgnoreAssemblyReferences);
            }
            scriptEnvironment.AddAssemblyReferences(assemblyReferences);

            var scriptBuilder = new StringBuilder();

            foreach (var ns in namespaces)
            {
                scriptBuilder.AppendLine("using " + ns + ";");
            }
            scriptBuilder.AppendLine();
            scriptBuilder.AppendLine("[Combinator]");
            scriptBuilder.AppendLine("[Description(\"\")]");
            scriptBuilder.AppendLine("[WorkflowElementCategory(ElementCategory." + scriptComponent.Category + ")]");
            scriptBuilder.AppendLine("public class " + scriptName);
            scriptBuilder.AppendLine("{");
            scriptBuilder.AppendLine("    public " + typeName + " Process(" + (inputType != null ? typeName + " source)" : ")"));
            scriptBuilder.AppendLine("    {");
            string template;

            switch (scriptComponent.Category)
            {
            case ElementCategory.Source: template = "Observable.Return(0)"; break;

            case ElementCategory.Transform: template = "source.Select(value => value)"; break;

            case ElementCategory.Sink: template = "source.Do(value => Console.WriteLine(value))"; break;

            case ElementCategory.Combinator: template = "source"; break;

            default: throw new InvalidOperationException("The specified element category is not allowed for automatic script generation.");
            }
            scriptBuilder.AppendLine("        return " + template + ";");
            scriptBuilder.AppendLine("    }");
            scriptBuilder.AppendLine("}");

            using (var writer = new StreamWriter(scriptFile))
            {
                writer.Write(scriptBuilder);
            }

            if (moduleBuilder == null)
            {
                var assemblyName         = new AssemblyName("@DynamicExtensions");
                var assemblyBuilder      = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
                var iconAttributeBuilder = new CustomAttributeBuilder(
                    typeof(WorkflowNamespaceIconAttribute).GetConstructor(new[] { typeof(string) }),
                    new object[] { "Bonsai:ElementIcon.CSharp" });
                assemblyBuilder.SetCustomAttribute(iconAttributeBuilder);
                moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.FullName);

                var emptyExpressionBuilder   = moduleBuilder.DefineType("@EmptyExpression", TypeAttributes.Class, typeof(Expression));
                var propertyMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.HideBySig;
                var nodeTypeProperty         = emptyExpressionBuilder.DefineProperty("NodeType", PropertyAttributes.None, typeof(ExpressionType), null);
                var nodeTypeGet          = emptyExpressionBuilder.DefineMethod("get_NodeType", propertyMethodAttributes, typeof(ExpressionType), Type.EmptyTypes);
                var nodeTypeGetGenerator = nodeTypeGet.GetILGenerator();
                nodeTypeGetGenerator.Emit(OpCodes.Ldc_I4, (int)ExpressionType.Extension);
                nodeTypeGetGenerator.Emit(OpCodes.Ret);
                nodeTypeProperty.SetGetMethod(nodeTypeGet);

                var typeProperty                = emptyExpressionBuilder.DefineProperty("Type", PropertyAttributes.None, typeof(Type), null);
                var typePropertyGet             = emptyExpressionBuilder.DefineMethod("get_Type", propertyMethodAttributes, typeof(Type), Type.EmptyTypes);
                var typeGetGenerator            = typePropertyGet.GetILGenerator();
                var typeGetExceptionConstructor = typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) });
                typeGetGenerator.Emit(OpCodes.Ldstr, Resources.UncompiledScriptExpression_Error);
                typeGetGenerator.Emit(OpCodes.Newobj, typeGetExceptionConstructor);
                typeGetGenerator.Emit(OpCodes.Throw);
                typeProperty.SetGetMethod(typePropertyGet);

                var emptyExpressionType = emptyExpressionBuilder.CreateType();
                emptyExpression = emptyExpressionType.GetConstructor(Type.EmptyTypes);
            }

            var typeBuilder = moduleBuilder.DefineType(
                scriptName,
                TypeAttributes.Public | TypeAttributes.Class,
                inputType == null ? typeof(ZeroArgumentExpressionBuilder) : typeof(SingleArgumentExpressionBuilder));
            var descriptionAttributeBuilder = new CustomAttributeBuilder(
                typeof(DescriptionAttribute).GetConstructor(new[] { typeof(string) }),
                new object[] { "Extensions must be reloaded in order to compile and use the script." });
            var categoryAttributeBuilder = new CustomAttributeBuilder(
                typeof(WorkflowElementCategoryAttribute).GetConstructor(new[] { typeof(ElementCategory) }),
                new object[] { scriptComponent.Category });

            typeBuilder.SetCustomAttribute(descriptionAttributeBuilder);
            typeBuilder.SetCustomAttribute(categoryAttributeBuilder);
            var buildMethod = typeBuilder.DefineMethod("Build",
                                                       MethodAttributes.Public |
                                                       MethodAttributes.ReuseSlot |
                                                       MethodAttributes.Virtual |
                                                       MethodAttributes.HideBySig,
                                                       typeof(Expression),
                                                       new[] { typeof(IEnumerable <Expression>) });
            var generator = buildMethod.GetILGenerator();

            generator.Emit(OpCodes.Newobj, emptyExpression);
            generator.Emit(OpCodes.Ret);

            var type    = typeBuilder.CreateType();
            var builder = new CombinatorBuilder();

            builder.Combinator = Activator.CreateInstance(type);
            selectedView.Editor.CreateGraphNode(builder, selectedNode, CreateGraphNodeType.Successor, branch: false, validate: false);
            selectedView.Editor.DeleteGraphNodes(selectionModel.SelectedNodes);
            commandExecutor.Execute(() => { }, null);

            ScriptEditorLauncher.Launch(owner, scriptEnvironment.ProjectFileName, scriptFile);
            return(true);
        }