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.

285 lines
8.6KB

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