예제 #1
0
        public PapyrusProgram(
            ProgramOptions options,
            IFileSystem fileSystem,
            IScriptTextProvider textProvider,
            ILogger <PapyrusProgram> logger,
            ILogger <ScriptFile> scriptFileLogger,
            ILogger <FlagsFile> flagsFileLogger)
        {
            _options      = options.Clone();
            _fileSystem   = fileSystem;
            _textProvider = textProvider;

            _logger           = logger;
            _scriptFileLogger = scriptFileLogger;

            _flagsFile = new FlagsFile(this, textProvider, flagsFileLogger);

            _typeChecker = new TypeChecker(this);
        }
예제 #2
0
        public FlagsFile(PapyrusProgram program, IScriptTextProvider textProvider, ILogger <FlagsFile> logger)
        {
            _program      = program;
            _textProvider = textProvider;

            _logger = logger;

            // TODO: Invalidate this
            _flagsFilePath = new CachedValue <string>(() => _program.GetFlagsFilePath().WaitForResult());

            _scriptText = new TokenEqualityCachedValue <ScriptText, string>(
                () => _textProvider.GetText(_flagsFilePath).WaitForResult(),
                (_) => _textProvider.GetTextVersion(_flagsFilePath).WaitForResult());

            _textProvider.OnScriptTextChanged += HandleScriptTextChanged;

            _parseResult = new TokenEqualityCachedValue <DiagnosticResult <dynamic>, string>(() =>
            {
                return(DiagnosticResult <dynamic> .TryWithDiagnostics((diagnostics) =>
                {
                    void errorHandler(object s, ErrorEventArgs e)
                    {
                        diagnostics.Add(e.ToDiagnostic());
                    }

                    var flagsLexer = new FlagsLexer(new CaseInsensitiveStringStream(_scriptText.Value.Text));
                    flagsLexer.OnError(errorHandler);

                    var flagsParser = new FlagsParser(new CommonTokenStream(flagsLexer));
                    flagsParser.OnError(errorHandler);

                    flagsParser.flags();

                    return flagsParser.AsDynamic().DefinedFlags;
                }));
            },
                                                                                             (_) => _scriptText.Value.Version);
        }
예제 #3
0
 public static void SetTextProvider(IScriptTextProvider textProvider)
 {
     _textProvider = textProvider;
 }
예제 #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);
        }
예제 #5
0
 public TextDocumentScriptTextProvider(IScriptTextProvider baseProvider, ILogger <TextDocumentScriptTextProvider> logger)
 {
     _logger       = logger;
     _baseProvider = baseProvider;
 }