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.

234 lines
7.3KB

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