2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
// 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.
2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
2012-12-06 13:54:20 +04:00
# include "cling/UserInterface/UserInterface.h"
2012-09-05 13:37:39 +04:00
2013-09-09 16:32:37 +04:00
# include "cling/UserInterface/CompilationException.h"
2015-11-27 15:54:20 +03:00
# include "cling/Interpreter/Exception.h"
2012-12-06 13:54:20 +04:00
# include "cling/MetaProcessor/MetaProcessor.h"
2012-09-05 13:37:39 +04:00
# include "textinput/TextInput.h"
# include "textinput/StreamReader.h"
# include "textinput/TerminalDisplay.h"
2013-09-19 20:10:25 +04:00
# include "llvm/ADT/SmallString.h"
2012-09-05 13:37:39 +04:00
# include "llvm/Support/raw_ostream.h"
2013-09-06 23:36:03 +04:00
# include "llvm/Support/ErrorHandling.h"
2013-09-19 18:54:21 +04:00
# include "llvm/Support/Path.h"
2013-01-22 17:56:38 +04:00
# include "llvm/Config/config.h"
2012-09-05 13:37:39 +04:00
2015-02-22 01:09:18 +03:00
# include "clang/Basic/LangOptions.h"
# include "clang/Frontend/CompilerInstance.h"
2013-01-18 13:02:46 +04:00
// Fragment copied from LLVM's raw_ostream.cpp
2013-01-18 20:20:34 +04:00
# if defined(HAVE_UNISTD_H)
# include <unistd.h>
# endif
2013-09-19 18:54:21 +04:00
# if defined(LLVM_ON_WIN32)
# include <Shlobj.h>
# endif
2013-01-18 13:02:46 +04:00
# if defined(_MSC_VER)
# ifndef STDIN_FILENO
# define STDIN_FILENO 0
# endif
# ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
# endif
# ifndef STDERR_FILENO
# define STDERR_FILENO 2
# endif
# endif
2013-01-17 20:40:33 +04:00
2014-08-01 16:02:15 +04:00
# include <memory>
2013-09-06 23:36:03 +04:00
namespace {
2013-09-11 12:03:27 +04:00
// Handle fatal llvm errors by throwing an exception.
2013-09-06 23:36:03 +04:00
// Yes, throwing exceptions in error handlers is bad.
// Doing nothing is pretty terrible, too.
void exceptionErrorHandler ( void * /*user_data*/ ,
const std : : string & reason ,
bool /*gen_crash_diag*/ ) {
2013-09-09 16:32:37 +04:00
throw cling : : CompilationException ( reason ) ;
2013-09-06 23:36:03 +04:00
}
2013-09-19 18:54:21 +04:00
# if defined(LLVM_ON_UNIX)
static void GetUserHomeDirectory ( llvm : : SmallVectorImpl < char > & str ) {
2013-09-19 20:10:25 +04:00
str . clear ( ) ;
const char * home = getenv ( " HOME " ) ;
if ( ! home )
home = " / " ;
llvm : : StringRef SRhome ( home ) ;
str . insert ( str . begin ( ) , SRhome . begin ( ) , SRhome . end ( ) ) ;
2013-09-19 18:54:21 +04:00
}
# elif defined(LLVM_ON_WIN32)
static void GetUserHomeDirectory ( llvm : : SmallVectorImpl < char > & str ) {
str . reserve ( MAX_PATH ) ;
HRESULT res = SHGetFolderPathA ( NULL ,
CSIDL_FLAG_CREATE | CSIDL_APPDATA ,
NULL ,
SHGFP_TYPE_CURRENT ,
str . data ( ) ) ;
if ( res ! = S_OK ) {
assert ( 0 & & " Failed to get user home directory " ) ;
2013-09-19 20:10:25 +04:00
llvm : : StringRef SRhome ( " \\ " ) ;
str . insert ( str . begin ( ) , SRhome . begin ( ) , SRhome . end ( ) ) ;
2013-09-19 18:54:21 +04:00
}
}
# else
# error "Unsupported platform."
# endif
2013-09-06 23:36:03 +04:00
}
2012-12-06 13:54:20 +04:00
namespace cling {
2013-09-09 16:32:37 +04:00
// Declared in CompilationException.h; vtable pinned here.
CompilationException : : ~ CompilationException ( ) throw ( ) { }
2012-12-06 13:54:20 +04:00
UserInterface : : UserInterface ( Interpreter & interp ) {
2013-01-17 19:27:14 +04:00
// We need stream that doesn't close its file descriptor, thus we are not
// using llvm::outs. Keeping file descriptor open we will be able to use
// the results in pipes (Savannah #99234).
static llvm : : raw_fd_ostream m_MPOuts ( STDOUT_FILENO , /*ShouldClose*/ false ) ;
m_MetaProcessor . reset ( new MetaProcessor ( interp , m_MPOuts ) ) ;
2013-09-06 23:36:03 +04:00
llvm : : install_fatal_error_handler ( & exceptionErrorHandler ) ;
2012-09-05 13:37:39 +04:00
}
2012-12-06 13:54:20 +04:00
UserInterface : : ~ UserInterface ( ) { }
2012-09-05 13:37:39 +04:00
2012-12-06 13:54:20 +04:00
void UserInterface : : runInteractively ( bool nologo /* = false */ ) {
if ( ! nologo ) {
PrintLogo ( ) ;
2012-09-05 13:37:39 +04:00
}
2013-09-19 20:10:25 +04:00
llvm : : SmallString < 512 > histfilePath ;
2014-02-06 20:34:56 +04:00
if ( ! getenv ( " CLING_NOHISTORY " ) ) {
// History file is $HOME/.cling_history
static const char * histfile = " .cling_history " ;
GetUserHomeDirectory ( histfilePath ) ;
llvm : : sys : : path : : append ( histfilePath , histfile ) ;
}
2012-12-06 13:54:20 +04:00
using namespace textinput ;
2014-08-01 16:02:15 +04:00
std : : unique_ptr < StreamReader > R ( StreamReader : : Create ( ) ) ;
std : : unique_ptr < TerminalDisplay > D ( TerminalDisplay : : Create ( ) ) ;
2014-02-06 20:34:56 +04:00
TextInput TI ( * R , * D , histfilePath . empty ( ) ? 0 : histfilePath . c_str ( ) ) ;
2012-12-06 13:54:20 +04:00
TI . SetPrompt ( " [cling]$ " ) ;
std : : string line ;
2013-08-28 01:40:49 +04:00
while ( true ) {
try {
2013-08-28 01:00:35 +04:00
m_MetaProcessor - > getOuts ( ) . flush ( ) ;
TextInput : : EReadResult RR = TI . ReadInput ( ) ;
TI . TakeInput ( line ) ;
if ( RR = = TextInput : : kRREOF ) {
break ;
}
cling : : Interpreter : : CompilationResult compRes ;
2014-01-13 11:57:12 +04:00
MetaProcessor : : MaybeRedirectOutputRAII RAII ( m_MetaProcessor . get ( ) ) ;
2014-08-04 06:05:42 +04:00
int indent
2013-08-28 01:00:35 +04:00
= m_MetaProcessor - > process ( line . c_str ( ) , compRes , 0 /*result*/ ) ;
// Quit requested
if ( indent < 0 )
break ;
std : : string Prompt = " [cling] " ;
if ( m_MetaProcessor - > getInterpreter ( ) . isRawInputEnabled ( ) )
Prompt . append ( " ! " ) ;
else
Prompt . append ( " $ " ) ;
if ( indent > 0 )
// Continuation requested.
Prompt . append ( ' ? ' + std : : string ( indent * 3 , ' ' ) ) ;
TI . SetPrompt ( Prompt . c_str ( ) ) ;
2012-12-06 13:54:20 +04:00
}
2015-12-08 15:26:13 +03:00
catch ( InvalidDerefException & e ) {
2013-09-07 12:44:01 +04:00
e . diagnose ( ) ;
2013-09-07 01:37:21 +04:00
}
2015-12-01 17:41:16 +03:00
catch ( InterpreterException & e ) {
2013-09-11 11:36:37 +04:00
llvm : : errs ( ) < < " >>> Caught an interpreter exception! \n "
< < " >>> " < < e . what ( ) < < ' \n ' ;
}
catch ( std : : exception & e ) {
llvm : : errs ( ) < < " >>> Caught a std::exception! \n "
< < " >>> " < < e . what ( ) < < ' \n ' ;
2013-09-05 18:43:20 +04:00
}
2013-08-28 01:40:49 +04:00
catch ( . . . ) {
llvm : : errs ( ) < < " Exception occurred. Recovering... \n " ;
}
2012-12-06 13:54:20 +04:00
}
2012-09-05 13:37:39 +04:00
}
2012-12-06 13:54:20 +04:00
void UserInterface : : PrintLogo ( ) {
2013-01-17 19:27:14 +04:00
llvm : : raw_ostream & outs = m_MetaProcessor - > getOuts ( ) ;
2015-02-22 01:09:18 +03:00
const clang : : LangOptions & LangOpts
= m_MetaProcessor - > getInterpreter ( ) . getCI ( ) - > getLangOpts ( ) ;
if ( LangOpts . CPlusPlus ) {
outs < < " \n "
" ****************** CLING ****************** \n "
" * Type C++ code and press enter to run it * \n "
" * Type .q to exit * \n "
" ******************************************* \n " ;
} else {
outs < < " \n "
" ***************** CLING ***************** \n "
" * Type C code and press enter to run it * \n "
" * Type .q to exit * \n "
" ***************************************** \n " ;
}
2012-12-06 13:54:20 +04:00
}
} // end namespace cling