cling/lib/Interpreter/IncrementalParser.h

267 lines
8.3 KiB
C
Raw Normal View History

//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
2014-01-07 14:08:37 +04:00
//
// 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>
2014-08-01 16:02:15 +04:00
#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;
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 16:49:28 +03:00
class ASTTransformer;
///\brief Responsible for the incremental parsing and compilation of input.
///
2014-08-04 06:05:42 +04:00
/// 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.
2014-08-01 16:02:15 +04:00
std::unique_ptr<clang::CompilerInstance> m_CI;
// parser (incremental)
2014-08-01 16:02:15 +04:00
std::unique_ptr<clang::Parser> m_Parser;
// One buffer for each command line, owner by the source file manager
std::deque<std::pair<llvm::MemoryBuffer*, clang::FileID>> m_MemoryBuffers;
// 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.
///
2014-08-01 16:02:15 +04:00
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);
2014-08-04 06:05:42 +04:00
///\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
2015-03-20 17:38:44 +03:00
/// 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 {
2015-03-20 12:48:29 +03:00
if (m_Transactions.empty())
return 0;
return m_Transactions.front();
}
///\brief Returns the last transaction the incremental parser saw.
///
Transaction* getLastTransaction() {
2015-03-20 12:48:29 +03:00
if (m_Transactions.empty())
return 0;
return m_Transactions.back();
}
///\brief Returns the last transaction the incremental parser saw.
///
const Transaction* getLastTransaction() const {
2015-03-20 12:48:29 +03:00
if (m_Transactions.empty())
return 0;
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);
2013-07-06 15:02:49 +04:00
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);
///\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