The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
8.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. struct CppParserHelpers
  18. {
  19. static bool parseHexInt (const String& text, int64& result)
  20. {
  21. CppTokeniserFunctions::StringIterator i (text);
  22. if (CppTokeniserFunctions::parseHexLiteral (i))
  23. {
  24. result = text.fromFirstOccurrenceOf ("x", false, true).getHexValue64();
  25. return true;
  26. }
  27. return false;
  28. }
  29. static bool parseOctalInt (const String& text, int64& result)
  30. {
  31. CppTokeniserFunctions::StringIterator it (text);
  32. if (CppTokeniserFunctions::parseOctalLiteral (it))
  33. {
  34. result = 0;
  35. for (int i = 0; i < text.length(); ++i)
  36. {
  37. const int digit = text[i] - '0';
  38. if (digit < 0 || digit > 7)
  39. break;
  40. result = result * 8 + digit;
  41. }
  42. return true;
  43. }
  44. return false;
  45. }
  46. static bool parseDecimalInt (const String& text, int64& result)
  47. {
  48. CppTokeniserFunctions::StringIterator i (text);
  49. if (CppTokeniserFunctions::parseDecimalLiteral (i))
  50. {
  51. result = text.getLargeIntValue();
  52. return true;
  53. }
  54. return false;
  55. }
  56. static bool parseInt (const String& text, int64& result)
  57. {
  58. return parseHexInt (text, result)
  59. || parseOctalInt (text, result)
  60. || parseDecimalInt (text, result);
  61. }
  62. static bool parseFloat (const String& text, double& result)
  63. {
  64. CppTokeniserFunctions::StringIterator i (text);
  65. if (CppTokeniserFunctions::parseFloatLiteral (i))
  66. {
  67. result = text.getDoubleValue();
  68. return true;
  69. }
  70. return false;
  71. }
  72. static int parseSingleToken (const String& text)
  73. {
  74. if (text.isEmpty())
  75. return CPlusPlusCodeTokeniser::tokenType_error;
  76. CppTokeniserFunctions::StringIterator i (text);
  77. i.skipWhitespace();
  78. const int tok = CppTokeniserFunctions::readNextToken (i);
  79. i.skipWhitespace();
  80. i.skip();
  81. return i.isEOF() ? tok : CPlusPlusCodeTokeniser::tokenType_error;
  82. }
  83. static String getIntegerSuffix (const String& s) { return s.retainCharacters ("lLuU"); }
  84. static String getFloatSuffix (const String& s) { return s.retainCharacters ("fF"); }
  85. static String getReplacementStringInSameFormat (const String& old, double newValue)
  86. {
  87. {
  88. CppTokeniserFunctions::StringIterator i (old);
  89. if (CppTokeniserFunctions::parseFloatLiteral (i))
  90. {
  91. String s (newValue);
  92. if (! s.containsChar ('.'))
  93. s += ".0";
  94. return s + getFloatSuffix (old);
  95. }
  96. }
  97. return getReplacementStringInSameFormat (old, (int64) newValue);
  98. }
  99. static String getReplacementStringInSameFormat (const String& old, int64 newValue)
  100. {
  101. {
  102. CppTokeniserFunctions::StringIterator i (old);
  103. if (CppTokeniserFunctions::parseHexLiteral (i))
  104. {
  105. String s ("0x" + String::toHexString (newValue) + getIntegerSuffix (old));
  106. if (old.toUpperCase() == old)
  107. s = s.toUpperCase();
  108. return s;
  109. }
  110. }
  111. {
  112. CppTokeniserFunctions::StringIterator i (old);
  113. if (CppTokeniserFunctions::parseDecimalLiteral (i))
  114. return String (newValue) + getIntegerSuffix (old);
  115. }
  116. return old;
  117. }
  118. // Given a type name which could be a smart pointer or other pointer/ref, this extracts
  119. // the essential class name of the thing that it points to.
  120. static String getSignificantClass (String cls)
  121. {
  122. int firstAngleBracket = cls.indexOfChar ('<');
  123. if (firstAngleBracket > 0)
  124. cls = cls.substring (firstAngleBracket + 1).upToLastOccurrenceOf (">", false, false).trim();
  125. while (cls.endsWithChar ('*') || cls.endsWithChar ('&'))
  126. cls = cls.dropLastCharacters (1).trim();
  127. return cls;
  128. }
  129. //==============================================================================
  130. struct ValidCppIdentifierRestriction : public TextEditor::InputFilter
  131. {
  132. ValidCppIdentifierRestriction (bool allowTemplatesAndNamespaces)
  133. : className (allowTemplatesAndNamespaces) {}
  134. String filterNewText (TextEditor& ed, const String& text)
  135. {
  136. String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_");
  137. if (className)
  138. allowedChars += "<>:";
  139. if (ed.getHighlightedRegion().getStart() > 0)
  140. allowedChars += "0123456789";
  141. String s = text.retainCharacters (allowedChars);
  142. if (CPlusPlusCodeTokeniser::isReservedKeyword (ed.getText().replaceSection (ed.getHighlightedRegion().getStart(),
  143. ed.getHighlightedRegion().getLength(),
  144. s)))
  145. return String();
  146. return s;
  147. }
  148. bool className;
  149. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValidCppIdentifierRestriction)
  150. };
  151. };
  152. //==============================================================================
  153. struct CodeChange
  154. {
  155. CodeChange (Range<int> r, const String& t) : range (r), text (t)
  156. {
  157. }
  158. bool mergeWith (const CodeChange& next)
  159. {
  160. if (text.isEmpty())
  161. {
  162. if (next.text.isNotEmpty()
  163. && next.range.isEmpty()
  164. && next.range.getStart() == range.getStart())
  165. {
  166. text = next.text;
  167. return true;
  168. }
  169. if (next.text.isEmpty())
  170. {
  171. Range<int> nextRange (next.range);
  172. if (nextRange.getStart() >= range.getStart())
  173. nextRange += range.getLength();
  174. else if (nextRange.getEnd() > range.getStart())
  175. nextRange.setEnd (nextRange.getEnd() + range.getLength());
  176. if (range.intersects (nextRange)
  177. || range.getEnd() == nextRange.getStart()
  178. || range.getStart() == nextRange.getEnd())
  179. {
  180. range = range.getUnionWith (nextRange);
  181. return true;
  182. }
  183. }
  184. }
  185. else if (next.text.isEmpty())
  186. {
  187. if (next.range.getEnd() == range.getStart())
  188. {
  189. range.setStart (next.range.getStart());
  190. return true;
  191. }
  192. if (next.range.getStart() == range.getStart() + text.length())
  193. {
  194. range.setLength (range.getLength() + next.range.getLength());
  195. return true;
  196. }
  197. }
  198. return false;
  199. }
  200. void addToList (Array<CodeChange>& list) const
  201. {
  202. if (list.size() == 0 || ! list.getReference (list.size() - 1).mergeWith (*this))
  203. list.add (*this);
  204. }
  205. Range<int> range;
  206. String text;
  207. };
  208. //==============================================================================
  209. static inline String concatenateListOfStrings (const StringArray& s)
  210. {
  211. return s.joinIntoString ("\x01");
  212. }
  213. static inline StringArray separateJoinedStrings (const String& s)
  214. {
  215. return StringArray::fromTokens (s, "\x01", juce::StringRef());
  216. }