2012-09-05 09:37:39 +00:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author: Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------
# include "IncrementalParser.h"
# include "ASTDumper.h"
2013-06-14 09:46:59 +02:00
# include "IRDumper.h"
2012-09-05 09:37:39 +00:00
# include "ASTNodeEraser.h"
2013-02-27 15:28:38 +00:00
# include "AutoSynthesizer.h"
2012-09-05 09:37:39 +00:00
# include "DeclCollector.h"
# include "DeclExtractor.h"
# include "DynamicLookup.h"
2012-10-15 13:42:09 +00:00
# include "ReturnSynthesizer.h"
2012-09-05 09:37:39 +00:00
# include "ValuePrinterSynthesizer.h"
# include "cling/Interpreter/CIFactory.h"
# include "cling/Interpreter/Interpreter.h"
2012-10-02 10:30:25 +00:00
# include "cling/Interpreter/InterpreterCallbacks.h"
2012-10-02 10:34:22 +00:00
# include "cling/Interpreter/Transaction.h"
2012-09-05 09:37:39 +00:00
# include "clang/AST/ASTContext.h"
# include "clang/AST/Decl.h"
# include "clang/AST/DeclGroup.h"
2013-03-01 15:15:31 +00:00
# include "clang/AST/RecursiveASTVisitor.h"
2012-09-05 09:37:39 +00:00
# include "clang/Basic/FileManager.h"
# include "clang/CodeGen/ModuleBuilder.h"
# include "clang/Parse/Parser.h"
# include "clang/Lex/Preprocessor.h"
# include "clang/Frontend/CompilerInstance.h"
# include "clang/Serialization/ASTWriter.h"
2013-04-24 16:28:08 +00:00
# include "llvm/IR/LLVMContext.h"
# include "llvm/IR/Module.h"
2012-09-05 09:37:39 +00:00
# include "llvm/Support/CrashRecoveryContext.h"
# include "llvm/Support/MemoryBuffer.h"
# include "llvm/Support/raw_os_ostream.h"
# include <iostream>
# include <stdio.h>
# include <sstream>
using namespace clang ;
namespace cling {
IncrementalParser : : IncrementalParser ( Interpreter * interp ,
int argc , const char * const * argv ,
const char * llvmdir ) :
2013-06-04 16:15:43 +02:00
m_Interpreter ( interp ) , m_Consumer ( 0 ) , m_FirstTransaction ( 0 ) ,
m_LastTransaction ( 0 ) {
2012-09-05 09:37:39 +00:00
CompilerInstance * CI
2013-03-27 18:07:03 +00:00
= CIFactory : : createCI ( 0 , argc , argv , llvmdir ) ;
2012-09-05 09:37:39 +00:00
assert ( CI & & " CompilerInstance is (null)! " ) ;
m_Consumer = dyn_cast < DeclCollector > ( & CI - > getASTConsumer ( ) ) ;
assert ( m_Consumer & & " Expected ChainedConsumer! " ) ;
2013-04-10 15:15:49 +00:00
m_Consumer - > setInterpreter ( interp ) ;
2012-09-05 09:37:39 +00:00
m_CI . reset ( CI ) ;
if ( CI - > getFrontendOpts ( ) . ProgramAction ! = clang : : frontend : : ParseSyntaxOnly ) {
m_CodeGen . reset ( CreateLLVMCodeGen ( CI - > getDiagnostics ( ) , " cling input " ,
CI - > getCodeGenOpts ( ) ,
2013-04-24 16:28:08 +00:00
CI - > getTargetOpts ( ) ,
2012-09-05 09:37:39 +00:00
* m_Interpreter - > getLLVMContext ( )
) ) ;
2013-04-04 15:40:05 +00:00
m_Consumer - > setCodeGen ( m_CodeGen . get ( ) ) ;
2012-09-05 09:37:39 +00:00
}
CreateSLocOffsetGenerator ( ) ;
// Add transformers to the IncrementalParser, which owns them
2013-02-27 15:28:38 +00:00
Sema * TheSema = & CI - > getSema ( ) ;
m_TTransformers . push_back ( new EvaluateTSynthesizer ( TheSema ) ) ;
2012-09-05 09:37:39 +00:00
2013-02-27 15:28:38 +00:00
m_TTransformers . push_back ( new AutoSynthesizer ( TheSema ) ) ;
m_TTransformers . push_back ( new ValuePrinterSynthesizer ( TheSema , 0 ) ) ;
2012-09-05 09:37:39 +00:00
m_TTransformers . push_back ( new ASTDumper ( ) ) ;
2013-06-14 09:46:59 +02:00
m_TTransformers . push_back ( new IRDumper ( ) ) ;
2013-02-27 15:28:38 +00:00
m_TTransformers . push_back ( new DeclExtractor ( TheSema ) ) ;
2013-06-10 14:18:32 +02:00
m_TTransformers . push_back ( new ReturnSynthesizer ( TheSema ) ) ;
2013-03-11 13:11:15 +00:00
}
void IncrementalParser : : Initialize ( ) {
2013-06-04 16:15:55 +02:00
// pull in PCHs
2013-05-23 10:57:23 +02:00
if ( hasCodeGenerator ( ) )
2013-03-11 13:11:15 +00:00
getCodeGenerator ( ) - > Initialize ( getCI ( ) - > getASTContext ( ) ) ;
2013-06-04 16:15:53 +02:00
const std : : string & PCHFileName
= m_CI - > getInvocation ( ) . getPreprocessorOpts ( ) . ImplicitPCHInclude ;
2013-03-26 09:59:19 +00:00
CompilationOptions CO ;
CO . DeclarationExtraction = 0 ;
CO . ValuePrinting = CompilationOptions : : VPDisabled ;
CO . CodeGeneration = hasCodeGenerator ( ) ;
2013-03-11 13:11:15 +00:00
if ( ! PCHFileName . empty ( ) ) {
2013-04-27 01:52:55 +02:00
Transaction * CurT = beginTransaction ( CO ) ;
2013-03-11 13:11:15 +00:00
m_CI - > createPCHExternalASTSource ( PCHFileName ,
true /*DisablePCHValidation*/ ,
true /*AllowPCHWithCompilerErrors*/ ,
0 /*DeserializationListener*/ ) ;
2013-04-27 01:52:55 +02:00
Transaction * EndedT = endTransaction ( CurT ) ;
commitTransaction ( EndedT ) ;
2013-03-11 13:11:15 +00:00
}
2012-09-05 09:37:39 +00:00
2013-04-27 01:52:55 +02:00
Transaction * CurT = beginTransaction ( CO ) ;
2013-03-11 13:11:15 +00:00
Sema * TheSema = & m_CI - > getSema ( ) ;
m_Parser . reset ( new Parser ( m_CI - > getPreprocessor ( ) , * TheSema ,
2012-09-05 09:37:39 +00:00
false /*skipFuncBodies*/ ) ) ;
2013-03-11 13:11:15 +00:00
m_CI - > getPreprocessor ( ) . EnterMainSourceFile ( ) ;
2012-09-05 09:37:39 +00:00
// Initialize the parser after we have entered the main source file.
m_Parser - > Initialize ( ) ;
// Perform initialization that occurs after the parser has been initialized
// but before it parses anything. Initializes the consumers too.
2013-03-11 13:11:15 +00:00
TheSema - > Initialize ( ) ;
ExternalASTSource * External = TheSema - > getASTContext ( ) . getExternalSource ( ) ;
if ( External )
External - > StartTranslationUnit ( m_Consumer ) ;
2013-04-27 01:52:55 +02:00
Transaction * EndedT = endTransaction ( CurT ) ;
commitTransaction ( EndedT ) ;
2012-09-05 09:37:39 +00:00
}
IncrementalParser : : ~ IncrementalParser ( ) {
2012-11-20 13:21:00 +00:00
if ( hasCodeGenerator ( ) ) {
getCodeGenerator ( ) - > ReleaseModule ( ) ;
}
const Transaction * T = getFirstTransaction ( ) ;
const Transaction * nextT = 0 ;
while ( T ) {
nextT = T - > getNext ( ) ;
delete T ;
T = nextT ;
}
for ( size_t i = 0 ; i < m_TTransformers . size ( ) ; + + i )
delete m_TTransformers [ i ] ;
2012-09-05 09:37:39 +00:00
}
2012-11-14 22:06:58 +00:00
Transaction * IncrementalParser : : beginTransaction ( const CompilationOptions &
Opts ) {
2012-09-05 09:37:39 +00:00
Transaction * OldCurT = m_Consumer - > getTransaction ( ) ;
2013-04-24 09:57:30 +00:00
Transaction * NewCurT = 0 ;
2012-09-05 09:37:39 +00:00
// If we are in the middle of transaction and we see another begin
// transaction - it must be nested transaction.
2013-04-24 15:09:47 +00:00
if ( OldCurT & & OldCurT - > getState ( ) < = Transaction : : kCommitting ) {
2013-04-24 09:57:30 +00:00
// If the last nested was empty just reuse it.
Transaction * LastNestedT = OldCurT - > getLastNestedTransaction ( ) ;
if ( LastNestedT & & LastNestedT - > empty ( ) ) {
2013-04-24 15:09:47 +00:00
assert ( LastNestedT - > getState ( ) = = Transaction : : kCommitted & & " Broken " ) ;
2013-04-24 09:57:30 +00:00
NewCurT = LastNestedT ;
NewCurT - > reset ( ) ;
NewCurT - > setCompilationOpts ( Opts ) ;
}
2013-04-25 16:29:27 +00:00
else {
2013-04-24 11:57:29 +00:00
NewCurT = new Transaction ( Opts ) ;
2013-04-25 16:29:27 +00:00
OldCurT - > addNestedTransaction ( NewCurT ) ; // takes the ownership
}
2013-04-24 06:55:38 +00:00
m_Consumer - > setTransaction ( NewCurT ) ;
2012-11-14 22:06:58 +00:00
return NewCurT ;
2012-09-05 09:37:39 +00:00
}
2013-04-24 06:55:38 +00:00
if ( getLastTransaction ( ) & & getLastTransaction ( ) - > empty ( ) ) {
NewCurT = getLastTransaction ( ) ;
2013-04-24 09:06:58 +00:00
NewCurT - > reset ( ) ;
2013-04-24 06:55:38 +00:00
NewCurT - > setCompilationOpts ( Opts ) ;
}
2013-06-04 16:15:43 +02:00
else
2013-04-24 06:55:38 +00:00
NewCurT = new Transaction ( Opts ) ;
2013-04-24 08:51:27 +00:00
2013-04-24 06:55:38 +00:00
m_Consumer - > setTransaction ( NewCurT ) ;
2013-06-04 16:15:43 +02:00
if ( ! m_FirstTransaction ) {
m_FirstTransaction = NewCurT ;
m_LastTransaction = NewCurT ;
}
else if ( NewCurT ! = m_LastTransaction ) {
m_LastTransaction - > setNext ( NewCurT ) ;
m_LastTransaction = NewCurT ; // takes the ownership
2012-10-19 14:17:20 +00:00
}
2013-04-24 08:51:27 +00:00
2012-11-14 22:06:58 +00:00
return NewCurT ;
2012-09-05 09:37:39 +00:00
}
2013-04-27 01:52:55 +02:00
Transaction * IncrementalParser : : endTransaction ( Transaction * T ) const {
assert ( T & & " Null transaction!? " ) ;
assert ( T - > getState ( ) = = Transaction : : kCollecting ) ;
T - > setState ( Transaction : : kCompleted ) ;
2012-09-05 09:37:39 +00:00
const DiagnosticsEngine & Diags = getCI ( ) - > getSema ( ) . getDiagnostics ( ) ;
//TODO: Make the enum orable.
if ( Diags . getNumWarnings ( ) > 0 )
2013-04-27 01:52:55 +02:00
T - > setIssuedDiags ( Transaction : : kWarnings ) ;
2012-09-05 09:37:39 +00:00
if ( Diags . hasErrorOccurred ( ) | | Diags . hasFatalErrorOccurred ( ) )
2013-04-27 01:52:55 +02:00
T - > setIssuedDiags ( Transaction : : kErrors ) ;
2012-09-05 09:37:39 +00:00
2013-04-27 01:52:55 +02:00
if ( T - > hasNestedTransactions ( ) ) {
for ( Transaction : : const_nested_iterator I = T - > nested_begin ( ) ,
E = T - > nested_end ( ) ; I ! = E ; + + I )
2012-11-14 22:06:58 +00:00
assert ( ( * I ) - > isCompleted ( ) & & " Nested transaction not completed!? " ) ;
2012-11-13 23:52:30 +00:00
}
2013-04-27 01:52:55 +02:00
return T ;
2012-09-05 09:37:39 +00:00
}
2013-06-20 18:37:38 +02:00
void IncrementalParser : : commitTransaction ( Transaction * T ,
bool forceCodeGen /*=false*/ ) {
2012-11-14 22:06:58 +00:00
//Transaction* CurT = m_Consumer->getTransaction();
assert ( T - > isCompleted ( ) & & " Transaction not ended!? " ) ;
2013-04-09 15:30:16 +00:00
assert ( T - > getState ( ) ! = Transaction : : kCommitted
& & " Committing an already committed transaction. " ) ;
2012-09-05 09:37:39 +00:00
// Check for errors...
2012-11-14 22:06:58 +00:00
if ( T - > getIssuedDiags ( ) = = Transaction : : kErrors ) {
rollbackTransaction ( T ) ;
2012-09-05 09:37:39 +00:00
return ;
}
2012-11-14 22:06:58 +00:00
if ( T - > hasNestedTransactions ( ) ) {
2013-04-08 14:35:35 +00:00
for ( Transaction : : const_nested_iterator I = T - > nested_begin ( ) ,
E = T - > nested_end ( ) ; I ! = E ; + + I )
2013-04-09 15:30:16 +00:00
if ( ( * I ) - > getState ( ) ! = Transaction : : kCommitted )
commitTransaction ( * I ) ;
2012-11-14 22:06:58 +00:00
}
2013-06-14 09:37:45 +02:00
if ( hasCodeGenerator ( ) )
T - > setModule ( getCodeGenerator ( ) - > GetModule ( ) ) ;
2013-06-20 18:37:38 +02:00
2012-10-26 10:08:00 +00:00
bool success = true ;
2013-06-20 18:37:38 +02:00
if ( ! forceCodeGen ) {
// We are sure it's safe to pipe it through the transformers
for ( size_t i = 0 ; ! forceCodeGen & & i < m_TTransformers . size ( ) ; + + i ) {
success = m_TTransformers [ i ] - > TransformTransaction ( * T ) ;
if ( ! success ) {
break ;
}
}
m_CI - > getDiagnostics ( ) . Reset ( ) ; // FIXME: Should be in rollback transaction.
2012-10-27 21:41:21 +00:00
if ( ! success ) {
2013-06-20 18:37:38 +02:00
// Roll back on error in a transformer
rollbackTransaction ( T ) ;
return ;
2012-09-05 09:37:39 +00:00
}
2013-06-20 18:37:38 +02:00
// Pull all template instantiations in that came from the consumers.
getCI ( ) - > getSema ( ) . PerformPendingInstantiations ( ) ;
2012-10-26 10:08:00 +00:00
2013-06-20 18:37:38 +02:00
m_Consumer - > HandleTranslationUnit ( getCI ( ) - > getASTContext ( ) ) ;
2012-10-26 10:08:00 +00:00
}
2013-06-20 18:37:38 +02:00
LangOptions & Opts = m_CI - > getLangOpts ( ) ;
int EmitAllDeclsPrev = Opts . EmitAllDecls ;
if ( forceCodeGen )
Opts . EmitAllDecls = 1 ;
2012-09-05 09:37:39 +00:00
2012-11-14 22:06:58 +00:00
if ( T - > getCompilationOpts ( ) . CodeGeneration & & hasCodeGenerator ( ) ) {
2012-09-05 09:37:39 +00:00
// codegen the transaction
2013-04-23 21:48:36 +00:00
for ( size_t Idx = 0 ; Idx < T - > size ( ) /*can change in the loop!*/ ; + + Idx ) {
2013-03-11 13:11:15 +00:00
// Copy DCI; it might get relocated below.
Transaction : : DelayCallInfo I = ( * T ) [ Idx ] ;
if ( I . m_Call = = Transaction : : kCCIHandleTopLevelDecl )
getCodeGenerator ( ) - > HandleTopLevelDecl ( I . m_DGR ) ;
else if ( I . m_Call = = Transaction : : kCCIHandleInterestingDecl ) {
// Usually through BackendConsumer which doesn't implement
// HandleInterestingDecl() and thus calls
// ASTConsumer::HandleInterestingDecl()
getCodeGenerator ( ) - > HandleTopLevelDecl ( I . m_DGR ) ;
} else if ( I . m_Call = = Transaction : : kCCIHandleTagDeclDefinition ) {
TagDecl * TD = cast < TagDecl > ( I . m_DGR . getSingleDecl ( ) ) ;
2012-12-03 16:28:24 +00:00
getCodeGenerator ( ) - > HandleTagDeclDefinition ( TD ) ;
}
2013-03-11 13:11:15 +00:00
else if ( I . m_Call = = Transaction : : kCCIHandleVTable ) {
CXXRecordDecl * CXXRD = cast < CXXRecordDecl > ( I . m_DGR . getSingleDecl ( ) ) ;
2012-12-03 16:28:24 +00:00
getCodeGenerator ( ) - > HandleVTable ( CXXRD , /*isRequired*/ true ) ;
2012-12-12 08:08:56 +00:00
}
2013-03-11 13:11:15 +00:00
else if ( I . m_Call
2012-12-12 08:08:56 +00:00
= = Transaction : : kCCIHandleCXXImplicitFunctionInstantiation ) {
2013-03-11 13:11:15 +00:00
FunctionDecl * FD = cast < FunctionDecl > ( I . m_DGR . getSingleDecl ( ) ) ;
2012-12-12 08:08:56 +00:00
getCodeGenerator ( ) - > HandleCXXImplicitFunctionInstantiation ( FD ) ;
}
2013-03-11 13:11:15 +00:00
else if ( I . m_Call
2012-12-12 08:08:56 +00:00
= = Transaction : : kCCIHandleCXXStaticMemberVarInstantiation ) {
2013-03-11 13:11:15 +00:00
VarDecl * VD = cast < VarDecl > ( I . m_DGR . getSingleDecl ( ) ) ;
2012-12-12 08:08:56 +00:00
getCodeGenerator ( ) - > HandleCXXStaticMemberVarInstantiation ( VD ) ;
2012-12-03 16:28:24 +00:00
}
2013-03-11 13:11:15 +00:00
else if ( I . m_Call = = Transaction : : kCCINone )
2012-12-05 14:50:00 +00:00
; // We use that internally as delimiter in the Transaction.
else
2012-12-04 10:53:44 +00:00
llvm_unreachable ( " We shouldn't have decl without call info. " ) ;
2012-09-05 09:37:39 +00:00
}
2013-04-10 15:15:49 +00:00
2012-09-05 09:37:39 +00:00
getCodeGenerator ( ) - > HandleTranslationUnit ( getCI ( ) - > getASTContext ( ) ) ;
2013-04-09 15:30:16 +00:00
2013-04-10 15:15:49 +00:00
// The static initializers might run anything and can thus cause more
// decls that need to end up in a transaction. But this one is done
// with CodeGen...
T - > setState ( Transaction : : kCommitting ) ;
2012-09-05 09:37:39 +00:00
// run the static initializers that came from codegenning
2013-06-04 16:15:43 +02:00
if ( m_Interpreter - > runStaticInitializersOnce ( )
2012-11-20 16:24:02 +00:00
> = Interpreter : : kExeFirstError ) {
2012-12-03 16:28:24 +00:00
// Roll back on error in a transformer
rollbackTransaction ( T ) ;
return ;
2012-11-20 16:24:02 +00:00
}
2013-04-10 15:15:49 +00:00
} else
T - > setState ( Transaction : : kCommitting ) ;
2013-04-09 15:30:16 +00:00
2013-06-20 18:37:38 +02:00
if ( forceCodeGen )
Opts . EmitAllDecls = EmitAllDeclsPrev ;
2012-10-27 21:41:21 +00:00
2013-06-20 18:37:38 +02:00
if ( ! forceCodeGen ) {
InterpreterCallbacks * callbacks = m_Interpreter - > getCallbacks ( ) ;
if ( callbacks ) {
callbacks - > TransactionCommitted ( * T ) ;
}
if ( T - > hasNestedTransactions ( ) ) {
Transaction * SubTransactionWhileCommitting = * T - > rnested_begin ( ) ;
if ( SubTransactionWhileCommitting - > getState ( )
= = Transaction : : kCollecting ) {
// A nested transaction was created while committing this
// transaction; commit it now.
SubTransactionWhileCommitting - > setState ( Transaction : : kCompleted ) ;
commitTransaction ( SubTransactionWhileCommitting ) ;
}
2013-03-11 13:11:15 +00:00
}
}
2013-04-24 15:09:47 +00:00
T - > setState ( Transaction : : kCommitted ) ;
// If the transaction is empty do nothing.
// Except it was nested transaction and we want to reuse it later on.
if ( T - > empty ( ) & & T - > isNestedTransaction ( ) ) {
// We need to remove the marker from its parent.
Transaction * ParentT = T - > getParent ( ) ;
for ( size_t i = 0 ; i < ParentT - > size ( ) ; + + i )
if ( ( * ParentT ) [ i ] . m_DGR . isNull ( ) )
ParentT - > erase ( i ) ;
}
if ( T - > isNestedTransaction ( ) ) {
// TODO: Add proper logic in the case where there are multiple nested
// transaction. This now won't handle the case where there are more than
// one level 1 nested transactions.
m_Consumer - > setTransaction ( T - > getParent ( ) ) ;
}
2012-09-05 09:37:39 +00:00
}
void IncrementalParser : : rollbackTransaction ( Transaction * T ) const {
ASTNodeEraser NodeEraser ( & getCI ( ) - > getSema ( ) ) ;
if ( NodeEraser . RevertTransaction ( T ) )
T - > setState ( Transaction : : kRolledBack ) ;
else
T - > setState ( Transaction : : kRolledBackWithErrors ) ;
}
2012-11-14 22:06:58 +00:00
std : : vector < const Transaction * > IncrementalParser : : getAllTransactions ( ) {
std : : vector < const Transaction * > result ;
const cling : : Transaction * T = getFirstTransaction ( ) ;
while ( T ) {
result . push_back ( T ) ;
T = T - > getNext ( ) ;
}
return result ;
}
2012-09-05 09:37:39 +00:00
// Each input line is contained in separate memory buffer. The SourceManager
// assigns sort-of invalid FileID for each buffer, i.e there is no FileEntry
// for the MemoryBuffer's FileID. That in turn is problem because invalid
// SourceLocations are given to the diagnostics. Thus the diagnostics cannot
// order the overloads, for example
//
// Our work-around is creating a virtual file, which doesn't exist on the disk
// with enormous size (no allocation is done). That file has valid FileEntry
// and so on... We use it for generating valid SourceLocations with valid
// offsets so that it doesn't cause any troubles to the diagnostics.
//
// +---------------------+
// | Main memory buffer |
// +---------------------+
// | Virtual file SLoc |
// | address space |<-----------------+
// | ... |<------------+ |
// | ... | | |
// | ... |<----+ | |
// | ... | | | |
// +~~~~~~~~~~~~~~~~~~~~~+ | | |
// | input_line_1 | ....+.......+..--+
// +---------------------+ | |
// | input_line_2 | ....+.....--+
// +---------------------+ |
// | ... | |
// +---------------------+ |
// | input_line_N | ..--+
// +---------------------+
//
void IncrementalParser : : CreateSLocOffsetGenerator ( ) {
SourceManager & SM = getCI ( ) - > getSourceManager ( ) ;
2013-03-11 13:11:15 +00:00
m_VirtualFileID = SM . getMainFileID ( ) ;
2012-09-05 09:37:39 +00:00
assert ( ! m_VirtualFileID . isInvalid ( ) & & " No VirtualFileID created? " ) ;
}
2012-11-20 03:26:52 +00:00
Transaction * IncrementalParser : : Compile ( llvm : : StringRef input ,
const CompilationOptions & Opts ) {
2012-09-05 09:37:39 +00:00
2012-11-20 03:26:52 +00:00
Transaction * CurT = beginTransaction ( Opts ) ;
EParseResult ParseRes = ParseInternal ( input ) ;
2012-09-05 09:37:39 +00:00
2012-11-20 03:26:52 +00:00
if ( ParseRes = = kSuccessWithWarnings )
CurT - > setIssuedDiags ( Transaction : : kWarnings ) ;
else if ( ParseRes = = kFailed )
CurT - > setIssuedDiags ( Transaction : : kErrors ) ;
2013-04-27 01:52:55 +02:00
const Transaction * EndedT = endTransaction ( CurT ) ;
assert ( EndedT = = CurT & & " Not ending the expected transaction. " ) ;
2012-11-20 03:26:52 +00:00
commitTransaction ( CurT ) ;
return CurT ;
2012-09-05 09:37:39 +00:00
}
2012-10-15 13:42:09 +00:00
Transaction * IncrementalParser : : Parse ( llvm : : StringRef input ,
const CompilationOptions & Opts ) {
2013-04-27 01:52:55 +02:00
Transaction * CurT = beginTransaction ( Opts ) ;
2012-09-05 09:37:39 +00:00
ParseInternal ( input ) ;
2013-04-27 01:52:55 +02:00
Transaction * EndedT = endTransaction ( CurT ) ;
assert ( EndedT = = CurT & & " Not ending the expected transaction. " ) ;
return EndedT ;
2012-09-05 09:37:39 +00:00
}
// Add the input to the memory buffer, parse it, and add it to the AST.
IncrementalParser : : EParseResult
IncrementalParser : : ParseInternal ( llvm : : StringRef input ) {
if ( input . empty ( ) ) return IncrementalParser : : kSuccess ;
Sema & S = getCI ( ) - > getSema ( ) ;
2013-04-10 07:09:57 +00:00
2013-04-10 07:14:37 +00:00
assert ( ! ( S . getLangOpts ( ) . Modules
& & m_Consumer - > getTransaction ( ) - > getCompilationOpts ( )
. CodeGenerationForModule )
2013-04-10 07:09:57 +00:00
& & " CodeGenerationForModule should be removed once modules are available! " ) ;
2012-09-05 09:37:39 +00:00
// Recover resources if we crash before exiting this method.
llvm : : CrashRecoveryContextCleanupRegistrar < Sema > CleanupSema ( & S ) ;
Preprocessor & PP = m_CI - > getPreprocessor ( ) ;
if ( ! PP . getCurrentLexer ( ) ) {
PP . EnterSourceFile ( m_CI - > getSourceManager ( ) . getMainFileID ( ) ,
0 , SourceLocation ( ) ) ;
}
2012-10-04 13:09:52 +00:00
assert ( PP . isIncrementalProcessingEnabled ( ) & & " Not in incremental mode!? " ) ;
2012-09-05 09:37:39 +00:00
PP . enableIncrementalProcessing ( ) ;
std : : ostringstream source_name ;
source_name < < " input_line_ " < < ( m_MemoryBuffers . size ( ) + 1 ) ;
// Create an uninitialized memory buffer, copy code in and append "\n"
size_t InputSize = input . size ( ) ; // don't include trailing 0
// MemBuffer size should *not* include terminating zero
llvm : : MemoryBuffer * MB
= llvm : : MemoryBuffer : : getNewUninitMemBuffer ( InputSize + 1 ,
source_name . str ( ) ) ;
char * MBStart = const_cast < char * > ( MB - > getBufferStart ( ) ) ;
memcpy ( MBStart , input . data ( ) , InputSize ) ;
memcpy ( MBStart + InputSize , " \n " , 2 ) ;
m_MemoryBuffers . push_back ( MB ) ;
SourceManager & SM = getCI ( ) - > getSourceManager ( ) ;
// Create SourceLocation, which will allow clang to order the overload
// candidates for example
SourceLocation NewLoc = SM . getLocForStartOfFile ( m_VirtualFileID ) ;
NewLoc = NewLoc . getLocWithOffset ( m_MemoryBuffers . size ( ) + 1 ) ;
// Create FileID for the current buffer
FileID FID = SM . createFileIDForMemBuffer ( m_MemoryBuffers . back ( ) ,
2013-04-24 16:28:08 +00:00
SrcMgr : : C_User ,
2012-09-05 09:37:39 +00:00
/*LoadedID*/ 0 ,
/*LoadedOffset*/ 0 , NewLoc ) ;
PP . EnterSourceFile ( FID , /*DirLookup*/ 0 , NewLoc ) ;
Parser : : DeclGroupPtrTy ADecl ;
while ( ! m_Parser - > ParseTopLevelDecl ( ADecl ) ) {
// If we got a null return and something *was* parsed, ignore it. This
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
if ( ADecl )
m_Consumer - > HandleTopLevelDecl ( ADecl . getAsVal < DeclGroupRef > ( ) ) ;
} ;
// Process any TopLevelDecls generated by #pragma weak.
for ( llvm : : SmallVector < Decl * , 2 > : : iterator I = S . WeakTopLevelDecls ( ) . begin ( ) ,
E = S . WeakTopLevelDecls ( ) . end ( ) ; I ! = E ; + + I ) {
m_Consumer - > HandleTopLevelDecl ( DeclGroupRef ( * I ) ) ;
}
DiagnosticsEngine & Diag = S . getDiagnostics ( ) ;
if ( Diag . hasErrorOccurred ( ) )
return IncrementalParser : : kFailed ;
else if ( Diag . getNumWarnings ( ) )
return IncrementalParser : : kSuccessWithWarnings ;
return IncrementalParser : : kSuccess ;
}
void IncrementalParser : : unloadTransaction ( Transaction * T ) {
if ( ! T )
T = getLastTransaction ( ) ;
assert ( T - > getState ( ) = = Transaction : : kCommitted & &
" Unloading not commited transaction? " ) ;
assert ( T - > getModule ( ) & &
" Trying to uncodegen transaction taken in syntax only mode. " ) ;
ASTNodeEraser NodeEraser ( & getCI ( ) - > getSema ( ) ) ;
NodeEraser . RevertTransaction ( T ) ;
2012-10-02 10:30:25 +00:00
InterpreterCallbacks * callbacks = m_Interpreter - > getCallbacks ( ) ;
2012-10-10 14:50:45 +00:00
if ( callbacks )
2012-10-02 10:30:25 +00:00
callbacks - > TransactionUnloaded ( * T ) ;
2012-09-05 09:37:39 +00:00
}
} // namespace cling