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.

284 lines
8.6KB

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