예제 #1
0
        public string GetScriptAssembly()
        {
            if (CompilerType == null)
            {
                return(null);
            }

            var papyrusGen = new PapyrusGen(new CommonTreeNodeStream(CompilerType.GetAst())
            {
                TokenStream = CompilerType.GetTokenStream()
            });

            using (var manifestResourceStream = papyrusGen.GetType().Assembly.GetManifestResourceStream("PCompiler.PapyrusAssembly.stg"))
            {
                var templateGroup = new StringTemplateGroup(new StreamReader(manifestResourceStream));
#if SKYRIM
                papyrusGen.TemplateLib = templateGroup;
#else
                papyrusGen.TemplateGroup = templateGroup;
#endif

                papyrusGen.AsDynamic().KnownUserFlags = _program.FlagsFile.NativeFlagsDict;
                var template = papyrusGen.script(_filePath, CompilerType).Template;
                return(template.ToString());
            }
        }
예제 #2
0
        public ScriptFile(ObjectIdentifier id, string filePath, PapyrusProgram program, IScriptTextProvider textProvider, ILogger <ScriptFile> logger)
        {
            _id           = id;
            _filePath     = filePath;
            _program      = program;
            _textProvider = textProvider;
            _logger       = logger;

            var initialVersion = _textProvider.GetTextVersion(_filePath).WaitForResult();

            _scriptText = new TokenEqualityCachedValue <ScriptText, string>(
                () => _textProvider.GetText(_filePath).WaitForResult(),
                (_) =>
            {
                var currentVersion = _scriptText.CurrentToken;
                var version        = _textProvider.GetTextVersion(_filePath).WaitForResult();

                if (currentVersion != version)
                {
                    _logger.LogTrace($"{_id} file version changed from '{currentVersion}' to '{version}'. (Thread: {Thread.CurrentThread.ManagedThreadId})");
                }

                return(version);
            },
                initialVersion);

            _textProvider.OnScriptTextChanged += HandleScriptTextChanged;

            _compiler = new TokenEqualityCachedValue <ScriptCompiler, string>(() =>
            {
                var compiler = new ScriptCompiler(this, _logger);
                compiler.CompilerNotifyHandler += (s, e) =>
                {
                    _logger.LogTrace($"Compiler: {e.sMessage}");
                };

                return(compiler);
            }, (_) => _scriptText.Value.Version, initialVersion);

            _compilationResult = new TokenEqualityCachedValue <DiagnosticResult <CompilationResult>, ScriptCompiler>(() =>
            {
                DiagnosticResult <CompilationResult> compileFunc()
                {
                    return(DiagnosticResult <CompilationResult> .TryWithDiagnostics((diagnostics) =>
                    {
                        return UseCompiler((compiler, types) =>
                        {
                            var compilationResult = new CompilationResult();

                            _logger.LogTrace($"Compiling {_id}... (Thread: {Thread.CurrentThread.ManagedThreadId})");

                            var type = compiler.Load(types);
                            compilationResult.CompilerType = type;
                            compilationResult.CompilerNode = type?.GetAst();

                            _logger.LogTrace($"Type checking {_id}... (Thread: {Thread.CurrentThread.ManagedThreadId})");

                            var typeWalker = new TypeWalker(this, type, _logger);
                            typeWalker.OnError((s, e) =>
                            {
                                if (!e.ErrorText.StartsWith("mismatched tree node"))
                                {
                                    diagnostics.Add(e.ToDiagnostic());
                                }
                            });

                            try
                            {
#if FALLOUT4
                                typeWalker.script(type, compiler, types);
#elif SKYRIM
                                lock (types)
                                {
                                    if (types.ContainsKey("int"))
                                    {
                                        types.Remove("int");
                                        types.Remove("float");
                                        types.Remove("string");
                                        types.Remove("bool");
                                    }
                                }

                                typeWalker.script(type, compiler, types, new Stack <string>());
#endif
                            }
                            catch (Exception e)
                            {
                                _logger.LogWarning(e, $"Thrown during type checking of {_id}");
                            }

                            return compilationResult;
                        },
                                           (s, e) =>
                        {
                            diagnostics.Add(e.ToDiagnostic());
                        });
                    }));
                }

                // If there are diagnostic errors, we re-run the compile once in case anything was missing,
                // but couldn't be resolved at the time.
                var result = compileFunc();
                if (result.Diagnostics.Count > 0)
                {
                    return(compileFunc());
                }

                return(result);
            }, (_) => _compiler.Value);

            _node = new TokenEqualityCachedValue <DiagnosticResult <ScriptNode>, CompilationResult>(() =>
            {
                if (CompilerType == null)
                {
                    return(null);
                }

                _logger.LogTrace($"Transforming {_id} syntax tree... (Thread: {Thread.CurrentThread.ManagedThreadId})");

                var nodeBinder = new NodeBinder();

                var node = nodeBinder.Bind(this, _program, Text, CompilerType.GetTokenStream(), CompilerNode);

                _logger.LogTrace($"Binding script scopes to {_id} syntax tree... (Thread: {Thread.CurrentThread.ManagedThreadId})");
                var scopeBinder = new ScopeBinder();
                var scopeResult = scopeBinder.Bind(CompilerType, node.Value);

                node.Diagnostics.AddRange(scopeResult.Diagnostics);

                _logger.LogTrace($"Binding {_id} symbols... (Thread: {Thread.CurrentThread.ManagedThreadId})");
                var symbolBinder = new SymbolBinder();
                var symbolResult = symbolBinder.Bind(node.Value);

                node.Diagnostics.AddRange(symbolResult.Diagnostics);

                return(node);
            }, (_) => _compilationResult.Value?.Value);

            _type = new TokenEqualityCachedValue <ScriptType, ScriptSymbol>(() =>
            {
                if (Symbol == null)
                {
                    return(null);
                }

                _logger.LogTrace($"Creating {_id} type... (Thread: {Thread.CurrentThread.ManagedThreadId})");

                return(new ScriptType(Program, Symbol, CompilerType));
            }, (_) => Symbol);
        }