1 // Scintilla source code edit control
3 ** Lexer for PostScript
5 ** Written by Nigel Hathaway <nigel@bprj.co.uk>.
6 ** The License.txt file describes the conditions under which this software may be distributed.
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.
23 #include "Scintilla.h"
27 #include "LexAccessor.h"
29 #include "StyleContext.h"
30 #include "CharacterSet.h"
31 #include "LexerModule.h"
34 using namespace Scintilla
;
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
) {
53 maxdig
= '0' + base
- 1;
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
,
70 WordList
*keywordlists
[],
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);
87 bool numHasPoint
= false;
88 bool numHasExponent
= false;
89 bool numHasSign
= false;
91 for (; sc
.More(); sc
.Forward()) {
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
) {
98 sc
.SetState(SCE_C_DEFAULT
);
100 } else if (sc
.state
== SCE_PS_DSC_COMMENT
) {
104 sc
.SetState(SCE_PS_DSC_VALUE
);
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
);
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
);
132 numHasExponent
= true;
133 if (sc
.chNext
== '+' || sc
.chNext
== '-')
136 } else if (sc
.ch
== '.') {
137 if (numHasPoint
|| numHasExponent
|| numRadix
!= 0) {
138 sc
.ChangeState(SCE_PS_NAME
);
142 } else if (numRadix
== 0) {
143 if (!IsABaseNDigit(sc
.ch
, 10))
144 sc
.ChangeState(SCE_PS_NAME
);
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
)) {
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
) {
170 } else if (sc
.ch
== ')') {
171 if (--nestTextCurrent
== 0)
172 sc
.ForwardSetState(SCE_PS_DEFAULT
);
173 } else if (sc
.ch
== '\\') {
176 } else if (sc
.state
== SCE_PS_HEXSTRING
) {
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('~', '>')) {
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
);
205 sc
.SetState(SCE_PS_LITERAL
);
207 } else if (sc
.ch
== '<') {
208 if (sc
.chNext
== '<') {
209 sc
.SetState(SCE_PS_PAREN_DICT
);
211 } else if (sc
.chNext
== '~') {
212 sc
.SetState(SCE_PS_BASE85STRING
);
215 sc
.SetState(SCE_PS_HEXSTRING
);
217 } else if (sc
.ch
== '>' && sc
.chNext
== '>') {
218 sc
.SetState(SCE_PS_PAREN_DICT
);
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
);
226 } else if (sc
.ch
== '%') {
227 if (sc
.chNext
== '%' && sc
.atLineStart
) {
228 sc
.SetState(SCE_PS_DSC_COMMENT
);
230 if (sc
.chNext
== '+') {
232 sc
.ForwardSetState(SCE_PS_DSC_VALUE
);
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
);
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
);
249 numHasExponent
= false;
251 } else if (IsABaseNDigit(sc
.ch
, 10)) {
252 sc
.SetState(SCE_PS_NUMBER
);
255 numHasExponent
= false;
257 } else if (!IsAWhitespaceChar(sc
.ch
)) {
258 sc
.SetState(SCE_PS_NAME
);
263 styler
.SetLineState(lineCurrent
, nestTextCurrent
);
269 static void FoldPSDoc(unsigned int startPos
, int length
, int, WordList
*[],
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
;
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
++) {
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
) {
291 // Measure the minimum before a '{' to allow
293 if (levelMinCurrent
> levelNext
) {
294 levelMinCurrent
= levelNext
;
297 } else if (ch
== '}') {
302 int levelUse
= levelCurrent
;
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
);
315 levelCurrent
= levelNext
;
316 levelMinCurrent
= levelCurrent
;
319 if (!isspacechar(ch
))
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
);