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
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"
2016-07-19 12:46:57 +03:00
# include "textinput/Callbacks.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-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>
2016-07-07 11:47:58 +03:00
namespace {
///\brief Class that specialises the textinput TabCompletion to allow Cling
/// to code complete through its own textinput mechanism which is part of the
/// UserInterface.
///
2016-07-19 12:46:57 +03:00
class UITabCompletion : public textinput : : TabCompletion {
const cling : : Interpreter & m_ParentInterpreter ;
2016-07-07 11:47:58 +03:00
public :
2016-07-19 12:46:57 +03:00
UITabCompletion ( const cling : : Interpreter & Parent ) :
m_ParentInterpreter ( Parent ) { }
~ UITabCompletion ( ) { }
2016-07-07 11:47:58 +03:00
bool Complete ( textinput : : Text & Line /*in+out*/ ,
2016-07-19 12:46:57 +03:00
size_t & Cursor /*in+out*/ ,
textinput : : EditorRange & R /*out*/ ,
std : : vector < std : : string > & Completions /*out*/ ) override {
m_ParentInterpreter . codeComplete ( Line . GetText ( ) , Cursor , Completions ) ;
return true ;
2016-07-07 11:47:58 +03:00
}
} ;
}
2012-12-06 13:54:20 +04:00
namespace cling {
2013-09-09 16:32:37 +04:00
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 ) ) ;
2016-09-05 21:06:32 +03:00
llvm : : install_fatal_error_handler ( & CompilationException : : throwingHandler ) ;
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
2016-09-16 04:19:46 +03:00
if ( llvm : : sys : : path : : home_directory ( histfilePath ) )
llvm : : sys : : path : : append ( histfilePath , " .cling_history " ) ;
2014-02-06 20:34:56 +04:00
}
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
2016-06-23 19:09:06 +03:00
// Inform text input about the code complete consumer
2016-07-07 11:47:58 +03:00
// TextInput owns the TabCompletion.
2016-07-19 12:46:57 +03:00
UITabCompletion * Completion =
new UITabCompletion ( m_MetaProcessor - > getInterpreter ( ) ) ;
2016-06-28 20:10:37 +03:00
TI . SetCompletion ( Completion ) ;
2016-06-23 19:09:06 +03:00
2016-08-31 06:09:14 +03:00
std : : string Line ;
std : : string Prompt ( " [cling]$ " ) ;
2013-08-28 01:40:49 +04:00
while ( true ) {
try {
2016-08-31 06:09:14 +03:00
TI . SetPrompt ( Prompt . c_str ( ) ) ;
2013-08-28 01:00:35 +04:00
m_MetaProcessor - > getOuts ( ) . flush ( ) ;
TextInput : : EReadResult RR = TI . ReadInput ( ) ;
2016-08-31 06:09:14 +03:00
TI . TakeInput ( Line ) ;
2013-08-28 01:00:35 +04:00
if ( RR = = TextInput : : kRREOF ) {
break ;
}
cling : : Interpreter : : CompilationResult compRes ;
2014-01-13 11:57:12 +04:00
MetaProcessor : : MaybeRedirectOutputRAII RAII ( m_MetaProcessor . get ( ) ) ;
2016-08-31 06:09:14 +03:00
const int indent = m_MetaProcessor - > process ( Line . c_str ( ) , compRes ) ;
2016-08-31 05:51:41 +03:00
// Quit requested?
2013-08-28 01:00:35 +04:00
if ( indent < 0 )
break ;
2016-08-31 06:09:14 +03:00
Prompt . replace ( 7 , std : : string : : npos ,
m_MetaProcessor - > getInterpreter ( ) . isRawInputEnabled ( ) ? " ! " : " $ " ) ;
2012-12-06 13:54:20 +04:00
2016-08-31 06:09:14 +03:00
// Continuation requested?
if ( indent > 0 ) {
Prompt . append ( 1 , ' ? ' ) ;
Prompt . append ( indent * 3 , ' ' ) ;
}
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