LCOV - code coverage report
Current view: top level - extra/webserver/pug - SPPugExpression.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 442 485 91.1 %
Date: 2024-05-12 00:16:13 Functions: 43 43 100.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "SPPugExpression.h"
      24             : 
      25             : namespace STAPPLER_VERSIONIZED stappler::pug {
      26             : 
      27        7600 : inline void Lexer_parseBufferString(StringView &r, const Lexer::OutStream &stream) {
      28             : #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      29             :         static const char escape[256] = {
      30             :                 Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, '\'', 0, 0, 0, 0, 0, 0, 0,'/',
      31             :                 Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
      32             :                 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
      33             :                 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      34             :                 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
      35             :         };
      36             : #undef Z16
      37        7600 :         char quot = 0;
      38        7600 :         if (r.is('"')) { r ++; quot = '"'; }
      39        7600 :         if (r.is('\'')) { r ++; quot = '\''; }
      40             : 
      41        7600 :         if (quot) {
      42             :                 do {
      43        7650 :                         auto s = (quot == '"') ? r.readUntil<StringView::Chars<'"', '\\'>>() : r.readUntil<StringView::Chars<'\'', '\\'>>();
      44        7650 :                         stream << s;
      45        7650 :                         if (r.is('\\')) {
      46          75 :                                 ++ r;
      47          75 :                                 if (r.is('u') && r.size() >= 5) {
      48          25 :                                         ++ r;
      49           0 :                                         unicode::utf8EncodeCb([&] (char c) {
      50          25 :                                                 stream << c;
      51          25 :                                         }, char16_t(base16::hexToChar(r[0], r[1]) << 8 | base16::hexToChar(r[2], r[3]) ));
      52          25 :                                         r += 4;
      53             :                                 } else {
      54          50 :                                         auto tmp = escape[(uint8_t)r[0]];
      55          50 :                                         if (tmp) {
      56          50 :                                                 stream << tmp;
      57             :                                         } else {
      58           0 :                                                 stream << r[0];
      59             :                                         }
      60          50 :                                         ++ r;
      61             :                                 }
      62             :                         }
      63        7650 :                 } while (!r.empty() && !r.is(quot));
      64        7600 :                 if (r.is(quot)) { ++ r; }
      65             :         } else {
      66           0 :                 stream << r.readChars<StringView::CharGroup<CharGroupId::Alphanumeric>, StringView::Chars<'_'>>();
      67             :         }
      68        7600 : }
      69             : 
      70       45300 : static uint8_t Lexer_Expression_priority(Expression::Op o) {
      71             :         static const uint8_t p_arr[] = {
      72             :                 0, 1, // NoOp, Var
      73             :                 1, 1, // ++ --
      74             :                 1, 1, 1, 1, 1, 1, // # . : () [] {}
      75             :                 2, 2, // ++ --
      76             :                 2, 2, 2, // - not ~
      77             :                 3, 3, 3, // * / %
      78             :                 4, 4, // + -
      79             :                 5, 5, // << >>
      80             :                 6, 6, 6, 6, // < <= > >=
      81             :                 7, 7, // == !=
      82             :                 8, 9, 10, // & ^ |
      83             :                 11, 12, // and or
      84             :                 13, 14,  // ?:
      85             :                 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // = += -= *= /= %= <<= >>= &= ^= |=
      86             :                 16, 17, 18 // ?: : , ;
      87             :         };
      88       45300 :         return p_arr[toInt(o)];
      89             : }
      90             : 
      91       14925 : static bool Lexer_Expression_associativity(Expression::Op o) { // false for Left-to-right, true for Right-to-left
      92             :         static const bool p_arr[] = {
      93             :                 false, false, // NoOp, Var    Left-to-right
      94             :                 false, false, // ++ --
      95             :                 false, false, false, false, false, false, // # . :: () [] {}    Left-to-right
      96             :                 true, true, // ++ --
      97             :                 true, true, true, // - not ~   Right-to-left
      98             :                 false, false, false, // * / %   Left-to-right
      99             :                 false, false, // + -    Left-to-right
     100             :                 false, false, // << >>  Left-to-right
     101             :                 false, false, false, false, // < <= > >=    Left-to-right
     102             :                 false, false, // == !=   Left-to-right
     103             :                 false, false, false, // & ^ |    Left-to-right
     104             :                 false, false, // and or
     105             :                 true, true, // ?:
     106             :                 true, true, true, true, true, true, true, true, true, true, true, // = Right-to-left
     107             :                 false, false, false // , ; Left-to-right
     108             :         };
     109       14925 :         return p_arr[toInt(o)];
     110             : }
     111             : 
     112             : 
     113          25 : Expression::Expression() : op(NoOp) { new (&value) Value(); }
     114       30750 : Expression::Expression(Op op) : op (op) { new (&value) Value(); }
     115       14925 : Expression::Expression(Op op, Expression *l, Expression *r) : op(op), left(l), right(r) { new (&value) Value(); }
     116          25 : Expression::Expression(Op op, Expression *l, Expression *r, const StringView & t) : op(op), left(l), right(r) {
     117          25 :         isToken = true;
     118          25 :         value.setString(t);
     119          25 : }
     120          25 : Expression::Expression(Op op, Expression *l, Expression *r, Value && d) : op(op), left(l), right(r), value(move(d)) { }
     121             : 
     122          75 : Expression::~Expression() { }
     123             : 
     124       10950 : void Expression::set(Value && d) {
     125       10950 :         isToken = false;
     126       10950 :         value = std::move(d);
     127       10950 : }
     128       17775 : void Expression::set(const StringView & t) {
     129       17775 :         isToken = true;
     130       17775 :         value.setString(t);
     131       17775 : }
     132             : 
     133          75 : bool Expression::empty() const {
     134          75 :         return value.empty();
     135             : }
     136             : 
     137       11900 : static bool Expression_isConst(const Expression &expr, Expression::Op op) {
     138       11900 :         if (expr.op == Expression::Call) {
     139         300 :                 return false;
     140             :         }
     141       11600 :         if (expr.left && expr.right) {
     142        3800 :                 return Expression_isConst(*expr.left, expr.op) && Expression_isConst(*expr.right, Expression::NoOp);
     143        7800 :         } else if (expr.left) {
     144         125 :                 return Expression_isConst(*expr.left, Expression::NoOp);
     145             :         } else {
     146        7675 :                 return !expr.isToken || op == Expression::Colon;
     147             :         }
     148             : }
     149             : 
     150        7075 : bool Expression::isConst() const {
     151        7075 :         return Expression_isConst(*this, NoOp);
     152             : }
     153             : 
     154             : static bool Lexer_readExpression(Expression **node, StringView &r, const Expression::Options &opts, bool isRoot);
     155             : static bool Lexer_Expression_readOperand(Expression **node, StringView &r, Expression::Op op, const Expression::Options &opts);
     156             : static bool Lexer_Expression_readOperandValue(Expression *current, StringView &r, Expression::Op op, const Expression::Options &opts);
     157             : 
     158       28000 : static Expression::Op Lexer_Expression_readOperator(StringView &r, char brace, const Expression::Options &opts) {
     159       14800 :         auto checkOperator = [&] (Expression::Op op) {
     160       14800 :                 return opts.hasOperator(op) ? op : Expression::NoOp;
     161       28000 :         };
     162             : 
     163       28000 :         if (r.is("+=")) { r += 2; return checkOperator(Expression::SumAssignment); }
     164       27825 :         else if (r.is("-=")) { r += 2; return checkOperator(Expression::DiffAssignment); }
     165       27750 :         else if (r.is("*=")) { r += 2; return checkOperator(Expression::MultAssignment); }
     166       27675 :         else if (r.is("/=")) { r += 2; return checkOperator(Expression::DivAssignment); }
     167       27600 :         else if (r.is("%=")) { r += 2; return checkOperator(Expression::RemAssignment); }
     168       27525 :         else if (r.is("<<=")) { r += 3; return checkOperator(Expression::LShiftAssignment); }
     169       27450 :         else if (r.is(">>=")) { r += 3; return checkOperator(Expression::RShiftAssignment); }
     170       27375 :         else if (r.is("&=")) { r += 2; return checkOperator(Expression::AndAssignment); }
     171       27300 :         else if (r.is("^=")) { r += 2; return checkOperator(Expression::XorAssignment); }
     172       27225 :         else if (r.is("|=")) { r += 2; return checkOperator(Expression::OrAssignment); }
     173       27150 :         else if (r.is("&&")) { r += 2; return checkOperator(Expression::And); }
     174       26975 :         else if (r.is("||")) { r += 2; return checkOperator(Expression::Or); }
     175       26800 :         else if (r.is("++")) { r += 2; return checkOperator(Expression::SuffixIncr); }
     176       26675 :         else if (r.is("--")) { r += 2; return checkOperator(Expression::SuffixDecr); }
     177       26550 :         else if (r.is("<<")) { r += 2; return checkOperator(Expression::ShiftLeft); }
     178       26475 :         else if (r.is(">>")) { r += 2; return checkOperator(Expression::ShiftRight); }
     179       26400 :         else if (r.is("<=")) { r += 2; return checkOperator(Expression::LtEq); }
     180       26175 :         else if (r.is(">=")) { r += 2; return checkOperator(Expression::GtEq); }
     181       25950 :         else if (r.is("==")) { r += 2; return checkOperator(Expression::Eq); }
     182       25825 :         else if (r.is("!=")) { r += 2; return checkOperator(Expression::NotEq); }
     183       25700 :         else if (r.is("::")) { r += 2; return checkOperator(Expression::Scope); }
     184       25650 :         else if (r.is('=')) { ++ r; return checkOperator(Expression::Assignment); }
     185       23000 :         else if (r.is('#')) { ++ r; return checkOperator(Expression::Sharp); }
     186       22975 :         else if (r.is('.')) { ++ r; return checkOperator(Expression::Dot); }
     187       20300 :         else if (r.is('?')) { return checkOperator(Expression::Conditional); }
     188       20175 :         else if (r.is('(')) { return checkOperator(Expression::Call); }
     189       19600 :         else if (r.is('[')) { return checkOperator(Expression::Subscript); }
     190       19325 :         else if (r.is('{')) { return checkOperator(Expression::Construct); }
     191       19300 :         else if (r.is('*')) { ++ r; return checkOperator(Expression::Mult); }
     192       19200 :         else if (r.is('/')) { ++ r; return checkOperator(Expression::Div); }
     193       19125 :         else if (r.is('%')) { ++ r; return checkOperator(Expression::Rem); }
     194       19025 :         else if (r.is('+')) { ++ r; return checkOperator(Expression::Sum); }
     195       16125 :         else if (r.is('-')) { ++ r; return checkOperator(Expression::Sub); }
     196       16000 :         else if (r.is('<')) { ++ r; return checkOperator(Expression::Lt); }
     197       15750 :         else if (r.is('>')) { ++ r; return checkOperator(Expression::Gt); }
     198       15525 :         else if (r.is('&')) { ++ r; return checkOperator(Expression::BitAnd); }
     199       15450 :         else if (r.is('^')) { ++ r; return checkOperator(Expression::BitXor); }
     200       15375 :         else if (r.is('|')) { ++ r; return checkOperator(Expression::BitOr); }
     201       15300 :         else if (r.is(':') && (brace || !opts.hasFlag(Expression::StopOnRootColon))) { ++ r; return checkOperator(Expression::Colon); }
     202       14650 :         else if (r.is(',') && (brace || !opts.hasFlag(Expression::StopOnRootComma))) { ++ r; return checkOperator(Expression::Comma); }
     203       13225 :         else if (r.is(';') && (brace || !opts.hasFlag(Expression::StopOnRootSequence))) { ++ r; return checkOperator(Expression::Sequence); }
     204             : 
     205       13200 :         return Expression::NoOp;
     206             : }
     207             : 
     208        1850 : static Expression **Lexer_Expression_pushUnaryOp(Expression *node, Expression::Op op) {
     209        1850 :         node->op = op;
     210        1850 :         node->left = new Expression{Expression::Op::NoOp};
     211        1850 :         return &node->left;
     212             : }
     213             : 
     214       14925 : static Expression *Lexer_Expression_insertOp(Expression **node, Expression::Op op) {
     215       14925 :         Expression **insert = node;
     216       14925 :         Expression *prev = nullptr;
     217       14925 :         Expression *current = *node;
     218       18900 :         while (Lexer_Expression_priority(current->op) > Lexer_Expression_priority(op) && (current->right || current->left) && !current->block) {
     219        3975 :                 prev = current;
     220        3975 :                 if (current->right) {
     221        3975 :                         insert = &prev->right;
     222        3975 :                         current = current->right;
     223             :                 } else {
     224           0 :                         insert = &prev->left;
     225           0 :                         current = current->left;
     226             :                 }
     227             :         }
     228             : 
     229       14925 :         if (Lexer_Expression_associativity(op) && Lexer_Expression_priority(current->op) >= Lexer_Expression_priority(op)) {
     230           0 :                 while (current->right->left && Lexer_Expression_priority(current->right->op) == Lexer_Expression_priority(op)) {
     231           0 :                         current = current->right;
     232             :                 }
     233           0 :                 current->right = new Expression(op, current->right, new Expression{Expression::NoOp});
     234           0 :                 return current->right;
     235             :         } else {
     236       14925 :                 *insert = new Expression(op, current,
     237       14800 :                                 (op != Expression::SuffixIncr && op != Expression::SuffixDecr)
     238       29725 :                                         ? new Expression{Expression::NoOp}
     239       14925 :                                         : nullptr);
     240       14925 :                 return *insert;
     241             :         }
     242             : }
     243             : 
     244       28850 : static bool Lexer_Expression_readOperandValue(Expression *current, StringView &r, Expression::Op op, const Expression::Options &opts) {
     245       28850 :         bool ret = false;
     246       28850 :         if (r.is('\'') || r.is('"')) {
     247        7600 :                 String stream;
     248        7600 :                 Lexer_parseBufferString(r, [&] (StringView str) {
     249        7725 :                         stream.append(str.data(), str.size());
     250        7725 :                 });
     251        7600 :                 current->set(Value(stream));
     252        7600 :                 ret = true;
     253       28850 :         } else if (r.is<StringView::CharGroup<CharGroupId::Numbers>>()) { // numeric literal
     254        2850 :                 bool isFloat = false;
     255        2850 :                 auto tmp = r;
     256        2850 :                 r.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
     257        2850 :                 if (r.is('.')) {
     258         375 :                         isFloat = true;
     259         375 :                         ++ r;
     260         375 :                         r.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
     261             :                 }
     262        2850 :                 if (r.is('E') || r.is('e')) {
     263          25 :                         isFloat = true;
     264          25 :                         ++ r;
     265          25 :                         if (r.is('+') || r.is('-')) {
     266          25 :                                 ++ r;
     267             :                         }
     268          25 :                         r.skipChars<StringView::CharGroup<CharGroupId::Numbers>>();
     269             :                 }
     270             : 
     271        2850 :                 auto value = StringView(tmp.data(), tmp.size() - r.size());
     272        2850 :                 if (isFloat) {
     273         375 :                         current->set(Value(value.readDouble().get()));
     274             :                 } else {
     275        2475 :                         current->set(Value(value.readInteger().get()));
     276             :                 }
     277        2850 :                 ret = true;
     278             :         } else { // token literal
     279       18400 :                 if (op == Expression::Dot || op == Expression::Colon || op == Expression::Sharp) {
     280        2850 :                         auto tmp = r;
     281        2850 :                         if (op == Expression::Colon && (r.is('+') || r.is('-'))) {
     282           0 :                                 ++ r;
     283             :                         }
     284        2850 :                         r.skipChars<StringView::CharGroup<CharGroupId::Alphanumeric>, StringView::Chars<'_'>>();
     285        2850 :                         auto value = StringView(tmp.data(), tmp.size() - r.size());
     286        2850 :                         current->set(String(value.data(), value.size()));
     287        2850 :                         ret = true;
     288        2850 :                 } else {
     289       15550 :                         auto value = r.readChars<StringView::CharGroup<CharGroupId::Alphanumeric>, StringView::Chars<'_'>>();
     290             : 
     291       15550 :                         if (value.empty() && (op == Expression::Call || op == Expression::Subscript || op == Expression::Construct)) {
     292         125 :                                 current->isToken = true;
     293       15425 :                         } else if (value == "true") {
     294         225 :                                 current->set(Value(true));
     295       15200 :                         } else if (value == "false") {
     296         175 :                                 current->set(Value(false));
     297       15025 :                         } else if (value == "null") {
     298          50 :                                 current->set(Value());
     299       14975 :                         } else if (value == "inf") {
     300          25 :                                 current->set(Value(std::numeric_limits<double>::infinity()));
     301       14950 :                         } else if (value == "nan") {
     302          25 :                                 current->set(Value(nan()));
     303       14925 :                         } else if (!value.empty()) {
     304       14925 :                                 current->set(String(value.data(), value.size()));
     305             :                         } else {
     306           0 :                                 return false;
     307             :                         }
     308       15550 :                         ret = true;
     309             :                 }
     310             :         }
     311       28850 :         return ret;
     312             : }
     313             : 
     314       90200 : static bool Lexer_Expression_skipWhitespace(StringView &r, const Expression::Options &opts, bool isFinalizable) {
     315          50 :         auto tryEmptyString = [] (StringView &r, const StringView &token) -> bool {
     316          50 :                 auto tmp = r;
     317          50 :                 if (tmp.is("\r\n")) { tmp += 2; }
     318          50 :                 else if (tmp.is('\n') || tmp.is('\r')) { ++ tmp; }
     319          50 :                 tmp.skipChars<StringView::Chars<' ', '\t'>>();
     320          50 :                 if (tmp.is('\n') || tmp.is('\r')) {
     321           0 :                         r = tmp;
     322           0 :                         return true;
     323             :                 }
     324          50 :                 return false;
     325             :         };
     326             : 
     327       90200 :         if (opts.hasFlag(Expression::UseNewlineToken)) {
     328         750 :                 while (r.is<StringView::Chars<' ', '\t', '\n', '\r'>>()) {
     329         200 :                         r.skipChars<StringView::Chars<' ', '\t'>>();
     330         200 :                         if (r.is('\n') || r.is('\r')) {
     331          50 :                                 if (!tryEmptyString(r, opts.newlineToken)) {
     332          50 :                                         if (isFinalizable || !r.is(opts.newlineToken)) {
     333          25 :                                                 return false;
     334             :                                         } else {
     335          25 :                                                 r += opts.newlineToken.size();
     336          25 :                                                 r.skipChars<StringView::Chars<' ', '\t'>>();
     337             :                                         }
     338             :                                 }
     339             :                         }
     340         175 :                         r.skipChars<StringView::Chars<' ', '\t'>>();
     341             :                 }
     342         550 :                 return !r.empty();
     343       89625 :         } else if (!opts.hasFlag(Expression::StopOnNewLine)) {
     344        5475 :                 if (isFinalizable) {
     345        1975 :                         r.skipChars<StringView::Chars<' ', '\t'>>();
     346        1975 :                         if (r.is('\n') || r.is('\r')) {
     347           0 :                                 return false;
     348             :                         }
     349             :                 }
     350        5475 :                 r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     351        5475 :                 return !r.empty();
     352             :         } else {
     353       84150 :                 r.skipChars<StringView::Chars<' ', '\t'>>();
     354       84150 :                 if (r.is('\n' || r.is('\r'))) {
     355           0 :                         return false;
     356             :                 }
     357       84150 :                 r.skipChars<StringView::Chars<' ', '\t'>>();
     358       84150 :                 return !r.empty();
     359             :         }
     360             : }
     361             : 
     362       29725 : static bool Lexer_Expression_readOperand(Expression **node, StringView &r, Expression::Op op, const Expression::Options &opts) {
     363       29725 :         if (!Lexer_Expression_skipWhitespace(r, opts, false)) {
     364           0 :                 return false;
     365             :         }
     366             : 
     367       29725 :         if (op != Expression::Dot && op != Expression::Sharp) {
     368       27025 :                 bool finalized = false;
     369             :                 do {
     370       28875 :                         r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     371       28875 :                         if (r.is('!')) {
     372         100 :                                 ++ r;
     373         100 :                                 node = (Lexer_Expression_pushUnaryOp(*node, Expression::Neg));
     374       28775 :                         } else if (r.is('-')) {
     375         425 :                                 ++ r;
     376         425 :                                 node = (Lexer_Expression_pushUnaryOp(*node, Expression::Minus));
     377       28350 :                         } else if (r.is('~')) {
     378          50 :                                 ++ r;
     379          50 :                                 node = (Lexer_Expression_pushUnaryOp(*node, Expression::BitNot));
     380       28300 :                         } else if (r.is("++")) {
     381         175 :                                 r += 2;
     382         175 :                                 node = (Lexer_Expression_pushUnaryOp(*node, Expression::PrefixIncr));
     383       28125 :                         } else if (r.is("--")) {
     384           0 :                                 r += 2;
     385           0 :                                 node = (Lexer_Expression_pushUnaryOp(*node, Expression::PrefixDecr));
     386       28125 :                         } else if (r.is('+')) {
     387           0 :                                 ++ r;
     388       28125 :                         } else if (r.is("var")) {
     389        1100 :                                 auto tmp = r;
     390        1100 :                                 tmp += 3;
     391        1100 :                                 if (tmp.is<StringView::Chars<' ', '\t'>>()) {
     392        1100 :                                         tmp.skipChars<StringView::Chars<' ', '\t'>>();
     393        1100 :                                         r = tmp;
     394        1100 :                                         node = (Lexer_Expression_pushUnaryOp(*node, Expression::Var));
     395             :                                 } else {
     396           0 :                                         finalized = true;
     397             :                                 }
     398             :                         } else {
     399       27025 :                                 finalized = true;
     400             :                         }
     401       28875 :                 } while (!finalized);
     402             :         }
     403             : 
     404             :         // read as expression
     405       29725 :         if (r.is('(') || r.is('[') || r.is('{')) {
     406         875 :                 if (Lexer_readExpression(node, r, opts, false)) {
     407         875 :                         return true;
     408             :                 }
     409           0 :                 return false;
     410             :         }
     411             : 
     412             :         // read as literal
     413       28850 :         return Lexer_Expression_readOperandValue(*node, r, op, opts);
     414             : }
     415             : 
     416       16100 : static bool Lexer_readExpression(Expression **node, StringView &r, const Expression::Options &opts, bool isRoot) {
     417       16100 :         Expression::Op targetOp = Expression::NoOp;
     418       16100 :         Expression::Block block = Expression::Block::Parentesis;
     419       16100 :         char brace = 0;
     420       16100 :         if ((r.is('(') || r.is('[') || r.is('{') || r.is('?')) && !isRoot) {
     421        1875 :                 auto tmp = r[0];
     422        1875 :                 switch (tmp) {
     423         975 :                 case '(': brace = ')'; block = Expression::Parentesis; targetOp = Expression::Call; break;
     424         125 :                 case '?': brace = ':'; block = Expression::Parentesis; targetOp = Expression::Conditional; break;
     425         475 :                 case '[': brace = ']'; block = Expression::Composition; targetOp = Expression::Subscript; break;
     426         300 :                 case '{': brace = '}'; block = Expression::Operator; targetOp = Expression::Construct; break;
     427           0 :                 default: break;
     428             :                 }
     429        1875 :                 ++ r;
     430        1875 :                 if (!Lexer_Expression_skipWhitespace(r, opts, false)) {
     431           0 :                         return false;
     432             :                 }
     433             : 
     434        1875 :                 if (brace == '}' && r.is('}')) {
     435          25 :                         ++ r;
     436          25 :                         (*node)->op = Expression::Construct;
     437          25 :                         (*node)->block = Expression::Operator;
     438          25 :                         return true;
     439             :                 }
     440        1850 :                 if (brace == ']' && r.is(']')) {
     441          25 :                         ++ r;
     442          25 :                         (*node)->op = Expression::Subscript;
     443          25 :                         (*node)->block = Expression::Composition;
     444          25 :                         return true;
     445             :                 }
     446             :         }
     447             : 
     448             :         // read first operand
     449       16050 :         if (!Lexer_Expression_readOperand(node, r, targetOp, opts)) {
     450           0 :                 return false;
     451             :         }
     452       16050 :         if (!Lexer_Expression_skipWhitespace(r, opts, isRoot)) {
     453         125 :                 return isRoot;
     454             :         }
     455             : 
     456       15925 :         Expression *current = *node;
     457             :         // if there is only first operand - no other ops will be executed
     458       29850 :         while (!r.empty() && (brace == 0 || !r.is(brace))) {
     459             :                 // read operator
     460       28000 :                 if (!Lexer_Expression_skipWhitespace(r, opts, false)) {
     461           0 :                         return isRoot;
     462             :                 }
     463       28000 :                 auto op = Lexer_Expression_readOperator(r, brace, opts);
     464       28000 :                 if (op == Expression::NoOp) {
     465       13200 :                         return isRoot;
     466             :                 }
     467             : 
     468       14800 :                 current = Lexer_Expression_insertOp(node, op);
     469       14800 :                 if (op == Expression::Conditional) {
     470         125 :                         if (!Lexer_readExpression(&current->right, r, opts, false)) {
     471           0 :                                 return false;
     472             :                         }
     473         125 :                         current = Lexer_Expression_insertOp(node, Expression::ConditionalSwitch);
     474         125 :                         if (!Lexer_Expression_readOperand(&current->right, r, current->op, opts)) {
     475           0 :                                 return false;
     476             :                         }
     477         125 :                         if (!Lexer_Expression_skipWhitespace(r, opts, isRoot)) {
     478           0 :                                 return isRoot;
     479             :                         }
     480       14675 :                 } else if (op == Expression::Call || op == Expression::Subscript || op == Expression::Construct) {
     481         875 :                         if (!Lexer_readExpression(&current->right, r, opts, false)) {
     482           0 :                                 return false;
     483             :                         }
     484         875 :                         if (!Lexer_Expression_skipWhitespace(r, opts, false)) {
     485          75 :                                 return isRoot;
     486             :                         }
     487       13800 :                 } else if (op == Expression::SuffixIncr || op == Expression::SuffixDecr) {
     488             :                         // pass thru
     489             :                 } else {
     490       13550 :                         if (!Lexer_Expression_readOperand(&current->right, r, current->op, opts)) {
     491           0 :                                 return false;
     492             :                         }
     493       13550 :                         if (!Lexer_Expression_skipWhitespace(r, opts, isRoot)) {
     494         800 :                                 return isRoot;
     495             :                         }
     496             :                 }
     497             :         }
     498             : 
     499        1850 :         (*node)->block = block;
     500        1850 :         if (brace != 0 && r.is(brace)) {
     501        1825 :                 ++ r;
     502             :         }
     503        1850 :         return true;
     504             : }
     505             : 
     506        2975 : static void stl_print_expression_op(const Lexer::OutStream &stream, Expression::Op op) {
     507        2975 :         switch (op) {
     508             : 
     509           0 :         case Expression::NoOp: stream << "<noop>"; break;
     510         350 :         case Expression::Var: stream << "<var>"; break;
     511          25 :         case Expression::SuffixIncr: stream << "() ++"; break;
     512          25 :         case Expression::SuffixDecr: stream << "() --"; break;
     513             : 
     514          25 :         case Expression::Sharp: stream << "# <sharp>"; break;
     515         125 :         case Expression::Dot: stream << ". <dot>"; break;
     516          50 :         case Expression::Scope: stream << ":: <scope>"; break;
     517          75 :         case Expression::Call: stream << "() <call>"; break;
     518          25 :         case Expression::Subscript: stream << "[] <subscript>"; break;
     519          25 :         case Expression::Construct: stream << "{} <construct>"; break;
     520             : 
     521          25 :         case Expression::PrefixIncr: stream << "++ ()"; break;
     522           0 :         case Expression::PrefixDecr: stream << "-- ()"; break;
     523             : 
     524          75 :         case Expression::Minus: stream << "- <minus>"; break;
     525          25 :         case Expression::Neg: stream << "! <neg>"; break;
     526          25 :         case Expression::BitNot: stream << "~ <bit-not>"; break;
     527             : 
     528          25 :         case Expression::Mult: stream << "* <mult>"; break;
     529          25 :         case Expression::Div: stream << "/ <div>"; break;
     530          50 :         case Expression::Rem: stream << "% <rem>"; break;
     531             : 
     532         225 :         case Expression::Sum: stream << "+ <sum>"; break;
     533          25 :         case Expression::Sub: stream << "- <sub>"; break;
     534             : 
     535          25 :         case Expression::ShiftLeft: stream << "<< <shift-left>"; break;
     536          25 :         case Expression::ShiftRight: stream << ">> <shift-right>"; break;
     537             : 
     538          50 :         case Expression::Lt: stream << "< <lt>"; break;
     539          25 :         case Expression::LtEq: stream << "<= <lt-eq>"; break;
     540          25 :         case Expression::Gt: stream << "> <gt>"; break;
     541          25 :         case Expression::GtEq: stream << ">= <gt-eq>"; break;
     542             : 
     543          25 :         case Expression::Eq: stream << "== <eq>"; break;
     544          25 :         case Expression::NotEq: stream << "!= <eq>"; break;
     545             : 
     546          25 :         case Expression::BitAnd: stream << "& <bit-and>"; break;
     547          25 :         case Expression::BitXor: stream << "^ <bit-xor>"; break;
     548          25 :         case Expression::BitOr: stream << "| <bit-or>"; break;
     549             : 
     550          25 :         case Expression::And: stream << "&& <and>"; break;
     551          25 :         case Expression::Or: stream << "|| <or>"; break;
     552             : 
     553          50 :         case Expression::Conditional: stream << "? <conditional>"; break;
     554          50 :         case Expression::ConditionalSwitch: stream << "?: <conditional-switch>"; break;
     555             : 
     556         475 :         case Expression::Assignment: stream << "= <assignment>"; break;
     557          25 :         case Expression::SumAssignment: stream << "+= <assignment>"; break;
     558          25 :         case Expression::DiffAssignment: stream << "-= <assignment>"; break;
     559          25 :         case Expression::MultAssignment: stream << "*= <assignment>"; break;
     560          25 :         case Expression::DivAssignment: stream << "/= <assignment>"; break;
     561          25 :         case Expression::RemAssignment: stream << "%= <assignment>"; break;
     562          25 :         case Expression::LShiftAssignment: stream << "<<= <assignment>"; break;
     563          25 :         case Expression::RShiftAssignment: stream << ">>= <assignment>"; break;
     564          25 :         case Expression::AndAssignment: stream << "&= <assignment>"; break;
     565          25 :         case Expression::XorAssignment: stream << "^= <assignment>"; break;
     566          25 :         case Expression::OrAssignment: stream << "|= <assignment>"; break;
     567             : 
     568         200 :         case Expression::Colon: stream << ": <colon>"; break;
     569         350 :         case Expression::Comma: stream << ", <comma>"; break;
     570          25 :         case Expression::Sequence: stream << "; <sequence>"; break;
     571             : 
     572             :         }
     573        2975 : }
     574             : 
     575        2425 : static void stl_print_expression_open_block(const Lexer::OutStream &stream, Expression::Block b, uint16_t depth) {
     576        2425 :         switch (b) {
     577        2200 :         case Expression::None:
     578        2200 :                 break;
     579          75 :         case Expression::Parentesis:
     580         375 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     581          75 :                 stream << "(\n";
     582          75 :                 break;
     583          50 :         case Expression::Composition:
     584         350 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     585          50 :                 stream << "[\n";
     586          50 :                 break;
     587         100 :         case Expression::Operator:
     588         650 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     589         100 :                 stream << "{\n";
     590         100 :                 break;
     591             :         }
     592        2425 : }
     593             : 
     594        2425 : static void stl_print_expression_close_block(const Lexer::OutStream &stream, Expression::Block b, uint16_t depth) {
     595        2425 :         switch (b) {
     596        2200 :         case Expression::None:
     597        2200 :                 break;
     598          75 :         case Expression::Parentesis:
     599         375 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     600          75 :                 stream << ")\n";
     601          75 :                 break;
     602          50 :         case Expression::Composition:
     603         350 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     604          50 :                 stream << "]\n";
     605          50 :                 break;
     606         100 :         case Expression::Operator:
     607         650 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     608         100 :                 stream << "}\n";
     609         100 :                 break;
     610             :         }
     611        2425 : }
     612             : 
     613        8625 : static void stl_print_expression(const Lexer::OutStream &stream, Expression * t, uint16_t depth) {
     614        8625 :         if (!t->left && !t->right) {
     615       32300 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     616        5650 :                 if (t->isToken) {
     617        3525 :                         stream << "(token) " << data::toString<stappler::memory::PoolInterface>(t->value, false) << "\n";
     618        2125 :                 } else if (t->op == Expression::NoOp) {
     619        2075 :                         switch (t->value.getType()) {
     620          25 :                         case Value::Type::EMPTY: break;
     621           0 :                         case Value::Type::NONE: break;
     622         200 :                         case Value::Type::BOOLEAN: stream << "(bool) "; break;
     623         300 :                         case Value::Type::INTEGER: stream << "(int) "; break;
     624           0 :                         case Value::Type::DOUBLE: stream << "(float) "; break;
     625        1550 :                         case Value::Type::CHARSTRING: stream << "(string) "; break;
     626           0 :                         case Value::Type::BYTESTRING: stream << "(bytes) "; break;
     627           0 :                         case Value::Type::ARRAY: stream << "(array) "; break;
     628           0 :                         case Value::Type::DICTIONARY: stream << "(dict) "; break;
     629             :                         }
     630        2075 :                         stream << data::toString<stappler::memory::PoolInterface>(t->value, false) << "\n";
     631             :                 } else {
     632          50 :                         switch (t->op) {
     633          25 :                         case Expression::Subscript: stream << "[] <subscript>\n"; break;
     634          25 :                         case Expression::Construct: stream << "{} <construct>\n"; break;
     635           0 :                         default: break;
     636             :                         }
     637             :                 }
     638        8625 :         } else if (t->left && t->right) {
     639        2425 :                 stl_print_expression_open_block(stream, t->block, depth);
     640        2425 :                 stl_print_expression(stream, t->left, depth + 1);
     641             : 
     642       11225 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     643        2425 :                 stream << "-> ";
     644        2425 :                 stl_print_expression_op(stream, t->op);
     645        2425 :                 stream << "\n";
     646             : 
     647        2425 :                 stl_print_expression(stream, t->right, depth + 1);
     648        2425 :                 stl_print_expression_close_block(stream, t->block, depth);
     649        2975 :         } else if (t->left) {
     650        2850 :                 for (size_t i = 0; i < depth; ++ i) { stream << "  "; }
     651             : 
     652         550 :                 switch (t->block) {
     653         525 :                 case Expression::None: break;
     654          25 :                 case Expression::Parentesis: stream << "( "; break;
     655           0 :                 case Expression::Composition: stream << "{ "; break;
     656           0 :                 case Expression::Operator: stream << "[ "; break;
     657             :                 }
     658             : 
     659         550 :                 stl_print_expression_op(stream, t->op);
     660             : 
     661         550 :                 switch (t->block) {
     662         525 :                 case Expression::None: break;
     663          25 :                 case Expression::Parentesis: stream << " )"; break;
     664           0 :                 case Expression::Composition: stream << " }"; break;
     665           0 :                 case Expression::Operator: stream << " ]"; break;
     666             :                 }
     667             : 
     668         550 :                 stream << "\n";
     669             : 
     670         550 :                 stl_print_expression(stream, t->left, depth + 1);
     671             :         }
     672        8625 : }
     673             : 
     674        3225 : void Expression::describe(const OutStream &stream, size_t depth) {
     675        3225 :         stl_print_expression(stream, this, depth);
     676        3225 : }
     677             : 
     678             : 
     679       13200 : Expression::Options Expression::Options::getDefaultInline() {
     680       13200 :         return Options().enableAllOperators().setFlags({StopOnNewLine, StopOnRootColon, StopOnRootComma, StopOnRootSequence});
     681             : }
     682        1000 : Expression::Options Expression::Options::getDefaultScript() {
     683        1000 :         return Options().enableAllOperators().setFlags({StopOnRootColon, StopOnRootComma, StopOnRootSequence});
     684             : }
     685          25 : Expression::Options Expression::Options::getWithNewlineToken(const StringView &token) {
     686          25 :         return Options().enableAllOperators().setFlags({StopOnRootColon, StopOnRootComma, StopOnRootSequence}).useNewlineToken(token);
     687             : }
     688             : 
     689       14250 : Expression::Options &Expression::Options::enableAllOperators() {
     690       14250 :         operators.set();
     691       14250 :         return *this;
     692             : }
     693             : 
     694          25 : Expression::Options &Expression::Options::disableAllOperators() {
     695          25 :         operators.reset();
     696          25 :         return *this;
     697             : }
     698             : 
     699          25 : Expression::Options &Expression::Options::enableOperators(std::initializer_list<Op> && il) {
     700          50 :         for (auto &it : il) { operators.set(toInt(it)); }
     701          25 :         return *this;
     702             : }
     703          25 : Expression::Options &Expression::Options::disableOperators(std::initializer_list<Op> && il) {
     704          50 :         for (auto &it : il) { operators.reset(toInt(it)); }
     705          25 :         return *this;
     706             : }
     707             : 
     708          25 : Expression::Options &Expression::Options::useNewlineToken(const StringView &str) {
     709          25 :         newlineToken = str;
     710          25 :         setFlags({UseNewlineToken});
     711          25 :         return *this;
     712             : }
     713             : 
     714       14250 : Expression::Options &Expression::Options::setFlags(std::initializer_list<Flags> && il) {
     715       70150 :         for (auto &it : il) { flags.set(toInt(it)); }
     716       14250 :         return *this;
     717             : }
     718        1000 : Expression::Options &Expression::Options::clearFlags(std::initializer_list<Flags> && il) {
     719        2000 :         for (auto &it : il) { flags.reset(toInt(it)); }
     720        1000 :         return *this;
     721             : }
     722             : 
     723      181800 : bool Expression::Options::hasFlag(Flags f) const {
     724      181800 :         return flags.test(toInt(f));
     725             : }
     726       14800 : bool Expression::Options::hasOperator(Op op) const {
     727       14800 :         return operators.test(toInt(op));
     728             : }
     729             : 
     730       14225 : Expression * Expression::parse(StringView &r, const Options &opts) {
     731       14225 :         auto root = new Expression{Op::NoOp};
     732       14225 :         if (!Lexer_readExpression(&root, r, opts, true)) {
     733           0 :                 return nullptr;
     734             :         }
     735       14225 :         return root;
     736             : }
     737             : 
     738             : }

Generated by: LCOV version 1.14