1 // Scintilla source code edit control
\r
3 ** Lexer for the GAP language. (The GAP System for Computational Discrete Algebra)
\r
4 ** http://www.gap-system.org
\r
6 // Copyright 2007 by Istvan Szollosi ( szteven <at> gmail <dot> com )
\r
7 // The License.txt file describes the conditions under which this software may be distributed.
\r
15 #include "Platform.h"
\r
17 #include "PropSet.h"
\r
18 #include "Accessor.h"
\r
19 #include "StyleContext.h"
\r
20 #include "KeyWords.h"
\r
21 #include "Scintilla.h"
\r
22 #include "SciLexer.h"
\r
24 #ifdef SCI_NAMESPACE
\r
25 using namespace Scintilla;
\r
28 static inline bool IsGAPOperator(char ch) {
\r
29 if (isalnum(ch)) return false;
\r
30 if (ch == '+' || ch == '-' || ch == '*' || ch == '/' ||
\r
31 ch == '^' || ch == ',' || ch == '!' || ch == '.' ||
\r
32 ch == '=' || ch == '<' || ch == '>' || ch == '(' ||
\r
33 ch == ')' || ch == ';' || ch == '[' || ch == ']' ||
\r
34 ch == '{' || ch == '}' || ch == ':' )
\r
39 static void GetRange(unsigned int start, unsigned int end, Accessor &styler, char *s, unsigned int len) {
\r
41 while ((i < end - start + 1) && (i < len-1)) {
\r
42 s[i] = static_cast<char>(styler[start + i]);
\r
48 static void ColouriseGAPDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) {
\r
50 WordList &keywords1 = *keywordlists[0];
\r
51 WordList &keywords2 = *keywordlists[1];
\r
52 WordList &keywords3 = *keywordlists[2];
\r
53 WordList &keywords4 = *keywordlists[3];
\r
55 // Do not leak onto next line
\r
56 if (initStyle == SCE_GAP_STRINGEOL) initStyle = SCE_GAP_DEFAULT;
\r
58 StyleContext sc(startPos, length, initStyle, styler);
\r
60 for (; sc.More(); sc.Forward()) {
\r
62 // Prevent SCE_GAP_STRINGEOL from leaking back to previous line
\r
63 if ( sc.atLineStart ) {
\r
64 if (sc.state == SCE_GAP_STRING) sc.SetState(SCE_GAP_STRING);
\r
65 if (sc.state == SCE_GAP_CHAR) sc.SetState(SCE_GAP_CHAR);
\r
68 // Handle line continuation generically
\r
69 if (sc.ch == '\\' ) {
\r
70 if (sc.chNext == '\n' || sc.chNext == '\r') {
\r
72 if (sc.ch == '\r' && sc.chNext == '\n') {
\r
79 // Determine if the current state should terminate
\r
81 case SCE_GAP_OPERATOR :
\r
82 sc.SetState(SCE_GAP_DEFAULT);
\r
85 case SCE_GAP_NUMBER :
\r
86 if (!IsADigit(sc.ch)) {
\r
87 if (sc.ch == '\\') {
\r
88 if (!sc.atLineEnd) {
\r
89 if (!IsADigit(sc.chNext)) {
\r
91 sc.ChangeState(SCE_GAP_IDENTIFIER);
\r
94 } else if (isalpha(sc.ch) || sc.ch == '_') {
\r
95 sc.ChangeState(SCE_GAP_IDENTIFIER);
\r
97 else sc.SetState(SCE_GAP_DEFAULT);
\r
101 case SCE_GAP_IDENTIFIER :
\r
102 if (!(iswordstart(static_cast<char>(sc.ch)) || sc.ch == '$')) {
\r
103 if (sc.ch == '\\') sc.Forward();
\r
106 sc.GetCurrent(s, sizeof(s));
\r
107 if (keywords1.InList(s)) {
\r
108 sc.ChangeState(SCE_GAP_KEYWORD);
\r
109 } else if (keywords2.InList(s)) {
\r
110 sc.ChangeState(SCE_GAP_KEYWORD2);
\r
111 } else if (keywords3.InList(s)) {
\r
112 sc.ChangeState(SCE_GAP_KEYWORD3);
\r
113 } else if (keywords4.InList(s)) {
\r
114 sc.ChangeState(SCE_GAP_KEYWORD4);
\r
116 sc.SetState(SCE_GAP_DEFAULT);
\r
121 case SCE_GAP_COMMENT :
\r
122 if (sc.atLineEnd) {
\r
123 sc.SetState(SCE_GAP_DEFAULT);
\r
127 case SCE_GAP_STRING:
\r
128 if (sc.atLineEnd) {
\r
129 sc.ChangeState(SCE_GAP_STRINGEOL);
\r
130 } else if (sc.ch == '\\') {
\r
131 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
\r
134 } else if (sc.ch == '\"') {
\r
135 sc.ForwardSetState(SCE_GAP_DEFAULT);
\r
140 if (sc.atLineEnd) {
\r
141 sc.ChangeState(SCE_GAP_STRINGEOL);
\r
142 } else if (sc.ch == '\\') {
\r
143 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
\r
146 } else if (sc.ch == '\'') {
\r
147 sc.ForwardSetState(SCE_GAP_DEFAULT);
\r
151 case SCE_GAP_STRINGEOL:
\r
152 if (sc.atLineStart) {
\r
153 sc.SetState(SCE_GAP_DEFAULT);
\r
158 // Determine if a new state should be entered
\r
159 if (sc.state == SCE_GAP_DEFAULT) {
\r
160 if (IsGAPOperator(static_cast<char>(sc.ch))) {
\r
161 sc.SetState(SCE_GAP_OPERATOR);
\r
163 else if (IsADigit(sc.ch)) {
\r
164 sc.SetState(SCE_GAP_NUMBER);
\r
165 } else if (isalpha(sc.ch) || sc.ch == '_' || sc.ch == '\\' || sc.ch == '$' || sc.ch == '~') {
\r
166 sc.SetState(SCE_GAP_IDENTIFIER);
\r
167 if (sc.ch == '\\') sc.Forward();
\r
168 } else if (sc.ch == '#') {
\r
169 sc.SetState(SCE_GAP_COMMENT);
\r
170 } else if (sc.ch == '\"') {
\r
171 sc.SetState(SCE_GAP_STRING);
\r
172 } else if (sc.ch == '\'') {
\r
173 sc.SetState(SCE_GAP_CHAR);
\r
181 static int ClassifyFoldPointGAP(const char* s) {
\r
183 if (strcmp(s, "function") == 0 ||
\r
184 strcmp(s, "do") == 0 ||
\r
185 strcmp(s, "if") == 0 ||
\r
186 strcmp(s, "repeat") == 0 ) {
\r
188 } else if (strcmp(s, "end") == 0 ||
\r
189 strcmp(s, "od") == 0 ||
\r
190 strcmp(s, "fi") == 0 ||
\r
191 strcmp(s, "until") == 0 ) {
\r
197 static void FoldGAPDoc( unsigned int startPos, int length, int initStyle, WordList** , Accessor &styler) {
\r
198 unsigned int endPos = startPos + length;
\r
199 int visibleChars = 0;
\r
200 int lineCurrent = styler.GetLine(startPos);
\r
201 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
\r
202 int levelCurrent = levelPrev;
\r
203 char chNext = styler[startPos];
\r
204 int styleNext = styler.StyleAt(startPos);
\r
205 int style = initStyle;
\r
209 for (unsigned int i = startPos; i < endPos; i++) {
\r
211 chNext = styler.SafeGetCharAt(i + 1);
\r
212 int stylePrev = style;
\r
214 styleNext = styler.StyleAt(i + 1);
\r
215 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
\r
217 if (stylePrev != SCE_GAP_KEYWORD && style == SCE_GAP_KEYWORD) {
\r
218 // Store last word start point.
\r
222 if (stylePrev == SCE_GAP_KEYWORD) {
\r
223 if(iswordchar(ch) && !iswordchar(chNext)) {
\r
225 GetRange(lastStart, i, styler, s, sizeof(s));
\r
226 levelCurrent += ClassifyFoldPointGAP(s);
\r
231 int lev = levelPrev;
\r
232 if ((levelCurrent > levelPrev) && (visibleChars > 0))
\r
233 lev |= SC_FOLDLEVELHEADERFLAG;
\r
234 if (lev != styler.LevelAt(lineCurrent)) {
\r
235 styler.SetLevel(lineCurrent, lev);
\r
238 levelPrev = levelCurrent;
\r
242 if (!isspacechar(ch))
\r
246 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
\r
247 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
\r
250 static const char * const GAPWordListDesc[] = {
\r
253 "Keywords 3 (unused)",
\r
254 "Keywords 4 (unused)",
\r