Skip to content

Commit b0ed2c4

Browse files
committed
Implemented lexer for is_complete_request
1 parent c90867a commit b0ed2c4

6 files changed

Lines changed: 629 additions & 13 deletions

File tree

CMakeLists.txt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,20 +184,26 @@ set(XEUS_CPP_HEADERS
184184
include/xeus-cpp/xmanager.hpp
185185
include/xeus-cpp/xmagics.hpp
186186
include/xeus-cpp/xpreamble.hpp
187-
#src/xinspect.hpp
188-
#src/xsystem.hpp
189-
#src/xparser.hpp
190187
)
191188

192189
set(XEUS_CPP_SRC
193190
src/xholder.cpp
194191
src/xinput.cpp
192+
src/xinput.hpp
193+
src/xinput_validator.cpp
194+
src/xinput_validator.hpp
195195
src/xinspect.cpp
196+
src/xinspect.hpp
196197
src/xinterpreter.cpp
198+
src/xlexer.cpp
199+
src/xlexer.hpp
197200
src/xoptions.cpp
198201
src/xparser.cpp
202+
src/xparser.hpp
203+
src/xsystem.hpp
199204
src/xutils.cpp
200205
src/xmagics/os.cpp
206+
src/xmagics/os.hpp
201207
)
202208

203209
if(NOT EMSCRIPTEN)

