--- /dev/null
+// Scintilla source code edit control\r
+/** @file LexProgress.cxx\r
+ ** Lexer for Progress 4GL.\r
+ ** Based on LexCPP.cxx of Neil Hodgson <neilh@scintilla.org>\r
+ **/\r
+// Copyright 2006-2007 by Yuval Papish <Yuval@YuvCom.com>\r
+// The License.txt file describes the conditions under which this software may be distributed.\r
+\r
+/** TODO:\r
+WebSpeed support in html lexer\r
+Support "end triggers" expression of the triggers phrase\r
+change lmPS to lmProgress\r
+Support more than 6 comments levels\r
+**/\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+\r
+#include "Platform.h"\r
+\r
+#include "PropSet.h"\r
+#include "Accessor.h"\r
+#include "StyleContext.h"\r
+#include "KeyWords.h"\r
+#include "Scintilla.h"\r
+#include "SciLexer.h"\r
+\r
+#ifdef SCI_NAMESPACE\r
+using namespace Scintilla;\r
+#endif\r
+\r
+static inline bool IsAWordChar(int ch) {\r
+ return (ch < 0x80) && (isalnum(ch) || ch == '_');\r
+}\r
+\r
+static inline bool IsAWordStart(int ch) {\r
+ return (ch < 0x80) && (isalpha(ch) || ch == '_');\r
+}\r
+\r
+enum SentenceStart { SetSentenceStart = 0xf, ResetSentenceStart = 0x10}; // true -> bit = 0\r
+\r
+static void Colourise4glDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],\r
+ Accessor &styler) {\r
+\r
+ WordList &keywords1 = *keywordlists[0];\r
+ WordList &keywords2 = *keywordlists[1];\r
+ WordList &keywords3 = *keywordlists[2];\r
+ //WordList &keywords4 = *keywordlists[3];\r
+ //WordList &keywords5 = *keywordlists[4];\r
+\r
+ int visibleChars = 0;\r
+ int mask;\r
+\r
+ StyleContext sc(startPos, length, initStyle, styler);\r
+\r
+ for (; sc.More(); sc.Forward()) {\r
+\r
+ if (sc.atLineStart) {\r
+ // Reset states to begining of colourise so no surprises\r
+ // if different sets of lines lexed.\r
+ visibleChars = 0;\r
+ }\r
+\r
+ // Handle line continuation generically.\r
+ if (sc.ch == '~') {\r
+ if (sc.chNext > ' ') {\r
+ // skip special char after ~\r
+ sc.Forward();\r
+ continue;\r
+ }\r
+ else {\r
+ // Skip whitespace between ~ and EOL\r
+ while (sc.More() && (sc.chNext == ' ' || sc.chNext == '\t') ) {\r
+ sc.Forward();\r
+ }\r
+ if (sc.chNext == '\n' || sc.chNext == '\r') {\r
+ sc.Forward();\r
+ if (sc.ch == '\r' && sc.chNext == '\n') {\r
+ sc.Forward();\r
+ }\r
+ sc.Forward();\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ // Determine if a new state should be terminated.\r
+ mask = sc.state & 0x10;\r
+ switch (sc.state & 0xf) {\r
+ case SCE_4GL_OPERATOR:\r
+ sc.SetState(SCE_4GL_DEFAULT | mask);\r
+ break;\r
+ case SCE_4GL_NUMBER:\r
+ if (!(IsADigit(sc.ch))) {\r
+ sc.SetState(SCE_4GL_DEFAULT | mask);\r
+ }\r
+ break;\r
+ case SCE_4GL_IDENTIFIER:\r
+ if (!IsAWordChar(sc.ch) && sc.ch != '-') {\r
+ char s[1000];\r
+ sc.GetCurrentLowered(s, sizeof(s));\r
+ if (((sc.state & 0x10) == 0) && keywords2.InList(s) || keywords3.InList(s)) {\r
+ sc.ChangeState(SCE_4GL_BLOCK | ResetSentenceStart);\r
+ }\r
+ else if (keywords1.InList(s)) {\r
+ if ((s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !isalnum(s[3]) && s[3] != '-') ||\r
+ (s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !isalnum(s[7]))) {\r
+ sc.ChangeState(SCE_4GL_END | ResetSentenceStart);\r
+ }\r
+ else if ((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') ||\r
+ (s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) {\r
+ sc.ChangeState(SCE_4GL_WORD & SetSentenceStart);\r
+ }\r
+ else {\r
+ sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart);\r
+ }\r
+ }\r
+ sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10));\r
+ }\r
+ break;\r
+ case SCE_4GL_PREPROCESSOR:\r
+ if (sc.atLineStart) {\r
+ sc.SetState(SCE_4GL_DEFAULT & SetSentenceStart);\r
+ } else if (sc.ch == '*' && sc.chNext == '/') {\r
+ sc.ForwardSetState(SCE_4GL_DEFAULT | mask);\r
+ }\r
+ break;\r
+ case SCE_4GL_STRING:\r
+ if (sc.ch == '\"') {\r
+ sc.ForwardSetState(SCE_4GL_DEFAULT | mask);\r
+ }\r
+ break;\r
+ case SCE_4GL_CHARACTER:\r
+ if (sc.ch == '\'') {\r
+ sc.ForwardSetState(SCE_4GL_DEFAULT | mask);\r
+ }\r
+ break;\r
+ default:\r
+ if ((sc.state & 0xf) >= SCE_4GL_COMMENT1) {\r
+ if (sc.ch == '*' && sc.chNext == '/') {\r
+ sc.Forward();\r
+ if ((sc.state & 0xf) == SCE_4GL_COMMENT1) {\r
+ sc.ForwardSetState(SCE_4GL_DEFAULT | mask);\r
+ }\r
+ else\r
+ sc.SetState((sc.state & 0x1f) - 1);\r
+ } else if (sc.ch == '/' && sc.chNext == '*') {\r
+ sc.Forward();\r
+ sc.SetState((sc.state & 0x1f) + 1);\r
+ }\r
+ }\r
+ }\r
+\r
+ // Determine if a new state should be entered.\r
+ mask = sc.state & 0x10;\r
+ if ((sc.state & 0xf) == SCE_4GL_DEFAULT) {\r
+ if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {\r
+ sc.SetState(SCE_4GL_NUMBER | ResetSentenceStart);\r
+ } else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {\r
+ sc.SetState(SCE_4GL_IDENTIFIER | mask);\r
+ } else if (sc.ch == '/' && sc.chNext == '*') {\r
+ sc.SetState(SCE_4GL_COMMENT1 | mask);\r
+ sc.Forward();\r
+ } else if (sc.ch == '\"') {\r
+ sc.SetState(SCE_4GL_STRING | ResetSentenceStart);\r
+ } else if (sc.ch == '\'') {\r
+ sc.SetState(SCE_4GL_CHARACTER | ResetSentenceStart);\r
+ } else if (sc.ch == '&' && visibleChars == 0 && ((sc.state & 0x10) == 0)) {\r
+ sc.SetState(SCE_4GL_PREPROCESSOR | ResetSentenceStart);\r
+ // Skip whitespace between & and preprocessor word\r
+ do {\r
+ sc.Forward();\r
+ } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());\r
+ // Handle syntactical line termination\r
+ } else if ((sc.ch == '.' || sc.ch == ':' || sc.ch == '}') && (sc.chNext == ' ' || sc.chNext == '\t' || sc.chNext == '\n' || sc.chNext == '\r')) {\r
+ sc.SetState(sc.state & SetSentenceStart);\r
+ } else if (isoperator(static_cast<char>(sc.ch))) {\r
+ if (sc.ch == ':')\r
+ sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart);\r
+ else\r
+ sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart);\r
+ }\r
+ }\r
+\r
+ if (!IsASpace(sc.ch)) {\r
+ visibleChars++;\r
+ }\r
+ }\r
+ sc.Complete();\r
+}\r
+\r
+static bool IsStreamCommentStyle(int style) {\r
+ return (style & 0xf) >= SCE_4GL_COMMENT1 ;\r
+}\r
+\r
+// Store both the current line's fold level and the next lines in the\r
+// level store to make it easy to pick up with each increment\r
+// and to make it possible to fiddle the current level for "} else {".\r
+static void FoldNoBox4glDoc(unsigned int startPos, int length, int initStyle,\r
+ Accessor &styler) {\r
+ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;\r
+ bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;\r
+ bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;\r
+ unsigned int endPos = startPos + length;\r
+ int visibleChars = 0;\r
+ int lineCurrent = styler.GetLine(startPos);\r
+ int levelCurrent = SC_FOLDLEVELBASE;\r
+ if (lineCurrent > 0)\r
+ levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;\r
+ int levelMinCurrent = levelCurrent;\r
+ int levelNext = levelCurrent;\r
+ char chNext = static_cast<char>(tolower(styler[startPos]));\r
+ int styleNext = styler.StyleAt(startPos);\r
+ int style = initStyle;\r
+ for (unsigned int i = startPos; i < endPos; i++) {\r
+ char ch = chNext;\r
+ chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));\r
+ int stylePrev = style;\r
+ style = styleNext;\r
+ styleNext = styler.StyleAt(i + 1);\r
+ bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');\r
+ if (foldComment && IsStreamCommentStyle(style)) {\r
+ if (!IsStreamCommentStyle(stylePrev)) {\r
+ levelNext++;\r
+ } else if (!IsStreamCommentStyle(styleNext)) { // && !atEOL) {\r
+ // Comments don't end at end of line and the next character may be unstyled.\r
+ levelNext--;\r
+ }\r
+ }\r
+ else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) {\r
+ levelNext++;\r
+ }\r
+ else if ((style & 0xf) == SCE_4GL_END && (ch == 'e' || ch == 'f')) {\r
+ levelNext--;\r
+ }\r
+ if (atEOL) {\r
+ int levelUse = levelCurrent;\r
+ if (foldAtElse) {\r
+ levelUse = levelMinCurrent;\r
+ }\r
+ int lev = levelUse | levelNext << 16;\r
+ if (visibleChars == 0 && foldCompact)\r
+ lev |= SC_FOLDLEVELWHITEFLAG;\r
+ if (levelUse < levelNext)\r
+ lev |= SC_FOLDLEVELHEADERFLAG;\r
+ if (lev != styler.LevelAt(lineCurrent)) {\r
+ styler.SetLevel(lineCurrent, lev);\r
+ }\r
+ lineCurrent++;\r
+ levelCurrent = levelNext;\r
+ levelMinCurrent = levelCurrent;\r
+ visibleChars = 0;\r
+ }\r
+ if (!isspacechar(ch))\r
+ visibleChars++;\r
+ }\r
+}\r
+\r
+static void Fold4glDoc(unsigned int startPos, int length, int initStyle, WordList *[],\r
+ Accessor &styler) {\r
+ FoldNoBox4glDoc(startPos, length, initStyle, styler);\r
+}\r
+\r
+static const char * const FglWordLists[] = {\r
+ "Primary keywords and identifiers",\r
+ "Secondary keywords and identifiers",\r
+ "Documentation comment keywords",\r
+ "Unused",\r
+ "Global classes and typedefs",\r
+ 0,\r
+ };\r
+\r
+LexerModule lmProgress(SCLEX_PS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists);\r
+\r
+\r