2015-12-16 11:25:58 +01:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
2015-12-09 21:01:04 +01:00
//
2015-12-16 11:25:58 +01: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.
//------------------------------------------------------------------------------
2015-12-09 21:01:04 +01:00
2015-12-16 11:25:58 +01:00
// FIXME: This file shall contain the decl of cling::Jupyter in a future
// revision!
2015-12-10 15:20:01 +01:00
//#include "cling/Interpreter/Jupyter/Kernel.h"
2015-12-09 21:01:04 +01:00
# include "cling/Interpreter/Interpreter.h"
# include "cling/Interpreter/Value.h"
2016-04-08 16:45:45 +02:00
# include "cling/MetaProcessor/MetaProcessor.h"
2016-09-10 15:04:39 -04:00
# include "cling/Utils/Output.h"
2015-12-09 21:01:04 +01:00
2018-11-22 14:18:31 -08:00
# include "cling/Interpreter/Exception.h"
2015-12-11 16:18:29 +01:00
# include "llvm/Support/raw_ostream.h"
2015-12-10 15:20:01 +01:00
# include <map>
# include <string>
2015-12-11 16:18:29 +01:00
# include <cstring>
2020-10-05 06:22:33 +00:00
# ifndef _WIN32
2016-02-23 09:24:23 +01:00
# include <unistd.h>
# else
# include <io.h>
# define write _write
# endif
2015-12-10 15:20:01 +01:00
2015-12-10 17:16:21 +01:00
// FIXME: should be moved into a Jupyter interp struct that then gets returned
// from create.
int pipeToJupyterFD = - 1 ;
2015-12-10 15:20:01 +01:00
namespace cling {
namespace Jupyter {
struct MIMEDataRef {
const char * m_Data ;
const long m_Size ;
MIMEDataRef ( const std : : string & str ) :
m_Data ( str . c_str ( ) ) , m_Size ( ( long ) str . length ( ) + 1 ) { }
MIMEDataRef ( const char * str ) :
MIMEDataRef ( std : : string ( str ) ) { }
MIMEDataRef ( const char * data , long size ) :
m_Data ( data ) , m_Size ( size ) { }
} ;
/// Push MIME stuff to Jupyter. To be called from user code.
///\param contentDict - dictionary of MIME type versus content. E.g.
/// {{"text/html", {"<div></div>", }}
2016-04-01 16:09:32 +02:00
///\returns `false` if the output could not be sent.
bool pushOutput ( const std : : map < std : : string , MIMEDataRef > contentDict ) {
2015-12-10 15:20:01 +01:00
// Pipe sees (all numbers are longs, except for the first:
// - num bytes in a long (sent as a single unsigned char!)
// - num elements of the MIME dictionary; Jupyter selects one to display.
// For each MIME dictionary element:
2015-12-10 17:34:02 +01:00
// - size of MIME type string (including the terminating 0)
2015-12-10 15:20:01 +01:00
// - MIME type as 0-terminated string
// - size of MIME data buffer (including the terminating 0 for
// 0-terminated strings)
// - MIME data buffer
// Write number of dictionary elements (and the size of that number in a
// char)
unsigned char sizeLong = sizeof ( long ) ;
2016-04-01 16:09:32 +02:00
if ( write ( pipeToJupyterFD , & sizeLong , 1 ) ! = 1 )
return false ;
2015-12-10 15:20:01 +01:00
long dictSize = contentDict . size ( ) ;
2016-04-01 16:09:32 +02:00
if ( write ( pipeToJupyterFD , & dictSize , sizeof ( long ) ) ! = sizeof ( long ) )
return false ;
2015-12-10 15:20:01 +01:00
for ( auto iContent : contentDict ) {
const std : : string & mimeType = iContent . first ;
2015-12-10 17:34:02 +01:00
long mimeTypeSize = ( long ) mimeType . size ( ) ;
2016-04-01 16:09:32 +02:00
if ( write ( pipeToJupyterFD , & mimeTypeSize , sizeof ( long ) ) ! = sizeof ( long ) )
return false ;
if ( write ( pipeToJupyterFD , mimeType . c_str ( ) , mimeType . size ( ) + 1 )
2016-04-01 20:50:03 +02:00
! = ( long ) ( mimeType . size ( ) + 1 ) )
2016-04-01 16:09:32 +02:00
return false ;
2015-12-10 15:20:01 +01:00
const MIMEDataRef & mimeData = iContent . second ;
2016-04-01 16:09:32 +02:00
if ( write ( pipeToJupyterFD , & mimeData . m_Size , sizeof ( long ) )
! = sizeof ( long ) )
return false ;
if ( write ( pipeToJupyterFD , mimeData . m_Data , mimeData . m_Size )
! = mimeData . m_Size )
return false ;
2015-12-10 15:20:01 +01:00
}
2016-04-01 16:09:32 +02:00
return true ;
2015-12-10 15:20:01 +01:00
}
} // namespace Jupyter
} // namespace cling
2015-12-09 21:01:04 +01:00
extern " C " {
///\{
///\name Cling4CTypes
/// The Python compatible view of cling
2016-04-08 16:45:45 +02:00
/// The MetaProcessor cast to void*
using TheMetaProcessor = void ;
2015-12-09 21:01:04 +01:00
/// Create an interpreter object.
2016-04-08 16:45:45 +02:00
TheMetaProcessor *
2015-12-10 17:16:21 +01:00
cling_create ( int argc , const char * argv [ ] , const char * llvmdir , int pipefd ) {
pipeToJupyterFD = pipefd ;
2016-04-08 16:45:45 +02:00
auto I = new cling : : Interpreter ( argc , argv , llvmdir ) ;
2016-09-10 15:04:39 -04:00
return new cling : : MetaProcessor ( * I , cling : : errs ( ) ) ;
2015-12-09 21:01:04 +01:00
}
2015-12-10 14:13:56 +01:00
/// Destroy the interpreter.
2016-04-08 16:45:45 +02:00
void cling_destroy ( TheMetaProcessor * metaProc ) {
cling : : MetaProcessor * M = ( cling : : MetaProcessor * ) metaProc ;
cling : : Interpreter * I = const_cast < cling : : Interpreter * > ( & M - > getInterpreter ( ) ) ;
delete M ;
delete I ;
2015-12-10 14:13:56 +01:00
}
2015-12-10 17:16:21 +01:00
/// Stringify a cling::Value
static std : : string ValueToString ( const cling : : Value & V ) {
std : : string valueString ;
{
2015-12-11 16:18:29 +01:00
llvm : : raw_string_ostream os ( valueString ) ;
2015-12-10 17:16:21 +01:00
V . print ( os ) ;
}
return valueString ;
}
2015-12-10 14:13:56 +01:00
2015-12-10 17:16:21 +01:00
/// Evaluate a string of code. Returns nullptr on failure.
/// Returns a string representation of the expression (can be "") on success.
2016-04-08 16:45:45 +02:00
char * cling_eval ( TheMetaProcessor * metaProc , const char * code ) {
cling : : MetaProcessor * M = ( cling : : MetaProcessor * ) metaProc ;
2015-12-10 17:16:21 +01:00
cling : : Value V ;
2016-04-08 16:45:45 +02:00
cling : : Interpreter : : CompilationResult Res ;
2018-11-22 14:18:31 -08:00
bool isExcept = false ;
try {
if ( M - > process ( code , Res , & V , /*disableValuePrinting*/ true ) ) {
cling : : Jupyter : : pushOutput ( { { " text/html " , " Incomplete input! Ignored. " } } ) ;
M - > cancelContinuation ( ) ;
return nullptr ;
}
}
catch ( cling : : InterpreterException & e ) {
//std::string output (strcat("Caught an interpreter exception:", e.what().c_str())) ;
std : : string output ( " Caught an interpreter exception: " ) ;
output + = e . what ( ) ;
cling : : Jupyter : : pushOutput ( { { " text/html " , output } } ) ;
isExcept = true ;
}
catch ( std : : exception & e ) {
//std::string output(strcat("Caught a standard exception:" , e.what().c_str())) ;
std : : string output ( " Caught a standard exception: " ) ;
output + = e . what ( ) ;
cling : : Jupyter : : pushOutput ( { { " text/html " , output } } ) ;
isExcept = true ;
}
catch ( . . . ) {
std : : string output = " Exception occurred. Recovering... \n " ;
cling : : Jupyter : : pushOutput ( { { " text/html " , output } } ) ;
isExcept = true ;
}
if ( isExcept ) {
2016-04-08 16:45:45 +02:00
return nullptr ;
}
2018-11-22 14:18:31 -08:00
2015-12-09 21:01:04 +01:00
if ( Res ! = cling : : Interpreter : : kSuccess )
2015-12-10 17:16:21 +01:00
return nullptr ;
if ( ! V . isValid ( ) )
return strdup ( " " ) ;
2015-12-11 16:18:29 +01:00
return strdup ( ValueToString ( V ) . c_str ( ) ) ;
2015-12-10 17:16:21 +01:00
}
void cling_eval_free ( char * str ) {
free ( str ) ;
2015-12-09 21:01:04 +01:00
}
2015-12-10 15:20:01 +01:00
2015-12-10 16:00:46 +01:00
/// Code completion interfaces.
/// Start completion of code. Returns a handle to be passed to
/// cling_complete_next() to iterate over the completion options. Returns nulptr
/// if no completions are known.
void * cling_complete_start ( const char * code ) {
return new int ( 42 ) ;
}
/// Grab the next completion of some code. Returns nullptr if none is left.
const char * cling_complete_next ( void * completionHandle ) {
2015-12-11 16:18:29 +01:00
int * counter = ( int * ) completionHandle ;
2015-12-10 16:00:46 +01:00
if ( + + ( * counter ) > 43 ) {
delete counter ;
return nullptr ;
}
return " COMPLETE! " ;
}
2015-12-09 21:01:04 +01:00
///\}
2015-12-10 14:09:09 +01:00
} // extern "C"