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