Skip to content

Commit d2d305f

Browse files
committed
Attempt to process cell without semicolon
1 parent 4745f72 commit d2d305f

File tree

4 files changed

+192
-36
lines changed

4 files changed

+192
-36
lines changed

src/xinterpreter.cpp

+43-36
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "xinput.hpp"
2929
#include "xinspect.hpp"
3030
#include "xmagics/os.hpp"
31+
#include "xmime_internal.hpp"
3132
#include "xparser.hpp"
3233
#include "xsystem.hpp"
3334

@@ -128,17 +129,14 @@ __get_cxx_version ()
128129

129130
void interpreter::execute_request_impl(
130131
send_reply_callback cb,
131-
int /*execution_count*/,
132+
int execution_counter,
132133
const std::string& code,
133134
xeus::execute_request_config config,
134135
nl::json /*user_expressions*/
135136
)
136137
{
137138
nl::json kernel_res;
138139

139-
140-
auto input_guard = input_redirection(config.allow_stdin);
141-
142140
// Check for magics
143141
for (auto& pre : preamble_manager.preamble)
144142
{
@@ -150,10 +148,15 @@ __get_cxx_version ()
150148
}
151149
}
152150

151+
// Split code from includes
152+
auto blocks = split_from_includes(code);
153+
153154
auto errorlevel = 0;
155+
154156
std::string ename;
155157
std::string evalue;
156-
bool compilation_result = false;
158+
intptr_t output_value = 0;
159+
bool hadError = false;
157160

158161
// If silent is set to true, temporarily dismiss all std::cerr and
159162
// std::cout outputs resulting from `process_code`.
@@ -170,30 +173,36 @@ __get_cxx_version ()
170173

171174
std::string err;
172175

173-
// Attempt normal evaluation
174-
try
175-
{
176-
StreamRedirectRAII R(err);
177-
compilation_result = Cpp::Process(code.c_str());
178-
}
179-
catch (std::exception& e)
180-
{
181-
errorlevel = 1;
182-
ename = "Standard Exception: ";
183-
evalue = e.what();
184-
}
185-
catch (...)
186-
{
187-
errorlevel = 1;
188-
ename = "Error: ";
189-
}
176+
// Scope guard performing the temporary redirection of input requests.
177+
auto input_guard = input_redirection(config.allow_stdin);
190178

191-
if (compilation_result)
179+
for (const auto& block : blocks)
192180
{
193-
errorlevel = 1;
194-
ename = "Error: ";
195-
evalue = "Compilation error! " + err;
196-
std::cerr << err;
181+
// Attempt normal evaluation
182+
try
183+
{
184+
StreamRedirectRAII R(err);
185+
output_value = Cpp::Evaluate(block.c_str(), &hadError);
186+
}
187+
catch (std::exception& e)
188+
{
189+
errorlevel = 1;
190+
ename = "Standard Exception: ";
191+
evalue = e.what();
192+
}
193+
catch (...)
194+
{
195+
errorlevel = 1;
196+
ename = "Error: ";
197+
}
198+
199+
if (hadError)
200+
{
201+
errorlevel = 1;
202+
ename = "Error: ";
203+
evalue = "Compilation error! " + err;
204+
std::cerr << err;
205+
}
197206
}
198207

