1 // Scintilla source code edit control
2 /** @file LexMatlab.cxx
3  ** Lexer for Matlab.
4  ** Written by Jos� Fonseca
5  **
6  ** Changes by Christoph Dalitz 2003/12/04:
7  **   - added support for Octave
8  **   - Strings can now be included both in single or double quotes
9  **/
10 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
11 // The License.txt file describes the conditions under which this software may be distributed.
12 
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <assert.h>
18 #include <ctype.h>
19 
20 #include "ILexer.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
23 
24 #include "WordList.h"
25 #include "LexAccessor.h"
26 #include "Accessor.h"
27 #include "StyleContext.h"
28 #include "CharacterSet.h"
29 #include "LexerModule.h"
30 
31 #ifdef SCI_NAMESPACE
32 using namespace Scintilla;
33 #endif
34 
IsMatlabCommentChar(int c)35 static bool IsMatlabCommentChar(int c) {
36 	return (c == '%') ;
37 }
38 
IsOctaveCommentChar(int c)39 static bool IsOctaveCommentChar(int c) {
40 	return (c == '%' || c == '#') ;
41 }
42 
IsMatlabComment(Accessor & styler,int pos,int len)43 static bool IsMatlabComment(Accessor &styler, int pos, int len) {
44 	return len > 0 && IsMatlabCommentChar(styler[pos]) ;
45 }
46 
IsOctaveComment(Accessor & styler,int pos,int len)47 static bool IsOctaveComment(Accessor &styler, int pos, int len) {
48 	return len > 0 && IsOctaveCommentChar(styler[pos]) ;
49 }
50 
IsAWordChar(const int ch)51 static inline bool IsAWordChar(const int ch) {
52 	return (ch < 0x80) && (isalnum(ch) || ch == '_');
53 }
54 
IsAWordStart(const int ch)55 static inline bool IsAWordStart(const int ch) {
56 	return (ch < 0x80) && (isalnum(ch) || ch == '_');
57 }
58 
ColouriseMatlabOctaveDoc(unsigned int startPos,int length,int initStyle,WordList * keywordlists[],Accessor & styler,bool (* IsCommentChar)(int))59 static void ColouriseMatlabOctaveDoc(
60             unsigned int startPos, int length, int initStyle,
61             WordList *keywordlists[], Accessor &styler,
62             bool (*IsCommentChar)(int)) {
63 
64 	WordList &keywords = *keywordlists[0];
65 
66 	styler.StartAt(startPos);
67 
68 	bool transpose = false;
69 
70 	StyleContext sc(startPos, length, initStyle, styler);
71 
72 	for (; sc.More(); sc.Forward()) {
73 
74 		if (sc.state == SCE_MATLAB_OPERATOR) {
75 			if (sc.chPrev == '.') {
76 				if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') {
77 					sc.ForwardSetState(SCE_MATLAB_DEFAULT);
78 					transpose = false;
79 				} else if (sc.ch == '\'') {
80 					sc.ForwardSetState(SCE_MATLAB_DEFAULT);
81 					transpose = true;
82 				} else {
83 					sc.SetState(SCE_MATLAB_DEFAULT);
84 				}
85 			} else {
86 				sc.SetState(SCE_MATLAB_DEFAULT);
87 			}
88 		} else if (sc.state == SCE_MATLAB_KEYWORD) {
89 			if (!isalnum(sc.ch) && sc.ch != '_') {
90 				char s[100];
91 				sc.GetCurrentLowered(s, sizeof(s));
92 				if (keywords.InList(s)) {
93 					sc.SetState(SCE_MATLAB_DEFAULT);
94 					transpose = false;
95 				} else {
96 					sc.ChangeState(SCE_MATLAB_IDENTIFIER);
97 					sc.SetState(SCE_MATLAB_DEFAULT);
98 					transpose = true;
99 				}
100 			}
101 		} else if (sc.state == SCE_MATLAB_NUMBER) {
102 			if (!isdigit(sc.ch) && sc.ch != '.'
103 			        && !(sc.ch == 'e' || sc.ch == 'E')
104 			        && !((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E'))) {
105 				sc.SetState(SCE_MATLAB_DEFAULT);
106 				transpose = true;
107 			}
108 		} else if (sc.state == SCE_MATLAB_STRING) {
109 			if (sc.ch == '\'') {
110 				if (sc.chNext == '\'') {
111  					sc.Forward();
112 				} else {
113 					sc.ForwardSetState(SCE_MATLAB_DEFAULT);
114  				}
115 			}
116 		} else if (sc.state == SCE_MATLAB_DOUBLEQUOTESTRING) {
117 			if (sc.ch == '\\') {
118 				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
119 					sc.Forward();
120 				}
121 			} else if (sc.ch == '\"') {
122 				sc.ForwardSetState(SCE_MATLAB_DEFAULT);
123 			}
124 		} else if (sc.state == SCE_MATLAB_COMMENT || sc.state == SCE_MATLAB_COMMAND) {
125 			if (sc.atLineEnd) {
126 				sc.SetState(SCE_MATLAB_DEFAULT);
127 				transpose = false;
128 			}
129 		}
130 
131 		if (sc.state == SCE_MATLAB_DEFAULT) {
132 			if (IsCommentChar(sc.ch)) {
133 				sc.SetState(SCE_MATLAB_COMMENT);
134 			} else if (sc.ch == '!' && sc.chNext != '=' ) {
135 				sc.SetState(SCE_MATLAB_COMMAND);
136 			} else if (sc.ch == '\'') {
137 				if (transpose) {
138 					sc.SetState(SCE_MATLAB_OPERATOR);
139 				} else {
140 					sc.SetState(SCE_MATLAB_STRING);
141 				}
142 			} else if (sc.ch == '"') {
143 				sc.SetState(SCE_MATLAB_DOUBLEQUOTESTRING);
144 			} else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) {
145 				sc.SetState(SCE_MATLAB_NUMBER);
146 			} else if (isalpha(sc.ch)) {
147 				sc.SetState(SCE_MATLAB_KEYWORD);
148 			} else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '\\') {
149 				if (sc.ch == ')' || sc.ch == ']') {
150 					transpose = true;
151 				} else {
152 					transpose = false;
153 				}
154 				sc.SetState(SCE_MATLAB_OPERATOR);
155 			} else {
156 				transpose = false;
157 			}
158 		}
159 	}
160 	sc.Complete();
161 }
162 
ColouriseMatlabDoc(unsigned int startPos,int length,int initStyle,WordList * keywordlists[],Accessor & styler)163 static void ColouriseMatlabDoc(unsigned int startPos, int length, int initStyle,
164                                WordList *keywordlists[], Accessor &styler) {
165 	ColouriseMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsMatlabCommentChar);
166 }
167 
ColouriseOctaveDoc(unsigned int startPos,int length,int initStyle,WordList * keywordlists[],Accessor & styler)168 static void ColouriseOctaveDoc(unsigned int startPos, int length, int initStyle,
169                                WordList *keywordlists[], Accessor &styler) {
170 	ColouriseMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsOctaveCommentChar);
171 }
172 
FoldMatlabOctaveDoc(unsigned int startPos,int length,int,WordList * [],Accessor & styler,bool (* IsComment)(Accessor &,int,int))173 static void FoldMatlabOctaveDoc(unsigned int startPos, int length, int,
174                                 WordList *[], Accessor &styler,
175                                 bool (*IsComment)(Accessor&, int, int)) {
176 
177 	int endPos = startPos + length;
178 
179 	// Backtrack to previous line in case need to fix its fold status
180 	int lineCurrent = styler.GetLine(startPos);
181 	if (startPos > 0) {
182 		if (lineCurrent > 0) {
183 			lineCurrent--;
184 			startPos = styler.LineStart(lineCurrent);
185 		}
186 	}
187 	int spaceFlags = 0;
188 	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsComment);
189 	char chNext = styler[startPos];
190 	for (int i = startPos; i < endPos; i++) {
191 		char ch = chNext;
192 		chNext = styler.SafeGetCharAt(i + 1);
193 
194 		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
195 			int lev = indentCurrent;
196 			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsComment);
197 			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
198 				// Only non whitespace lines can be headers
199 				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
200 					lev |= SC_FOLDLEVELHEADERFLAG;
201 				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
202 					// Line after is blank so check the next - maybe should continue further?
203 					int spaceFlags2 = 0;
204 					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsComment);
205 					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
206 						lev |= SC_FOLDLEVELHEADERFLAG;
207 					}
208 				}
209 			}
210 			indentCurrent = indentNext;
211 			styler.SetLevel(lineCurrent, lev);
212 			lineCurrent++;
213 		}
214 	}
215 }
216 
FoldMatlabDoc(unsigned int startPos,int length,int initStyle,WordList * keywordlists[],Accessor & styler)217 static void FoldMatlabDoc(unsigned int startPos, int length, int initStyle,
218                           WordList *keywordlists[], Accessor &styler) {
219 	FoldMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsMatlabComment);
220 }
221 
FoldOctaveDoc(unsigned int startPos,int length,int initStyle,WordList * keywordlists[],Accessor & styler)222 static void FoldOctaveDoc(unsigned int startPos, int length, int initStyle,
223                           WordList *keywordlists[], Accessor &styler) {
224 	FoldMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsOctaveComment);
225 }
226 
227 static const char * const matlabWordListDesc[] = {
228 	"Keywords",
229 	0
230 };
231 
232 static const char * const octaveWordListDesc[] = {
233 	"Keywords",
234 	0
235 };
236 
237 LexerModule lmMatlab(SCLEX_MATLAB, ColouriseMatlabDoc, "matlab", FoldMatlabDoc, matlabWordListDesc);
238 
239 LexerModule lmOctave(SCLEX_OCTAVE, ColouriseOctaveDoc, "octave", FoldOctaveDoc, octaveWordListDesc);
240