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"
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>
2016-02-23 12:37:22 +01:00
# ifndef LLVM_ON_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
/// The Interpreter object cast to void*
using TheInterpreter = void ;
/// Create an interpreter object.
2015-12-10 15:20:01 +01:00
TheInterpreter *
2015-12-10 17:16:21 +01:00
cling_create ( int argc , const char * argv [ ] , const char * llvmdir , int pipefd ) {
2015-12-10 10:36:55 +01:00
auto interp = new cling : : Interpreter ( argc , argv , llvmdir ) ;
2015-12-10 17:16:21 +01:00
pipeToJupyterFD = pipefd ;
2015-12-10 10:36:55 +01:00
return interp ;
2015-12-09 21:01:04 +01:00
}
2015-12-10 14:13:56 +01:00
/// Destroy the interpreter.
void cling_destroy ( TheInterpreter * interpVP ) {
cling : : Interpreter * interp = ( cling : : Interpreter * ) interpVP ;
delete interp ;
}
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.
char * cling_eval ( TheInterpreter * interpVP , const char * code ) {
2015-12-09 21:01:04 +01:00
cling : : Interpreter * interp = ( cling : : Interpreter * ) interpVP ;
2015-12-10 17:16:21 +01:00
cling : : Value V ;
2015-12-12 16:49:47 +01:00
cling : : Interpreter : : CompilationResult Res = interp - > process ( code , & V ) ;
2015-12-09 21:01:04 +01:00
if ( Res ! = cling : : Interpreter : : kSuccess )
2015-12-10 17:16:21 +01:00
return nullptr ;
2016-03-31 21:02:12 +02:00
// cling::Jupyter::pushOutput({{"text/html", "You just executed C++ code!"}});
2015-12-10 17:16:21 +01:00
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"