48#include "selection/SelectionCompiler.hpp"
57 bool SelectionCompiler::compile(
const std::string& filename,
58 const std::string& script) {
59 this->filename = filename;
60 this->script = script;
63 aatokenCompiled.clear();
65 if (internalCompile()) {
return true; }
68 if ((icharEnd = script.find(
'\r', ichCurrentCommand)) ==
70 (icharEnd = script.find(
'\n', ichCurrentCommand)) ==
72 icharEnd = script.size();
74 errorLine = script.substr(ichCurrentCommand, icharEnd);
78 bool SelectionCompiler::internalCompile() {
79 cchScript = script.size();
86 aatokenCompiled.clear();
87 std::vector<Token> ltoken;
90 int tokCommand = Token::nada;
92 for (;
true; ichToken += cchToken) {
93 if (lookingAtLeadingWhitespace())
continue;
96 bool endOfLine = lookingAtEndOfLine();
97 if (endOfLine || lookingAtEndOfStatement()) {
98 if (tokCommand != Token::nada) {
99 if (!compileCommand(ltoken)) {
return false; }
100 aatokenCompiled.push_back(atokenCommand);
101 lineNumbers.push_back(lineCurrent);
102 lineIndices.push_back(ichCurrentCommand);
104 tokCommand = Token::nada;
107 if (ichToken < cchScript) {
108 if (endOfLine) ++lineCurrent;
114 if (tokCommand != Token::nada) {
115 if (lookingAtString()) {
116 std::string str = getUnescapedStringLiteral();
117 ltoken.push_back(Token(Token::string, str));
127 if (lookingAtDecimal((tokCommand) != 0)) {
128 float value = lexi_cast<float>(script.substr(ichToken, cchToken));
129 ltoken.push_back(Token(Token::decimal, std::any(value)));
133 if (lookingAtInteger((tokCommand) != 0)) {
134 int val = lexi_cast<int>(script.substr(ichToken, cchToken));
135 ltoken.push_back(Token(Token::integer, std::any(val)));
140 if (lookingAtLookupToken()) {
141 std::string ident = script.substr(ichToken, cchToken);
143 Token* pToken = TokenMap::getInstance().getToken(ident);
144 if (pToken != NULL) {
147 token = Token(Token::identifier, ident);
152 switch (tokCommand) {
154 ichCurrentCommand = ichToken;
157 if ((tokCommand & Token::command) == 0)
return commandExpected();
161 if (ltoken.size() == 1) {
163 if (tok != Token::identifier &&
164 (tok & Token::predefinedset) != Token::predefinedset)
165 return invalidExpressionToken(ident);
168 if (tok != Token::identifier &&
169 (tok & (Token::expression | Token::predefinedset)) == 0)
170 return invalidExpressionToken(ident);
176 if (tok != Token::identifier && (tok & Token::expression) == 0)
177 return invalidExpressionToken(ident);
180 ltoken.push_back(token);
184 if (ltoken.empty()) {
return commandExpected(); }
186 return unrecognizedToken();
192 bool SelectionCompiler::lookingAtLeadingWhitespace() {
194 while (ichT < cchScript && std::isspace(script[ichT])) {
197 cchToken = ichT - ichToken;
201 bool SelectionCompiler::lookingAtEndOfLine() {
202 if (ichToken == cchScript)
return true;
204 char ch = script[ichT];
207 if (ichT < cchScript && script[ichT] ==
'\n') ++ichT;
208 }
else if (ch ==
'\n') {
213 cchToken = ichT - ichToken;
217 bool SelectionCompiler::lookingAtEndOfStatement() {
218 if (ichToken == cchScript || script[ichToken] !=
';')
return false;
223 bool SelectionCompiler::lookingAtString() {
224 if (ichToken == cchScript)
return false;
225 if (script[ichToken] !=
'"')
return false;
231 int ichT = ichToken + 1;
234 bool previousCharBackslash =
false;
235 while (ichT < cchScript) {
237 if (ch ==
'"' && !previousCharBackslash)
break;
238 previousCharBackslash = ch ==
'\\' ? !previousCharBackslash :
false;
240 cchToken = ichT - ichToken;
245 std::string SelectionCompiler::getUnescapedStringLiteral() {
247 std::string sb(cchToken - 2,
' ');
249 int ichMax = ichToken + cchToken - 1;
250 int ich = ichToken + 1;
252 while (ich < ichMax) {
253 char ch = script[ich++];
254 if (ch ==
'\\' && ich < ichMax) {
275 int digitCount = ch ==
'x' ? 2 : 4;
278 for (
int k = digitCount; --k >= 0 && ich < ichMax;) {
279 char chT = script[ich];
280 int hexit = getHexitValue(chT);
281 if (hexit < 0)
break;
296 int SelectionCompiler::getHexitValue(
char ch) {
297 if (ch >=
'0' && ch <=
'9')
299 else if (ch >=
'a' && ch <=
'f')
300 return 10 + ch -
'a';
301 else if (ch >=
'A' && ch <=
'F')
302 return 10 + ch -
'A';
307 bool SelectionCompiler::lookingAtSpecialString() {
309 char ch = script[ichT];
310 while (ichT < cchScript && ch !=
';' && ch !=
'\r' && ch !=
'\n') {
313 cchToken = ichT - ichToken;
317 bool SelectionCompiler::lookingAtDecimal(
bool) {
318 if (ichToken == cchScript) {
return false; }
321 if (script[ichT] ==
'-') { ++ichT; }
322 bool digitSeen =
false;
324 while (ichT < cchScript && std::isdigit(ch = script[ichT])) {
329 if (ichT == cchScript || ch !=
'.') {
return false; }
332 if (ch ==
'.' && (ichT > 0) && std::isalpha(script[ichT - 1])) {
337 while (ichT < cchScript && std::isdigit(script[ichT])) {
341 cchToken = ichT - ichToken;
345 bool SelectionCompiler::lookingAtInteger(
bool allowNegative) {
346 if (ichToken == cchScript) {
return false; }
348 if (allowNegative && script[ichToken] ==
'-') { ++ichT; }
349 int ichBeginDigits = ichT;
350 while (ichT < cchScript && std::isdigit(script[ichT])) {
353 if (ichBeginDigits == ichT) {
return false; }
354 cchToken = ichT - ichToken;
355 return isInteger(script.substr(ichToken, cchToken).c_str());
358 bool SelectionCompiler::lookingAtLookupToken() {
359 if (ichToken == cchScript) {
return false; }
363 switch (ch = script[ichT++]) {
372 if (ichT < cchScript && script[ichT] == ch) { ++ichT; }
377 if (ichT < cchScript &&
378 ((ch = script[ichT]) ==
'<' || ch ==
'=' || ch ==
'>')) {
384 if (ichT < cchScript && script[ichT] ==
'=') { ++ichT; }
387 if ((ch <
'a' || ch >
'z') && (ch <
'A' && ch >
'Z') && ch !=
'_') {
393 while (ichT < cchScript && !std::isspace(ch = script[ichT]) &&
394 (std::isalpha(ch) || std::isdigit(ch) || ch ==
'_' || ch ==
'.' ||
395 ch ==
'*' || ch ==
'?' || ch ==
'+' || ch ==
'-' || ch ==
'[' ||
402 cchToken = ichT - ichToken;
407 bool SelectionCompiler::compileCommand(
const std::vector<Token>& ltoken) {
408 const Token& tokenCommand = ltoken[0];
409 int tokCommand = tokenCommand.tok;
411 atokenCommand = ltoken;
412 if ((tokCommand & Token::expressionCommand) != 0 && !compileExpression()) {
419 bool SelectionCompiler::compileExpression() {
422 int tokCommand = atokenCommand[0].tok;
423 if (tokCommand == Token::define) {
425 }
else if ((tokCommand & Token::embeddedExpression) != 0) {
427 while (i < atokenCommand.size() &&
428 atokenCommand[i].tok != Token::leftparen)
432 if (i >= atokenCommand.size()) {
return true; }
433 return compileExpression(i);
436 bool SelectionCompiler::addTokenToPostfix(
const Token& token) {
437 ltokenPostfix.push_back(token);
441 bool SelectionCompiler::compileExpression(
int itoken) {
442 ltokenPostfix.clear();
443 for (
int i = 0; i < itoken; ++i) {
444 addTokenToPostfix(atokenCommand[i]);
447 atokenInfix = atokenCommand;
448 itokenInfix = itoken;
450 addTokenToPostfix(Token::tokenExpressionBegin);
451 if (!clauseOr()) {
return false; }
453 addTokenToPostfix(Token::tokenExpressionEnd);
454 if (itokenInfix != atokenInfix.size()) {
return endOfExpressionExpected(); }
456 atokenCommand = ltokenPostfix;
460 Token SelectionCompiler::tokenNext() {
461 if (itokenInfix == atokenInfix.size()) {
return Token(); }
462 return atokenInfix[itokenInfix++];
465 std::any SelectionCompiler::valuePeek() {
466 if (itokenInfix == atokenInfix.size()) {
469 return atokenInfix[itokenInfix].value;
473 int SelectionCompiler::tokPeek() {
474 if (itokenInfix == atokenInfix.size()) {
477 return atokenInfix[itokenInfix].tok;
481 bool SelectionCompiler::clauseOr() {
482 if (!clauseAnd()) {
return false; }
484 while (tokPeek() == Token::opOr) {
485 Token tokenOr = tokenNext();
486 if (!clauseAnd()) {
return false; }
487 addTokenToPostfix(tokenOr);
492 bool SelectionCompiler::clauseAnd() {
493 if (!clauseNot()) {
return false; }
495 while (tokPeek() == Token::opAnd) {
496 Token tokenAnd = tokenNext();
497 if (!clauseNot()) {
return false; }
498 addTokenToPostfix(tokenAnd);
503 bool SelectionCompiler::clauseNot() {
504 if (tokPeek() == Token::opNot) {
505 Token tokenNot = tokenNext();
506 if (!clauseNot()) {
return false; }
507 return addTokenToPostfix(tokenNot);
509 return clausePrimitive();
512 bool SelectionCompiler::clausePrimitive() {
516 return clauseWithin();
518 case Token::alphahull:
519 return clauseAlphaHull();
521 case Token::asterisk:
522 case Token::identifier:
523 return clauseChemObjName();
526 return clauseIndex();
528 if ((tok & Token::atomproperty) == Token::atomproperty) {
529 return clauseComparator();
531 if ((tok & Token::predefinedset) != Token::predefinedset) {
break; }
537 return addTokenToPostfix(tokenNext());
538 case Token::leftparen:
540 if (!clauseOr()) {
return false; }
541 if (tokenNext().tok != Token::rightparen) {
542 return rightParenthesisExpected();
546 return unrecognizedExpressionToken();
549 bool SelectionCompiler::clauseComparator() {
550 Token tokenAtomProperty = tokenNext();
551 Token tokenComparator = tokenNext();
552 if ((tokenComparator.tok & Token::comparator) == 0) {
553 return comparisonOperatorExpected();
556 Token tokenValue = tokenNext();
557 if (tokenValue.tok != Token::integer && tokenValue.tok != Token::decimal) {
558 return numberExpected();
562 if (tokenValue.value.type() ==
typeid(
int)) {
563 val = std::any_cast<int>(tokenValue.value);
564 }
else if (tokenValue.value.type() ==
typeid(
float)) {
565 val = std::any_cast<float>(tokenValue.value);
572 return addTokenToPostfix(
573 Token(tokenComparator.tok, tokenAtomProperty.tok, floatVal));
576 bool SelectionCompiler::clauseWithin() {
578 if (tokenNext().tok != Token::leftparen) {
579 return leftParenthesisExpected();
583 Token tokenDistance = tokenNext();
584 switch (tokenDistance.tok) {
590 return numberOrKeywordExpected();
593 if (tokenNext().tok != Token::opOr) {
594 return commaExpected();
601 if (tokenNext().tok != Token::rightparen) {
602 return rightParenthesisExpected();
605 return addTokenToPostfix(Token(Token::within,
distance));
608 bool SelectionCompiler::clauseAlphaHull() {
610 if (tokenNext().tok != Token::leftparen) {
611 return leftParenthesisExpected();
615 Token tokenAlpha = tokenNext();
616 switch (tokenAlpha.tok) {
619 alpha = tokenAlpha.value;
622 return numberOrKeywordExpected();
625 if (tokenNext().tok != Token::rightparen) {
626 return rightParenthesisExpected();
629 return addTokenToPostfix(Token(Token::alphahull, alpha));
632 bool SelectionCompiler::clauseChemObjName() {
633 Token token = tokenNext();
634 if (token.tok == Token::identifier &&
635 token.value.type() ==
typeid(std::string)) {
636 std::string name = std::any_cast<std::string>(token.value);
637 if (isNameValid(name)) {
638 return addTokenToPostfix(Token(Token::name, name));
640 return compileError(
"invalid name: " + name);
647 bool SelectionCompiler::isNameValid(
const std::string& name) {
650 for (
unsigned int i = 0; i < name.size(); ++i) {
665 return (ndot <= 3 && nbracket == 0) ? true :
false;
668 bool SelectionCompiler::clauseIndex() {
669 Token token = tokenNext();
670 if (token.tok == Token::integer) {
671 int index = std::any_cast<int>(token.value);
673 if (tok == Token::to) {
676 if (tok != Token::integer) {
return numberExpected(); }
678 std::any intVal = tokenNext().value;
680 if (intVal.type() !=
typeid(
int)) {
return false; }
681 int second = std::any_cast<int>(intVal);
683 return addTokenToPostfix(
684 Token(Token::index, std::any(std::make_pair(first, second))));
687 return addTokenToPostfix(Token(Token::index, std::any(index)));
690 return numberExpected();
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Real distance(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the distance between two DynamicVectors.