StringMath::Token StringMath::Lexer::nextNumber(const int base, const int line, const int column) { // match digits for integer part int digit = 0; int64_t integer = 0; while(peekDigit(digit, base)) { pop(); integer = integer * base + digit; } // return integer if point or scientific exponent not matched if(peek() != "." && !(base == 10 && peek() == "e")) return Token(integer, line, column); // match digits for floating point part double floating = static_cast<double>(integer); if(peek() == ".") { pop(); for(int index = -1; peekDigit(digit, base); index--) { pop(); floating += digit * pow(base, index); } } // match scientific exponent part if(base == 10 && peek() == "e") { pop(); bool negate = false; int64_t exponent = 0; if(peek() == "-") { pop(); negate = true; } while(peekDigit(digit, base)) { pop(); exponent = exponent * base + digit; } floating *= pow(10, negate ? -exponent : exponent); } return Token(floating, line, column); }
Escape Parser::consumeEscape(bool inCharacterClass) { switch (peek()) { case EndOfPattern: setError(EscapeUnterminated); return Escape(Escape::Error); // Assertions case 'b': consume(); if (inCharacterClass) return PatternCharacterEscape('\b'); return WordBoundaryAssertionEscape(false); // do not invert case 'B': consume(); if (inCharacterClass) return PatternCharacterEscape('B'); return WordBoundaryAssertionEscape(true); // invert // CharacterClassEscape case 'd': consume(); return CharacterClassEscape(CharacterClass::digits(), false); case 's': consume(); return CharacterClassEscape(CharacterClass::spaces(), false); case 'w': consume(); return CharacterClassEscape(CharacterClass::wordchar(), false); case 'D': consume(); return inCharacterClass ? CharacterClassEscape(CharacterClass::nondigits(), false) : CharacterClassEscape(CharacterClass::digits(), true); case 'S': consume(); return inCharacterClass ? CharacterClassEscape(CharacterClass::nonspaces(), false) : CharacterClassEscape(CharacterClass::spaces(), true); case 'W': consume(); return inCharacterClass ? CharacterClassEscape(CharacterClass::nonwordchar(), false) : CharacterClassEscape(CharacterClass::wordchar(), true); // DecimalEscape case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { if (peekDigit() > m_numSubpatterns || inCharacterClass) { // To match Firefox, we parse an invalid backreference in the range [1-7] // as an octal escape. return peekDigit() > 7 ? PatternCharacterEscape('\\') : PatternCharacterEscape(consumeOctal()); } int value = 0; do { unsigned newValue = value * 10 + peekDigit(); if (newValue > m_numSubpatterns) break; value = newValue; consume(); } while (peekIsDigit()); return BackreferenceEscape(value); } // Octal escape case '0': consume(); return PatternCharacterEscape(consumeOctal()); // ControlEscape case 'f': consume(); return PatternCharacterEscape('\f'); case 'n': consume(); return PatternCharacterEscape('\n'); case 'r': consume(); return PatternCharacterEscape('\r'); case 't': consume(); return PatternCharacterEscape('\t'); case 'v': consume(); return PatternCharacterEscape('\v'); // ControlLetter case 'c': { SavedState state(*this); consume(); int control = consume(); if (!isASCIIAlpha(control)) { state.restore(); return PatternCharacterEscape('\\'); } return PatternCharacterEscape(control & 31); } // HexEscape case 'x': { consume(); SavedState state(*this); int x = consumeHex(2); if (x == -1) { state.restore(); return PatternCharacterEscape('x'); } return PatternCharacterEscape(x); } // UnicodeEscape case 'u': { consume(); SavedState state(*this); int x = consumeHex(4); if (x == -1) { state.restore(); return PatternCharacterEscape('u'); } return PatternCharacterEscape(x); } // IdentityEscape default: return PatternCharacterEscape(consume()); } }