PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/cssed-0.4.0/scintilla/src/LexSQL.cxx

#
C++ | 430 lines | 403 code | 18 blank | 9 comment | 197 complexity | 525bbb26459855a2333932b4f2c505f3 MD5 | raw file
Possible License(s): GPL-2.0
  1. // Scintilla source code edit control
  2. /** @file LexSQL.cxx
  3. ** Lexer for SQL.
  4. **/
  5. // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
  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 <ctype.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include "Platform.h"
  13. #include "PropSet.h"
  14. #include "Accessor.h"
  15. #include "KeyWords.h"
  16. #include "Scintilla.h"
  17. #include "SciLexer.h"
  18. static inline bool IsASpace(unsigned int ch) {
  19. return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
  20. }
  21. static bool MatchIgnoreCaseSubstring(const char *s, Accessor &styler, unsigned int startPos) {
  22. char ch = styler.SafeGetCharAt(startPos);
  23. bool isSubword = false;
  24. if (tolower(ch) != *s)
  25. return false;
  26. s++;
  27. if (*s == '~')
  28. {
  29. isSubword = true;
  30. s++;
  31. }
  32. int n;
  33. for (n = 1; *s; n++) {
  34. if (*s == '~')
  35. {
  36. isSubword = true;
  37. s++;
  38. }
  39. if (isSubword && IsASpace(styler.SafeGetCharAt(startPos + n)))
  40. return true;
  41. if (*s != tolower((styler.SafeGetCharAt(startPos + n))))
  42. return false;
  43. s++;
  44. }
  45. return (IsASpace(styler.SafeGetCharAt(startPos + n))
  46. || styler.SafeGetCharAt(startPos + n) == ';');
  47. }
  48. static void getCurrent(unsigned int start,
  49. unsigned int end,
  50. Accessor &styler,
  51. char *s,
  52. unsigned int len) {
  53. for (unsigned int i = 0; i < end - start + 1 && i < len; i++) {
  54. s[i] = static_cast<char>(tolower(styler[start + i]));
  55. s[i + 1] = '\0';
  56. }
  57. }
  58. static void classifyWordSQL(unsigned int start, unsigned int end, WordList *keywordlists[], Accessor &styler) {
  59. char s[100];
  60. bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
  61. for (unsigned int i = 0; i < end - start + 1 && i < 80; i++) {
  62. s[i] = static_cast<char>(tolower(styler[start + i]));
  63. s[i + 1] = '\0';
  64. }
  65. WordList &keywords1 = *keywordlists[0];
  66. WordList &keywords2 = *keywordlists[1];
  67. // WordList &kw_pldoc = *keywordlists[2];
  68. WordList &kw_sqlplus = *keywordlists[3];
  69. WordList &kw_user1 = *keywordlists[4];
  70. WordList &kw_user2 = *keywordlists[5];
  71. WordList &kw_user3 = *keywordlists[6];
  72. WordList &kw_user4 = *keywordlists[7];
  73. char chAttr = SCE_SQL_IDENTIFIER;
  74. if (wordIsNumber)
  75. chAttr = SCE_SQL_NUMBER;
  76. else if (keywords1.InList(s))
  77. chAttr = SCE_SQL_WORD;
  78. else if (keywords2.InList(s))
  79. chAttr = SCE_SQL_WORD2;
  80. else if (kw_sqlplus.InListAbbreviated(s, '~'))
  81. chAttr = SCE_SQL_SQLPLUS;
  82. else if (kw_user1.InList(s))
  83. chAttr = SCE_SQL_USER1;
  84. else if (kw_user2.InList(s))
  85. chAttr = SCE_SQL_USER2;
  86. else if (kw_user3.InList(s))
  87. chAttr = SCE_SQL_USER3;
  88. else if (kw_user4.InList(s))
  89. chAttr = SCE_SQL_USER4;
  90. styler.ColourTo(end, chAttr);
  91. }
  92. static void ColouriseSQLDoc(unsigned int startPos, int length,
  93. int initStyle, WordList *keywordlists[], Accessor &styler) {
  94. WordList &kw_pldoc = *keywordlists[2];
  95. styler.StartAt(startPos);
  96. bool fold = styler.GetPropertyInt("fold") != 0;
  97. bool sqlBackslashEscapes = styler.GetPropertyInt("sql.backslash.escapes", 0) != 0;
  98. bool sqlBackticksIdentifier = styler.GetPropertyInt("sql.backticks.identifier", 0) != 0;
  99. int lineCurrent = styler.GetLine(startPos);
  100. int spaceFlags = 0;
  101. int state = initStyle;
  102. char chPrev = ' ';
  103. char chNext = styler[startPos];
  104. styler.StartSegment(startPos);
  105. unsigned int lengthDoc = startPos + length;
  106. for (unsigned int i = startPos; i < lengthDoc; i++) {
  107. char ch = chNext;
  108. chNext = styler.SafeGetCharAt(i + 1);
  109. if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
  110. int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags);
  111. int lev = indentCurrent;
  112. if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
  113. // Only non whitespace lines can be headers
  114. int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags);
  115. if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) {
  116. lev |= SC_FOLDLEVELHEADERFLAG;
  117. }
  118. }
  119. if (fold) {
  120. styler.SetLevel(lineCurrent, lev);
  121. }
  122. }
  123. if (styler.IsLeadByte(ch)) {
  124. chNext = styler.SafeGetCharAt(i + 2);
  125. chPrev = ' ';
  126. i += 1;
  127. continue;
  128. }
  129. if (state == SCE_SQL_DEFAULT) {
  130. if (MatchIgnoreCaseSubstring("rem~ark", styler, i)) {
  131. styler.ColourTo(i - 1, state);
  132. state = SCE_SQL_SQLPLUS_COMMENT;
  133. } else if (MatchIgnoreCaseSubstring("pro~mpt", styler, i)) {
  134. styler.ColourTo(i - 1, state);
  135. state = SCE_SQL_SQLPLUS_PROMPT;
  136. } else if (iswordstart(ch)) {
  137. styler.ColourTo(i - 1, state);
  138. state = SCE_SQL_WORD;
  139. } else if (ch == '/' && chNext == '*') {
  140. styler.ColourTo(i - 1, state);
  141. if ((styler.SafeGetCharAt(i + 2)) == '*') { // Support of Doxygen doc. style
  142. state = SCE_SQL_COMMENTDOC;
  143. } else {
  144. state = SCE_SQL_COMMENT;
  145. }
  146. } else if (ch == '-' && chNext == '-') {
  147. styler.ColourTo(i - 1, state);
  148. state = SCE_SQL_COMMENTLINE;
  149. } else if (ch == '#') {
  150. styler.ColourTo(i - 1, state);
  151. state = SCE_SQL_COMMENTLINEDOC;
  152. } else if (ch == '\'') {
  153. styler.ColourTo(i - 1, state);
  154. state = SCE_SQL_CHARACTER;
  155. } else if (ch == '"') {
  156. styler.ColourTo(i - 1, state);
  157. state = SCE_SQL_STRING;
  158. } else if (ch == 0x60 && sqlBackticksIdentifier) {
  159. styler.ColourTo(i - 1, state);
  160. state = SCE_SQL_BACKTICKS_IDENTIFIER;
  161. } else if (isoperator(ch)) {
  162. styler.ColourTo(i - 1, state);
  163. styler.ColourTo(i, SCE_SQL_OPERATOR);
  164. }
  165. } else if (state == SCE_SQL_WORD) {
  166. if (!iswordchar(ch)) {
  167. classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler);
  168. state = SCE_SQL_DEFAULT;
  169. if (ch == '/' && chNext == '*') {
  170. if ((styler.SafeGetCharAt(i + 2)) == '*') { // Support of Doxygen doc. style
  171. state = SCE_SQL_COMMENTDOC;
  172. } else {
  173. state = SCE_SQL_COMMENT;
  174. }
  175. } else if (ch == '-' && chNext == '-') {
  176. state = SCE_SQL_COMMENTLINE;
  177. } else if (ch == '#') {
  178. state = SCE_SQL_COMMENTLINEDOC;
  179. } else if (ch == '\'') {
  180. state = SCE_SQL_CHARACTER;
  181. } else if (ch == '"') {
  182. state = SCE_SQL_STRING;
  183. } else if (ch == 0x60 && sqlBackticksIdentifier) {
  184. state = SCE_SQL_BACKTICKS_IDENTIFIER;
  185. } else if (isoperator(ch)) {
  186. styler.ColourTo(i, SCE_SQL_OPERATOR);
  187. }
  188. }
  189. } else {
  190. if (state == SCE_SQL_COMMENT) {
  191. if (ch == '/' && chPrev == '*') {
  192. if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_C_COMMENT) &&
  193. (styler.GetStartSegment() == startPos)))) {
  194. styler.ColourTo(i, state);
  195. state = SCE_SQL_DEFAULT;
  196. }
  197. }
  198. } else if (state == SCE_SQL_COMMENTDOC) {
  199. if (ch == '/' && chPrev == '*') {
  200. if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_SQL_COMMENTDOC) &&
  201. (styler.GetStartSegment() == startPos)))) {
  202. styler.ColourTo(i, state);
  203. state = SCE_SQL_DEFAULT;
  204. }
  205. } else if (ch == '@') {
  206. // Verify that we have the conditions to mark a comment-doc-keyword
  207. if ((IsASpace(chPrev) || chPrev == '*') && (!IsASpace(chNext))) {
  208. styler.ColourTo(i - 1, state);
  209. state = SCE_SQL_COMMENTDOCKEYWORD;
  210. }
  211. }
  212. } else if (state == SCE_SQL_COMMENTLINE || state == SCE_SQL_COMMENTLINEDOC || state == SCE_SQL_SQLPLUS_COMMENT) {
  213. if (ch == '\r' || ch == '\n') {
  214. styler.ColourTo(i - 1, state);
  215. state = SCE_SQL_DEFAULT;
  216. }
  217. } else if (state == SCE_SQL_COMMENTDOCKEYWORD) {
  218. if (ch == '/' && chPrev == '*') {
  219. styler.ColourTo(i - 1, SCE_SQL_COMMENTDOCKEYWORDERROR);
  220. state = SCE_SQL_DEFAULT;
  221. } else if (!iswordchar(ch)) {
  222. char s[100];
  223. getCurrent(styler.GetStartSegment(), i - 1, styler, s, 30);
  224. if (!kw_pldoc.InList(s + 1)) {
  225. state = SCE_SQL_COMMENTDOCKEYWORDERROR;
  226. }
  227. styler.ColourTo(i - 1, state);
  228. state = SCE_SQL_COMMENTDOC;
  229. }
  230. } else if (state == SCE_SQL_SQLPLUS_PROMPT) {
  231. if (ch == '\r' || ch == '\n') {
  232. styler.ColourTo(i - 1, state);
  233. state = SCE_SQL_DEFAULT;
  234. }
  235. } else if (state == SCE_SQL_CHARACTER) {
  236. if (sqlBackslashEscapes && ch == '\\') {
  237. i++;
  238. ch = chNext;
  239. chNext = styler.SafeGetCharAt(i + 1);
  240. } else if (ch == '\'') {
  241. if (chNext == '\'') {
  242. i++;
  243. } else {
  244. styler.ColourTo(i, state);
  245. state = SCE_SQL_DEFAULT;
  246. i++;
  247. }
  248. ch = chNext;
  249. chNext = styler.SafeGetCharAt(i + 1);
  250. }
  251. } else if (state == SCE_SQL_STRING) {
  252. if (ch == '"') {
  253. if (chNext == '"') {
  254. i++;
  255. } else {
  256. styler.ColourTo(i, state);
  257. state = SCE_SQL_DEFAULT;
  258. i++;
  259. }
  260. ch = chNext;
  261. chNext = styler.SafeGetCharAt(i + 1);
  262. }
  263. } else if (state == SCE_SQL_BACKTICKS_IDENTIFIER) {
  264. if (ch == 0x60) {
  265. if (chNext == 0x60) {
  266. i++;
  267. } else {
  268. styler.ColourTo(i, state);
  269. state = SCE_SQL_DEFAULT;
  270. i++;
  271. }
  272. ch = chNext;
  273. chNext = styler.SafeGetCharAt(i + 1);
  274. }
  275. }
  276. if (state == SCE_SQL_DEFAULT) { // One of the above succeeded
  277. if (ch == '/' && chNext == '*') {
  278. if ((styler.SafeGetCharAt(i + 2)) == '*') { // Support of Doxygen doc. style
  279. state = SCE_SQL_COMMENTDOC;
  280. } else {
  281. state = SCE_SQL_COMMENT;
  282. }
  283. } else if (ch == '-' && chNext == '-') {
  284. state = SCE_SQL_COMMENTLINE;
  285. } else if (ch == '#') {
  286. state = SCE_SQL_COMMENTLINEDOC;
  287. } else if (MatchIgnoreCaseSubstring("rem~ark", styler, i)) {
  288. state = SCE_SQL_SQLPLUS_COMMENT;
  289. } else if (MatchIgnoreCaseSubstring("pro~mpt", styler, i)) {
  290. state = SCE_SQL_SQLPLUS_PROMPT;
  291. } else if (ch == '\'') {
  292. state = SCE_SQL_CHARACTER;
  293. } else if (ch == '"') {
  294. state = SCE_SQL_STRING;
  295. } else if (ch == 0x60 && sqlBackticksIdentifier) {
  296. state = SCE_SQL_BACKTICKS_IDENTIFIER;
  297. } else if (iswordstart(ch)) {
  298. state = SCE_SQL_WORD;
  299. } else if (isoperator(ch)) {
  300. styler.ColourTo(i, SCE_SQL_OPERATOR);
  301. }
  302. }
  303. }
  304. chPrev = ch;
  305. }
  306. styler.ColourTo(lengthDoc - 1, state);
  307. }
  308. static bool IsStreamCommentStyle(int style) {
  309. return style == SCE_SQL_COMMENT ||
  310. style == SCE_SQL_COMMENTDOC ||
  311. style == SCE_SQL_COMMENTDOCKEYWORD ||
  312. style == SCE_SQL_COMMENTDOCKEYWORDERROR;
  313. }
  314. // Store both the current line's fold level and the next lines in the
  315. // level store to make it easy to pick up with each increment
  316. // and to make it possible to fiddle the current level for "} else {".
  317. static void FoldSQLDoc(unsigned int startPos, int length, int initStyle,
  318. WordList *[], Accessor &styler) {
  319. bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
  320. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  321. unsigned int endPos = startPos + length;
  322. int visibleChars = 0;
  323. int lineCurrent = styler.GetLine(startPos);
  324. int levelCurrent = SC_FOLDLEVELBASE;
  325. if (lineCurrent > 0)
  326. levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
  327. int levelNext = levelCurrent;
  328. char chNext = styler[startPos];
  329. int styleNext = styler.StyleAt(startPos);
  330. int style = initStyle;
  331. bool endFound = false;
  332. for (unsigned int i = startPos; i < endPos; i++) {
  333. char ch = chNext;
  334. chNext = styler.SafeGetCharAt(i + 1);
  335. int stylePrev = style;
  336. style = styleNext;
  337. styleNext = styler.StyleAt(i + 1);
  338. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  339. if (foldComment && IsStreamCommentStyle(style)) {
  340. if (!IsStreamCommentStyle(stylePrev)) {
  341. levelNext++;
  342. } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
  343. // Comments don't end at end of line and the next character may be unstyled.
  344. levelNext--;
  345. }
  346. }
  347. if (foldComment && (style == SCE_SQL_COMMENTLINE)) {
  348. if ((ch == '-') && (chNext == '-')) {
  349. char chNext2 = styler.SafeGetCharAt(i + 2);
  350. if (chNext2 == '{') {
  351. levelNext++;
  352. } else if (chNext2 == '}') {
  353. levelNext--;
  354. }
  355. }
  356. }
  357. if (style == SCE_SQL_WORD) {
  358. if (MatchIgnoreCaseSubstring("elsif", styler, i)) {
  359. // ignore elsif
  360. i += 4;
  361. } else if (MatchIgnoreCaseSubstring("if", styler, i)
  362. || MatchIgnoreCaseSubstring("loop", styler, i)){
  363. if (endFound){
  364. // ignore
  365. endFound = false;
  366. } else {
  367. levelNext++;
  368. }
  369. } else if (MatchIgnoreCaseSubstring("begin", styler, i)){
  370. levelNext++;
  371. } else if (MatchIgnoreCaseSubstring("end", styler, i)) {
  372. endFound = true;
  373. levelNext--;
  374. if (levelNext < SC_FOLDLEVELBASE)
  375. levelNext = SC_FOLDLEVELBASE;
  376. }
  377. }
  378. if (atEOL) {
  379. int levelUse = levelCurrent;
  380. int lev = levelUse | levelNext << 16;
  381. if (visibleChars == 0 && foldCompact)
  382. lev |= SC_FOLDLEVELWHITEFLAG;
  383. if (levelUse < levelNext)
  384. lev |= SC_FOLDLEVELHEADERFLAG;
  385. if (lev != styler.LevelAt(lineCurrent)) {
  386. styler.SetLevel(lineCurrent, lev);
  387. }
  388. lineCurrent++;
  389. levelCurrent = levelNext;
  390. visibleChars = 0;
  391. endFound = false;
  392. }
  393. if (!isspacechar(ch))
  394. visibleChars++;
  395. }
  396. }
  397. static const char * const sqlWordListDesc[] = {
  398. "Keywords",
  399. "Database Objects",
  400. "PLDoc",
  401. "SQL*Plus",
  402. "User Keywords 1",
  403. "User Keywords 2",
  404. "User Keywords 3",
  405. "User Keywords 4",
  406. 0
  407. };
  408. LexerModule lmSQL(SCLEX_SQL, ColouriseSQLDoc, "sql", FoldSQLDoc, sqlWordListDesc);