1 // SciTE - Scintilla based Text Editor
2 /** @file LexAVE.cxx
3 ** Lexer for Avenue.
4 **
5 ** Written by Alexey Yutkin <yutkin@geol.msu.ru>.
6 **/
7 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
8 // The License.txt file describes the conditions under which this software may be distributed.
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <assert.h>
15 #include <ctype.h>
16
17 #include "ILexer.h"
18 #include "Scintilla.h"
19 #include "SciLexer.h"
20
21 #include "WordList.h"
22 #include "LexAccessor.h"
23 #include "Accessor.h"
24 #include "StyleContext.h"
25 #include "CharacterSet.h"
26 #include "LexerModule.h"
27
28 using namespace Scintilla;
29
30
IsAWordChar(const int ch)31 static inline bool IsAWordChar(const int ch) {
32 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
33 }
IsEnumChar(const int ch)34 static inline bool IsEnumChar(const int ch) {
35 return (ch < 0x80) && (isalnum(ch)|| ch == '_');
36 }
IsANumberChar(const int ch)37 static inline bool IsANumberChar(const int ch) {
38 return (ch < 0x80) && (isalnum(ch) || ch == '.' );
39 }
40
IsAWordStart(const int ch)41 inline bool IsAWordStart(const int ch) {
42 return (ch < 0x80) && (isalnum(ch) || ch == '_');
43 }
44
isAveOperator(char ch)45 inline bool isAveOperator(char ch) {
46 if (IsASCII(ch) && isalnum(ch))
47 return false;
48 // '.' left out as it is used to make up numbers
49 if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
50 ch == '(' || ch == ')' || ch == '=' ||
51 ch == '{' || ch == '}' ||
52 ch == '[' || ch == ']' || ch == ';' ||
53 ch == '<' || ch == '>' || ch == ',' ||
54 ch == '.' )
55 return true;
56 return false;
57 }
58
ColouriseAveDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)59 static void ColouriseAveDoc(
60 Sci_PositionU startPos,
61 Sci_Position length,
62 int initStyle,
63 WordList *keywordlists[],
64 Accessor &styler) {
65
66 WordList &keywords = *keywordlists[0];
67 WordList &keywords2 = *keywordlists[1];
68 WordList &keywords3 = *keywordlists[2];
69 WordList &keywords4 = *keywordlists[3];
70 WordList &keywords5 = *keywordlists[4];
71 WordList &keywords6 = *keywordlists[5];
72
73 // Do not leak onto next line
74 if (initStyle == SCE_AVE_STRINGEOL) {
75 initStyle = SCE_AVE_DEFAULT;
76 }
77
78 StyleContext sc(startPos, length, initStyle, styler);
79
80 for (; sc.More(); sc.Forward()) {
81 if (sc.atLineEnd) {
82 // Update the line state, so it can be seen by next line
83 Sci_Position currentLine = styler.GetLine(sc.currentPos);
84 styler.SetLineState(currentLine, 0);
85 }
86 if (sc.atLineStart && (sc.state == SCE_AVE_STRING)) {
87 // Prevent SCE_AVE_STRINGEOL from leaking back to previous line
88 sc.SetState(SCE_AVE_STRING);
89 }
90
91
92 // Determine if the current state should terminate.
93 if (sc.state == SCE_AVE_OPERATOR) {
94 sc.SetState(SCE_AVE_DEFAULT);
95 } else if (sc.state == SCE_AVE_NUMBER) {
96 if (!IsANumberChar(sc.ch)) {
97 sc.SetState(SCE_AVE_DEFAULT);
98 }
99 } else if (sc.state == SCE_AVE_ENUM) {
100 if (!IsEnumChar(sc.ch)) {
101 sc.SetState(SCE_AVE_DEFAULT);
102 }
103 } else if (sc.state == SCE_AVE_IDENTIFIER) {
104 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
105 char s[100];
106 //sc.GetCurrent(s, sizeof(s));
107 sc.GetCurrentLowered(s, sizeof(s));
108 if (keywords.InList(s)) {
109 sc.ChangeState(SCE_AVE_WORD);
110 } else if (keywords2.InList(s)) {
111 sc.ChangeState(SCE_AVE_WORD2);
112 } else if (keywords3.InList(s)) {
113 sc.ChangeState(SCE_AVE_WORD3);
114 } else if (keywords4.InList(s)) {
115 sc.ChangeState(SCE_AVE_WORD4);
116 } else if (keywords5.InList(s)) {
117 sc.ChangeState(SCE_AVE_WORD5);
118 } else if (keywords6.InList(s)) {
119 sc.ChangeState(SCE_AVE_WORD6);
120 }
121 sc.SetState(SCE_AVE_DEFAULT);
122 }
123 } else if (sc.state == SCE_AVE_COMMENT) {
124 if (sc.atLineEnd) {
125 sc.SetState(SCE_AVE_DEFAULT);
126 }
127 } else if (sc.state == SCE_AVE_STRING) {
128 if (sc.ch == '\"') {
129 sc.ForwardSetState(SCE_AVE_DEFAULT);
130 } else if (sc.atLineEnd) {
131 sc.ChangeState(SCE_AVE_STRINGEOL);
132 sc.ForwardSetState(SCE_AVE_DEFAULT);
133 }
134 }
135
136 // Determine if a new state should be entered.
137 if (sc.state == SCE_AVE_DEFAULT) {
138 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
139 sc.SetState(SCE_AVE_NUMBER);
140 } else if (IsAWordStart(sc.ch)) {
141 sc.SetState(SCE_AVE_IDENTIFIER);
142 } else if (sc.Match('\"')) {
143 sc.SetState(SCE_AVE_STRING);
144 } else if (sc.Match('\'')) {
145 sc.SetState(SCE_AVE_COMMENT);
146 sc.Forward();
147 } else if (isAveOperator(static_cast<char>(sc.ch))) {
148 sc.SetState(SCE_AVE_OPERATOR);
149 } else if (sc.Match('#')) {
150 sc.SetState(SCE_AVE_ENUM);
151 sc.Forward();
152 }
153 }
154 }
155 sc.Complete();
156 }
157
FoldAveDoc(Sci_PositionU startPos,Sci_Position length,int,WordList * [],Accessor & styler)158 static void FoldAveDoc(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[],
159 Accessor &styler) {
160 Sci_PositionU lengthDoc = startPos + length;
161 int visibleChars = 0;
162 Sci_Position lineCurrent = styler.GetLine(startPos);
163 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
164 int levelCurrent = levelPrev;
165 char chNext = static_cast<char>(tolower(styler[startPos]));
166 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
167 int styleNext = styler.StyleAt(startPos);
168 char s[10] = "";
169
170 for (Sci_PositionU i = startPos; i < lengthDoc; i++) {
171 char ch = static_cast<char>(tolower(chNext));
172 chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));
173 int style = styleNext;
174 styleNext = styler.StyleAt(i + 1);
175 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
176 if (style == SCE_AVE_WORD) {
177 if (ch == 't' || ch == 'f' || ch == 'w' || ch == 'e') {
178 for (unsigned int j = 0; j < 6; j++) {
179 if (!iswordchar(styler[i + j])) {
180 break;
181 }
182 s[j] = static_cast<char>(tolower(styler[i + j]));
183 s[j + 1] = '\0';
184 }
185
186 if ((strcmp(s, "then") == 0) || (strcmp(s, "for") == 0) || (strcmp(s, "while") == 0)) {
187 levelCurrent++;
188 }
189 if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
190 // Normally "elseif" and "then" will be on the same line and will cancel
191 // each other out. // As implemented, this does not support fold.at.else.
192 levelCurrent--;
193 }
194 }
195 } else if (style == SCE_AVE_OPERATOR) {
196 if (ch == '{' || ch == '(') {
197 levelCurrent++;
198 } else if (ch == '}' || ch == ')') {
199 levelCurrent--;
200 }
201 }
202
203 if (atEOL) {
204 int lev = levelPrev;
205 if (visibleChars == 0 && foldCompact) {
206 lev |= SC_FOLDLEVELWHITEFLAG;
207 }
208 if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
209 lev |= SC_FOLDLEVELHEADERFLAG;
210 }
211 if (lev != styler.LevelAt(lineCurrent)) {
212 styler.SetLevel(lineCurrent, lev);
213 }
214 lineCurrent++;
215 levelPrev = levelCurrent;
216 visibleChars = 0;
217 }
218 if (!isspacechar(ch)) {
219 visibleChars++;
220 }
221 }
222 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
223
224 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
225 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
226 }
227
228 LexerModule lmAVE(SCLEX_AVE, ColouriseAveDoc, "ave", FoldAveDoc);
229
230