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