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.

240 lines
7.2KB

  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. namespace juce
  19. {
  20. struct LuaTokeniserFunctions
  21. {
  22. static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
  23. {
  24. static const char* const keywords2Char[] =
  25. { "if", "or", "in", "do", nullptr };
  26. static const char* const keywords3Char[] =
  27. { "and", "end", "for", "nil", "not", nullptr };
  28. static const char* const keywords4Char[] =
  29. { "then", "true", "else", nullptr };
  30. static const char* const keywords5Char[] =
  31. { "false", "local", "until", "while", "break", nullptr };
  32. static const char* const keywords6Char[] =
  33. { "repeat", "return", "elseif", nullptr};
  34. static const char* const keywordsOther[] =
  35. { "function", "@interface", "@end", "@synthesize", "@dynamic", "@public",
  36. "@private", "@property", "@protected", "@class", nullptr };
  37. const char* const* k;
  38. switch (tokenLength)
  39. {
  40. case 2: k = keywords2Char; break;
  41. case 3: k = keywords3Char; break;
  42. case 4: k = keywords4Char; break;
  43. case 5: k = keywords5Char; break;
  44. case 6: k = keywords6Char; break;
  45. default:
  46. if (tokenLength < 2 || tokenLength > 16)
  47. return false;
  48. k = keywordsOther;
  49. break;
  50. }
  51. for (int i = 0; k[i] != nullptr; ++i)
  52. if (token.compare (CharPointer_ASCII (k[i])) == 0)
  53. return true;
  54. return false;
  55. }
  56. template <typename Iterator>
  57. static int parseIdentifier (Iterator& source) noexcept
  58. {
  59. int tokenLength = 0;
  60. String::CharPointerType::CharType possibleIdentifier[100];
  61. String::CharPointerType possible (possibleIdentifier);
  62. while (CppTokeniserFunctions::isIdentifierBody (source.peekNextChar()))
  63. {
  64. auto c = source.nextChar();
  65. if (tokenLength < 20)
  66. possible.write (c);
  67. ++tokenLength;
  68. }
  69. if (tokenLength > 1 && tokenLength <= 16)
  70. {
  71. possible.writeNull();
  72. if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
  73. return LuaTokeniser::tokenType_keyword;
  74. }
  75. return LuaTokeniser::tokenType_identifier;
  76. }
  77. template <typename Iterator>
  78. static int readNextToken (Iterator& source)
  79. {
  80. source.skipWhitespace();
  81. auto firstChar = source.peekNextChar();
  82. switch (firstChar)
  83. {
  84. case 0:
  85. break;
  86. case '0': case '1': case '2': case '3': case '4':
  87. case '5': case '6': case '7': case '8': case '9':
  88. case '.':
  89. {
  90. auto result = CppTokeniserFunctions::parseNumber (source);
  91. if (result == LuaTokeniser::tokenType_error)
  92. {
  93. source.skip();
  94. if (firstChar == '.')
  95. return LuaTokeniser::tokenType_punctuation;
  96. }
  97. return result;
  98. }
  99. case ',':
  100. case ';':
  101. case ':':
  102. source.skip();
  103. return LuaTokeniser::tokenType_punctuation;
  104. case '(': case ')':
  105. case '{': case '}':
  106. case '[': case ']':
  107. source.skip();
  108. return LuaTokeniser::tokenType_bracket;
  109. case '"':
  110. case '\'':
  111. CppTokeniserFunctions::skipQuotedString (source);
  112. return LuaTokeniser::tokenType_string;
  113. case '+':
  114. source.skip();
  115. CppTokeniserFunctions::skipIfNextCharMatches (source, '+', '=');
  116. return LuaTokeniser::tokenType_operator;
  117. case '-':
  118. {
  119. source.skip();
  120. auto result = CppTokeniserFunctions::parseNumber (source);
  121. if (source.peekNextChar() == '-')
  122. {
  123. source.skipToEndOfLine();
  124. return LuaTokeniser::tokenType_comment;
  125. }
  126. if (result == LuaTokeniser::tokenType_error)
  127. {
  128. CppTokeniserFunctions::skipIfNextCharMatches (source, '-', '=');
  129. return LuaTokeniser::tokenType_operator;
  130. }
  131. return result;
  132. }
  133. case '*': case '%':
  134. case '=': case '!':
  135. source.skip();
  136. CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
  137. return LuaTokeniser::tokenType_operator;
  138. case '?':
  139. case '~':
  140. source.skip();
  141. return LuaTokeniser::tokenType_operator;
  142. case '<': case '>':
  143. case '|': case '&': case '^':
  144. source.skip();
  145. CppTokeniserFunctions::skipIfNextCharMatches (source, firstChar);
  146. CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
  147. return LuaTokeniser::tokenType_operator;
  148. default:
  149. if (CppTokeniserFunctions::isIdentifierStart (firstChar))
  150. return parseIdentifier (source);
  151. source.skip();
  152. break;
  153. }
  154. return LuaTokeniser::tokenType_error;
  155. }
  156. };
  157. //==============================================================================
  158. LuaTokeniser::LuaTokeniser() {}
  159. LuaTokeniser::~LuaTokeniser() {}
  160. int LuaTokeniser::readNextToken (CodeDocument::Iterator& source)
  161. {
  162. return LuaTokeniserFunctions::readNextToken (source);
  163. }
  164. CodeEditorComponent::ColourScheme LuaTokeniser::getDefaultColourScheme()
  165. {
  166. static const CodeEditorComponent::ColourScheme::TokenType types[] =
  167. {
  168. { "Error", Colour (0xffcc0000) },
  169. { "Comment", Colour (0xff3c3c3c) },
  170. { "Keyword", Colour (0xff0000cc) },
  171. { "Operator", Colour (0xff225500) },
  172. { "Identifier", Colour (0xff000000) },
  173. { "Integer", Colour (0xff880000) },
  174. { "Float", Colour (0xff885500) },
  175. { "String", Colour (0xff990099) },
  176. { "Bracket", Colour (0xff000055) },
  177. { "Punctuation", Colour (0xff004400) }
  178. };
  179. CodeEditorComponent::ColourScheme cs;
  180. for (auto& t : types)
  181. cs.set (t.name, Colour (t.colour));
  182. return cs;
  183. }
  184. } // namespace juce