-
Notifications
You must be signed in to change notification settings - Fork 100
/
Kernel.cpp
202 lines (175 loc) · 6.28 KB
/
Kernel.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <[email protected]>
//
// 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.
//------------------------------------------------------------------------------
// FIXME: This file shall contain the decl of cling::Jupyter in a future
// revision!
//#include "cling/Interpreter/Jupyter/Kernel.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "cling/Utils/Output.h"
#include "cling/Interpreter/Exception.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <string>
#include <cstring>
#ifndef _WIN32
# include <unistd.h>
#else
# include <io.h>
# define write _write
#endif
// FIXME: should be moved into a Jupyter interp struct that then gets returned
// from create.
int pipeToJupyterFD = -1;
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>", }}
///\returns `false` if the output could not be sent.
bool pushOutput(const std::map<std::string, MIMEDataRef> contentDict) {
// 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:
// - size of MIME type string (including the terminating 0)
// - 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);
if (write(pipeToJupyterFD, &sizeLong, 1) != 1)
return false;
long dictSize = contentDict.size();
if (write(pipeToJupyterFD, &dictSize, sizeof(long)) != sizeof(long))
return false;
for (auto iContent: contentDict) {
const std::string& mimeType = iContent.first;
long mimeTypeSize = (long)mimeType.size();
if (write(pipeToJupyterFD, &mimeTypeSize, sizeof(long)) != sizeof(long))
return false;
if (write(pipeToJupyterFD, mimeType.c_str(), mimeType.size() + 1)
!= (long)(mimeType.size() + 1))
return false;
const MIMEDataRef& mimeData = iContent.second;
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;
}
return true;
}
} // namespace Jupyter
} // namespace cling
extern "C" {
///\{
///\name Cling4CTypes
/// The Python compatible view of cling
/// The MetaProcessor cast to void*
using TheMetaProcessor = void;
/// Create an interpreter object.
TheMetaProcessor*
cling_create(int argc, const char *argv[], const char* llvmdir, int pipefd) {
pipeToJupyterFD = pipefd;
auto I = new cling::Interpreter(argc, argv, llvmdir);
return new cling::MetaProcessor(*I, cling::errs());
}
/// Destroy the interpreter.
void cling_destroy(TheMetaProcessor *metaProc) {
cling::MetaProcessor *M = (cling::MetaProcessor*)metaProc;
cling::Interpreter *I = const_cast<cling::Interpreter*>(&M->getInterpreter());
delete M;
delete I;
}
/// Stringify a cling::Value
static std::string ValueToString(const cling::Value& V) {
std::string valueString;
{
llvm::raw_string_ostream os(valueString);
V.print(os);
}
return valueString;
}
/// Evaluate a string of code. Returns nullptr on failure.
/// Returns a string representation of the expression (can be "") on success.
char* cling_eval(TheMetaProcessor *metaProc, const char *code) {
cling::MetaProcessor *M = (cling::MetaProcessor*)metaProc;
cling::Value V;
cling::Interpreter::CompilationResult Res;
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) {
return nullptr;
}
if (Res != cling::Interpreter::kSuccess)
return nullptr;
if (!V.isValid())
return strdup("");
return strdup(ValueToString(V).c_str());
}
void cling_eval_free(char* str) {
free(str);
}
/// 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) {
int* counter = (int*) completionHandle;
if (++(*counter) > 43) {
delete counter;
return nullptr;
}
return "COMPLETE!";
}
///\}
} // extern "C"