예제 #1
0
        public Node Instantiate(string guid)
        {
            var parserNode = ParserNodes.FirstOrDefault(p => p.Guid == guid);

            if (parserNode == null)
            {
                var error = new BuildError {
                    Message = $"Could not find a node with GUID: {guid}."
                };
                Errors.Add(error);

                return(null);
            }

            // Uses a depth first loop instead of recursion to avoid potential stack overflows.
            var root = parserNode.CreateInstance(TypeDefMap, Errors);
            var n    = new InstantiationNode {
                Instance = root, Parser = parserNode
            };
            var open = new Stack <InstantiationNode>();

            open.Push(n);

            while (open.Count > 0)
            {
                var next = open.Pop();

                var children = next.Parser.IsDerivedFromTypeDef
                    ? TypeDefMap[next.Parser.Tag].Children
                    : next.Parser.Children;

                foreach (var parserChild in children)
                {
                    var instance = parserChild.CreateInstance(TypeDefMap, Errors);
                    if (instance == null)
                    {
                        continue;
                    }

                    var c = new InstantiationNode {
                        Instance = instance, Parser = parserChild
                    };

                    if (next.Instance.Children == null)
                    {
                        next.Instance.Children = new List <Node>();
                    }

                    next.Instance.Children.Add(instance);
                    open.Push(c);
                }
            }

            foreach (var node in root.DepthFirstIterate())
            {
                node?.Initialize();
            }

            return(root);
        }
예제 #2
0
        public static BuildError FileMissing(string file)
        {
            var error = new BuildError();

            error.IsCritical = false;
            error.Message    = $"File does not exit: {file}";

            return(error);
        }
예제 #3
0
        public static BuildError MissingTypeDefInstance(string typeDef, string file)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = $"Could not find node type or TypeDef during instantiation: {typeDef}";
            error.Data.Add($"File: {file}");

            return(error);
        }
예제 #4
0
        public static BuildError CannotCastToNode(string type, string file)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = $"Could not cast {type} into {nameof(Node)}.";
            error.Data.Add($"File: {file}");

            return(error);
        }
예제 #5
0
        public static BuildError CannotLoadReference(string exception)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = "Could not load reference assembly.";
            error.Data.Add(exception);

            return(error);
        }
예제 #6
0
        public static BuildError UnableToInstantiate(string type, string file, string exception)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = $"Could not instantiate node of type: {type}";
            error.Data.Add(exception);
            error.Data.Add($"File: {file}");

            return(error);
        }
예제 #7
0
        public static BuildError FileLoad(string file, string exception)
        {
            var error = new BuildError();

            error.IsCritical = false;
            error.Message    = "Could not load file.";

            error.Data.Add($"File: {file}");
            error.Data.Add(exception);

            return(error);
        }
예제 #8
0
        public static BuildError RepeatedNodeGuid(string guid, params string[] files)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = $"Repeated node GUID: {guid}";

            foreach (var file in files)
            {
                error.Data.Add($"File: {file}");
            }

            return(error);
        }
예제 #9
0
        public static BuildError MissingTypeDef(string typeDef, params string[] files)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = $"Missing TypeDef: {typeDef}";

            foreach (var file in files)
            {
                error.Data.Add($"File: {file}");
            }

            return(error);
        }
예제 #10
0
        public static BuildError TypeDefsUnresolved(IEnumerable <string> typeDefs)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = "Some TypeDefs could not be resolved.";

            foreach (var typeDef in typeDefs)
            {
                error.Data.Add(typeDef);
            }

            return(error);
        }
예제 #11
0
        public static BuildError UnsupportedScriptFunctionType(string guid, string declaringType,
                                                               string propertyType, string genericDefinitionType, string functionText)
        {
            var error = new BuildError();

            error.IsCritical = true;
            error.Message    = "Unsupported function type.";
            error.Data.Add($"Guid: {guid}");
            error.Data.Add($"Declaring Type: {declaringType}");
            error.Data.Add($"Property Type: {propertyType}");
            error.Data.Add($"Generic Type Definition: {genericDefinitionType}");
            error.Data.Add(functionText);

            return(error);
        }
예제 #12
0
        public YggCompilation Compile <TState>(IEnumerable <string> namespaces,
                                               IEnumerable <string> referenceAssemblyPaths,
                                               List <ScriptedFunctionDefinition> definitions)
        {
            var compilation      = new YggCompilation();
            var builderClassText = new StringBuilder();
            var usings           = new List <string>(namespaces.Distinct().Select(s => $"using {s};\n"));
            var referencePaths   = new HashSet <string>(referenceAssemblyPaths);

            // Add dynamic using if necessary.
            if (definitions.Any(d => d.ReplaceObjectWithDynamic))
            {
                usings.Add("using System.Dynamic;");
            }

            foreach (var u in usings)
            {
                builderClassText.Append(u);
            }

            builderClassText.Append("public class FunctionBuilder\n{");

            foreach (var definition in definitions)
            {
                var sf = CreateScriptedFunction <TState>(definition.Guid, definition.FunctionProperty,
                                                         definition.FunctionText, definition.ReplaceObjectWithDynamic, compilation.Errors);

                if (sf == null)
                {
                    continue;
                }

                if (!compilation.GuidFunctionMap.TryGetValue(sf.Guid, out var functions))
                {
                    functions = new List <ScriptedFunction>();
                    compilation.GuidFunctionMap[sf.Guid] = functions;
                }

                functions.Add(sf);
                builderClassText.Append(sf.ScriptText);

                foreach (var reference in sf.References)
                {
                    referencePaths.Add(reference);
                }
            }

            builderClassText.Append("\n}");

            List <PortableExecutableReference> references;

            try
            {
                references = referencePaths
                             .Select(p => MetadataReference.CreateFromFile(p))
                             .ToList();
            }
            catch (Exception e)
            {
                compilation.Errors.Add(ParserErrorHelper.CannotLoadReference(e.Message));
                return(compilation);
            }

            var options = ScriptOptions.Default.AddReferences(references);
            var script  = CSharpScript.Create(builderClassText.ToString(), options);
            var comp    = script.GetCompilation();

            byte[] compiledAssembly;
            using (var output = new MemoryStream())
            {
                var emitResult = comp.Emit(output);

                if (!emitResult.Success)
                {
                    var error = new BuildError {
                        Message = "Emit compilation error.", IsCritical = true
                    };
                    foreach (var diag in emitResult.Diagnostics)
                    {
                        error.Diagnostics.Add(diag);
                    }

                    compilation.Errors.Add(error);
                    return(compilation);
                }

                compiledAssembly = output.ToArray();
            }

            var assembly  = Assembly.Load(compiledAssembly);
            var entryType = assembly.GetTypes().First(t => t.Name == "FunctionBuilder");
            var builder   = Activator.CreateInstance(entryType);

            foreach (var sf in compilation.GuidFunctionMap.Values.SelectMany(g => g))
            {
                sf.Builder       = builder;
                sf.BuilderMethod = entryType.GetMethod(sf.BuilderMethodName);
            }

            return(compilation);
        }