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.

236 lines
7.3KB

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