LexMagik.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. // Scintilla source code edit control
  2. /**
  3. * @file LexMagik.cxx
  4. * Lexer for GE(r) Smallworld(tm) MagikSF
  5. */
  6. // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
  7. // The License.txt file describes the conditions under which this software may be distributed.
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include <assert.h>
  13. #include <ctype.h>
  14. #include "ILexer.h"
  15. #include "Scintilla.h"
  16. #include "SciLexer.h"
  17. #include "WordList.h"
  18. #include "LexAccessor.h"
  19. #include "Accessor.h"
  20. #include "StyleContext.h"
  21. #include "CharacterSet.h"
  22. #include "LexerModule.h"
  23. #ifdef SCI_NAMESPACE
  24. using namespace Scintilla;
  25. #endif
  26. /**
  27. * Is it a core character (C isalpha(), exclamation and question mark)
  28. *
  29. * \param ch The character
  30. * \return True if ch is a character, False otherwise
  31. */
  32. static inline bool IsAlphaCore(int ch) {
  33. return (isalpha(ch) || ch == '!' || ch == '?');
  34. }
  35. /**
  36. * Is it a character (IsAlphaCore() and underscore)
  37. *
  38. * \param ch The character
  39. * \return True if ch is a character, False otherwise
  40. */
  41. static inline bool IsAlpha(int ch) {
  42. return (IsAlphaCore(ch) || ch == '_');
  43. }
  44. /**
  45. * Is it a symbolic character (IsAlpha() and colon)
  46. *
  47. * \param ch The character
  48. * \return True if ch is a character, False otherwise
  49. */
  50. static inline bool IsAlphaSym(int ch) {
  51. return (IsAlpha(ch) || ch == ':');
  52. }
  53. /**
  54. * Is it a numerical character (IsAlpha() and 0 - 9)
  55. *
  56. * \param ch The character
  57. * \return True if ch is a character, False otherwise
  58. */
  59. static inline bool IsAlNum(int ch) {
  60. return ((ch >= '0' && ch <= '9') || IsAlpha(ch));
  61. }
  62. /**
  63. * Is it a symbolic numerical character (IsAlNum() and colon)
  64. *
  65. * \param ch The character
  66. * \return True if ch is a character, False otherwise
  67. */
  68. static inline bool IsAlNumSym(int ch) {
  69. return (IsAlNum(ch) || ch == ':');
  70. }
  71. /**
  72. * The lexer function
  73. *
  74. * \param startPos Where to start scanning
  75. * \param length Where to scan to
  76. * \param initStyle The style at the initial point, not used in this folder
  77. * \param keywordslists The keywordslists, currently, number 5 is used
  78. * \param styler The styler
  79. */
  80. static void ColouriseMagikDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
  81. WordList *keywordlists[], Accessor &styler) {
  82. styler.StartAt(startPos);
  83. WordList &keywords = *keywordlists[0];
  84. WordList &pragmatics = *keywordlists[1];
  85. WordList &containers = *keywordlists[2];
  86. WordList &flow = *keywordlists[3];
  87. WordList &characters = *keywordlists[4];
  88. StyleContext sc(startPos, length, initStyle, styler);
  89. for (; sc.More(); sc.Forward()) {
  90. repeat:
  91. if(sc.ch == '#') {
  92. if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);
  93. else sc.SetState(SCE_MAGIK_COMMENT);
  94. for(; sc.More() && !(sc.atLineEnd); sc.Forward());
  95. sc.SetState(SCE_MAGIK_DEFAULT);
  96. goto repeat;
  97. }
  98. if(sc.ch == '"') {
  99. sc.SetState(SCE_MAGIK_STRING);
  100. if(sc.More())
  101. {
  102. sc.Forward();
  103. for(; sc.More() && sc.ch != '"'; sc.Forward());
  104. }
  105. sc.ForwardSetState(SCE_MAGIK_DEFAULT);
  106. goto repeat;
  107. }
  108. // The default state
  109. if(sc.state == SCE_MAGIK_DEFAULT) {
  110. // A certain keyword has been detected
  111. if (sc.ch == '_' && (
  112. sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {
  113. char keyword[50];
  114. memset(keyword, '\0', 50);
  115. for(
  116. int scanPosition = 0;
  117. scanPosition < 50;
  118. scanPosition++) {
  119. char keywordChar = static_cast<char>(
  120. tolower(styler.SafeGetCharAt(
  121. scanPosition +
  122. static_cast<Sci_Position>(sc.currentPos+1), ' ')));
  123. if(IsAlpha(keywordChar)) {
  124. keyword[scanPosition] = keywordChar;
  125. } else {
  126. break;
  127. }
  128. }
  129. // It is a pragma
  130. if(pragmatics.InList(keyword)) {
  131. sc.SetState(SCE_MAGIK_PRAGMA);
  132. }
  133. // it is a normal keyword like _local, _self, etc.
  134. else if(keywords.InList(keyword)) {
  135. sc.SetState(SCE_MAGIK_KEYWORD);
  136. }
  137. // It is a container keyword, such as _method, _proc, etc.
  138. else if(containers.InList(keyword)) {
  139. sc.SetState(SCE_MAGIK_CONTAINER);
  140. }
  141. // It is a flow keyword, such as _for, _if, _try, etc.
  142. else if(flow.InList(keyword)) {
  143. sc.SetState(SCE_MAGIK_FLOW);
  144. }
  145. // Interpret as unknown keyword
  146. else {
  147. sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);
  148. }
  149. }
  150. // Symbolic expression
  151. else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {
  152. sc.SetState(SCE_MAGIK_SYMBOL);
  153. bool firstTrip = true;
  154. for(sc.Forward(); sc.More(); sc.Forward()) {
  155. if(firstTrip && IsAlphaSym(sc.ch));
  156. else if(!firstTrip && IsAlNumSym(sc.ch));
  157. else if(sc.ch == '|') {
  158. for(sc.Forward();
  159. sc.More() && sc.ch != '|';
  160. sc.Forward());
  161. }
  162. else break;
  163. firstTrip = false;
  164. }
  165. sc.SetState(SCE_MAGIK_DEFAULT);
  166. goto repeat;
  167. }
  168. // Identifier (label) expression
  169. else if(sc.ch == '@') {
  170. sc.SetState(SCE_MAGIK_IDENTIFIER);
  171. bool firstTrip = true;
  172. for(sc.Forward(); sc.More(); sc.Forward()) {
  173. if(firstTrip && IsAlphaCore(sc.ch)) {
  174. firstTrip = false;
  175. }
  176. else if(!firstTrip && IsAlpha(sc.ch));
  177. else break;
  178. }
  179. sc.SetState(SCE_MAGIK_DEFAULT);
  180. goto repeat;
  181. }
  182. // Start of a character
  183. else if(sc.ch == '%') {
  184. sc.SetState(SCE_MAGIK_CHARACTER);
  185. sc.Forward();
  186. char keyword[50];
  187. memset(keyword, '\0', 50);
  188. for(
  189. int scanPosition = 0;
  190. scanPosition < 50;
  191. scanPosition++) {
  192. char keywordChar = static_cast<char>(
  193. tolower(styler.SafeGetCharAt(
  194. scanPosition +
  195. static_cast<int>(sc.currentPos), ' ')));
  196. if(IsAlpha(keywordChar)) {
  197. keyword[scanPosition] = keywordChar;
  198. } else {
  199. break;
  200. }
  201. }
  202. if(characters.InList(keyword)) {
  203. sc.Forward(static_cast<int>(strlen(keyword)));
  204. } else {
  205. sc.Forward();
  206. }
  207. sc.SetState(SCE_MAGIK_DEFAULT);
  208. goto repeat;
  209. }
  210. // Operators
  211. else if(
  212. sc.ch == '>' ||
  213. sc.ch == '<' ||
  214. sc.ch == '.' ||
  215. sc.ch == ',' ||
  216. sc.ch == '+' ||
  217. sc.ch == '-' ||
  218. sc.ch == '/' ||
  219. sc.ch == '*' ||
  220. sc.ch == '~' ||
  221. sc.ch == '$' ||
  222. sc.ch == '=') {
  223. sc.SetState(SCE_MAGIK_OPERATOR);
  224. }
  225. // Braces
  226. else if(sc.ch == '(' || sc.ch == ')') {
  227. sc.SetState(SCE_MAGIK_BRACE_BLOCK);
  228. }
  229. // Brackets
  230. else if(sc.ch == '{' || sc.ch == '}') {
  231. sc.SetState(SCE_MAGIK_BRACKET_BLOCK);
  232. }
  233. // Square Brackets
  234. else if(sc.ch == '[' || sc.ch == ']') {
  235. sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);
  236. }
  237. }
  238. // It is an operator
  239. else if(
  240. sc.state == SCE_MAGIK_OPERATOR ||
  241. sc.state == SCE_MAGIK_BRACE_BLOCK ||
  242. sc.state == SCE_MAGIK_BRACKET_BLOCK ||
  243. sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {
  244. sc.SetState(SCE_MAGIK_DEFAULT);
  245. goto repeat;
  246. }
  247. // It is the pragma state
  248. else if(sc.state == SCE_MAGIK_PRAGMA) {
  249. if(!IsAlpha(sc.ch)) {
  250. sc.SetState(SCE_MAGIK_DEFAULT);
  251. goto repeat;
  252. }
  253. }
  254. // It is the keyword state
  255. else if(
  256. sc.state == SCE_MAGIK_KEYWORD ||
  257. sc.state == SCE_MAGIK_CONTAINER ||
  258. sc.state == SCE_MAGIK_FLOW ||
  259. sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {
  260. if(!IsAlpha(sc.ch)) {
  261. sc.SetState(SCE_MAGIK_DEFAULT);
  262. goto repeat;
  263. }
  264. }
  265. }
  266. sc.Complete();
  267. }
  268. /**
  269. * The word list description
  270. */
  271. static const char * const magikWordListDesc[] = {
  272. "Accessors (local, global, self, super, thisthread)",
  273. "Pragmatic (pragma, private)",
  274. "Containers (method, block, proc)",
  275. "Flow (if, then, elif, else)",
  276. "Characters (space, tab, newline, return)",
  277. "Fold Containers (method, proc, block, if, loop)",
  278. 0};
  279. /**
  280. * This function detects keywords which are able to have a body. Note that it
  281. * uses the Fold Containers word description, not the containers description. It
  282. * only works when the style at that particular position is set on Containers
  283. * or Flow (number 3 or 4).
  284. *
  285. * \param keywordslist The list of keywords that are scanned, they should only
  286. * contain the start keywords, not the end keywords
  287. * \param The actual keyword
  288. * \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword
  289. * 0 otherwise
  290. */
  291. static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {
  292. if(
  293. strlen(keyword) > 3 &&
  294. keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {
  295. if (keywordslist.InList(keyword + 3)) {
  296. return -1;
  297. }
  298. } else {
  299. if(keywordslist.InList(keyword)) {
  300. return 1;
  301. }
  302. }
  303. return 0;
  304. }
  305. /**
  306. * The folding function
  307. *
  308. * \param startPos Where to start scanning
  309. * \param length Where to scan to
  310. * \param keywordslists The keywordslists, currently, number 5 is used
  311. * \param styler The styler
  312. */
  313. static void FoldMagikDoc(Sci_PositionU startPos, Sci_Position length, int,
  314. WordList *keywordslists[], Accessor &styler) {
  315. bool compact = styler.GetPropertyInt("fold.compact") != 0;
  316. WordList &foldingElements = *keywordslists[5];
  317. Sci_Position endPos = startPos + length;
  318. Sci_Position line = styler.GetLine(startPos);
  319. int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
  320. int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
  321. for(
  322. Sci_Position currentPos = startPos;
  323. currentPos < endPos;
  324. currentPos++) {
  325. char currentState = styler.StyleAt(currentPos);
  326. char c = styler.SafeGetCharAt(currentPos, ' ');
  327. Sci_Position prevLine = styler.GetLine(currentPos - 1);
  328. line = styler.GetLine(currentPos);
  329. // Default situation
  330. if(prevLine < line) {
  331. styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);
  332. flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
  333. }
  334. if(
  335. (
  336. currentState == SCE_MAGIK_CONTAINER ||
  337. currentState == SCE_MAGIK_FLOW
  338. ) &&
  339. c == '_') {
  340. char keyword[50];
  341. memset(keyword, '\0', 50);
  342. for(
  343. int scanPosition = 0;
  344. scanPosition < 50;
  345. scanPosition++) {
  346. char keywordChar = static_cast<char>(
  347. tolower(styler.SafeGetCharAt(
  348. scanPosition +
  349. currentPos + 1, ' ')));
  350. if(IsAlpha(keywordChar)) {
  351. keyword[scanPosition] = keywordChar;
  352. } else {
  353. break;
  354. }
  355. }
  356. if(IsFoldingContainer(foldingElements, keyword) > 0) {
  357. styler.SetLevel(
  358. line,
  359. styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
  360. level++;
  361. } else if(IsFoldingContainer(foldingElements, keyword) < 0) {
  362. styler.SetLevel(line, styler.LevelAt(line));
  363. level--;
  364. }
  365. }
  366. if(
  367. compact && (
  368. currentState == SCE_MAGIK_BRACE_BLOCK ||
  369. currentState == SCE_MAGIK_BRACKET_BLOCK ||
  370. currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {
  371. if(c == '{' || c == '[' || c == '(') {
  372. styler.SetLevel(
  373. line,
  374. styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
  375. level++;
  376. } else if(c == '}' || c == ']' || c == ')') {
  377. styler.SetLevel(line, styler.LevelAt(line));
  378. level--;
  379. }
  380. }
  381. }
  382. }
  383. /**
  384. * Injecting the module
  385. */
  386. LexerModule lmMagikSF(
  387. SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);