1 // Scintilla source code edit control
2 /** @file LexR.cxx
3 ** Lexer for R, S, SPlus Statistics Program (Heavily derived from CPP Lexer).
4 **
5 **/
6 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 using namespace Scintilla;
28
IsAWordChar(const int ch)29 static inline bool IsAWordChar(const int ch) {
30 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
31 }
32
IsAWordStart(const int ch)33 static inline bool IsAWordStart(const int ch) {
34 return (ch < 0x80) && (isalnum(ch) || ch == '_');
35 }
36
IsAnOperator(const int ch)37 static inline bool IsAnOperator(const int ch) {
38 if (IsASCII(ch) && isalnum(ch))
39 return false;
40 // '.' left out as it is used to make up numbers
41 if (ch == '-' || ch == '+' || ch == '!' || ch == '~' ||
42 ch == '?' || ch == ':' || ch == '*' || ch == '/' ||
43 ch == '^' || ch == '<' || ch == '>' || ch == '=' ||
44 ch == '&' || ch == '|' || ch == '$' || ch == '(' ||
45 ch == ')' || ch == '}' || ch == '{' || ch == '[' ||
46 ch == ']')
47 return true;
48 return false;
49 }
50
ColouriseRDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)51 static void ColouriseRDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
52 Accessor &styler) {
53
54 WordList &keywords = *keywordlists[0];
55 WordList &keywords2 = *keywordlists[1];
56 WordList &keywords3 = *keywordlists[2];
57
58
59 // Do not leak onto next line
60 if (initStyle == SCE_R_INFIXEOL)
61 initStyle = SCE_R_DEFAULT;
62
63
64 StyleContext sc(startPos, length, initStyle, styler);
65
66 for (; sc.More(); sc.Forward()) {
67
68 if (sc.atLineStart && (sc.state == SCE_R_STRING)) {
69 // Prevent SCE_R_STRINGEOL from leaking back to previous line
70 sc.SetState(SCE_R_STRING);
71 }
72
73 // Determine if the current state should terminate.
74 if (sc.state == SCE_R_OPERATOR) {
75 sc.SetState(SCE_R_DEFAULT);
76 } else if (sc.state == SCE_R_NUMBER) {
77 if (!IsADigit(sc.ch) && !(sc.ch == '.' && IsADigit(sc.chNext))) {
78 sc.SetState(SCE_R_DEFAULT);
79 }
80 } else if (sc.state == SCE_R_IDENTIFIER) {
81 if (!IsAWordChar(sc.ch)) {
82 char s[100];
83 sc.GetCurrent(s, sizeof(s));
84 if (keywords.InList(s)) {
85 sc.ChangeState(SCE_R_KWORD);
86 } else if (keywords2.InList(s)) {
87 sc.ChangeState(SCE_R_BASEKWORD);
88 } else if (keywords3.InList(s)) {
89 sc.ChangeState(SCE_R_OTHERKWORD);
90 }
91 sc.SetState(SCE_R_DEFAULT);
92 }
93 } else if (sc.state == SCE_R_COMMENT) {
94 if (sc.ch == '\r' || sc.ch == '\n') {
95 sc.SetState(SCE_R_DEFAULT);
96 }
97 } else if (sc.state == SCE_R_STRING) {
98 if (sc.ch == '\\') {
99 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
100 sc.Forward();
101 }
102 } else if (sc.ch == '\"') {
103 sc.ForwardSetState(SCE_R_DEFAULT);
104 }
105 } else if (sc.state == SCE_R_INFIX) {
106 if (sc.ch == '%') {
107 sc.ForwardSetState(SCE_R_DEFAULT);
108 } else if (sc.atLineEnd) {
109 sc.ChangeState(SCE_R_INFIXEOL);
110 sc.ForwardSetState(SCE_R_DEFAULT);
111 }
112 }else if (sc.state == SCE_R_STRING2) {
113 if (sc.ch == '\\') {
114 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
115 sc.Forward();
116 }
117 } else if (sc.ch == '\'') {
118 sc.ForwardSetState(SCE_R_DEFAULT);
119 }
120 }
121
122 // Determine if a new state should be entered.
123 if (sc.state == SCE_R_DEFAULT) {
124 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
125 sc.SetState(SCE_R_NUMBER);
126 } else if (IsAWordStart(sc.ch) ) {
127 sc.SetState(SCE_R_IDENTIFIER);
128 } else if (sc.Match('#')) {
129 sc.SetState(SCE_R_COMMENT);
130 } else if (sc.ch == '\"') {
131 sc.SetState(SCE_R_STRING);
132 } else if (sc.ch == '%') {
133 sc.SetState(SCE_R_INFIX);
134 } else if (sc.ch == '\'') {
135 sc.SetState(SCE_R_STRING2);
136 } else if (IsAnOperator(sc.ch)) {
137 sc.SetState(SCE_R_OPERATOR);
138 }
139 }
140 }
141 sc.Complete();
142 }
143
144 // Store both the current line's fold level and the next lines in the
145 // level store to make it easy to pick up with each increment
146 // and to make it possible to fiddle the current level for "} else {".
FoldRDoc(Sci_PositionU startPos,Sci_Position length,int,WordList * [],Accessor & styler)147 static void FoldRDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
148 Accessor &styler) {
149 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
150 bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
151 Sci_PositionU endPos = startPos + length;
152 int visibleChars = 0;
153 Sci_Position lineCurrent = styler.GetLine(startPos);
154 int levelCurrent = SC_FOLDLEVELBASE;
155 if (lineCurrent > 0)
156 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
157 int levelMinCurrent = levelCurrent;
158 int levelNext = levelCurrent;
159 char chNext = styler[startPos];
160 int styleNext = styler.StyleAt(startPos);
161 for (Sci_PositionU i = startPos; i < endPos; i++) {
162 char ch = chNext;
163 chNext = styler.SafeGetCharAt(i + 1);
164 int style = styleNext;
165 styleNext = styler.StyleAt(i + 1);
166 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
167 if (style == SCE_R_OPERATOR) {
168 if (ch == '{') {
169 // Measure the minimum before a '{' to allow
170 // folding on "} else {"
171 if (levelMinCurrent > levelNext) {
172 levelMinCurrent = levelNext;
173 }
174 levelNext++;
175 } else if (ch == '}') {
176 levelNext--;
177 }
178 }
179 if (atEOL) {
180 int levelUse = levelCurrent;
181 if (foldAtElse) {
182 levelUse = levelMinCurrent;
183 }
184 int lev = levelUse | levelNext << 16;
185 if (visibleChars == 0 && foldCompact)
186 lev |= SC_FOLDLEVELWHITEFLAG;
187 if (levelUse < levelNext)
188 lev |= SC_FOLDLEVELHEADERFLAG;
189 if (lev != styler.LevelAt(lineCurrent)) {
190 styler.SetLevel(lineCurrent, lev);
191 }
192 lineCurrent++;
193 levelCurrent = levelNext;
194 levelMinCurrent = levelCurrent;
195 visibleChars = 0;
196 }
197 if (!isspacechar(ch))
198 visibleChars++;
199 }
200 }
201
202
203 static const char * const RWordLists[] = {
204 "Language Keywords",
205 "Base / Default package function",
206 "Other Package Functions",
207 "Unused",
208 "Unused",
209 0,
210 };
211
212
213
214 LexerModule lmR(SCLEX_R, ColouriseRDoc, "r", FoldRDoc, RWordLists);
215