//===-- include/flang/Parser/parsing.h --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_PARSER_PARSING_H_
#define FORTRAN_PARSER_PARSING_H_

#include "characters.h"
#include "instrumented-parser.h"
#include "message.h"
#include "parse-tree.h"
#include "provenance.h"
#include "flang/Common/Fortran-features.h"
#include "flang/Parser/preprocessor.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
#include <string>
#include <utility>
#include <vector>

namespace Fortran::parser {

struct Options {
  Options() {}

  using Predefinition = std::pair<std::string, std::optional<std::string>>;

  bool isFixedForm{false};
  int fixedFormColumns{72};
  common::LanguageFeatureControl features;
  std::vector<std::string> searchDirectories;
  std::vector<std::string> intrinsicModuleDirectories;
  std::vector<Predefinition> predefinitions;
  bool instrumentedParse{false};
  bool isModuleFile{false};
  bool needProvenanceRangeToCharBlockMappings{false};
  Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
  bool prescanAndReformat{false}; // -E
  bool expandIncludeLinesInPreprocessedOutput{true};
  bool showColors{false};
};

class Parsing {
public:
  explicit Parsing(AllCookedSources &);
  ~Parsing();

  bool consumedWholeFile() const { return consumedWholeFile_; }
  const char *finalRestingPlace() const { return finalRestingPlace_; }
  AllCookedSources &allCooked() { return allCooked_; }
  const AllCookedSources &allCooked() const { return allCooked_; }
  Messages &messages() { return messages_; }
  std::optional<Program> &parseTree() { return parseTree_; }

  const CookedSource &cooked() const { return DEREF(currentCooked_); }

  const SourceFile *Prescan(const std::string &path, Options);
  void EmitPreprocessedSource(
      llvm::raw_ostream &, bool lineDirectives = true) const;
  void EmitPreprocessorMacros(llvm::raw_ostream &) const;
  void DumpCookedChars(llvm::raw_ostream &) const;
  void DumpProvenance(llvm::raw_ostream &) const;
  void DumpParsingLog(llvm::raw_ostream &) const;
  void Parse(llvm::raw_ostream &debugOutput);
  void ClearLog();

  void EmitMessage(llvm::raw_ostream &o, const char *at,
      const std::string &message, const std::string &prefix,
      llvm::raw_ostream::Colors color = llvm::raw_ostream::SAVEDCOLOR,
      bool echoSourceLine = false) const {
    allCooked_.allSources().EmitMessage(o,
        allCooked_.GetProvenanceRange(CharBlock(at)), message, prefix, color,
        echoSourceLine);
  }

private:
  Options options_;
  AllCookedSources &allCooked_;
  CookedSource *currentCooked_{nullptr};
  Messages messages_;
  bool consumedWholeFile_{false};
  const char *finalRestingPlace_{nullptr};
  std::optional<Program> parseTree_;
  ParsingLog log_;
  Preprocessor preprocessor_{allCooked_.allSources()};
};
} // namespace Fortran::parser
#endif // FORTRAN_PARSER_PARSING_H_
