예제 #1
0
 public static bool Prefix(
     ScriptCompiler __instance, ref ScriptObjectType __result,
     string asObjectName, Dictionary <string, ScriptComplexType> apKnownTypes, Stack <string> apChildren, bool abErrorOnNoObject, ScriptObjectType apImmediateChild)
 {
예제 #2
0
 public static bool Prefix(
     ScriptCompiler __instance,
     ITokenStream apTokenStream, out ScriptObjectType apParsedObj, out IToken arpParentName, out Dictionary <string, IToken> apImports)
 {
예제 #3
0
 // Skyrim's LoadObject method calls TypeCheck internally, which mutates the AST and prevents a subsequent type check from succeeding.
 // So, this patch is just to replace it with a no-op.
 public static bool Prefix(ScriptCompiler __instance, ScriptObjectType akObj, Dictionary <string, ScriptObjectType> akKnownTypes, Stack <string> akChildren)
 {
     return(false);
 }
예제 #4
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);
        }