269 lines
8.3 KiB
C++
269 lines
8.3 KiB
C++
//--------------------------------------------------------------------*- C++ -*-
|
|
// CLING - the C++ LLVM-based InterpreterG :)
|
|
// author: Axel Naumann <axel@cern.ch>
|
|
//
|
|
// This file is dual-licensed: you can choose to license it under the University
|
|
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
|
// LICENSE.TXT for details.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifndef CLING_INCREMENTAL_PARSER_H
|
|
#define CLING_INCREMENTAL_PARSER_H
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "llvm/ADT/PointerIntPair.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include <vector>
|
|
#include <deque>
|
|
#include <memory>
|
|
|
|
namespace llvm {
|
|
struct GenericValue;
|
|
class MemoryBuffer;
|
|
class Module;
|
|
}
|
|
|
|
namespace clang {
|
|
class ASTConsumer;
|
|
class CodeGenerator;
|
|
class CompilerInstance;
|
|
class DiagnosticConsumer;
|
|
class Decl;
|
|
class FileID;
|
|
class ModuleFileExtension;
|
|
class Parser;
|
|
}
|
|
|
|
namespace cling {
|
|
class CompilationOptions;
|
|
class DeclCollector;
|
|
class ExecutionContext;
|
|
class Interpreter;
|
|
class Transaction;
|
|
class TransactionPool;
|
|
class ASTTransformer;
|
|
|
|
///\brief Responsible for the incremental parsing and compilation of input.
|
|
///
|
|
/// The class manages the entire process of compilation line-by-line by
|
|
/// appending the compiled delta to clang'a AST. It provides basic operations
|
|
/// on the already compiled code. See cling::Transaction class.
|
|
///
|
|
class IncrementalParser {
|
|
private:
|
|
// our interpreter context
|
|
// FIXME: Get rid of that back reference to the interpreter.
|
|
Interpreter* m_Interpreter;
|
|
|
|
// compiler instance.
|
|
std::unique_ptr<clang::CompilerInstance> m_CI;
|
|
|
|
// parser (incremental)
|
|
std::unique_ptr<clang::Parser> m_Parser;
|
|
|
|
/// Counts the number of direct user input lines that have been parsed.
|
|
unsigned InputCount = 0;
|
|
|
|
// file ID of the memory buffer
|
|
clang::FileID m_VirtualFileID;
|
|
|
|
// The next available unique sourcelocation offset. Skip the system sloc 0
|
|
// and any offset that may actually exist in the virtual file.
|
|
unsigned m_VirtualFileLocOffset = 100;
|
|
|
|
// CI owns it
|
|
DeclCollector* m_Consumer;
|
|
|
|
///\brief The storage for our transactions.
|
|
///
|
|
/// We don't need the elements to be contiguous in memory, that is why we
|
|
/// don't use std::vector. We don't need to copy the elements every time the
|
|
/// capacity is exceeded.
|
|
///
|
|
std::deque<Transaction*> m_Transactions;
|
|
|
|
///\brief Number of created modules.
|
|
unsigned m_ModuleNo = 0;
|
|
|
|
///\brief Code generator
|
|
///
|
|
clang::CodeGenerator* m_CodeGen = nullptr;
|
|
|
|
///\brief Pool of reusable block-allocated transactions.
|
|
///
|
|
std::unique_ptr<TransactionPool> m_TransactionPool;
|
|
|
|
///\brief DiagnosticConsumer instance
|
|
///
|
|
std::unique_ptr<clang::DiagnosticConsumer> m_DiagConsumer;
|
|
|
|
using ModuleFileExtensions =
|
|
std::vector<std::shared_ptr<clang::ModuleFileExtension>>;
|
|
|
|
public:
|
|
enum EParseResult {
|
|
kSuccess,
|
|
kSuccessWithWarnings,
|
|
kFailed
|
|
};
|
|
typedef llvm::PointerIntPair<Transaction*, 2, EParseResult>
|
|
ParseResultTransaction;
|
|
IncrementalParser(Interpreter* interp, const char* llvmdir,
|
|
const ModuleFileExtensions& moduleExtensions);
|
|
~IncrementalParser();
|
|
|
|
///\brief Whether the IncrementalParser is valid.
|
|
///
|
|
///\param[in] initialized - check if IncrementalParser has been initialized.
|
|
///
|
|
bool isValid(bool initialized = true) const;
|
|
|
|
bool Initialize(llvm::SmallVectorImpl<ParseResultTransaction>& result,
|
|
bool isChildInterpreter);
|
|
clang::CompilerInstance* getCI() const { return m_CI.get(); }
|
|
clang::Parser* getParser() const { return m_Parser.get(); }
|
|
clang::CodeGenerator* getCodeGenerator() const { return m_CodeGen; }
|
|
bool hasCodeGenerator() const { return m_CodeGen; }
|
|
|
|
void setDiagnosticConsumer(clang::DiagnosticConsumer* Consumer, bool Own);
|
|
clang::DiagnosticConsumer* getDiagnosticConsumer() const;
|
|
|
|
/// Returns the next available unique source location. It is an offset into
|
|
/// the limitless virtual file. Each time this interface is used it bumps
|
|
/// an internal counter. This is very useful for using the various API in
|
|
/// clang which expect valid source locations.
|
|
clang::SourceLocation getNextAvailableUniqueSourceLoc();
|
|
|
|
/// \{
|
|
/// \name Transaction Support
|
|
|
|
///\brief Starts a transaction.
|
|
///
|
|
Transaction* beginTransaction(const CompilationOptions& Opts);
|
|
|
|
///\brief Finishes a transaction.
|
|
///
|
|
ParseResultTransaction endTransaction(Transaction* T);
|
|
|
|
///\brief Commits a transaction if it was complete. I.e pipes it
|
|
/// through the consumer chain, including codegen.
|
|
///
|
|
///\param[in] PRT - the transaction (ParseResultTransaction) to be
|
|
/// committed
|
|
///\param[in] ClearDiagClient - Reset the DiagnosticsEngine client or not
|
|
///
|
|
void commitTransaction(ParseResultTransaction& PRT,
|
|
bool ClearDiagClient = true);
|
|
|
|
///\brief Runs the consumers (e.g. CodeGen) on a non-parsed transaction.
|
|
///
|
|
///\param[in] T - the transaction to be consumed
|
|
///
|
|
void emitTransaction(Transaction* T);
|
|
|
|
///\brief Remove a Transaction from the collection of Transactions.
|
|
///
|
|
///\param[in] T - The transaction to be reverted from the AST
|
|
///
|
|
void deregisterTransaction(Transaction& T);
|
|
|
|
///\brief Returns the first transaction the incremental parser saw.
|
|
///
|
|
const Transaction* getFirstTransaction() const {
|
|
if (m_Transactions.empty())
|
|
return nullptr;
|
|
return m_Transactions.front();
|
|
}
|
|
|
|
///\brief Returns the last transaction the incremental parser saw.
|
|
///
|
|
Transaction* getLastTransaction() {
|
|
if (m_Transactions.empty())
|
|
return nullptr;
|
|
return m_Transactions.back();
|
|
}
|
|
|
|
///\brief Returns the last transaction the incremental parser saw.
|
|
///
|
|
const Transaction* getLastTransaction() const {
|
|
if (m_Transactions.empty())
|
|
return nullptr;
|
|
return m_Transactions.back();
|
|
}
|
|
|
|
///\brief Returns the most recent transaction with an input line wrapper,
|
|
/// which could well be the current one.
|
|
///
|
|
const Transaction* getLastWrapperTransaction() const;
|
|
|
|
///\brief Returns the currently active transaction.
|
|
///
|
|
const Transaction* getCurrentTransaction() const;
|
|
|
|
|
|
///\brief Add a user-generated transaction.
|
|
void addTransaction(Transaction* T);
|
|
|
|
///\brief Returns the list of transactions seen by the interpreter.
|
|
/// Intentionally makes a copy - that function is meant to be use for debug
|
|
/// purposes.
|
|
///
|
|
std::vector<const Transaction*> getAllTransactions();
|
|
|
|
/// \}
|
|
|
|
///\brief Compiles the given input with the given compilation options.
|
|
///
|
|
///\param[in] input - The code to compile.
|
|
///\param[in] Opts - The compilation options to use.
|
|
///\returns the declarations that were compiled.
|
|
///
|
|
ParseResultTransaction Compile(llvm::StringRef input, const CompilationOptions& Opts);
|
|
|
|
void printTransactionStructure() const;
|
|
|
|
///\brief Runs the static initializers created by codegening a transaction.
|
|
///
|
|
///\param[in] T - the transaction for which to run the initializers.
|
|
///
|
|
bool runStaticInitOnTransaction(Transaction* T) const;
|
|
|
|
///\brief Add the trnasformers to the Incremental Parser.
|
|
///
|
|
void SetTransformers(bool isChildInterpreter);
|
|
|
|
private:
|
|
///\brief Finalizes the consumers (e.g. CodeGen) on a transaction.
|
|
///
|
|
///\param[in] T - the transaction to be finalized
|
|
///
|
|
void codeGenTransaction(Transaction* T);
|
|
|
|
///\brief Initializes a virtual file, which will be able to produce valid
|
|
/// source locations, with the proper offsets.
|
|
///
|
|
void initializeVirtualFile();
|
|
|
|
///\brief The work horse for parsing. It queries directly clang.
|
|
///
|
|
///\param[in] input - The incremental input that needs to be parsed.
|
|
///
|
|
EParseResult ParseInternal(llvm::StringRef input);
|
|
|
|
llvm::Expected<bool> ParseOrWrapTopLevelDecl();
|
|
|
|
///\brief Create a unique name for the next llvm::Module
|
|
///
|
|
std::string makeModuleName();
|
|
|
|
///\brief Create a new llvm::Module
|
|
///
|
|
llvm::Module* StartModule();
|
|
|
|
};
|
|
} // end namespace cling
|
|
#endif // CLING_INCREMENTAL_PARSER_H
|