src/xinput_validator.cpp

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/************************************************************************************
2+
* Copyright (c) 2023, xeus-cpp contributors *
3+
* Copyright (c) 2023, Johan Mabille, Loic Gouarin, Sylvain Corlay, Wolf Vollprecht *
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+
#include "xinput_validator.hpp"
11+
#include "xlexer.hpp"
12+
13+
namespace xcpp
14+
{
15+
std::string to_string(validation_result res)
16+
{
17+
if (res == validation_result::incomplete)
18+
{
19+
return "incomplete";
20+
}
21+
else if (res == validation_result::complete)
22+
{
23+
return "complete";
24+
}
25+
else
26+
{
27+
return "mismatch";
28+
}
29+
}
30+
31+
validation_result xinput_validator::validate(const std::string& input)
32+
{
33+
auto res = validation_result::complete;
34+
35+
// Only check for 'template' if we're not already indented
36+
if (m_parent_stack.empty())
37+
{
38+
xlexer luthor(input.data(), true);
39+
auto tok = luthor.lex();
40+
if (tok.kind() == token_kind::ident && tok.identifier() == "template")
41+
{
42+
m_parent_stack.push_back(as_int(token_kind::less));
43+
}
44+
}
45+
46+
xlexer luthor(input.data(), true);
47+
token tok, last_not_space_tok;
48+
49+
do
50+
{
51+
if (tok.kind() != token_kind::space)
52+
{
53+
last_not_space_tok = tok;
54+
}
55+
tok = luthor.lex();
56+
57+
if (in_block_comment() && tok.kind() != token_kind::r_comment)
58+
{
59+
continue;
60+
}
61+
62+
switch(tok.kind())
63+
{
64+
case token_kind::comment:
65+
tok = luthor.read_to_end_of_line();
66+
break;
67+
case token_kind::r_comment:
68+
if (in_block_comment())
69+
{
70+
m_parent_stack.pop_back();
71+
}
72+
else
73+
{
74+
res = validation_result::mismatch;
75+
}
76+
break;
77+
case token_kind::l_square:
78+
case token_kind::l_paren:
79+
case token_kind::l_brace:
80+
case token_kind::l_comment:
81+
m_parent_stack.push_back(as_int(tok.kind()));
82+
break;
83+
case token_kind::r_square:
84+
case token_kind::r_paren:
85+
case token_kind::r_brace:
86+
{
87+
auto tos =
88+
m_parent_stack.empty() ?
89+
token_kind::unknown :
90+
static_cast<token_kind>(m_parent_stack.back());
91+
if (!tok.closes_brace(tos))
92+
{
93+
res = validation_result::mismatch;
94+
break;
95+
}
96+
m_parent_stack.pop_back();
97+
// '}' will also pop a template '<' if their is one
98+
if (tok.kind() == token_kind::r_brace && in_template())
99+
{
100+
m_parent_stack.pop_back();
101+
}
102+
break;
103+
}
104+
case token_kind::semicolon:
105+
// Template forward declatation, i.e. 'template' '<' ... '>' ... ';'
106+
if (in_template())
107+
{
108+
m_parent_stack.pop_back();
109+
}
110+
break;
111+
case token_kind::hash:
112+
luthor.skip_whitespace();
113+
tok = luthor.lex_any_string();
114+
if (tok.kind() != token_kind::eof)
115+
{
116+
auto pptk = tok.identifier();
117+
if (pptk.substr(0u, 2u) == "if")
118+
{
119+
m_parent_stack.push_back(as_int(token_kind::hash));
120+
}
121+
else if (pptk.substr(0u, 5u) == "endif" &&
122+
(pptk.size() == 5u || pptk[5u] == '/' || std::isspace(pptk[5u])))
123+
{
124+
if (m_parent_stack.empty() || m_parent_stack.back() != as_int(token_kind::hash))
125+
{
126+
res = validation_result::mismatch;
127+
}
128+
else
129+
{
130+
m_parent_stack.pop_back();
131+
}
132+
}
133+
}
134+
break;
135+
default:
136+
break;
137+
}
138+
}
139+
while (tok.kind() != token_kind::eof && res != validation_result::mismatch);
140+
141+
const auto last_kind = last_not_space_tok.kind();
142+
const bool cont = (last_kind == token_kind::backslash || last_kind == token_kind::comma);
143+
144+
if (cont || (!m_parent_stack.empty() && res != validation_result::mismatch))
145+
{
146+
res = validation_result::incomplete;
147+
}
148+
149+
return res;
150+
}
151+
152+
bool xinput_validator::in_block_comment() const
153+
{
154+
return !m_parent_stack.empty() && m_parent_stack.back() == as_int(token_kind::l_comment);
155+
}
156+
157+
bool xinput_validator::in_template() const
158+
{
159+
return m_parent_stack.size() == 1u && m_parent_stack.back() == as_int(token_kind::less);
160+
}
161+
}

src/xinput_validator.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/************************************************************************************
2+
* Copyright (c) 2025, xeus-cpp contributors *
3+
* *
4+
* Distributed under the terms of the BSD 3-Clause License. *
5+
* *
6+
* The full license is in the file LICENSE, distributed with this software. *
7+
************************************************************************************/
8+
9+
#ifndef XEUS_CPP_INPUT_VALIDATOR_HPP
10+
#define XEUS_CPP_INPUT_VALIDATOR_HPP
11+
12+
#include <deque>
13+
#include <string>
14+
15+
namespace xcpp
16+
{
17+
enum class validation_result
18+
{
19+
incomplete,
20+
complete,
21+
mismatch
22+
};
23+
24+
std::string to_string(validation_result res);
25+
26+
class xinput_validator
27+
{
28+
public:
29+
30+
validation_result validate(const std::string& input);
31+
32+
private:
33+
34+
bool in_block_comment() const;
35+
bool in_template() const;
36+
37+
std::deque<int> m_parent_stack;
38+
};
39+
}
40+
41+
#endif

src/xinterpreter.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "xeus-cpp/xmagics.hpp"
1919

2020
#include "xinput.hpp"
21+
#include "xinput_validator.hpp"
2122
#include "xinspect.hpp"
2223
#include "xmagics/os.hpp"
2324
#include <algorithm>
@@ -413,16 +414,9 @@ namespace xcpp
413414

414415
nl::json interpreter::is_complete_request_impl(const std::string& code)
415416
{
416-
if (!code.empty() && code[code.size() - 1] == '\\') {
417-
auto found = code.rfind('\n');
418-
if (found == std::string::npos)
419-
found = -1;
420-
auto found1 = found++;
421-
while (isspace(code[++found1])) ;
422-
return xeus::create_is_complete_reply("incomplete", code.substr(found, found1-found));
423-
}
424-
425-
return xeus::create_is_complete_reply("complete");
417+
xinput_validator v;
418+
std::string res = to_string(v.validate(code));
419+
return xeus::create_is_complete_reply(res);
426420
}
427421

428422
nl::json interpreter::kernel_info_request_impl()

0 commit comments

Comments
 (0)