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