16 std::cout << string(2 * level,
' ') << s <<
'\n';
19 static constexpr std::string_view type2string(
int type)
24 case TCL_TOKEN_SIMPLE_WORD:
26 case TCL_TOKEN_EXPAND_WORD:
32 case TCL_TOKEN_COMMAND:
34 case TCL_TOKEN_VARIABLE:
36 case TCL_TOKEN_SUB_EXPR:
38 case TCL_TOKEN_OPERATOR:
47 static constexpr
bool inRange(
char c,
char low,
char high)
50 return t <= unsigned(high - low);
53 static bool isNumber(std::string_view str)
61 return inRange(c,
'0',
'9') ||
62 inRange(c,
'a',
'f') ||
67 [](
char c) {
return inRange(c,
'0',
'9'); });
74 , colors(input.
size(),
'.')
81 parse(parseStr.data(),
int(parseStr.size()), COMMAND);
84 void TclParser::parse(
const char* p,
int size, ParseType type)
88 last.push_back(offset);
98 int parseStatus = (type == EXPRESSION)
99 ? Tcl_ParseExpr(interp, parseStr.data(), int(parseStr.size()), &parseInfo)
100 : Tcl_ParseCommand(interp, parseStr.data(), int(parseStr.size()), 1, &parseInfo);
101 if (parseStatus == TCL_OK)
break;
102 Tcl_FreeParse(&parseInfo);
105 bool allowComplete = ((offset + parseStr.size()) >= colors.size()) &&
107 Tcl_Obj* resObj = Tcl_GetObjResult(interp);
109 const char* resStr = Tcl_GetStringFromObj(resObj, &resLen);
110 std::string_view error(resStr, resLen);
131 setColors(parseStr.data(),
int(parseStr.size()),
'E');
132 if ((offset +
size) <
int(colors.size())) last.pop_back();
137 if (type == EXPRESSION) {
140 if (parseInfo.commentSize) {
141 DEBUG_PRINT(
"COMMENT: " + std::string_view(parseInfo.commentStart, parseInfo.commentSize));
142 setColors(parseInfo.commentStart, parseInfo.commentSize,
'c');
144 DEBUG_PRINT(
"COMMAND: " + std::string_view(parseInfo.commandStart, parseInfo.commandSize));
146 printTokens(parseInfo.tokenPtr, parseInfo.numTokens);
151 if ((offset +
size) <
int(colors.size())) last.pop_back();
153 const char* nextStart = parseInfo.commandStart + parseInfo.commandSize;
154 Tcl_FreeParse(&parseInfo);
156 if (type == COMMAND) {
158 int nextSize = int((parseStr.data() + parseStr.size()) - nextStart);
160 parse(nextStart, nextSize, type);
165 void TclParser::printTokens(Tcl_Token* tokens,
int numTokens)
170 for (
int i = 0; i < numTokens; ) {
171 Tcl_Token& token = tokens[i];
172 std::string_view tokenStr(token.start, token.size);
173 DEBUG_PRINT(type2string(token.type) +
" -> " + tokenStr);
174 switch (token.type) {
175 case TCL_TOKEN_VARIABLE:
176 assert(token.numComponents >= 1);
177 setColors(tokens[i + 1].start - 1, tokens[i + 1].
size + 1,
'v');
180 case TCL_TOKEN_SIMPLE_WORD:
181 if (*token.start ==
'"') {
182 setColors(token.start, token.size,
'l');
184 if ((i == 0) &&
isProc(interp, tokenStr)) {
185 setColors(token.start, token.size,
'p');
188 case TCL_TOKEN_EXPAND_WORD:
189 setColors(token.start, 3,
'o');
191 case TCL_TOKEN_OPERATOR:
193 setColors(token.start, token.size,
'o');
196 if (isNumber(tokenStr) || (*token.start ==
'"')) {
198 setColors(token.start, token.size,
'l');
202 if (token.type == TCL_TOKEN_COMMAND) {
203 parse(token.start + 1, token.size - 2, COMMAND);
204 }
else if (token.type == TCL_TOKEN_SIMPLE_WORD) {
205 ParseType subType = guessSubType(tokens, i);
206 if (subType != OTHER) {
207 parse(tokens[i + 1].start, tokens[i + 1].
size, subType);
210 printTokens(&tokens[++i], token.numComponents);
211 i += token.numComponents;
215 TclParser::ParseType TclParser::guessSubType(Tcl_Token* tokens,
int i)
218 if ((i >= 1) && (tokens[i - 1].type == TCL_TOKEN_TEXT)) {
219 std::string_view prevText(tokens[i - 1].start, tokens[i - 1].
size);
220 if (prevText ==
one_of(
"if",
"elseif",
"expr")) {
226 if (*tokens[i].start ==
'{') {
236 auto command =
tmpStrCat(
"openmsx::is_command_name {", str,
'}');
237 if (Tcl_Eval(interp, command.c_str()) != TCL_OK)
return false;
239 if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp), &result)
240 != TCL_OK)
return false;
244 void TclParser::setColors(
const char* p,
int size,
char c)
246 int start = (p - parseStr.data()) + offset;
248 for (
auto i :
xrange(start, stop)) {
Assign new value to some variable and restore the original value when this object goes out of scope.
TclParser(Tcl_Interp *interp, std::string_view input)
Input: Tcl interpreter and command to parse
static bool isProc(Tcl_Interp *interp, std::string_view str)
Is the given string a valid Tcl command.
bool startsWith(string_view total, string_view part)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
bool all_of(InputRange &&range, UnaryPredicate pred)
size_t size(std::string_view utf8)
TemporaryString tmpStrCat(Ts &&... ts)
constexpr auto xrange(T e)