199208
// Flush streams
@@ -233,15 +242,13 @@ __get_cxx_version ()
233242
}
234243
else
235244
{
236-
/*
237-
// Publish a mime bundle for the last return value if
238-
// the semicolon was omitted.
239-
if (!config.silent && output.hasValue() && trim(code).back() != ';')
240-
{
241-
nl::json pub_data = mime_repr(output);
242-
publish_execution_result(execution_counter, std::move(pub_data), nl::json::object());
243-
}
244-
*/
245+
// Publish a mime bundle for the last return value if
246+
// the semicolon was omitted.
247+
if (!config.silent && output_value != 0 && trim(blocks.back()).back() != ';')
248+
{
249+
nl::json pub_data = mime_repr(output_value);
250+
publish_execution_result(execution_counter, std::move(pub_data), nl::json::object());
251+
}
245252
// Compose execute_reply message.
246253
kernel_res["status"] = "ok";
247254
kernel_res["payload"] = nl::json::array();

src/xmime_internal.hpp

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/************************************************************************************
2+
* Copyright (c) 2016, Johan Mabille, Loic Gouarin, Sylvain Corlay, Wolf Vollprecht *
3+
* Copyright (c) 2016, QuantStack *
4+
* *
5+
* Distributed under the terms of the BSD 3-Clause License. *
6+
* *
7+
* The full license is in the file LICENSE, distributed with this software. *
8+
************************************************************************************/
9+
10+
#ifndef XCPP_MIME_INTERNAL_HPP
11+
#define XCPP_MIME_INTERNAL_HPP
12+
13+
#include <cstddef>
14+
#include <locale>
15+
#include <string>
16+
17+
#include "clang/Interpreter/CppInterOp.h" // from CppInterOp package
18+
19+
#include <nlohmann/json.hpp>
20+
21+
namespace nl = nlohmann;
22+
23+
namespace xcpp
24+
{
25+
inline nl::json mime_repr(intptr_t V)
26+
{
27+
// Return a JSON mime bundle representing the specified value.
28+
void* value_ptr = reinterpret_cast<void*>(V);
29+
30+
// Include "xcpp/xmime.hpp" only on the first time a variable is displayed.
31+
static bool xmime_included = false;
32+
33+
if (!xmime_included)
34+
{
35+
Cpp::Declare("#include \"xcpp/xmime.hpp\"");
36+
xmime_included = true;
37+
}
38+
39+
intptr_t mimeReprV;
40+
bool hadError = false;
41+
{
42+
std::ostringstream code;
43+
code << "using xcpp::mime_bundle_repr;";
44+
code << "mime_bundle_repr(";
45+
// code << "*(" << getTypeAsString(V);
46+
code << &value_ptr;
47+
code << "));";
48+
49+
std::string codeString = code.str();
50+
51+
mimeReprV = Cpp::Evaluate(codeString.c_str(), &hadError);
52+
}
53+
54+
void* mimeReprV_ptr = reinterpret_cast<void*>(V);
55+
56+
if (!hadError && mimeReprV_ptr)
57+
{
58+
return *(nl::json*) mimeReprV_ptr;
59+
}
60+
else
61+
{
62+
return nl::json::object();
63+
}
64+
}
65+
}
66+
67+
#endif

src/xparser.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,80 @@ namespace xcpp
5454

5555
return result;
5656
}
57+
58+
std::vector<std::string> get_lines(const std::string& input)
59+
{
60+
std::vector<std::string> lines;
61+
std::regex re("\\n");
62+
63+
std::copy(
64+
std::sregex_token_iterator(input.begin(), input.end(), re, -1),
65+
std::sregex_token_iterator(),
66+
std::back_inserter(lines)
67+
);
68+
return lines;
69+
}
70+
71+
std::vector<std::string> split_from_includes(const std::string& input)
72+
{
73+
// this function split the input into part where we have only #include.
74+
75+
// split input into lines
76+
std::vector<std::string> lines = get_lines(input);
77+
78+
// check if each line contains #include and concatenate the result in the good part of the result
79+
std::regex incl_re("\\#include.*");
80+
std::regex magic_re("^\\%\\w+");
81+
std::vector<std::string> result;
82+
result.push_back("");
83+
std::size_t current = 0; // 0 include, 1 other
84+
std::size_t rindex = 0; // current index of result vector
85+
for (std::size_t i = 0; i < lines.size(); ++i)
86+
{
87+
if (!lines[i].empty())
88+
{
89+
if (std::regex_search(lines[i], magic_re))
90+
{
91+
result.push_back(lines[i] + "\n");
92+
result.push_back("");
93+
rindex += 2;
94+
}
95+
else
96+
{
97+
if (std::regex_match(lines[i], incl_re))
98+
{
99+
// if we have #include in this line
100+
// but the current item of result vector contains
101+
// other things
102+
if (current != 0)
103+
{
104+
current = 0;
105+
result.push_back("");
106+
rindex++;
107+
}
108+
}
109+
else
110+
{
111+
// if we don't have #include in this line
112+
// but the current item of result vector contains
113+
// the include parts
114+
if (current != 1)
115+
{
116+
current = 1;
117+
result.push_back("");
118+
rindex++;
119+
}
120+
}
121+
// if we have multiple lines, we add a semicolon at the end of the lines that not contain
122+
// #include keyword (except for the last line)
123+
result[rindex] += lines[i];
124+
if (i != lines.size() - 1)
125+
{
126+
result[rindex] += "\n";
127+
}
128+
}
129+
}
130+
}
131+
return result;
132+
}
57133
}

src/xparser.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,11 @@ namespace xcpp
2222

2323
XEUS_CPP_API std::vector<std::string>
2424
split_line(const std::string& input, const std::string& delims, std::size_t cursor_pos);
25+
26+
XEUS_CPP_API
27+
std::vector<std::string> get_lines(const std::string& input);
28+
29+
XEUS_CPP_API
30+
std::vector<std::string> split_from_includes(const std::string& input);
2531
}
2632
#endif

0 commit comments

Comments
 (0)