updated Scintilla to 2.29
[TortoiseGit.git] / ext / scintilla / lexers / LexPS.cxx
blobe4e49491521491722d4acfe0f901d8d2af32aad5
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 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
31 static inline bool IsASelfDelimitingChar(const int ch) {
32 return (ch == '[' || ch == ']' || ch == '{' || ch == '}' ||
33 ch == '/' || ch == '<' || ch == '>' ||
34 ch == '(' || ch == ')' || ch == '%');
37 static inline bool IsAWhitespaceChar(const int ch) {
38 return (ch == ' ' || ch == '\t' || ch == '\r' ||
39 ch == '\n' || ch == '\f' || ch == '\0');
42 static bool IsABaseNDigit(const int ch, const int base) {
43 int maxdig = '9';
44 int letterext = -1;
46 if (base <= 10)
47 maxdig = '0' + base - 1;
48 else
49 letterext = base - 11;
51 return ((ch >= '0' && ch <= maxdig) ||
52 (ch >= 'A' && ch <= ('A' + letterext)) ||
53 (ch >= 'a' && ch <= ('a' + letterext)));
56 static inline bool IsABase85Char(const int ch) {
57 return ((ch >= '!' && ch <= 'u') || ch == 'z');
60 static void ColourisePSDoc(
61 unsigned int startPos,
62 int length,
63 int initStyle,
64 WordList *keywordlists[],
65 Accessor &styler) {
67 WordList &keywords1 = *keywordlists[0];
68 WordList &keywords2 = *keywordlists[1];
69 WordList &keywords3 = *keywordlists[2];
70 WordList &keywords4 = *keywordlists[3];
71 WordList &keywords5 = *keywordlists[4];
73 StyleContext sc(startPos, length, initStyle, styler);
75 bool tokenizing = styler.GetPropertyInt("ps.tokenize") != 0;
76 int pslevel = styler.GetPropertyInt("ps.level", 3);
77 int lineCurrent = styler.GetLine(startPos);
78 int nestTextCurrent = 0;
79 if (lineCurrent > 0 && initStyle == SCE_PS_TEXT)
80 nestTextCurrent = styler.GetLineState(lineCurrent - 1);
81 int numRadix = 0;
82 bool numHasPoint = false;
83 bool numHasExponent = false;
84 bool numHasSign = false;
86 // Clear out existing tokenization
87 if (tokenizing && length > 0) {
88 styler.StartAt(startPos, static_cast<char>(INDIC2_MASK));
89 styler.ColourTo(startPos + length-1, 0);
90 styler.Flush();
91 styler.StartAt(startPos);
92 styler.StartSegment(startPos);
95 for (; sc.More(); sc.Forward()) {
96 if (sc.atLineStart)
97 lineCurrent = styler.GetLine(sc.currentPos);
99 // Determine if the current state should terminate.
100 if (sc.state == SCE_PS_COMMENT || sc.state == SCE_PS_DSC_VALUE) {
101 if (sc.atLineEnd) {
102 sc.SetState(SCE_C_DEFAULT);
104 } else if (sc.state == SCE_PS_DSC_COMMENT) {
105 if (sc.ch == ':') {
106 sc.Forward();
107 if (!sc.atLineEnd)
108 sc.SetState(SCE_PS_DSC_VALUE);
109 else
110 sc.SetState(SCE_C_DEFAULT);
111 } else if (sc.atLineEnd) {
112 sc.SetState(SCE_C_DEFAULT);
113 } else if (IsAWhitespaceChar(sc.ch) && sc.ch != '\r') {
114 sc.ChangeState(SCE_PS_COMMENT);
116 } else if (sc.state == SCE_PS_NUMBER) {
117 if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch)) {
118 if ((sc.chPrev == '+' || sc.chPrev == '-' ||
119 sc.chPrev == 'E' || sc.chPrev == 'e') && numRadix == 0)
120 sc.ChangeState(SCE_PS_NAME);
121 sc.SetState(SCE_C_DEFAULT);
122 } else if (sc.ch == '#') {
123 if (numHasPoint || numHasExponent || numHasSign || numRadix != 0) {
124 sc.ChangeState(SCE_PS_NAME);
125 } else {
126 char szradix[5];
127 sc.GetCurrent(szradix, 4);
128 numRadix = atoi(szradix);
129 if (numRadix < 2 || numRadix > 36)
130 sc.ChangeState(SCE_PS_NAME);
132 } else if ((sc.ch == 'E' || sc.ch == 'e') && numRadix == 0) {
133 if (numHasExponent) {
134 sc.ChangeState(SCE_PS_NAME);
135 } else {
136 numHasExponent = true;
137 if (sc.chNext == '+' || sc.chNext == '-')
138 sc.Forward();
140 } else if (sc.ch == '.') {
141 if (numHasPoint || numHasExponent || numRadix != 0) {
142 sc.ChangeState(SCE_PS_NAME);
143 } else {
144 numHasPoint = true;
146 } else if (numRadix == 0) {
147 if (!IsABaseNDigit(sc.ch, 10))
148 sc.ChangeState(SCE_PS_NAME);
149 } else {
150 if (!IsABaseNDigit(sc.ch, numRadix))
151 sc.ChangeState(SCE_PS_NAME);
153 } else if (sc.state == SCE_PS_NAME || sc.state == SCE_PS_KEYWORD) {
154 if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch)) {
155 char s[100];
156 sc.GetCurrent(s, sizeof(s));
157 if ((pslevel >= 1 && keywords1.InList(s)) ||
158 (pslevel >= 2 && keywords2.InList(s)) ||
159 (pslevel >= 3 && keywords3.InList(s)) ||
160 keywords4.InList(s) || keywords5.InList(s)) {
161 sc.ChangeState(SCE_PS_KEYWORD);
163 sc.SetState(SCE_C_DEFAULT);
165 } else if (sc.state == SCE_PS_LITERAL || sc.state == SCE_PS_IMMEVAL) {
166 if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch))
167 sc.SetState(SCE_C_DEFAULT);
168 } else if (sc.state == SCE_PS_PAREN_ARRAY || sc.state == SCE_PS_PAREN_DICT ||
169 sc.state == SCE_PS_PAREN_PROC) {
170 sc.SetState(SCE_C_DEFAULT);
171 } else if (sc.state == SCE_PS_TEXT) {
172 if (sc.ch == '(') {
173 nestTextCurrent++;
174 } else if (sc.ch == ')') {
175 if (--nestTextCurrent == 0)
176 sc.ForwardSetState(SCE_PS_DEFAULT);
177 } else if (sc.ch == '\\') {
178 sc.Forward();
180 } else if (sc.state == SCE_PS_HEXSTRING) {
181 if (sc.ch == '>') {
182 sc.ForwardSetState(SCE_PS_DEFAULT);
183 } else if (!IsABaseNDigit(sc.ch, 16) && !IsAWhitespaceChar(sc.ch)) {
184 sc.SetState(SCE_PS_HEXSTRING);
185 styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
187 } else if (sc.state == SCE_PS_BASE85STRING) {
188 if (sc.Match('~', '>')) {
189 sc.Forward();
190 sc.ForwardSetState(SCE_PS_DEFAULT);
191 } else if (!IsABase85Char(sc.ch) && !IsAWhitespaceChar(sc.ch)) {
192 sc.SetState(SCE_PS_BASE85STRING);
193 styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
197 // Determine if a new state should be entered.
198 if (sc.state == SCE_C_DEFAULT) {
199 unsigned int tokenpos = sc.currentPos;
201 if (sc.ch == '[' || sc.ch == ']') {
202 sc.SetState(SCE_PS_PAREN_ARRAY);
203 } else if (sc.ch == '{' || sc.ch == '}') {
204 sc.SetState(SCE_PS_PAREN_PROC);
205 } else if (sc.ch == '/') {
206 if (sc.chNext == '/') {
207 sc.SetState(SCE_PS_IMMEVAL);
208 sc.Forward();
209 } else {
210 sc.SetState(SCE_PS_LITERAL);
212 } else if (sc.ch == '<') {
213 if (sc.chNext == '<') {
214 sc.SetState(SCE_PS_PAREN_DICT);
215 sc.Forward();
216 } else if (sc.chNext == '~') {
217 sc.SetState(SCE_PS_BASE85STRING);
218 sc.Forward();
219 } else {
220 sc.SetState(SCE_PS_HEXSTRING);
222 } else if (sc.ch == '>' && sc.chNext == '>') {
223 sc.SetState(SCE_PS_PAREN_DICT);
224 sc.Forward();
225 } else if (sc.ch == '>' || sc.ch == ')') {
226 sc.SetState(SCE_C_DEFAULT);
227 styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
228 } else if (sc.ch == '(') {
229 sc.SetState(SCE_PS_TEXT);
230 nestTextCurrent = 1;
231 } else if (sc.ch == '%') {
232 if (sc.chNext == '%' && sc.atLineStart) {
233 sc.SetState(SCE_PS_DSC_COMMENT);
234 sc.Forward();
235 if (sc.chNext == '+') {
236 sc.Forward();
237 sc.ForwardSetState(SCE_PS_DSC_VALUE);
239 } else {
240 sc.SetState(SCE_PS_COMMENT);
242 } else if ((sc.ch == '+' || sc.ch == '-' || sc.ch == '.') &&
243 IsABaseNDigit(sc.chNext, 10)) {
244 sc.SetState(SCE_PS_NUMBER);
245 numRadix = 0;
246 numHasPoint = (sc.ch == '.');
247 numHasExponent = false;
248 numHasSign = (sc.ch == '+' || sc.ch == '-');
249 } else if ((sc.ch == '+' || sc.ch == '-') && sc.chNext == '.' &&
250 IsABaseNDigit(sc.GetRelative(2), 10)) {
251 sc.SetState(SCE_PS_NUMBER);
252 numRadix = 0;
253 numHasPoint = false;
254 numHasExponent = false;
255 numHasSign = true;
256 } else if (IsABaseNDigit(sc.ch, 10)) {
257 sc.SetState(SCE_PS_NUMBER);
258 numRadix = 0;
259 numHasPoint = false;
260 numHasExponent = false;
261 numHasSign = false;
262 } else if (!IsAWhitespaceChar(sc.ch)) {
263 sc.SetState(SCE_PS_NAME);
266 // Mark the start of tokens
267 if (tokenizing && sc.state != SCE_C_DEFAULT && sc.state != SCE_PS_COMMENT &&
268 sc.state != SCE_PS_DSC_COMMENT && sc.state != SCE_PS_DSC_VALUE) {
269 styler.Flush();
270 styler.StartAt(tokenpos, static_cast<char>(INDIC2_MASK));
271 styler.ColourTo(tokenpos, INDIC2_MASK);
272 styler.Flush();
273 styler.StartAt(tokenpos);
274 styler.StartSegment(tokenpos);
278 if (sc.atLineEnd)
279 styler.SetLineState(lineCurrent, nestTextCurrent);
282 sc.Complete();
285 static void FoldPSDoc(unsigned int startPos, int length, int, WordList *[],
286 Accessor &styler) {
287 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
288 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
289 unsigned int endPos = startPos + length;
290 int visibleChars = 0;
291 int lineCurrent = styler.GetLine(startPos);
292 int levelCurrent = SC_FOLDLEVELBASE;
293 if (lineCurrent > 0)
294 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
295 int levelMinCurrent = levelCurrent;
296 int levelNext = levelCurrent;
297 char chNext = styler[startPos];
298 int styleNext = styler.StyleAt(startPos);
299 int style;
300 for (unsigned int i = startPos; i < endPos; i++) {
301 char ch = chNext;
302 chNext = styler.SafeGetCharAt(i + 1);
303 style = styleNext;
304 styleNext = styler.StyleAt(i + 1);
305 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); //mac??
306 if ((style & 31) == SCE_PS_PAREN_PROC) {
307 if (ch == '{') {
308 // Measure the minimum before a '{' to allow
309 // folding on "} {"
310 if (levelMinCurrent > levelNext) {
311 levelMinCurrent = levelNext;
313 levelNext++;
314 } else if (ch == '}') {
315 levelNext--;
318 if (atEOL) {
319 int levelUse = levelCurrent;
320 if (foldAtElse) {
321 levelUse = levelMinCurrent;
323 int lev = levelUse | levelNext << 16;
324 if (visibleChars == 0 && foldCompact)
325 lev |= SC_FOLDLEVELWHITEFLAG;
326 if (levelUse < levelNext)
327 lev |= SC_FOLDLEVELHEADERFLAG;
328 if (lev != styler.LevelAt(lineCurrent)) {
329 styler.SetLevel(lineCurrent, lev);
331 lineCurrent++;
332 levelCurrent = levelNext;
333 levelMinCurrent = levelCurrent;
334 visibleChars = 0;
336 if (!isspacechar(ch))
337 visibleChars++;
341 static const char * const psWordListDesc[] = {
342 "PS Level 1 operators",
343 "PS Level 2 operators",
344 "PS Level 3 operators",
345 "RIP-specific operators",
346 "User-defined operators",
350 LexerModule lmPS(SCLEX_PS, ColourisePSDoc, "ps", FoldPSDoc, psWordListDesc);