/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2015 - ROLI Ltd. Permission is granted to use this software under the terms of either: a) the GPL v2 (or any later version) b) the Affero GPL v3 Details of these licenses can be found at: www.gnu.org/licenses JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.juce.com for more information. ============================================================================== */ struct CppParserHelpers { static bool parseHexInt (const String& text, int64& result) { CppTokeniserFunctions::StringIterator i (text); if (CppTokeniserFunctions::parseHexLiteral (i)) { result = text.fromFirstOccurrenceOf ("x", false, true).getHexValue64(); return true; } return false; } static bool parseOctalInt (const String& text, int64& result) { CppTokeniserFunctions::StringIterator it (text); if (CppTokeniserFunctions::parseOctalLiteral (it)) { result = 0; for (int i = 0; i < text.length(); ++i) { const int digit = text[i] - '0'; if (digit < 0 || digit > 7) break; result = result * 8 + digit; } return true; } return false; } static bool parseDecimalInt (const String& text, int64& result) { CppTokeniserFunctions::StringIterator i (text); if (CppTokeniserFunctions::parseDecimalLiteral (i)) { result = text.getLargeIntValue(); return true; } return false; } static bool parseInt (const String& text, int64& result) { return parseHexInt (text, result) || parseOctalInt (text, result) || parseDecimalInt (text, result); } static bool parseFloat (const String& text, double& result) { CppTokeniserFunctions::StringIterator i (text); if (CppTokeniserFunctions::parseFloatLiteral (i)) { result = text.getDoubleValue(); return true; } return false; } static int parseSingleToken (const String& text) { if (text.isEmpty()) return CPlusPlusCodeTokeniser::tokenType_error; CppTokeniserFunctions::StringIterator i (text); i.skipWhitespace(); const int tok = CppTokeniserFunctions::readNextToken (i); i.skipWhitespace(); i.skip(); return i.isEOF() ? tok : CPlusPlusCodeTokeniser::tokenType_error; } static String getIntegerSuffix (const String& s) { return s.retainCharacters ("lLuU"); } static String getFloatSuffix (const String& s) { return s.retainCharacters ("fF"); } static String getReplacementStringInSameFormat (const String& old, double newValue) { { CppTokeniserFunctions::StringIterator i (old); if (CppTokeniserFunctions::parseFloatLiteral (i)) { String s (newValue); if (! s.containsChar ('.')) s += ".0"; return s + getFloatSuffix (old); } } return getReplacementStringInSameFormat (old, (int64) newValue); } static String getReplacementStringInSameFormat (const String& old, int64 newValue) { { CppTokeniserFunctions::StringIterator i (old); if (CppTokeniserFunctions::parseHexLiteral (i)) { String s ("0x" + String::toHexString (newValue) + getIntegerSuffix (old)); if (old.toUpperCase() == old) s = s.toUpperCase(); return s; } } { CppTokeniserFunctions::StringIterator i (old); if (CppTokeniserFunctions::parseDecimalLiteral (i)) return String (newValue) + getIntegerSuffix (old); } return old; } // Given a type name which could be a smart pointer or other pointer/ref, this extracts // the essential class name of the thing that it points to. static String getSignificantClass (String cls) { int firstAngleBracket = cls.indexOfChar ('<'); if (firstAngleBracket > 0) cls = cls.substring (firstAngleBracket + 1).upToLastOccurrenceOf (">", false, false).trim(); while (cls.endsWithChar ('*') || cls.endsWithChar ('&')) cls = cls.dropLastCharacters (1).trim(); return cls; } //============================================================================== struct ValidCppIdentifierRestriction : public TextEditor::InputFilter { ValidCppIdentifierRestriction (bool allowTemplatesAndNamespaces) : className (allowTemplatesAndNamespaces) {} String filterNewText (TextEditor& ed, const String& text) { String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"); if (className) allowedChars += "<>:"; if (ed.getHighlightedRegion().getStart() > 0) allowedChars += "0123456789"; String s = text.retainCharacters (allowedChars); if (CPlusPlusCodeTokeniser::isReservedKeyword (ed.getText().replaceSection (ed.getHighlightedRegion().getStart(), ed.getHighlightedRegion().getLength(), s))) return String(); return s; } bool className; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValidCppIdentifierRestriction) }; }; //============================================================================== struct CodeChange { CodeChange (Range r, const String& t) : range (r), text (t) { } bool mergeWith (const CodeChange& next) { if (text.isEmpty()) { if (next.text.isNotEmpty() && next.range.isEmpty() && next.range.getStart() == range.getStart()) { text = next.text; return true; } if (next.text.isEmpty()) { Range nextRange (next.range); if (nextRange.getStart() >= range.getStart()) nextRange += range.getLength(); else if (nextRange.getEnd() > range.getStart()) nextRange.setEnd (nextRange.getEnd() + range.getLength()); if (range.intersects (nextRange) || range.getEnd() == nextRange.getStart() || range.getStart() == nextRange.getEnd()) { range = range.getUnionWith (nextRange); return true; } } } else if (next.text.isEmpty()) { if (next.range.getEnd() == range.getStart()) { range.setStart (next.range.getStart()); return true; } if (next.range.getStart() == range.getStart() + text.length()) { range.setLength (range.getLength() + next.range.getLength()); return true; } } return false; } void addToList (Array& list) const { if (list.size() == 0 || ! list.getReference (list.size() - 1).mergeWith (*this)) list.add (*this); } Range range; String text; }; //============================================================================== static inline String concatenateListOfStrings (const StringArray& s) { return s.joinIntoString ("\x01"); } static inline StringArray separateJoinedStrings (const String& s) { return StringArray::fromTokens (s, "\x01", juce::StringRef()); }