]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexPOV.cxx
33ba6a490f999bd27a7195de599df7338f2b5985
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexPOV.cxx
1 // Scintilla source code edit control
2 /** @file LexPOV.cxx
3 ** Lexer for POV-Ray SDL (Persistance of Vision Raytracer, Scene Description Language).
4 ** Written by Philippe Lhoste but this is mostly a derivative of LexCPP...
5 **/
6 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 // Some points that distinguish from a simple C lexer:
10 // Identifiers start only by a character.
11 // No line continuation character.
12 // Strings are limited to 256 characters.
13 // Directives are similar to preprocessor commands,
14 // but we match directive keywords and colorize incorrect ones.
15 // Block comments can be nested (code stolen from my code in LexLua).
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <stdio.h>
21 #include <stdarg.h>
22
23 #include "Platform.h"
24
25 #include "PropSet.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "KeyWords.h"
29 #include "Scintilla.h"
30 #include "SciLexer.h"
31
32 static inline bool IsAWordChar(const int ch) {
33 return ch < 0x80 && (isalnum(ch) || ch == '_');
34 }
35
36 inline bool IsAWordStart(const int ch) {
37 return ch < 0x80 && isalpha(ch);
38 }
39
40 static void ColourisePovDoc(
41 unsigned int startPos,
42 int length,
43 int initStyle,
44 WordList *keywordlists[],
45 Accessor &styler) {
46
47 WordList &keywords1 = *keywordlists[0];
48 WordList &keywords2 = *keywordlists[1];
49 WordList &keywords3 = *keywordlists[2];
50 WordList &keywords4 = *keywordlists[3];
51 WordList &keywords5 = *keywordlists[4];
52 WordList &keywords6 = *keywordlists[5];
53 WordList &keywords7 = *keywordlists[6];
54 WordList &keywords8 = *keywordlists[7];
55
56 int currentLine = styler.GetLine(startPos);
57 // Initialize the block comment /* */ nesting level, if we are inside such a comment.
58 int blockCommentLevel = 0;
59 if (initStyle == SCE_POV_COMMENT) {
60 blockCommentLevel = styler.GetLineState(currentLine - 1);
61 }
62
63 // Do not leak onto next line
64 if (initStyle == SCE_POV_STRINGEOL) {
65 initStyle = SCE_POV_DEFAULT;
66 }
67
68 StyleContext sc(startPos, length, initStyle, styler);
69 short stringLen = 0;
70
71 for (; sc.More(); sc.Forward()) {
72 if (sc.atLineEnd) {
73 // Update the line state, so it can be seen by next line
74 currentLine = styler.GetLine(sc.currentPos);
75 if (sc.state == SCE_POV_COMMENT) {
76 // Inside a block comment, we set the line state
77 styler.SetLineState(currentLine, blockCommentLevel);
78 } else {
79 // Reset the line state
80 styler.SetLineState(currentLine, 0);
81 }
82 }
83
84 if (sc.atLineStart && (sc.state == SCE_POV_STRING)) {
85 // Prevent SCE_POV_STRINGEOL from leaking back to previous line
86 sc.SetState(SCE_POV_STRING);
87 }
88
89 // Determine if the current state should terminate.
90 if (sc.state == SCE_POV_OPERATOR) {
91 sc.SetState(SCE_POV_DEFAULT);
92 } else if (sc.state == SCE_POV_NUMBER) {
93 // We stop the number definition on non-numerical non-dot non-eE non-sign char
94 if (!(isdigit(sc.ch) || sc.ch == '.' ||
95 toupper(sc.ch) == 'E' || sc.ch == '-' || sc.ch == '+')) {
96 // Not exactly following number definition (several dots are seen as OK, etc.)
97 // but probably enough in most cases.
98 sc.SetState(SCE_POV_DEFAULT);
99 }
100 } else if (sc.state == SCE_POV_IDENTIFIER) {
101 if (!IsAWordChar(sc.ch)) {
102 char s[100];
103 sc.GetCurrent(s, sizeof(s));
104 if (keywords2.InList(s)) {
105 sc.ChangeState(SCE_POV_WORD2);
106 } else if (keywords3.InList(s)) {
107 sc.ChangeState(SCE_POV_WORD3);
108 } else if (keywords4.InList(s)) {
109 sc.ChangeState(SCE_POV_WORD4);
110 } else if (keywords5.InList(s)) {
111 sc.ChangeState(SCE_POV_WORD5);
112 } else if (keywords6.InList(s)) {
113 sc.ChangeState(SCE_POV_WORD6);
114 } else if (keywords7.InList(s)) {
115 sc.ChangeState(SCE_POV_WORD7);
116 } else if (keywords8.InList(s)) {
117 sc.ChangeState(SCE_POV_WORD8);
118 }
119 sc.SetState(SCE_POV_DEFAULT);
120 }
121 } else if (sc.state == SCE_POV_DIRECTIVE) {
122 if (!IsAWordChar(sc.ch)) {
123 char s[100], *p;
124 sc.GetCurrent(s, sizeof(s));
125 p = s;
126 // Skip # and whitespace between # and directive word
127 do {
128 p++;
129 } while ((*p == ' ' || *p == '\t') && *p != '\0');
130 if (!keywords1.InList(p)) {
131 sc.ChangeState(SCE_POV_BADDIRECTIVE);
132 }
133 sc.SetState(SCE_POV_DEFAULT);
134 }
135 } else if (sc.state == SCE_POV_COMMENT) {
136 if (sc.Match('/', '*')) {
137 blockCommentLevel++;
138 sc.Forward();
139 } else if (sc.Match('*', '/') && blockCommentLevel > 0) {
140 blockCommentLevel--;
141 sc.Forward();
142 if (blockCommentLevel == 0) {
143 sc.ForwardSetState(SCE_POV_DEFAULT);
144 }
145 }
146 } else if (sc.state == SCE_POV_COMMENTLINE) {
147 if (sc.atLineEnd) {
148 sc.SetState(SCE_POV_DEFAULT);
149 }
150 } else if (sc.state == SCE_POV_STRING) {
151 if (sc.ch == '\\') {
152 stringLen++;
153 if (strchr("abfnrtuv0'\"", sc.chNext)) {
154 // Compound characters are counted as one.
155 // Note: for Unicode chars \u, we shouldn't count the next 4 digits...
156 sc.Forward();
157 }
158 } else if (sc.ch == '\"') {
159 sc.ForwardSetState(SCE_POV_DEFAULT);
160 } else if (sc.atLineEnd) {
161 sc.ChangeState(SCE_POV_STRINGEOL);
162 sc.ForwardSetState(SCE_POV_DEFAULT);
163 } else {
164 stringLen++;
165 }
166 if (stringLen > 256) {
167 // Strings are limited to 256 chars
168 sc.SetState(SCE_POV_STRINGEOL);
169 }
170 } else if (sc.state == SCE_POV_STRINGEOL) {
171 if (sc.ch == '\\') {
172 if (sc.chNext == '\"' || sc.chNext == '\\') {
173 sc.Forward();
174 }
175 } else if (sc.ch == '\"') {
176 sc.ForwardSetState(SCE_C_DEFAULT);
177 } else if (sc.atLineEnd) {
178 sc.ForwardSetState(SCE_POV_DEFAULT);
179 }
180 }
181
182 // Determine if a new state should be entered.
183 if (sc.state == SCE_POV_DEFAULT) {
184 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
185 sc.SetState(SCE_POV_NUMBER);
186 } else if (IsAWordStart(sc.ch)) {
187 sc.SetState(SCE_POV_IDENTIFIER);
188 } else if (sc.Match('/', '*')) {
189 blockCommentLevel = 1;
190 sc.SetState(SCE_POV_COMMENT);
191 sc.Forward(); // Eat the * so it isn't used for the end of the comment
192 } else if (sc.Match('/', '/')) {
193 sc.SetState(SCE_POV_COMMENTLINE);
194 } else if (sc.ch == '\"') {
195 sc.SetState(SCE_POV_STRING);
196 stringLen = 0;
197 } else if (sc.ch == '#') {
198 sc.SetState(SCE_POV_DIRECTIVE);
199 // Skip whitespace between # and directive word
200 do {
201 sc.Forward();
202 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
203 if (sc.atLineEnd) {
204 sc.SetState(SCE_POV_DEFAULT);
205 }
206 } else if (isoperator(static_cast<char>(sc.ch))) {
207 sc.SetState(SCE_POV_OPERATOR);
208 }
209 }
210 }
211 sc.Complete();
212 }
213
214 static void FoldPovDoc(
215 unsigned int startPos,
216 int length,
217 int initStyle,
218 WordList *[],
219 Accessor &styler) {
220
221 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
222 bool foldDirective = styler.GetPropertyInt("fold.directive") != 0;
223 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
224 unsigned int endPos = startPos + length;
225 int visibleChars = 0;
226 int lineCurrent = styler.GetLine(startPos);
227 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
228 int levelCurrent = levelPrev;
229 char chNext = styler[startPos];
230 int styleNext = styler.StyleAt(startPos);
231 int style = initStyle;
232 for (unsigned int i = startPos; i < endPos; i++) {
233 char ch = chNext;
234 chNext = styler.SafeGetCharAt(i + 1);
235 int stylePrev = style;
236 style = styleNext;
237 styleNext = styler.StyleAt(i + 1);
238 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
239 if (foldComment && (style == SCE_POV_COMMENT)) {
240 if (stylePrev != SCE_POV_COMMENT) {
241 levelCurrent++;
242 } else if ((styleNext != SCE_POV_COMMENT) && !atEOL) {
243 // Comments don't end at end of line and the next character may be unstyled.
244 levelCurrent--;
245 }
246 }
247 if (foldComment && (style == SCE_POV_COMMENTLINE)) {
248 if ((ch == '/') && (chNext == '/')) {
249 char chNext2 = styler.SafeGetCharAt(i + 2);
250 if (chNext2 == '{') {
251 levelCurrent++;
252 } else if (chNext2 == '}') {
253 levelCurrent--;
254 }
255 }
256 }
257 if (foldDirective && (style == SCE_POV_DIRECTIVE)) {
258 if (ch == '#') {
259 unsigned int j=i+1;
260 while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
261 j++;
262 }
263 }
264 }
265 if (style == SCE_POV_OPERATOR) {
266 if (ch == '{') {
267 levelCurrent++;
268 } else if (ch == '}') {
269 levelCurrent--;
270 }
271 }
272 if (atEOL) {
273 int lev = levelPrev;
274 if (visibleChars == 0 && foldCompact)
275 lev |= SC_FOLDLEVELWHITEFLAG;
276 if ((levelCurrent > levelPrev) && (visibleChars > 0))
277 lev |= SC_FOLDLEVELHEADERFLAG;
278 if (lev != styler.LevelAt(lineCurrent)) {
279 styler.SetLevel(lineCurrent, lev);
280 }
281 lineCurrent++;
282 levelPrev = levelCurrent;
283 visibleChars = 0;
284 }
285 if (!isspacechar(ch))
286 visibleChars++;
287 }
288 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
289 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
290 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
291 }
292
293 static const char * const povWordLists[] = {
294 "Language directives",
295 "Objects & CSG & Appearance",
296 "Types & Modifiers & Items",
297 "Predefined Identifiers",
298 "Predefined Functions",
299 "User defined 1",
300 "User defined 2",
301 "User defined 3",
302 0,
303 };
304
305 LexerModule lmPOV(SCLEX_POV, ColourisePovDoc, "pov", FoldPovDoc, povWordLists);