*** empty log message ***
[anjuta-git-plugin.git] / scintilla / LexPOV.cxx
blob0c1a21ab48bdd7c8fdc8f1c8e76a9184a939759c
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.
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).
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <stdio.h>
21 #include <stdarg.h>
23 #include "Platform.h"
25 #include "PropSet.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "KeyWords.h"
29 #include "Scintilla.h"
30 #include "SciLexer.h"
32 static inline bool IsAWordChar(const int ch) {
33 return ch < 0x80 && (isalnum(ch) || ch == '_');
36 static inline bool IsAWordStart(const int ch) {
37 return ch < 0x80 && isalpha(ch);
40 static inline bool IsANumberChar(const int ch) {
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 == '+');
48 static void ColourisePovDoc(
49 unsigned int startPos,
50 int length,
51 int initStyle,
52 WordList *keywordlists[],
53 Accessor &styler) {
55 WordList &keywords1 = *keywordlists[0];
56 WordList &keywords2 = *keywordlists[1];
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];
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);
71 // Do not leak onto next line
72 if (initStyle == SCE_POV_STRINGEOL) {
73 initStyle = SCE_POV_DEFAULT;
76 StyleContext sc(startPos, length, initStyle, styler);
77 short stringLen = 0;
79 for (; sc.More(); sc.Forward()) {
80 if (sc.atLineEnd) {
81 // Update the line state, so it can be seen by next line
82 currentLine = styler.GetLine(sc.currentPos);
83 if (sc.state == SCE_POV_COMMENT) {
84 // Inside a block comment, we set the line state
85 styler.SetLineState(currentLine, blockCommentLevel);
86 } else {
87 // Reset the line state
88 styler.SetLineState(currentLine, 0);
92 if (sc.atLineStart && (sc.state == SCE_POV_STRING)) {
93 // Prevent SCE_POV_STRINGEOL from leaking back to previous line
94 sc.SetState(SCE_POV_STRING);
97 // Determine if the current state should terminate.
98 if (sc.state == SCE_POV_OPERATOR) {
99 sc.SetState(SCE_POV_DEFAULT);
100 } else if (sc.state == SCE_POV_NUMBER) {
101 // We stop the number definition on non-numerical non-dot non-eE non-sign char
102 if (!IsANumberChar(sc.ch)) {
103 sc.SetState(SCE_POV_DEFAULT);
105 } else if (sc.state == SCE_POV_IDENTIFIER) {
106 if (!IsAWordChar(sc.ch)) {
107 char s[100];
108 sc.GetCurrent(s, sizeof(s));
109 if (keywords2.InList(s)) {
110 sc.ChangeState(SCE_POV_WORD2);
111 } else if (keywords3.InList(s)) {
112 sc.ChangeState(SCE_POV_WORD3);
113 } else if (keywords4.InList(s)) {
114 sc.ChangeState(SCE_POV_WORD4);
115 } else if (keywords5.InList(s)) {
116 sc.ChangeState(SCE_POV_WORD5);
117 } else if (keywords6.InList(s)) {
118 sc.ChangeState(SCE_POV_WORD6);
119 } else if (keywords7.InList(s)) {
120 sc.ChangeState(SCE_POV_WORD7);
121 } else if (keywords8.InList(s)) {
122 sc.ChangeState(SCE_POV_WORD8);
124 sc.SetState(SCE_POV_DEFAULT);
126 } else if (sc.state == SCE_POV_DIRECTIVE) {
127 if (!IsAWordChar(sc.ch)) {
128 char s[100], *p;
129 sc.GetCurrent(s, sizeof(s));
130 p = s;
131 // Skip # and whitespace between # and directive word
132 do {
133 p++;
134 } while ((*p == ' ' || *p == '\t') && *p != '\0');
135 if (!keywords1.InList(p)) {
136 sc.ChangeState(SCE_POV_BADDIRECTIVE);
138 sc.SetState(SCE_POV_DEFAULT);
140 } else if (sc.state == SCE_POV_COMMENT) {
141 if (sc.Match('/', '*')) {
142 blockCommentLevel++;
143 sc.Forward();
144 } else if (sc.Match('*', '/') && blockCommentLevel > 0) {
145 blockCommentLevel--;
146 sc.Forward();
147 if (blockCommentLevel == 0) {
148 sc.ForwardSetState(SCE_POV_DEFAULT);
151 } else if (sc.state == SCE_POV_COMMENTLINE) {
152 if (sc.atLineEnd) {
153 sc.SetState(SCE_POV_DEFAULT);
155 } else if (sc.state == SCE_POV_STRING) {
156 if (sc.ch == '\\') {
157 stringLen++;
158 if (strchr("abfnrtuv0'\"", sc.chNext)) {
159 // Compound characters are counted as one.
160 // Note: for Unicode chars \u, we shouldn't count the next 4 digits...
161 sc.Forward();
163 } else if (sc.ch == '\"') {
164 sc.ForwardSetState(SCE_POV_DEFAULT);
165 } else if (sc.atLineEnd) {
166 sc.ChangeState(SCE_POV_STRINGEOL);
167 sc.ForwardSetState(SCE_POV_DEFAULT);
168 } else {
169 stringLen++;
171 if (stringLen > 256) {
172 // Strings are limited to 256 chars
173 sc.SetState(SCE_POV_STRINGEOL);
175 } else if (sc.state == SCE_POV_STRINGEOL) {
176 if (sc.ch == '\\') {
177 if (sc.chNext == '\"' || sc.chNext == '\\') {
178 sc.Forward();
180 } else if (sc.ch == '\"') {
181 sc.ForwardSetState(SCE_C_DEFAULT);
182 } else if (sc.atLineEnd) {
183 sc.ForwardSetState(SCE_POV_DEFAULT);
187 // Determine if a new state should be entered.
188 if (sc.state == SCE_POV_DEFAULT) {
189 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
190 sc.SetState(SCE_POV_NUMBER);
191 } else if (IsAWordStart(sc.ch)) {
192 sc.SetState(SCE_POV_IDENTIFIER);
193 } else if (sc.Match('/', '*')) {
194 blockCommentLevel = 1;
195 sc.SetState(SCE_POV_COMMENT);
196 sc.Forward(); // Eat the * so it isn't used for the end of the comment
197 } else if (sc.Match('/', '/')) {
198 sc.SetState(SCE_POV_COMMENTLINE);
199 } else if (sc.ch == '\"') {
200 sc.SetState(SCE_POV_STRING);
201 stringLen = 0;
202 } else if (sc.ch == '#') {
203 sc.SetState(SCE_POV_DIRECTIVE);
204 // Skip whitespace between # and directive word
205 do {
206 sc.Forward();
207 } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
208 if (sc.atLineEnd) {
209 sc.SetState(SCE_POV_DEFAULT);
211 } else if (isoperator(static_cast<char>(sc.ch))) {
212 sc.SetState(SCE_POV_OPERATOR);
216 sc.Complete();
219 static void FoldPovDoc(
220 unsigned int startPos,
221 int length,
222 int initStyle,
223 WordList *[],
224 Accessor &styler) {
226 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
227 bool foldDirective = styler.GetPropertyInt("fold.directive") != 0;
228 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
229 unsigned int endPos = startPos + length;
230 int visibleChars = 0;
231 int lineCurrent = styler.GetLine(startPos);
232 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
233 int levelCurrent = levelPrev;
234 char chNext = styler[startPos];
235 int styleNext = styler.StyleAt(startPos);
236 int style = initStyle;
237 for (unsigned int i = startPos; i < endPos; i++) {
238 char ch = chNext;
239 chNext = styler.SafeGetCharAt(i + 1);
240 int stylePrev = style;
241 style = styleNext;
242 styleNext = styler.StyleAt(i + 1);
243 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
244 if (foldComment && (style == SCE_POV_COMMENT)) {
245 if (stylePrev != SCE_POV_COMMENT) {
246 levelCurrent++;
247 } else if ((styleNext != SCE_POV_COMMENT) && !atEOL) {
248 // Comments don't end at end of line and the next character may be unstyled.
249 levelCurrent--;
252 if (foldComment && (style == SCE_POV_COMMENTLINE)) {
253 if ((ch == '/') && (chNext == '/')) {
254 char chNext2 = styler.SafeGetCharAt(i + 2);
255 if (chNext2 == '{') {
256 levelCurrent++;
257 } else if (chNext2 == '}') {
258 levelCurrent--;
262 if (foldDirective && (style == SCE_POV_DIRECTIVE)) {
263 if (ch == '#') {
264 unsigned int j=i+1;
265 while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
266 j++;
270 if (style == SCE_POV_OPERATOR) {
271 if (ch == '{') {
272 levelCurrent++;
273 } else if (ch == '}') {
274 levelCurrent--;
277 if (atEOL) {
278 int lev = levelPrev;
279 if (visibleChars == 0 && foldCompact)
280 lev |= SC_FOLDLEVELWHITEFLAG;
281 if ((levelCurrent > levelPrev) && (visibleChars > 0))
282 lev |= SC_FOLDLEVELHEADERFLAG;
283 if (lev != styler.LevelAt(lineCurrent)) {
284 styler.SetLevel(lineCurrent, lev);
286 lineCurrent++;
287 levelPrev = levelCurrent;
288 visibleChars = 0;
290 if (!isspacechar(ch))
291 visibleChars++;
293 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
294 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
295 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
298 static const char * const povWordLists[] = {
299 "Language directives",
300 "Objects & CSG & Appearance",
301 "Types & Modifiers & Items",
302 "Predefined Identifiers",
303 "Predefined Functions",
304 "User defined 1",
305 "User defined 2",
306 "User defined 3",
310 LexerModule lmPOV(SCLEX_POV, ColourisePovDoc, "pov", FoldPovDoc, povWordLists);