LexMSSQL.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // Scintilla source code edit control
  2. /** @file LexMSSQL.cxx
  3. ** Lexer for MSSQL.
  4. **/
  5. // By Filip Yaghob <fyaghob@gmail.com>
  6. // The License.txt file describes the conditions under which this software may be distributed.
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <assert.h>
  12. #include <ctype.h>
  13. #include "ILexer.h"
  14. #include "Scintilla.h"
  15. #include "SciLexer.h"
  16. #include "WordList.h"
  17. #include "LexAccessor.h"
  18. #include "Accessor.h"
  19. #include "StyleContext.h"
  20. #include "CharacterSet.h"
  21. #include "LexerModule.h"
  22. #ifdef SCI_NAMESPACE
  23. using namespace Scintilla;
  24. #endif
  25. #define KW_MSSQL_STATEMENTS 0
  26. #define KW_MSSQL_DATA_TYPES 1
  27. #define KW_MSSQL_SYSTEM_TABLES 2
  28. #define KW_MSSQL_GLOBAL_VARIABLES 3
  29. #define KW_MSSQL_FUNCTIONS 4
  30. #define KW_MSSQL_STORED_PROCEDURES 5
  31. #define KW_MSSQL_OPERATORS 6
  32. static char classifyWordSQL(Sci_PositionU start,
  33. Sci_PositionU end,
  34. WordList *keywordlists[],
  35. Accessor &styler,
  36. unsigned int actualState,
  37. unsigned int prevState) {
  38. char s[256];
  39. bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
  40. WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS];
  41. WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES];
  42. WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES];
  43. WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES];
  44. WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS];
  45. WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES];
  46. WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS];
  47. for (Sci_PositionU i = 0; i < end - start + 1 && i < 128; i++) {
  48. s[i] = static_cast<char>(tolower(styler[start + i]));
  49. s[i + 1] = '\0';
  50. }
  51. char chAttr = SCE_MSSQL_IDENTIFIER;
  52. if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) {
  53. if (kwGlobalVariables.InList(&s[2]))
  54. chAttr = SCE_MSSQL_GLOBAL_VARIABLE;
  55. } else if (wordIsNumber) {
  56. chAttr = SCE_MSSQL_NUMBER;
  57. } else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
  58. // Look first in datatypes
  59. if (kwDataTypes.InList(s))
  60. chAttr = SCE_MSSQL_DATATYPE;
  61. else if (kwOperators.InList(s))
  62. chAttr = SCE_MSSQL_OPERATOR;
  63. else if (kwStatements.InList(s))
  64. chAttr = SCE_MSSQL_STATEMENT;
  65. else if (kwSystemTables.InList(s))
  66. chAttr = SCE_MSSQL_SYSTABLE;
  67. else if (kwFunctions.InList(s))
  68. chAttr = SCE_MSSQL_FUNCTION;
  69. else if (kwStoredProcedures.InList(s))
  70. chAttr = SCE_MSSQL_STORED_PROCEDURE;
  71. } else {
  72. if (kwOperators.InList(s))
  73. chAttr = SCE_MSSQL_OPERATOR;
  74. else if (kwStatements.InList(s))
  75. chAttr = SCE_MSSQL_STATEMENT;
  76. else if (kwSystemTables.InList(s))
  77. chAttr = SCE_MSSQL_SYSTABLE;
  78. else if (kwFunctions.InList(s))
  79. chAttr = SCE_MSSQL_FUNCTION;
  80. else if (kwStoredProcedures.InList(s))
  81. chAttr = SCE_MSSQL_STORED_PROCEDURE;
  82. else if (kwDataTypes.InList(s))
  83. chAttr = SCE_MSSQL_DATATYPE;
  84. }
  85. styler.ColourTo(end, chAttr);
  86. return chAttr;
  87. }
  88. static void ColouriseMSSQLDoc(Sci_PositionU startPos, Sci_Position length,
  89. int initStyle, WordList *keywordlists[], Accessor &styler) {
  90. styler.StartAt(startPos);
  91. bool fold = styler.GetPropertyInt("fold") != 0;
  92. Sci_Position lineCurrent = styler.GetLine(startPos);
  93. int spaceFlags = 0;
  94. int state = initStyle;
  95. int prevState = initStyle;
  96. char chPrev = ' ';
  97. char chNext = styler[startPos];
  98. styler.StartSegment(startPos);
  99. Sci_PositionU lengthDoc = startPos + length;
  100. for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
  101. char ch = chNext;
  102. chNext = styler.SafeGetCharAt(i + 1);
  103. if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
  104. int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
  105. int lev = indentCurrent;
  106. if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
  107. // Only non whitespace lines can be headers
  108. int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
  109. if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
  110. lev |= SC_FOLDLEVELHEADERFLAG;
  111. }
  112. }
  113. if (fold) {
  114. styler.SetLevel(lineCurrent, lev);
  115. }
  116. }
  117. if (styler.IsLeadByte(ch)) {
  118. chNext = styler.SafeGetCharAt(i + 2);
  119. chPrev = ' ';
  120. i += 1;
  121. continue;
  122. }
  123. // When the last char isn't part of the state (have to deal with it too)...
  124. if ( (state == SCE_MSSQL_IDENTIFIER) ||
  125. (state == SCE_MSSQL_STORED_PROCEDURE) ||
  126. (state == SCE_MSSQL_DATATYPE) ||
  127. //~ (state == SCE_MSSQL_COLUMN_NAME) ||
  128. (state == SCE_MSSQL_FUNCTION) ||
  129. //~ (state == SCE_MSSQL_GLOBAL_VARIABLE) ||
  130. (state == SCE_MSSQL_VARIABLE)) {
  131. if (!iswordchar(ch)) {
  132. int stateTmp;
  133. if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) {
  134. styler.ColourTo(i - 1, state);
  135. stateTmp = state;
  136. } else
  137. stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
  138. prevState = state;
  139. if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE)
  140. state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
  141. else
  142. state = SCE_MSSQL_DEFAULT;
  143. }
  144. } else if (state == SCE_MSSQL_LINE_COMMENT) {
  145. if (ch == '\r' || ch == '\n') {
  146. styler.ColourTo(i - 1, state);
  147. prevState = state;
  148. state = SCE_MSSQL_DEFAULT;
  149. }
  150. } else if (state == SCE_MSSQL_GLOBAL_VARIABLE) {
  151. if ((ch != '@') && !iswordchar(ch)) {
  152. classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState);
  153. prevState = state;
  154. state = SCE_MSSQL_DEFAULT;
  155. }
  156. }
  157. // If is the default or one of the above succeeded
  158. if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) {
  159. if (iswordstart(ch)) {
  160. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  161. prevState = state;
  162. state = SCE_MSSQL_IDENTIFIER;
  163. } else if (ch == '/' && chNext == '*') {
  164. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  165. prevState = state;
  166. state = SCE_MSSQL_COMMENT;
  167. } else if (ch == '-' && chNext == '-') {
  168. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  169. prevState = state;
  170. state = SCE_MSSQL_LINE_COMMENT;
  171. } else if (ch == '\'') {
  172. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  173. prevState = state;
  174. state = SCE_MSSQL_STRING;
  175. } else if (ch == '"') {
  176. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  177. prevState = state;
  178. state = SCE_MSSQL_COLUMN_NAME;
  179. } else if (ch == '[') {
  180. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  181. prevState = state;
  182. state = SCE_MSSQL_COLUMN_NAME_2;
  183. } else if (isoperator(ch)) {
  184. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  185. styler.ColourTo(i, SCE_MSSQL_OPERATOR);
  186. //~ style = SCE_MSSQL_DEFAULT;
  187. prevState = state;
  188. state = SCE_MSSQL_DEFAULT;
  189. } else if (ch == '@') {
  190. styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT);
  191. prevState = state;
  192. if (chNext == '@') {
  193. state = SCE_MSSQL_GLOBAL_VARIABLE;
  194. // i += 2;
  195. } else
  196. state = SCE_MSSQL_VARIABLE;
  197. }
  198. // When the last char is part of the state...
  199. } else if (state == SCE_MSSQL_COMMENT) {
  200. if (ch == '/' && chPrev == '*') {
  201. if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) &&
  202. (styler.GetStartSegment() == startPos)))) {
  203. styler.ColourTo(i, state);
  204. //~ state = SCE_MSSQL_COMMENT;
  205. prevState = state;
  206. state = SCE_MSSQL_DEFAULT;
  207. }
  208. }
  209. } else if (state == SCE_MSSQL_STRING) {
  210. if (ch == '\'') {
  211. if ( chNext == '\'' ) {
  212. i++;
  213. ch = chNext;
  214. chNext = styler.SafeGetCharAt(i + 1);
  215. } else {
  216. styler.ColourTo(i, state);
  217. prevState = state;
  218. state = SCE_MSSQL_DEFAULT;
  219. //i++;
  220. }
  221. //ch = chNext;
  222. //chNext = styler.SafeGetCharAt(i + 1);
  223. }
  224. } else if (state == SCE_MSSQL_COLUMN_NAME) {
  225. if (ch == '"') {
  226. if (chNext == '"') {
  227. i++;
  228. ch = chNext;
  229. chNext = styler.SafeGetCharAt(i + 1);
  230. } else {
  231. styler.ColourTo(i, state);
  232. prevState = state;
  233. state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
  234. //i++;
  235. }
  236. }
  237. } else if (state == SCE_MSSQL_COLUMN_NAME_2) {
  238. if (ch == ']') {
  239. styler.ColourTo(i, state);
  240. prevState = state;
  241. state = SCE_MSSQL_DEFAULT_PREF_DATATYPE;
  242. //i++;
  243. }
  244. }
  245. chPrev = ch;
  246. }
  247. styler.ColourTo(lengthDoc - 1, state);
  248. }
  249. static void FoldMSSQLDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
  250. bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
  251. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  252. Sci_PositionU endPos = startPos + length;
  253. int visibleChars = 0;
  254. Sci_Position lineCurrent = styler.GetLine(startPos);
  255. int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
  256. int levelCurrent = levelPrev;
  257. char chNext = styler[startPos];
  258. bool inComment = (styler.StyleAt(startPos-1) == SCE_MSSQL_COMMENT);
  259. char s[10] = "";
  260. for (Sci_PositionU i = startPos; i < endPos; i++) {
  261. char ch = chNext;
  262. chNext = styler.SafeGetCharAt(i + 1);
  263. int style = styler.StyleAt(i);
  264. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  265. // Comment folding
  266. if (foldComment) {
  267. if (!inComment && (style == SCE_MSSQL_COMMENT))
  268. levelCurrent++;
  269. else if (inComment && (style != SCE_MSSQL_COMMENT))
  270. levelCurrent--;
  271. inComment = (style == SCE_MSSQL_COMMENT);
  272. }
  273. if (style == SCE_MSSQL_STATEMENT) {
  274. // Folding between begin or case and end
  275. if (ch == 'b' || ch == 'B' || ch == 'c' || ch == 'C' || ch == 'e' || ch == 'E') {
  276. for (Sci_PositionU j = 0; j < 5; j++) {
  277. if (!iswordchar(styler[i + j])) {
  278. break;
  279. }
  280. s[j] = static_cast<char>(tolower(styler[i + j]));
  281. s[j + 1] = '\0';
  282. }
  283. if ((strcmp(s, "begin") == 0) || (strcmp(s, "case") == 0)) {
  284. levelCurrent++;
  285. }
  286. if (strcmp(s, "end") == 0) {
  287. levelCurrent--;
  288. }
  289. }
  290. }
  291. if (atEOL) {
  292. int lev = levelPrev;
  293. if (visibleChars == 0 && foldCompact)
  294. lev |= SC_FOLDLEVELWHITEFLAG;
  295. if ((levelCurrent > levelPrev) && (visibleChars > 0))
  296. lev |= SC_FOLDLEVELHEADERFLAG;
  297. if (lev != styler.LevelAt(lineCurrent)) {
  298. styler.SetLevel(lineCurrent, lev);
  299. }
  300. lineCurrent++;
  301. levelPrev = levelCurrent;
  302. visibleChars = 0;
  303. }
  304. if (!isspacechar(ch))
  305. visibleChars++;
  306. }
  307. // Fill in the real level of the next line, keeping the current flags as they will be filled in later
  308. int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
  309. styler.SetLevel(lineCurrent, levelPrev | flagsNext);
  310. }
  311. static const char * const sqlWordListDesc[] = {
  312. "Statements",
  313. "Data Types",
  314. "System tables",
  315. "Global variables",
  316. "Functions",
  317. "System Stored Procedures",
  318. "Operators",
  319. 0,
  320. };
  321. LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", FoldMSSQLDoc, sqlWordListDesc);