Refactor: CString optimizations
[TortoiseGit.git] / ext / scintilla / lexers / LexPS.cxx
blob82349e9a95a59555877d587b152ad74fd5635b45
1 // Scintilla source code edit control
2 /** @file LexPS.cxx
3 ** Lexer for PostScript
4 **
5 ** Written by Nigel Hathaway <nigel@bprj.co.uk>.
6 ** The License.txt file describes the conditions under which this software may be distributed.
7 **/
9 // Previous releases of this lexer included support for marking token starts with
10 // a style byte indicator. This was used by the wxGhostscript IDE/debugger.
11 // Style byte indicators were removed in version 3.4.3.
12 // Anyone wanting to restore this functionality for wxGhostscript using 'modern'
13 // indicators can examine the earlier source in the Mercurial repository.
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <assert.h>
20 #include <ctype.h>
22 #include "ILexer.h"
23 #include "Scintilla.h"
24 #include "SciLexer.h"
26 #include "WordList.h"
27 #include "LexAccessor.h"
28 #include "Accessor.h"
29 #include "StyleContext.h"
30 #include "CharacterSet.h"
31 #include "LexerModule.h"
33 #ifdef SCI_NAMESPACE
34 using namespace Scintilla;
35 #endif
37 static inline bool IsASelfDelimitingChar(const int ch) {
38 return (ch == '[' || ch == ']' || ch == '{' || ch == '}' ||
39 ch == '/' || ch == '<' || ch == '>' ||
40 ch == '(' || ch == ')' || ch == '%');
43 static inline bool IsAWhitespaceChar(const int ch) {
44 return (ch == ' ' || ch == '\t' || ch == '\r' ||
45 ch == '\n' || ch == '\f' || ch == '\0');
48 static bool IsABaseNDigit(const int ch, const int base) {
49 int maxdig = '9';
50 int letterext = -1;
52 if (base <= 10)
53 maxdig = '0' + base - 1;
54 else
55 letterext = base - 11;
57 return ((ch >= '0' && ch <= maxdig) ||
58 (ch >= 'A' && ch <= ('A' + letterext)) ||
59 (ch >= 'a' && ch <= ('a' + letterext)));
62 static inline bool IsABase85Char(const int ch) {
63 return ((ch >= '!' && ch <= 'u') || ch == 'z');
66 static void ColourisePSDoc(
67 unsigned int startPos,
68 int length,
69 int initStyle,
70 WordList *keywordlists[],
71 Accessor &styler) {
73 WordList &keywords1 = *keywordlists[0];
74 WordList &keywords2 = *keywordlists[1];
75 WordList &keywords3 = *keywordlists[2];
76 WordList &keywords4 = *keywordlists[3];
77 WordList &keywords5 = *keywordlists[4];
79 StyleContext sc(startPos, length, initStyle, styler);
81 int pslevel = styler.GetPropertyInt("ps.level", 3);
82 int lineCurrent = styler.GetLine(startPos);
83 int nestTextCurrent = 0;
84 if (lineCurrent > 0 && initStyle == SCE_PS_TEXT)
85 nestTextCurrent = styler.GetLineState(lineCurrent - 1);
86 int numRadix = 0;
87 bool numHasPoint = false;
88 bool numHasExponent = false;
89 bool numHasSign = false;
91 for (; sc.More(); sc.Forward()) {
92 if (sc.atLineStart)
93 lineCurrent = styler.GetLine(sc.currentPos);
95 // Determine if the current state should terminate.
96 if (sc.state == SCE_PS_COMMENT || sc.state == SCE_PS_DSC_VALUE) {
97 if (sc.atLineEnd) {
98 sc.SetState(SCE_C_DEFAULT);
100 } else if (sc.state == SCE_PS_DSC_COMMENT) {
101 if (sc.ch == ':') {
102 sc.Forward();
103 if (!sc.atLineEnd)
104 sc.SetState(SCE_PS_DSC_VALUE);
105 else
106 sc.SetState(SCE_C_DEFAULT);
107 } else if (sc.atLineEnd) {
108 sc.SetState(SCE_C_DEFAULT);
109 } else if (IsAWhitespaceChar(sc.ch) && sc.ch != '\r') {
110 sc.ChangeState(SCE_PS_COMMENT);
112 } else if (sc.state == SCE_PS_NUMBER) {
113 if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch)) {
114 if ((sc.chPrev == '+' || sc.chPrev == '-' ||
115 sc.chPrev == 'E' || sc.chPrev == 'e') && numRadix == 0)
116 sc.ChangeState(SCE_PS_NAME);
117 sc.SetState(SCE_C_DEFAULT);
118 } else if (sc.ch == '#') {
119 if (numHasPoint || numHasExponent || numHasSign || numRadix != 0) {
120 sc.ChangeState(SCE_PS_NAME);
121 } else {
122 char szradix[5];
123 sc.GetCurrent(szradix, 4);
124 numRadix = atoi(szradix);
125 if (numRadix < 2 || numRadix > 36)
126 sc.ChangeState(SCE_PS_NAME);
128 } else if ((sc.ch == 'E' || sc.ch == 'e') && numRadix == 0) {
129 if (numHasExponent) {
130 sc.ChangeState(SCE_PS_NAME);
131 } else {
132 numHasExponent = true;
133 if (sc.chNext == '+' || sc.chNext == '-')
134 sc.Forward();
136 } else if (sc.ch == '.') {
137 if (numHasPoint || numHasExponent || numRadix != 0) {
138 sc.ChangeState(SCE_PS_NAME);
139 } else {
140 numHasPoint = true;
142 } else if (numRadix == 0) {
143 if (!IsABaseNDigit(sc.ch, 10))
144 sc.ChangeState(SCE_PS_NAME);
145 } else {
146 if (!IsABaseNDigit(sc.ch, numRadix))
147 sc.ChangeState(SCE_PS_NAME);
149 } else if (sc.state == SCE_PS_NAME || sc.state == SCE_PS_KEYWORD) {
150 if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch)) {
151 char s[100];
152 sc.GetCurrent(s, sizeof(s));
153 if ((pslevel >= 1 && keywords1.InList(s)) ||
154 (pslevel >= 2 && keywords2.InList(s)) ||
155 (pslevel >= 3 && keywords3.InList(s)) ||
156 keywords4.InList(s) || keywords5.InList(s)) {
157 sc.ChangeState(SCE_PS_KEYWORD);
159 sc.SetState(SCE_C_DEFAULT);
161 } else if (sc.state == SCE_PS_LITERAL || sc.state == SCE_PS_IMMEVAL) {
162 if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch))
163 sc.SetState(SCE_C_DEFAULT);
164 } else if (sc.state == SCE_PS_PAREN_ARRAY || sc.state == SCE_PS_PAREN_DICT ||
165 sc.state == SCE_PS_PAREN_PROC) {
166 sc.SetState(SCE_C_DEFAULT);
167 } else if (sc.state == SCE_PS_TEXT) {
168 if (sc.ch == '(') {
169 nestTextCurrent++;
170 } else if (sc.ch == ')') {
171 if (--nestTextCurrent == 0)
172 sc.ForwardSetState(SCE_PS_DEFAULT);
173 } else if (sc.ch == '\\') {
174 sc.Forward();
176 } else if (sc.state == SCE_PS_HEXSTRING) {
177 if (sc.ch == '>') {
178 sc.ForwardSetState(SCE_PS_DEFAULT);
179 } else if (!IsABaseNDigit(sc.ch, 16) && !IsAWhitespaceChar(sc.ch)) {
180 sc.SetState(SCE_PS_HEXSTRING);
181 styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
183 } else if (sc.state == SCE_PS_BASE85STRING) {
184 if (sc.Match('~', '>')) {
185 sc.Forward();
186 sc.ForwardSetState(SCE_PS_DEFAULT);
187 } else if (!IsABase85Char(sc.ch) && !IsAWhitespaceChar(sc.ch)) {
188 sc.SetState(SCE_PS_BASE85STRING);
189 styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
193 // Determine if a new state should be entered.
194 if (sc.state == SCE_C_DEFAULT) {
196 if (sc.ch == '[' || sc.ch == ']') {
197 sc.SetState(SCE_PS_PAREN_ARRAY);
198 } else if (sc.ch == '{' || sc.ch == '}') {
199 sc.SetState(SCE_PS_PAREN_PROC);
200 } else if (sc.ch == '/') {
201 if (sc.chNext == '/') {
202 sc.SetState(SCE_PS_IMMEVAL);
203 sc.Forward();
204 } else {
205 sc.SetState(SCE_PS_LITERAL);
207 } else if (sc.ch == '<') {
208 if (sc.chNext == '<') {
209 sc.SetState(SCE_PS_PAREN_DICT);
210 sc.Forward();
211 } else if (sc.chNext == '~') {
212 sc.SetState(SCE_PS_BASE85STRING);
213 sc.Forward();
214 } else {
215 sc.SetState(SCE_PS_HEXSTRING);
217 } else if (sc.ch == '>' && sc.chNext == '>') {
218 sc.SetState(SCE_PS_PAREN_DICT);
219 sc.Forward();
220 } else if (sc.ch == '>' || sc.ch == ')') {
221 sc.SetState(SCE_C_DEFAULT);
222 styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
223 } else if (sc.ch == '(') {
224 sc.SetState(SCE_PS_TEXT);
225 nestTextCurrent = 1;
226 } else if (sc.ch == '%') {
227 if (sc.chNext == '%' && sc.atLineStart) {
228 sc.SetState(SCE_PS_DSC_COMMENT);
229 sc.Forward();
230 if (sc.chNext == '+') {
231 sc.Forward();
232 sc.ForwardSetState(SCE_PS_DSC_VALUE);
234 } else {
235 sc.SetState(SCE_PS_COMMENT);
237 } else if ((sc.ch == '+' || sc.ch == '-' || sc.ch == '.') &&
238 IsABaseNDigit(sc.chNext, 10)) {
239 sc.SetState(SCE_PS_NUMBER);
240 numRadix = 0;
241 numHasPoint = (sc.ch == '.');
242 numHasExponent = false;
243 numHasSign = (sc.ch == '+' || sc.ch == '-');
244 } else if ((sc.ch == '+' || sc.ch == '-') && sc.chNext == '.' &&
245 IsABaseNDigit(sc.GetRelative(2), 10)) {
246 sc.SetState(SCE_PS_NUMBER);
247 numRadix = 0;
248 numHasPoint = false;
249 numHasExponent = false;
250 numHasSign = true;
251 } else if (IsABaseNDigit(sc.ch, 10)) {
252 sc.SetState(SCE_PS_NUMBER);
253 numRadix = 0;
254 numHasPoint = false;
255 numHasExponent = false;
256 numHasSign = false;
257 } else if (!IsAWhitespaceChar(sc.ch)) {
258 sc.SetState(SCE_PS_NAME);
262 if (sc.atLineEnd)
263 styler.SetLineState(lineCurrent, nestTextCurrent);
266 sc.Complete();
269 static void FoldPSDoc(unsigned int startPos, int length, int, WordList *[],
270 Accessor &styler) {
271 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
272 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
273 unsigned int endPos = startPos + length;
274 int visibleChars = 0;
275 int lineCurrent = styler.GetLine(startPos);
276 int levelCurrent = SC_FOLDLEVELBASE;
277 if (lineCurrent > 0)
278 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
279 int levelMinCurrent = levelCurrent;
280 int levelNext = levelCurrent;
281 char chNext = styler[startPos];
282 int styleNext = styler.StyleAt(startPos);
283 for (unsigned int i = startPos; i < endPos; i++) {
284 char ch = chNext;
285 chNext = styler.SafeGetCharAt(i + 1);
286 int style = styleNext;
287 styleNext = styler.StyleAt(i + 1);
288 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); //mac??
289 if ((style & 31) == SCE_PS_PAREN_PROC) {
290 if (ch == '{') {
291 // Measure the minimum before a '{' to allow
292 // folding on "} {"
293 if (levelMinCurrent > levelNext) {
294 levelMinCurrent = levelNext;
296 levelNext++;
297 } else if (ch == '}') {
298 levelNext--;
301 if (atEOL) {
302 int levelUse = levelCurrent;
303 if (foldAtElse) {
304 levelUse = levelMinCurrent;
306 int lev = levelUse | levelNext << 16;
307 if (visibleChars == 0 && foldCompact)
308 lev |= SC_FOLDLEVELWHITEFLAG;
309 if (levelUse < levelNext)
310 lev |= SC_FOLDLEVELHEADERFLAG;
311 if (lev != styler.LevelAt(lineCurrent)) {
312 styler.SetLevel(lineCurrent, lev);
314 lineCurrent++;
315 levelCurrent = levelNext;
316 levelMinCurrent = levelCurrent;
317 visibleChars = 0;
319 if (!isspacechar(ch))
320 visibleChars++;
324 static const char * const psWordListDesc[] = {
325 "PS Level 1 operators",
326 "PS Level 2 operators",
327 "PS Level 3 operators",
328 "RIP-specific operators",
329 "User-defined operators",
333 LexerModule lmPS(SCLEX_PS, ColourisePSDoc, "ps", FoldPSDoc, psWordListDesc);